From cf390bf8b9f0652679a4ddc2ad66674e3793e3e7 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 24 Nov 2021 21:20:46 +0100 Subject: [PATCH 0001/1052] Recover from closing brace not found in field list --- core/odin/parser/parser.odin | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 7660005e0..b4efc1460 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -416,7 +416,16 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { str := tokenizer.token_to_string(token) error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str) } - return expect_token(p, .Close_Brace) + expect_brace := expect_token(p, .Close_Brace) + + if expect_brace.kind != .Close_Brace { + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { + advance_token(p) + } + return p.curr_tok + } + + return expect_brace } From a4ba91a55435febb0b5daeadcff2450f52680044 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 25 Nov 2021 18:47:58 +0100 Subject: [PATCH 0002/1052] Check for non inserted semicolon in *expect_closing_brace_of_field_list* --- core/odin/parser/parser.odin | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index b4efc1460..1d27b4a79 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -419,7 +419,7 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { expect_brace := expect_token(p, .Close_Brace) if expect_brace.kind != .Close_Brace { - for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) { advance_token(p) } return p.curr_tok @@ -428,6 +428,9 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { return expect_brace } +is_non_inserted_semicolon :: proc(tok: tokenizer.Token) -> bool { + return tok.kind == .Semicolon && tok.text != "\n" +} is_blank_ident :: proc{ is_blank_ident_string, From b5c828fe4ee3f0942b2eda1dc5753e4ad6d38ea9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 30 Nov 2021 23:01:22 +0100 Subject: [PATCH 0003/1052] [xml] Initial implementation of `core:encoding/xml`. A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). Features: - Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage. - Simple to understand and use. Small. Caveats: - We do NOT support HTML in this package, as that may or may not be valid XML. If it works, great. If it doesn't, that's not considered a bug. - We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences. - <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options. TODO: - Optional CDATA unboxing. - Optional `>`, ` `, ` ` and other escape substitution in tag bodies. - Test suite MAYBE: - XML writer? - Serialize/deserialize Odin types? --- core/encoding/xml/debug_print.odin | 73 ++ core/encoding/xml/example/xml_example.odin | 55 ++ core/encoding/xml/tokenizer.odin | 339 +++++++++ core/encoding/xml/xml_reader.odin | 651 ++++++++++++++++++ tests/core/Makefile | 17 +- tests/core/assets/xml/nl_NL-qt-ts.ts | 35 + tests/core/assets/xml/nl_NL-xliff-1.0.xliff | 38 + tests/core/assets/xml/nl_NL-xliff-2.0.xliff | 52 ++ tests/core/assets/xml/utf8.xml | 8 + tests/core/build.bat | 15 +- .../encoding/{ => json}/test_core_json.odin | 36 +- tests/core/encoding/xml/test_core_xml.odin | 264 +++++++ 12 files changed, 1553 insertions(+), 30 deletions(-) create mode 100644 core/encoding/xml/debug_print.odin create mode 100644 core/encoding/xml/example/xml_example.odin create mode 100644 core/encoding/xml/tokenizer.odin create mode 100644 core/encoding/xml/xml_reader.odin create mode 100644 tests/core/assets/xml/nl_NL-qt-ts.ts create mode 100644 tests/core/assets/xml/nl_NL-xliff-1.0.xliff create mode 100644 tests/core/assets/xml/nl_NL-xliff-2.0.xliff create mode 100644 tests/core/assets/xml/utf8.xml rename tests/core/encoding/{ => json}/test_core_json.odin (63%) create mode 100644 tests/core/encoding/xml/test_core_xml.odin diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin new file mode 100644 index 000000000..0b7ffa822 --- /dev/null +++ b/core/encoding/xml/debug_print.odin @@ -0,0 +1,73 @@ +package xml +/* + An XML 1.0 / 1.1 parser + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +import "core:fmt" + +/* + Just for debug purposes. +*/ +print :: proc(doc: ^Document) { + assert(doc != nil) + + using fmt + println("[XML Prolog]") + + for attr in doc.prolog { + printf("\t%v: %v\n", attr.key, attr.val) + } + + printf("[Encoding] %v\n", doc.encoding) + printf("[DOCTYPE] %v\n", doc.doctype.ident) + + if len(doc.doctype.rest) > 0 { + printf("\t%v\n", doc.doctype.rest) + } + + if doc.root != nil { + println(" --- ") + print_element(0, doc.root) + println(" --- ") + } +} + +print_element :: proc(indent: int, element: ^Element) { + if element == nil { return } + using fmt + + tab :: proc(indent: int) { + tabs := "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" + + i := max(0, min(indent, len(tabs))) + printf("%v", tabs[:i]) + } + + tab(indent) + + if element.kind == .Element { + printf("<%v>\n", element.ident) + if len(element.value) > 0 { + tab(indent + 1) + printf("[Value] %v\n", element.value) + } + + for attr in element.attribs { + tab(indent + 1) + printf("[Attr] %v: %v\n", attr.key, attr.val) + } + + for child in element.children { + print_element(indent + 1, child) + } + } else if element.kind == .Comment { + printf("[COMMENT] %v\n", element.value) + } +} \ No newline at end of file diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin new file mode 100644 index 000000000..24a277de6 --- /dev/null +++ b/core/encoding/xml/example/xml_example.odin @@ -0,0 +1,55 @@ +package xml_example + +import "core:encoding/xml" +import "core:mem" +import "core:fmt" + +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) { + +} + +FILENAME :: "../../../../tests/core/assets/xml/nl_NL-xliff-1.0.xliff" +DOC :: #load(FILENAME) + +OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", +} + +_main :: proc() { + using fmt + + println("--- DOCUMENT TO PARSE ---") + println(string(DOC)) + println("--- /DOCUMENT TO PARSE ---\n") + + doc, err := xml.parse(DOC, OPTIONS, FILENAME, Error_Handler) + defer xml.destroy(doc) + + xml.print(doc) + + if err != .None { + printf("Parse error: %v\n", err) + } else { + println("DONE!") + } +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + _main() + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } +} \ No newline at end of file diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin new file mode 100644 index 000000000..a63dca5bd --- /dev/null +++ b/core/encoding/xml/tokenizer.odin @@ -0,0 +1,339 @@ +package xml + +import "core:fmt" +import "core:unicode" +import "core:unicode/utf8" + +Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any) + +Token :: struct { + kind: Token_Kind, + text: string, + pos: Pos, +} + +Pos :: struct { + file: string, + offset: int, // starting at 0 + line: int, // starting at 1 + column: int, // starting at 1 +} + +Token_Kind :: enum { + Invalid, + + Ident, + Literal, + Rune, + String, + + Double_Quote, // " + Single_Quote, // ' + Colon, // : + + Eq, // = + Lt, // < + Gt, // > + Exclaim, // ! + Question, // ? + Hash, // # + Slash, // / + Dash, // - + + Open_Bracket, // [ + Close_Bracket, // ] + + EOF, +} + +CDATA_START :: "" + +Tokenizer :: struct { + // Immutable data + path: string, + src: string, + err: Error_Handler, + + // Tokenizing state + ch: rune, + offset: int, + read_offset: int, + line_offset: int, + line_count: int, + + // Mutable data + error_count: int, +} + +init :: proc(t: ^Tokenizer, src: string, path: string, err: Error_Handler = default_error_handler) { + t.src = src + t.err = err + t.ch = ' ' + t.offset = 0 + t.read_offset = 0 + t.line_offset = 0 + t.line_count = len(src) > 0 ? 1 : 0 + t.error_count = 0 + t.path = path + + advance_rune(t) + if t.ch == utf8.RUNE_BOM { + advance_rune(t) + } +} + +@(private) +offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos { + line := t.line_count + column := offset - t.line_offset + 1 + + return Pos { + file = t.path, + offset = offset, + line = line, + column = column, + } +} + +default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { + fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column) + fmt.eprintf(msg, ..args) + fmt.eprintf("\n") +} + +error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { + pos := offset_to_pos(t, offset) + if t.err != nil { + t.err(pos, msg, ..args) + } + t.error_count += 1 +} + +advance_rune :: proc(using t: ^Tokenizer) { + if read_offset < len(src) { + offset = read_offset + if ch == '\n' { + line_offset = offset + line_count += 1 + } + r, w := rune(src[read_offset]), 1 + switch { + case r == 0: + error(t, t.offset, "illegal character NUL") + case r >= utf8.RUNE_SELF: + r, w = utf8.decode_rune_in_string(src[read_offset:]) + if r == utf8.RUNE_ERROR && w == 1 { + error(t, t.offset, "illegal UTF-8 encoding") + } else if r == utf8.RUNE_BOM && offset > 0 { + error(t, t.offset, "illegal byte order mark") + } + } + read_offset += w + ch = r + } else { + offset = len(src) + if ch == '\n' { + line_offset = offset + line_count += 1 + } + ch = -1 + } +} + +peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte { + if t.read_offset+offset < len(t.src) { + return t.src[t.read_offset+offset] + } + return 0 +} + +skip_whitespace :: proc(t: ^Tokenizer) { + for { + switch t.ch { + case ' ', '\t', '\r', '\n': + advance_rune(t) + case: + return + } + } +} + +is_letter :: proc(r: rune) -> bool { + if r < utf8.RUNE_SELF { + switch r { + case '_': + return true + case 'A'..='Z', 'a'..='z': + return true + } + } + return unicode.is_letter(r) +} + +is_valid_identifier_rune :: proc(r: rune) -> bool { + if r < utf8.RUNE_SELF { + switch r { + case '_', '-', ':': return true + case 'A'..='Z', 'a'..='z': return true + case '0'..'9': return true + } + } + + if unicode.is_digit(r) || unicode.is_letter(r) { + return true + } + return false +} + +scan_identifier :: proc(t: ^Tokenizer) -> string { + offset := t.offset + namespaced := false + + for is_valid_identifier_rune(t.ch) { + advance_rune(t) + if t.ch == ':' { + /* + A namespaced attr can have at most two parts, `namespace:ident`. + */ + if namespaced { + break + } + namespaced = true + } + } + return string(t.src[offset : t.offset]) +} + +scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false) -> (value: string, err: Error) { + err = .None + in_cdata := false + + loop: for { + ch := t.ch + + switch ch { + case -1: + error(t, t.offset, "[scan_string] Premature end of file.\n") + return "", .Premature_EOF + + case '<': + /* + Might be the start of a CDATA tag. + */ + if t.read_offset + len(CDATA_START) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { + in_cdata = true + } + } + + case ']': + /* + Might be the end of a CDATA tag. + */ + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + in_cdata = false + } + } + + case '\n': + if !in_cdata { + error(t, offset, string(t.src[offset : t.offset])) + error(t, offset, "[scan_string] Not terminated\n") + err = .Invalid_Tag_Value + break loop + } + } + + if ch == close && !in_cdata { + /* + If it's not a CDATA tag, it's the end of this body. + */ + break loop + } + + advance_rune(t) + } + + lit := string(t.src[offset : t.offset]) + if consume_close { + advance_rune(t) + } + + /* + TODO: Handle decoding escape characters and unboxing CDATA. + */ + + return lit, err +} + +peek :: proc(t: ^Tokenizer) -> (token: Token) { + old := t^ + token = scan(t) + t^ = old + return token +} + +scan :: proc(t: ^Tokenizer) -> Token { + skip_whitespace(t) + + offset := t.offset + + kind: Token_Kind + err: Error + lit: string + pos := offset_to_pos(t, offset) + + switch ch := t.ch; true { + case is_letter(ch): + lit = scan_identifier(t) + kind = .Ident + + case: + advance_rune(t) + switch ch { + case -1: + kind = .EOF + + case '<': kind = .Lt + case '>': kind = .Gt + case '!': kind = .Exclaim + case '?': kind = .Question + case '=': kind = .Eq + case '#': kind = .Hash + case '/': kind = .Slash + case '-': kind = .Dash + case ':': kind = .Colon + + case '"', '\'': + lit, err = scan_string(t, t.offset, ch, true) + if err == .None { + kind = .String + } else { + kind = .Invalid + } + + case '\n': + lit = "\n" + + case '\\': + token := scan(t) + if token.pos.line == pos.line { + error(t, token.pos.offset, "expected a newline after \\") + } + return token + + case: + if ch != utf8.RUNE_BOM { + // error(t, t.offset, "illegal character '%r': %d", ch, ch) + } + kind = .Invalid + } + } + + if lit == "" { + lit = string(t.src[offset : t.offset]) + } + return Token{kind, lit, pos} +} \ No newline at end of file diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin new file mode 100644 index 000000000..526be5856 --- /dev/null +++ b/core/encoding/xml/xml_reader.odin @@ -0,0 +1,651 @@ +package xml +/* + An XML 1.0 / 1.1 parser + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + A from-scratch XML implementation, loosely modelled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). + + Features: + - Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage. + - Simple to understand and use. Small. + + Caveats: + - We do NOT support HTML in this package, as that may or may not be valid XML. + If it works, great. If it doesn't, that's not considered a bug. + + - We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences. + - <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options. + + TODO: + - Optional CDATA unboxing. + - Optional `>`, ` `, ` ` and other escape substitution in tag bodies. + + MAYBE: + - XML writer? + - Serialize/deserialize Odin types? + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ + +import "core:strings" +import "core:mem" +import "core:os" + +DEFAULT_Options :: Options{ + flags = { + .Ignore_Unsupported, + }, + expected_doctype = "", +} + +Option_Flag :: enum { + /* + Document MUST start with ` (doc: ^Document, err: Error) { + context.allocator = allocator + + opts := validate_options(options) or_return + + t := &Tokenizer{} + init(t, string(data), path, error_handler) + + doc = new(Document) + doc.allocator = allocator + doc.tokenizer = t + + strings.intern_init(&doc.intern, allocator, allocator) + + err = .Unexpected_Token + element, parent: ^Element + + /* + If a DOCTYPE is present, the root tag has to match. + If an expected DOCTYPE is given in options (i.e. it's non-empty), the DOCTYPE (if present) and root tag have to match. + */ + expected_doctype := options.expected_doctype + + loop: for { + tok := scan(t) + #partial switch tok.kind { + + case .Lt: + open := scan(t) + #partial switch open.kind { + + case .Question: + /* + 0 { + /* + We've already seen a prolog. + */ + return doc, .Too_Many_Prologs + } else { + error(t, t.offset, "Expected \" 0 { + return doc, .Too_Many_DocTypes + } + if doc.root != nil { + return doc, .DocType_Must_Proceed_Elements + } + parse_doctype(doc) or_return + + if len(expected_doctype) > 0 && expected_doctype != doc.doctype.ident { + error(t, t.offset, "Invalid DOCTYPE. Expected: %v, got: %v\n", expected_doctype, doc.doctype.ident) + return doc, .Invalid_DocType + } + expected_doctype = doc.doctype.ident + + case: + if .Error_on_Unsupported in opts.flags { + error(t, t.offset, "Unhandled: . + The grammar does not allow a comment to end in ---> + */ + if doc.root == nil { + return doc, .Comment_Before_Root_Element + } + + expect(t, .Dash) + offset := t.offset + + for { + advance_rune(t) + ch := t.ch + + /* + A comment ends when we see -->, preceded by a character that's not a dash. + "For compatibility, the string "--" (double-hyphen) must not occur within comments." + + See: https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-comment + + Thanks to the length (4) of the comment start, we also have enough lookback, + and the peek at the next byte asserts that there's at least one more character + that's a `>`. + */ + if ch < 0 { + error(t, offset, "[parse] Comment was not terminated\n") + return doc, .Unclosed_Comment + } + + if string(t.src[t.offset - 1:][:2]) == "--" { + if peek_byte(t) == '>' { + break + } else { + error(t, t.offset - 1, "Invalid -- sequence in comment.\n") + return doc, .Invalid_Sequence_In_Comment + } + } + } + + if .Intern_Comments in opts.flags { + el := new(Element) + + el.parent = element + el.kind = .Comment + el.value = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + append(&element.children, el) + } + + expect(t, .Dash) + expect(t, .Gt) + + case: + error(t, t.offset, "Invalid Token after 0 && expected_doctype != open.text { + error(t, t.offset, "Root Tag doesn't match DOCTYPE. Expected: %v, got: %v\n", expected_doctype, open.text) + return doc, .Invalid_DocType + } + } + + /* + One of these should follow: + - `>`, which means we've just opened this tag and expect a later element to close it. + - `/>`, which means this is an 'empty' or self-closing tag. + */ + end_token := scan(t) + + #partial switch end_token.kind { + case .Gt: + /* + We're now the new parent. + */ + parent = element + + case .Slash: + /* + Empty tag? + */ + expect(t, .Gt) or_return + + case: + error(t, t.offset, "Expected close tag, got: %#v\n", end_token) + return + } + + case .Slash: + /* + Close tag. + */ + ident := expect(t, .Ident) or_return + _ = expect(t, .Gt) or_return + + if element.ident != ident.text { + error(t, t.offset, "Mismatched Closing Tag: %v\n", ident.text) + return doc, .Mismatched_Closing_Tag + } + parent = element.parent + element = parent + + case: + error(t, t.offset, "Invalid Token after <: %#v\n", open) + return + } + + case .EOF: + break loop + + case: + /* + This should be a tag's body text. + */ + element.value = scan_string(t, tok.pos.offset) or_return + } + } + + if .Must_Have_Prolog in opts.flags && len(doc.prolog) == 0 { + return doc, .No_Prolog + } + + if .Must_Have_DocType in opts.flags && len(doc.doctype.ident) == 0 { + return doc, .No_DocType + } + + return doc, .None +} + +parse_from_file :: proc(filename: string, options := DEFAULT_Options, error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) { + context.allocator = allocator + + data, data_ok := os.read_entire_file(filename) + defer delete(data) + + if !data_ok { return {}, .File_Error } + + return parse_from_slice(data, options, filename, error_handler, allocator) +} + +parse :: proc { parse_from_file, parse_from_slice } + +free_element :: proc(element: ^Element) { + if element == nil { return } + + for child in element.children { + /* + NOTE: Recursive. + + Could be rewritten so it adds them to a list of pointers to free. + */ + free_element(child) + } + delete(element.attribs) + delete(element.children) + free(element) +} + +destroy :: proc(doc: ^Document) { + if doc == nil { return } + + free_element(doc.root) + strings.intern_destroy(&doc.intern) + + delete(doc.prolog) + free(doc) +} + +/* + Helpers. +*/ + +validate_options :: proc(options: Options) -> (validated: Options, err: Error) { + validated = options + + if .Error_on_Unsupported in validated.flags && .Ignore_Unsupported in validated.flags { + return options, .Conflicting_Options + } + + if .Unbox_CDATA in validated.flags { + return options, .Unhandled_CDATA_Unboxing + } + + if .Decode_SGML_Entities in validated.flags { + return options, .Unhandled_SGML_Entity_Decoding + } + + return validated, .None +} + +expect :: proc(t: ^Tokenizer, kind: Token_Kind) -> (tok: Token, err: Error) { + tok = scan(t) + if tok.kind == kind { return tok, .None } + + error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind) + return tok, .Unexpected_Token +} + +parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + key := expect(t, .Ident) or_return + offset = t.offset - len(key.text) + + _ = expect(t, .Eq) or_return + value := expect(t, .String) or_return + + attr.key = strings.intern_get(&doc.intern, key.text) + attr.val = strings.intern_get(&doc.intern, value.text) + + err = .None + return +} + +check_duplicate_attributes :: proc(t: ^Tokenizer, attribs: Attributes, attr: Attr, offset: int) -> (err: Error) { + for a in attribs { + if attr.key == a.key { + error(t, offset, "Duplicate attribute: %v\n", attr.key) + return .Duplicate_Attribute + } + } + return .None +} + +parse_attributes :: proc(doc: ^Document, attribs: ^Attributes) -> (err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + for peek(t).kind == .Ident { + attr, offset := parse_attribute(doc) or_return + check_duplicate_attributes(t, attribs^, attr, offset) or_return + append(attribs, attr) + } + skip_whitespace(t) + return .None +} + +parse_prolog :: proc(doc: ^Document) -> (err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + offset := t.offset + parse_attributes(doc, &doc.prolog) or_return + + for attr in doc.prolog { + switch attr.key { + case "version": + switch attr.val { + case "1.0", "1.1": + case: + error(t, offset, "[parse_prolog] Warning: Unhandled XML version: %v\n", attr.val) + } + + case "encoding": + switch strings.to_lower(attr.val, context.temp_allocator) { + case "utf-8", "utf8": + doc.encoding = .UTF_8 + + case "latin-1", "latin1", "iso-8859-1": + doc.encoding = .LATIN_1 + + case: + /* + Unrecognized encoding, assume UTF-8. + */ + error(t, offset, "[parse_prolog] Warning: Unrecognized encoding: %v\n", attr.val) + } + + case: + // Ignored. + } + } + + _ = expect(t, .Question) or_return + _ = expect(t, .Gt) or_return + + return .None +} + +skip_element :: proc(t: ^Tokenizer) -> (err: Error) { + close := 1 + + loop: for { + tok := scan(t) + #partial switch tok.kind { + case .EOF: + error(t, t.offset, "[skip_element] Premature EOF\n") + return .Premature_EOF + + case .Lt: + close += 1 + + case .Gt: + close -= 1 + if close == 0 { + break loop + } + + case: + + } + } + return .None +} + +parse_doctype :: proc(doc: ^Document) -> (err: Error) { + /* + + + + ]> + */ + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + tok := expect(t, .Ident) or_return + doc.doctype.ident = strings.intern_get(&doc.intern, tok.text) + + skip_whitespace(t) + offset := t.offset + skip_element(t) or_return + + /* + -1 because the current offset is that of the closing tag, so the rest of the DOCTYPE tag ends just before it. + */ + doc.doctype.rest = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + return .None +} \ No newline at end of file diff --git a/tests/core/Makefile b/tests/core/Makefile index 0f0ffe4d6..e17dede90 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,22 +1,29 @@ ODIN=../../odin PYTHON=$(shell which python3) -all: download_test_assets image_test compress_test strings_test hash_test crypto_test +all: download_test_assets image_test compress_test strings_test hash_test crypto_test encoding_test download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image/test_core_image.odin + $(ODIN) run image/test_core_image.odin -out=test_image -o:speed -no-bounds-check compress_test: - $(ODIN) run compress/test_core_compress.odin + $(ODIN) run compress/test_core_compress.odin -out=test_compress -o:speed -no-bounds-check strings_test: - $(ODIN) run strings/test_core_strings.odin + $(ODIN) run strings/test_core_strings.odin -out=test_strings -o:speed -no-bounds-check + +odin_test: + $(ODIN) run odin -out=test_odin -o:speed -no-bounds-check hash_test: $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check crypto_test: - $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check \ No newline at end of file + $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check + +encoding_test: + $(ODIN) run encoding/json -out=test_encoding_json -o:speed -no-bounds-check + $(ODIN) run encoding/xml -out=test_encoding_xml -o:speed -no-bounds-check diff --git a/tests/core/assets/xml/nl_NL-qt-ts.ts b/tests/core/assets/xml/nl_NL-qt-ts.ts new file mode 100644 index 000000000..6ec3f2f47 --- /dev/null +++ b/tests/core/assets/xml/nl_NL-qt-ts.ts @@ -0,0 +1,35 @@ + + + + + Page + + Text for translation + commenting + Tekst om te vertalen + + + Also text to translate + some text + Ook tekst om te vertalen + + + + installscript + + 99 bottles of beer on the wall + some new comments here + 99 flessen bier op de muur + + + + apple_count + + %d apple(s) + + %d appel + %d appels + + + + diff --git a/tests/core/assets/xml/nl_NL-xliff-1.0.xliff b/tests/core/assets/xml/nl_NL-xliff-1.0.xliff new file mode 100644 index 000000000..7a1abcd66 --- /dev/null +++ b/tests/core/assets/xml/nl_NL-xliff-1.0.xliff @@ -0,0 +1,38 @@ + + + + + + text + tekst + Context + + + text 1 + tekst 1 + Context 1 + + + text 2 + + Context of the segment 2 + + + text 3 + translation 3 + Context 3 + + + Plurals + + %d month + %d maand + + + %d months + %d maanden + + + + + diff --git a/tests/core/assets/xml/nl_NL-xliff-2.0.xliff b/tests/core/assets/xml/nl_NL-xliff-2.0.xliff new file mode 100644 index 000000000..611ac80c4 --- /dev/null +++ b/tests/core/assets/xml/nl_NL-xliff-2.0.xliff @@ -0,0 +1,52 @@ + + + + + Note for file + + + + Note for unit + + + text + + + + + + Note for unit 2 + + + text 2 + translation 2 + + + + + Note for unit 3 + + + text 3 + approved translation 3 + + + + + + Plurals + + + %d month + %d maand + + + + + %d months + %d maanden + + + + + \ No newline at end of file diff --git a/tests/core/assets/xml/utf8.xml b/tests/core/assets/xml/utf8.xml new file mode 100644 index 000000000..c9ed3bf69 --- /dev/null +++ b/tests/core/assets/xml/utf8.xml @@ -0,0 +1,8 @@ + + +<恥ずべきフクロウ 올빼미_id="Foozle Hello, world!"]]>Barzle"> +<부끄러운:barzle> + ရှက်စရာ ဇီးကွက် + Owl of Shame + More CDATA Hello, world! Nonsense. + \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index 176b7f175..7a214acc9 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -5,34 +5,35 @@ python3 download_assets.py echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% run image %COMMON% +%PATH_TO_ODIN% run image %COMMON% -out:test_image.exe echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% run compress %COMMON% +%PATH_TO_ODIN% run compress %COMMON% -out:test_compress.exe echo --- echo Running core:strings tests echo --- -%PATH_TO_ODIN% run strings %COMMON% +%PATH_TO_ODIN% run strings %COMMON% -out:test_strings.exe echo --- echo Running core:hash tests echo --- -%PATH_TO_ODIN% run hash %COMMON% -o:size +%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_hash.exe echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size +%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_odin.exe echo --- echo Running core:crypto hash tests echo --- -%PATH_TO_ODIN% run crypto %COMMON% +%PATH_TO_ODIN% run crypto %COMMON% -o:speed -out:test_crypto.exe echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding %COMMON% \ No newline at end of file +%PATH_TO_ODIN% run encoding\json %COMMON% -out:test_json.exe +%PATH_TO_ODIN% run encoding\xml %COMMON% -out:test_xml.exe \ No newline at end of file diff --git a/tests/core/encoding/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin similarity index 63% rename from tests/core/encoding/test_core_json.odin rename to tests/core/encoding/json/test_core_json.odin index f536eb4c6..4f415c008 100644 --- a/tests/core/encoding/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -8,32 +8,32 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } main :: proc() { - t := testing.T{} + t := testing.T{} parse_json(&t) marshal_json(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin new file mode 100644 index 000000000..7eefac212 --- /dev/null +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -0,0 +1,264 @@ +package test_core_xml + +import "core:encoding/xml" +import "core:testing" +import "core:mem" +import "core:fmt" + +Silent :: proc(pos: xml.Pos, fmt: string, args: ..any) { + // Custom (silent) error handler. +} + +OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", +} + +TEST_count := 0 +TEST_fail := 0 + +TEST :: struct { + filename: string, + options: xml.Options, + expected: struct { + error: xml.Error, + xml_version: string, + xml_encoding: string, + doctype: string, + }, +} + +TESTS :: []TEST{ + /* + First we test that certain files parse without error. + */ + { + filename = "assets/xml/utf8.xml", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "恥ずべきフクロウ", + }, + }, + { + filename = "assets/xml/nl_NL-qt-ts.ts", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "TS", + }, + }, + { + filename = "assets/xml/nl_NL-xliff-1.0.xliff", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "UTF-8", + doctype = "", + }, + }, + { + filename = "assets/xml/nl_NL-xliff-2.0.xliff", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "", + }, + }, + + /* + Then we test that certain errors are returned as expected. + */ + { + filename = "assets/xml/utf8.xml", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "Odin", + }, + expected = { + error = .Invalid_DocType, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "恥ずべきフクロウ", + }, + }, +} + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + run_tests(&t) + + if len(track.allocation_map) > 0 { + for _, v in track.allocation_map { + err_msg := fmt.tprintf("%v Leaked %v bytes.", v.location, v.size) + expect(&t, false, err_msg) + } + } + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +@test +run_tests :: proc(t: ^testing.T) { + using fmt + + count := 0 + + for test in TESTS { + printf("Trying to parse %v\n\n", test.filename) + + doc, err := xml.parse(test.filename, test.options, Silent) + defer xml.destroy(doc) + + err_msg := tprintf("Expected return value %v, got %v", test.expected.error, err) + expect(t, err == test.expected.error, err_msg) + + if len(test.expected.xml_version) > 0 { + xml_version := "" + for attr in doc.prolog { + if attr.key == "version" { + xml_version = attr.val + } + } + + err_msg = tprintf("Expected XML version %v, got %v", test.expected.xml_version, xml_version) + expect(t, xml_version == test.expected.xml_version, err_msg) + } + + if len(test.expected.xml_encoding) > 0 { + xml_encoding := "" + for attr in doc.prolog { + if attr.key == "encoding" { + xml_encoding = attr.val + } + } + + err_msg = tprintf("Expected XML encoding %v, got %v", test.expected.xml_encoding, xml_encoding) + expect(t, xml_encoding == test.expected.xml_encoding, err_msg) + } + + err_msg = tprintf("Expected DOCTYPE %v, got %v", test.expected.doctype, doc.doctype.ident) + expect(t, doc.doctype.ident == test.expected.doctype, err_msg) + + /* + File-specific tests. + */ + switch count { + case 0: + expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") + attr := doc.root.attribs[0] + + attr_key_expected := "올빼미_id" + attr_val_expected := "Foozle Hello, world!\"]]>Barzle" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + + expect(t, len(doc.root.children) > 0, "Expected the root tag to have children.") + child := doc.root.children[0] + + first_child_ident := "부끄러운:barzle" + attr_err = tprintf("Expected first child tag's ident to be %v, got %v", first_child_ident, child.ident) + expect(t, child.ident == first_child_ident, attr_err) + + case 2: + expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") + + { + attr := doc.root.attribs[0] + + attr_key_expected := "version" + attr_val_expected := "1.2" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + + { + attr := doc.root.attribs[1] + + attr_key_expected := "xmlns" + attr_val_expected := "urn:oasis:names:tc:xliff:document:1.2" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + + case 3: + expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") + + { + attr := doc.root.attribs[0] + + attr_key_expected := "xmlns" + attr_val_expected := "urn:oasis:names:tc:xliff:document:2.0" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + + { + attr := doc.root.attribs[1] + + attr_key_expected := "version" + attr_val_expected := "2.0" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + } + + count += 1 + } +} \ No newline at end of file From 9b2e67df67b5f801687f3c48c6701daa00c38088 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 30 Nov 2021 23:43:51 +0100 Subject: [PATCH 0004/1052] [xml] Small cleanup. --- core/encoding/xml/tokenizer.odin | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index a63dca5bd..3dcffb0d6 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -180,7 +180,7 @@ is_valid_identifier_rune :: proc(r: rune) -> bool { } } - if unicode.is_digit(r) || unicode.is_letter(r) { + if unicode.is_letter(r) || unicode.is_digit(r) { return true } return false @@ -317,17 +317,7 @@ scan :: proc(t: ^Tokenizer) -> Token { case '\n': lit = "\n" - case '\\': - token := scan(t) - if token.pos.line == pos.line { - error(t, token.pos.offset, "expected a newline after \\") - } - return token - case: - if ch != utf8.RUNE_BOM { - // error(t, t.offset, "illegal character '%r': %d", ch, ch) - } kind = .Invalid } } From 46a4927acad674b3265969bd5bde591b480d0c73 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 00:32:35 +0100 Subject: [PATCH 0005/1052] [xml] Use `io.Writer` for `xml.print(doc)`. --- core/encoding/xml/debug_print.odin | 51 ++++++++++++---------- core/encoding/xml/example/xml_example.odin | 8 +++- core/encoding/xml/xml_reader.odin | 2 +- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index 0b7ffa822..be1175cbc 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -10,64 +10,69 @@ package xml List of contributors: Jeroen van Rijn: Initial implementation. */ +import "core:io" import "core:fmt" /* Just for debug purposes. */ -print :: proc(doc: ^Document) { - assert(doc != nil) - +print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error) { + if doc == nil { return } using fmt - println("[XML Prolog]") + + written += wprintf(writer, "[XML Prolog]\n") for attr in doc.prolog { - printf("\t%v: %v\n", attr.key, attr.val) + written += wprintf(writer, "\t%v: %v\n", attr.key, attr.val) } - printf("[Encoding] %v\n", doc.encoding) - printf("[DOCTYPE] %v\n", doc.doctype.ident) + written += wprintf(writer, "[Encoding] %v\n", doc.encoding) + written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) if len(doc.doctype.rest) > 0 { - printf("\t%v\n", doc.doctype.rest) + wprintf(writer, "\t%v\n", doc.doctype.rest) } if doc.root != nil { - println(" --- ") - print_element(0, doc.root) - println(" --- ") - } + wprintln(writer, " --- ") + print_element(writer, doc.root) + wprintln(writer, " --- ") + } + + return written, .None } -print_element :: proc(indent: int, element: ^Element) { +print_element :: proc(writer: io.Writer, element: ^Element, indent := 0) -> (written: int, err: io.Error) { if element == nil { return } using fmt - tab :: proc(indent: int) { + tab :: proc(writer: io.Writer, indent: int) { tabs := "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" i := max(0, min(indent, len(tabs))) - printf("%v", tabs[:i]) + wprintf(writer, "%v", tabs[:i]) } - tab(indent) + tab(writer, indent) if element.kind == .Element { - printf("<%v>\n", element.ident) + wprintf(writer, "<%v>\n", element.ident) if len(element.value) > 0 { - tab(indent + 1) - printf("[Value] %v\n", element.value) + tab(writer, indent + 1) + wprintf(writer, "[Value] %v\n", element.value) } for attr in element.attribs { - tab(indent + 1) - printf("[Attr] %v: %v\n", attr.key, attr.val) + tab(writer, indent + 1) + wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val) } for child in element.children { - print_element(indent + 1, child) + print_element(writer, child, indent + 1) } } else if element.kind == .Comment { - printf("[COMMENT] %v\n", element.value) + wprintf(writer, "[COMMENT] %v\n", element.value) } + + return written, .None } \ No newline at end of file diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 24a277de6..82938c223 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -2,6 +2,7 @@ package xml_example import "core:encoding/xml" import "core:mem" +import "core:strings" import "core:fmt" Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) { @@ -28,7 +29,12 @@ _main :: proc() { doc, err := xml.parse(DOC, OPTIONS, FILENAME, Error_Handler) defer xml.destroy(doc) - xml.print(doc) + buf: strings.Builder + defer strings.destroy_builder(&buf) + w := strings.to_writer(&buf) + + xml.print(w, doc) + println(strings.to_string(buf)) if err != .None { printf("Parse error: %v\n", err) diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 526be5856..34f6e65d0 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -75,6 +75,7 @@ Option_Flag :: enum { */ Decode_SGML_Entities, } +Option_Flags :: bit_set[Option_Flag; u8] Document :: struct { root: ^Element, @@ -122,7 +123,6 @@ Options :: struct { flags: Option_Flags, expected_doctype: string, } -Option_Flags :: bit_set[Option_Flag] Encoding :: enum { Unknown, From 682783a2aabad34e838493bb1e4c2437fd13058a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 00:43:22 +0100 Subject: [PATCH 0006/1052] [xml] Tab indentation in debug printer. --- core/encoding/xml/debug_print.odin | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index be1175cbc..c4d6875cc 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -47,10 +47,9 @@ print_element :: proc(writer: io.Writer, element: ^Element, indent := 0) -> (wri using fmt tab :: proc(writer: io.Writer, indent: int) { - tabs := "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" - - i := max(0, min(indent, len(tabs))) - wprintf(writer, "%v", tabs[:i]) + for _ in 0..=indent { + wprintf(writer, "\t") + } } tab(writer, indent) From 32eab04d662b0c1128e64a4b91fb81f5f2be5a95 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 03:15:44 +0100 Subject: [PATCH 0007/1052] [xml] Allow multi-line bodies w/o CDATA. Strip trailing whitespace. --- core/encoding/xml/debug_print.odin | 9 ++++++--- core/encoding/xml/tokenizer.odin | 21 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index c4d6875cc..65b71e30b 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -27,10 +27,13 @@ print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error } written += wprintf(writer, "[Encoding] %v\n", doc.encoding) - written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) - if len(doc.doctype.rest) > 0 { - wprintf(writer, "\t%v\n", doc.doctype.rest) + if len(doc.doctype.ident) > 0 { + written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) + + if len(doc.doctype.rest) > 0 { + wprintf(writer, "\t%v\n", doc.doctype.rest) + } } if doc.root != nil { diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 3dcffb0d6..e453552b8 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -205,7 +205,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string { return string(t.src[offset : t.offset]) } -scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false) -> (value: string, err: Error) { +scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) { err = .None in_cdata := false @@ -238,7 +238,7 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close } case '\n': - if !in_cdata { + if !(multiline || in_cdata) { error(t, offset, string(t.src[offset : t.offset])) error(t, offset, "[scan_string] Not terminated\n") err = .Invalid_Tag_Value @@ -256,7 +256,22 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close advance_rune(t) } + /* + Strip trailing whitespace. + */ lit := string(t.src[offset : t.offset]) + + end := len(lit) + eat: for ; end > 0; end -= 1 { + ch := lit[end - 1] + switch ch { + case ' ', '\t', '\r', '\n': + case: + break eat + } + } + lit = lit[:end] + if consume_close { advance_rune(t) } @@ -307,7 +322,7 @@ scan :: proc(t: ^Tokenizer) -> Token { case ':': kind = .Colon case '"', '\'': - lit, err = scan_string(t, t.offset, ch, true) + lit, err = scan_string(t, t.offset, ch, true, false) if err == .None { kind = .String } else { From ec63d0bbd21aa3d3f33cd762bd656ea8eb0af4a6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 15:30:36 +0100 Subject: [PATCH 0008/1052] [xml] Robustness improvement. Can now parse https://www.w3.org/2003/entities/2007xml/unicode.xml no problem. --- core/encoding/xml/debug_print.odin | 4 ++ core/encoding/xml/xml_reader.odin | 73 ++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index 65b71e30b..e6a8c9433 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -36,6 +36,10 @@ print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error } } + for comment in doc.comments { + written += wprintf(writer, "[Pre-root comment] %v\n", comment) + } + if doc.root != nil { wprintln(writer, " --- ") print_element(writer, doc.root) diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 34f6e65d0..b2226e6b9 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -86,10 +86,16 @@ Document :: struct { /* We only scan the . The grammar does not allow a comment to end in ---> */ - if doc.root == nil { - return doc, .Comment_Before_Root_Element - } - expect(t, .Dash) offset := t.offset @@ -329,12 +339,17 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err } if .Intern_Comments in opts.flags { - el := new(Element) + comment := strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) - el.parent = element - el.kind = .Comment - el.value = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) - append(&element.children, el) + if doc.root == nil { + append(&doc.comments, comment) + } else { + el := new(Element) + el.parent = element + el.kind = .Comment + el.value = comment + append(&element.children, el) + } } expect(t, .Dash) @@ -350,6 +365,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err e.g. `, which means this is an 'empty' or self-closing tag. */ end_token := scan(t) - #partial switch end_token.kind { case .Gt: /* @@ -394,9 +409,12 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err case .Slash: /* - Empty tag? + Empty tag. Close it. */ expect(t, .Gt) or_return + parent = element.parent + element = parent + tag_is_open = false case: error(t, t.offset, "Expected close tag, got: %#v\n", end_token) @@ -411,25 +429,33 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err _ = expect(t, .Gt) or_return if element.ident != ident.text { - error(t, t.offset, "Mismatched Closing Tag: %v\n", ident.text) + error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", element.ident, ident.text) return doc, .Mismatched_Closing_Tag } - parent = element.parent - element = parent + parent = element.parent + element = parent + tag_is_open = false case: error(t, t.offset, "Invalid Token after <: %#v\n", open) return } - case .EOF: + case -1: + /* + End of file. + */ + if tag_is_open { + return doc, .Premature_EOF + } break loop case: /* This should be a tag's body text. */ - element.value = scan_string(t, tok.pos.offset) or_return + body_text := scan_string(t, t.offset) or_return + element.value = strings.intern_get(&doc.intern, body_text) } } @@ -480,6 +506,7 @@ destroy :: proc(doc: ^Document) { strings.intern_destroy(&doc.intern) delete(doc.prolog) + delete(doc.comments) free(doc) } From beff90e1d12391e63cd1119023f8565eda97593e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 18:02:48 +0100 Subject: [PATCH 0009/1052] [xml] Slight optimization. About a 5% speed bump. More rigorous optimization later. --- core/encoding/xml/tokenizer.odin | 62 ++++++++++++++++++------------- core/encoding/xml/xml_reader.odin | 4 +- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index e453552b8..9247d2531 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -110,44 +110,51 @@ error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { t.error_count += 1 } +@(optimization_mode="speed") advance_rune :: proc(using t: ^Tokenizer) { - if read_offset < len(src) { - offset = read_offset - if ch == '\n' { - line_offset = offset - line_count += 1 - } - r, w := rune(src[read_offset]), 1 - switch { - case r == 0: - error(t, t.offset, "illegal character NUL") - case r >= utf8.RUNE_SELF: - r, w = utf8.decode_rune_in_string(src[read_offset:]) - if r == utf8.RUNE_ERROR && w == 1 { - error(t, t.offset, "illegal UTF-8 encoding") - } else if r == utf8.RUNE_BOM && offset > 0 { - error(t, t.offset, "illegal byte order mark") + #no_bounds_check { + /* + Already bounds-checked here. + */ + if read_offset < len(src) { + offset = read_offset + if ch == '\n' { + line_offset = offset + line_count += 1 } + r, w := rune(src[read_offset]), 1 + switch { + case r == 0: + error(t, t.offset, "illegal character NUL") + case r >= utf8.RUNE_SELF: + r, w = #force_inline utf8.decode_rune_in_string(src[read_offset:]) + if r == utf8.RUNE_ERROR && w == 1 { + error(t, t.offset, "illegal UTF-8 encoding") + } else if r == utf8.RUNE_BOM && offset > 0 { + error(t, t.offset, "illegal byte order mark") + } + } + read_offset += w + ch = r + } else { + offset = len(src) + if ch == '\n' { + line_offset = offset + line_count += 1 + } + ch = -1 } - read_offset += w - ch = r - } else { - offset = len(src) - if ch == '\n' { - line_offset = offset - line_count += 1 - } - ch = -1 } } peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte { if t.read_offset+offset < len(t.src) { - return t.src[t.read_offset+offset] + #no_bounds_check return t.src[t.read_offset+offset] } return 0 } +@(optimization_mode="speed") skip_whitespace :: proc(t: ^Tokenizer) { for { switch t.ch { @@ -159,6 +166,7 @@ skip_whitespace :: proc(t: ^Tokenizer) { } } +@(optimization_mode="speed") is_letter :: proc(r: rune) -> bool { if r < utf8.RUNE_SELF { switch r { @@ -177,6 +185,7 @@ is_valid_identifier_rune :: proc(r: rune) -> bool { case '_', '-', ':': return true case 'A'..='Z', 'a'..='z': return true case '0'..'9': return true + case -1: return false } } @@ -205,6 +214,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string { return string(t.src[offset : t.offset]) } +@(optimization_mode="speed") scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) { err = .None in_cdata := false diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index b2226e6b9..35dd83b3f 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -239,7 +239,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err /* Consume peeked `<` */ - tok := scan(t) + advance_rune(t) open := scan(t) #partial switch open.kind { @@ -265,7 +265,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err skip_element(t) or_return } case: - error(t, t.offset, "Expected \" Date: Wed, 1 Dec 2021 22:01:19 +0100 Subject: [PATCH 0010/1052] [xml] Improve CDATA + comment handling in tag body. --- core/encoding/xml/tokenizer.odin | 117 ++++++++++++++++++++++++------ core/encoding/xml/xml_reader.odin | 36 +-------- 2 files changed, 96 insertions(+), 57 deletions(-) diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 9247d2531..95024518d 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -46,8 +46,11 @@ Token_Kind :: enum { EOF, } -CDATA_START :: "" +CDATA_START :: "" + +COMMENT_START :: "" Tokenizer :: struct { // Immutable data @@ -214,10 +217,83 @@ scan_identifier :: proc(t: ^Tokenizer) -> string { return string(t.src[offset : t.offset]) } +/* + A comment ends when we see -->, preceded by a character that's not a dash. + "For compatibility, the string "--" (double-hyphen) must not occur within comments." + + See: https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-comment + + Thanks to the length (4) of the comment start, we also have enough lookback, + and the peek at the next byte asserts that there's at least one more character + that's a `>`. +*/ +scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) { + offset := t.offset + + for { + advance_rune(t) + ch := t.ch + + if ch < 0 { + error(t, offset, "[parse] Comment was not terminated\n") + return "", .Unclosed_Comment + } + + if string(t.src[t.offset - 1:][:2]) == "--" { + if peek_byte(t) == '>' { + break + } else { + error(t, t.offset - 1, "Invalid -- sequence in comment.\n") + return "", .Invalid_Sequence_In_Comment + } + } + } + + expect(t, .Dash) + expect(t, .Gt) + + return string(t.src[offset : t.offset - 1]), .None +} + +/* + Skip CDATA +*/ +skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { + if t.read_offset + len(CDATA_START) >= len(t.src) { + /* + Can't be the start of a CDATA tag. + */ + return .None + } + + if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { + t.read_offset += len(CDATA_START) + offset := t.offset + + cdata_scan: for { + advance_rune(t) + if t.ch < 0 { + error(t, offset, "[scan_string] CDATA was not terminated\n") + return .Premature_EOF + } + + /* + Scan until the end of a CDATA tag. + */ + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + t.read_offset += len(CDATA_END) + break cdata_scan + } + } + } + } + return +} + @(optimization_mode="speed") scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) { err = .None - in_cdata := false loop: for { ch := t.ch @@ -228,27 +304,23 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close return "", .Premature_EOF case '<': - /* - Might be the start of a CDATA tag. - */ - if t.read_offset + len(CDATA_START) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { - in_cdata = true - } - } - - case ']': - /* - Might be the end of a CDATA tag. - */ - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - in_cdata = false + if peek_byte(t) == '!' { + if peek_byte(t, 1) == '[' { + /* + Might be the start of a CDATA tag. + */ + skip_cdata(t) or_return + } else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' { + /* + Comment start. Eat comment. + */ + t.read_offset += 3 + _ = scan_comment(t) or_return } } case '\n': - if !(multiline || in_cdata) { + if !multiline { error(t, offset, string(t.src[offset : t.offset])) error(t, offset, "[scan_string] Not terminated\n") err = .Invalid_Tag_Value @@ -256,13 +328,12 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close } } - if ch == close && !in_cdata { + if t.ch == close { /* - If it's not a CDATA tag, it's the end of this body. + If it's not a CDATA or comment, it's the end of this body. */ break loop } - advance_rune(t) } diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 35dd83b3f..146c278cb 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -307,39 +307,10 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err The grammar does not allow a comment to end in ---> */ expect(t, .Dash) - offset := t.offset - - for { - advance_rune(t) - ch := t.ch - - /* - A comment ends when we see -->, preceded by a character that's not a dash. - "For compatibility, the string "--" (double-hyphen) must not occur within comments." - - See: https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-comment - - Thanks to the length (4) of the comment start, we also have enough lookback, - and the peek at the next byte asserts that there's at least one more character - that's a `>`. - */ - if ch < 0 { - error(t, offset, "[parse] Comment was not terminated\n") - return doc, .Unclosed_Comment - } - - if string(t.src[t.offset - 1:][:2]) == "--" { - if peek_byte(t) == '>' { - break - } else { - error(t, t.offset - 1, "Invalid -- sequence in comment.\n") - return doc, .Invalid_Sequence_In_Comment - } - } - } + comment := scan_comment(t) or_return if .Intern_Comments in opts.flags { - comment := strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + comment = strings.intern_get(&doc.intern, comment) if doc.root == nil { append(&doc.comments, comment) @@ -352,9 +323,6 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err } } - expect(t, .Dash) - expect(t, .Gt) - case: error(t, t.offset, "Invalid Token after Date: Thu, 2 Dec 2021 18:00:29 +0100 Subject: [PATCH 0011/1052] [xml] Improvements. --- core/encoding/xml/example/xml_example.odin | 71 +++++++++++-------- core/encoding/xml/helpers.odin | 49 +++++++++++++ core/encoding/xml/tokenizer.odin | 6 +- core/encoding/xml/xml_reader.odin | 2 + tests/core/assets/XML/.gitignore | 2 + tests/core/assets/{xml => XML}/nl_NL-qt-ts.ts | 0 .../assets/{xml => XML}/nl_NL-xliff-1.0.xliff | 0 .../assets/{xml => XML}/nl_NL-xliff-2.0.xliff | 0 tests/core/assets/{xml => XML}/utf8.xml | 0 tests/core/download_assets.py | 43 ++++++++--- tests/core/encoding/xml/test_core_xml.odin | 10 +-- 11 files changed, 137 insertions(+), 46 deletions(-) create mode 100644 core/encoding/xml/helpers.odin create mode 100644 tests/core/assets/XML/.gitignore rename tests/core/assets/{xml => XML}/nl_NL-qt-ts.ts (100%) rename tests/core/assets/{xml => XML}/nl_NL-xliff-1.0.xliff (100%) rename tests/core/assets/{xml => XML}/nl_NL-xliff-2.0.xliff (100%) rename tests/core/assets/{xml => XML}/utf8.xml (100%) diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 82938c223..085252e92 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -1,45 +1,55 @@ package xml_example import "core:encoding/xml" +import "core:os" +import "core:path" import "core:mem" -import "core:strings" import "core:fmt" -Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) { +/* + Silent error handler for the parser. +*/ +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} -} +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } -FILENAME :: "../../../../tests/core/assets/xml/nl_NL-xliff-1.0.xliff" -DOC :: #load(FILENAME) - -OPTIONS :: xml.Options{ - flags = { - .Ignore_Unsupported, .Intern_Comments, - }, - expected_doctype = "", -} - -_main :: proc() { +example :: proc() { using fmt - println("--- DOCUMENT TO PARSE ---") - println(string(DOC)) - println("--- /DOCUMENT TO PARSE ---\n") + filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml") + defer delete(filename) - doc, err := xml.parse(DOC, OPTIONS, FILENAME, Error_Handler) + doc, err := xml.parse(filename, OPTIONS, Error_Handler) defer xml.destroy(doc) - buf: strings.Builder - defer strings.destroy_builder(&buf) - w := strings.to_writer(&buf) - - xml.print(w, doc) - println(strings.to_string(buf)) - if err != .None { - printf("Parse error: %v\n", err) - } else { - println("DONE!") + printf("Load/Parse error: %v\n", err) + if err == .File_Error { + printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) + } + os.exit(1) + } + + printf("\"%v\" loaded and parsed.\n", filename) + + charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") + if !charlist_ok { + eprintln("Could not locate top-level `` tag.") + os.exit(1) + } + + printf("Found `` with %v children.\n", len(charlist.children)) + + for char in charlist.children { + if char.ident != "character" { + eprintf("Expected ``, got `<%v>`\n", char.ident) + os.exit(1) + } + + if _, ok := xml.find_attribute_val_by_key(char, "dec"); !ok { + eprintln("`` attribute not found.") + os.exit(1) + } } } @@ -50,12 +60,13 @@ main :: proc() { mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) - _main() + example() if len(track.allocation_map) > 0 { println() for _, v in track.allocation_map { printf("%v Leaked %v bytes.\n", v.location, v.size) } - } + } + println("Done and cleaned up!") } \ No newline at end of file diff --git a/core/encoding/xml/helpers.odin b/core/encoding/xml/helpers.odin new file mode 100644 index 000000000..14597ddbd --- /dev/null +++ b/core/encoding/xml/helpers.odin @@ -0,0 +1,49 @@ +package xml +/* + An XML 1.0 / 1.1 parser + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + This file contains helper functions. +*/ + + +/* + Find `tag`'s nth child with a given ident. +*/ +find_child_by_ident :: proc(tag: ^Element, ident: string, nth := 0) -> (res: ^Element, found: bool) { + if tag == nil { return nil, false } + + count := 0 + for child in tag.children { + /* + Skip commments. They have no name. + */ + if child.kind != .Element { continue } + + /* + If the ident matches and it's the nth such child, return it. + */ + if child.ident == ident { + if count == nth { return child, true } + count += 1 + } + } + return nil, false +} + +/* + Find an attribute by key. +*/ +find_attribute_val_by_key :: proc(tag: ^Element, key: string) -> (val: string, found: bool) { + if tag == nil { return "", false } + + for attr in tag.attribs { + /* + If the ident matches, we're done. There can only ever be one attribute with the same name. + */ + if attr.key == key { return attr.val, true } + } + return "", false +} \ No newline at end of file diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 95024518d..2da3b7683 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -403,11 +403,11 @@ scan :: proc(t: ^Tokenizer) -> Token { case ':': kind = .Colon case '"', '\'': + kind = .Invalid + lit, err = scan_string(t, t.offset, ch, true, false) if err == .None { kind = .String - } else { - kind = .Invalid } case '\n': @@ -418,7 +418,7 @@ scan :: proc(t: ^Tokenizer) -> Token { } } - if lit == "" { + if kind != .String && lit == "" { lit = string(t.src[offset : t.offset]) } return Token{kind, lit, pos} diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 146c278cb..563294309 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -519,6 +519,8 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) _ = expect(t, .Eq) or_return value := expect(t, .String) or_return + error(t, t.offset, "String: %v\n", value) + attr.key = strings.intern_get(&doc.intern, key.text) attr.val = strings.intern_get(&doc.intern, value.text) diff --git a/tests/core/assets/XML/.gitignore b/tests/core/assets/XML/.gitignore new file mode 100644 index 000000000..32dc58b57 --- /dev/null +++ b/tests/core/assets/XML/.gitignore @@ -0,0 +1,2 @@ +# This file will be downloaded by download_assets.py +unicode.xml \ No newline at end of file diff --git a/tests/core/assets/xml/nl_NL-qt-ts.ts b/tests/core/assets/XML/nl_NL-qt-ts.ts similarity index 100% rename from tests/core/assets/xml/nl_NL-qt-ts.ts rename to tests/core/assets/XML/nl_NL-qt-ts.ts diff --git a/tests/core/assets/xml/nl_NL-xliff-1.0.xliff b/tests/core/assets/XML/nl_NL-xliff-1.0.xliff similarity index 100% rename from tests/core/assets/xml/nl_NL-xliff-1.0.xliff rename to tests/core/assets/XML/nl_NL-xliff-1.0.xliff diff --git a/tests/core/assets/xml/nl_NL-xliff-2.0.xliff b/tests/core/assets/XML/nl_NL-xliff-2.0.xliff similarity index 100% rename from tests/core/assets/xml/nl_NL-xliff-2.0.xliff rename to tests/core/assets/XML/nl_NL-xliff-2.0.xliff diff --git a/tests/core/assets/xml/utf8.xml b/tests/core/assets/XML/utf8.xml similarity index 100% rename from tests/core/assets/xml/utf8.xml rename to tests/core/assets/XML/utf8.xml diff --git a/tests/core/download_assets.py b/tests/core/download_assets.py index d86f7f1e7..831b5b13a 100644 --- a/tests/core/download_assets.py +++ b/tests/core/download_assets.py @@ -50,10 +50,7 @@ def try_download_file(url, out_file): print("Could not download", url) return 1 -def try_download_and_unpack_zip(suite): - url = ASSETS_BASE_URL.format(suite, "{}.zip".format(suite)) - out_file = DOWNLOAD_BASE_PATH.format(suite) + "/{}.zip".format(suite) - +def try_download_and_unpack_zip(url, out_file, extract_path): print("\tDownloading {} to {}.".format(url, out_file)) if try_download_file(url, out_file) is not None: @@ -65,7 +62,6 @@ def try_download_and_unpack_zip(suite): with zipfile.ZipFile(out_file) as z: for file in z.filelist: filename = file.filename - extract_path = DOWNLOAD_BASE_PATH.format(suite) print("\t\tExtracting: {}".format(filename)) z.extract(file, extract_path) @@ -73,25 +69,56 @@ def try_download_and_unpack_zip(suite): print("Could not extract ZIP file") return 2 +def download_png_assets(): + suite = "PNG" + url = ASSETS_BASE_URL.format(suite, "{}.zip".format(suite)) + out_file = DOWNLOAD_BASE_PATH.format(suite) + "/{}.zip".format(suite) + extract_path = DOWNLOAD_BASE_PATH.format(suite) -def main(): print("Downloading PNG assets") # Make PNG assets path try: - path = DOWNLOAD_BASE_PATH.format("PNG") + path = DOWNLOAD_BASE_PATH.format(suite) os.makedirs(path) except FileExistsError: pass # Try downloading and unpacking the PNG assets - r = try_download_and_unpack_zip("PNG") + r = try_download_and_unpack_zip(url, out_file, extract_path) if r is not None: return r # We could fall back on downloading the PNG files individually, but it's slow print("Done downloading PNG assets") + +def download_unicode_assets(): + suite = "XML" + url = "https://www.w3.org/2003/entities/2007xml/unicode.xml.zip" + out_file = DOWNLOAD_BASE_PATH.format(suite) + "/{}.zip".format(suite) + extract_path = DOWNLOAD_BASE_PATH.format(suite) + + print("Downloading {}.".format(url)) + + # Make XML assets path + try: + path = DOWNLOAD_BASE_PATH.format(suite) + os.makedirs(path) + except FileExistsError: + pass + + # Try downloading and unpacking the assets + r = try_download_and_unpack_zip(url, out_file, extract_path) + if r is not None: + return r + + print("Done downloading Unicode/XML assets") + +def main(): + download_png_assets() + download_unicode_assets() + return 0 if __name__ == '__main__': diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 7eefac212..c2e0aa172 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -35,7 +35,7 @@ TESTS :: []TEST{ First we test that certain files parse without error. */ { - filename = "assets/xml/utf8.xml", + filename = "assets/XML/utf8.xml", options = OPTIONS, expected = { error = .None, @@ -45,7 +45,7 @@ TESTS :: []TEST{ }, }, { - filename = "assets/xml/nl_NL-qt-ts.ts", + filename = "assets/XML/nl_NL-qt-ts.ts", options = OPTIONS, expected = { error = .None, @@ -55,7 +55,7 @@ TESTS :: []TEST{ }, }, { - filename = "assets/xml/nl_NL-xliff-1.0.xliff", + filename = "assets/XML/nl_NL-xliff-1.0.xliff", options = OPTIONS, expected = { error = .None, @@ -65,7 +65,7 @@ TESTS :: []TEST{ }, }, { - filename = "assets/xml/nl_NL-xliff-2.0.xliff", + filename = "assets/XML/nl_NL-xliff-2.0.xliff", options = OPTIONS, expected = { error = .None, @@ -79,7 +79,7 @@ TESTS :: []TEST{ Then we test that certain errors are returned as expected. */ { - filename = "assets/xml/utf8.xml", + filename = "assets/XML/utf8.xml", options = { flags = { .Ignore_Unsupported, .Intern_Comments, From 2dd67dba89732b89adb0199bc0a99de4cbc34e8f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 2 Dec 2021 20:12:12 +0100 Subject: [PATCH 0012/1052] [core:encoding/entity] Add new package to decode &; entities. Includes generator to generate a lookup for named entitiess. --- core/encoding/entity/LICENSE_table.md | 21 + core/encoding/entity/entity.odin | 358 + .../entity/example/entity_example.odin | 122 + core/encoding/entity/example/test.html | 26 + core/encoding/entity/generated.odin | 7493 +++++++++++++++++ core/encoding/xml/xml_reader.odin | 2 - core/unicode/tools/generate_entity_table.odin | 287 + 7 files changed, 8307 insertions(+), 2 deletions(-) create mode 100644 core/encoding/entity/LICENSE_table.md create mode 100644 core/encoding/entity/entity.odin create mode 100644 core/encoding/entity/example/entity_example.odin create mode 100644 core/encoding/entity/example/test.html create mode 100644 core/encoding/entity/generated.odin create mode 100644 core/unicode/tools/generate_entity_table.odin diff --git a/core/encoding/entity/LICENSE_table.md b/core/encoding/entity/LICENSE_table.md new file mode 100644 index 000000000..51e3f34b5 --- /dev/null +++ b/core/encoding/entity/LICENSE_table.md @@ -0,0 +1,21 @@ +# License + +By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software Short Notice should be included (hypertext is preferred, text is permitted) within the body of any redistributed or derivative code. + +Notice of any changes or modifications to the files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.) + +# Disclaimers + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. + +# Notes +This version: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 \ No newline at end of file diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin new file mode 100644 index 000000000..e40896819 --- /dev/null +++ b/core/encoding/entity/entity.odin @@ -0,0 +1,358 @@ +package unicode_entity +/* + A unicode entity encoder/decoder + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + This code has several procedures to map unicode runes to/from different textual encodings. + - SGML/XML/HTML entity + -- &#; + -- &#x; + -- &; (If the lookup tables are compiled in). + Reference: https://www.w3.org/2003/entities/2007xml/unicode.xml + + - URL encode / decode %hex entity + Reference: https://datatracker.ietf.org/doc/html/rfc3986/#section-2.1 + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ + +import "core:unicode/utf8" +import "core:unicode" +import "core:strings" + +MAX_RUNE_CODEPOINT :: int(unicode.MAX_RUNE) + +write_rune :: strings.write_rune_builder +write_string :: strings.write_string_builder + +Error :: enum u8 { + None = 0, + Tokenizer_Is_Nil, + + Illegal_NUL_Character, + Illegal_UTF_Encoding, + Illegal_BOM, + + CDATA_Not_Terminated, + Comment_Not_Terminated, + Invalid_Entity_Encoding, +} + +Tokenizer :: struct { + r: rune, + w: int, + + src: string, + offset: int, + read_offset: int, +} + +CDATA_START :: "" + +COMMENT_START :: "" + +/* + Default: CDATA and comments are passed through unchanged. +*/ +XML_Decode_Option :: enum u8 { + /* + CDATA is unboxed. + */ + CDATA_Unbox, + + /* + Unboxed CDATA is decoded as well. + Ignored if `.CDATA_Unbox` is not given. + */ + CDATA_Decode, + + /* + Comments are stripped. + */ + Comment_Strip, +} +XML_Decode_Options :: bit_set[XML_Decode_Option; u8] + +/* + Decode a string that may include SGML/XML/HTML entities. + The caller has to free the result. +*/ +decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) { + context.allocator = allocator + + l := len(input) + if l == 0 { return "", .None } + + builder := strings.make_builder() + defer strings.destroy_builder(&builder) + + t := Tokenizer{src=input} + in_data := false + + loop: for { + advance(&t) or_return + if t.r < 0 { break loop } + + /* + Below here we're never inside a CDATA tag. + At most we'll see the start of one, but that doesn't affect the logic. + */ + switch t.r { + case '<': + /* + Might be the start of a CDATA tag or comment. + + We don't need to check if we need to write a `<`, because if it isn't CDATA or a comment, + it couldn't have been part of an XML tag body to be decoded here. + */ + in_data = _handle_xml_special(&t, &builder, options) or_return + + case ']': + /* + If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag. + */ + if in_data { + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + in_data = false + t.read_offset += len(CDATA_END) - 1 + } + } + continue + } else { + write_rune(&builder, ']') + } + + case: + if in_data && .CDATA_Decode not_in options { + /* + Unboxed, but undecoded. + */ + write_rune(&builder, t.r) + continue + } + + if t.r == '&' { + if entity, entity_err := _extract_xml_entity(&t); entity_err != .None { + /* + We read to the end of the string without closing the entity. + Pass through as-is. + */ + write_string(&builder, entity) + } else { + if decoded, ok := xml_decode_entity(entity); ok { + write_rune(&builder, decoded) + } else { + /* + Decode failed. Pass through original. + */ + write_string(&builder, "&") + write_string(&builder, entity) + write_string(&builder, ";") + } + + } + } else { + write_rune(&builder, t.r) + } + } + } + + return strings.clone(strings.to_string(builder), allocator), err +} + +advance :: proc(t: ^Tokenizer) -> (err: Error) { + if t == nil { return .Tokenizer_Is_Nil } + using t + + #no_bounds_check { + if read_offset < len(src) { + offset = read_offset + r, w = rune(src[read_offset]), 1 + switch { + case r == 0: + return .Illegal_NUL_Character + case r >= utf8.RUNE_SELF: + r, w = utf8.decode_rune_in_string(src[read_offset:]) + if r == utf8.RUNE_ERROR && w == 1 { + return .Illegal_UTF_Encoding + } else if r == utf8.RUNE_BOM && offset > 0 { + return .Illegal_BOM + } + } + read_offset += w + return .None + } else { + offset = len(src) + r = -1 + return + } + } +} + +xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) { + entity := entity + if len(entity) == 0 { return -1, false } + + switch entity[0] { + case '#': + base := 10 + val := 0 + entity = entity[1:] + + if len(entity) == 0 { return -1, false } + + if entity[0] == 'x' || entity[0] == 'X' { + base = 16 + entity = entity[1:] + } + + for len(entity) > 0 { + r := entity[0] + switch r { + case '0'..'9': + val *= base + val += int(r - '0') + + case 'a'..'f': + if base == 10 { return -1, false } + val *= base + val += int(r - 'a' + 10) + + case 'A'..'F': + if base == 10 { return -1, false } + val *= base + val += int(r - 'A' + 10) + + case: + return -1, false + } + + if val > MAX_RUNE_CODEPOINT { return -1, false } + entity = entity[1:] + } + return rune(val), true + + case: + /* + Named entity. + */ + return named_xml_entity_to_rune(entity) + } +} + +/* + Private XML helper to extract `&;` entity. +*/ +@(private="file") +_extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) { + assert(t != nil && t.r == '&') + + /* + All of these would be in the ASCII range. + Even if one is not, it doesn't matter. All characters we need to compare to extract are. + */ + using t + + length := len(t.src) + found := false + + #no_bounds_check { + for read_offset < length { + if src[read_offset] == ';' { + found = true + read_offset += 1 + break + } + read_offset += 1 + } + } + + if found { + return string(src[offset + 1 : read_offset - 1]), .None + } + return string(src[offset : read_offset]), .Invalid_Entity_Encoding +} + +/* + Private XML helper for CDATA and comments. +*/ +@(private="file") +_handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) { + assert(t != nil && t.r == '<') + if t.read_offset + len(CDATA_START) >= len(t.src) { return false, .None } + + if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { + t.read_offset += len(CDATA_START) - 1 + + if .CDATA_Unbox in options && .CDATA_Decode in options { + /* + We're unboxing _and_ decoding CDATA + */ + return true, .None + } + + /* + CDATA is passed through. + */ + offset := t.offset + + /* + Scan until end of CDATA. + */ + for { + advance(t) or_return + if t.r < 0 { return true, .CDATA_Not_Terminated } + + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + t.read_offset += len(CDATA_END) - 1 + + cdata := string(t.src[offset : t.read_offset]) + + if .CDATA_Unbox in options { + cdata = cdata[len(CDATA_START):] + cdata = cdata[:len(cdata) - len(CDATA_END)] + } + + write_string(builder, cdata) + return false, .None + } + } + } + + } else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START { + t.read_offset += len(COMMENT_START) + /* + Comment is passed through by default. + */ + offset := t.offset + + /* + Scan until end of Comment. + */ + for { + advance(t) or_return + if t.r < 0 { return true, .Comment_Not_Terminated } + + if t.read_offset + len(COMMENT_END) < len(t.src) { + if string(t.src[t.offset:][:len(COMMENT_END)]) == COMMENT_END { + t.read_offset += len(COMMENT_END) - 1 + + if .Comment_Strip not_in options { + comment := string(t.src[offset : t.read_offset]) + write_string(builder, comment) + } + return false, .None + } + } + } + + } + return false, .None +} \ No newline at end of file diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin new file mode 100644 index 000000000..8758d9ad9 --- /dev/null +++ b/core/encoding/entity/example/entity_example.odin @@ -0,0 +1,122 @@ +package unicode_entity_example + +import "core:encoding/xml" +import "core:encoding/entity" +import "core:strings" +import "core:mem" +import "core:fmt" +import "core:time" + +OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", +} + +doc_print :: proc(doc: ^xml.Document) { + buf: strings.Builder + defer strings.destroy_builder(&buf) + w := strings.to_writer(&buf) + + xml.print(w, doc) + fmt.println(strings.to_string(buf)) +} + +_entities :: proc() { + doc: ^xml.Document + err: xml.Error + + DOC :: #load("../../../../tests/core/assets/XML/unicode.xml") + + parse_duration: time.Duration + + { + time.SCOPED_TICK_DURATION(&parse_duration) + doc, err = xml.parse(DOC, OPTIONS) + } + defer xml.destroy(doc) + + doc_print(doc) + + ms := time.duration_milliseconds(parse_duration) + + speed := (f64(1000.0) / ms) * f64(len(DOC)) / 1_024.0 / 1_024.0 + + fmt.printf("Parse time: %.2f ms (%.2f MiB/s).\n", ms, speed) + fmt.printf("Error: %v\n", err) +} + +_main :: proc() { + using fmt + + doc, err := xml.parse(#load("test.html")) + defer xml.destroy(doc) + doc_print(doc) + + if false { + val := doc.root.children[1].children[2].value + + println() + replaced, ok := entity.decode_xml(val) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("Passthrough: '%v'\nOK: %v\n", replaced, ok) + println() + } + + if false { + val := doc.root.children[1].children[2].value + + println() + replaced, ok := entity.decode_xml(val, { .CDATA_Unbox }) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("CDATA_Unbox: '%v'\nOK: %v\n", replaced, ok) + println() + } + + if true { + val := doc.root.children[1].children[2].value + + println() + replaced, ok := entity.decode_xml(val, { .CDATA_Unbox, .CDATA_Decode }) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("CDATA_Decode: '%v'\nOK: %v\n", replaced, ok) + println() + } + + if true { + val := doc.root.children[1].children[1].value + + println() + replaced, ok := entity.decode_xml(val, { .Comment_Strip }) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("Comment_Strip: '%v'\nOK: %v\n", replaced, ok) + println() + } +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + _main() + //_entities() + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } +} \ No newline at end of file diff --git a/core/encoding/entity/example/test.html b/core/encoding/entity/example/test.html new file mode 100644 index 000000000..60e32bf03 --- /dev/null +++ b/core/encoding/entity/example/test.html @@ -0,0 +1,26 @@ + + + Entity Reference Test + + + +

Entity Reference Test

+
+ Foozle]! © 42&;1234& +
+
+ Foozle]! © 42&;1234& +
+
+ | | | fj ` \ ® ϱ ∳ +
+ + \ No newline at end of file diff --git a/core/encoding/entity/generated.odin b/core/encoding/entity/generated.odin new file mode 100644 index 000000000..9afdcae6d --- /dev/null +++ b/core/encoding/entity/generated.odin @@ -0,0 +1,7493 @@ +package unicode_entity + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ + +/* + This file is generated from "https://www.w3.org/2003/entities/2007xml/unicode.xml". + + UPDATE: + - Ensure the XML file was downloaded using "tests\core\download_assets.py". + - Run "core/unicode/tools/generate_entity_table.odin" + + Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity + + Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology, + European Research Consortium for Informatics and Mathematics, Keio University, Beihang). + + All Rights Reserved. + + This work is distributed under the W3C® Software License [1] in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + [1] http://www.w3.org/Consortium/Legal/copyright-software + + See also: LICENSE_table.md +*/ + +// `<` +XML_NAME_TO_RUNE_MIN_LENGTH :: 2 +// `∳` +XML_NAME_TO_RUNE_MAX_LENGTH :: 31 + + +/* + Input: + entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML. + + Output: + "decoded" - The decoded rune if found by name, or -1 otherwise. + "ok" - true if found, false if not. + + IMPORTANT: XML processors (including browsers) treat these names as case-sensitive. So do we. +*/ +named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { + /* + Early out if the name is too short or too long. + min as a precaution in case the generated table has a bogus value. + */ + if len(name) < min(1, XML_NAME_TO_RUNE_MIN_LENGTH) || len(name) > XML_NAME_TO_RUNE_MAX_LENGTH { + return -1, false + } + + switch rune(name[0]) { + + case 'A': + switch name { + case "AElig": + // LATIN CAPITAL LETTER AE + return rune(0xc6), true + case "AMP": + // AMPERSAND + return rune(0x26), true + case "Aacgr": + // GREEK CAPITAL LETTER ALPHA WITH TONOS + return rune(0x0386), true + case "Aacute": + // LATIN CAPITAL LETTER A WITH ACUTE + return rune(0xc1), true + case "Abreve": + // LATIN CAPITAL LETTER A WITH BREVE + return rune(0x0102), true + case "Acirc": + // LATIN CAPITAL LETTER A WITH CIRCUMFLEX + return rune(0xc2), true + case "Acy": + // CYRILLIC CAPITAL LETTER A + return rune(0x0410), true + case "Afr": + // MATHEMATICAL FRAKTUR CAPITAL A + return rune(0x01d504), true + case "Agrave": + // LATIN CAPITAL LETTER A WITH GRAVE + return rune(0xc0), true + case "Agr": + // GREEK CAPITAL LETTER ALPHA + return rune(0x0391), true + case "Alpha": + // GREEK CAPITAL LETTER ALPHA + return rune(0x0391), true + case "Amacr": + // LATIN CAPITAL LETTER A WITH MACRON + return rune(0x0100), true + case "And": + // DOUBLE LOGICAL AND + return rune(0x2a53), true + case "Aogon": + // LATIN CAPITAL LETTER A WITH OGONEK + return rune(0x0104), true + case "Aopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL A + return rune(0x01d538), true + case "ApplyFunction": + // FUNCTION APPLICATION + return rune(0x2061), true + case "Aring": + // LATIN CAPITAL LETTER A WITH RING ABOVE + return rune(0xc5), true + case "Ascr": + // MATHEMATICAL SCRIPT CAPITAL A + return rune(0x01d49c), true + case "Assign": + // COLON EQUALS + return rune(0x2254), true + case "Ast": + // TWO ASTERISKS ALIGNED VERTICALLY + return rune(0x2051), true + case "Atilde": + // LATIN CAPITAL LETTER A WITH TILDE + return rune(0xc3), true + case "Auml": + // LATIN CAPITAL LETTER A WITH DIAERESIS + return rune(0xc4), true + } + + case 'B': + switch name { + case "Backslash": + // SET MINUS + return rune(0x2216), true + case "Barint": + // INTEGRAL WITH DOUBLE STROKE + return rune(0x2a0e), true + case "Barv": + // SHORT DOWN TACK WITH OVERBAR + return rune(0x2ae7), true + case "Barwedl": + // LOGICAL AND WITH DOUBLE OVERBAR + return rune(0x2a5e), true + case "Barwed": + // PERSPECTIVE + return rune(0x2306), true + case "Bcy": + // CYRILLIC CAPITAL LETTER BE + return rune(0x0411), true + case "Because": + // BECAUSE + return rune(0x2235), true + case "Bernoullis": + // SCRIPT CAPITAL B + return rune(0x212c), true + case "Beta": + // GREEK CAPITAL LETTER BETA + return rune(0x0392), true + case "Bfr": + // MATHEMATICAL FRAKTUR CAPITAL B + return rune(0x01d505), true + case "Bgr": + // GREEK CAPITAL LETTER BETA + return rune(0x0392), true + case "Bopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL B + return rune(0x01d539), true + case "Breve": + // BREVE + return rune(0x02d8), true + case "Bscr": + // SCRIPT CAPITAL B + return rune(0x212c), true + case "Bumpeq": + // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "Bvert": + // BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL + return rune(0x2506), true + } + + case 'C': + switch name { + case "CHcy": + // CYRILLIC CAPITAL LETTER CHE + return rune(0x0427), true + case "COPY": + // COPYRIGHT SIGN + return rune(0xa9), true + case "Cacute": + // LATIN CAPITAL LETTER C WITH ACUTE + return rune(0x0106), true + case "CapitalDifferentialD": + // DOUBLE-STRUCK ITALIC CAPITAL D + return rune(0x2145), true + case "Cap": + // DOUBLE INTERSECTION + return rune(0x22d2), true + case "Cayleys": + // BLACK-LETTER CAPITAL C + return rune(0x212d), true + case "Ccaron": + // LATIN CAPITAL LETTER C WITH CARON + return rune(0x010c), true + case "Ccedil": + // LATIN CAPITAL LETTER C WITH CEDILLA + return rune(0xc7), true + case "Ccirc": + // LATIN CAPITAL LETTER C WITH CIRCUMFLEX + return rune(0x0108), true + case "Cconint": + // VOLUME INTEGRAL + return rune(0x2230), true + case "Cdot": + // LATIN CAPITAL LETTER C WITH DOT ABOVE + return rune(0x010a), true + case "Cedilla": + // CEDILLA + return rune(0xb8), true + case "CenterDot": + // MIDDLE DOT + return rune(0xb7), true + case "Cfr": + // BLACK-LETTER CAPITAL C + return rune(0x212d), true + case "Chi": + // GREEK CAPITAL LETTER CHI + return rune(0x03a7), true + case "CircleDot": + // CIRCLED DOT OPERATOR + return rune(0x2299), true + case "CircleMinus": + // CIRCLED MINUS + return rune(0x2296), true + case "CirclePlus": + // CIRCLED PLUS + return rune(0x2295), true + case "CircleTimes": + // CIRCLED TIMES + return rune(0x2297), true + case "ClockwiseContourIntegral": + // CLOCKWISE CONTOUR INTEGRAL + return rune(0x2232), true + case "CloseCurlyDoubleQuote": + // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "CloseCurlyQuote": + // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "Colon": + // PROPORTION + return rune(0x2237), true + case "Colone": + // DOUBLE COLON EQUAL + return rune(0x2a74), true + case "Congruent": + // IDENTICAL TO + return rune(0x2261), true + case "Conint": + // SURFACE INTEGRAL + return rune(0x222f), true + case "ContourIntegral": + // CONTOUR INTEGRAL + return rune(0x222e), true + case "Copf": + // DOUBLE-STRUCK CAPITAL C + return rune(0x2102), true + case "Coproduct": + // N-ARY COPRODUCT + return rune(0x2210), true + case "CounterClockwiseContourIntegral": + // ANTICLOCKWISE CONTOUR INTEGRAL + return rune(0x2233), true + case "Cross": + // VECTOR OR CROSS PRODUCT + return rune(0x2a2f), true + case "Cscr": + // MATHEMATICAL SCRIPT CAPITAL C + return rune(0x01d49e), true + case "CupCap": + // EQUIVALENT TO + return rune(0x224d), true + case "Cup": + // DOUBLE UNION + return rune(0x22d3), true + } + + case 'D': + switch name { + case "DD": + // DOUBLE-STRUCK ITALIC CAPITAL D + return rune(0x2145), true + case "DDotrahd": + // RIGHTWARDS ARROW WITH DOTTED STEM + return rune(0x2911), true + case "DJcy": + // CYRILLIC CAPITAL LETTER DJE + return rune(0x0402), true + case "DScy": + // CYRILLIC CAPITAL LETTER DZE + return rune(0x0405), true + case "DZcy": + // CYRILLIC CAPITAL LETTER DZHE + return rune(0x040f), true + case "Dagger": + // DOUBLE DAGGER + return rune(0x2021), true + case "Darr": + // DOWNWARDS TWO HEADED ARROW + return rune(0x21a1), true + case "Dashv": + // VERTICAL BAR DOUBLE LEFT TURNSTILE + return rune(0x2ae4), true + case "Dcaron": + // LATIN CAPITAL LETTER D WITH CARON + return rune(0x010e), true + case "Dcy": + // CYRILLIC CAPITAL LETTER DE + return rune(0x0414), true + case "Del": + // NABLA + return rune(0x2207), true + case "Delta": + // GREEK CAPITAL LETTER DELTA + return rune(0x0394), true + case "Dfr": + // MATHEMATICAL FRAKTUR CAPITAL D + return rune(0x01d507), true + case "Dgr": + // GREEK CAPITAL LETTER DELTA + return rune(0x0394), true + case "DiacriticalAcute": + // ACUTE ACCENT + return rune(0xb4), true + case "DiacriticalDot": + // DOT ABOVE + return rune(0x02d9), true + case "DiacriticalDoubleAcute": + // DOUBLE ACUTE ACCENT + return rune(0x02dd), true + case "DiacriticalGrave": + // GRAVE ACCENT + return rune(0x60), true + case "DiacriticalTilde": + // SMALL TILDE + return rune(0x02dc), true + case "Diamond": + // DIAMOND OPERATOR + return rune(0x22c4), true + case "DifferentialD": + // DOUBLE-STRUCK ITALIC SMALL D + return rune(0x2146), true + case "Dopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL D + return rune(0x01d53b), true + case "Dot": + // DIAERESIS + return rune(0xa8), true + case "DotDot": + // COMBINING FOUR DOTS ABOVE + return rune(0x20dc), true + case "DotEqual": + // APPROACHES THE LIMIT + return rune(0x2250), true + case "DoubleContourIntegral": + // SURFACE INTEGRAL + return rune(0x222f), true + case "DoubleDot": + // DIAERESIS + return rune(0xa8), true + case "DoubleDownArrow": + // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "DoubleLeftArrow": + // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "DoubleLeftRightArrow": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "DoubleLeftTee": + // VERTICAL BAR DOUBLE LEFT TURNSTILE + return rune(0x2ae4), true + case "DoubleLongLeftArrow": + // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "DoubleLongLeftRightArrow": + // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "DoubleLongRightArrow": + // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "DoubleRightArrow": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "DoubleRightTee": + // TRUE + return rune(0x22a8), true + case "DoubleUpArrow": + // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "DoubleUpDownArrow": + // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "DoubleVerticalBar": + // PARALLEL TO + return rune(0x2225), true + case "DownArrowUpArrow": + // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + return rune(0x21f5), true + case "DownArrow": + // DOWNWARDS ARROW + return rune(0x2193), true + case "DownArrowBar": + // DOWNWARDS ARROW TO BAR + return rune(0x2913), true + case "DownBreve": + // COMBINING INVERTED BREVE + return rune(0x0311), true + case "DownLeftRightVector": + // LEFT BARB DOWN RIGHT BARB DOWN HARPOON + return rune(0x2950), true + case "DownLeftTeeVector": + // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295e), true + case "DownLeftVector": + // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "DownLeftVectorBar": + // LEFTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2956), true + case "DownRightTeeVector": + // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295f), true + case "DownRightVector": + // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "DownRightVectorBar": + // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2957), true + case "DownTeeArrow": + // DOWNWARDS ARROW FROM BAR + return rune(0x21a7), true + case "DownTee": + // DOWN TACK + return rune(0x22a4), true + case "Downarrow": + // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "Dscr": + // MATHEMATICAL SCRIPT CAPITAL D + return rune(0x01d49f), true + case "Dstrok": + // LATIN CAPITAL LETTER D WITH STROKE + return rune(0x0110), true + } + + case 'E': + switch name { + case "EEacgr": + // GREEK CAPITAL LETTER ETA WITH TONOS + return rune(0x0389), true + case "EEgr": + // GREEK CAPITAL LETTER ETA + return rune(0x0397), true + case "ENG": + // LATIN CAPITAL LETTER ENG + return rune(0x014a), true + case "ETH": + // LATIN CAPITAL LETTER ETH + return rune(0xd0), true + case "Eacgr": + // GREEK CAPITAL LETTER EPSILON WITH TONOS + return rune(0x0388), true + case "Eacute": + // LATIN CAPITAL LETTER E WITH ACUTE + return rune(0xc9), true + case "Ecaron": + // LATIN CAPITAL LETTER E WITH CARON + return rune(0x011a), true + case "Ecirc": + // LATIN CAPITAL LETTER E WITH CIRCUMFLEX + return rune(0xca), true + case "Ecy": + // CYRILLIC CAPITAL LETTER E + return rune(0x042d), true + case "Edot": + // LATIN CAPITAL LETTER E WITH DOT ABOVE + return rune(0x0116), true + case "Efr": + // MATHEMATICAL FRAKTUR CAPITAL E + return rune(0x01d508), true + case "Egrave": + // LATIN CAPITAL LETTER E WITH GRAVE + return rune(0xc8), true + case "Egr": + // GREEK CAPITAL LETTER EPSILON + return rune(0x0395), true + case "Element": + // ELEMENT OF + return rune(0x2208), true + case "Emacr": + // LATIN CAPITAL LETTER E WITH MACRON + return rune(0x0112), true + case "EmptySmallSquare": + // WHITE MEDIUM SQUARE + return rune(0x25fb), true + case "EmptyVerySmallSquare": + // WHITE SMALL SQUARE + return rune(0x25ab), true + case "Eogon": + // LATIN CAPITAL LETTER E WITH OGONEK + return rune(0x0118), true + case "Eopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL E + return rune(0x01d53c), true + case "Epsilon": + // GREEK CAPITAL LETTER EPSILON + return rune(0x0395), true + case "EqualTilde": + // MINUS TILDE + return rune(0x2242), true + case "Equal": + // TWO CONSECUTIVE EQUALS SIGNS + return rune(0x2a75), true + case "Equilibrium": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "Escr": + // SCRIPT CAPITAL E + return rune(0x2130), true + case "Esim": + // EQUALS SIGN ABOVE TILDE OPERATOR + return rune(0x2a73), true + case "Eta": + // GREEK CAPITAL LETTER ETA + return rune(0x0397), true + case "Euml": + // LATIN CAPITAL LETTER E WITH DIAERESIS + return rune(0xcb), true + case "Exists": + // THERE EXISTS + return rune(0x2203), true + case "ExponentialE": + // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true + } + + case 'F': + switch name { + case "Fcy": + // CYRILLIC CAPITAL LETTER EF + return rune(0x0424), true + case "Ffr": + // MATHEMATICAL FRAKTUR CAPITAL F + return rune(0x01d509), true + case "FilledSmallSquare": + // BLACK MEDIUM SQUARE + return rune(0x25fc), true + case "FilledVerySmallSquare": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "Fopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL F + return rune(0x01d53d), true + case "ForAll": + // FOR ALL + return rune(0x2200), true + case "Fouriertrf": + // SCRIPT CAPITAL F + return rune(0x2131), true + case "Fscr": + // SCRIPT CAPITAL F + return rune(0x2131), true + } + + case 'G': + switch name { + case "GJcy": + // CYRILLIC CAPITAL LETTER GJE + return rune(0x0403), true + case "GT": + // GREATER-THAN SIGN + return rune(0x3e), true + case "Game": + // TURNED SANS-SERIF CAPITAL G + return rune(0x2141), true + case "Gamma": + // GREEK CAPITAL LETTER GAMMA + return rune(0x0393), true + case "Gammad": + // GREEK LETTER DIGAMMA + return rune(0x03dc), true + case "Gbreve": + // LATIN CAPITAL LETTER G WITH BREVE + return rune(0x011e), true + case "Gcedil": + // LATIN CAPITAL LETTER G WITH CEDILLA + return rune(0x0122), true + case "Gcirc": + // LATIN CAPITAL LETTER G WITH CIRCUMFLEX + return rune(0x011c), true + case "Gcy": + // CYRILLIC CAPITAL LETTER GHE + return rune(0x0413), true + case "Gdot": + // LATIN CAPITAL LETTER G WITH DOT ABOVE + return rune(0x0120), true + case "Gfr": + // MATHEMATICAL FRAKTUR CAPITAL G + return rune(0x01d50a), true + case "Ggr": + // GREEK CAPITAL LETTER GAMMA + return rune(0x0393), true + case "Gg": + // VERY MUCH GREATER-THAN + return rune(0x22d9), true + case "Gopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL G + return rune(0x01d53e), true + case "GreaterEqual": + // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "GreaterEqualLess": + // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "GreaterFullEqual": + // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "GreaterGreater": + // DOUBLE NESTED GREATER-THAN + return rune(0x2aa2), true + case "GreaterLess": + // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "GreaterSlantEqual": + // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "GreaterTilde": + // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "Gscr": + // MATHEMATICAL SCRIPT CAPITAL G + return rune(0x01d4a2), true + case "Gt": + // MUCH GREATER-THAN + return rune(0x226b), true + } + + case 'H': + switch name { + case "HARDcy": + // CYRILLIC CAPITAL LETTER HARD SIGN + return rune(0x042a), true + case "Hacek": + // CARON + return rune(0x02c7), true + case "Hat": + // CIRCUMFLEX ACCENT + return rune(0x5e), true + case "Hcirc": + // LATIN CAPITAL LETTER H WITH CIRCUMFLEX + return rune(0x0124), true + case "Hfr": + // BLACK-LETTER CAPITAL H + return rune(0x210c), true + case "HilbertSpace": + // SCRIPT CAPITAL H + return rune(0x210b), true + case "Hopf": + // DOUBLE-STRUCK CAPITAL H + return rune(0x210d), true + case "HorizontalLine": + // BOX DRAWINGS LIGHT HORIZONTAL + return rune(0x2500), true + case "Hscr": + // SCRIPT CAPITAL H + return rune(0x210b), true + case "Hstrok": + // LATIN CAPITAL LETTER H WITH STROKE + return rune(0x0126), true + case "HumpDownHump": + // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "HumpEqual": + // DIFFERENCE BETWEEN + return rune(0x224f), true + } + + case 'I': + switch name { + case "IEcy": + // CYRILLIC CAPITAL LETTER IE + return rune(0x0415), true + case "IJlig": + // LATIN CAPITAL LIGATURE IJ + return rune(0x0132), true + case "IOcy": + // CYRILLIC CAPITAL LETTER IO + return rune(0x0401), true + case "Iacgr": + // GREEK CAPITAL LETTER IOTA WITH TONOS + return rune(0x038a), true + case "Iacute": + // LATIN CAPITAL LETTER I WITH ACUTE + return rune(0xcd), true + case "Icirc": + // LATIN CAPITAL LETTER I WITH CIRCUMFLEX + return rune(0xce), true + case "Icy": + // CYRILLIC CAPITAL LETTER I + return rune(0x0418), true + case "Idigr": + // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA + return rune(0x03aa), true + case "Idot": + // LATIN CAPITAL LETTER I WITH DOT ABOVE + return rune(0x0130), true + case "Ifr": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "Igrave": + // LATIN CAPITAL LETTER I WITH GRAVE + return rune(0xcc), true + case "Igr": + // GREEK CAPITAL LETTER IOTA + return rune(0x0399), true + case "Imacr": + // LATIN CAPITAL LETTER I WITH MACRON + return rune(0x012a), true + case "ImaginaryI": + // DOUBLE-STRUCK ITALIC SMALL I + return rune(0x2148), true + case "Implies": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "Im": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "Integral": + // INTEGRAL + return rune(0x222b), true + case "Int": + // DOUBLE INTEGRAL + return rune(0x222c), true + case "Intersection": + // N-ARY INTERSECTION + return rune(0x22c2), true + case "InvisibleComma": + // INVISIBLE SEPARATOR + return rune(0x2063), true + case "InvisibleTimes": + // INVISIBLE TIMES + return rune(0x2062), true + case "Iogon": + // LATIN CAPITAL LETTER I WITH OGONEK + return rune(0x012e), true + case "Iopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL I + return rune(0x01d540), true + case "Iota": + // GREEK CAPITAL LETTER IOTA + return rune(0x0399), true + case "Iscr": + // SCRIPT CAPITAL I + return rune(0x2110), true + case "Itilde": + // LATIN CAPITAL LETTER I WITH TILDE + return rune(0x0128), true + case "Iukcy": + // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I + return rune(0x0406), true + case "Iuml": + // LATIN CAPITAL LETTER I WITH DIAERESIS + return rune(0xcf), true + } + + case 'J': + switch name { + case "Jcirc": + // LATIN CAPITAL LETTER J WITH CIRCUMFLEX + return rune(0x0134), true + case "Jcy": + // CYRILLIC CAPITAL LETTER SHORT I + return rune(0x0419), true + case "Jfr": + // MATHEMATICAL FRAKTUR CAPITAL J + return rune(0x01d50d), true + case "Jopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL J + return rune(0x01d541), true + case "Jscr": + // MATHEMATICAL SCRIPT CAPITAL J + return rune(0x01d4a5), true + case "Jsercy": + // CYRILLIC CAPITAL LETTER JE + return rune(0x0408), true + case "Jukcy": + // CYRILLIC CAPITAL LETTER UKRAINIAN IE + return rune(0x0404), true + } + + case 'K': + switch name { + case "KHcy": + // CYRILLIC CAPITAL LETTER HA + return rune(0x0425), true + case "KHgr": + // GREEK CAPITAL LETTER CHI + return rune(0x03a7), true + case "KJcy": + // CYRILLIC CAPITAL LETTER KJE + return rune(0x040c), true + case "Kappa": + // GREEK CAPITAL LETTER KAPPA + return rune(0x039a), true + case "Kcedil": + // LATIN CAPITAL LETTER K WITH CEDILLA + return rune(0x0136), true + case "Kcy": + // CYRILLIC CAPITAL LETTER KA + return rune(0x041a), true + case "Kfr": + // MATHEMATICAL FRAKTUR CAPITAL K + return rune(0x01d50e), true + case "Kgr": + // GREEK CAPITAL LETTER KAPPA + return rune(0x039a), true + case "Kopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL K + return rune(0x01d542), true + case "Kscr": + // MATHEMATICAL SCRIPT CAPITAL K + return rune(0x01d4a6), true + } + + case 'L': + switch name { + case "LJcy": + // CYRILLIC CAPITAL LETTER LJE + return rune(0x0409), true + case "LT": + // LESS-THAN SIGN + return rune(0x3c), true + case "Lacute": + // LATIN CAPITAL LETTER L WITH ACUTE + return rune(0x0139), true + case "Lambda": + // GREEK CAPITAL LETTER LAMDA + return rune(0x039b), true + case "Lang": + // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET + return rune(0x27ea), true + case "Laplacetrf": + // SCRIPT CAPITAL L + return rune(0x2112), true + case "Larr": + // LEFTWARDS TWO HEADED ARROW + return rune(0x219e), true + case "Lcaron": + // LATIN CAPITAL LETTER L WITH CARON + return rune(0x013d), true + case "Lcedil": + // LATIN CAPITAL LETTER L WITH CEDILLA + return rune(0x013b), true + case "Lcy": + // CYRILLIC CAPITAL LETTER EL + return rune(0x041b), true + case "LeftAngleBracket": + // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "LeftArrowBar": + // LEFTWARDS ARROW TO BAR + return rune(0x21e4), true + case "LeftArrowRightArrow": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "LeftArrow": + // LEFTWARDS ARROW + return rune(0x2190), true + case "LeftCeiling": + // LEFT CEILING + return rune(0x2308), true + case "LeftDoubleBracket": + // MATHEMATICAL LEFT WHITE SQUARE BRACKET + return rune(0x27e6), true + case "LeftDownTeeVector": + // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2961), true + case "LeftDownVector": + // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "LeftDownVectorBar": + // DOWNWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2959), true + case "LeftFloor": + // LEFT FLOOR + return rune(0x230a), true + case "LeftRightArrow": + // LEFT RIGHT ARROW + return rune(0x2194), true + case "LeftRightVector": + // LEFT BARB UP RIGHT BARB UP HARPOON + return rune(0x294e), true + case "LeftTeeArrow": + // LEFTWARDS ARROW FROM BAR + return rune(0x21a4), true + case "LeftTeeVector": + // LEFTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295a), true + case "LeftTee": + // LEFT TACK + return rune(0x22a3), true + case "LeftTriangleBar": + // LEFT TRIANGLE BESIDE VERTICAL BAR + return rune(0x29cf), true + case "LeftTriangle": + // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "LeftTriangleEqual": + // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "LeftUpDownVector": + // UP BARB LEFT DOWN BARB LEFT HARPOON + return rune(0x2951), true + case "LeftUpTeeVector": + // UPWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2960), true + case "LeftUpVector": + // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "LeftUpVectorBar": + // UPWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2958), true + case "LeftVector": + // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "LeftVectorBar": + // LEFTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2952), true + case "Leftarrow": + // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "Leftrightarrow": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "LessEqualGreater": + // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "LessFullEqual": + // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "LessGreater": + // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "LessLess": + // DOUBLE NESTED LESS-THAN + return rune(0x2aa1), true + case "LessSlantEqual": + // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "LessTilde": + // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "Lfr": + // MATHEMATICAL FRAKTUR CAPITAL L + return rune(0x01d50f), true + case "Lgr": + // GREEK CAPITAL LETTER LAMDA + return rune(0x039b), true + case "Lleftarrow": + // LEFTWARDS TRIPLE ARROW + return rune(0x21da), true + case "Ll": + // VERY MUCH LESS-THAN + return rune(0x22d8), true + case "Lmidot": + // LATIN CAPITAL LETTER L WITH MIDDLE DOT + return rune(0x013f), true + case "LongLeftArrow": + // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "LongLeftRightArrow": + // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "LongRightArrow": + // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "Longleftarrow": + // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "Longleftrightarrow": + // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "Longrightarrow": + // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "Lopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL L + return rune(0x01d543), true + case "LowerLeftArrow": + // SOUTH WEST ARROW + return rune(0x2199), true + case "LowerRightArrow": + // SOUTH EAST ARROW + return rune(0x2198), true + case "Lscr": + // SCRIPT CAPITAL L + return rune(0x2112), true + case "Lsh": + // UPWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b0), true + case "Lstrok": + // LATIN CAPITAL LETTER L WITH STROKE + return rune(0x0141), true + case "Ltbar": + // DOUBLE NESTED LESS-THAN WITH UNDERBAR + return rune(0x2aa3), true + case "Lt": + // MUCH LESS-THAN + return rune(0x226a), true + } + + case 'M': + switch name { + case "Mapfrom": + // LEFTWARDS DOUBLE ARROW FROM BAR + return rune(0x2906), true + case "Mapto": + // RIGHTWARDS DOUBLE ARROW FROM BAR + return rune(0x2907), true + case "Map": + // RIGHTWARDS TWO-HEADED ARROW FROM BAR + return rune(0x2905), true + case "Mcy": + // CYRILLIC CAPITAL LETTER EM + return rune(0x041c), true + case "MediumSpace": + // MEDIUM MATHEMATICAL SPACE + return rune(0x205f), true + case "Mellintrf": + // SCRIPT CAPITAL M + return rune(0x2133), true + case "Mfr": + // MATHEMATICAL FRAKTUR CAPITAL M + return rune(0x01d510), true + case "Mgr": + // GREEK CAPITAL LETTER MU + return rune(0x039c), true + case "MinusPlus": + // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "Mopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL M + return rune(0x01d544), true + case "Mscr": + // SCRIPT CAPITAL M + return rune(0x2133), true + case "Mu": + // GREEK CAPITAL LETTER MU + return rune(0x039c), true + } + + case 'N': + switch name { + case "NJcy": + // CYRILLIC CAPITAL LETTER NJE + return rune(0x040a), true + case "Nacute": + // LATIN CAPITAL LETTER N WITH ACUTE + return rune(0x0143), true + case "Ncaron": + // LATIN CAPITAL LETTER N WITH CARON + return rune(0x0147), true + case "Ncedil": + // LATIN CAPITAL LETTER N WITH CEDILLA + return rune(0x0145), true + case "Ncy": + // CYRILLIC CAPITAL LETTER EN + return rune(0x041d), true + case "NegativeMediumSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeThickSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeThinSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeVeryThinSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NestedGreaterGreater": + // MUCH GREATER-THAN + return rune(0x226b), true + case "NestedLessLess": + // MUCH LESS-THAN + return rune(0x226a), true + case "NewLine": + // LINE FEED (LF) + return rune(0x0a), true + case "Nfr": + // MATHEMATICAL FRAKTUR CAPITAL N + return rune(0x01d511), true + case "Ngr": + // GREEK CAPITAL LETTER NU + return rune(0x039d), true + case "NoBreak": + // WORD JOINER + return rune(0x2060), true + case "NonBreakingSpace": + // NO-BREAK SPACE + return rune(0xa0), true + case "Nopf": + // DOUBLE-STRUCK CAPITAL N + return rune(0x2115), true + case "NotDoubleVerticalBar": + // NOT PARALLEL TO + return rune(0x2226), true + case "NotElement": + // NOT AN ELEMENT OF + return rune(0x2209), true + case "NotEqualTilde": + // MINUS TILDE with slash + return rune(0x2242), true + case "NotEqual": + // NOT EQUAL TO + return rune(0x2260), true + case "NotExists": + // THERE DOES NOT EXIST + return rune(0x2204), true + case "NotHumpDownHump": + // GEOMETRICALLY EQUIVALENT TO with slash + return rune(0x224e), true + case "NotHumpEqual": + // DIFFERENCE BETWEEN with slash + return rune(0x224f), true + case "NotLessGreater": + // NEITHER LESS-THAN NOR GREATER-THAN + return rune(0x2278), true + case "NotReverseElement": + // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "NotTilde": + // NOT TILDE + return rune(0x2241), true + case "NotTildeEqual": + // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "NotTildeFullEqual": + // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + return rune(0x2247), true + case "NotTildeTilde": + // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "NotVerticalBar": + // DOES NOT DIVIDE + return rune(0x2224), true + case "Not": + // DOUBLE STROKE NOT SIGN + return rune(0x2aec), true + case "NotCongruent": + // NOT IDENTICAL TO + return rune(0x2262), true + case "NotCupCap": + // NOT EQUIVALENT TO + return rune(0x226d), true + case "NotGreaterFullEqual": + // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "NotGreaterGreater": + // MUCH GREATER THAN with slash + return rune(0x226b), true + case "NotGreaterSlantEqual": + // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "NotGreater": + // NOT GREATER-THAN + return rune(0x226f), true + case "NotGreaterEqual": + // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "NotGreaterLess": + // NEITHER GREATER-THAN NOR LESS-THAN + return rune(0x2279), true + case "NotGreaterTilde": + // NEITHER GREATER-THAN NOR EQUIVALENT TO + return rune(0x2275), true + case "NotLeftTriangleBar": + // LEFT TRIANGLE BESIDE VERTICAL BAR with slash + return rune(0x29cf), true + case "NotLeftTriangle": + // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "NotLeftTriangleEqual": + // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "NotLessLess": + // MUCH LESS THAN with slash + return rune(0x226a), true + case "NotLessSlantEqual": + // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "NotLess": + // NOT LESS-THAN + return rune(0x226e), true + case "NotLessEqual": + // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "NotLessTilde": + // NEITHER LESS-THAN NOR EQUIVALENT TO + return rune(0x2274), true + case "NotNestedGreaterGreater": + // DOUBLE NESTED GREATER-THAN with slash + return rune(0x2aa2), true + case "NotNestedLessLess": + // DOUBLE NESTED LESS-THAN with slash + return rune(0x2aa1), true + case "NotPrecedesEqual": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "NotPrecedes": + // DOES NOT PRECEDE + return rune(0x2280), true + case "NotPrecedesSlantEqual": + // DOES NOT PRECEDE OR EQUAL + return rune(0x22e0), true + case "NotRightTriangleBar": + // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash + return rune(0x29d0), true + case "NotRightTriangle": + // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "NotRightTriangleEqual": + // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "NotSquareSubset": + // SQUARE IMAGE OF with slash + return rune(0x228f), true + case "NotSquareSubsetEqual": + // NOT SQUARE IMAGE OF OR EQUAL TO + return rune(0x22e2), true + case "NotSquareSuperset": + // SQUARE ORIGINAL OF with slash + return rune(0x2290), true + case "NotSquareSupersetEqual": + // NOT SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x22e3), true + case "NotSubset": + // SUBSET OF with vertical line + return rune(0x2282), true + case "NotSubsetEqual": + // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "NotSucceedsEqual": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "NotSucceedsTilde": + // SUCCEEDS OR EQUIVALENT TO with slash + return rune(0x227f), true + case "NotSucceeds": + // DOES NOT SUCCEED + return rune(0x2281), true + case "NotSucceedsSlantEqual": + // DOES NOT SUCCEED OR EQUAL + return rune(0x22e1), true + case "NotSuperset": + // SUPERSET OF with vertical line + return rune(0x2283), true + case "NotSupersetEqual": + // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "Nscr": + // MATHEMATICAL SCRIPT CAPITAL N + return rune(0x01d4a9), true + case "Ntilde": + // LATIN CAPITAL LETTER N WITH TILDE + return rune(0xd1), true + case "Nu": + // GREEK CAPITAL LETTER NU + return rune(0x039d), true + } + + case 'O': + switch name { + case "OElig": + // LATIN CAPITAL LIGATURE OE + return rune(0x0152), true + case "OHacgr": + // GREEK CAPITAL LETTER OMEGA WITH TONOS + return rune(0x038f), true + case "OHgr": + // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "Oacgr": + // GREEK CAPITAL LETTER OMICRON WITH TONOS + return rune(0x038c), true + case "Oacute": + // LATIN CAPITAL LETTER O WITH ACUTE + return rune(0xd3), true + case "Ocirc": + // LATIN CAPITAL LETTER O WITH CIRCUMFLEX + return rune(0xd4), true + case "Ocy": + // CYRILLIC CAPITAL LETTER O + return rune(0x041e), true + case "Odblac": + // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE + return rune(0x0150), true + case "Ofr": + // MATHEMATICAL FRAKTUR CAPITAL O + return rune(0x01d512), true + case "Ograve": + // LATIN CAPITAL LETTER O WITH GRAVE + return rune(0xd2), true + case "Ogr": + // GREEK CAPITAL LETTER OMICRON + return rune(0x039f), true + case "Omacr": + // LATIN CAPITAL LETTER O WITH MACRON + return rune(0x014c), true + case "Omega": + // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "Omicron": + // GREEK CAPITAL LETTER OMICRON + return rune(0x039f), true + case "Oopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL O + return rune(0x01d546), true + case "OpenCurlyDoubleQuote": + // LEFT DOUBLE QUOTATION MARK + return rune(0x201c), true + case "OpenCurlyQuote": + // LEFT SINGLE QUOTATION MARK + return rune(0x2018), true + case "Or": + // DOUBLE LOGICAL OR + return rune(0x2a54), true + case "Oscr": + // MATHEMATICAL SCRIPT CAPITAL O + return rune(0x01d4aa), true + case "Oslash": + // LATIN CAPITAL LETTER O WITH STROKE + return rune(0xd8), true + case "Otilde": + // LATIN CAPITAL LETTER O WITH TILDE + return rune(0xd5), true + case "Otimes": + // MULTIPLICATION SIGN IN DOUBLE CIRCLE + return rune(0x2a37), true + case "Ouml": + // LATIN CAPITAL LETTER O WITH DIAERESIS + return rune(0xd6), true + case "OverBar": + // OVERLINE + return rune(0x203e), true + case "OverBrace": + // TOP CURLY BRACKET + return rune(0x23de), true + case "OverBracket": + // TOP SQUARE BRACKET + return rune(0x23b4), true + case "OverParenthesis": + // TOP PARENTHESIS + return rune(0x23dc), true + } + + case 'P': + switch name { + case "PHgr": + // GREEK CAPITAL LETTER PHI + return rune(0x03a6), true + case "PSgr": + // GREEK CAPITAL LETTER PSI + return rune(0x03a8), true + case "PartialD": + // PARTIAL DIFFERENTIAL + return rune(0x2202), true + case "Pcy": + // CYRILLIC CAPITAL LETTER PE + return rune(0x041f), true + case "Pfr": + // MATHEMATICAL FRAKTUR CAPITAL P + return rune(0x01d513), true + case "Pgr": + // GREEK CAPITAL LETTER PI + return rune(0x03a0), true + case "Phi": + // GREEK CAPITAL LETTER PHI + return rune(0x03a6), true + case "Pi": + // GREEK CAPITAL LETTER PI + return rune(0x03a0), true + case "PlusMinus": + // PLUS-MINUS SIGN + return rune(0xb1), true + case "Poincareplane": + // BLACK-LETTER CAPITAL H + return rune(0x210c), true + case "Popf": + // DOUBLE-STRUCK CAPITAL P + return rune(0x2119), true + case "Product": + // N-ARY PRODUCT + return rune(0x220f), true + case "Proportional": + // PROPORTIONAL TO + return rune(0x221d), true + case "Proportion": + // PROPORTION + return rune(0x2237), true + case "Pr": + // DOUBLE PRECEDES + return rune(0x2abb), true + case "PrecedesEqual": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "Precedes": + // PRECEDES + return rune(0x227a), true + case "PrecedesSlantEqual": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "PrecedesTilde": + // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "Prime": + // DOUBLE PRIME + return rune(0x2033), true + case "Pscr": + // MATHEMATICAL SCRIPT CAPITAL P + return rune(0x01d4ab), true + case "Psi": + // GREEK CAPITAL LETTER PSI + return rune(0x03a8), true + } + + case 'Q': + switch name { + case "QUOT": + // QUOTATION MARK + return rune(0x22), true + case "Qfr": + // MATHEMATICAL FRAKTUR CAPITAL Q + return rune(0x01d514), true + case "Qopf": + // DOUBLE-STRUCK CAPITAL Q + return rune(0x211a), true + case "Qscr": + // MATHEMATICAL SCRIPT CAPITAL Q + return rune(0x01d4ac), true + } + + case 'R': + switch name { + case "RBarr": + // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW + return rune(0x2910), true + case "REG": + // REGISTERED SIGN + return rune(0xae), true + case "Racute": + // LATIN CAPITAL LETTER R WITH ACUTE + return rune(0x0154), true + case "Rang": + // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET + return rune(0x27eb), true + case "Rarr": + // RIGHTWARDS TWO HEADED ARROW + return rune(0x21a0), true + case "Rarrtl": + // RIGHTWARDS TWO-HEADED ARROW WITH TAIL + return rune(0x2916), true + case "Rcaron": + // LATIN CAPITAL LETTER R WITH CARON + return rune(0x0158), true + case "Rcedil": + // LATIN CAPITAL LETTER R WITH CEDILLA + return rune(0x0156), true + case "Rcy": + // CYRILLIC CAPITAL LETTER ER + return rune(0x0420), true + case "ReverseElement": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "ReverseEquilibrium": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "Re": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "ReverseUpEquilibrium": + // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x296f), true + case "Rfr": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "Rgr": + // GREEK CAPITAL LETTER RHO + return rune(0x03a1), true + case "Rho": + // GREEK CAPITAL LETTER RHO + return rune(0x03a1), true + case "RightAngleBracket": + // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "RightArrowBar": + // RIGHTWARDS ARROW TO BAR + return rune(0x21e5), true + case "RightArrow": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "RightArrowLeftArrow": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "RightCeiling": + // RIGHT CEILING + return rune(0x2309), true + case "RightDoubleBracket": + // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + return rune(0x27e7), true + case "RightDownTeeVector": + // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295d), true + case "RightDownVector": + // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "RightDownVectorBar": + // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2955), true + case "RightFloor": + // RIGHT FLOOR + return rune(0x230b), true + case "RightTeeArrow": + // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "RightTeeVector": + // RIGHTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295b), true + case "RightTee": + // RIGHT TACK + return rune(0x22a2), true + case "RightTriangleBar": + // VERTICAL BAR BESIDE RIGHT TRIANGLE + return rune(0x29d0), true + case "RightTriangle": + // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "RightTriangleEqual": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "RightUpDownVector": + // UP BARB RIGHT DOWN BARB RIGHT HARPOON + return rune(0x294f), true + case "RightUpTeeVector": + // UPWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295c), true + case "RightUpVector": + // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "RightUpVectorBar": + // UPWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2954), true + case "RightVector": + // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "RightVectorBar": + // RIGHTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2953), true + case "Rightarrow": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "Ropf": + // DOUBLE-STRUCK CAPITAL R + return rune(0x211d), true + case "RoundImplies": + // RIGHT DOUBLE ARROW WITH ROUNDED HEAD + return rune(0x2970), true + case "Rrightarrow": + // RIGHTWARDS TRIPLE ARROW + return rune(0x21db), true + case "Rscr": + // SCRIPT CAPITAL R + return rune(0x211b), true + case "Rsh": + // UPWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b1), true + case "RuleDelayed": + // RULE-DELAYED + return rune(0x29f4), true + } + + case 'S': + switch name { + case "SHCHcy": + // CYRILLIC CAPITAL LETTER SHCHA + return rune(0x0429), true + case "SHcy": + // CYRILLIC CAPITAL LETTER SHA + return rune(0x0428), true + case "SOFTcy": + // CYRILLIC CAPITAL LETTER SOFT SIGN + return rune(0x042c), true + case "Sacute": + // LATIN CAPITAL LETTER S WITH ACUTE + return rune(0x015a), true + case "Sc": + // DOUBLE SUCCEEDS + return rune(0x2abc), true + case "Scaron": + // LATIN CAPITAL LETTER S WITH CARON + return rune(0x0160), true + case "Scedil": + // LATIN CAPITAL LETTER S WITH CEDILLA + return rune(0x015e), true + case "Scirc": + // LATIN CAPITAL LETTER S WITH CIRCUMFLEX + return rune(0x015c), true + case "Scy": + // CYRILLIC CAPITAL LETTER ES + return rune(0x0421), true + case "Sfr": + // MATHEMATICAL FRAKTUR CAPITAL S + return rune(0x01d516), true + case "Sgr": + // GREEK CAPITAL LETTER SIGMA + return rune(0x03a3), true + case "ShortDownArrow": + // DOWNWARDS ARROW + return rune(0x2193), true + case "ShortLeftArrow": + // LEFTWARDS ARROW + return rune(0x2190), true + case "ShortRightArrow": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "ShortUpArrow": + // UPWARDS ARROW + return rune(0x2191), true + case "Sigma": + // GREEK CAPITAL LETTER SIGMA + return rune(0x03a3), true + case "SmallCircle": + // RING OPERATOR + return rune(0x2218), true + case "Sopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL S + return rune(0x01d54a), true + case "Sqrt": + // SQUARE ROOT + return rune(0x221a), true + case "SquareIntersection": + // SQUARE CAP + return rune(0x2293), true + case "SquareSubset": + // SQUARE IMAGE OF + return rune(0x228f), true + case "SquareSubsetEqual": + // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "Square": + // WHITE SQUARE + return rune(0x25a1), true + case "SquareSuperset": + // SQUARE ORIGINAL OF + return rune(0x2290), true + case "SquareSupersetEqual": + // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "SquareUnion": + // SQUARE CUP + return rune(0x2294), true + case "Sscr": + // MATHEMATICAL SCRIPT CAPITAL S + return rune(0x01d4ae), true + case "Star": + // STAR OPERATOR + return rune(0x22c6), true + case "Sub": + // DOUBLE SUBSET + return rune(0x22d0), true + case "Subset": + // DOUBLE SUBSET + return rune(0x22d0), true + case "SubsetEqual": + // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "Succeeds": + // SUCCEEDS + return rune(0x227b), true + case "SucceedsEqual": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "SucceedsSlantEqual": + // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "SucceedsTilde": + // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "SuchThat": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "Sum": + // N-ARY SUMMATION + return rune(0x2211), true + case "SupersetEqual": + // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "Sup": + // DOUBLE SUPERSET + return rune(0x22d1), true + case "Superset": + // SUPERSET OF + return rune(0x2283), true + case "Supset": + // DOUBLE SUPERSET + return rune(0x22d1), true + } + + case 'T': + switch name { + case "THORN": + // LATIN CAPITAL LETTER THORN + return rune(0xde), true + case "THgr": + // GREEK CAPITAL LETTER THETA + return rune(0x0398), true + case "TRADE": + // TRADE MARK SIGN + return rune(0x2122), true + case "TSHcy": + // CYRILLIC CAPITAL LETTER TSHE + return rune(0x040b), true + case "TScy": + // CYRILLIC CAPITAL LETTER TSE + return rune(0x0426), true + case "Tab": + // CHARACTER TABULATION + return rune(0x09), true + case "Tau": + // GREEK CAPITAL LETTER TAU + return rune(0x03a4), true + case "Tcaron": + // LATIN CAPITAL LETTER T WITH CARON + return rune(0x0164), true + case "Tcedil": + // LATIN CAPITAL LETTER T WITH CEDILLA + return rune(0x0162), true + case "Tcy": + // CYRILLIC CAPITAL LETTER TE + return rune(0x0422), true + case "Tfr": + // MATHEMATICAL FRAKTUR CAPITAL T + return rune(0x01d517), true + case "Tgr": + // GREEK CAPITAL LETTER TAU + return rune(0x03a4), true + case "Therefore": + // THEREFORE + return rune(0x2234), true + case "Theta": + // GREEK CAPITAL LETTER THETA + return rune(0x0398), true + case "Thetav": + // GREEK CAPITAL THETA SYMBOL + return rune(0x03f4), true + case "ThickSpace": + // space of width 5/18 em + return rune(0x205f), true + case "ThinSpace": + // THIN SPACE + return rune(0x2009), true + case "Tilde": + // TILDE OPERATOR + return rune(0x223c), true + case "TildeEqual": + // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "TildeFullEqual": + // APPROXIMATELY EQUAL TO + return rune(0x2245), true + case "TildeTilde": + // ALMOST EQUAL TO + return rune(0x2248), true + case "Topf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL T + return rune(0x01d54b), true + case "TripleDot": + // COMBINING THREE DOTS ABOVE + return rune(0x20db), true + case "Tscr": + // MATHEMATICAL SCRIPT CAPITAL T + return rune(0x01d4af), true + case "Tstrok": + // LATIN CAPITAL LETTER T WITH STROKE + return rune(0x0166), true + } + + case 'U': + switch name { + case "Uacgr": + // GREEK CAPITAL LETTER UPSILON WITH TONOS + return rune(0x038e), true + case "Uacute": + // LATIN CAPITAL LETTER U WITH ACUTE + return rune(0xda), true + case "Uarrocir": + // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE + return rune(0x2949), true + case "Uarr": + // UPWARDS TWO HEADED ARROW + return rune(0x219f), true + case "Ubrcy": + // CYRILLIC CAPITAL LETTER SHORT U + return rune(0x040e), true + case "Ubreve": + // LATIN CAPITAL LETTER U WITH BREVE + return rune(0x016c), true + case "Ucirc": + // LATIN CAPITAL LETTER U WITH CIRCUMFLEX + return rune(0xdb), true + case "Ucy": + // CYRILLIC CAPITAL LETTER U + return rune(0x0423), true + case "Udblac": + // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE + return rune(0x0170), true + case "Udigr": + // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA + return rune(0x03ab), true + case "Ufr": + // MATHEMATICAL FRAKTUR CAPITAL U + return rune(0x01d518), true + case "Ugrave": + // LATIN CAPITAL LETTER U WITH GRAVE + return rune(0xd9), true + case "Ugr": + // GREEK CAPITAL LETTER UPSILON + return rune(0x03a5), true + case "Umacr": + // LATIN CAPITAL LETTER U WITH MACRON + return rune(0x016a), true + case "UnderBar": + // LOW LINE + return rune(0x5f), true + case "UnderBrace": + // BOTTOM CURLY BRACKET + return rune(0x23df), true + case "UnderBracket": + // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "UnderParenthesis": + // BOTTOM PARENTHESIS + return rune(0x23dd), true + case "Union": + // N-ARY UNION + return rune(0x22c3), true + case "UnionPlus": + // MULTISET UNION + return rune(0x228e), true + case "Uogon": + // LATIN CAPITAL LETTER U WITH OGONEK + return rune(0x0172), true + case "Uopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL U + return rune(0x01d54c), true + case "UpArrow": + // UPWARDS ARROW + return rune(0x2191), true + case "UpArrowBar": + // UPWARDS ARROW TO BAR + return rune(0x2912), true + case "UpArrowDownArrow": + // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + return rune(0x21c5), true + case "UpDownArrow": + // UP DOWN ARROW + return rune(0x2195), true + case "UpEquilibrium": + // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x296e), true + case "UpTee": + // UP TACK + return rune(0x22a5), true + case "UpTeeArrow": + // UPWARDS ARROW FROM BAR + return rune(0x21a5), true + case "Uparrow": + // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "Updownarrow": + // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "UpperLeftArrow": + // NORTH WEST ARROW + return rune(0x2196), true + case "UpperRightArrow": + // NORTH EAST ARROW + return rune(0x2197), true + case "Upsilon": + // GREEK CAPITAL LETTER UPSILON + return rune(0x03a5), true + case "Upsi": + // GREEK UPSILON WITH HOOK SYMBOL + return rune(0x03d2), true + case "Uring": + // LATIN CAPITAL LETTER U WITH RING ABOVE + return rune(0x016e), true + case "Uscr": + // MATHEMATICAL SCRIPT CAPITAL U + return rune(0x01d4b0), true + case "Utilde": + // LATIN CAPITAL LETTER U WITH TILDE + return rune(0x0168), true + case "Uuml": + // LATIN CAPITAL LETTER U WITH DIAERESIS + return rune(0xdc), true + } + + case 'V': + switch name { + case "VDash": + // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + return rune(0x22ab), true + case "Vbar": + // DOUBLE UP TACK + return rune(0x2aeb), true + case "Vcy": + // CYRILLIC CAPITAL LETTER VE + return rune(0x0412), true + case "Vdashl": + // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL + return rune(0x2ae6), true + case "Vdash": + // FORCES + return rune(0x22a9), true + case "Vee": + // N-ARY LOGICAL OR + return rune(0x22c1), true + case "Verbar": + // DOUBLE VERTICAL LINE + return rune(0x2016), true + case "Vert": + // DOUBLE VERTICAL LINE + return rune(0x2016), true + case "VerticalBar": + // DIVIDES + return rune(0x2223), true + case "VerticalLine": + // VERTICAL LINE + return rune(0x7c), true + case "VerticalSeparator": + // LIGHT VERTICAL BAR + return rune(0x2758), true + case "VerticalTilde": + // WREATH PRODUCT + return rune(0x2240), true + case "VeryThinSpace": + // HAIR SPACE + return rune(0x200a), true + case "Vfr": + // MATHEMATICAL FRAKTUR CAPITAL V + return rune(0x01d519), true + case "Vopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL V + return rune(0x01d54d), true + case "Vscr": + // MATHEMATICAL SCRIPT CAPITAL V + return rune(0x01d4b1), true + case "Vvdash": + // TRIPLE VERTICAL BAR RIGHT TURNSTILE + return rune(0x22aa), true + } + + case 'W': + switch name { + case "Wcirc": + // LATIN CAPITAL LETTER W WITH CIRCUMFLEX + return rune(0x0174), true + case "Wedge": + // N-ARY LOGICAL AND + return rune(0x22c0), true + case "Wfr": + // MATHEMATICAL FRAKTUR CAPITAL W + return rune(0x01d51a), true + case "Wopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL W + return rune(0x01d54e), true + case "Wscr": + // MATHEMATICAL SCRIPT CAPITAL W + return rune(0x01d4b2), true + } + + case 'X': + switch name { + case "Xfr": + // MATHEMATICAL FRAKTUR CAPITAL X + return rune(0x01d51b), true + case "Xgr": + // GREEK CAPITAL LETTER XI + return rune(0x039e), true + case "Xi": + // GREEK CAPITAL LETTER XI + return rune(0x039e), true + case "Xopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL X + return rune(0x01d54f), true + case "Xscr": + // MATHEMATICAL SCRIPT CAPITAL X + return rune(0x01d4b3), true + } + + case 'Y': + switch name { + case "YAcy": + // CYRILLIC CAPITAL LETTER YA + return rune(0x042f), true + case "YIcy": + // CYRILLIC CAPITAL LETTER YI + return rune(0x0407), true + case "YUcy": + // CYRILLIC CAPITAL LETTER YU + return rune(0x042e), true + case "Yacute": + // LATIN CAPITAL LETTER Y WITH ACUTE + return rune(0xdd), true + case "Ycirc": + // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX + return rune(0x0176), true + case "Ycy": + // CYRILLIC CAPITAL LETTER YERU + return rune(0x042b), true + case "Yfr": + // MATHEMATICAL FRAKTUR CAPITAL Y + return rune(0x01d51c), true + case "Yopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y + return rune(0x01d550), true + case "Yscr": + // MATHEMATICAL SCRIPT CAPITAL Y + return rune(0x01d4b4), true + case "Yuml": + // LATIN CAPITAL LETTER Y WITH DIAERESIS + return rune(0x0178), true + } + + case 'Z': + switch name { + case "ZHcy": + // CYRILLIC CAPITAL LETTER ZHE + return rune(0x0416), true + case "Zacute": + // LATIN CAPITAL LETTER Z WITH ACUTE + return rune(0x0179), true + case "Zcaron": + // LATIN CAPITAL LETTER Z WITH CARON + return rune(0x017d), true + case "Zcy": + // CYRILLIC CAPITAL LETTER ZE + return rune(0x0417), true + case "Zdot": + // LATIN CAPITAL LETTER Z WITH DOT ABOVE + return rune(0x017b), true + case "ZeroWidthSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "Zeta": + // GREEK CAPITAL LETTER ZETA + return rune(0x0396), true + case "Zfr": + // BLACK-LETTER CAPITAL Z + return rune(0x2128), true + case "Zgr": + // GREEK CAPITAL LETTER ZETA + return rune(0x0396), true + case "Zopf": + // DOUBLE-STRUCK CAPITAL Z + return rune(0x2124), true + case "Zscr": + // MATHEMATICAL SCRIPT CAPITAL Z + return rune(0x01d4b5), true + } + + case 'a': + switch name { + case "aacgr": + // GREEK SMALL LETTER ALPHA WITH TONOS + return rune(0x03ac), true + case "aacute": + // LATIN SMALL LETTER A WITH ACUTE + return rune(0xe1), true + case "abreve": + // LATIN SMALL LETTER A WITH BREVE + return rune(0x0103), true + case "acE": + // INVERTED LAZY S with double underline + return rune(0x223e), true + case "acd": + // SINE WAVE + return rune(0x223f), true + case "acute": + // ACUTE ACCENT + return rune(0xb4), true + case "ac": + // INVERTED LAZY S + return rune(0x223e), true + case "acirc": + // LATIN SMALL LETTER A WITH CIRCUMFLEX + return rune(0xe2), true + case "actuary": + // COMBINING ANNUITY SYMBOL + return rune(0x20e7), true + case "acy": + // CYRILLIC SMALL LETTER A + return rune(0x0430), true + case "aelig": + // LATIN SMALL LETTER AE + return rune(0xe6), true + case "af": + // FUNCTION APPLICATION + return rune(0x2061), true + case "afr": + // MATHEMATICAL FRAKTUR SMALL A + return rune(0x01d51e), true + case "agr": + // GREEK SMALL LETTER ALPHA + return rune(0x03b1), true + case "agrave": + // LATIN SMALL LETTER A WITH GRAVE + return rune(0xe0), true + case "alefsym": + // ALEF SYMBOL + return rune(0x2135), true + case "aleph": + // ALEF SYMBOL + return rune(0x2135), true + case "alpha": + // GREEK SMALL LETTER ALPHA + return rune(0x03b1), true + case "amacr": + // LATIN SMALL LETTER A WITH MACRON + return rune(0x0101), true + case "amalg": + // AMALGAMATION OR COPRODUCT + return rune(0x2a3f), true + case "amp": + // AMPERSAND + return rune(0x26), true + case "andand": + // TWO INTERSECTING LOGICAL AND + return rune(0x2a55), true + case "andd": + // LOGICAL AND WITH HORIZONTAL DASH + return rune(0x2a5c), true + case "andslope": + // SLOPING LARGE AND + return rune(0x2a58), true + case "andv": + // LOGICAL AND WITH MIDDLE STEM + return rune(0x2a5a), true + case "and": + // LOGICAL AND + return rune(0x2227), true + case "angdnl": + // TURNED ANGLE + return rune(0x29a2), true + case "angdnr": + // ACUTE ANGLE + return rune(0x299f), true + case "ange": + // ANGLE WITH UNDERBAR + return rune(0x29a4), true + case "angles": + // ANGLE WITH S INSIDE + return rune(0x299e), true + case "angle": + // ANGLE + return rune(0x2220), true + case "angmsdaa": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT + return rune(0x29a8), true + case "angmsdab": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT + return rune(0x29a9), true + case "angmsdac": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT + return rune(0x29aa), true + case "angmsdad": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT + return rune(0x29ab), true + case "angmsdae": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP + return rune(0x29ac), true + case "angmsdaf": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP + return rune(0x29ad), true + case "angmsdag": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN + return rune(0x29ae), true + case "angmsdah": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN + return rune(0x29af), true + case "angmsd": + // MEASURED ANGLE + return rune(0x2221), true + case "angrtvbd": + // MEASURED RIGHT ANGLE WITH DOT + return rune(0x299d), true + case "angrtvb": + // RIGHT ANGLE WITH ARC + return rune(0x22be), true + case "angsph": + // SPHERICAL ANGLE + return rune(0x2222), true + case "angst": + // LATIN CAPITAL LETTER A WITH RING ABOVE + return rune(0xc5), true + case "angupl": + // REVERSED ANGLE + return rune(0x29a3), true + case "angzarr": + // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW + return rune(0x237c), true + case "ang": + // ANGLE + return rune(0x2220), true + case "ang90": + // RIGHT ANGLE + return rune(0x221f), true + case "angrt": + // RIGHT ANGLE + return rune(0x221f), true + case "aogon": + // LATIN SMALL LETTER A WITH OGONEK + return rune(0x0105), true + case "aopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL A + return rune(0x01d552), true + case "apE": + // APPROXIMATELY EQUAL OR EQUAL TO + return rune(0x2a70), true + case "apacir": + // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT + return rune(0x2a6f), true + case "ape": + // ALMOST EQUAL OR EQUAL TO + return rune(0x224a), true + case "apid": + // TRIPLE TILDE + return rune(0x224b), true + case "approxeq": + // ALMOST EQUAL OR EQUAL TO + return rune(0x224a), true + case "approx": + // ALMOST EQUAL TO + return rune(0x2248), true + case "ap": + // ALMOST EQUAL TO + return rune(0x2248), true + case "apos": + // APOSTROPHE + return rune(0x27), true + case "aring": + // LATIN SMALL LETTER A WITH RING ABOVE + return rune(0xe5), true + case "arrllsr": + // LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW + return rune(0x2943), true + case "arrlrsl": + // RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW + return rune(0x2942), true + case "arrsrll": + // SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW + return rune(0x2944), true + case "ascr": + // MATHEMATICAL SCRIPT SMALL A + return rune(0x01d4b6), true + case "astb": + // SQUARED ASTERISK + return rune(0x29c6), true + case "ast": + // ASTERISK + return rune(0x2a), true + case "asympeq": + // EQUIVALENT TO + return rune(0x224d), true + case "asymp": + // ALMOST EQUAL TO + return rune(0x2248), true + case "atilde": + // LATIN SMALL LETTER A WITH TILDE + return rune(0xe3), true + case "auml": + // LATIN SMALL LETTER A WITH DIAERESIS + return rune(0xe4), true + case "awconint": + // ANTICLOCKWISE CONTOUR INTEGRAL + return rune(0x2233), true + case "awint": + // ANTICLOCKWISE INTEGRATION + return rune(0x2a11), true + } + + case 'b': + switch name { + case "b.Delta": + // MATHEMATICAL BOLD CAPITAL DELTA + return rune(0x01d6ab), true + case "b.Gamma": + // MATHEMATICAL BOLD CAPITAL GAMMA + return rune(0x01d6aa), true + case "b.Gammad": + // MATHEMATICAL BOLD CAPITAL DIGAMMA + return rune(0x01d7ca), true + case "b.Lambda": + // MATHEMATICAL BOLD CAPITAL LAMDA + return rune(0x01d6b2), true + case "b.Omega": + // MATHEMATICAL BOLD CAPITAL OMEGA + return rune(0x01d6c0), true + case "b.Phi": + // MATHEMATICAL BOLD CAPITAL PHI + return rune(0x01d6bd), true + case "b.Pi": + // MATHEMATICAL BOLD CAPITAL PI + return rune(0x01d6b7), true + case "b.Psi": + // MATHEMATICAL BOLD CAPITAL PSI + return rune(0x01d6bf), true + case "b.Sigma": + // MATHEMATICAL BOLD CAPITAL SIGMA + return rune(0x01d6ba), true + case "b.Theta": + // MATHEMATICAL BOLD CAPITAL THETA + return rune(0x01d6af), true + case "b.Upsi": + // MATHEMATICAL BOLD CAPITAL UPSILON + return rune(0x01d6bc), true + case "b.Xi": + // MATHEMATICAL BOLD CAPITAL XI + return rune(0x01d6b5), true + case "b.alpha": + // MATHEMATICAL BOLD SMALL ALPHA + return rune(0x01d6c2), true + case "b.beta": + // MATHEMATICAL BOLD SMALL BETA + return rune(0x01d6c3), true + case "b.chi": + // MATHEMATICAL BOLD SMALL CHI + return rune(0x01d6d8), true + case "b.delta": + // MATHEMATICAL BOLD SMALL DELTA + return rune(0x01d6c5), true + case "b.epsi": + // MATHEMATICAL BOLD SMALL EPSILON + return rune(0x01d6c6), true + case "b.epsiv": + // MATHEMATICAL BOLD EPSILON SYMBOL + return rune(0x01d6dc), true + case "b.eta": + // MATHEMATICAL BOLD SMALL ETA + return rune(0x01d6c8), true + case "b.gammad": + // MATHEMATICAL BOLD SMALL DIGAMMA + return rune(0x01d7cb), true + case "b.gamma": + // MATHEMATICAL BOLD SMALL GAMMA + return rune(0x01d6c4), true + case "b.iota": + // MATHEMATICAL BOLD SMALL IOTA + return rune(0x01d6ca), true + case "b.kappa": + // MATHEMATICAL BOLD SMALL KAPPA + return rune(0x01d6cb), true + case "b.kappav": + // MATHEMATICAL BOLD KAPPA SYMBOL + return rune(0x01d6de), true + case "b.lambda": + // MATHEMATICAL BOLD SMALL LAMDA + return rune(0x01d6cc), true + case "b.mu": + // MATHEMATICAL BOLD SMALL MU + return rune(0x01d6cd), true + case "b.nu": + // MATHEMATICAL BOLD SMALL NU + return rune(0x01d6ce), true + case "b.omega": + // MATHEMATICAL BOLD SMALL OMEGA + return rune(0x01d6da), true + case "b.phi": + // MATHEMATICAL BOLD SMALL PHI + return rune(0x01d6d7), true + case "b.phiv": + // MATHEMATICAL BOLD PHI SYMBOL + return rune(0x01d6df), true + case "b.pi": + // MATHEMATICAL BOLD SMALL PI + return rune(0x01d6d1), true + case "b.piv": + // MATHEMATICAL BOLD PI SYMBOL + return rune(0x01d6e1), true + case "b.psi": + // MATHEMATICAL BOLD SMALL PSI + return rune(0x01d6d9), true + case "b.rho": + // MATHEMATICAL BOLD SMALL RHO + return rune(0x01d6d2), true + case "b.rhov": + // MATHEMATICAL BOLD RHO SYMBOL + return rune(0x01d6e0), true + case "b.sigmav": + // MATHEMATICAL BOLD SMALL FINAL SIGMA + return rune(0x01d6d3), true + case "b.sigma": + // MATHEMATICAL BOLD SMALL SIGMA + return rune(0x01d6d4), true + case "b.tau": + // MATHEMATICAL BOLD SMALL TAU + return rune(0x01d6d5), true + case "b.thetas": + // MATHEMATICAL BOLD SMALL THETA + return rune(0x01d6c9), true + case "b.thetav": + // MATHEMATICAL BOLD THETA SYMBOL + return rune(0x01d6dd), true + case "b.upsi": + // MATHEMATICAL BOLD SMALL UPSILON + return rune(0x01d6d6), true + case "b.xi": + // MATHEMATICAL BOLD SMALL XI + return rune(0x01d6cf), true + case "b.zeta": + // MATHEMATICAL BOLD SMALL ZETA + return rune(0x01d6c7), true + case "bNot": + // REVERSED DOUBLE STROKE NOT SIGN + return rune(0x2aed), true + case "backcong": + // ALL EQUAL TO + return rune(0x224c), true + case "backepsilon": + // GREEK REVERSED LUNATE EPSILON SYMBOL + return rune(0x03f6), true + case "backprime": + // REVERSED PRIME + return rune(0x2035), true + case "backsimeq": + // REVERSED TILDE EQUALS + return rune(0x22cd), true + case "backsim": + // REVERSED TILDE + return rune(0x223d), true + case "barV": + // DOUBLE DOWN TACK + return rune(0x2aea), true + case "barvee": + // NOR + return rune(0x22bd), true + case "barwed": + // PROJECTIVE + return rune(0x2305), true + case "barwedge": + // PROJECTIVE + return rune(0x2305), true + case "bbrk": + // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "bbrktbrk": + // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET + return rune(0x23b6), true + case "bcong": + // ALL EQUAL TO + return rune(0x224c), true + case "bcy": + // CYRILLIC SMALL LETTER BE + return rune(0x0431), true + case "bdlhar": + // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2961), true + case "bdquo": + // DOUBLE LOW-9 QUOTATION MARK + return rune(0x201e), true + case "bdrhar": + // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295d), true + case "because": + // BECAUSE + return rune(0x2235), true + case "becaus": + // BECAUSE + return rune(0x2235), true + case "bemptyv": + // REVERSED EMPTY SET + return rune(0x29b0), true + case "bepsi": + // GREEK REVERSED LUNATE EPSILON SYMBOL + return rune(0x03f6), true + case "bernou": + // SCRIPT CAPITAL B + return rune(0x212c), true + case "beta": + // GREEK SMALL LETTER BETA + return rune(0x03b2), true + case "beth": + // BET SYMBOL + return rune(0x2136), true + case "between": + // BETWEEN + return rune(0x226c), true + case "bfr": + // MATHEMATICAL FRAKTUR SMALL B + return rune(0x01d51f), true + case "bgr": + // GREEK SMALL LETTER BETA + return rune(0x03b2), true + case "bigcap": + // N-ARY INTERSECTION + return rune(0x22c2), true + case "bigcirc": + // LARGE CIRCLE + return rune(0x25ef), true + case "bigcup": + // N-ARY UNION + return rune(0x22c3), true + case "bigodot": + // N-ARY CIRCLED DOT OPERATOR + return rune(0x2a00), true + case "bigoplus": + // N-ARY CIRCLED PLUS OPERATOR + return rune(0x2a01), true + case "bigotimes": + // N-ARY CIRCLED TIMES OPERATOR + return rune(0x2a02), true + case "bigsqcup": + // N-ARY SQUARE UNION OPERATOR + return rune(0x2a06), true + case "bigstar": + // BLACK STAR + return rune(0x2605), true + case "bigtriangledown": + // WHITE DOWN-POINTING TRIANGLE + return rune(0x25bd), true + case "bigtriangleup": + // WHITE UP-POINTING TRIANGLE + return rune(0x25b3), true + case "biguplus": + // N-ARY UNION OPERATOR WITH PLUS + return rune(0x2a04), true + case "bigvee": + // N-ARY LOGICAL OR + return rune(0x22c1), true + case "bigwedge": + // N-ARY LOGICAL AND + return rune(0x22c0), true + case "bkarow": + // RIGHTWARDS DOUBLE DASH ARROW + return rune(0x290d), true + case "blacklozenge": + // BLACK LOZENGE + return rune(0x29eb), true + case "blacksquare": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "blacktriangledown": + // BLACK DOWN-POINTING SMALL TRIANGLE + return rune(0x25be), true + case "blacktriangleleft": + // BLACK LEFT-POINTING SMALL TRIANGLE + return rune(0x25c2), true + case "blacktriangleright": + // BLACK RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b8), true + case "blacktriangle": + // BLACK UP-POINTING SMALL TRIANGLE + return rune(0x25b4), true + case "blank": + // BLANK SYMBOL + return rune(0x2422), true + case "bldhar": + // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295e), true + case "blk12": + // MEDIUM SHADE + return rune(0x2592), true + case "blk14": + // LIGHT SHADE + return rune(0x2591), true + case "blk34": + // DARK SHADE + return rune(0x2593), true + case "block": + // FULL BLOCK + return rune(0x2588), true + case "bluhar": + // LEFTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295a), true + case "bnequiv": + // IDENTICAL TO with reverse slash + return rune(0x2261), true + case "bne": + // EQUALS SIGN with reverse slash + return rune(0x3d), true + case "bnot": + // REVERSED NOT SIGN + return rune(0x2310), true + case "bopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL B + return rune(0x01d553), true + case "bot": + // UP TACK + return rune(0x22a5), true + case "bottom": + // UP TACK + return rune(0x22a5), true + case "bowtie": + // BOWTIE + return rune(0x22c8), true + case "boxDL": + // BOX DRAWINGS DOUBLE DOWN AND LEFT + return rune(0x2557), true + case "boxDR": + // BOX DRAWINGS DOUBLE DOWN AND RIGHT + return rune(0x2554), true + case "boxDl": + // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + return rune(0x2556), true + case "boxDr": + // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + return rune(0x2553), true + case "boxHD": + // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + return rune(0x2566), true + case "boxHU": + // BOX DRAWINGS DOUBLE UP AND HORIZONTAL + return rune(0x2569), true + case "boxHd": + // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + return rune(0x2564), true + case "boxHu": + // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + return rune(0x2567), true + case "boxH": + // BOX DRAWINGS DOUBLE HORIZONTAL + return rune(0x2550), true + case "boxUL": + // BOX DRAWINGS DOUBLE UP AND LEFT + return rune(0x255d), true + case "boxUR": + // BOX DRAWINGS DOUBLE UP AND RIGHT + return rune(0x255a), true + case "boxUl": + // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + return rune(0x255c), true + case "boxUr": + // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + return rune(0x2559), true + case "boxVH": + // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + return rune(0x256c), true + case "boxVL": + // BOX DRAWINGS DOUBLE VERTICAL AND LEFT + return rune(0x2563), true + case "boxVR": + // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + return rune(0x2560), true + case "boxVh": + // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + return rune(0x256b), true + case "boxVl": + // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + return rune(0x2562), true + case "boxVr": + // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + return rune(0x255f), true + case "boxV": + // BOX DRAWINGS DOUBLE VERTICAL + return rune(0x2551), true + case "boxbox": + // TWO JOINED SQUARES + return rune(0x29c9), true + case "boxdL": + // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + return rune(0x2555), true + case "boxdR": + // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + return rune(0x2552), true + case "boxdl": + // BOX DRAWINGS LIGHT DOWN AND LEFT + return rune(0x2510), true + case "boxdr": + // BOX DRAWINGS LIGHT DOWN AND RIGHT + return rune(0x250c), true + case "boxhU": + // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + return rune(0x2568), true + case "boxh": + // BOX DRAWINGS LIGHT HORIZONTAL + return rune(0x2500), true + case "boxhD": + // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + return rune(0x2565), true + case "boxhd": + // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + return rune(0x252c), true + case "boxhu": + // BOX DRAWINGS LIGHT UP AND HORIZONTAL + return rune(0x2534), true + case "boxminus": + // SQUARED MINUS + return rune(0x229f), true + case "boxplus": + // SQUARED PLUS + return rune(0x229e), true + case "boxtimes": + // SQUARED TIMES + return rune(0x22a0), true + case "boxuL": + // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + return rune(0x255b), true + case "boxuR": + // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + return rune(0x2558), true + case "boxul": + // BOX DRAWINGS LIGHT UP AND LEFT + return rune(0x2518), true + case "boxur": + // BOX DRAWINGS LIGHT UP AND RIGHT + return rune(0x2514), true + case "boxvL": + // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + return rune(0x2561), true + case "boxvR": + // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + return rune(0x255e), true + case "boxvl": + // BOX DRAWINGS LIGHT VERTICAL AND LEFT + return rune(0x2524), true + case "boxvr": + // BOX DRAWINGS LIGHT VERTICAL AND RIGHT + return rune(0x251c), true + case "boxv": + // BOX DRAWINGS LIGHT VERTICAL + return rune(0x2502), true + case "boxvH": + // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + return rune(0x256a), true + case "boxvh": + // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + return rune(0x253c), true + case "bprime": + // REVERSED PRIME + return rune(0x2035), true + case "brdhar": + // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295f), true + case "breve": + // BREVE + return rune(0x02d8), true + case "bruhar": + // RIGHTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295b), true + case "brvbar": + // BROKEN BAR + return rune(0xa6), true + case "bscr": + // MATHEMATICAL SCRIPT SMALL B + return rune(0x01d4b7), true + case "bsemi": + // REVERSED SEMICOLON + return rune(0x204f), true + case "bsim": + // REVERSED TILDE + return rune(0x223d), true + case "bsime": + // REVERSED TILDE EQUALS + return rune(0x22cd), true + case "bsolb": + // SQUARED FALLING DIAGONAL SLASH + return rune(0x29c5), true + case "bsolhsub": + // REVERSE SOLIDUS PRECEDING SUBSET + return rune(0x27c8), true + case "bsol": + // REVERSE SOLIDUS + return rune(0x5c), true + case "btimes": + // SEMIDIRECT PRODUCT WITH BOTTOM CLOSED + return rune(0x2a32), true + case "bulhar": + // UPWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2960), true + case "bullet": + // BULLET + return rune(0x2022), true + case "bull": + // BULLET + return rune(0x2022), true + case "bump": + // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "bumpE": + // EQUALS SIGN WITH BUMPY ABOVE + return rune(0x2aae), true + case "bumpe": + // DIFFERENCE BETWEEN + return rune(0x224f), true + case "bumpeq": + // DIFFERENCE BETWEEN + return rune(0x224f), true + case "burhar": + // UPWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295c), true + } + + case 'c': + switch name { + case "cacute": + // LATIN SMALL LETTER C WITH ACUTE + return rune(0x0107), true + case "cap": + // INTERSECTION + return rune(0x2229), true + case "capand": + // INTERSECTION WITH LOGICAL AND + return rune(0x2a44), true + case "capbrcup": + // INTERSECTION ABOVE BAR ABOVE UNION + return rune(0x2a49), true + case "capcap": + // INTERSECTION BESIDE AND JOINED WITH INTERSECTION + return rune(0x2a4b), true + case "capcup": + // INTERSECTION ABOVE UNION + return rune(0x2a47), true + case "capdot": + // INTERSECTION WITH DOT + return rune(0x2a40), true + case "capint": + // INTEGRAL WITH INTERSECTION + return rune(0x2a19), true + case "caps": + // INTERSECTION with serifs + return rune(0x2229), true + case "caret": + // CARET INSERTION POINT + return rune(0x2041), true + case "caron": + // CARON + return rune(0x02c7), true + case "ccaps": + // CLOSED INTERSECTION WITH SERIFS + return rune(0x2a4d), true + case "ccaron": + // LATIN SMALL LETTER C WITH CARON + return rune(0x010d), true + case "ccedil": + // LATIN SMALL LETTER C WITH CEDILLA + return rune(0xe7), true + case "ccirc": + // LATIN SMALL LETTER C WITH CIRCUMFLEX + return rune(0x0109), true + case "ccups": + // CLOSED UNION WITH SERIFS + return rune(0x2a4c), true + case "ccupssm": + // CLOSED UNION WITH SERIFS AND SMASH PRODUCT + return rune(0x2a50), true + case "cdot": + // LATIN SMALL LETTER C WITH DOT ABOVE + return rune(0x010b), true + case "cedil": + // CEDILLA + return rune(0xb8), true + case "cemptyv": + // EMPTY SET WITH SMALL CIRCLE ABOVE + return rune(0x29b2), true + case "centerdot": + // MIDDLE DOT + return rune(0xb7), true + case "cent": + // CENT SIGN + return rune(0xa2), true + case "cfr": + // MATHEMATICAL FRAKTUR SMALL C + return rune(0x01d520), true + case "chcy": + // CYRILLIC SMALL LETTER CHE + return rune(0x0447), true + case "check": + // CHECK MARK + return rune(0x2713), true + case "checkmark": + // CHECK MARK + return rune(0x2713), true + case "chi": + // GREEK SMALL LETTER CHI + return rune(0x03c7), true + case "circeq": + // RING EQUAL TO + return rune(0x2257), true + case "circlearrowleft": + // ANTICLOCKWISE OPEN CIRCLE ARROW + return rune(0x21ba), true + case "circlearrowright": + // CLOCKWISE OPEN CIRCLE ARROW + return rune(0x21bb), true + case "circledS": + // CIRCLED LATIN CAPITAL LETTER S + return rune(0x24c8), true + case "circledast": + // CIRCLED ASTERISK OPERATOR + return rune(0x229b), true + case "circledcirc": + // CIRCLED RING OPERATOR + return rune(0x229a), true + case "circleddash": + // CIRCLED DASH + return rune(0x229d), true + case "cire": + // RING EQUAL TO + return rune(0x2257), true + case "cir": + // WHITE CIRCLE + return rune(0x25cb), true + case "cirE": + // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT + return rune(0x29c3), true + case "cirb": + // SQUARED SMALL CIRCLE + return rune(0x29c7), true + case "circ": + // MODIFIER LETTER CIRCUMFLEX ACCENT + return rune(0x02c6), true + case "circledR": + // REGISTERED SIGN + return rune(0xae), true + case "cirdarr": + // WHITE CIRCLE WITH DOWN ARROW + return rune(0x29ec), true + case "cirerr": + // ERROR-BARRED WHITE CIRCLE + return rune(0x29f2), true + case "cirfdarr": + // BLACK CIRCLE WITH DOWN ARROW + return rune(0x29ed), true + case "cirferr": + // ERROR-BARRED BLACK CIRCLE + return rune(0x29f3), true + case "cirfnint": + // CIRCULATION FUNCTION + return rune(0x2a10), true + case "cirmid": + // VERTICAL LINE WITH CIRCLE ABOVE + return rune(0x2aef), true + case "cirscir": + // CIRCLE WITH SMALL CIRCLE TO THE RIGHT + return rune(0x29c2), true + case "closur": + // CLOSE UP + return rune(0x2050), true + case "clubs": + // BLACK CLUB SUIT + return rune(0x2663), true + case "clubsuit": + // BLACK CLUB SUIT + return rune(0x2663), true + case "colone": + // COLON EQUALS + return rune(0x2254), true + case "coloneq": + // COLON EQUALS + return rune(0x2254), true + case "colon": + // COLON + return rune(0x3a), true + case "commat": + // COMMERCIAL AT + return rune(0x40), true + case "comma": + // COMMA + return rune(0x2c), true + case "comp": + // COMPLEMENT + return rune(0x2201), true + case "compfn": + // RING OPERATOR + return rune(0x2218), true + case "complement": + // COMPLEMENT + return rune(0x2201), true + case "complexes": + // DOUBLE-STRUCK CAPITAL C + return rune(0x2102), true + case "cong": + // APPROXIMATELY EQUAL TO + return rune(0x2245), true + case "congdot": + // CONGRUENT WITH DOT ABOVE + return rune(0x2a6d), true + case "conint": + // CONTOUR INTEGRAL + return rune(0x222e), true + case "copf": + // MATHEMATICAL DOUBLE-STRUCK SMALL C + return rune(0x01d554), true + case "coprod": + // N-ARY COPRODUCT + return rune(0x2210), true + case "copysr": + // SOUND RECORDING COPYRIGHT + return rune(0x2117), true + case "copy": + // COPYRIGHT SIGN + return rune(0xa9), true + case "crarr": + // DOWNWARDS ARROW WITH CORNER LEFTWARDS + return rune(0x21b5), true + case "cross": + // BALLOT X + return rune(0x2717), true + case "cscr": + // MATHEMATICAL SCRIPT SMALL C + return rune(0x01d4b8), true + case "csub": + // CLOSED SUBSET + return rune(0x2acf), true + case "csube": + // CLOSED SUBSET OR EQUAL TO + return rune(0x2ad1), true + case "csup": + // CLOSED SUPERSET + return rune(0x2ad0), true + case "csupe": + // CLOSED SUPERSET OR EQUAL TO + return rune(0x2ad2), true + case "ctdot": + // MIDLINE HORIZONTAL ELLIPSIS + return rune(0x22ef), true + case "cudarrl": + // RIGHT-SIDE ARC CLOCKWISE ARROW + return rune(0x2938), true + case "cudarrr": + // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS + return rune(0x2935), true + case "cuepr": + // EQUAL TO OR PRECEDES + return rune(0x22de), true + case "cuesc": + // EQUAL TO OR SUCCEEDS + return rune(0x22df), true + case "cularr": + // ANTICLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b6), true + case "cularrp": + // TOP ARC ANTICLOCKWISE ARROW WITH PLUS + return rune(0x293d), true + case "cup": + // UNION + return rune(0x222a), true + case "cupbrcap": + // UNION ABOVE BAR ABOVE INTERSECTION + return rune(0x2a48), true + case "cupcap": + // UNION ABOVE INTERSECTION + return rune(0x2a46), true + case "cupcup": + // UNION BESIDE AND JOINED WITH UNION + return rune(0x2a4a), true + case "cupdot": + // MULTISET MULTIPLICATION + return rune(0x228d), true + case "cupint": + // INTEGRAL WITH UNION + return rune(0x2a1a), true + case "cupor": + // UNION WITH LOGICAL OR + return rune(0x2a45), true + case "cupre": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "cups": + // UNION with serifs + return rune(0x222a), true + case "curarr": + // CLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b7), true + case "curarrm": + // TOP ARC CLOCKWISE ARROW WITH MINUS + return rune(0x293c), true + case "curlyeqprec": + // EQUAL TO OR PRECEDES + return rune(0x22de), true + case "curlyeqsucc": + // EQUAL TO OR SUCCEEDS + return rune(0x22df), true + case "curlyvee": + // CURLY LOGICAL OR + return rune(0x22ce), true + case "curlywedge": + // CURLY LOGICAL AND + return rune(0x22cf), true + case "curren": + // CURRENCY SIGN + return rune(0xa4), true + case "curvearrowleft": + // ANTICLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b6), true + case "curvearrowright": + // CLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b7), true + case "cuvee": + // CURLY LOGICAL OR + return rune(0x22ce), true + case "cuwed": + // CURLY LOGICAL AND + return rune(0x22cf), true + case "cwconint": + // CLOCKWISE CONTOUR INTEGRAL + return rune(0x2232), true + case "cwint": + // CLOCKWISE INTEGRAL + return rune(0x2231), true + case "cylcty": + // CYLINDRICITY + return rune(0x232d), true + } + + case 'd': + switch name { + case "dAarr": + // DOWNWARDS TRIPLE ARROW + return rune(0x290b), true + case "dArr": + // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "dHar": + // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x2965), true + case "dagger": + // DAGGER + return rune(0x2020), true + case "dalembrt": + // SQUARE WITH CONTOURED OUTLINE + return rune(0x29e0), true + case "daleth": + // DALET SYMBOL + return rune(0x2138), true + case "darr2": + // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "darr": + // DOWNWARDS ARROW + return rune(0x2193), true + case "darrb": + // DOWNWARDS ARROW TO BAR + return rune(0x2913), true + case "darrln": + // DOWNWARDS ARROW WITH HORIZONTAL STROKE + return rune(0x2908), true + case "dashv": + // LEFT TACK + return rune(0x22a3), true + case "dash": + // HYPHEN + return rune(0x2010), true + case "dashV": + // DOUBLE VERTICAL BAR LEFT TURNSTILE + return rune(0x2ae3), true + case "dbkarow": + // RIGHTWARDS TRIPLE DASH ARROW + return rune(0x290f), true + case "dblac": + // DOUBLE ACUTE ACCENT + return rune(0x02dd), true + case "dcaron": + // LATIN SMALL LETTER D WITH CARON + return rune(0x010f), true + case "dcy": + // CYRILLIC SMALL LETTER DE + return rune(0x0434), true + case "ddarr": + // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "dd": + // DOUBLE-STRUCK ITALIC SMALL D + return rune(0x2146), true + case "ddagger": + // DOUBLE DAGGER + return rune(0x2021), true + case "ddotseq": + // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW + return rune(0x2a77), true + case "deg": + // DEGREE SIGN + return rune(0xb0), true + case "delta": + // GREEK SMALL LETTER DELTA + return rune(0x03b4), true + case "demptyv": + // EMPTY SET WITH OVERBAR + return rune(0x29b1), true + case "dfisht": + // DOWN FISH TAIL + return rune(0x297f), true + case "dfr": + // MATHEMATICAL FRAKTUR SMALL D + return rune(0x01d521), true + case "dgr": + // GREEK SMALL LETTER DELTA + return rune(0x03b4), true + case "dharl": + // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "dharr": + // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "diam": + // DIAMOND OPERATOR + return rune(0x22c4), true + case "diamdarr": + // BLACK DIAMOND WITH DOWN ARROW + return rune(0x29ea), true + case "diamerr": + // ERROR-BARRED WHITE DIAMOND + return rune(0x29f0), true + case "diamerrf": + // ERROR-BARRED BLACK DIAMOND + return rune(0x29f1), true + case "diamond": + // DIAMOND OPERATOR + return rune(0x22c4), true + case "diamondsuit": + // BLACK DIAMOND SUIT + return rune(0x2666), true + case "diams": + // BLACK DIAMOND SUIT + return rune(0x2666), true + case "die": + // DIAERESIS + return rune(0xa8), true + case "digamma": + // GREEK SMALL LETTER DIGAMMA + return rune(0x03dd), true + case "disin": + // ELEMENT OF WITH LONG HORIZONTAL STROKE + return rune(0x22f2), true + case "divideontimes": + // DIVISION TIMES + return rune(0x22c7), true + case "divonx": + // DIVISION TIMES + return rune(0x22c7), true + case "div": + // DIVISION SIGN + return rune(0xf7), true + case "divide": + // DIVISION SIGN + return rune(0xf7), true + case "djcy": + // CYRILLIC SMALL LETTER DJE + return rune(0x0452), true + case "dlarr": + // SOUTH WEST ARROW + return rune(0x2199), true + case "dlcorn": + // BOTTOM LEFT CORNER + return rune(0x231e), true + case "dlcrop": + // BOTTOM LEFT CROP + return rune(0x230d), true + case "dlharb": + // DOWNWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2959), true + case "dollar": + // DOLLAR SIGN + return rune(0x24), true + case "dopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL D + return rune(0x01d555), true + case "doteq": + // APPROACHES THE LIMIT + return rune(0x2250), true + case "doteqdot": + // GEOMETRICALLY EQUAL TO + return rune(0x2251), true + case "dotminus": + // DOT MINUS + return rune(0x2238), true + case "dotplus": + // DOT PLUS + return rune(0x2214), true + case "dotsquare": + // SQUARED DOT OPERATOR + return rune(0x22a1), true + case "dot": + // DOT ABOVE + return rune(0x02d9), true + case "doublebarwedge": + // PERSPECTIVE + return rune(0x2306), true + case "downarrow": + // DOWNWARDS ARROW + return rune(0x2193), true + case "downdownarrows": + // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "downharpoonleft": + // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "downharpoonright": + // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "drarr": + // SOUTH EAST ARROW + return rune(0x2198), true + case "drbkarow": + // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW + return rune(0x2910), true + case "drcorn": + // BOTTOM RIGHT CORNER + return rune(0x231f), true + case "drcrop": + // BOTTOM RIGHT CROP + return rune(0x230c), true + case "drharb": + // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2955), true + case "dscr": + // MATHEMATICAL SCRIPT SMALL D + return rune(0x01d4b9), true + case "dscy": + // CYRILLIC SMALL LETTER DZE + return rune(0x0455), true + case "dsol": + // SOLIDUS WITH OVERBAR + return rune(0x29f6), true + case "dstrok": + // LATIN SMALL LETTER D WITH STROKE + return rune(0x0111), true + case "dtdot": + // DOWN RIGHT DIAGONAL ELLIPSIS + return rune(0x22f1), true + case "dtrif": + // BLACK DOWN-POINTING SMALL TRIANGLE + return rune(0x25be), true + case "dtri": + // WHITE DOWN-POINTING SMALL TRIANGLE + return rune(0x25bf), true + case "dtrilf": + // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK + return rune(0x29e8), true + case "dtrirf": + // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK + return rune(0x29e9), true + case "duarr": + // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + return rune(0x21f5), true + case "duhar": + // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x296f), true + case "dumap": + // DOUBLE-ENDED MULTIMAP + return rune(0x29df), true + case "dwangle": + // OBLIQUE ANGLE OPENING UP + return rune(0x29a6), true + case "dzcy": + // CYRILLIC SMALL LETTER DZHE + return rune(0x045f), true + case "dzigrarr": + // LONG RIGHTWARDS SQUIGGLE ARROW + return rune(0x27ff), true + } + + case 'e': + switch name { + case "eDDot": + // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW + return rune(0x2a77), true + case "eDot": + // GEOMETRICALLY EQUAL TO + return rune(0x2251), true + case "eacgr": + // GREEK SMALL LETTER EPSILON WITH TONOS + return rune(0x03ad), true + case "eacute": + // LATIN SMALL LETTER E WITH ACUTE + return rune(0xe9), true + case "easter": + // EQUALS WITH ASTERISK + return rune(0x2a6e), true + case "ecaron": + // LATIN SMALL LETTER E WITH CARON + return rune(0x011b), true + case "ecir": + // RING IN EQUAL TO + return rune(0x2256), true + case "ecirc": + // LATIN SMALL LETTER E WITH CIRCUMFLEX + return rune(0xea), true + case "ecolon": + // EQUALS COLON + return rune(0x2255), true + case "ecy": + // CYRILLIC SMALL LETTER E + return rune(0x044d), true + case "edot": + // LATIN SMALL LETTER E WITH DOT ABOVE + return rune(0x0117), true + case "ee": + // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true + case "eeacgr": + // GREEK SMALL LETTER ETA WITH TONOS + return rune(0x03ae), true + case "eegr": + // GREEK SMALL LETTER ETA + return rune(0x03b7), true + case "efDot": + // APPROXIMATELY EQUAL TO OR THE IMAGE OF + return rune(0x2252), true + case "efr": + // MATHEMATICAL FRAKTUR SMALL E + return rune(0x01d522), true + case "egr": + // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "egs": + // SLANTED EQUAL TO OR GREATER-THAN + return rune(0x2a96), true + case "egsdot": + // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE + return rune(0x2a98), true + case "eg": + // DOUBLE-LINE EQUAL TO OR GREATER-THAN + return rune(0x2a9a), true + case "egrave": + // LATIN SMALL LETTER E WITH GRAVE + return rune(0xe8), true + case "elinters": + // ELECTRICAL INTERSECTION + return rune(0x23e7), true + case "ell": + // SCRIPT SMALL L + return rune(0x2113), true + case "els": + // SLANTED EQUAL TO OR LESS-THAN + return rune(0x2a95), true + case "elsdot": + // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE + return rune(0x2a97), true + case "el": + // DOUBLE-LINE EQUAL TO OR LESS-THAN + return rune(0x2a99), true + case "emacr": + // LATIN SMALL LETTER E WITH MACRON + return rune(0x0113), true + case "empty": + // EMPTY SET + return rune(0x2205), true + case "emptyset": + // EMPTY SET + return rune(0x2205), true + case "emptyv": + // EMPTY SET + return rune(0x2205), true + case "emsp13": + // THREE-PER-EM SPACE + return rune(0x2004), true + case "emsp14": + // FOUR-PER-EM SPACE + return rune(0x2005), true + case "emsp": + // EM SPACE + return rune(0x2003), true + case "eng": + // LATIN SMALL LETTER ENG + return rune(0x014b), true + case "ensp": + // EN SPACE + return rune(0x2002), true + case "eogon": + // LATIN SMALL LETTER E WITH OGONEK + return rune(0x0119), true + case "eopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL E + return rune(0x01d556), true + case "epar": + // EQUAL AND PARALLEL TO + return rune(0x22d5), true + case "eparsl": + // EQUALS SIGN AND SLANTED PARALLEL + return rune(0x29e3), true + case "eplus": + // EQUALS SIGN ABOVE PLUS SIGN + return rune(0x2a71), true + case "epsilon": + // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "epsis": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "epsiv": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "epsi": + // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "eqcirc": + // RING IN EQUAL TO + return rune(0x2256), true + case "eqcolon": + // EQUALS COLON + return rune(0x2255), true + case "eqeq": + // TWO CONSECUTIVE EQUALS SIGNS + return rune(0x2a75), true + case "eqsim": + // MINUS TILDE + return rune(0x2242), true + case "eqslantgtr": + // SLANTED EQUAL TO OR GREATER-THAN + return rune(0x2a96), true + case "eqslantless": + // SLANTED EQUAL TO OR LESS-THAN + return rune(0x2a95), true + case "equals": + // EQUALS SIGN + return rune(0x3d), true + case "equest": + // QUESTIONED EQUAL TO + return rune(0x225f), true + case "equiv": + // IDENTICAL TO + return rune(0x2261), true + case "equivDD": + // EQUIVALENT WITH FOUR DOTS ABOVE + return rune(0x2a78), true + case "eqvparsl": + // IDENTICAL TO AND SLANTED PARALLEL + return rune(0x29e5), true + case "erDot": + // IMAGE OF OR APPROXIMATELY EQUAL TO + return rune(0x2253), true + case "erarr": + // EQUALS SIGN ABOVE RIGHTWARDS ARROW + return rune(0x2971), true + case "escr": + // SCRIPT SMALL E + return rune(0x212f), true + case "esdot": + // APPROACHES THE LIMIT + return rune(0x2250), true + case "esim": + // MINUS TILDE + return rune(0x2242), true + case "eta": + // GREEK SMALL LETTER ETA + return rune(0x03b7), true + case "eth": + // LATIN SMALL LETTER ETH + return rune(0xf0), true + case "euml": + // LATIN SMALL LETTER E WITH DIAERESIS + return rune(0xeb), true + case "euro": + // EURO SIGN + return rune(0x20ac), true + case "excl": + // EXCLAMATION MARK + return rune(0x21), true + case "exist": + // THERE EXISTS + return rune(0x2203), true + case "expectation": + // SCRIPT CAPITAL E + return rune(0x2130), true + case "exponentiale": + // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true + } + + case 'f': + switch name { + case "fallingdotseq": + // APPROXIMATELY EQUAL TO OR THE IMAGE OF + return rune(0x2252), true + case "fbowtie": + // BLACK BOWTIE + return rune(0x29d3), true + case "fcy": + // CYRILLIC SMALL LETTER EF + return rune(0x0444), true + case "fdiag": + // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + return rune(0x2572), true + case "fdiordi": + // FALLING DIAGONAL CROSSING RISING DIAGONAL + return rune(0x292c), true + case "fdonearr": + // FALLING DIAGONAL CROSSING NORTH EAST ARROW + return rune(0x292f), true + case "female": + // FEMALE SIGN + return rune(0x2640), true + case "ffilig": + // LATIN SMALL LIGATURE FFI + return rune(0xfb03), true + case "fflig": + // LATIN SMALL LIGATURE FF + return rune(0xfb00), true + case "ffllig": + // LATIN SMALL LIGATURE FFL + return rune(0xfb04), true + case "ffr": + // MATHEMATICAL FRAKTUR SMALL F + return rune(0x01d523), true + case "fhrglass": + // BLACK HOURGLASS + return rune(0x29d7), true + case "filig": + // LATIN SMALL LIGATURE FI + return rune(0xfb01), true + case "fjlig": + // fj ligature + return rune(0x66), true + case "flat": + // MUSIC FLAT SIGN + return rune(0x266d), true + case "fllig": + // LATIN SMALL LIGATURE FL + return rune(0xfb02), true + case "fltns": + // WHITE PARALLELOGRAM + return rune(0x25b1), true + case "fnof": + // LATIN SMALL LETTER F WITH HOOK + return rune(0x0192), true + case "fopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL F + return rune(0x01d557), true + case "forall": + // FOR ALL + return rune(0x2200), true + case "fork": + // PITCHFORK + return rune(0x22d4), true + case "forkv": + // ELEMENT OF OPENING DOWNWARDS + return rune(0x2ad9), true + case "fpartint": + // FINITE PART INTEGRAL + return rune(0x2a0d), true + case "frac12": + // VULGAR FRACTION ONE HALF + return rune(0xbd), true + case "frac13": + // VULGAR FRACTION ONE THIRD + return rune(0x2153), true + case "frac14": + // VULGAR FRACTION ONE QUARTER + return rune(0xbc), true + case "frac15": + // VULGAR FRACTION ONE FIFTH + return rune(0x2155), true + case "frac16": + // VULGAR FRACTION ONE SIXTH + return rune(0x2159), true + case "frac18": + // VULGAR FRACTION ONE EIGHTH + return rune(0x215b), true + case "frac23": + // VULGAR FRACTION TWO THIRDS + return rune(0x2154), true + case "frac25": + // VULGAR FRACTION TWO FIFTHS + return rune(0x2156), true + case "frac34": + // VULGAR FRACTION THREE QUARTERS + return rune(0xbe), true + case "frac35": + // VULGAR FRACTION THREE FIFTHS + return rune(0x2157), true + case "frac38": + // VULGAR FRACTION THREE EIGHTHS + return rune(0x215c), true + case "frac45": + // VULGAR FRACTION FOUR FIFTHS + return rune(0x2158), true + case "frac56": + // VULGAR FRACTION FIVE SIXTHS + return rune(0x215a), true + case "frac58": + // VULGAR FRACTION FIVE EIGHTHS + return rune(0x215d), true + case "frac78": + // VULGAR FRACTION SEVEN EIGHTHS + return rune(0x215e), true + case "frasl": + // FRACTION SLASH + return rune(0x2044), true + case "frown": + // FROWN + return rune(0x2322), true + case "fscr": + // MATHEMATICAL SCRIPT SMALL F + return rune(0x01d4bb), true + } + + case 'g': + switch name { + case "gE": + // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "gEl": + // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + return rune(0x2a8c), true + case "gacute": + // LATIN SMALL LETTER G WITH ACUTE + return rune(0x01f5), true + case "gammad": + // GREEK SMALL LETTER DIGAMMA + return rune(0x03dd), true + case "gamma": + // GREEK SMALL LETTER GAMMA + return rune(0x03b3), true + case "gap": + // GREATER-THAN OR APPROXIMATE + return rune(0x2a86), true + case "gbreve": + // LATIN SMALL LETTER G WITH BREVE + return rune(0x011f), true + case "gcedil": + // LATIN SMALL LETTER G WITH CEDILLA + return rune(0x0123), true + case "gcirc": + // LATIN SMALL LETTER G WITH CIRCUMFLEX + return rune(0x011d), true + case "gcy": + // CYRILLIC SMALL LETTER GHE + return rune(0x0433), true + case "gdot": + // LATIN SMALL LETTER G WITH DOT ABOVE + return rune(0x0121), true + case "ge": + // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "gel": + // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "geq": + // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "geqq": + // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "geqslant": + // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "gesl": + // GREATER-THAN slanted EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "ges": + // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "gescc": + // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + return rune(0x2aa9), true + case "gesdot": + // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + return rune(0x2a80), true + case "gesdoto": + // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + return rune(0x2a82), true + case "gesdotol": + // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT + return rune(0x2a84), true + case "gesles": + // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL + return rune(0x2a94), true + case "gfr": + // MATHEMATICAL FRAKTUR SMALL G + return rune(0x01d524), true + case "gg": + // MUCH GREATER-THAN + return rune(0x226b), true + case "ggg": + // VERY MUCH GREATER-THAN + return rune(0x22d9), true + case "ggr": + // GREEK SMALL LETTER GAMMA + return rune(0x03b3), true + case "gimel": + // GIMEL SYMBOL + return rune(0x2137), true + case "gjcy": + // CYRILLIC SMALL LETTER GJE + return rune(0x0453), true + case "gl": + // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "glE": + // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL + return rune(0x2a92), true + case "gla": + // GREATER-THAN BESIDE LESS-THAN + return rune(0x2aa5), true + case "glj": + // GREATER-THAN OVERLAPPING LESS-THAN + return rune(0x2aa4), true + case "gnE": + // GREATER-THAN BUT NOT EQUAL TO + return rune(0x2269), true + case "gnap": + // GREATER-THAN AND NOT APPROXIMATE + return rune(0x2a8a), true + case "gnapprox": + // GREATER-THAN AND NOT APPROXIMATE + return rune(0x2a8a), true + case "gneqq": + // GREATER-THAN BUT NOT EQUAL TO + return rune(0x2269), true + case "gne": + // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a88), true + case "gneq": + // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a88), true + case "gnsim": + // GREATER-THAN BUT NOT EQUIVALENT TO + return rune(0x22e7), true + case "gopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL G + return rune(0x01d558), true + case "grave": + // GRAVE ACCENT + return rune(0x60), true + case "gscr": + // SCRIPT SMALL G + return rune(0x210a), true + case "gsdot": + // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gsim": + // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "gsime": + // GREATER-THAN ABOVE SIMILAR OR EQUAL + return rune(0x2a8e), true + case "gsiml": + // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN + return rune(0x2a90), true + case "gtcc": + // GREATER-THAN CLOSED BY CURVE + return rune(0x2aa7), true + case "gtcir": + // GREATER-THAN WITH CIRCLE INSIDE + return rune(0x2a7a), true + case "gtdot": + // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gtlPar": + // DOUBLE LEFT ARC GREATER-THAN BRACKET + return rune(0x2995), true + case "gtquest": + // GREATER-THAN WITH QUESTION MARK ABOVE + return rune(0x2a7c), true + case "gtrapprox": + // GREATER-THAN OR APPROXIMATE + return rune(0x2a86), true + case "gtrarr": + // GREATER-THAN ABOVE RIGHTWARDS ARROW + return rune(0x2978), true + case "gtrdot": + // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gtreqless": + // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "gtreqqless": + // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + return rune(0x2a8c), true + case "gtrless": + // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "gtrpar": + // SPHERICAL ANGLE OPENING LEFT + return rune(0x29a0), true + case "gtrsim": + // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "gt": + // GREATER-THAN SIGN + return rune(0x3e), true + case "gvertneqq": + // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2269), true + case "gvnE": + // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2269), true + } + + case 'h': + switch name { + case "hArr": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "hairsp": + // HAIR SPACE + return rune(0x200a), true + case "half": + // VULGAR FRACTION ONE HALF + return rune(0xbd), true + case "hamilt": + // SCRIPT CAPITAL H + return rune(0x210b), true + case "hardcy": + // CYRILLIC SMALL LETTER HARD SIGN + return rune(0x044a), true + case "harrw": + // LEFT RIGHT WAVE ARROW + return rune(0x21ad), true + case "harr": + // LEFT RIGHT ARROW + return rune(0x2194), true + case "harrcir": + // LEFT RIGHT ARROW THROUGH SMALL CIRCLE + return rune(0x2948), true + case "hbar": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "hcirc": + // LATIN SMALL LETTER H WITH CIRCUMFLEX + return rune(0x0125), true + case "hearts": + // BLACK HEART SUIT + return rune(0x2665), true + case "heartsuit": + // BLACK HEART SUIT + return rune(0x2665), true + case "hellip": + // HORIZONTAL ELLIPSIS + return rune(0x2026), true + case "hercon": + // HERMITIAN CONJUGATE MATRIX + return rune(0x22b9), true + case "hfr": + // MATHEMATICAL FRAKTUR SMALL H + return rune(0x01d525), true + case "hksearow": + // SOUTH EAST ARROW WITH HOOK + return rune(0x2925), true + case "hkswarow": + // SOUTH WEST ARROW WITH HOOK + return rune(0x2926), true + case "hoarr": + // LEFT RIGHT OPEN-HEADED ARROW + return rune(0x21ff), true + case "homtht": + // HOMOTHETIC + return rune(0x223b), true + case "hookleftarrow": + // LEFTWARDS ARROW WITH HOOK + return rune(0x21a9), true + case "hookrightarrow": + // RIGHTWARDS ARROW WITH HOOK + return rune(0x21aa), true + case "hopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL H + return rune(0x01d559), true + case "horbar": + // HORIZONTAL BAR + return rune(0x2015), true + case "hrglass": + // WHITE HOURGLASS + return rune(0x29d6), true + case "hscr": + // MATHEMATICAL SCRIPT SMALL H + return rune(0x01d4bd), true + case "hslash": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "hstrok": + // LATIN SMALL LETTER H WITH STROKE + return rune(0x0127), true + case "htimes": + // VECTOR OR CROSS PRODUCT + return rune(0x2a2f), true + case "hybull": + // HYPHEN BULLET + return rune(0x2043), true + case "hyphen": + // HYPHEN + return rune(0x2010), true + } + + case 'i': + switch name { + case "iacgr": + // GREEK SMALL LETTER IOTA WITH TONOS + return rune(0x03af), true + case "iacute": + // LATIN SMALL LETTER I WITH ACUTE + return rune(0xed), true + case "ic": + // INVISIBLE SEPARATOR + return rune(0x2063), true + case "icirc": + // LATIN SMALL LETTER I WITH CIRCUMFLEX + return rune(0xee), true + case "icy": + // CYRILLIC SMALL LETTER I + return rune(0x0438), true + case "idiagr": + // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + return rune(0x0390), true + case "idigr": + // GREEK SMALL LETTER IOTA WITH DIALYTIKA + return rune(0x03ca), true + case "iecy": + // CYRILLIC SMALL LETTER IE + return rune(0x0435), true + case "iexcl": + // INVERTED EXCLAMATION MARK + return rune(0xa1), true + case "iff": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "ifr": + // MATHEMATICAL FRAKTUR SMALL I + return rune(0x01d526), true + case "igr": + // GREEK SMALL LETTER IOTA + return rune(0x03b9), true + case "igrave": + // LATIN SMALL LETTER I WITH GRAVE + return rune(0xec), true + case "iiint": + // TRIPLE INTEGRAL + return rune(0x222d), true + case "ii": + // DOUBLE-STRUCK ITALIC SMALL I + return rune(0x2148), true + case "iiiint": + // QUADRUPLE INTEGRAL OPERATOR + return rune(0x2a0c), true + case "iinfin": + // INCOMPLETE INFINITY + return rune(0x29dc), true + case "iiota": + // TURNED GREEK SMALL LETTER IOTA + return rune(0x2129), true + case "ijlig": + // LATIN SMALL LIGATURE IJ + return rune(0x0133), true + case "imacr": + // LATIN SMALL LETTER I WITH MACRON + return rune(0x012b), true + case "image": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "imagline": + // SCRIPT CAPITAL I + return rune(0x2110), true + case "imagpart": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "imath": + // LATIN SMALL LETTER DOTLESS I + return rune(0x0131), true + case "imof": + // IMAGE OF + return rune(0x22b7), true + case "imped": + // LATIN CAPITAL LETTER Z WITH STROKE + return rune(0x01b5), true + case "in": + // ELEMENT OF + return rune(0x2208), true + case "incare": + // CARE OF + return rune(0x2105), true + case "infin": + // INFINITY + return rune(0x221e), true + case "infintie": + // TIE OVER INFINITY + return rune(0x29dd), true + case "inodot": + // LATIN SMALL LETTER DOTLESS I + return rune(0x0131), true + case "int": + // INTEGRAL + return rune(0x222b), true + case "intcal": + // INTERCALATE + return rune(0x22ba), true + case "integers": + // DOUBLE-STRUCK CAPITAL Z + return rune(0x2124), true + case "intercal": + // INTERCALATE + return rune(0x22ba), true + case "intlarhk": + // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK + return rune(0x2a17), true + case "intprod": + // INTERIOR PRODUCT + return rune(0x2a3c), true + case "iocy": + // CYRILLIC SMALL LETTER IO + return rune(0x0451), true + case "iogon": + // LATIN SMALL LETTER I WITH OGONEK + return rune(0x012f), true + case "iopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL I + return rune(0x01d55a), true + case "iota": + // GREEK SMALL LETTER IOTA + return rune(0x03b9), true + case "iprod": + // INTERIOR PRODUCT + return rune(0x2a3c), true + case "iprodr": + // RIGHTHAND INTERIOR PRODUCT + return rune(0x2a3d), true + case "iquest": + // INVERTED QUESTION MARK + return rune(0xbf), true + case "iscr": + // MATHEMATICAL SCRIPT SMALL I + return rune(0x01d4be), true + case "isin": + // ELEMENT OF + return rune(0x2208), true + case "isinE": + // ELEMENT OF WITH TWO HORIZONTAL STROKES + return rune(0x22f9), true + case "isindot": + // ELEMENT OF WITH DOT ABOVE + return rune(0x22f5), true + case "isinsv": + // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22f3), true + case "isins": + // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22f4), true + case "isinv": + // ELEMENT OF + return rune(0x2208), true + case "isinvb": + // ELEMENT OF WITH UNDERBAR + return rune(0x22f8), true + case "it": + // INVISIBLE TIMES + return rune(0x2062), true + case "itilde": + // LATIN SMALL LETTER I WITH TILDE + return rune(0x0129), true + case "iukcy": + // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + return rune(0x0456), true + case "iuml": + // LATIN SMALL LETTER I WITH DIAERESIS + return rune(0xef), true + } + + case 'j': + switch name { + case "jcirc": + // LATIN SMALL LETTER J WITH CIRCUMFLEX + return rune(0x0135), true + case "jcy": + // CYRILLIC SMALL LETTER SHORT I + return rune(0x0439), true + case "jfr": + // MATHEMATICAL FRAKTUR SMALL J + return rune(0x01d527), true + case "jmath": + // LATIN SMALL LETTER DOTLESS J + return rune(0x0237), true + case "jnodot": + // LATIN SMALL LETTER DOTLESS J + return rune(0x0237), true + case "jopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL J + return rune(0x01d55b), true + case "jscr": + // MATHEMATICAL SCRIPT SMALL J + return rune(0x01d4bf), true + case "jsercy": + // CYRILLIC SMALL LETTER JE + return rune(0x0458), true + case "jukcy": + // CYRILLIC SMALL LETTER UKRAINIAN IE + return rune(0x0454), true + } + + case 'k': + switch name { + case "kappav": + // GREEK KAPPA SYMBOL + return rune(0x03f0), true + case "kappa": + // GREEK SMALL LETTER KAPPA + return rune(0x03ba), true + case "kcedil": + // LATIN SMALL LETTER K WITH CEDILLA + return rune(0x0137), true + case "kcy": + // CYRILLIC SMALL LETTER KA + return rune(0x043a), true + case "kfr": + // MATHEMATICAL FRAKTUR SMALL K + return rune(0x01d528), true + case "kgr": + // GREEK SMALL LETTER KAPPA + return rune(0x03ba), true + case "kgreen": + // LATIN SMALL LETTER KRA + return rune(0x0138), true + case "khcy": + // CYRILLIC SMALL LETTER HA + return rune(0x0445), true + case "khgr": + // GREEK SMALL LETTER CHI + return rune(0x03c7), true + case "kjcy": + // CYRILLIC SMALL LETTER KJE + return rune(0x045c), true + case "kopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL K + return rune(0x01d55c), true + case "koppa": + // GREEK LETTER KOPPA + return rune(0x03de), true + case "kscr": + // MATHEMATICAL SCRIPT SMALL K + return rune(0x01d4c0), true + } + + case 'l': + switch name { + case "lAarr": + // LEFTWARDS TRIPLE ARROW + return rune(0x21da), true + case "lArr": + // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "lAtail": + // LEFTWARDS DOUBLE ARROW-TAIL + return rune(0x291b), true + case "lBarr": + // LEFTWARDS TRIPLE DASH ARROW + return rune(0x290e), true + case "lE": + // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "lEg": + // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + return rune(0x2a8b), true + case "lHar": + // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN + return rune(0x2962), true + case "lacute": + // LATIN SMALL LETTER L WITH ACUTE + return rune(0x013a), true + case "laemptyv": + // EMPTY SET WITH LEFT ARROW ABOVE + return rune(0x29b4), true + case "lagran": + // SCRIPT CAPITAL L + return rune(0x2112), true + case "lambda": + // GREEK SMALL LETTER LAMDA + return rune(0x03bb), true + case "lang": + // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "langd": + // LEFT ANGLE BRACKET WITH DOT + return rune(0x2991), true + case "langle": + // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "lap": + // LESS-THAN OR APPROXIMATE + return rune(0x2a85), true + case "laquo": + // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + return rune(0xab), true + case "larr2": + // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "larrb": + // LEFTWARDS ARROW TO BAR + return rune(0x21e4), true + case "larrhk": + // LEFTWARDS ARROW WITH HOOK + return rune(0x21a9), true + case "larrlp": + // LEFTWARDS ARROW WITH LOOP + return rune(0x21ab), true + case "larrtl": + // LEFTWARDS ARROW WITH TAIL + return rune(0x21a2), true + case "larr": + // LEFTWARDS ARROW + return rune(0x2190), true + case "larrbfs": + // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND + return rune(0x291f), true + case "larrfs": + // LEFTWARDS ARROW TO BLACK DIAMOND + return rune(0x291d), true + case "larrpl": + // LEFT-SIDE ARC ANTICLOCKWISE ARROW + return rune(0x2939), true + case "larrsim": + // LEFTWARDS ARROW ABOVE TILDE OPERATOR + return rune(0x2973), true + case "latail": + // LEFTWARDS ARROW-TAIL + return rune(0x2919), true + case "lat": + // LARGER THAN + return rune(0x2aab), true + case "late": + // LARGER THAN OR EQUAL TO + return rune(0x2aad), true + case "lates": + // LARGER THAN OR slanted EQUAL + return rune(0x2aad), true + case "lbarr": + // LEFTWARDS DOUBLE DASH ARROW + return rune(0x290c), true + case "lbbrk": + // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + return rune(0x2772), true + case "lbrace": + // LEFT CURLY BRACKET + return rune(0x7b), true + case "lbrack": + // LEFT SQUARE BRACKET + return rune(0x5b), true + case "lbrke": + // LEFT SQUARE BRACKET WITH UNDERBAR + return rune(0x298b), true + case "lbrksld": + // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + return rune(0x298f), true + case "lbrkslu": + // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER + return rune(0x298d), true + case "lcaron": + // LATIN SMALL LETTER L WITH CARON + return rune(0x013e), true + case "lcedil": + // LATIN SMALL LETTER L WITH CEDILLA + return rune(0x013c), true + case "lceil": + // LEFT CEILING + return rune(0x2308), true + case "lcub": + // LEFT CURLY BRACKET + return rune(0x7b), true + case "lcy": + // CYRILLIC SMALL LETTER EL + return rune(0x043b), true + case "ldca": + // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS + return rune(0x2936), true + case "ldharb": + // LEFTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2956), true + case "ldot": + // LESS-THAN WITH DOT + return rune(0x22d6), true + case "ldquor": + // DOUBLE LOW-9 QUOTATION MARK + return rune(0x201e), true + case "ldquo": + // LEFT DOUBLE QUOTATION MARK + return rune(0x201c), true + case "ldrdhar": + // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + return rune(0x2967), true + case "ldrdshar": + // LEFT BARB DOWN RIGHT BARB DOWN HARPOON + return rune(0x2950), true + case "ldrushar": + // LEFT BARB DOWN RIGHT BARB UP HARPOON + return rune(0x294b), true + case "ldsh": + // DOWNWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b2), true + case "leftarrowtail": + // LEFTWARDS ARROW WITH TAIL + return rune(0x21a2), true + case "leftarrow": + // LEFTWARDS ARROW + return rune(0x2190), true + case "leftharpoondown": + // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "leftharpoonup": + // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "leftleftarrows": + // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "leftrightarrows": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "leftrightarrow": + // LEFT RIGHT ARROW + return rune(0x2194), true + case "leftrightharpoons": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "leftrightsquigarrow": + // LEFT RIGHT WAVE ARROW + return rune(0x21ad), true + case "le": + // LESS-THAN OR EQUAL TO + return rune(0x2264), true + case "leftthreetimes": + // LEFT SEMIDIRECT PRODUCT + return rune(0x22cb), true + case "leg": + // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "leq": + // LESS-THAN OR EQUAL TO + return rune(0x2264), true + case "leqq": + // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "leqslant": + // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "lesg": + // LESS-THAN slanted EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "lessdot": + // LESS-THAN WITH DOT + return rune(0x22d6), true + case "lesseqgtr": + // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "lessgtr": + // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "lesssim": + // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "les": + // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "lescc": + // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + return rune(0x2aa8), true + case "lesdot": + // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + return rune(0x2a7f), true + case "lesdoto": + // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + return rune(0x2a81), true + case "lesdotor": + // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT + return rune(0x2a83), true + case "lesges": + // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL + return rune(0x2a93), true + case "lessapprox": + // LESS-THAN OR APPROXIMATE + return rune(0x2a85), true + case "lesseqqgtr": + // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + return rune(0x2a8b), true + case "lfbowtie": + // BOWTIE WITH LEFT HALF BLACK + return rune(0x29d1), true + case "lfisht": + // LEFT FISH TAIL + return rune(0x297c), true + case "lfloor": + // LEFT FLOOR + return rune(0x230a), true + case "lfr": + // MATHEMATICAL FRAKTUR SMALL L + return rune(0x01d529), true + case "lftimes": + // TIMES WITH LEFT HALF BLACK + return rune(0x29d4), true + case "lg": + // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "lgE": + // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL + return rune(0x2a91), true + case "lgr": + // GREEK SMALL LETTER LAMDA + return rune(0x03bb), true + case "lhard": + // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "lharu": + // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "lharul": + // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + return rune(0x296a), true + case "lhblk": + // LOWER HALF BLOCK + return rune(0x2584), true + case "ljcy": + // CYRILLIC SMALL LETTER LJE + return rune(0x0459), true + case "llarr": + // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "ll": + // MUCH LESS-THAN + return rune(0x226a), true + case "llcorner": + // BOTTOM LEFT CORNER + return rune(0x231e), true + case "llhard": + // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + return rune(0x296b), true + case "lltrif": + // BLACK LOWER LEFT TRIANGLE + return rune(0x25e3), true + case "lltri": + // LOWER LEFT TRIANGLE + return rune(0x25fa), true + case "lmidot": + // LATIN SMALL LETTER L WITH MIDDLE DOT + return rune(0x0140), true + case "lmoust": + // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION + return rune(0x23b0), true + case "lmoustache": + // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION + return rune(0x23b0), true + case "lnE": + // LESS-THAN BUT NOT EQUAL TO + return rune(0x2268), true + case "lnap": + // LESS-THAN AND NOT APPROXIMATE + return rune(0x2a89), true + case "lnapprox": + // LESS-THAN AND NOT APPROXIMATE + return rune(0x2a89), true + case "lneqq": + // LESS-THAN BUT NOT EQUAL TO + return rune(0x2268), true + case "lne": + // LESS-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a87), true + case "lneq": + // LESS-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a87), true + case "lnsim": + // LESS-THAN BUT NOT EQUIVALENT TO + return rune(0x22e6), true + case "loang": + // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET + return rune(0x27ec), true + case "loarr": + // LEFTWARDS OPEN-HEADED ARROW + return rune(0x21fd), true + case "lobrk": + // MATHEMATICAL LEFT WHITE SQUARE BRACKET + return rune(0x27e6), true + case "locub": + // LEFT WHITE CURLY BRACKET + return rune(0x2983), true + case "longleftarrow": + // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "longleftrightarrow": + // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "longmapsto": + // LONG RIGHTWARDS ARROW FROM BAR + return rune(0x27fc), true + case "longrightarrow": + // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "looparrowleft": + // LEFTWARDS ARROW WITH LOOP + return rune(0x21ab), true + case "looparrowright": + // RIGHTWARDS ARROW WITH LOOP + return rune(0x21ac), true + case "lopar": + // LEFT WHITE PARENTHESIS + return rune(0x2985), true + case "lopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL L + return rune(0x01d55d), true + case "loplus": + // PLUS SIGN IN LEFT HALF CIRCLE + return rune(0x2a2d), true + case "lotimes": + // MULTIPLICATION SIGN IN LEFT HALF CIRCLE + return rune(0x2a34), true + case "lowast": + // LOW ASTERISK + return rune(0x204e), true + case "lowbar": + // LOW LINE + return rune(0x5f), true + case "lowint": + // INTEGRAL WITH UNDERBAR + return rune(0x2a1c), true + case "loz": + // LOZENGE + return rune(0x25ca), true + case "lozenge": + // LOZENGE + return rune(0x25ca), true + case "lozf": + // BLACK LOZENGE + return rune(0x29eb), true + case "lpargt": + // SPHERICAL ANGLE OPENING LEFT + return rune(0x29a0), true + case "lparlt": + // LEFT ARC LESS-THAN BRACKET + return rune(0x2993), true + case "lpar": + // LEFT PARENTHESIS + return rune(0x28), true + case "lrarr2": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "lrarr": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "lrcorner": + // BOTTOM RIGHT CORNER + return rune(0x231f), true + case "lrhar": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "lrhar2": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "lrhard": + // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + return rune(0x296d), true + case "lrm": + // LEFT-TO-RIGHT MARK + return rune(0x200e), true + case "lrtri": + // RIGHT TRIANGLE + return rune(0x22bf), true + case "lsaquo": + // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + return rune(0x2039), true + case "lscr": + // MATHEMATICAL SCRIPT SMALL L + return rune(0x01d4c1), true + case "lsh": + // UPWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b0), true + case "lsim": + // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "lsime": + // LESS-THAN ABOVE SIMILAR OR EQUAL + return rune(0x2a8d), true + case "lsimg": + // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN + return rune(0x2a8f), true + case "lsqb": + // LEFT SQUARE BRACKET + return rune(0x5b), true + case "lsquor": + // SINGLE LOW-9 QUOTATION MARK + return rune(0x201a), true + case "lsquo": + // LEFT SINGLE QUOTATION MARK + return rune(0x2018), true + case "lstrok": + // LATIN SMALL LETTER L WITH STROKE + return rune(0x0142), true + case "ltcc": + // LESS-THAN CLOSED BY CURVE + return rune(0x2aa6), true + case "ltcir": + // LESS-THAN WITH CIRCLE INSIDE + return rune(0x2a79), true + case "ltdot": + // LESS-THAN WITH DOT + return rune(0x22d6), true + case "lthree": + // LEFT SEMIDIRECT PRODUCT + return rune(0x22cb), true + case "ltimes": + // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + return rune(0x22c9), true + case "ltlarr": + // LESS-THAN ABOVE LEFTWARDS ARROW + return rune(0x2976), true + case "ltquest": + // LESS-THAN WITH QUESTION MARK ABOVE + return rune(0x2a7b), true + case "ltrPar": + // DOUBLE RIGHT ARC LESS-THAN BRACKET + return rune(0x2996), true + case "ltrie": + // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "ltrif": + // BLACK LEFT-POINTING SMALL TRIANGLE + return rune(0x25c2), true + case "ltri": + // WHITE LEFT-POINTING SMALL TRIANGLE + return rune(0x25c3), true + case "ltrivb": + // LEFT TRIANGLE BESIDE VERTICAL BAR + return rune(0x29cf), true + case "lt": + // LESS-THAN SIGN + return rune(0x3c), true + case "luharb": + // LEFTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2952), true + case "lurdshar": + // LEFT BARB UP RIGHT BARB DOWN HARPOON + return rune(0x294a), true + case "luruhar": + // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP + return rune(0x2966), true + case "lurushar": + // LEFT BARB UP RIGHT BARB UP HARPOON + return rune(0x294e), true + case "lvertneqq": + // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2268), true + case "lvnE": + // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2268), true + } + + case 'm': + switch name { + case "mDDot": + // GEOMETRIC PROPORTION + return rune(0x223a), true + case "macr": + // MACRON + return rune(0xaf), true + case "male": + // MALE SIGN + return rune(0x2642), true + case "malt": + // MALTESE CROSS + return rune(0x2720), true + case "maltese": + // MALTESE CROSS + return rune(0x2720), true + case "mapstodown": + // DOWNWARDS ARROW FROM BAR + return rune(0x21a7), true + case "mapsto": + // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "map": + // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "mapstoleft": + // LEFTWARDS ARROW FROM BAR + return rune(0x21a4), true + case "mapstoup": + // UPWARDS ARROW FROM BAR + return rune(0x21a5), true + case "marker": + // BLACK VERTICAL RECTANGLE + return rune(0x25ae), true + case "mcomma": + // MINUS SIGN WITH COMMA ABOVE + return rune(0x2a29), true + case "mcy": + // CYRILLIC SMALL LETTER EM + return rune(0x043c), true + case "mdash": + // EM DASH + return rune(0x2014), true + case "measuredangle": + // MEASURED ANGLE + return rune(0x2221), true + case "mfr": + // MATHEMATICAL FRAKTUR SMALL M + return rune(0x01d52a), true + case "mgr": + // GREEK SMALL LETTER MU + return rune(0x03bc), true + case "mho": + // INVERTED OHM SIGN + return rune(0x2127), true + case "micro": + // MICRO SIGN + return rune(0xb5), true + case "mid": + // DIVIDES + return rune(0x2223), true + case "midast": + // ASTERISK + return rune(0x2a), true + case "midcir": + // VERTICAL LINE WITH CIRCLE BELOW + return rune(0x2af0), true + case "middot": + // MIDDLE DOT + return rune(0xb7), true + case "minus": + // MINUS SIGN + return rune(0x2212), true + case "minusb": + // SQUARED MINUS + return rune(0x229f), true + case "minusd": + // DOT MINUS + return rune(0x2238), true + case "minusdu": + // MINUS SIGN WITH DOT BELOW + return rune(0x2a2a), true + case "mlcp": + // TRANSVERSAL INTERSECTION + return rune(0x2adb), true + case "mldr": + // HORIZONTAL ELLIPSIS + return rune(0x2026), true + case "mnplus": + // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "models": + // MODELS + return rune(0x22a7), true + case "mopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL M + return rune(0x01d55e), true + case "mp": + // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "mscr": + // MATHEMATICAL SCRIPT SMALL M + return rune(0x01d4c2), true + case "mstpos": + // INVERTED LAZY S + return rune(0x223e), true + case "multimap": + // MULTIMAP + return rune(0x22b8), true + case "mumap": + // MULTIMAP + return rune(0x22b8), true + case "mu": + // GREEK SMALL LETTER MU + return rune(0x03bc), true + } + + case 'n': + switch name { + case "nGg": + // VERY MUCH GREATER-THAN with slash + return rune(0x22d9), true + case "nGtv": + // MUCH GREATER THAN with slash + return rune(0x226b), true + case "nGt": + // MUCH GREATER THAN with vertical line + return rune(0x226b), true + case "nLeftarrow": + // LEFTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cd), true + case "nLeftrightarrow": + // LEFT RIGHT DOUBLE ARROW WITH STROKE + return rune(0x21ce), true + case "nLl": + // VERY MUCH LESS-THAN with slash + return rune(0x22d8), true + case "nLtv": + // MUCH LESS THAN with slash + return rune(0x226a), true + case "nLt": + // MUCH LESS THAN with vertical line + return rune(0x226a), true + case "nRightarrow": + // RIGHTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cf), true + case "nVDash": + // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + return rune(0x22af), true + case "nVdash": + // DOES NOT FORCE + return rune(0x22ae), true + case "nabla": + // NABLA + return rune(0x2207), true + case "nacute": + // LATIN SMALL LETTER N WITH ACUTE + return rune(0x0144), true + case "nang": + // ANGLE with vertical line + return rune(0x2220), true + case "nap": + // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "napE": + // APPROXIMATELY EQUAL OR EQUAL TO with slash + return rune(0x2a70), true + case "napid": + // TRIPLE TILDE with slash + return rune(0x224b), true + case "napos": + // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + return rune(0x0149), true + case "napprox": + // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "naturals": + // DOUBLE-STRUCK CAPITAL N + return rune(0x2115), true + case "natur": + // MUSIC NATURAL SIGN + return rune(0x266e), true + case "natural": + // MUSIC NATURAL SIGN + return rune(0x266e), true + case "nbsp": + // NO-BREAK SPACE + return rune(0xa0), true + case "nbump": + // GEOMETRICALLY EQUIVALENT TO with slash + return rune(0x224e), true + case "nbumpe": + // DIFFERENCE BETWEEN with slash + return rune(0x224f), true + case "ncap": + // INTERSECTION WITH OVERBAR + return rune(0x2a43), true + case "ncaron": + // LATIN SMALL LETTER N WITH CARON + return rune(0x0148), true + case "ncedil": + // LATIN SMALL LETTER N WITH CEDILLA + return rune(0x0146), true + case "ncong": + // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + return rune(0x2247), true + case "ncongdot": + // CONGRUENT WITH DOT ABOVE with slash + return rune(0x2a6d), true + case "ncup": + // UNION WITH OVERBAR + return rune(0x2a42), true + case "ncy": + // CYRILLIC SMALL LETTER EN + return rune(0x043d), true + case "ndash": + // EN DASH + return rune(0x2013), true + case "neArr": + // NORTH EAST DOUBLE ARROW + return rune(0x21d7), true + case "nearrow": + // NORTH EAST ARROW + return rune(0x2197), true + case "nearr": + // NORTH EAST ARROW + return rune(0x2197), true + case "nedot": + // APPROACHES THE LIMIT with slash + return rune(0x2250), true + case "nesim": + // MINUS TILDE with slash + return rune(0x2242), true + case "nexist": + // THERE DOES NOT EXIST + return rune(0x2204), true + case "nexists": + // THERE DOES NOT EXIST + return rune(0x2204), true + case "ne": + // NOT EQUAL TO + return rune(0x2260), true + case "nearhk": + // NORTH EAST ARROW WITH HOOK + return rune(0x2924), true + case "neonwarr": + // NORTH EAST ARROW CROSSING NORTH WEST ARROW + return rune(0x2931), true + case "neosearr": + // NORTH EAST ARROW CROSSING SOUTH EAST ARROW + return rune(0x292e), true + case "nequiv": + // NOT IDENTICAL TO + return rune(0x2262), true + case "nesear": + // NORTH EAST ARROW AND SOUTH EAST ARROW + return rune(0x2928), true + case "neswsarr": + // NORTH EAST AND SOUTH WEST ARROW + return rune(0x2922), true + case "nfr": + // MATHEMATICAL FRAKTUR SMALL N + return rune(0x01d52b), true + case "ngE": + // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "ngeqq": + // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "nge": + // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "ngeq": + // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "ngeqslant": + // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "nges": + // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "ngr": + // GREEK SMALL LETTER NU + return rune(0x03bd), true + case "ngsim": + // NEITHER GREATER-THAN NOR EQUIVALENT TO + return rune(0x2275), true + case "ngt": + // NOT GREATER-THAN + return rune(0x226f), true + case "ngtr": + // NOT GREATER-THAN + return rune(0x226f), true + case "nhArr": + // LEFT RIGHT DOUBLE ARROW WITH STROKE + return rune(0x21ce), true + case "nharr": + // LEFT RIGHT ARROW WITH STROKE + return rune(0x21ae), true + case "nhpar": + // PARALLEL WITH HORIZONTAL STROKE + return rune(0x2af2), true + case "niv": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "ni": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "nisd": + // CONTAINS WITH LONG HORIZONTAL STROKE + return rune(0x22fa), true + case "nis": + // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22fc), true + case "njcy": + // CYRILLIC SMALL LETTER NJE + return rune(0x045a), true + case "nlArr": + // LEFTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cd), true + case "nlE": + // LESS-THAN OVER EQUAL TO with slash + return rune(0x2266), true + case "nlarr": + // LEFTWARDS ARROW WITH STROKE + return rune(0x219a), true + case "nldr": + // TWO DOT LEADER + return rune(0x2025), true + case "nleftarrow": + // LEFTWARDS ARROW WITH STROKE + return rune(0x219a), true + case "nleftrightarrow": + // LEFT RIGHT ARROW WITH STROKE + return rune(0x21ae), true + case "nleqq": + // LESS-THAN OVER EQUAL TO with slash + return rune(0x2266), true + case "nless": + // NOT LESS-THAN + return rune(0x226e), true + case "nle": + // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "nleq": + // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "nleqslant": + // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "nles": + // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "nlsim": + // NEITHER LESS-THAN NOR EQUIVALENT TO + return rune(0x2274), true + case "nlt": + // NOT LESS-THAN + return rune(0x226e), true + case "nltri": + // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "nltrie": + // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "nltrivb": + // LEFT TRIANGLE BESIDE VERTICAL BAR with slash + return rune(0x29cf), true + case "nmid": + // DOES NOT DIVIDE + return rune(0x2224), true + case "nopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL N + return rune(0x01d55f), true + case "notin": + // NOT AN ELEMENT OF + return rune(0x2209), true + case "notinE": + // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash + return rune(0x22f9), true + case "notindot": + // ELEMENT OF WITH DOT ABOVE with slash + return rune(0x22f5), true + case "notinva": + // NOT AN ELEMENT OF + return rune(0x2209), true + case "notinvb": + // SMALL ELEMENT OF WITH OVERBAR + return rune(0x22f7), true + case "notinvc": + // ELEMENT OF WITH OVERBAR + return rune(0x22f6), true + case "notni": + // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "notniva": + // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "notnivb": + // SMALL CONTAINS WITH OVERBAR + return rune(0x22fe), true + case "notnivc": + // CONTAINS WITH OVERBAR + return rune(0x22fd), true + case "not": + // NOT SIGN + return rune(0xac), true + case "npart": + // PARTIAL DIFFERENTIAL with slash + return rune(0x2202), true + case "npar": + // NOT PARALLEL TO + return rune(0x2226), true + case "nparallel": + // NOT PARALLEL TO + return rune(0x2226), true + case "nparsl": + // DOUBLE SOLIDUS OPERATOR with reverse slash + return rune(0x2afd), true + case "npolint": + // LINE INTEGRATION NOT INCLUDING THE POLE + return rune(0x2a14), true + case "nprsim": + // PRECEDES OR EQUIVALENT TO with slash + return rune(0x227e), true + case "npr": + // DOES NOT PRECEDE + return rune(0x2280), true + case "nprcue": + // DOES NOT PRECEDE OR EQUAL + return rune(0x22e0), true + case "nprec": + // DOES NOT PRECEDE + return rune(0x2280), true + case "npre": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "npreceq": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "nrArr": + // RIGHTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cf), true + case "nrarrw": + // RIGHTWARDS WAVE ARROW with slash + return rune(0x219d), true + case "nrarr": + // RIGHTWARDS ARROW WITH STROKE + return rune(0x219b), true + case "nrarrc": + // WAVE ARROW POINTING DIRECTLY RIGHT with slash + return rune(0x2933), true + case "nrightarrow": + // RIGHTWARDS ARROW WITH STROKE + return rune(0x219b), true + case "nrtri": + // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "nrtrie": + // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "nsGt": + // DOUBLE NESTED GREATER-THAN with slash + return rune(0x2aa2), true + case "nsLt": + // DOUBLE NESTED LESS-THAN with slash + return rune(0x2aa1), true + case "nscsim": + // SUCCEEDS OR EQUIVALENT TO with slash + return rune(0x227f), true + case "nsc": + // DOES NOT SUCCEED + return rune(0x2281), true + case "nsccue": + // DOES NOT SUCCEED OR EQUAL + return rune(0x22e1), true + case "nsce": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "nscr": + // MATHEMATICAL SCRIPT SMALL N + return rune(0x01d4c3), true + case "nshortmid": + // DOES NOT DIVIDE + return rune(0x2224), true + case "nshortparallel": + // NOT PARALLEL TO + return rune(0x2226), true + case "nsim": + // NOT TILDE + return rune(0x2241), true + case "nsime": + // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "nsimeq": + // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "nsmid": + // DOES NOT DIVIDE + return rune(0x2224), true + case "nspar": + // NOT PARALLEL TO + return rune(0x2226), true + case "nsqsub": + // SQUARE IMAGE OF with slash + return rune(0x228f), true + case "nsqsube": + // NOT SQUARE IMAGE OF OR EQUAL TO + return rune(0x22e2), true + case "nsqsup": + // SQUARE ORIGINAL OF with slash + return rune(0x2290), true + case "nsqsupe": + // NOT SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x22e3), true + case "nsubset": + // SUBSET OF with vertical line + return rune(0x2282), true + case "nsub": + // NOT A SUBSET OF + return rune(0x2284), true + case "nsubE": + // SUBSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac5), true + case "nsube": + // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "nsubseteq": + // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "nsubseteqq": + // SUBSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac5), true + case "nsucc": + // DOES NOT SUCCEED + return rune(0x2281), true + case "nsucceq": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "nsupset": + // SUPERSET OF with vertical line + return rune(0x2283), true + case "nsup": + // NOT A SUPERSET OF + return rune(0x2285), true + case "nsupE": + // SUPERSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac6), true + case "nsupe": + // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "nsupseteq": + // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "nsupseteqq": + // SUPERSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac6), true + case "ntgl": + // NEITHER GREATER-THAN NOR LESS-THAN + return rune(0x2279), true + case "ntilde": + // LATIN SMALL LETTER N WITH TILDE + return rune(0xf1), true + case "ntlg": + // NEITHER LESS-THAN NOR GREATER-THAN + return rune(0x2278), true + case "ntriangleleft": + // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "ntrianglelefteq": + // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "ntriangleright": + // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "ntrianglerighteq": + // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "numero": + // NUMERO SIGN + return rune(0x2116), true + case "numsp": + // FIGURE SPACE + return rune(0x2007), true + case "nu": + // GREEK SMALL LETTER NU + return rune(0x03bd), true + case "num": + // NUMBER SIGN + return rune(0x23), true + case "nvDash": + // NOT TRUE + return rune(0x22ad), true + case "nvHarr": + // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2904), true + case "nvap": + // EQUIVALENT TO with vertical line + return rune(0x224d), true + case "nvbrtri": + // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash + return rune(0x29d0), true + case "nvdash": + // DOES NOT PROVE + return rune(0x22ac), true + case "nvge": + // GREATER-THAN OR EQUAL TO with vertical line + return rune(0x2265), true + case "nvgt": + // GREATER-THAN SIGN with vertical line + return rune(0x3e), true + case "nvinfin": + // INFINITY NEGATED WITH VERTICAL BAR + return rune(0x29de), true + case "nvlArr": + // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2902), true + case "nvle": + // LESS-THAN OR EQUAL TO with vertical line + return rune(0x2264), true + case "nvltrie": + // NORMAL SUBGROUP OF OR EQUAL TO with vertical line + return rune(0x22b4), true + case "nvlt": + // LESS-THAN SIGN with vertical line + return rune(0x3c), true + case "nvrArr": + // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2903), true + case "nvrtrie": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line + return rune(0x22b5), true + case "nvsim": + // TILDE OPERATOR with vertical line + return rune(0x223c), true + case "nwArr": + // NORTH WEST DOUBLE ARROW + return rune(0x21d6), true + case "nwarhk": + // NORTH WEST ARROW WITH HOOK + return rune(0x2923), true + case "nwarrow": + // NORTH WEST ARROW + return rune(0x2196), true + case "nwarr": + // NORTH WEST ARROW + return rune(0x2196), true + case "nwnear": + // NORTH WEST ARROW AND NORTH EAST ARROW + return rune(0x2927), true + case "nwonearr": + // NORTH WEST ARROW CROSSING NORTH EAST ARROW + return rune(0x2932), true + case "nwsesarr": + // NORTH WEST AND SOUTH EAST ARROW + return rune(0x2921), true + } + + case 'o': + switch name { + case "oS": + // CIRCLED LATIN CAPITAL LETTER S + return rune(0x24c8), true + case "oacgr": + // GREEK SMALL LETTER OMICRON WITH TONOS + return rune(0x03cc), true + case "oacute": + // LATIN SMALL LETTER O WITH ACUTE + return rune(0xf3), true + case "oast": + // CIRCLED ASTERISK OPERATOR + return rune(0x229b), true + case "obsol": + // CIRCLED REVERSE SOLIDUS + return rune(0x29b8), true + case "ocir": + // CIRCLED RING OPERATOR + return rune(0x229a), true + case "ocirc": + // LATIN SMALL LETTER O WITH CIRCUMFLEX + return rune(0xf4), true + case "ocy": + // CYRILLIC SMALL LETTER O + return rune(0x043e), true + case "odash": + // CIRCLED DASH + return rune(0x229d), true + case "odblac": + // LATIN SMALL LETTER O WITH DOUBLE ACUTE + return rune(0x0151), true + case "odiv": + // CIRCLED DIVISION SIGN + return rune(0x2a38), true + case "odot": + // CIRCLED DOT OPERATOR + return rune(0x2299), true + case "odsold": + // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN + return rune(0x29bc), true + case "oelig": + // LATIN SMALL LIGATURE OE + return rune(0x0153), true + case "ofcir": + // CIRCLED BULLET + return rune(0x29bf), true + case "ofr": + // MATHEMATICAL FRAKTUR SMALL O + return rune(0x01d52c), true + case "ogon": + // OGONEK + return rune(0x02db), true + case "ogr": + // GREEK SMALL LETTER OMICRON + return rune(0x03bf), true + case "ograve": + // LATIN SMALL LETTER O WITH GRAVE + return rune(0xf2), true + case "ogt": + // CIRCLED GREATER-THAN + return rune(0x29c1), true + case "ohacgr": + // GREEK SMALL LETTER OMEGA WITH TONOS + return rune(0x03ce), true + case "ohbar": + // CIRCLE WITH HORIZONTAL BAR + return rune(0x29b5), true + case "ohgr": + // GREEK SMALL LETTER OMEGA + return rune(0x03c9), true + case "ohm": + // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "oint": + // CONTOUR INTEGRAL + return rune(0x222e), true + case "olarr": + // ANTICLOCKWISE OPEN CIRCLE ARROW + return rune(0x21ba), true + case "olcir": + // CIRCLED WHITE BULLET + return rune(0x29be), true + case "olcross": + // CIRCLE WITH SUPERIMPOSED X + return rune(0x29bb), true + case "oline": + // OVERLINE + return rune(0x203e), true + case "olt": + // CIRCLED LESS-THAN + return rune(0x29c0), true + case "omacr": + // LATIN SMALL LETTER O WITH MACRON + return rune(0x014d), true + case "omega": + // GREEK SMALL LETTER OMEGA + return rune(0x03c9), true + case "omicron": + // GREEK SMALL LETTER OMICRON + return rune(0x03bf), true + case "omid": + // CIRCLED VERTICAL BAR + return rune(0x29b6), true + case "ominus": + // CIRCLED MINUS + return rune(0x2296), true + case "oopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL O + return rune(0x01d560), true + case "opar": + // CIRCLED PARALLEL + return rune(0x29b7), true + case "operp": + // CIRCLED PERPENDICULAR + return rune(0x29b9), true + case "opfgamma": + // DOUBLE-STRUCK SMALL GAMMA + return rune(0x213d), true + case "opfpi": + // DOUBLE-STRUCK CAPITAL PI + return rune(0x213f), true + case "opfsum": + // DOUBLE-STRUCK N-ARY SUMMATION + return rune(0x2140), true + case "oplus": + // CIRCLED PLUS + return rune(0x2295), true + case "orarr": + // CLOCKWISE OPEN CIRCLE ARROW + return rune(0x21bb), true + case "or": + // LOGICAL OR + return rune(0x2228), true + case "orderof": + // SCRIPT SMALL O + return rune(0x2134), true + case "order": + // SCRIPT SMALL O + return rune(0x2134), true + case "ord": + // LOGICAL OR WITH HORIZONTAL DASH + return rune(0x2a5d), true + case "ordf": + // FEMININE ORDINAL INDICATOR + return rune(0xaa), true + case "ordm": + // MASCULINE ORDINAL INDICATOR + return rune(0xba), true + case "origof": + // ORIGINAL OF + return rune(0x22b6), true + case "oror": + // TWO INTERSECTING LOGICAL OR + return rune(0x2a56), true + case "orslope": + // SLOPING LARGE OR + return rune(0x2a57), true + case "orv": + // LOGICAL OR WITH MIDDLE STEM + return rune(0x2a5b), true + case "oscr": + // SCRIPT SMALL O + return rune(0x2134), true + case "oslash": + // LATIN SMALL LETTER O WITH STROKE + return rune(0xf8), true + case "osol": + // CIRCLED DIVISION SLASH + return rune(0x2298), true + case "otilde": + // LATIN SMALL LETTER O WITH TILDE + return rune(0xf5), true + case "otimes": + // CIRCLED TIMES + return rune(0x2297), true + case "otimesas": + // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT + return rune(0x2a36), true + case "ouml": + // LATIN SMALL LETTER O WITH DIAERESIS + return rune(0xf6), true + case "ovbar": + // APL FUNCTIONAL SYMBOL CIRCLE STILE + return rune(0x233d), true + case "ovrbrk": + // TOP SQUARE BRACKET + return rune(0x23b4), true + case "ovrcub": + // TOP CURLY BRACKET + return rune(0x23de), true + case "ovrpar": + // TOP PARENTHESIS + return rune(0x23dc), true + case "oxuarr": + // UP ARROW THROUGH CIRCLE + return rune(0x29bd), true + } + + case 'p': + switch name { + case "part": + // PARTIAL DIFFERENTIAL + return rune(0x2202), true + case "par": + // PARALLEL TO + return rune(0x2225), true + case "parallel": + // PARALLEL TO + return rune(0x2225), true + case "para": + // PILCROW SIGN + return rune(0xb6), true + case "parsim": + // PARALLEL WITH TILDE OPERATOR + return rune(0x2af3), true + case "parsl": + // DOUBLE SOLIDUS OPERATOR + return rune(0x2afd), true + case "pcy": + // CYRILLIC SMALL LETTER PE + return rune(0x043f), true + case "percnt": + // PERCENT SIGN + return rune(0x25), true + case "period": + // FULL STOP + return rune(0x2e), true + case "permil": + // PER MILLE SIGN + return rune(0x2030), true + case "perp": + // UP TACK + return rune(0x22a5), true + case "pertenk": + // PER TEN THOUSAND SIGN + return rune(0x2031), true + case "pfr": + // MATHEMATICAL FRAKTUR SMALL P + return rune(0x01d52d), true + case "pgr": + // GREEK SMALL LETTER PI + return rune(0x03c0), true + case "phgr": + // GREEK SMALL LETTER PHI + return rune(0x03c6), true + case "phis": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "phiv": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "phi": + // GREEK SMALL LETTER PHI + return rune(0x03c6), true + case "phmmat": + // SCRIPT CAPITAL M + return rune(0x2133), true + case "phone": + // BLACK TELEPHONE + return rune(0x260e), true + case "pitchfork": + // PITCHFORK + return rune(0x22d4), true + case "piv": + // GREEK PI SYMBOL + return rune(0x03d6), true + case "pi": + // GREEK SMALL LETTER PI + return rune(0x03c0), true + case "planck": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "planckh": + // PLANCK CONSTANT + return rune(0x210e), true + case "plankv": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "plusacir": + // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE + return rune(0x2a23), true + case "plusb": + // SQUARED PLUS + return rune(0x229e), true + case "pluscir": + // PLUS SIGN WITH SMALL CIRCLE ABOVE + return rune(0x2a22), true + case "plusdo": + // DOT PLUS + return rune(0x2214), true + case "plusdu": + // PLUS SIGN WITH DOT BELOW + return rune(0x2a25), true + case "pluse": + // PLUS SIGN ABOVE EQUALS SIGN + return rune(0x2a72), true + case "plusmn": + // PLUS-MINUS SIGN + return rune(0xb1), true + case "plussim": + // PLUS SIGN WITH TILDE BELOW + return rune(0x2a26), true + case "plustrif": + // PLUS SIGN WITH BLACK TRIANGLE + return rune(0x2a28), true + case "plustwo": + // PLUS SIGN WITH SUBSCRIPT TWO + return rune(0x2a27), true + case "plus": + // PLUS SIGN + return rune(0x2b), true + case "pm": + // PLUS-MINUS SIGN + return rune(0xb1), true + case "pointint": + // INTEGRAL AROUND A POINT OPERATOR + return rune(0x2a15), true + case "popf": + // MATHEMATICAL DOUBLE-STRUCK SMALL P + return rune(0x01d561), true + case "pound": + // POUND SIGN + return rune(0xa3), true + case "prod": + // N-ARY PRODUCT + return rune(0x220f), true + case "prop": + // PROPORTIONAL TO + return rune(0x221d), true + case "propto": + // PROPORTIONAL TO + return rune(0x221d), true + case "pr": + // PRECEDES + return rune(0x227a), true + case "prE": + // PRECEDES ABOVE EQUALS SIGN + return rune(0x2ab3), true + case "prap": + // PRECEDES ABOVE ALMOST EQUAL TO + return rune(0x2ab7), true + case "prcue": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "prec": + // PRECEDES + return rune(0x227a), true + case "preccurlyeq": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "precnsim": + // PRECEDES BUT NOT EQUIVALENT TO + return rune(0x22e8), true + case "precsim": + // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "pre": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "precapprox": + // PRECEDES ABOVE ALMOST EQUAL TO + return rune(0x2ab7), true + case "preceq": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "precnapprox": + // PRECEDES ABOVE NOT ALMOST EQUAL TO + return rune(0x2ab9), true + case "precneqq": + // PRECEDES ABOVE NOT EQUAL TO + return rune(0x2ab5), true + case "primes": + // DOUBLE-STRUCK CAPITAL P + return rune(0x2119), true + case "prime": + // PRIME + return rune(0x2032), true + case "prnE": + // PRECEDES ABOVE NOT EQUAL TO + return rune(0x2ab5), true + case "prnap": + // PRECEDES ABOVE NOT ALMOST EQUAL TO + return rune(0x2ab9), true + case "prnsim": + // PRECEDES BUT NOT EQUIVALENT TO + return rune(0x22e8), true + case "profalar": + // ALL AROUND-PROFILE + return rune(0x232e), true + case "profline": + // ARC + return rune(0x2312), true + case "profsurf": + // SEGMENT + return rune(0x2313), true + case "prsim": + // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "prurel": + // PRECEDES UNDER RELATION + return rune(0x22b0), true + case "pscr": + // MATHEMATICAL SCRIPT SMALL P + return rune(0x01d4c5), true + case "psgr": + // GREEK SMALL LETTER PSI + return rune(0x03c8), true + case "psi": + // GREEK SMALL LETTER PSI + return rune(0x03c8), true + case "puncsp": + // PUNCTUATION SPACE + return rune(0x2008), true + } + + case 'q': + switch name { + case "qfr": + // MATHEMATICAL FRAKTUR SMALL Q + return rune(0x01d52e), true + case "qint": + // QUADRUPLE INTEGRAL OPERATOR + return rune(0x2a0c), true + case "qopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL Q + return rune(0x01d562), true + case "qprime": + // QUADRUPLE PRIME + return rune(0x2057), true + case "qscr": + // MATHEMATICAL SCRIPT SMALL Q + return rune(0x01d4c6), true + case "quaternions": + // DOUBLE-STRUCK CAPITAL H + return rune(0x210d), true + case "quatint": + // QUATERNION INTEGRAL OPERATOR + return rune(0x2a16), true + case "questeq": + // QUESTIONED EQUAL TO + return rune(0x225f), true + case "quest": + // QUESTION MARK + return rune(0x3f), true + case "quot": + // QUOTATION MARK + return rune(0x22), true + } + + case 'r': + switch name { + case "rAarr": + // RIGHTWARDS TRIPLE ARROW + return rune(0x21db), true + case "rArr": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "rAtail": + // RIGHTWARDS DOUBLE ARROW-TAIL + return rune(0x291c), true + case "rBarr": + // RIGHTWARDS TRIPLE DASH ARROW + return rune(0x290f), true + case "rHar": + // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + return rune(0x2964), true + case "race": + // REVERSED TILDE with underline + return rune(0x223d), true + case "racute": + // LATIN SMALL LETTER R WITH ACUTE + return rune(0x0155), true + case "radic": + // SQUARE ROOT + return rune(0x221a), true + case "raemptyv": + // EMPTY SET WITH RIGHT ARROW ABOVE + return rune(0x29b3), true + case "rang": + // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "rangd": + // RIGHT ANGLE BRACKET WITH DOT + return rune(0x2992), true + case "range": + // REVERSED ANGLE WITH UNDERBAR + return rune(0x29a5), true + case "rangle": + // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "raquo": + // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + return rune(0xbb), true + case "rarr2": + // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rarr3": + // THREE RIGHTWARDS ARROWS + return rune(0x21f6), true + case "rarrb": + // RIGHTWARDS ARROW TO BAR + return rune(0x21e5), true + case "rarrhk": + // RIGHTWARDS ARROW WITH HOOK + return rune(0x21aa), true + case "rarrlp": + // RIGHTWARDS ARROW WITH LOOP + return rune(0x21ac), true + case "rarrtl": + // RIGHTWARDS ARROW WITH TAIL + return rune(0x21a3), true + case "rarrw": + // RIGHTWARDS WAVE ARROW + return rune(0x219d), true + case "rarr": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "rarrap": + // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO + return rune(0x2975), true + case "rarrbfs": + // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND + return rune(0x2920), true + case "rarrc": + // WAVE ARROW POINTING DIRECTLY RIGHT + return rune(0x2933), true + case "rarrfs": + // RIGHTWARDS ARROW TO BLACK DIAMOND + return rune(0x291e), true + case "rarrpl": + // RIGHTWARDS ARROW WITH PLUS BELOW + return rune(0x2945), true + case "rarrsim": + // RIGHTWARDS ARROW ABOVE TILDE OPERATOR + return rune(0x2974), true + case "rarrx": + // RIGHTWARDS ARROW THROUGH X + return rune(0x2947), true + case "ratail": + // RIGHTWARDS ARROW-TAIL + return rune(0x291a), true + case "ratio": + // RATIO + return rune(0x2236), true + case "rationals": + // DOUBLE-STRUCK CAPITAL Q + return rune(0x211a), true + case "rbarr": + // RIGHTWARDS DOUBLE DASH ARROW + return rune(0x290d), true + case "rbbrk": + // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + return rune(0x2773), true + case "rbrace": + // RIGHT CURLY BRACKET + return rune(0x7d), true + case "rbrack": + // RIGHT SQUARE BRACKET + return rune(0x5d), true + case "rbrke": + // RIGHT SQUARE BRACKET WITH UNDERBAR + return rune(0x298c), true + case "rbrksld": + // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + return rune(0x298e), true + case "rbrkslu": + // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER + return rune(0x2990), true + case "rcaron": + // LATIN SMALL LETTER R WITH CARON + return rune(0x0159), true + case "rcedil": + // LATIN SMALL LETTER R WITH CEDILLA + return rune(0x0157), true + case "rceil": + // RIGHT CEILING + return rune(0x2309), true + case "rcub": + // RIGHT CURLY BRACKET + return rune(0x7d), true + case "rcy": + // CYRILLIC SMALL LETTER ER + return rune(0x0440), true + case "rdca": + // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS + return rune(0x2937), true + case "rdharb": + // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2957), true + case "rdiag": + // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + return rune(0x2571), true + case "rdiofdi": + // RISING DIAGONAL CROSSING FALLING DIAGONAL + return rune(0x292b), true + case "rdldhar": + // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN + return rune(0x2969), true + case "rdosearr": + // RISING DIAGONAL CROSSING SOUTH EAST ARROW + return rune(0x2930), true + case "rdquor": + // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "rdquo": + // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "rdsh": + // DOWNWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b3), true + case "realpart": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "reals": + // DOUBLE-STRUCK CAPITAL R + return rune(0x211d), true + case "real": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "realine": + // SCRIPT CAPITAL R + return rune(0x211b), true + case "rect": + // WHITE RECTANGLE + return rune(0x25ad), true + case "reg": + // REGISTERED SIGN + return rune(0xae), true + case "rfbowtie": + // BOWTIE WITH RIGHT HALF BLACK + return rune(0x29d2), true + case "rfisht": + // RIGHT FISH TAIL + return rune(0x297d), true + case "rfloor": + // RIGHT FLOOR + return rune(0x230b), true + case "rfr": + // MATHEMATICAL FRAKTUR SMALL R + return rune(0x01d52f), true + case "rftimes": + // TIMES WITH RIGHT HALF BLACK + return rune(0x29d5), true + case "rgr": + // GREEK SMALL LETTER RHO + return rune(0x03c1), true + case "rhard": + // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "rharu": + // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "rharul": + // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + return rune(0x296c), true + case "rhov": + // GREEK RHO SYMBOL + return rune(0x03f1), true + case "rho": + // GREEK SMALL LETTER RHO + return rune(0x03c1), true + case "rightarrowtail": + // RIGHTWARDS ARROW WITH TAIL + return rune(0x21a3), true + case "rightarrow": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "rightharpoondown": + // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "rightharpoonup": + // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "rightleftarrows": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rightleftharpoons": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rightrightarrows": + // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rightsquigarrow": + // RIGHTWARDS WAVE ARROW + return rune(0x219d), true + case "rightthreetimes": + // RIGHT SEMIDIRECT PRODUCT + return rune(0x22cc), true + case "rimply": + // RIGHT DOUBLE ARROW WITH ROUNDED HEAD + return rune(0x2970), true + case "ring": + // RING ABOVE + return rune(0x02da), true + case "risingdotseq": + // IMAGE OF OR APPROXIMATELY EQUAL TO + return rune(0x2253), true + case "rlarr2": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rlarr": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rlhar": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rlhar2": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rlm": + // RIGHT-TO-LEFT MARK + return rune(0x200f), true + case "rmoust": + // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION + return rune(0x23b1), true + case "rmoustache": + // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION + return rune(0x23b1), true + case "rnmid": + // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH + return rune(0x2aee), true + case "roang": + // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET + return rune(0x27ed), true + case "roarr": + // RIGHTWARDS OPEN-HEADED ARROW + return rune(0x21fe), true + case "robrk": + // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + return rune(0x27e7), true + case "rocub": + // RIGHT WHITE CURLY BRACKET + return rune(0x2984), true + case "ropar": + // RIGHT WHITE PARENTHESIS + return rune(0x2986), true + case "ropf": + // MATHEMATICAL DOUBLE-STRUCK SMALL R + return rune(0x01d563), true + case "roplus": + // PLUS SIGN IN RIGHT HALF CIRCLE + return rune(0x2a2e), true + case "rotimes": + // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE + return rune(0x2a35), true + case "rpargt": + // RIGHT ARC GREATER-THAN BRACKET + return rune(0x2994), true + case "rpar": + // RIGHT PARENTHESIS + return rune(0x29), true + case "rppolint": + // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE + return rune(0x2a12), true + case "rrarr": + // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rsaquo": + // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + return rune(0x203a), true + case "rscr": + // MATHEMATICAL SCRIPT SMALL R + return rune(0x01d4c7), true + case "rsh": + // UPWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b1), true + case "rsolbar": + // REVERSE SOLIDUS WITH HORIZONTAL STROKE + return rune(0x29f7), true + case "rsqb": + // RIGHT SQUARE BRACKET + return rune(0x5d), true + case "rsquor": + // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "rsquo": + // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "rthree": + // RIGHT SEMIDIRECT PRODUCT + return rune(0x22cc), true + case "rtimes": + // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + return rune(0x22ca), true + case "rtrie": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "rtrif": + // BLACK RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b8), true + case "rtri": + // WHITE RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b9), true + case "rtriltri": + // RIGHT TRIANGLE ABOVE LEFT TRIANGLE + return rune(0x29ce), true + case "ruharb": + // RIGHTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2953), true + case "ruluhar": + // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP + return rune(0x2968), true + case "rx": + // PRESCRIPTION TAKE + return rune(0x211e), true + } + + case 's': + switch name { + case "sacute": + // LATIN SMALL LETTER S WITH ACUTE + return rune(0x015b), true + case "samalg": + // N-ARY COPRODUCT + return rune(0x2210), true + case "sampi": + // GREEK LETTER SAMPI + return rune(0x03e0), true + case "sbquo": + // SINGLE LOW-9 QUOTATION MARK + return rune(0x201a), true + case "sbsol": + // SMALL REVERSE SOLIDUS + return rune(0xfe68), true + case "sc": + // SUCCEEDS + return rune(0x227b), true + case "scE": + // SUCCEEDS ABOVE EQUALS SIGN + return rune(0x2ab4), true + case "scap": + // SUCCEEDS ABOVE ALMOST EQUAL TO + return rune(0x2ab8), true + case "scaron": + // LATIN SMALL LETTER S WITH CARON + return rune(0x0161), true + case "sccue": + // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "scedil": + // LATIN SMALL LETTER S WITH CEDILLA + return rune(0x015f), true + case "sce": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "scirc": + // LATIN SMALL LETTER S WITH CIRCUMFLEX + return rune(0x015d), true + case "scnE": + // SUCCEEDS ABOVE NOT EQUAL TO + return rune(0x2ab6), true + case "scnap": + // SUCCEEDS ABOVE NOT ALMOST EQUAL TO + return rune(0x2aba), true + case "scnsim": + // SUCCEEDS BUT NOT EQUIVALENT TO + return rune(0x22e9), true + case "scpolint": + // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE + return rune(0x2a13), true + case "scsim": + // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "scy": + // CYRILLIC SMALL LETTER ES + return rune(0x0441), true + case "sdotb": + // SQUARED DOT OPERATOR + return rune(0x22a1), true + case "sdot": + // DOT OPERATOR + return rune(0x22c5), true + case "sdote": + // EQUALS SIGN WITH DOT BELOW + return rune(0x2a66), true + case "seArr": + // SOUTH EAST DOUBLE ARROW + return rune(0x21d8), true + case "searhk": + // SOUTH EAST ARROW WITH HOOK + return rune(0x2925), true + case "searrow": + // SOUTH EAST ARROW + return rune(0x2198), true + case "searr": + // SOUTH EAST ARROW + return rune(0x2198), true + case "sect": + // SECTION SIGN + return rune(0xa7), true + case "semi": + // SEMICOLON + return rune(0x3b), true + case "seonearr": + // SOUTH EAST ARROW CROSSING NORTH EAST ARROW + return rune(0x292d), true + case "seswar": + // SOUTH EAST ARROW AND SOUTH WEST ARROW + return rune(0x2929), true + case "setminus": + // SET MINUS + return rune(0x2216), true + case "setmn": + // SET MINUS + return rune(0x2216), true + case "sext": + // SIX POINTED BLACK STAR + return rune(0x2736), true + case "sfgr": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sfrown": + // FROWN + return rune(0x2322), true + case "sfr": + // MATHEMATICAL FRAKTUR SMALL S + return rune(0x01d530), true + case "sgr": + // GREEK SMALL LETTER SIGMA + return rune(0x03c3), true + case "sharp": + // MUSIC SHARP SIGN + return rune(0x266f), true + case "shchcy": + // CYRILLIC SMALL LETTER SHCHA + return rune(0x0449), true + case "shcy": + // CYRILLIC SMALL LETTER SHA + return rune(0x0448), true + case "shortmid": + // DIVIDES + return rune(0x2223), true + case "shortparallel": + // PARALLEL TO + return rune(0x2225), true + case "shuffle": + // SHUFFLE PRODUCT + return rune(0x29e2), true + case "shy": + // SOFT HYPHEN + return rune(0xad), true + case "sigma": + // GREEK SMALL LETTER SIGMA + return rune(0x03c3), true + case "sigmaf": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sigmav": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sim": + // TILDE OPERATOR + return rune(0x223c), true + case "simdot": + // TILDE OPERATOR WITH DOT ABOVE + return rune(0x2a6a), true + case "sime": + // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "simeq": + // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "simg": + // SIMILAR OR GREATER-THAN + return rune(0x2a9e), true + case "simgE": + // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN + return rune(0x2aa0), true + case "siml": + // SIMILAR OR LESS-THAN + return rune(0x2a9d), true + case "simlE": + // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN + return rune(0x2a9f), true + case "simne": + // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO + return rune(0x2246), true + case "simplus": + // PLUS SIGN WITH TILDE ABOVE + return rune(0x2a24), true + case "simrarr": + // TILDE OPERATOR ABOVE RIGHTWARDS ARROW + return rune(0x2972), true + case "slarr": + // LEFTWARDS ARROW + return rune(0x2190), true + case "slint": + // INTEGRAL AVERAGE WITH SLASH + return rune(0x2a0f), true + case "smallsetminus": + // SET MINUS + return rune(0x2216), true + case "smashp": + // SMASH PRODUCT + return rune(0x2a33), true + case "smeparsl": + // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE + return rune(0x29e4), true + case "smid": + // DIVIDES + return rune(0x2223), true + case "smile": + // SMILE + return rune(0x2323), true + case "smt": + // SMALLER THAN + return rune(0x2aaa), true + case "smte": + // SMALLER THAN OR EQUAL TO + return rune(0x2aac), true + case "smtes": + // SMALLER THAN OR slanted EQUAL + return rune(0x2aac), true + case "softcy": + // CYRILLIC SMALL LETTER SOFT SIGN + return rune(0x044c), true + case "solbar": + // APL FUNCTIONAL SYMBOL SLASH BAR + return rune(0x233f), true + case "solb": + // SQUARED RISING DIAGONAL SLASH + return rune(0x29c4), true + case "sol": + // SOLIDUS + return rune(0x2f), true + case "sopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL S + return rune(0x01d564), true + case "spades": + // BLACK SPADE SUIT + return rune(0x2660), true + case "spadesuit": + // BLACK SPADE SUIT + return rune(0x2660), true + case "spar": + // PARALLEL TO + return rune(0x2225), true + case "sqcap": + // SQUARE CAP + return rune(0x2293), true + case "sqcaps": + // SQUARE CAP with serifs + return rune(0x2293), true + case "sqcup": + // SQUARE CUP + return rune(0x2294), true + case "sqcups": + // SQUARE CUP with serifs + return rune(0x2294), true + case "sqsub": + // SQUARE IMAGE OF + return rune(0x228f), true + case "sqsube": + // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "sqsubset": + // SQUARE IMAGE OF + return rune(0x228f), true + case "sqsubseteq": + // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "sqsup": + // SQUARE ORIGINAL OF + return rune(0x2290), true + case "sqsupe": + // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "sqsupset": + // SQUARE ORIGINAL OF + return rune(0x2290), true + case "sqsupseteq": + // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "squ": + // WHITE SQUARE + return rune(0x25a1), true + case "square": + // WHITE SQUARE + return rune(0x25a1), true + case "squarf": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "squb": + // SQUARED SQUARE + return rune(0x29c8), true + case "squerr": + // ERROR-BARRED WHITE SQUARE + return rune(0x29ee), true + case "squf": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "squferr": + // ERROR-BARRED BLACK SQUARE + return rune(0x29ef), true + case "srarr": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "sscr": + // MATHEMATICAL SCRIPT SMALL S + return rune(0x01d4c8), true + case "ssetmn": + // SET MINUS + return rune(0x2216), true + case "ssmile": + // SMILE + return rune(0x2323), true + case "sstarf": + // STAR OPERATOR + return rune(0x22c6), true + case "starf": + // BLACK STAR + return rune(0x2605), true + case "star": + // WHITE STAR + return rune(0x2606), true + case "stigma": + // GREEK LETTER STIGMA + return rune(0x03da), true + case "straightepsilon": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "straightphi": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "strns": + // MACRON + return rune(0xaf), true + case "sub": + // SUBSET OF + return rune(0x2282), true + case "subE": + // SUBSET OF ABOVE EQUALS SIGN + return rune(0x2ac5), true + case "subdot": + // SUBSET WITH DOT + return rune(0x2abd), true + case "sube": + // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "subedot": + // SUBSET OF OR EQUAL TO WITH DOT ABOVE + return rune(0x2ac3), true + case "submult": + // SUBSET WITH MULTIPLICATION SIGN BELOW + return rune(0x2ac1), true + case "subnE": + // SUBSET OF ABOVE NOT EQUAL TO + return rune(0x2acb), true + case "subne": + // SUBSET OF WITH NOT EQUAL TO + return rune(0x228a), true + case "subplus": + // SUBSET WITH PLUS SIGN BELOW + return rune(0x2abf), true + case "subrarr": + // SUBSET ABOVE RIGHTWARDS ARROW + return rune(0x2979), true + case "subset": + // SUBSET OF + return rune(0x2282), true + case "subseteq": + // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "subseteqq": + // SUBSET OF ABOVE EQUALS SIGN + return rune(0x2ac5), true + case "subsetneq": + // SUBSET OF WITH NOT EQUAL TO + return rune(0x228a), true + case "subsetneqq": + // SUBSET OF ABOVE NOT EQUAL TO + return rune(0x2acb), true + case "subsim": + // SUBSET OF ABOVE TILDE OPERATOR + return rune(0x2ac7), true + case "subsub": + // SUBSET ABOVE SUBSET + return rune(0x2ad5), true + case "subsup": + // SUBSET ABOVE SUPERSET + return rune(0x2ad3), true + case "succ": + // SUCCEEDS + return rune(0x227b), true + case "succapprox": + // SUCCEEDS ABOVE ALMOST EQUAL TO + return rune(0x2ab8), true + case "succcurlyeq": + // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "succeq": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "succnapprox": + // SUCCEEDS ABOVE NOT ALMOST EQUAL TO + return rune(0x2aba), true + case "succneqq": + // SUCCEEDS ABOVE NOT EQUAL TO + return rune(0x2ab6), true + case "succnsim": + // SUCCEEDS BUT NOT EQUIVALENT TO + return rune(0x22e9), true + case "succsim": + // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "sum": + // N-ARY SUMMATION + return rune(0x2211), true + case "sumint": + // SUMMATION WITH INTEGRAL + return rune(0x2a0b), true + case "sung": + // EIGHTH NOTE + return rune(0x266a), true + case "sup": + // SUPERSET OF + return rune(0x2283), true + case "sup1": + // SUPERSCRIPT ONE + return rune(0xb9), true + case "sup2": + // SUPERSCRIPT TWO + return rune(0xb2), true + case "sup3": + // SUPERSCRIPT THREE + return rune(0xb3), true + case "supE": + // SUPERSET OF ABOVE EQUALS SIGN + return rune(0x2ac6), true + case "supdot": + // SUPERSET WITH DOT + return rune(0x2abe), true + case "supdsub": + // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET + return rune(0x2ad8), true + case "supe": + // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "supedot": + // SUPERSET OF OR EQUAL TO WITH DOT ABOVE + return rune(0x2ac4), true + case "suphsol": + // SUPERSET PRECEDING SOLIDUS + return rune(0x27c9), true + case "suphsub": + // SUPERSET BESIDE SUBSET + return rune(0x2ad7), true + case "suplarr": + // SUPERSET ABOVE LEFTWARDS ARROW + return rune(0x297b), true + case "supmult": + // SUPERSET WITH MULTIPLICATION SIGN BELOW + return rune(0x2ac2), true + case "supnE": + // SUPERSET OF ABOVE NOT EQUAL TO + return rune(0x2acc), true + case "supne": + // SUPERSET OF WITH NOT EQUAL TO + return rune(0x228b), true + case "supplus": + // SUPERSET WITH PLUS SIGN BELOW + return rune(0x2ac0), true + case "supset": + // SUPERSET OF + return rune(0x2283), true + case "supseteq": + // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "supseteqq": + // SUPERSET OF ABOVE EQUALS SIGN + return rune(0x2ac6), true + case "supsetneq": + // SUPERSET OF WITH NOT EQUAL TO + return rune(0x228b), true + case "supsetneqq": + // SUPERSET OF ABOVE NOT EQUAL TO + return rune(0x2acc), true + case "supsim": + // SUPERSET OF ABOVE TILDE OPERATOR + return rune(0x2ac8), true + case "supsub": + // SUPERSET ABOVE SUBSET + return rune(0x2ad4), true + case "supsup": + // SUPERSET ABOVE SUPERSET + return rune(0x2ad6), true + case "swArr": + // SOUTH WEST DOUBLE ARROW + return rune(0x21d9), true + case "swarhk": + // SOUTH WEST ARROW WITH HOOK + return rune(0x2926), true + case "swarrow": + // SOUTH WEST ARROW + return rune(0x2199), true + case "swarr": + // SOUTH WEST ARROW + return rune(0x2199), true + case "swnwar": + // SOUTH WEST ARROW AND NORTH WEST ARROW + return rune(0x292a), true + case "szlig": + // LATIN SMALL LETTER SHARP S + return rune(0xdf), true + } + + case 't': + switch name { + case "target": + // POSITION INDICATOR + return rune(0x2316), true + case "tau": + // GREEK SMALL LETTER TAU + return rune(0x03c4), true + case "tbrk": + // TOP SQUARE BRACKET + return rune(0x23b4), true + case "tcaron": + // LATIN SMALL LETTER T WITH CARON + return rune(0x0165), true + case "tcedil": + // LATIN SMALL LETTER T WITH CEDILLA + return rune(0x0163), true + case "tcy": + // CYRILLIC SMALL LETTER TE + return rune(0x0442), true + case "tdot": + // COMBINING THREE DOTS ABOVE + return rune(0x20db), true + case "telrec": + // TELEPHONE RECORDER + return rune(0x2315), true + case "tfr": + // MATHEMATICAL FRAKTUR SMALL T + return rune(0x01d531), true + case "tgr": + // GREEK SMALL LETTER TAU + return rune(0x03c4), true + case "there4": + // THEREFORE + return rune(0x2234), true + case "therefore": + // THEREFORE + return rune(0x2234), true + case "thermod": + // THERMODYNAMIC + return rune(0x29e7), true + case "thetasym": + // GREEK THETA SYMBOL + return rune(0x03d1), true + case "thetas": + // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thetav": + // GREEK THETA SYMBOL + return rune(0x03d1), true + case "theta": + // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thgr": + // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thickapprox": + // ALMOST EQUAL TO + return rune(0x2248), true + case "thicksim": + // TILDE OPERATOR + return rune(0x223c), true + case "thinsp": + // THIN SPACE + return rune(0x2009), true + case "thkap": + // ALMOST EQUAL TO + return rune(0x2248), true + case "thksim": + // TILDE OPERATOR + return rune(0x223c), true + case "thorn": + // LATIN SMALL LETTER THORN + return rune(0xfe), true + case "tilde": + // SMALL TILDE + return rune(0x02dc), true + case "timeint": + // INTEGRAL WITH TIMES SIGN + return rune(0x2a18), true + case "timesb": + // SQUARED TIMES + return rune(0x22a0), true + case "timesbar": + // MULTIPLICATION SIGN WITH UNDERBAR + return rune(0x2a31), true + case "timesd": + // MULTIPLICATION SIGN WITH DOT ABOVE + return rune(0x2a30), true + case "times": + // MULTIPLICATION SIGN + return rune(0xd7), true + case "tint": + // TRIPLE INTEGRAL + return rune(0x222d), true + case "toea": + // NORTH EAST ARROW AND SOUTH EAST ARROW + return rune(0x2928), true + case "top": + // DOWN TACK + return rune(0x22a4), true + case "topbot": + // APL FUNCTIONAL SYMBOL I-BEAM + return rune(0x2336), true + case "topcir": + // DOWN TACK WITH CIRCLE BELOW + return rune(0x2af1), true + case "topfork": + // PITCHFORK WITH TEE TOP + return rune(0x2ada), true + case "topf": + // MATHEMATICAL DOUBLE-STRUCK SMALL T + return rune(0x01d565), true + case "tosa": + // SOUTH EAST ARROW AND SOUTH WEST ARROW + return rune(0x2929), true + case "tprime": + // TRIPLE PRIME + return rune(0x2034), true + case "trade": + // TRADE MARK SIGN + return rune(0x2122), true + case "triS": + // S IN TRIANGLE + return rune(0x29cc), true + case "trianglelefteq": + // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "triangleq": + // DELTA EQUAL TO + return rune(0x225c), true + case "trianglerighteq": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "triangle": + // WHITE UP-POINTING SMALL TRIANGLE + return rune(0x25b5), true + case "triangledown": + // WHITE DOWN-POINTING SMALL TRIANGLE + return rune(0x25bf), true + case "triangleleft": + // WHITE LEFT-POINTING SMALL TRIANGLE + return rune(0x25c3), true + case "triangleright": + // WHITE RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b9), true + case "tribar": + // TRIANGLE WITH UNDERBAR + return rune(0x29cb), true + case "tridot": + // WHITE UP-POINTING TRIANGLE WITH DOT + return rune(0x25ec), true + case "tridoto": + // TRIANGLE WITH DOT ABOVE + return rune(0x29ca), true + case "trie": + // DELTA EQUAL TO + return rune(0x225c), true + case "triminus": + // MINUS SIGN IN TRIANGLE + return rune(0x2a3a), true + case "triplus": + // PLUS SIGN IN TRIANGLE + return rune(0x2a39), true + case "trisb": + // TRIANGLE WITH SERIFS AT BOTTOM + return rune(0x29cd), true + case "tritime": + // MULTIPLICATION SIGN IN TRIANGLE + return rune(0x2a3b), true + case "trpezium": + // WHITE TRAPEZIUM + return rune(0x23e2), true + case "tscr": + // MATHEMATICAL SCRIPT SMALL T + return rune(0x01d4c9), true + case "tscy": + // CYRILLIC SMALL LETTER TSE + return rune(0x0446), true + case "tshcy": + // CYRILLIC SMALL LETTER TSHE + return rune(0x045b), true + case "tstrok": + // LATIN SMALL LETTER T WITH STROKE + return rune(0x0167), true + case "tverbar": + // TRIPLE VERTICAL BAR DELIMITER + return rune(0x2980), true + case "twixt": + // BETWEEN + return rune(0x226c), true + case "twoheadleftarrow": + // LEFTWARDS TWO HEADED ARROW + return rune(0x219e), true + case "twoheadrightarrow": + // RIGHTWARDS TWO HEADED ARROW + return rune(0x21a0), true + } + + case 'u': + switch name { + case "uAarr": + // UPWARDS TRIPLE ARROW + return rune(0x290a), true + case "uArr": + // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "uHar": + // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x2963), true + case "uacgr": + // GREEK SMALL LETTER UPSILON WITH TONOS + return rune(0x03cd), true + case "uacute": + // LATIN SMALL LETTER U WITH ACUTE + return rune(0xfa), true + case "uarr2": + // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "uarr": + // UPWARDS ARROW + return rune(0x2191), true + case "uarrb": + // UPWARDS ARROW TO BAR + return rune(0x2912), true + case "uarrln": + // UPWARDS ARROW WITH HORIZONTAL STROKE + return rune(0x2909), true + case "ubrcy": + // CYRILLIC SMALL LETTER SHORT U + return rune(0x045e), true + case "ubreve": + // LATIN SMALL LETTER U WITH BREVE + return rune(0x016d), true + case "ucirc": + // LATIN SMALL LETTER U WITH CIRCUMFLEX + return rune(0xfb), true + case "ucy": + // CYRILLIC SMALL LETTER U + return rune(0x0443), true + case "udarr": + // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + return rune(0x21c5), true + case "udblac": + // LATIN SMALL LETTER U WITH DOUBLE ACUTE + return rune(0x0171), true + case "udhar": + // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x296e), true + case "udiagr": + // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + return rune(0x03b0), true + case "udigr": + // GREEK SMALL LETTER UPSILON WITH DIALYTIKA + return rune(0x03cb), true + case "udrbrk": + // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "udrcub": + // BOTTOM CURLY BRACKET + return rune(0x23df), true + case "udrpar": + // BOTTOM PARENTHESIS + return rune(0x23dd), true + case "ufisht": + // UP FISH TAIL + return rune(0x297e), true + case "ufr": + // MATHEMATICAL FRAKTUR SMALL U + return rune(0x01d532), true + case "ugr": + // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "ugrave": + // LATIN SMALL LETTER U WITH GRAVE + return rune(0xf9), true + case "uharl": + // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "uharr": + // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "uhblk": + // UPPER HALF BLOCK + return rune(0x2580), true + case "ulcorn": + // TOP LEFT CORNER + return rune(0x231c), true + case "ulcorner": + // TOP LEFT CORNER + return rune(0x231c), true + case "ulcrop": + // TOP LEFT CROP + return rune(0x230f), true + case "uldlshar": + // UP BARB LEFT DOWN BARB LEFT HARPOON + return rune(0x2951), true + case "ulharb": + // UPWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2958), true + case "ultri": + // UPPER LEFT TRIANGLE + return rune(0x25f8), true + case "umacr": + // LATIN SMALL LETTER U WITH MACRON + return rune(0x016b), true + case "uml": + // DIAERESIS + return rune(0xa8), true + case "uogon": + // LATIN SMALL LETTER U WITH OGONEK + return rune(0x0173), true + case "uopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL U + return rune(0x01d566), true + case "uparrow": + // UPWARDS ARROW + return rune(0x2191), true + case "updownarrow": + // UP DOWN ARROW + return rune(0x2195), true + case "upharpoonleft": + // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "upharpoonright": + // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "upint": + // INTEGRAL WITH OVERBAR + return rune(0x2a1b), true + case "uplus": + // MULTISET UNION + return rune(0x228e), true + case "upsih": + // GREEK UPSILON WITH HOOK SYMBOL + return rune(0x03d2), true + case "upsilon": + // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "upsi": + // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "upuparrows": + // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "urcorn": + // TOP RIGHT CORNER + return rune(0x231d), true + case "urcorner": + // TOP RIGHT CORNER + return rune(0x231d), true + case "urcrop": + // TOP RIGHT CROP + return rune(0x230e), true + case "urdrshar": + // UP BARB RIGHT DOWN BARB RIGHT HARPOON + return rune(0x294f), true + case "urharb": + // UPWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2954), true + case "uring": + // LATIN SMALL LETTER U WITH RING ABOVE + return rune(0x016f), true + case "urtrif": + // BLACK UPPER RIGHT TRIANGLE + return rune(0x25e5), true + case "urtri": + // UPPER RIGHT TRIANGLE + return rune(0x25f9), true + case "uscr": + // MATHEMATICAL SCRIPT SMALL U + return rune(0x01d4ca), true + case "utdot": + // UP RIGHT DIAGONAL ELLIPSIS + return rune(0x22f0), true + case "utilde": + // LATIN SMALL LETTER U WITH TILDE + return rune(0x0169), true + case "utrif": + // BLACK UP-POINTING SMALL TRIANGLE + return rune(0x25b4), true + case "utri": + // WHITE UP-POINTING SMALL TRIANGLE + return rune(0x25b5), true + case "uuarr": + // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "uuml": + // LATIN SMALL LETTER U WITH DIAERESIS + return rune(0xfc), true + case "uwangle": + // OBLIQUE ANGLE OPENING DOWN + return rune(0x29a7), true + } + + case 'v': + switch name { + case "vArr": + // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "vBar": + // SHORT UP TACK WITH UNDERBAR + return rune(0x2ae8), true + case "vBarv": + // SHORT UP TACK ABOVE SHORT DOWN TACK + return rune(0x2ae9), true + case "vDash": + // TRUE + return rune(0x22a8), true + case "vDdash": + // VERTICAL BAR TRIPLE RIGHT TURNSTILE + return rune(0x2ae2), true + case "vangrt": + // RIGHT ANGLE VARIANT WITH SQUARE + return rune(0x299c), true + case "varepsilon": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "varkappa": + // GREEK KAPPA SYMBOL + return rune(0x03f0), true + case "varnothing": + // EMPTY SET + return rune(0x2205), true + case "varphi": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "varpi": + // GREEK PI SYMBOL + return rune(0x03d6), true + case "varpropto": + // PROPORTIONAL TO + return rune(0x221d), true + case "varr": + // UP DOWN ARROW + return rune(0x2195), true + case "varrho": + // GREEK RHO SYMBOL + return rune(0x03f1), true + case "varsigma": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "varsubsetneq": + // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228a), true + case "varsubsetneqq": + // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acb), true + case "varsupsetneq": + // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228b), true + case "varsupsetneqq": + // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acc), true + case "vartheta": + // GREEK THETA SYMBOL + return rune(0x03d1), true + case "vartriangleleft": + // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "vartriangleright": + // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "vbrtri": + // VERTICAL BAR BESIDE RIGHT TRIANGLE + return rune(0x29d0), true + case "vcy": + // CYRILLIC SMALL LETTER VE + return rune(0x0432), true + case "vdash": + // RIGHT TACK + return rune(0x22a2), true + case "vee": + // LOGICAL OR + return rune(0x2228), true + case "veeBar": + // LOGICAL OR WITH DOUBLE UNDERBAR + return rune(0x2a63), true + case "veebar": + // XOR + return rune(0x22bb), true + case "veeeq": + // EQUIANGULAR TO + return rune(0x225a), true + case "vellip": + // VERTICAL ELLIPSIS + return rune(0x22ee), true + case "vellip4": + // DOTTED FENCE + return rune(0x2999), true + case "vellipv": + // TRIPLE COLON OPERATOR + return rune(0x2af6), true + case "verbar": + // VERTICAL LINE + return rune(0x7c), true + case "vert3": + // TRIPLE VERTICAL BAR BINARY RELATION + return rune(0x2af4), true + case "vert": + // VERTICAL LINE + return rune(0x7c), true + case "vfr": + // MATHEMATICAL FRAKTUR SMALL V + return rune(0x01d533), true + case "vldash": + // LEFT SQUARE BRACKET LOWER CORNER + return rune(0x23a3), true + case "vltri": + // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "vnsub": + // SUBSET OF with vertical line + return rune(0x2282), true + case "vnsup": + // SUPERSET OF with vertical line + return rune(0x2283), true + case "vopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL V + return rune(0x01d567), true + case "vprime": + // PRIME + return rune(0x2032), true + case "vprop": + // PROPORTIONAL TO + return rune(0x221d), true + case "vrtri": + // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "vscr": + // MATHEMATICAL SCRIPT SMALL V + return rune(0x01d4cb), true + case "vsubnE": + // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acb), true + case "vsubne": + // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228a), true + case "vsupnE": + // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acc), true + case "vsupne": + // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228b), true + case "vzigzag": + // VERTICAL ZIGZAG LINE + return rune(0x299a), true + } + + case 'w': + switch name { + case "wcirc": + // LATIN SMALL LETTER W WITH CIRCUMFLEX + return rune(0x0175), true + case "wedbar": + // LOGICAL AND WITH UNDERBAR + return rune(0x2a5f), true + case "wedge": + // LOGICAL AND + return rune(0x2227), true + case "wedgeq": + // ESTIMATES + return rune(0x2259), true + case "weierp": + // SCRIPT CAPITAL P + return rune(0x2118), true + case "wfr": + // MATHEMATICAL FRAKTUR SMALL W + return rune(0x01d534), true + case "wopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL W + return rune(0x01d568), true + case "wp": + // SCRIPT CAPITAL P + return rune(0x2118), true + case "wreath": + // WREATH PRODUCT + return rune(0x2240), true + case "wr": + // WREATH PRODUCT + return rune(0x2240), true + case "wscr": + // MATHEMATICAL SCRIPT SMALL W + return rune(0x01d4cc), true + } + + case 'x': + switch name { + case "xandand": + // TWO LOGICAL AND OPERATOR + return rune(0x2a07), true + case "xbsol": + // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + return rune(0x2571), true + case "xcap": + // N-ARY INTERSECTION + return rune(0x22c2), true + case "xcirc": + // LARGE CIRCLE + return rune(0x25ef), true + case "xcup": + // N-ARY UNION + return rune(0x22c3), true + case "xcupdot": + // N-ARY UNION OPERATOR WITH DOT + return rune(0x2a03), true + case "xdtri": + // WHITE DOWN-POINTING TRIANGLE + return rune(0x25bd), true + case "xfr": + // MATHEMATICAL FRAKTUR SMALL X + return rune(0x01d535), true + case "xgr": + // GREEK SMALL LETTER XI + return rune(0x03be), true + case "xhArr": + // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "xharr": + // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "xi": + // GREEK SMALL LETTER XI + return rune(0x03be), true + case "xlArr": + // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "xlarr": + // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "xmap": + // LONG RIGHTWARDS ARROW FROM BAR + return rune(0x27fc), true + case "xnis": + // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22fb), true + case "xodot": + // N-ARY CIRCLED DOT OPERATOR + return rune(0x2a00), true + case "xopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL X + return rune(0x01d569), true + case "xoplus": + // N-ARY CIRCLED PLUS OPERATOR + return rune(0x2a01), true + case "xoror": + // TWO LOGICAL OR OPERATOR + return rune(0x2a08), true + case "xotime": + // N-ARY CIRCLED TIMES OPERATOR + return rune(0x2a02), true + case "xrArr": + // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "xrarr": + // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "xscr": + // MATHEMATICAL SCRIPT SMALL X + return rune(0x01d4cd), true + case "xsol": + // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + return rune(0x2572), true + case "xsqcap": + // N-ARY SQUARE INTERSECTION OPERATOR + return rune(0x2a05), true + case "xsqcup": + // N-ARY SQUARE UNION OPERATOR + return rune(0x2a06), true + case "xsqu": + // WHITE MEDIUM SQUARE + return rune(0x25fb), true + case "xsquf": + // BLACK MEDIUM SQUARE + return rune(0x25fc), true + case "xtimes": + // N-ARY TIMES OPERATOR + return rune(0x2a09), true + case "xuplus": + // N-ARY UNION OPERATOR WITH PLUS + return rune(0x2a04), true + case "xutri": + // WHITE UP-POINTING TRIANGLE + return rune(0x25b3), true + case "xvee": + // N-ARY LOGICAL OR + return rune(0x22c1), true + case "xwedge": + // N-ARY LOGICAL AND + return rune(0x22c0), true + } + + case 'y': + switch name { + case "yacute": + // LATIN SMALL LETTER Y WITH ACUTE + return rune(0xfd), true + case "yacy": + // CYRILLIC SMALL LETTER YA + return rune(0x044f), true + case "ycirc": + // LATIN SMALL LETTER Y WITH CIRCUMFLEX + return rune(0x0177), true + case "ycy": + // CYRILLIC SMALL LETTER YERU + return rune(0x044b), true + case "yen": + // YEN SIGN + return rune(0xa5), true + case "yfr": + // MATHEMATICAL FRAKTUR SMALL Y + return rune(0x01d536), true + case "yicy": + // CYRILLIC SMALL LETTER YI + return rune(0x0457), true + case "yopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL Y + return rune(0x01d56a), true + case "yscr": + // MATHEMATICAL SCRIPT SMALL Y + return rune(0x01d4ce), true + case "yucy": + // CYRILLIC SMALL LETTER YU + return rune(0x044e), true + case "yuml": + // LATIN SMALL LETTER Y WITH DIAERESIS + return rune(0xff), true + } + + case 'z': + switch name { + case "zacute": + // LATIN SMALL LETTER Z WITH ACUTE + return rune(0x017a), true + case "zcaron": + // LATIN SMALL LETTER Z WITH CARON + return rune(0x017e), true + case "zcy": + // CYRILLIC SMALL LETTER ZE + return rune(0x0437), true + case "zdot": + // LATIN SMALL LETTER Z WITH DOT ABOVE + return rune(0x017c), true + case "zeetrf": + // BLACK-LETTER CAPITAL Z + return rune(0x2128), true + case "zeta": + // GREEK SMALL LETTER ZETA + return rune(0x03b6), true + case "zfr": + // MATHEMATICAL FRAKTUR SMALL Z + return rune(0x01d537), true + case "zgr": + // GREEK SMALL LETTER ZETA + return rune(0x03b6), true + case "zhcy": + // CYRILLIC SMALL LETTER ZHE + return rune(0x0436), true + case "zigrarr": + // RIGHTWARDS SQUIGGLE ARROW + return rune(0x21dd), true + case "zopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL Z + return rune(0x01d56b), true + case "zscr": + // MATHEMATICAL SCRIPT SMALL Z + return rune(0x01d4cf), true + case "zwj": + // ZERO WIDTH JOINER + return rune(0x200d), true + case "zwnj": + // ZERO WIDTH NON-JOINER + return rune(0x200c), true + } + } + return -1, false +} + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 563294309..146c278cb 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -519,8 +519,6 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) _ = expect(t, .Eq) or_return value := expect(t, .String) or_return - error(t, t.offset, "String: %v\n", value) - attr.key = strings.intern_get(&doc.intern, key.text) attr.val = strings.intern_get(&doc.intern, value.text) diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin new file mode 100644 index 000000000..075ec1cca --- /dev/null +++ b/core/unicode/tools/generate_entity_table.odin @@ -0,0 +1,287 @@ +package xml_example + +import "core:encoding/xml" +import "core:os" +import "core:path" +import "core:mem" +import "core:strings" +import "core:strconv" +import "core:slice" +import "core:fmt" + +/* + Silent error handler for the parser. +*/ +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} + +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } + +Entity :: struct { + name: string, + codepoint: rune, + description: string, +} + +generate_encoding_entity_table :: proc() { + using fmt + + filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml") + defer delete(filename) + + generated_filename := path.join(ODIN_ROOT, "core", "encoding", "entity", "generated.odin") + defer delete(generated_filename) + + doc, err := xml.parse(filename, OPTIONS, Error_Handler) + defer xml.destroy(doc) + + if err != .None { + printf("Load/Parse error: %v\n", err) + if err == .File_Error { + printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) + } + os.exit(1) + } + + printf("\"%v\" loaded and parsed.\n", filename) + + generated_buf: strings.Builder + defer strings.destroy_builder(&generated_buf) + w := strings.to_writer(&generated_buf) + + charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") + if !charlist_ok { + eprintln("Could not locate top-level `` tag.") + os.exit(1) + } + + printf("Found `` with %v children.\n", len(charlist.children)) + + entity_map: map[string]Entity + names: [dynamic]string + + min_name_length := max(int) + max_name_length := min(int) + shortest_name: string + longest_name: string + + count := 0 + for char in charlist.children { + if char.ident != "character" { + eprintf("Expected ``, got `<%v>`\n", char.ident) + os.exit(1) + } + + if codepoint_string, ok := xml.find_attribute_val_by_key(char, "dec"); !ok { + eprintln("`` attribute not found.") + os.exit(1) + } else { + codepoint := strconv.atoi(codepoint_string) + + desc, desc_ok := xml.find_child_by_ident(char, "description") + description := desc.value if desc_ok else "" + + /* + For us to be interested in this codepoint, it has to have at least one entity. + */ + + nth := 0 + for { + character_entity, entity_ok := xml.find_child_by_ident(char, "entity", nth) + if !entity_ok { break } + + nth += 1 + if name, name_ok := xml.find_attribute_val_by_key(character_entity, "id"); name_ok { + + if len(name) == 0 { + /* + Invalid name. Skip. + */ + continue + } + + if name == "\"\"" { + printf("%#v\n", char) + printf("%#v\n", character_entity) + } + + if len(name) > max_name_length { longest_name = name } + if len(name) < min_name_length { shortest_name = name } + + min_name_length = min(min_name_length, len(name)) + max_name_length = max(max_name_length, len(name)) + + e := Entity{ + name = name, + codepoint = rune(codepoint), + description = description, + } + + if _, seen := entity_map[name]; seen { + continue + } + + entity_map[name] = e + append(&names, name) + count += 1 + } + } + } + } + + /* + Sort by name. + */ + slice.sort(names[:]) + + printf("Found %v unique `&name;` -> rune mappings.\n", count) + printf("Shortest name: %v (%v)\n", shortest_name, min_name_length) + printf("Longest name: %v (%v)\n", longest_name, max_name_length) + + // println(rune_to_string(1234)) + + /* + Generate table. + */ + wprintln(w, "package unicode_entity") + wprintln(w, "") + wprintln(w, GENERATED) + wprintln(w, "") + wprintf (w, TABLE_FILE_PROLOG) + wprintln(w, "") + + wprintf (w, "// `&%v;`\n", shortest_name) + wprintf (w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v\n", min_name_length) + wprintf (w, "// `&%v;`\n", longest_name) + wprintf (w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v\n", max_name_length) + wprintln(w, "") + + wprintln(w, +` +/* + Input: + entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML. + + Output: + "decoded" - The decoded rune if found by name, or -1 otherwise. + "ok" - true if found, false if not. + + IMPORTANT: XML processors (including browsers) treat these names as case-sensitive. So do we. +*/ +named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { + /* + Early out if the name is too short or too long. + min as a precaution in case the generated table has a bogus value. + */ + if len(name) < min(1, XML_NAME_TO_RUNE_MIN_LENGTH) || len(name) > XML_NAME_TO_RUNE_MAX_LENGTH { + return -1, false + } + + switch rune(name[0]) { +`) + + prefix := '?' + should_close := false + + for v in names { + if rune(v[0]) != prefix { + if should_close { + wprintln(w, "\t\t}\n") + } + + prefix = rune(v[0]) + wprintf (w, "\tcase '%v':\n", prefix) + wprintln(w, "\t\tswitch name {") + } + + e := entity_map[v] + + wprintf(w, "\t\t\tcase \"%v\": \n", e.name) + wprintf(w, "\t\t\t\t// %v\n", e.description) + wprintf(w, "\t\t\t\treturn %v, true\n", rune_to_string(e.codepoint)) + + should_close = true + } + wprintln(w, "\t\t}") + wprintln(w, "\t}") + wprintln(w, "\treturn -1, false") + wprintln(w, "}\n") + wprintln(w, GENERATED) + + println() + println(strings.to_string(generated_buf)) + println() + + written := os.write_entire_file(generated_filename, transmute([]byte)strings.to_string(generated_buf)) + + if written { + fmt.printf("Successfully written generated \"%v\".", generated_filename) + } else { + fmt.printf("Failed to write generated \"%v\".", generated_filename) + } + + delete(entity_map) + delete(names) + for name in &names { + free(&name) + } +} + +GENERATED :: `/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/` + +TABLE_FILE_PROLOG :: `/* + This file is generated from "https://www.w3.org/2003/entities/2007xml/unicode.xml". + + UPDATE: + - Ensure the XML file was downloaded using "tests\core\download_assets.py". + - Run "core/unicode/tools/generate_entity_table.odin" + + Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity + + Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology, + European Research Consortium for Informatics and Mathematics, Keio University, Beihang). + + All Rights Reserved. + + This work is distributed under the W3C® Software License [1] in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + [1] http://www.w3.org/Consortium/Legal/copyright-software + + See also: LICENSE_table.md +*/ +` + +rune_to_string :: proc(r: rune) -> (res: string) { + res = fmt.tprintf("%08x", int(r)) + for len(res) > 2 && res[:2] == "00" { + res = res[2:] + } + return fmt.tprintf("rune(0x%v)", res) +} + +is_dotted_name :: proc(name: string) -> (dotted: bool) { + for r in name { + if r == '.' { return true} + } + return false +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + generate_encoding_entity_table() + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } + println("Done and cleaned up!") +} \ No newline at end of file From 3d72e80ccf0f382f03a1c9407c4728862c5bca91 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 2 Dec 2021 21:07:40 +0100 Subject: [PATCH 0013/1052] [xml] Implement optional unboxing of CDATA and decoding of tag values. --- core/encoding/entity/entity.odin | 39 ++++++----- .../entity/example/entity_example.odin | 67 +++---------------- core/encoding/entity/example/test.html | 2 + core/encoding/xml/xml_reader.odin | 41 ++++++------ 4 files changed, 56 insertions(+), 93 deletions(-) diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index e40896819..8742446e6 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -60,16 +60,22 @@ COMMENT_END :: "-->" Default: CDATA and comments are passed through unchanged. */ XML_Decode_Option :: enum u8 { + /* + Do not decode & entities. It decodes by default. + If given, overrides `Decode_CDATA`. + */ + No_Entity_Decode, + /* CDATA is unboxed. */ - CDATA_Unbox, + Unbox_CDATA, /* Unboxed CDATA is decoded as well. - Ignored if `.CDATA_Unbox` is not given. + Ignored if `.Unbox_CDATA` is not given. */ - CDATA_Decode, + Decode_CDATA, /* Comments are stripped. @@ -129,7 +135,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := } case: - if in_data && .CDATA_Decode not_in options { + if in_data && .Decode_CDATA not_in options { /* Unboxed, but undecoded. */ @@ -145,17 +151,20 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := */ write_string(&builder, entity) } else { - if decoded, ok := xml_decode_entity(entity); ok { - write_rune(&builder, decoded) - } else { - /* - Decode failed. Pass through original. - */ - write_string(&builder, "&") - write_string(&builder, entity) - write_string(&builder, ";") + + if .No_Entity_Decode not_in options { + if decoded, ok := xml_decode_entity(entity); ok { + write_rune(&builder, decoded) + continue + } } + /* + Literal passthrough because the decode failed or we want entities not decoded. + */ + write_string(&builder, "&") + write_string(&builder, entity) + write_string(&builder, ";") } } else { write_rune(&builder, t.r) @@ -290,7 +299,7 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { t.read_offset += len(CDATA_START) - 1 - if .CDATA_Unbox in options && .CDATA_Decode in options { + if .Unbox_CDATA in options && .Decode_CDATA in options { /* We're unboxing _and_ decoding CDATA */ @@ -315,7 +324,7 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X cdata := string(t.src[offset : t.read_offset]) - if .CDATA_Unbox in options { + if .Unbox_CDATA in options { cdata = cdata[len(CDATA_START):] cdata = cdata[:len(cdata) - len(CDATA_END)] } diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin index 8758d9ad9..161a44827 100644 --- a/core/encoding/entity/example/entity_example.odin +++ b/core/encoding/entity/example/entity_example.odin @@ -1,19 +1,11 @@ package unicode_entity_example import "core:encoding/xml" -import "core:encoding/entity" import "core:strings" import "core:mem" import "core:fmt" import "core:time" -OPTIONS :: xml.Options{ - flags = { - .Ignore_Unsupported, .Intern_Comments, - }, - expected_doctype = "", -} - doc_print :: proc(doc: ^xml.Document) { buf: strings.Builder defer strings.destroy_builder(&buf) @@ -29,6 +21,13 @@ _entities :: proc() { DOC :: #load("../../../../tests/core/assets/XML/unicode.xml") + OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", + } + parse_duration: time.Duration { @@ -50,57 +49,11 @@ _entities :: proc() { _main :: proc() { using fmt - doc, err := xml.parse(#load("test.html")) + options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }} + doc, _ := xml.parse(#load("test.html"), options) + defer xml.destroy(doc) doc_print(doc) - - if false { - val := doc.root.children[1].children[2].value - - println() - replaced, ok := entity.decode_xml(val) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("Passthrough: '%v'\nOK: %v\n", replaced, ok) - println() - } - - if false { - val := doc.root.children[1].children[2].value - - println() - replaced, ok := entity.decode_xml(val, { .CDATA_Unbox }) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("CDATA_Unbox: '%v'\nOK: %v\n", replaced, ok) - println() - } - - if true { - val := doc.root.children[1].children[2].value - - println() - replaced, ok := entity.decode_xml(val, { .CDATA_Unbox, .CDATA_Decode }) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("CDATA_Decode: '%v'\nOK: %v\n", replaced, ok) - println() - } - - if true { - val := doc.root.children[1].children[1].value - - println() - replaced, ok := entity.decode_xml(val, { .Comment_Strip }) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("Comment_Strip: '%v'\nOK: %v\n", replaced, ok) - println() - } } main :: proc() { diff --git a/core/encoding/entity/example/test.html b/core/encoding/entity/example/test.html index 60e32bf03..62a0bb35a 100644 --- a/core/encoding/entity/example/test.html +++ b/core/encoding/entity/example/test.html @@ -16,9 +16,11 @@
Foozle]! © 42&;1234&
+
Foozle]! © 42&;1234&
+
| | | fj ` \ ® ϱ ∳
diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 146c278cb..6f49b8e08 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -18,10 +18,6 @@ package xml - We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences. - <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options. - TODO: - - Optional CDATA unboxing. - - Optional `>`, ` `, ` ` and other escape substitution in tag bodies. - MAYBE: - XML writer? - Serialize/deserialize Odin types? @@ -31,6 +27,7 @@ package xml */ import "core:strings" +import "core:encoding/entity" import "core:mem" import "core:os" @@ -196,12 +193,6 @@ Error :: enum { Duplicate_Attribute, Conflicting_Options, - - /* - Unhandled TODO: - */ - Unhandled_CDATA_Unboxing, - Unhandled_SGML_Entity_Decoding, } /* @@ -422,8 +413,25 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err /* This should be a tag's body text. */ - body_text := scan_string(t, t.offset) or_return - element.value = strings.intern_get(&doc.intern, body_text) + body_text := scan_string(t, t.offset) or_return + + decode_opts := entity.XML_Decode_Options{ .Comment_Strip } + + if .Decode_SGML_Entities not_in opts.flags { + decode_opts += { .No_Entity_Decode } + } + if .Unbox_CDATA in opts.flags { + decode_opts += { .Unbox_CDATA, .Decode_CDATA } + } + + decoded, decode_err := entity.decode_xml(body_text, decode_opts) + defer delete(decoded) + + if decode_err == .None { + element.value = strings.intern_get(&doc.intern, decoded) + } else { + element.value = strings.intern_get(&doc.intern, body_text) + } } } @@ -488,15 +496,6 @@ validate_options :: proc(options: Options) -> (validated: Options, err: Error) { if .Error_on_Unsupported in validated.flags && .Ignore_Unsupported in validated.flags { return options, .Conflicting_Options } - - if .Unbox_CDATA in validated.flags { - return options, .Unhandled_CDATA_Unboxing - } - - if .Decode_SGML_Entities in validated.flags { - return options, .Unhandled_SGML_Entity_Decoding - } - return validated, .None } From d65d6edb0e1887871c4de6a4e8a1630927153eae Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 5 Dec 2021 02:17:48 +0100 Subject: [PATCH 0014/1052] [xml] Improve XML tests, test `core:encoding/entity`. --- core/encoding/entity/entity.odin | 7 + .../entity/example/entity_example.odin | 1 + core/encoding/entity/example/test.html | 2 +- tests/core/assets/XML/entities.html | 29 ++ ...-xliff-1.0.xliff => nl_NL-xliff-1.2.xliff} | 0 tests/core/assets/XML/utf8.xml | 2 +- tests/core/encoding/xml/test_core_xml.odin | 426 +++++++++++------- 7 files changed, 291 insertions(+), 176 deletions(-) create mode 100644 tests/core/assets/XML/entities.html rename tests/core/assets/XML/{nl_NL-xliff-1.0.xliff => nl_NL-xliff-1.2.xliff} (100%) diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index 8742446e6..db1a5ad0b 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -115,7 +115,14 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := We don't need to check if we need to write a `<`, because if it isn't CDATA or a comment, it couldn't have been part of an XML tag body to be decoded here. + + Keep in mind that we could already *be* inside a CDATA tag. + If so, write `>` as a literal and continue. */ + if in_data { + write_rune(&builder, '<') + continue + } in_data = _handle_xml_special(&t, &builder, options) or_return case ']': diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin index 161a44827..882203f48 100644 --- a/core/encoding/entity/example/entity_example.odin +++ b/core/encoding/entity/example/entity_example.odin @@ -50,6 +50,7 @@ _main :: proc() { using fmt options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }} + doc, _ := xml.parse(#load("test.html"), options) defer xml.destroy(doc) diff --git a/core/encoding/entity/example/test.html b/core/encoding/entity/example/test.html index 62a0bb35a..ebbc6470c 100644 --- a/core/encoding/entity/example/test.html +++ b/core/encoding/entity/example/test.html @@ -22,7 +22,7 @@
- | | | fj ` \ ® ϱ ∳ + | | | fj ` \ ® ϱ ∳ ⁏
\ No newline at end of file diff --git a/tests/core/assets/XML/entities.html b/tests/core/assets/XML/entities.html new file mode 100644 index 000000000..05a6b107e --- /dev/null +++ b/tests/core/assets/XML/entities.html @@ -0,0 +1,29 @@ + + + Entity Reference Test + + + +

Entity Reference Test

+
+ Foozle]! © 42&;1234& +
+ + +
+ Foozle]! © 42&;1234& +
+ +
+ | | | fj ` \ ® ϱ ∳ ⁏ +
+ + \ No newline at end of file diff --git a/tests/core/assets/XML/nl_NL-xliff-1.0.xliff b/tests/core/assets/XML/nl_NL-xliff-1.2.xliff similarity index 100% rename from tests/core/assets/XML/nl_NL-xliff-1.0.xliff rename to tests/core/assets/XML/nl_NL-xliff-1.2.xliff diff --git a/tests/core/assets/XML/utf8.xml b/tests/core/assets/XML/utf8.xml index c9ed3bf69..6e1a897ea 100644 --- a/tests/core/assets/XML/utf8.xml +++ b/tests/core/assets/XML/utf8.xml @@ -4,5 +4,5 @@ <부끄러운:barzle> ရှက်စရာ ဇီးကွက် Owl of Shame - More CDATA Hello, world! Nonsense. + More CDATA Hello, world! Nonsense. \ No newline at end of file diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index c2e0aa172..5cb59e001 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -3,16 +3,16 @@ package test_core_xml import "core:encoding/xml" import "core:testing" import "core:mem" +import "core:strings" +import "core:io" import "core:fmt" +import "core:hash" Silent :: proc(pos: xml.Pos, fmt: string, args: ..any) { // Custom (silent) error handler. } -OPTIONS :: xml.Options{ - flags = { - .Ignore_Unsupported, .Intern_Comments, - }, +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "", } @@ -22,76 +22,153 @@ TEST_fail := 0 TEST :: struct { filename: string, options: xml.Options, - expected: struct { - error: xml.Error, - xml_version: string, - xml_encoding: string, - doctype: string, - }, + err: xml.Error, + crc32: u32, } +/* + Relative to ODIN_ROOT +*/ +TEST_FILE_PATH_PREFIX :: "tests/core/assets/XML" + TESTS :: []TEST{ /* First we test that certain files parse without error. */ + { - filename = "assets/XML/utf8.xml", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "恥ずべきフクロウ", + /* + + + <恥ずべきフクロウ 올빼미_id="Foozle Hello, world!"]]>Barzle"> + <부끄러운:barzle> + ရှက်စရာ ဇီးကွက် + Owl of Shame + More CDATA Hello, world! Nonsense. + + */ + + /* + Tests UTF-8 idents and values. + Test namespaced ident. + Tests that nested partial CDATA start doesn't trip up parser. + */ + filename = "utf8.xml", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "恥ずべきフクロウ", }, + crc32 = 0x30d82264, }, + { - filename = "assets/XML/nl_NL-qt-ts.ts", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "TS", + /* + Same as above. + Unbox CDATA in data tag. + */ + filename = "utf8.xml", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, + }, + expected_doctype = "恥ずべきフクロウ", }, + crc32 = 0x6d38ac58, }, + { - filename = "assets/XML/nl_NL-xliff-1.0.xliff", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "UTF-8", - doctype = "", + /* + Simple Qt TS translation file. + `core:i18n` requires it to be parsed properly. + */ + filename = "nl_NL-qt-ts.ts", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "TS", }, + crc32 = 0x7bce2630, }, + { - filename = "assets/XML/nl_NL-xliff-2.0.xliff", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "", + /* + Simple XLiff 1.2 file. + `core:i18n` requires it to be parsed properly. + */ + filename = "nl_NL-xliff-1.2.xliff", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "xliff", }, + crc32 = 0x43f19d61, + }, + + { + /* + Simple XLiff 2.0 file. + `core:i18n` requires it to be parsed properly. + */ + filename = "nl_NL-xliff-2.0.xliff", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "xliff", + }, + crc32 = 0x961e7635, + }, + + { + filename = "entities.html", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "html", + }, + crc32 = 0xdb4a1e79, + }, + + { + filename = "entities.html", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, + }, + expected_doctype = "html", + }, + crc32 = 0x82588917, + }, + + { + filename = "entities.html", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "html", + }, + crc32 = 0x5e74d8a6, }, /* Then we test that certain errors are returned as expected. */ { - filename = "assets/XML/utf8.xml", + filename = "utf8.xml", options = { flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "Odin", }, - expected = { - error = .Invalid_DocType, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "恥ずべきフクロウ", - }, + err = .Invalid_DocType, + crc32 = 0x49b83d0a, }, } @@ -115,6 +192,136 @@ when ODIN_TEST { } } +test_file_path :: proc(filename: string) -> (path: string) { + + path = fmt.tprintf("%v%v/%v", ODIN_ROOT, TEST_FILE_PATH_PREFIX, filename) + temp := transmute([]u8)path + + for r, i in path { + if r == '\\' { + temp[i] = '/' + } + } + return path +} + +doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { + /* + Effectively a clone of the debug printer in the xml package. + We duplicate it here so that the way it prints an XML document to a string is stable. + + This way we can hash the output. If it changes, it means that the document or how it was parsed changed, + not how it was printed. One less source of variability. + */ + print :: proc(writer: io.Writer, doc: ^xml.Document) -> (written: int, err: io.Error) { + if doc == nil { return } + using fmt + + written += wprintf(writer, "[XML Prolog]\n") + + for attr in doc.prolog { + written += wprintf(writer, "\t%v: %v\n", attr.key, attr.val) + } + + written += wprintf(writer, "[Encoding] %v\n", doc.encoding) + + if len(doc.doctype.ident) > 0 { + written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) + + if len(doc.doctype.rest) > 0 { + wprintf(writer, "\t%v\n", doc.doctype.rest) + } + } + + for comment in doc.comments { + written += wprintf(writer, "[Pre-root comment] %v\n", comment) + } + + if doc.root != nil { + wprintln(writer, " --- ") + print_element(writer, doc.root) + wprintln(writer, " --- ") + } + + return written, .None + } + + print_element :: proc(writer: io.Writer, element: ^xml.Element, indent := 0) -> (written: int, err: io.Error) { + if element == nil { return } + using fmt + + tab :: proc(writer: io.Writer, indent: int) { + for _ in 0..=indent { + wprintf(writer, "\t") + } + } + + tab(writer, indent) + + if element.kind == .Element { + wprintf(writer, "<%v>\n", element.ident) + if len(element.value) > 0 { + tab(writer, indent + 1) + wprintf(writer, "[Value] %v\n", element.value) + } + + for attr in element.attribs { + tab(writer, indent + 1) + wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val) + } + + for child in element.children { + print_element(writer, child, indent + 1) + } + } else if element.kind == .Comment { + wprintf(writer, "[COMMENT] %v\n", element.value) + } + + return written, .None + } + + buf: strings.Builder + defer strings.destroy_builder(&buf) + + print(strings.to_writer(&buf), doc) + return strings.clone(strings.to_string(buf)) +} + +@test +run_tests :: proc(t: ^testing.T) { + using fmt + + for test in TESTS { + path := test_file_path(test.filename) + printf("\nTrying to parse %v\n\n", path) + + doc, err := xml.parse(path, test.options, Silent) + defer xml.destroy(doc) + + tree_string := doc_to_string(doc) + tree_bytes := transmute([]u8)tree_string + defer delete(tree_bytes) + + crc32 := hash.crc32(tree_bytes) + + failed := err != test.err + err_msg := tprintf("Expected return value %v, got %v", test.err, err) + expect(t, err == test.err, err_msg) + + failed |= crc32 != test.crc32 + err_msg = tprintf("Expected CRC 0x%08x, got 0x%08x", test.crc32, crc32) + expect(t, crc32 == test.crc32, err_msg) + + if failed { + /* + Don't fully print big trees. + */ + tree_string = tree_string[:min(2_048, len(tree_string))] + println(tree_string) + } + } +} + main :: proc() { t := testing.T{} @@ -132,133 +339,4 @@ main :: proc() { } fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) -} - -@test -run_tests :: proc(t: ^testing.T) { - using fmt - - count := 0 - - for test in TESTS { - printf("Trying to parse %v\n\n", test.filename) - - doc, err := xml.parse(test.filename, test.options, Silent) - defer xml.destroy(doc) - - err_msg := tprintf("Expected return value %v, got %v", test.expected.error, err) - expect(t, err == test.expected.error, err_msg) - - if len(test.expected.xml_version) > 0 { - xml_version := "" - for attr in doc.prolog { - if attr.key == "version" { - xml_version = attr.val - } - } - - err_msg = tprintf("Expected XML version %v, got %v", test.expected.xml_version, xml_version) - expect(t, xml_version == test.expected.xml_version, err_msg) - } - - if len(test.expected.xml_encoding) > 0 { - xml_encoding := "" - for attr in doc.prolog { - if attr.key == "encoding" { - xml_encoding = attr.val - } - } - - err_msg = tprintf("Expected XML encoding %v, got %v", test.expected.xml_encoding, xml_encoding) - expect(t, xml_encoding == test.expected.xml_encoding, err_msg) - } - - err_msg = tprintf("Expected DOCTYPE %v, got %v", test.expected.doctype, doc.doctype.ident) - expect(t, doc.doctype.ident == test.expected.doctype, err_msg) - - /* - File-specific tests. - */ - switch count { - case 0: - expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") - attr := doc.root.attribs[0] - - attr_key_expected := "올빼미_id" - attr_val_expected := "Foozle Hello, world!\"]]>Barzle" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - - expect(t, len(doc.root.children) > 0, "Expected the root tag to have children.") - child := doc.root.children[0] - - first_child_ident := "부끄러운:barzle" - attr_err = tprintf("Expected first child tag's ident to be %v, got %v", first_child_ident, child.ident) - expect(t, child.ident == first_child_ident, attr_err) - - case 2: - expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") - - { - attr := doc.root.attribs[0] - - attr_key_expected := "version" - attr_val_expected := "1.2" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - - { - attr := doc.root.attribs[1] - - attr_key_expected := "xmlns" - attr_val_expected := "urn:oasis:names:tc:xliff:document:1.2" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - - case 3: - expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") - - { - attr := doc.root.attribs[0] - - attr_key_expected := "xmlns" - attr_val_expected := "urn:oasis:names:tc:xliff:document:2.0" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - - { - attr := doc.root.attribs[1] - - attr_key_expected := "version" - attr_val_expected := "2.0" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - } - - count += 1 - } } \ No newline at end of file From d7200f61441b6acfc4f0b47e900095f08490da58 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 5 Dec 2021 02:40:13 +0100 Subject: [PATCH 0015/1052] Improve tests in general. Less spammy core tests: They don't print PASSes now, only logs and failures. `core:image` and `core:encoding/xml` tests also find their assets relative to `ODIN_ROOT` now. --- tests/core/compress/test_core_compress.odin | 9 +- tests/core/crypto/test_core_crypto.odin | 1691 +++++++++--------- tests/core/encoding/json/test_core_json.odin | 9 +- tests/core/encoding/xml/test_core_xml.odin | 43 +- tests/core/hash/test_core_hash.odin | 9 +- tests/core/image/test_core_image.odin | 51 +- tests/core/odin/test_parser.odin | 37 +- tests/core/strings/test_core_strings.odin | 59 +- 8 files changed, 948 insertions(+), 960 deletions(-) diff --git a/tests/core/compress/test_core_compress.odin b/tests/core/compress/test_core_compress.odin index c925c0258..908ef12e4 100644 --- a/tests/core/compress/test_core_compress.odin +++ b/tests/core/compress/test_core_compress.odin @@ -30,18 +30,15 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(message) + fmt.printf("[%v] %v\n", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) } } @@ -51,7 +48,7 @@ main :: proc() { zlib_test(&t) gzip_test(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 2ad00be66..6d3a9f8e4 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -1,15 +1,15 @@ package test_core_crypto /* - Copyright 2021 zhibog - Made available under the BSD-3 license. + Copyright 2021 zhibog + Made available under the BSD-3 license. - List of contributors: - zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Test runner setup. + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Test runner setup. - Tests for the hashing algorithms within the crypto library. - Where possible, the official test vectors are used to validate the implementation. + Tests for the hashing algorithms within the crypto library. + Where possible, the official test vectors are used to validate the implementation. */ import "core:testing" @@ -41,1065 +41,1062 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } main :: proc() { - t := testing.T{} - test_md2(&t) - test_md4(&t) - test_md5(&t) - test_sha1(&t) - test_sha224(&t) - test_sha256(&t) - test_sha384(&t) - test_sha512(&t) - test_sha3_224(&t) - test_sha3_256(&t) - test_sha3_384(&t) - test_sha3_512(&t) - test_shake_128(&t) - test_shake_256(&t) - test_keccak_224(&t) - test_keccak_256(&t) - test_keccak_384(&t) - test_keccak_512(&t) - test_whirlpool(&t) - test_gost(&t) - test_streebog_256(&t) - test_streebog_512(&t) - test_blake_224(&t) - test_blake_256(&t) - test_blake_384(&t) - test_blake_512(&t) - test_blake2b(&t) - test_blake2s(&t) - test_ripemd_128(&t) - test_ripemd_160(&t) - test_ripemd_256(&t) - test_ripemd_320(&t) - test_tiger_128(&t) - test_tiger_160(&t) - test_tiger_192(&t) - test_tiger2_128(&t) - test_tiger2_160(&t) - test_tiger2_192(&t) - test_sm3(&t) - test_jh_224(&t) - test_jh_256(&t) - test_jh_384(&t) - test_jh_512(&t) - test_groestl_224(&t) - test_groestl_256(&t) - test_groestl_384(&t) - test_groestl_512(&t) - test_haval_128(&t) - test_haval_160(&t) - test_haval_192(&t) - test_haval_224(&t) - test_haval_256(&t) + t := testing.T{} + test_md2(&t) + test_md4(&t) + test_md5(&t) + test_sha1(&t) + test_sha224(&t) + test_sha256(&t) + test_sha384(&t) + test_sha512(&t) + test_sha3_224(&t) + test_sha3_256(&t) + test_sha3_384(&t) + test_sha3_512(&t) + test_shake_128(&t) + test_shake_256(&t) + test_keccak_224(&t) + test_keccak_256(&t) + test_keccak_384(&t) + test_keccak_512(&t) + test_whirlpool(&t) + test_gost(&t) + test_streebog_256(&t) + test_streebog_512(&t) + test_blake_224(&t) + test_blake_256(&t) + test_blake_384(&t) + test_blake_512(&t) + test_blake2b(&t) + test_blake2s(&t) + test_ripemd_128(&t) + test_ripemd_160(&t) + test_ripemd_256(&t) + test_ripemd_320(&t) + test_tiger_128(&t) + test_tiger_160(&t) + test_tiger_192(&t) + test_tiger2_128(&t) + test_tiger2_160(&t) + test_tiger2_192(&t) + test_sm3(&t) + test_jh_224(&t) + test_jh_256(&t) + test_jh_384(&t) + test_jh_512(&t) + test_groestl_224(&t) + test_groestl_256(&t) + test_groestl_384(&t) + test_groestl_512(&t) + test_haval_128(&t) + test_haval_160(&t) + test_haval_192(&t) + test_haval_224(&t) + test_haval_256(&t) - // "modern" crypto tests - test_chacha20(&t) - test_poly1305(&t) - test_chacha20poly1305(&t) - test_x25519(&t) - test_rand_bytes(&t) + // "modern" crypto tests + test_chacha20(&t) + test_poly1305(&t) + test_chacha20poly1305(&t) + test_x25519(&t) + test_rand_bytes(&t) - bench_modern(&t) + bench_modern(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } TestHash :: struct { - hash: string, - str: string, + hash: string, + str: string, } hex_string :: proc(bytes: []byte, allocator := context.temp_allocator) -> string { - lut: [16]byte = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} - buf := make([]byte, len(bytes) * 2, allocator) - for i := 0; i < len(bytes); i += 1 { - buf[i * 2 + 0] = lut[bytes[i] >> 4 & 0xf] - buf[i * 2 + 1] = lut[bytes[i] & 0xf] - } - return string(buf) + lut: [16]byte = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} + buf := make([]byte, len(bytes) * 2, allocator) + for i := 0; i < len(bytes); i += 1 { + buf[i * 2 + 0] = lut[bytes[i] >> 4 & 0xf] + buf[i * 2 + 1] = lut[bytes[i] & 0xf] + } + return string(buf) } @(test) test_md2 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 - test_vectors := [?]TestHash { - TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, - TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, - TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, - TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, - TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md2.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 + test_vectors := [?]TestHash { + TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, + TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, + TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, + TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, + TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md2.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_md4 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 - test_vectors := [?]TestHash { - TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, - TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, - TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, - TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, - TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md4.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 + test_vectors := [?]TestHash { + TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, + TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, + TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, + TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, + TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md4.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_md5 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 - test_vectors := [?]TestHash { - TestHash{"d41d8cd98f00b204e9800998ecf8427e", ""}, - TestHash{"0cc175b9c0f1b6a831c399e269772661", "a"}, - TestHash{"900150983cd24fb0d6963f7d28e17f72", "abc"}, - TestHash{"f96b697d7cb7938d525a2f31aaf161d0", "message digest"}, - TestHash{"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md5.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 + test_vectors := [?]TestHash { + TestHash{"d41d8cd98f00b204e9800998ecf8427e", ""}, + TestHash{"0cc175b9c0f1b6a831c399e269772661", "a"}, + TestHash{"900150983cd24fb0d6963f7d28e17f72", "abc"}, + TestHash{"f96b697d7cb7938d525a2f31aaf161d0", "message digest"}, + TestHash{"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md5.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha1 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, - TestHash{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, - TestHash{"f9537c23893d2014f365adf8ffe33b8eb0297ed1", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"346fb528a24b48f563cb061470bcfd23740427ad", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, - TestHash{"c729c8996ee0a6f74f4f3248e8957edf704fb624", "01234567012345670123456701234567"}, - TestHash{"84983e441c3bd26ebaae4aa1f95129e5e54670f1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha1.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, + TestHash{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, + TestHash{"f9537c23893d2014f365adf8ffe33b8eb0297ed1", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"346fb528a24b48f563cb061470bcfd23740427ad", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, + TestHash{"c729c8996ee0a6f74f4f3248e8957edf704fb624", "01234567012345670123456701234567"}, + TestHash{"84983e441c3bd26ebaae4aa1f95129e5e54670f1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha1.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, - TestHash{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, - TestHash{"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, + TestHash{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, + TestHash{"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, - TestHash{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, - TestHash{"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, + TestHash{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, + TestHash{"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, - TestHash{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, - TestHash{"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, + TestHash{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, + TestHash{"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, - TestHash{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, - TestHash{"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, + TestHash{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, + TestHash{"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""}, - TestHash{"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"}, - TestHash{"10241ac5187380bd501192e4e56b5280908727dd8fe0d10d4e5ad91e", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"fd645fe07d814c397e85e85f92fe58b949f55efa4d3468b2468da45a", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", "a"}, - TestHash{"6961f694b2ff3ed6f0c830d2c66da0c5e7ca9445f7c0dca679171112", "01234567012345670123456701234567"}, - TestHash{"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""}, + TestHash{"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"}, + TestHash{"10241ac5187380bd501192e4e56b5280908727dd8fe0d10d4e5ad91e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"fd645fe07d814c397e85e85f92fe58b949f55efa4d3468b2468da45a", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", "a"}, + TestHash{"6961f694b2ff3ed6f0c830d2c66da0c5e7ca9445f7c0dca679171112", "01234567012345670123456701234567"}, + TestHash{"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", ""}, - TestHash{"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"}, - TestHash{"565ada1ced21278cfaffdde00dea0107964121ac25e4e978abc59412be74550a", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"8cc1709d520f495ce972ece48b0d2e1f74ec80d53bc5c47457142158fae15d98", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "a"}, - TestHash{"e4786de5f88f7d374b7288f225ea9f2f7654da200bab5d417e1fb52d49202767", "01234567012345670123456701234567"}, - TestHash{"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", ""}, + TestHash{"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"}, + TestHash{"565ada1ced21278cfaffdde00dea0107964121ac25e4e978abc59412be74550a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"8cc1709d520f495ce972ece48b0d2e1f74ec80d53bc5c47457142158fae15d98", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "a"}, + TestHash{"e4786de5f88f7d374b7288f225ea9f2f7654da200bab5d417e1fb52d49202767", "01234567012345670123456701234567"}, + TestHash{"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", ""}, - TestHash{"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", "abc"}, - TestHash{"9aa92dbb716ebb573def0d5e3cdd28d6add38ada310b602b8916e690a3257b7144e5ddd3d0dbbc559c48480d34d57a9a", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"77c90323d7392bcdee8a3e7f74f19f47b7d1b1a825ac6a2d8d882a72317879cc26597035f1fc24fe65090b125a691282", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", "a"}, - TestHash{"51072590ad4c51b27ff8265590d74f92de7cc55284168e414ca960087c693285b08a283c6b19d77632994cb9eb93f1be", "01234567012345670123456701234567"}, - TestHash{"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", ""}, + TestHash{"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", "abc"}, + TestHash{"9aa92dbb716ebb573def0d5e3cdd28d6add38ada310b602b8916e690a3257b7144e5ddd3d0dbbc559c48480d34d57a9a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"77c90323d7392bcdee8a3e7f74f19f47b7d1b1a825ac6a2d8d882a72317879cc26597035f1fc24fe65090b125a691282", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", "a"}, + TestHash{"51072590ad4c51b27ff8265590d74f92de7cc55284168e414ca960087c693285b08a283c6b19d77632994cb9eb93f1be", "01234567012345670123456701234567"}, + TestHash{"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", ""}, - TestHash{"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", "abc"}, - TestHash{"9f9a327944a35988d67effc4fa748b3c07744f736ac70b479d8e12a3d10d6884d00a7ef593690305462e9e9030a67c51636fd346fd8fa0ee28a5ac2aee103d2e", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"dbb124a0deda966eb4d199d0844fa0beb0770ea1ccddabcd335a7939a931ac6fb4fa6aebc6573f462ced2e4e7178277803be0d24d8bc2864626d9603109b7891", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", "a"}, - TestHash{"5679e353bc8eeea3e801ca60448b249bcfd3ac4a6c3abe429a807bcbd4c9cd12da87a5a9dc74fde64c0d44718632cae966b078397c6f9ec155c6a238f2347cf1", "01234567012345670123456701234567"}, - TestHash{"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", ""}, + TestHash{"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", "abc"}, + TestHash{"9f9a327944a35988d67effc4fa748b3c07744f736ac70b479d8e12a3d10d6884d00a7ef593690305462e9e9030a67c51636fd346fd8fa0ee28a5ac2aee103d2e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"dbb124a0deda966eb4d199d0844fa0beb0770ea1ccddabcd335a7939a931ac6fb4fa6aebc6573f462ced2e4e7178277803be0d24d8bc2864626d9603109b7891", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", "a"}, + TestHash{"5679e353bc8eeea3e801ca60448b249bcfd3ac4a6c3abe429a807bcbd4c9cd12da87a5a9dc74fde64c0d44718632cae966b078397c6f9ec155c6a238f2347cf1", "01234567012345670123456701234567"}, + TestHash{"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_shake_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"7f9c2ba4e88f827d616045507605853e", ""}, - TestHash{"f4202e3c5852f9182a0430fd8144f0a7", "The quick brown fox jumps over the lazy dog"}, - TestHash{"853f4538be0db9621a6cea659a06c110", "The quick brown fox jumps over the lazy dof"}, - } - for v, _ in test_vectors { - computed := shake.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"7f9c2ba4e88f827d616045507605853e", ""}, + TestHash{"f4202e3c5852f9182a0430fd8144f0a7", "The quick brown fox jumps over the lazy dog"}, + TestHash{"853f4538be0db9621a6cea659a06c110", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_shake_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", ""}, - TestHash{"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca", "The quick brown fox jumps over the lazy dog"}, - TestHash{"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401", "The quick brown fox jumps over the lazy dof"}, - } - for v, _ in test_vectors { - computed := shake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", ""}, + TestHash{"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca", "The quick brown fox jumps over the lazy dog"}, + TestHash{"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", ""}, - TestHash{"c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", ""}, + TestHash{"c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", ""}, - TestHash{"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", ""}, + TestHash{"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", ""}, - TestHash{"f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", ""}, + TestHash{"f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", ""}, - TestHash{"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", ""}, + TestHash{"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_whirlpool :: proc(t: ^testing.T) { - // Test vectors from - // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html - test_vectors := [?]TestHash { - TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, - TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, - TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, - TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, - TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, - TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, - TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, - TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, - TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, - TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, - TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, - TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, - TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, - } - for v, _ in test_vectors { - computed := whirlpool.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html + test_vectors := [?]TestHash { + TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, + TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, + TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, + TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, + TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, + TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, + TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, + TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, + TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, + TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, + TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, + TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, + TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, + } + for v, _ in test_vectors { + computed := whirlpool.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_gost :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, - TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, - TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, - TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, - TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, - TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, - TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, - } - for v, _ in test_vectors { - computed := gost.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, + TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, + TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, + TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, + TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, + TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, + TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, + } + for v, _ in test_vectors { + computed := gost.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_streebog_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, - TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, - TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, + TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, + TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_streebog_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, - TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, - TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, + TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, + TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, - TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, - TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, + TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, + TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, - TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, - TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, + TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, + TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, - TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, - TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, + TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, + TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, - TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, - TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, + TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, + TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake2b :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", ""}, - TestHash{"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := blake2b.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", ""}, + TestHash{"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2b.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake2s :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9", ""}, - TestHash{"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := blake2s.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9", ""}, + TestHash{"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2s.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_128 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, - TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, - TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, - TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, - TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, + TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, + TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, + TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, + TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_160 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, - TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, - TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, - TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, - TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, + TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, + TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, + TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, + TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, - TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, - TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, - TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, - TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, + TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, + TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, + TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, + TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_320 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, - TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, - TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, - TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, - TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_320(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, + TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, + TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, + TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, + TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_320(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b92", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b92", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sm3 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", ""}, - TestHash{"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", "abc"}, - TestHash{"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, - TestHash{"5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea", "The quick brown fox jumps over the lazy dog"}, - TestHash{"ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := sm3.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", ""}, + TestHash{"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", "abc"}, + TestHash{"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, + TestHash{"5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea", "The quick brown fox jumps over the lazy dog"}, + TestHash{"ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := sm3.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, - TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, - TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, + TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, + TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, - TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, - TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, + TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, + TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, - TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, - TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, + TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, + TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, - TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, - TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, + TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, + TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, - TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, - TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, + TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, + TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, - TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, - TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, + TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, + TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, - TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, - TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, + TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, + TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, - TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, - TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, + TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, + TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_128 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, - TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, - TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, - TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, - TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_128_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, - TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_128_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, - TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_128_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, + TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, + TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, + TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, + TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_128_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, + TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_128_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, + TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_128_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_160 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, - TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, - TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, - TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, - TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_160_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, - TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_160_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, - TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_160_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, + TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, + TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, + TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, + TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_160_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, + TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_160_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, + TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_160_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_192 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, - TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_192_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, - TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_192_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, - TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_192_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, + TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_192_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, + TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_192_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, + TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_192_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_224 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, - TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_224_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, - TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_224_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, - TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_224_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, + TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_224_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, + TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_224_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, + TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_224_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_256 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, - TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_256_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, - TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_256_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, - TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_256_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, + TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_256_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, + TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_256_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, + TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_256_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin index 4f415c008..6f2e8c35a 100644 --- a/tests/core/encoding/json/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -12,18 +12,15 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(message) + fmt.printf("[%v] %v\n", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) } } @@ -33,7 +30,7 @@ main :: proc() { parse_json(&t) marshal_json(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 5cb59e001..f9f7a2992 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -173,23 +173,20 @@ TESTS :: []TEST{ } when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } test_file_path :: proc(filename: string) -> (path: string) { @@ -229,7 +226,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) if len(doc.doctype.rest) > 0 { - wprintf(writer, "\t%v\n", doc.doctype.rest) + wprintf(writer, "\t%v\n", doc.doctype.rest) } } @@ -238,9 +235,9 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { } if doc.root != nil { - wprintln(writer, " --- ") - print_element(writer, doc.root) - wprintln(writer, " --- ") + wprintln(writer, " --- ") + print_element(writer, doc.root) + wprintln(writer, " --- ") } return written, .None @@ -293,7 +290,7 @@ run_tests :: proc(t: ^testing.T) { for test in TESTS { path := test_file_path(test.filename) - printf("\nTrying to parse %v\n\n", path) + log(t, fmt.tprintf("Trying to parse %v", path)) doc, err := xml.parse(path, test.options, Silent) defer xml.destroy(doc) @@ -323,7 +320,7 @@ run_tests :: proc(t: ^testing.T) { } main :: proc() { - t := testing.T{} + t := testing.T{} track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) @@ -338,5 +335,5 @@ main :: proc() { } } - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } \ No newline at end of file diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index 8baa604b6..b81af01a5 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -14,18 +14,15 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(" FAIL:", message) + fmt.printf("[%v] %v", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) } } @@ -34,7 +31,7 @@ main :: proc() { test_benchmark_runner(&t) test_xxhash_vectors(&t) test_crc64_vectors(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } /* diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 155b69298..48d9ca1d2 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -25,38 +25,49 @@ import "core:time" import "core:runtime" -WRITE_PPM_ON_FAIL :: #config(WRITE_PPM_ON_FAIL, false) -TEST_SUITE_PATH :: "assets/PNG" +WRITE_PPM_ON_FAIL :: #config(WRITE_PPM_ON_FAIL, false) +TEST_FILE_PATH_PREFIX :: "tests/core/assets/PNG" TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } + I_Error :: image.Error main :: proc() { t := testing.T{} png_test(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +test_file_path :: proc(filename: string, extension := "png") -> (path: string) { + + path = fmt.tprintf("%v%v/%v.%v", ODIN_ROOT, TEST_FILE_PATH_PREFIX, filename, extension) + temp := transmute([]u8)path + + for r, i in path { + if r == '\\' { + temp[i] = '/' + } + } + return path } PNG_Test :: struct { @@ -1461,7 +1472,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { context = runtime.default_context() for file in suite { - test_file := fmt.tprintf("%v/%v.png", TEST_SUITE_PATH, file.file) + test_file := test_file_path(file.file) img: ^png.Image err: png.Error diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index 90d913d10..53711d3ec 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -10,34 +10,29 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } - main :: proc() { - t := testing.T{} - test_parse_demo(&t) + t := testing.T{} + test_parse_demo(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } - @test test_parse_demo :: proc(t: ^testing.T) { pkg, ok := parser.parse_package_from_path("examples/demo") diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index fc1518349..c5436f5c1 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -8,56 +8,53 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } main :: proc() { - t := testing.T{} - test_index_any_small_string_not_found(&t) - test_index_any_larger_string_not_found(&t) - test_index_any_small_string_found(&t) - test_index_any_larger_string_found(&t) + t := testing.T{} + test_index_any_small_string_not_found(&t) + test_index_any_larger_string_not_found(&t) + test_index_any_small_string_found(&t) + test_index_any_larger_string_found(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test test_index_any_small_string_not_found :: proc(t: ^testing.T) { - index := strings.index_any(".", "/:\"") - log(t, index) - expect(t, index == -1, "index_any should be negative") + index := strings.index_any(".", "/:\"") + log(t, index) + expect(t, index == -1, "index_any should be negative") } @test test_index_any_larger_string_not_found :: proc(t: ^testing.T) { - index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"") - expect(t, index == -1, "index_any should be negative") + index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"") + expect(t, index == -1, "index_any should be negative") } @test test_index_any_small_string_found :: proc(t: ^testing.T) { - index := strings.index_any(".", "/:.\"") - expect(t, index == 0, "index_any should be 0") + index := strings.index_any(".", "/:.\"") + expect(t, index == 0, "index_any should be 0") } @test test_index_any_larger_string_found :: proc(t: ^testing.T) { - index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") - expect(t, index == 8, "index_any should be 8") + index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") + expect(t, index == 8, "index_any should be 8") } From 7ec88d24302dcdea38ac09996a2279f4de4f6a25 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 5 Dec 2021 21:06:33 +0100 Subject: [PATCH 0016/1052] [xml] Add option. --- .../entity/example/entity_example.odin | 4 +- core/encoding/xml/example/xml_example.odin | 53 +++++++++++-------- core/encoding/xml/xml_reader.odin | 26 +++++++-- tests/core/encoding/xml/test_core_xml.odin | 10 ++-- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin index 882203f48..6fc377f9d 100644 --- a/core/encoding/entity/example/entity_example.odin +++ b/core/encoding/entity/example/entity_example.odin @@ -64,8 +64,8 @@ main :: proc() { mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) - _main() - //_entities() + // _main() + _entities() if len(track.allocation_map) > 0 { println() diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 085252e92..daa3c5dab 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -2,35 +2,40 @@ package xml_example import "core:encoding/xml" import "core:os" -import "core:path" import "core:mem" import "core:fmt" - -/* - Silent error handler for the parser. -*/ -Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} - -OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } +import "core:time" +import "core:strings" +import "core:hash" example :: proc() { using fmt - filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml") - defer delete(filename) + doc: ^xml.Document + err: xml.Error - doc, err := xml.parse(filename, OPTIONS, Error_Handler) + DOC :: #load("../../../../tests/core/assets/XML/unicode.xml") + + parse_duration: time.Duration + { + time.SCOPED_TICK_DURATION(&parse_duration) + doc, err = xml.parse(DOC, xml.Options{flags={.Ignore_Unsupported}}) + } defer xml.destroy(doc) + ms := time.duration_milliseconds(parse_duration) + speed := (f64(1000.0) / ms) * f64(len(DOC)) / 1_024.0 / 1_024.0 + fmt.printf("Parse time: %v bytes in %.2f ms (%.2f MiB/s).\n", len(DOC), ms, speed) + if err != .None { printf("Load/Parse error: %v\n", err) if err == .File_Error { - printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) + println("\"unicode.xml\" not found. Did you run \"tests\\download_assets.py\"?") } os.exit(1) } - printf("\"%v\" loaded and parsed.\n", filename) + println("\"unicode.xml\" loaded and parsed.") charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") if !charlist_ok { @@ -40,17 +45,19 @@ example :: proc() { printf("Found `` with %v children.\n", len(charlist.children)) - for char in charlist.children { - if char.ident != "character" { - eprintf("Expected ``, got `<%v>`\n", char.ident) - os.exit(1) - } + crc32 := doc_hash(doc) + printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0xcaa042b9 else "🤬", crc32) +} - if _, ok := xml.find_attribute_val_by_key(char, "dec"); !ok { - eprintln("`` attribute not found.") - os.exit(1) - } - } +doc_hash :: proc(doc: ^xml.Document, print := false) -> (crc32: u32) { + buf: strings.Builder + defer strings.destroy_builder(&buf) + w := strings.to_writer(&buf) + + xml.print(w, doc) + tree := strings.to_string(buf) + if print { fmt.println(tree) } + return hash.crc32(transmute([]u8)tree) } main :: proc() { diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 6f49b8e08..b169bd57a 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -71,6 +71,12 @@ Option_Flag :: enum { This option decodes them when encountered. */ Decode_SGML_Entities, + + /* + If a tag body has a comment, it will be stripped unless this option is given. + */ + Keep_Tag_Body_Comments, + } Option_Flags :: bit_set[Option_Flag; u8] @@ -413,15 +419,29 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err /* This should be a tag's body text. */ - body_text := scan_string(t, t.offset) or_return + body_text := scan_string(t, t.offset) or_return + needs_processing := .Unbox_CDATA in opts.flags + needs_processing |= .Decode_SGML_Entities in opts.flags - decode_opts := entity.XML_Decode_Options{ .Comment_Strip } + if !needs_processing { + element.value = strings.intern_get(&doc.intern, body_text) + continue + } + + decode_opts := entity.XML_Decode_Options{} + if .Keep_Tag_Body_Comments not_in opts.flags { + decode_opts += { .Comment_Strip } + } if .Decode_SGML_Entities not_in opts.flags { decode_opts += { .No_Entity_Decode } } + if .Unbox_CDATA in opts.flags { - decode_opts += { .Unbox_CDATA, .Decode_CDATA } + decode_opts += { .Unbox_CDATA } + if .Decode_SGML_Entities in opts.flags { + decode_opts += { .Decode_CDATA } + } } decoded, decode_err := entity.decode_xml(body_text, decode_opts) diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index f9f7a2992..7669afe97 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -8,9 +8,7 @@ import "core:io" import "core:fmt" import "core:hash" -Silent :: proc(pos: xml.Pos, fmt: string, args: ..any) { - // Custom (silent) error handler. -} +Silent :: proc(pos: xml.Pos, format: string, args: ..any) {} OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "", @@ -75,7 +73,7 @@ TESTS :: []TEST{ }, expected_doctype = "恥ずべきフクロウ", }, - crc32 = 0x6d38ac58, + crc32 = 0xad31d8e8, }, { @@ -131,7 +129,7 @@ TESTS :: []TEST{ }, expected_doctype = "html", }, - crc32 = 0xdb4a1e79, + crc32 = 0x573c1033, }, { @@ -306,7 +304,7 @@ run_tests :: proc(t: ^testing.T) { expect(t, err == test.err, err_msg) failed |= crc32 != test.crc32 - err_msg = tprintf("Expected CRC 0x%08x, got 0x%08x", test.crc32, crc32) + err_msg = tprintf("Expected CRC 0x%08x, got 0x%08x, with options %v", test.crc32, crc32, test.options) expect(t, crc32 == test.crc32, err_msg) if failed { From 6e61abc7d06f22129f93110a9f652c3eec21f0c6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 6 Dec 2021 12:04:59 +0100 Subject: [PATCH 0017/1052] [xml] Initial optimization. --- core/encoding/xml/xml_reader.odin | 68 +++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index b169bd57a..0315b0e05 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -26,6 +26,7 @@ package xml Jeroen van Rijn: Initial implementation. */ +import "core:bytes" import "core:strings" import "core:encoding/entity" import "core:mem" @@ -39,6 +40,12 @@ DEFAULT_Options :: Options{ } Option_Flag :: enum { + /* + If the caller says that input may be modified, we can perform in-situ parsing. + If this flag isn't provided, the XML parser first duplicates the input so that it can. + */ + Input_May_Be_Modified, + /* Document MUST start with ` (doc: ^Document, err: Error) { + data := data context.allocator = allocator opts := validate_options(options) or_return + /* + If `.Input_May_Be_Modified` is not specified, we duplicate the input so that we can modify it in-place. + */ + if .Input_May_Be_Modified not_in opts.flags { + data = bytes.clone(data) + } + t := &Tokenizer{} init(t, string(data), path, error_handler) doc = new(Document) doc.allocator = allocator doc.tokenizer = t + doc.input = data - strings.intern_init(&doc.intern, allocator, allocator) + // strings.intern_init(&doc.intern, allocator, allocator) - err = .Unexpected_Token - element, parent: ^Element + err = .Unexpected_Token + element, parent: ^Element tag_is_open := false @@ -292,8 +313,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err case: if .Error_on_Unsupported in opts.flags { error(t, t.offset, "Unhandled: (doc: ^Document, err: Error) { context.allocator = allocator + options := options data, data_ok := os.read_entire_file(filename) - defer delete(data) - if !data_ok { return {}, .File_Error } + options.flags += { .Input_May_Be_Modified } + return parse_from_slice(data, options, filename, error_handler, allocator) } @@ -499,10 +517,16 @@ destroy :: proc(doc: ^Document) { if doc == nil { return } free_element(doc.root) - strings.intern_destroy(&doc.intern) delete(doc.prolog) delete(doc.comments) + delete(doc.input) + + for s in doc.strings_to_free { + delete(s) + } + delete(doc.strings_to_free) + free(doc) } @@ -538,8 +562,8 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) _ = expect(t, .Eq) or_return value := expect(t, .String) or_return - attr.key = strings.intern_get(&doc.intern, key.text) - attr.val = strings.intern_get(&doc.intern, value.text) + attr.key = key.text + attr.val = value.text err = .None return @@ -651,7 +675,7 @@ parse_doctype :: proc(doc: ^Document) -> (err: Error) { t := doc.tokenizer tok := expect(t, .Ident) or_return - doc.doctype.ident = strings.intern_get(&doc.intern, tok.text) + doc.doctype.ident = tok.text skip_whitespace(t) offset := t.offset @@ -660,6 +684,6 @@ parse_doctype :: proc(doc: ^Document) -> (err: Error) { /* -1 because the current offset is that of the closing tag, so the rest of the DOCTYPE tag ends just before it. */ - doc.doctype.rest = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + doc.doctype.rest = string(t.src[offset : t.offset - 1]) return .None } \ No newline at end of file From 29ca6ee420f36381ee0fba6bd409dc51716ab206 Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 17 Dec 2021 10:41:49 -0500 Subject: [PATCH 0018/1052] add zeroing to new region from realloc --- core/os/os.odin | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/os/os.odin b/core/os/os.odin index 83158be80..9230bc22c 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -206,11 +206,20 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, } } - aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, mem.Allocator_Error) { + aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> (new_memory: []byte, err: mem.Allocator_Error) { if p == nil { return nil, nil } - return aligned_alloc(new_size, new_alignment, p) + + new_memory = aligned_alloc(new_size, new_alignment, p) or_return + when ODIN_OS != "windows" { + // NOTE: realloc does not zero the new memory, so we do it + if new_size > old_size { + new_region := mem.raw_data(new_memory[old_size:]) + mem.zero(new_region, new_size - old_size) + } + } + return } switch mode { From ebdb3ab43a8cdc49cb715ecb6f5fd38522912aa5 Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 17 Dec 2021 12:04:05 -0500 Subject: [PATCH 0019/1052] added notes about _unix_alloc --- core/os/os_darwin.odin | 2 ++ core/os/os_freebsd.odin | 2 ++ core/os/os_linux.odin | 2 ++ 3 files changed, 6 insertions(+) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index d40c80aeb..6fa43bf09 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -530,6 +530,8 @@ heap_alloc :: proc(size: int) -> rawptr { return _unix_calloc(1, size) } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. return _unix_realloc(ptr, new_size) } heap_free :: proc(ptr: rawptr) { diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index e9314b468..82317532d 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -378,6 +378,8 @@ heap_alloc :: proc(size: int) -> rawptr { } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. return _unix_realloc(ptr, c.size_t(new_size)); } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 260a051ce..116fbdba5 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -543,6 +543,8 @@ heap_alloc :: proc(size: int) -> rawptr { } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. return _unix_realloc(ptr, c.size_t(new_size)) } From 516065d7c22c19aa953edf1d4ab1537f07742dec Mon Sep 17 00:00:00 2001 From: Henry Dooley Date: Sat, 25 Dec 2021 16:27:52 -0600 Subject: [PATCH 0020/1052] factor out alloca generation into a helper --- src/llvm_backend.hpp | 2 ++ src/llvm_backend_const.cpp | 6 +++--- src/llvm_backend_general.cpp | 18 +++++++++++------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e70b1f84c..5616701f8 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -459,6 +459,8 @@ void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t); bool lb_is_expr_untyped_const(Ast *expr); +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment); + void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment); void lb_emit_init_context(lbProcedure *p, lbAddr addr); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 5862a7add..bc14b099b 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -413,9 +413,9 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); LLVMTypeRef llvm_type = lb_type(m, t); - array_data = LLVMBuildAlloca(p->builder, llvm_type, ""); - LLVMSetAlignment(array_data, 16); // TODO(bill): Make this configurable - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + + array_data = llvm_alloca(p, llvm_type, 16); + LLVMBuildStore(p->builder, backing_array.value, array_data); { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 17eeb0bea..9f77cef65 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -216,6 +216,14 @@ LLVMValueRef llvm_one(lbModule *m) { return LLVMConstInt(lb_type(m, t_i32), 1, false); } +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment) { + LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, ""); + LLVMSetAlignment(val, alignment); + LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + + return val; +} + lbValue lb_zero(lbModule *m, Type *t) { lbValue v = {}; v.value = LLVMConstInt(lb_type(m, t), 0, false); @@ -2267,11 +2275,10 @@ general_end:; GB_ASSERT(p->decl_block != p->curr_block); LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - LLVMValueRef ptr = LLVMBuildAlloca(p->builder, dst_type, ""); - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); max_align = gb_max(max_align, 4); - LLVMSetAlignment(ptr, cast(unsigned)max_align); + + LLVMValueRef ptr = llvm_alloca(p, dst_type, max_align); LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); LLVMBuildStore(p->builder, val, nptr); @@ -2642,16 +2649,13 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p } LLVMTypeRef llvm_type = lb_type(p->module, type); - LLVMValueRef ptr = LLVMBuildAlloca(p->builder, llvm_type, name); unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(llvm_type)); if (is_type_matrix(type)) { alignment *= 2; // NOTE(bill): Just in case } - LLVMSetAlignment(ptr, alignment); - - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment); if (!zero_init && !force_no_init) { // If there is any padding of any kind, just zero init regardless of zero_init parameter From 069c05669f5c7bbe0a2f5c82b1daa334481cd0cb Mon Sep 17 00:00:00 2001 From: Henry Dooley Date: Sat, 25 Dec 2021 16:46:02 -0600 Subject: [PATCH 0021/1052] cast isize to unsigned int for llvm api, add defaulted name parameter to helper. --- src/llvm_backend.hpp | 2 +- src/llvm_backend_general.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 5616701f8..9aea75be9 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -459,7 +459,7 @@ void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t); bool lb_is_expr_untyped_const(Ast *expr); -LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment); +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const* name = ""); void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 9f77cef65..46b5fdb88 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -216,9 +216,9 @@ LLVMValueRef llvm_one(lbModule *m) { return LLVMConstInt(lb_type(m, t_i32), 1, false); } -LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment) { - LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, ""); - LLVMSetAlignment(val, alignment); +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const* name) { + LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, name); + LLVMSetAlignment(val, cast(unsigned int)alignment); LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); return val; @@ -2655,7 +2655,7 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p alignment *= 2; // NOTE(bill): Just in case } - LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment); + LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment, name); if (!zero_init && !force_no_init) { // If there is any padding of any kind, just zero init regardless of zero_init parameter From 865d88dd56a8b048e861787e048f364a4579da2b Mon Sep 17 00:00:00 2001 From: Henry Dooley Date: Tue, 28 Dec 2021 10:50:34 -0600 Subject: [PATCH 0022/1052] review feedback --- src/llvm_backend_const.cpp | 2 -- src/llvm_backend_general.cpp | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index bc14b099b..2eedbb7c9 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -410,8 +410,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc // NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs // its backing data on the stack lbProcedure *p = m->curr_procedure; - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - LLVMTypeRef llvm_type = lb_type(m, t); array_data = llvm_alloca(p, llvm_type, 16); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 46b5fdb88..1f97826f4 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -217,8 +217,11 @@ LLVMValueRef llvm_one(lbModule *m) { } LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const* name) { + LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); + LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, name); LLVMSetAlignment(val, cast(unsigned int)alignment); + LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); return val; @@ -2273,7 +2276,6 @@ general_end:; return loaded_val; } else { GB_ASSERT(p->decl_block != p->curr_block); - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); max_align = gb_max(max_align, 4); From d57ec4a11d217c906a1ed18161b0dc6beba02089 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 16 Jan 2022 13:20:12 +0100 Subject: [PATCH 0023/1052] Fix return stmt when it's one lined(check for close brace). --- core/odin/parser/parser.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index e8c2c848d..0366e70d2 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1312,7 +1312,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { } results: [dynamic]^ast.Expr - for p.curr_tok.kind != .Semicolon { + for p.curr_tok.kind != .Semicolon && p.curr_tok.kind != .Close_Brace { result := parse_expr(p, false) append(&results, result) if p.curr_tok.kind != .Comma || From e5868e32050fc2fe92a50caa743c8123d3fe59d9 Mon Sep 17 00:00:00 2001 From: CiD- Date: Thu, 20 Jan 2022 10:17:47 -0500 Subject: [PATCH 0024/1052] add zeroing regardless of ODIN_OS --- core/os/os.odin | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/core/os/os.odin b/core/os/os.odin index 9230bc22c..2ebfebd2e 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -212,12 +212,11 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, } new_memory = aligned_alloc(new_size, new_alignment, p) or_return - when ODIN_OS != "windows" { - // NOTE: realloc does not zero the new memory, so we do it - if new_size > old_size { - new_region := mem.raw_data(new_memory[old_size:]) - mem.zero(new_region, new_size - old_size) - } + + // NOTE: heap_resize does not zero the new memory, so we do it + if new_size > old_size { + new_region := mem.raw_data(new_memory[old_size:]) + mem.zero(new_region, new_size - old_size) } return } From 3d7d3471924574beee08fc304a6daf6a8707d723 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Jan 2022 19:56:05 +0000 Subject: [PATCH 0025/1052] Convert `ODIN_OS` and `ODIN_ARCH` to use enums rather than use strings --- core/c/c.odin | 8 ++-- core/c/libc/complex.odin | 4 +- core/c/libc/ctype.odin | 4 +- core/c/libc/errno.odin | 10 ++--- core/c/libc/math.odin | 4 +- core/c/libc/setjmp.odin | 6 +-- core/c/libc/signal.odin | 10 ++--- core/c/libc/stdio.odin | 10 ++--- core/c/libc/stdlib.odin | 10 ++--- core/c/libc/string.odin | 4 +- core/c/libc/threads.odin | 6 +-- core/c/libc/time.odin | 8 ++-- core/c/libc/uchar.odin | 4 +- core/c/libc/wchar.odin | 4 +- core/c/libc/wctype.odin | 10 ++--- core/crypto/_fiat/field_poly1305/field.odin | 2 +- core/crypto/chacha20/chacha20.odin | 2 +- core/crypto/rand_generic.odin | 2 +- core/image/png/example.odin | 2 +- core/image/png/helpers.odin | 2 +- core/os/file_windows.odin | 2 +- core/os/os.odin | 2 +- core/os/os2/user.odin | 16 ++++---- core/os/os_darwin.odin | 2 +- core/os/os_linux.odin | 26 ++++++------- core/os/stream.odin | 6 +-- core/path/filepath/match.odin | 10 ++--- core/path/filepath/path.odin | 4 +- core/path/filepath/path_unix.odin | 4 +- core/runtime/core.odin | 2 +- core/runtime/default_allocators_nil.odin | 2 +- core/runtime/default_temporary_allocator.odin | 2 +- core/runtime/entry_windows.odin | 2 +- core/runtime/error_checks.odin | 4 +- core/runtime/internal.odin | 2 +- core/runtime/procs.odin | 4 +- core/sync/sync2/primitives.odin | 2 +- core/sync/sync2/primitives_internal.odin | 2 +- core/sys/unix/syscalls_linux.odin | 8 ++-- core/time/time_unix.odin | 2 +- src/checker.cpp | 37 +++++++++++++++++-- vendor/ENet/enet.odin | 4 +- vendor/OpenGL/helpers.odin | 2 +- vendor/botan/bindings/botan.odin | 6 +-- vendor/glfw/bindings/bindings.odin | 6 +-- vendor/glfw/native.odin | 6 +-- vendor/miniaudio/common.odin | 6 +-- vendor/miniaudio/data_conversion.odin | 4 +- vendor/miniaudio/decoding.odin | 4 +- vendor/miniaudio/device_io_procs.odin | 4 +- vendor/miniaudio/device_io_types.odin | 32 ++++++++-------- vendor/miniaudio/encoding.odin | 4 +- vendor/miniaudio/filtering.odin | 4 +- vendor/miniaudio/generation.odin | 4 +- vendor/miniaudio/logging.odin | 4 +- vendor/miniaudio/utilities.odin | 4 +- vendor/miniaudio/vfs.odin | 4 +- vendor/portmidi/portmidi.odin | 2 +- vendor/portmidi/util.odin | 2 +- vendor/raylib/raylib.odin | 6 +-- vendor/raylib/rlgl.odin | 6 +-- vendor/sdl2/image/sdl_image.odin | 8 ++-- vendor/sdl2/mixer/sdl_mixer.odin | 8 ++-- vendor/sdl2/net/sdl_net.odin | 8 ++-- vendor/sdl2/sdl2.odin | 8 ++-- vendor/sdl2/sdl_audio.odin | 8 ++-- vendor/sdl2/sdl_blendmode.odin | 8 ++-- vendor/sdl2/sdl_cpuinfo.odin | 8 ++-- vendor/sdl2/sdl_events.odin | 8 ++-- vendor/sdl2/sdl_gamecontroller.odin | 8 ++-- vendor/sdl2/sdl_gesture_haptic.odin | 8 ++-- vendor/sdl2/sdl_hints.odin | 8 ++-- vendor/sdl2/sdl_joystick.odin | 8 ++-- vendor/sdl2/sdl_keyboard.odin | 8 ++-- vendor/sdl2/sdl_log.odin | 8 ++-- vendor/sdl2/sdl_messagebox.odin | 8 ++-- vendor/sdl2/sdl_metal.odin | 8 ++-- vendor/sdl2/sdl_mouse.odin | 8 ++-- vendor/sdl2/sdl_mutex.odin | 8 ++-- vendor/sdl2/sdl_pixels.odin | 8 ++-- vendor/sdl2/sdl_rect.odin | 8 ++-- vendor/sdl2/sdl_render.odin | 8 ++-- vendor/sdl2/sdl_rwops.odin | 8 ++-- vendor/sdl2/sdl_stdinc.odin | 8 ++-- vendor/sdl2/sdl_surface.odin | 8 ++-- vendor/sdl2/sdl_system.odin | 8 ++-- vendor/sdl2/sdl_syswm.odin | 8 ++-- vendor/sdl2/sdl_thread.odin | 8 ++-- vendor/sdl2/sdl_timer.odin | 8 ++-- vendor/sdl2/sdl_touch.odin | 8 ++-- vendor/sdl2/sdl_video.odin | 8 ++-- vendor/sdl2/sdl_vulkan.odin | 8 ++-- vendor/sdl2/ttf/sdl_ttf.odin | 8 ++-- vendor/stb/image/stb_image.odin | 4 +- vendor/stb/image/stb_image_resize.odin | 4 +- vendor/stb/image/stb_image_write.odin | 4 +- vendor/stb/rect_pack/stb_rect_pack.odin | 4 +- vendor/stb/truetype/stb_truetype.odin | 4 +- vendor/stb/vorbis/stb_vorbis.odin | 4 +- .../vulkan/_gen/create_vulkan_odin_wrapper.py | 2 +- vendor/vulkan/structs.odin | 2 +- 101 files changed, 341 insertions(+), 310 deletions(-) diff --git a/core/c/c.odin b/core/c/c.odin index d0b8e377f..05732476f 100644 --- a/core/c/c.odin +++ b/core/c/c.odin @@ -7,20 +7,20 @@ char :: builtin.u8 // assuming -funsigned-char schar :: builtin.i8 short :: builtin.i16 int :: builtin.i32 -long :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64 +long :: builtin.i32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.i64 longlong :: builtin.i64 uchar :: builtin.u8 ushort :: builtin.u16 uint :: builtin.u32 -ulong :: builtin.u32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.u64 +ulong :: builtin.u32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.u64 ulonglong :: builtin.u64 bool :: builtin.bool size_t :: builtin.uint ssize_t :: builtin.int -wchar_t :: builtin.u16 when (ODIN_OS == "windows") else builtin.u32 +wchar_t :: builtin.u16 when (ODIN_OS == .Windows) else builtin.u32 float :: builtin.f32 double :: builtin.f64 @@ -48,7 +48,7 @@ int_least64_t :: builtin.i64 uint_least64_t :: builtin.u64 // Same on Windows, Linux, and FreeBSD -when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { +when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 { int_fast8_t :: builtin.i8 uint_fast8_t :: builtin.u8 int_fast16_t :: builtin.i32 diff --git a/core/c/libc/complex.odin b/core/c/libc/complex.odin index 62b28f0cd..22c422cce 100644 --- a/core/c/libc/complex.odin +++ b/core/c/libc/complex.odin @@ -2,9 +2,9 @@ package libc // 7.3 Complex arithmetic -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" diff --git a/core/c/libc/ctype.odin b/core/c/libc/ctype.odin index 05d9dcd37..185385a5e 100644 --- a/core/c/libc/ctype.odin +++ b/core/c/libc/ctype.odin @@ -1,8 +1,8 @@ package libc -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin index 8ebe2f734..ecde6af59 100644 --- a/core/c/libc/errno.odin +++ b/core/c/libc/errno.odin @@ -2,9 +2,9 @@ package libc // 7.5 Errors -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" @@ -14,7 +14,7 @@ when ODIN_OS == "windows" { // EDOM, // EILSEQ // ERANGE -when ODIN_OS == "linux" || ODIN_OS == "freebsd" { +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD { @(private="file") @(default_calling_convention="c") foreign libc { @@ -27,7 +27,7 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" { ERANGE :: 34 } -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { @(private="file") @(default_calling_convention="c") foreign libc { @@ -40,7 +40,7 @@ when ODIN_OS == "windows" { ERANGE :: 34 } -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { @(private="file") @(default_calling_convention="c") foreign libc { diff --git a/core/c/libc/math.odin b/core/c/libc/math.odin index ee702b82e..97f77236f 100644 --- a/core/c/libc/math.odin +++ b/core/c/libc/math.odin @@ -4,9 +4,9 @@ package libc import "core:intrinsics" -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" diff --git a/core/c/libc/setjmp.odin b/core/c/libc/setjmp.odin index dcd4a9c64..c2cd1d047 100644 --- a/core/c/libc/setjmp.odin +++ b/core/c/libc/setjmp.odin @@ -2,14 +2,14 @@ package libc // 7.13 Nonlocal jumps -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" } -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { @(default_calling_convention="c") foreign libc { // 7.13.1 Save calling environment diff --git a/core/c/libc/signal.odin b/core/c/libc/signal.odin index e1044dc02..186b74d8c 100644 --- a/core/c/libc/signal.odin +++ b/core/c/libc/signal.odin @@ -2,9 +2,9 @@ package libc // 7.14 Signal handling -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" @@ -21,7 +21,7 @@ foreign libc { raise :: proc(sig: int) -> int --- } -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { SIG_ERR :: rawptr(~uintptr(0)) SIG_DFL :: rawptr(uintptr(0)) SIG_IGN :: rawptr(uintptr(1)) @@ -34,7 +34,7 @@ when ODIN_OS == "windows" { SIGTERM :: 15 } -when ODIN_OS == "linux" || ODIN_OS == "freebsd" { +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD { SIG_ERR :: rawptr(~uintptr(0)) SIG_DFL :: rawptr(uintptr(0)) SIG_IGN :: rawptr(uintptr(1)) @@ -47,7 +47,7 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" { SIGTERM :: 15 } -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { SIG_ERR :: rawptr(~uintptr(0)) SIG_DFL :: rawptr(uintptr(0)) SIG_IGN :: rawptr(uintptr(1)) diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index 4a39c22e9..33be34625 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -1,8 +1,8 @@ package libc -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" @@ -13,7 +13,7 @@ when ODIN_OS == "windows" { FILE :: struct {} // MSVCRT compatible. -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { _IOFBF :: 0x0000 _IONBF :: 0x0004 _IOLBF :: 0x0040 @@ -48,7 +48,7 @@ when ODIN_OS == "windows" { } // GLIBC and MUSL compatible. -when ODIN_OS == "linux" { +when ODIN_OS == .Linux { fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, } _IOFBF :: 0 @@ -78,7 +78,7 @@ when ODIN_OS == "linux" { } } -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { fpos_t :: distinct i64 _IOFBF :: 0 diff --git a/core/c/libc/stdlib.odin b/core/c/libc/stdlib.odin index b368c0cee..a278db0ef 100644 --- a/core/c/libc/stdlib.odin +++ b/core/c/libc/stdlib.odin @@ -2,15 +2,15 @@ package libc // 7.22 General utilities -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" } -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { RAND_MAX :: 0x7fff @(private="file") @@ -24,7 +24,7 @@ when ODIN_OS == "windows" { } } -when ODIN_OS == "linux" { +when ODIN_OS == .Linux { RAND_MAX :: 0x7fffffff // GLIBC and MUSL only @@ -40,7 +40,7 @@ when ODIN_OS == "linux" { } -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { RAND_MAX :: 0x7fffffff // GLIBC and MUSL only diff --git a/core/c/libc/string.odin b/core/c/libc/string.odin index c91124dcb..8f83ee1b9 100644 --- a/core/c/libc/string.odin +++ b/core/c/libc/string.odin @@ -4,9 +4,9 @@ import "core:runtime" // 7.24 String handling -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" diff --git a/core/c/libc/threads.odin b/core/c/libc/threads.odin index ad305b517..a7a45150d 100644 --- a/core/c/libc/threads.odin +++ b/core/c/libc/threads.odin @@ -5,7 +5,7 @@ package libc thrd_start_t :: proc "c" (rawptr) -> int tss_dtor_t :: proc "c" (rawptr) -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc { "system:libucrt.lib", "system:msvcprt.lib" @@ -74,7 +74,7 @@ when ODIN_OS == "windows" { } // GLIBC and MUSL compatible constants and types. -when ODIN_OS == "linux" { +when ODIN_OS == .Linux { foreign import libc { "system:c", "system:pthread" @@ -138,6 +138,6 @@ when ODIN_OS == "linux" { } -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { // TODO: find out what this is meant to be! } diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin index 96e80e216..b3539a227 100644 --- a/core/c/libc/time.odin +++ b/core/c/libc/time.odin @@ -2,9 +2,9 @@ package libc // 7.27 Date and time -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" @@ -12,7 +12,7 @@ when ODIN_OS == "windows" { // We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as // we approach the 2038 problem. Windows has defaulted to this since VC8 (2005). -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign libc { // 7.27.2 Time manipulation functions clock :: proc() -> clock_t --- @@ -45,7 +45,7 @@ when ODIN_OS == "windows" { } } -when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" { +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin { @(default_calling_convention="c") foreign libc { // 7.27.2 Time manipulation functions diff --git a/core/c/libc/uchar.odin b/core/c/libc/uchar.odin index e49c29e51..a10969ceb 100644 --- a/core/c/libc/uchar.odin +++ b/core/c/libc/uchar.odin @@ -2,9 +2,9 @@ package libc // 7.28 Unicode utilities -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" diff --git a/core/c/libc/wchar.odin b/core/c/libc/wchar.odin index fc206e494..f2aa8410e 100644 --- a/core/c/libc/wchar.odin +++ b/core/c/libc/wchar.odin @@ -2,9 +2,9 @@ package libc // 7.29 Extended multibyte and wide character utilities -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin index 47f17e0b4..942726ba6 100644 --- a/core/c/libc/wctype.odin +++ b/core/c/libc/wctype.odin @@ -2,25 +2,25 @@ package libc // 7.30 Wide character classification and mapping utilities -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import libc "system:System.framework" } else { foreign import libc "system:c" } -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { wctrans_t :: distinct wchar_t wctype_t :: distinct ushort } -when ODIN_OS == "linux" { +when ODIN_OS == .Linux { wctrans_t :: distinct intptr_t wctype_t :: distinct ulong } -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { wctrans_t :: distinct int wctype_t :: distinct u32 } diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index 4ed8acbff..ca458e079 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -22,7 +22,7 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a assert(len(arg1) == 16) - when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { + when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 { // While it may be unwise to do deserialization here on our // own when fiat-crypto provides equivalent functionality, // doing it this way provides a little under 3x performance diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin index e32dacb2c..229949c22 100644 --- a/core/crypto/chacha20/chacha20.odin +++ b/core/crypto/chacha20/chacha20.odin @@ -346,7 +346,7 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) { // Until dedicated assembly can be written leverage the fact that // the callers of this routine ensure that src/dst are valid. - when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { + when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 { // util.PUT_U32_LE/util.U32_LE are not required on little-endian // systems that also happen to not be strict about aligned // memory access. diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin index 98890b5b1..be6987ee2 100644 --- a/core/crypto/rand_generic.odin +++ b/core/crypto/rand_generic.odin @@ -1,6 +1,6 @@ package crypto -when ODIN_OS != "linux" { +when ODIN_OS != .Linux { _rand_bytes :: proc (dst: []byte) { unimplemented("crypto: rand_bytes not supported on this OS") } diff --git a/core/image/png/example.odin b/core/image/png/example.odin index f4eb5128e..17436c260 100644 --- a/core/image/png/example.odin +++ b/core/image/png/example.odin @@ -207,7 +207,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b } mode: int = 0 - when ODIN_OS == "linux" || ODIN_OS == "darwin" { + when ODIN_OS == .Linux || ODIN_OS == .Darwin { // NOTE(justasd): 644 (owner read, write; group read; others read) mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH } diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index ecc0183bc..6ec674544 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -443,7 +443,7 @@ when false { } mode: int = 0 - when ODIN_OS == "linux" || ODIN_OS == "darwin" { + when ODIN_OS == .Linux || ODIN_OS == .Darwin { // NOTE(justasd): 644 (owner read, write; group read; others read) mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH } diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 419f8bbc2..8a0f2ed64 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -399,7 +399,7 @@ is_abs :: proc(path: string) -> bool { if len(path) > 0 && path[0] == '/' { return true } - when ODIN_OS == "windows" { + when ODIN_OS == .Windows { if len(path) > 2 { switch path[0] { case 'A'..='Z', 'a'..='z': diff --git a/core/os/os.odin b/core/os/os.odin index 83158be80..19a8099ef 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -139,7 +139,7 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ } mode: int = 0 - when OS == "linux" || OS == "darwin" { + when OS == .Linux || OS == .Darwin { // NOTE(justasd): 644 (owner read, write; group read; others read) mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH } diff --git a/core/os/os2/user.odin b/core/os/os2/user.odin index 6dd99c621..976e61bb1 100644 --- a/core/os/os2/user.odin +++ b/core/os/os2/user.odin @@ -3,13 +3,13 @@ package os2 import "core:strings" user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) { - switch ODIN_OS { - case "windows": + #partial switch ODIN_OS { + case .Windows: dir = get_env("LocalAppData") if dir != "" { dir = strings.clone(dir, allocator) } - case "darwin": + case .Darwin: dir = get_env("HOME") if dir != "" { dir = strings.concatenate({dir, "/Library/Caches"}, allocator) @@ -29,13 +29,13 @@ user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defin } user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) { - switch ODIN_OS { - case "windows": + #partial switch ODIN_OS { + case .Windows: dir = get_env("AppData") if dir != "" { dir = strings.clone(dir, allocator) } - case "darwin": + case .Darwin: dir = get_env("HOME") if dir != "" { dir = strings.concatenate({dir, "/Library/Application Support"}, allocator) @@ -56,8 +56,8 @@ user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defi user_home_dir :: proc() -> (dir: string, is_defined: bool) { env := "HOME" - switch ODIN_OS { - case "windows": + #partial switch ODIN_OS { + case .Windows: env = "USERPROFILE" } if v := get_env(env); v != "" { diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index b32453a5d..4828c5167 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -335,7 +335,7 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno return INVALID_HANDLE, 1 } -when ODIN_OS == "darwin" && ODIN_ARCH == "arm64" { +when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 { if mode != 0 { err := fchmod(handle, cast(u16)mode) if err != 0 { diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 1c796f1b8..3eb76249c 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -271,7 +271,7 @@ AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) _unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open res := int(intrinsics.syscall(unix.SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) @@ -292,7 +292,7 @@ _unix_write :: proc(fd: Handle, buf: rawptr, size: uint) -> int { } _unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 { - when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) } else { low := uintptr(offset & 0xFFFFFFFF) @@ -304,9 +304,9 @@ _unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 { } _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int { - when ODIN_ARCH == "amd64" { + when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != "arm64" { + } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have stat return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0)) @@ -314,7 +314,7 @@ _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int { } _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int { - when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat))) } else { return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat))) @@ -322,9 +322,9 @@ _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int { } _unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int { - when ODIN_ARCH == "amd64" { + when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != "arm64" { + } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have any lstat return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) @@ -332,7 +332,7 @@ _unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int { } _unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } else { // NOTE: arm64 does not have readlink return int(intrinsics.syscall(unix.SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) @@ -340,7 +340,7 @@ _unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { } _unix_access :: proc(path: cstring, mask: int) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask))) } else { // NOTE: arm64 does not have access return int(intrinsics.syscall(unix.SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask))) @@ -356,7 +356,7 @@ _unix_chdir :: proc(path: cstring) -> int { } _unix_rename :: proc(old, new: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) } else { // NOTE: arm64 does not have rename return int(intrinsics.syscall(unix.SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new)))) @@ -364,7 +364,7 @@ _unix_rename :: proc(old, new: cstring) -> int { } _unix_unlink :: proc(path: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have unlink return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0))) @@ -372,7 +372,7 @@ _unix_unlink :: proc(path: cstring) -> int { } _unix_rmdir :: proc(path: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have rmdir return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR)) @@ -380,7 +380,7 @@ _unix_rmdir :: proc(path: cstring) -> int { } _unix_mkdir :: proc(path: cstring, mode: u32) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir return int(intrinsics.syscall(unix.SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) diff --git a/core/os/stream.odin b/core/os/stream.odin index 5cf5c8405..2c6e1d47f 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -19,7 +19,7 @@ _file_stream_vtable := &io.Stream_VTable{ return }, impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - when ODIN_OS == "windows" || ODIN_OS == "wasi" { + when ODIN_OS == .Windows || ODIN_OS == .WASI { fd := Handle(uintptr(s.stream_data)) os_err: Errno n, os_err = read_at(fd, p, offset) @@ -33,7 +33,7 @@ _file_stream_vtable := &io.Stream_VTable{ return }, impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - when ODIN_OS == "windows" || ODIN_OS == "wasi" { + when ODIN_OS == .Windows || ODIN_OS == .WASI { fd := Handle(uintptr(s.stream_data)) os_err: Errno n, os_err = write_at(fd, p, offset) @@ -53,7 +53,7 @@ _file_stream_vtable := &io.Stream_VTable{ return sz }, impl_flush = proc(s: io.Stream) -> io.Error { - when ODIN_OS == "windows" { + when ODIN_OS == .Windows { fd := Handle(uintptr(s.stream_data)) flush(fd) } else { diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin index cba44953d..c045f3ece 100644 --- a/core/path/filepath/match.odin +++ b/core/path/filepath/match.odin @@ -89,7 +89,7 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) { scan_loop: for i = 0; i < len(pattern); i += 1 { switch pattern[i] { case '\\': - when ODIN_OS != "windows" { + when ODIN_OS != .Windows { if i+1 < len(pattern) { i += 1 } @@ -161,7 +161,7 @@ match_chunk :: proc(chunk, s: string) -> (rest: string, ok: bool, err: Match_Err chunk = chunk[1:] case '\\': - when ODIN_OS != "windows" { + when ODIN_OS != .Windows { chunk = chunk[1:] if len(chunk) == 0 { err = .Syntax_Error @@ -188,7 +188,7 @@ get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Match_Er return } chunk := chunk - if chunk[0] == '\\' && ODIN_OS != "windows" { + if chunk[0] == '\\' && ODIN_OS != .Windows { chunk = chunk[1:] if len(chunk) == 0 { err = .Syntax_Error @@ -231,7 +231,7 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str dir, file := split(pattern) volume_len := 0 - when ODIN_OS == "windows" { + when ODIN_OS == .Windows { volume_len, dir = clean_glob_path_windows(dir, temp_buf[:]) } else { dir = clean_glob_path(dir) @@ -308,7 +308,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s @(private) has_meta :: proc(path: string) -> bool { - when ODIN_OS == "windows" { + when ODIN_OS == .Windows { CHARS :: `*?[` } else { CHARS :: `*?[\` diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin index 39cd80a47..d6e36f649 100644 --- a/core/path/filepath/path.odin +++ b/core/path/filepath/path.odin @@ -8,7 +8,7 @@ import "core:strings" is_separator :: proc(c: byte) -> bool { switch c { case '/': return true - case '\\': return ODIN_OS == "windows" + case '\\': return ODIN_OS == .Windows } return false } @@ -32,7 +32,7 @@ volume_name :: proc(path: string) -> string { } volume_name_len :: proc(path: string) -> int { - if ODIN_OS == "windows" { + if ODIN_OS == .Windows { if len(path) < 2 { return 0 } diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin index 1db528a2f..3e49c4710 100644 --- a/core/path/filepath/path_unix.odin +++ b/core/path/filepath/path_unix.odin @@ -1,7 +1,7 @@ //+build linux, darwin, freebsd package filepath -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { foreign import libc "System.framework" } else { foreign import libc "system:c" @@ -54,7 +54,7 @@ foreign libc { @(link_name="free") _unix_free :: proc(ptr: rawptr) --- } -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { @(private) foreign libc { @(link_name="__error") __error :: proc() -> ^i32 --- diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 424650828..cd76b0bb5 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -539,7 +539,7 @@ __init_context :: proc "contextless" (c: ^Context) { } default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! { - when ODIN_OS == "freestanding" { + when ODIN_OS == .Freestanding { // Do nothing } else { print_caller_location(loc) diff --git a/core/runtime/default_allocators_nil.odin b/core/runtime/default_allocators_nil.odin index ccb4a3381..04dea0e19 100644 --- a/core/runtime/default_allocators_nil.odin +++ b/core/runtime/default_allocators_nil.odin @@ -32,7 +32,7 @@ nil_allocator :: proc() -> Allocator { -when ODIN_OS == "freestanding" { +when ODIN_OS == .Freestanding { default_allocator_proc :: nil_allocator_proc default_allocator :: nil_allocator } \ No newline at end of file diff --git a/core/runtime/default_temporary_allocator.odin b/core/runtime/default_temporary_allocator.odin index 01143e222..4337e555b 100644 --- a/core/runtime/default_temporary_allocator.odin +++ b/core/runtime/default_temporary_allocator.odin @@ -3,7 +3,7 @@ package runtime DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22) -when ODIN_OS == "freestanding" || ODIN_OS == "js" || ODIN_DEFAULT_TO_NIL_ALLOCATOR { +when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR { Default_Temp_Allocator :: struct {} default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {} diff --git a/core/runtime/entry_windows.odin b/core/runtime/entry_windows.odin index 35a6bb421..2f323cb41 100644 --- a/core/runtime/entry_windows.odin +++ b/core/runtime/entry_windows.odin @@ -22,7 +22,7 @@ when ODIN_BUILD_MODE == .Dynamic { return true } } else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT { - when ODIN_ARCH == "i386" || ODIN_NO_CRT { + when ODIN_ARCH == .i386 || ODIN_NO_CRT { @(link_name="mainCRTStartup", linkage="strong", require) mainCRTStartup :: proc "stdcall" () -> i32 { context = default_context() diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index 7f1aeb2d7..ed75cbea6 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -1,7 +1,7 @@ package runtime bounds_trap :: proc "contextless" () -> ! { - when ODIN_OS == "windows" { + when ODIN_OS == .Windows { windows_trap_array_bounds() } else { trap() @@ -9,7 +9,7 @@ bounds_trap :: proc "contextless" () -> ! { } type_assertion_trap :: proc "contextless" () -> ! { - when ODIN_OS == "windows" { + when ODIN_OS == .Windows { windows_trap_type_assertion() } else { trap() diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 7b283a132..0d0e196c4 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -3,7 +3,7 @@ package runtime import "core:intrinsics" @(private="file") -IS_WASM :: ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" +IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64 @(private) RUNTIME_LINKAGE :: "strong" when ( diff --git a/core/runtime/procs.odin b/core/runtime/procs.odin index 961f6376f..5a1d11fe0 100644 --- a/core/runtime/procs.odin +++ b/core/runtime/procs.odin @@ -1,6 +1,6 @@ package runtime -when ODIN_NO_CRT && ODIN_OS == "windows" { +when ODIN_NO_CRT && ODIN_OS == .Windows { foreign import lib "system:NtDll.lib" @(private="file") @@ -25,7 +25,7 @@ when ODIN_NO_CRT && ODIN_OS == "windows" { RtlMoveMemory(dst, src, len) return dst } -} else when ODIN_NO_CRT || (ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64") { +} else when ODIN_NO_CRT || (ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64) { @(link_name="memset", linkage="strong", require) memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr { if ptr != nil && len != 0 { diff --git a/core/sync/sync2/primitives.odin b/core/sync/sync2/primitives.odin index 6d056d439..046ecbc35 100644 --- a/core/sync/sync2/primitives.odin +++ b/core/sync/sync2/primitives.odin @@ -11,7 +11,7 @@ current_thread_id :: proc "contextless" () -> int { // // A Mutex must not be copied after first use Mutex :: struct { - impl: _Mutex, + impl: _Mutex `This is a tag`, } // mutex_lock locks m diff --git a/core/sync/sync2/primitives_internal.odin b/core/sync/sync2/primitives_internal.odin index ae7e2599c..eb692c6ae 100644 --- a/core/sync/sync2/primitives_internal.odin +++ b/core/sync/sync2/primitives_internal.odin @@ -93,7 +93,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { } -when ODIN_OS != "windows" { +when ODIN_OS != .Windows { RW_Mutex_State :: distinct uint RW_Mutex_State_Half_Width :: size_of(RW_Mutex_State)*8/2 RW_Mutex_State_Is_Writing :: RW_Mutex_State(1) diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 3dc3d2c74..0082c7261 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -15,7 +15,7 @@ import "core:intrinsics" // 386: arch/x86/entry/syscalls/sycall_32.tbl // arm: arch/arm/tools/syscall.tbl -when ODIN_ARCH == "amd64" { +when ODIN_ARCH == .amd64 { SYS_read : uintptr : 0 SYS_write : uintptr : 1 SYS_open : uintptr : 2 @@ -374,7 +374,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when ODIN_ARCH == "arm64" { +} else when ODIN_ARCH == .arm64 { SYS_io_setup : uintptr : 0 SYS_io_destroy : uintptr : 1 SYS_io_submit : uintptr : 2 @@ -675,7 +675,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 -} else when ODIN_ARCH == "i386" { +} else when ODIN_ARCH == .i386 { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 @@ -1112,7 +1112,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when ODIN_ARCH == "arm" { +} else when false /*ODIN_ARCH == .arm*/ { // TODO SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin index 0d765b72d..9c5c5cc35 100644 --- a/core/time/time_unix.odin +++ b/core/time/time_unix.odin @@ -3,7 +3,7 @@ package time IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC. -when ODIN_OS == "darwin" { +when ODIN_OS == .Darwin { foreign import libc "System.framework" } else { foreign import libc "system:c" diff --git a/src/checker.cpp b/src/checker.cpp index 63a697072..055d0d356 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -856,11 +856,42 @@ void init_universal(void) { add_global_bool_constant("false", false); // TODO(bill): Set through flags in the compiler - add_global_string_constant("ODIN_OS", bc->ODIN_OS); - add_global_string_constant("ODIN_ARCH", bc->ODIN_ARCH); add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR); add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION); add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT); + + { + GlobalEnumValue values[TargetOs_COUNT] = { + {"Unknown", TargetOs_Invalid}, + {"Windows", TargetOs_windows}, + {"Darwin", TargetOs_darwin}, + {"Linux", TargetOs_linux}, + {"Essence", TargetOs_essence}, + {"FreeBSD", TargetOs_freebsd}, + {"WASI", TargetOs_wasi}, + {"JS", TargetOs_js}, + {"Freestanding", TargetOs_freestanding}, + }; + + auto fields = add_global_enum_type(str_lit("Odin_OS_Type"), values, gb_count_of(values)); + add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os); + add_global_string_constant("ODIN_OS_STRING", target_os_names[bc->metrics.os]); + } + + { + GlobalEnumValue values[TargetArch_COUNT] = { + {"Unknown", TargetArch_Invalid}, + {"amd64", TargetArch_amd64}, + {"i386", TargetArch_i386}, + {"arm64", TargetArch_arm64}, + {"wasm32", TargetArch_wasm32}, + {"wasm64", TargetArch_wasm64}, + }; + + auto fields = add_global_enum_type(str_lit("Odin_Arch_Type"), values, gb_count_of(values)); + add_global_enum_constant(fields, "ODIN_ARCH", bc->metrics.arch); + add_global_string_constant("ODIN_ARCH_STRING", target_arch_names[bc->metrics.arch]); + } { GlobalEnumValue values[BuildMode_COUNT] = { @@ -875,7 +906,6 @@ void init_universal(void) { add_global_enum_constant(fields, "ODIN_BUILD_MODE", bc->build_mode); } - add_global_string_constant("ODIN_ENDIAN_STRING", target_endian_names[target_endians[bc->metrics.arch]]); { GlobalEnumValue values[TargetEndian_COUNT] = { {"Unknown", TargetEndian_Invalid}, @@ -886,6 +916,7 @@ void init_universal(void) { auto fields = add_global_enum_type(str_lit("Odin_Endian_Type"), values, gb_count_of(values)); add_global_enum_constant(fields, "ODIN_ENDIAN", target_endians[bc->metrics.arch]); + add_global_string_constant("ODIN_ENDIAN_STRING", target_endian_names[target_endians[bc->metrics.arch]]); } diff --git a/vendor/ENet/enet.odin b/vendor/ENet/enet.odin index 8d068fbfc..37e65b497 100644 --- a/vendor/ENet/enet.odin +++ b/vendor/ENet/enet.odin @@ -1,7 +1,7 @@ package ENet -when ODIN_OS == "windows" { - when ODIN_ARCH == "amd64" { +when ODIN_OS == .Windows { + when ODIN_ARCH == .amd64 { foreign import ENet { "lib/enet64.lib", "system:Ws2_32.lib", diff --git a/vendor/OpenGL/helpers.odin b/vendor/OpenGL/helpers.odin index 0a9cffefa..661de318c 100644 --- a/vendor/OpenGL/helpers.odin +++ b/vendor/OpenGL/helpers.odin @@ -188,7 +188,7 @@ load_shaders_source :: proc(vs_source, fs_source: string, binary_retrievable := load_shaders :: proc{load_shaders_file} -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { update_shader_if_changed :: proc( vertex_name, fragment_name: string, program: u32, diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index d1d88cda0..fdddc99a9 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -136,11 +136,11 @@ totp_t :: ^totp_struct fpe_struct :: struct{} fpe_t :: ^fpe_struct -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import botan_lib "botan.lib" -} else when ODIN_OS == "linux" { +} else when ODIN_OS == .Linux { foreign import botan_lib "system:botan-2" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import botan_lib "system:botan-2" } diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index 84905f603..f4e39015e 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -3,9 +3,9 @@ package glfw_bindings import "core:c" import vk "vendor:vulkan" -when ODIN_OS == "linux" { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux -when ODIN_OS == "darwin" { foreign import glfw "system:glfw" } -when ODIN_OS == "windows" { +when ODIN_OS == .Linux { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux +when ODIN_OS == .Darwin { foreign import glfw "system:glfw" } +when ODIN_OS == .Windows { foreign import glfw { "../lib/glfw3_mt.lib", "system:user32.lib", diff --git a/vendor/glfw/native.odin b/vendor/glfw/native.odin index 871c42af9..902b30656 100644 --- a/vendor/glfw/native.odin +++ b/vendor/glfw/native.odin @@ -1,6 +1,6 @@ package glfw -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { import win32 "core:sys/windows" foreign import glfw { "lib/glfw3.lib", "system:user32.lib", "system:gdi32.lib", "system:shell32.lib" } @@ -12,7 +12,7 @@ when ODIN_OS == "windows" { GetWin32Window :: proc(window: WindowHandle) -> win32.HWND --- GetWGLContext :: proc(window: WindowHandle) -> rawptr --- } -} else when ODIN_OS == "linux" { +} else when ODIN_OS == .Linux { // TODO: Native Linux // Display* glfwGetX11Display(void); // RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); @@ -24,7 +24,7 @@ when ODIN_OS == "windows" { // struct wl_display* glfwGetWaylandDisplay(void); // struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); // struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { // TODO: Native Darwin // CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); // id glfwGetCocoaWindow(GLFWwindow* window); diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index 62e32e8b1..75b66101f 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -2,8 +2,8 @@ package miniaudio import "core:c" -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } handle :: distinct rawptr @@ -270,7 +270,7 @@ thread_priority :: enum c.int { /* Spinlocks are 32-bit for compatibility reasons. */ spinlock :: distinct u32 -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { thread :: distinct rawptr mutex :: distinct rawptr event :: distinct rawptr diff --git a/vendor/miniaudio/data_conversion.odin b/vendor/miniaudio/data_conversion.odin index 1a5c9d265..8a53cc19e 100644 --- a/vendor/miniaudio/data_conversion.odin +++ b/vendor/miniaudio/data_conversion.odin @@ -2,8 +2,8 @@ package miniaudio import "core:c" -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } /************************************************************************************************************************************************************ diff --git a/vendor/miniaudio/decoding.odin b/vendor/miniaudio/decoding.odin index cdddd06fe..52b315f10 100644 --- a/vendor/miniaudio/decoding.odin +++ b/vendor/miniaudio/decoding.odin @@ -2,8 +2,8 @@ package miniaudio import "core:c" -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } diff --git a/vendor/miniaudio/device_io_procs.odin b/vendor/miniaudio/device_io_procs.odin index c9cfb7c04..8d6609186 100644 --- a/vendor/miniaudio/device_io_procs.odin +++ b/vendor/miniaudio/device_io_procs.odin @@ -1,7 +1,7 @@ package miniaudio -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } import "core:c" diff --git a/vendor/miniaudio/device_io_types.odin b/vendor/miniaudio/device_io_types.odin index 8f43b8640..7778e85cf 100644 --- a/vendor/miniaudio/device_io_types.odin +++ b/vendor/miniaudio/device_io_types.odin @@ -2,21 +2,21 @@ package miniaudio import "core:c" -SUPPORT_WASAPI :: ODIN_OS == "windows" -SUPPORT_DSOUND :: ODIN_OS == "windows" -SUPPORT_WINMM :: ODIN_OS == "windows" -SUPPORT_COREAUDIO :: ODIN_OS == "darwin" -SUPPORT_SNDIO :: ODIN_OS == "openbsd" -SUPPORT_AUDIO4 :: ODIN_OS == "openbsd" || ODIN_OS == "netbsd" -SUPPORT_OSS :: ODIN_OS == "freebsd" -SUPPORT_PULSEAUDIO :: ODIN_OS == "linux" -SUPPORT_ALSA :: ODIN_OS == "linux" -SUPPORT_JACK :: ODIN_OS == "windows" -SUPPORT_AAUDIO :: ODIN_OS == "android" -SUPPORT_OPENSL :: ODIN_OS == "android" -SUPPORT_WEBAUDIO :: ODIN_OS == "emscripten" +SUPPORT_WASAPI :: ODIN_OS == .Windows +SUPPORT_DSOUND :: ODIN_OS == .Windows +SUPPORT_WINMM :: ODIN_OS == .Windows +SUPPORT_COREAUDIO :: ODIN_OS == .Darwin +SUPPORT_SNDIO :: false // ODIN_OS == .OpenBSD +SUPPORT_AUDIO4 :: false // ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD +SUPPORT_OSS :: ODIN_OS == .FreeBSD +SUPPORT_PULSEAUDIO :: ODIN_OS == .Linux +SUPPORT_ALSA :: ODIN_OS == .Linux +SUPPORT_JACK :: ODIN_OS == .Windows +SUPPORT_AAUDIO :: false // ODIN_OS == .Android +SUPPORT_OPENSL :: false // ODIN_OS == .Android +SUPPORT_WEBAUDIO :: false // ODIN_OS == .Emscripten SUPPORT_CUSTOM :: true -SUPPORT_NULL :: ODIN_OS != "emscripten" +SUPPORT_NULL :: true // ODIN_OS != .Emscripten STATE_UNINITIALIZED :: 0 STATE_STOPPED :: 1 /* The device's default state after initialization. */ @@ -895,7 +895,7 @@ context_type :: struct { RegOpenKeyExA: proc "system" (), RegCloseKey: proc "system" (), RegQueryValueExA: proc "system" (), - } when ODIN_OS == "windows" else struct {}), + } when ODIN_OS == .Windows else struct {}), posix: (struct { pthreadSO: handle, @@ -914,7 +914,7 @@ context_type :: struct { pthread_attr_setschedpolicy: proc "system" (), pthread_attr_getschedparam: proc "system" (), pthread_attr_setschedparam: proc "system" (), - } when ODIN_OS != "windows" else struct {}), + } when ODIN_OS != .Windows else struct {}), _unused: c.int, }, diff --git a/vendor/miniaudio/encoding.odin b/vendor/miniaudio/encoding.odin index 866c19010..83f9d5252 100644 --- a/vendor/miniaudio/encoding.odin +++ b/vendor/miniaudio/encoding.odin @@ -2,8 +2,8 @@ package miniaudio import "core:c" -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } /************************************************************************************************************************************************************ diff --git a/vendor/miniaudio/filtering.odin b/vendor/miniaudio/filtering.odin index fec21f33d..4956da173 100644 --- a/vendor/miniaudio/filtering.odin +++ b/vendor/miniaudio/filtering.odin @@ -1,7 +1,7 @@ package miniaudio -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } /************************************************************************************************************************************************************** diff --git a/vendor/miniaudio/generation.odin b/vendor/miniaudio/generation.odin index c2009967c..c241f00b1 100644 --- a/vendor/miniaudio/generation.odin +++ b/vendor/miniaudio/generation.odin @@ -2,8 +2,8 @@ package miniaudio import "core:c" -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } waveform_type :: enum c.int { sine, diff --git a/vendor/miniaudio/logging.odin b/vendor/miniaudio/logging.odin index 54792bff9..35aa54bc9 100644 --- a/vendor/miniaudio/logging.odin +++ b/vendor/miniaudio/logging.odin @@ -2,8 +2,8 @@ package miniaudio import c "core:c/libc" -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } MAX_LOG_CALLBACKS :: 4 diff --git a/vendor/miniaudio/utilities.odin b/vendor/miniaudio/utilities.odin index 1a94550e4..19307a77d 100644 --- a/vendor/miniaudio/utilities.odin +++ b/vendor/miniaudio/utilities.odin @@ -1,7 +1,7 @@ package miniaudio -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } @(default_calling_convention="c", link_prefix="ma_") foreign lib { diff --git a/vendor/miniaudio/vfs.odin b/vendor/miniaudio/vfs.odin index fa18afb6b..547fbd265 100644 --- a/vendor/miniaudio/vfs.odin +++ b/vendor/miniaudio/vfs.odin @@ -2,8 +2,8 @@ package miniaudio import "core:c" -when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } +when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } /************************************************************************************************************************************************************ diff --git a/vendor/portmidi/portmidi.odin b/vendor/portmidi/portmidi.odin index 08f78150c..40fd18b8b 100644 --- a/vendor/portmidi/portmidi.odin +++ b/vendor/portmidi/portmidi.odin @@ -3,7 +3,7 @@ package portmidi import "core:c" import "core:strings" -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import lib { "portmidi_s.lib", "system:Winmm.lib", diff --git a/vendor/portmidi/util.odin b/vendor/portmidi/util.odin index d02142bd0..ca2e1f4ca 100644 --- a/vendor/portmidi/util.odin +++ b/vendor/portmidi/util.odin @@ -7,7 +7,7 @@ package portmidi import "core:c" -when ODIN_OS == "windows" { foreign import lib "portmidi_s.lib" } +when ODIN_OS == .Windows { foreign import lib "portmidi_s.lib" } Queue :: distinct rawptr diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index fb4d7dd92..0c8248683 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -91,7 +91,7 @@ MAX_TEXT_BUFFER_LENGTH :: #config(RAYLIB_MAX_TEXT_BUFFER_LENGTH, 1024) #assert(size_of(rune) == size_of(c.int)) -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import lib { "raylib.lib", "system:Winmm.lib", @@ -100,14 +100,14 @@ when ODIN_OS == "windows" { "system:Shell32.lib", } } -when ODIN_OS == "linux" { +when ODIN_OS == .Linux { foreign import lib { "linux/libraylib.a", "system:dl", "system:pthread", } } -when ODIN_OS == "darwin" { foreign import lib "macos/libraylib.a" } +when ODIN_OS == .Darwin { foreign import lib "macos/libraylib.a" } VERSION :: "4.0" diff --git a/vendor/raylib/rlgl.odin b/vendor/raylib/rlgl.odin index 8f91486c1..936a34765 100644 --- a/vendor/raylib/rlgl.odin +++ b/vendor/raylib/rlgl.odin @@ -2,7 +2,7 @@ package raylib import "core:c" -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import lib { "raylib.lib", "system:Winmm.lib", @@ -11,8 +11,8 @@ when ODIN_OS == "windows" { "system:Shell32.lib", } } -when ODIN_OS == "linux" { foreign import lib "linux/libraylib.a" } -when ODIN_OS == "darwin" { foreign import lib "macos/libraylib.a" } +when ODIN_OS == .Linux { foreign import lib "linux/libraylib.a" } +when ODIN_OS == .Darwin { foreign import lib "macos/libraylib.a" } GRAPHICS_API_OPENGL_11 :: false GRAPHICS_API_OPENGL_21 :: true diff --git a/vendor/sdl2/image/sdl_image.odin b/vendor/sdl2/image/sdl_image.odin index 1dbe048ed..30a7db6a8 100644 --- a/vendor/sdl2/image/sdl_image.odin +++ b/vendor/sdl2/image/sdl_image.odin @@ -3,10 +3,10 @@ package sdl2_image import "core:c" import SDL ".." -when ODIN_OS == "windows" { foreign import lib "SDL2_image.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2_image" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2_image" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2_image" } +when ODIN_OS == .Windows { foreign import lib "SDL2_image.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2_image" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2_image" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_image" } bool :: SDL.bool diff --git a/vendor/sdl2/mixer/sdl_mixer.odin b/vendor/sdl2/mixer/sdl_mixer.odin index 90334d91a..7fa3f216f 100644 --- a/vendor/sdl2/mixer/sdl_mixer.odin +++ b/vendor/sdl2/mixer/sdl_mixer.odin @@ -3,10 +3,10 @@ package sdl2_mixer import "core:c" import SDL ".." -when ODIN_OS == "windows" { foreign import lib "SDL2_mixer.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2_mixer" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2_mixer" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2_mixer" } +when ODIN_OS == .Windows { foreign import lib "SDL2_mixer.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2_mixer" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2_mixer" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_mixer" } MAJOR_VERSION :: 2 diff --git a/vendor/sdl2/net/sdl_net.odin b/vendor/sdl2/net/sdl_net.odin index 49671764a..b3e2c2e62 100644 --- a/vendor/sdl2/net/sdl_net.odin +++ b/vendor/sdl2/net/sdl_net.odin @@ -3,10 +3,10 @@ package sdl2_net import "core:c" import SDL ".." -when ODIN_OS == "windows" { foreign import lib "SDL2_net.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2_net" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2_net" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2_net" } +when ODIN_OS == .Windows { foreign import lib "SDL2_net.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2_net" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2_net" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_net" } bool :: SDL.bool diff --git a/vendor/sdl2/sdl2.odin b/vendor/sdl2/sdl2.odin index 4781483f7..e36c002dd 100644 --- a/vendor/sdl2/sdl2.odin +++ b/vendor/sdl2/sdl2.odin @@ -25,10 +25,10 @@ package sdl2 import "core:c" import "core:intrinsics" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } version :: struct { major: u8, /**< major version */ diff --git a/vendor/sdl2/sdl_audio.odin b/vendor/sdl2/sdl_audio.odin index 2c5b7fedb..a03031165 100644 --- a/vendor/sdl2/sdl_audio.odin +++ b/vendor/sdl2/sdl_audio.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } /** * \brief Audio format flags. diff --git a/vendor/sdl2/sdl_blendmode.odin b/vendor/sdl2/sdl_blendmode.odin index 3fb7c2e83..525cf0f38 100644 --- a/vendor/sdl2/sdl_blendmode.odin +++ b/vendor/sdl2/sdl_blendmode.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } /** * \brief The blend mode used in SDL_RenderCopy() and drawing operations. diff --git a/vendor/sdl2/sdl_cpuinfo.odin b/vendor/sdl2/sdl_cpuinfo.odin index 5fe5cf16c..7d2e681fe 100644 --- a/vendor/sdl2/sdl_cpuinfo.odin +++ b/vendor/sdl2/sdl_cpuinfo.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } /* This is a guess for the cacheline size used for padding. * Most x86 processors have a 64 byte cache line. diff --git a/vendor/sdl2/sdl_events.odin b/vendor/sdl2/sdl_events.odin index 535269656..3f58b51c3 100644 --- a/vendor/sdl2/sdl_events.odin +++ b/vendor/sdl2/sdl_events.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } RELEASED :: 0 PRESSED :: 1 diff --git a/vendor/sdl2/sdl_gamecontroller.odin b/vendor/sdl2/sdl_gamecontroller.odin index 747cd1af6..9fef6b1ab 100644 --- a/vendor/sdl2/sdl_gamecontroller.odin +++ b/vendor/sdl2/sdl_gamecontroller.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } GameController :: struct {} diff --git a/vendor/sdl2/sdl_gesture_haptic.odin b/vendor/sdl2/sdl_gesture_haptic.odin index 0d257a525..1c8616e99 100644 --- a/vendor/sdl2/sdl_gesture_haptic.odin +++ b/vendor/sdl2/sdl_gesture_haptic.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } // Gesture diff --git a/vendor/sdl2/sdl_hints.odin b/vendor/sdl2/sdl_hints.odin index b5793bb02..a84e5a090 100644 --- a/vendor/sdl2/sdl_hints.odin +++ b/vendor/sdl2/sdl_hints.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } HINT_ACCELEROMETER_AS_JOYSTICK :: "SDL_ACCELEROMETER_AS_JOYSTICK" HINT_ALLOW_ALT_TAB_WHILE_GRABBED :: "SDL_ALLOW_ALT_TAB_WHILE_GRABBED" diff --git a/vendor/sdl2/sdl_joystick.odin b/vendor/sdl2/sdl_joystick.odin index d2bb624b7..1178eae24 100644 --- a/vendor/sdl2/sdl_joystick.odin +++ b/vendor/sdl2/sdl_joystick.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } Joystick :: struct {} diff --git a/vendor/sdl2/sdl_keyboard.odin b/vendor/sdl2/sdl_keyboard.odin index 86112863a..a68c644ab 100644 --- a/vendor/sdl2/sdl_keyboard.odin +++ b/vendor/sdl2/sdl_keyboard.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } Keysym :: struct { scancode: Scancode, /**< SDL physical key code - see ::SDL_Scancode for details */ diff --git a/vendor/sdl2/sdl_log.odin b/vendor/sdl2/sdl_log.odin index b9f8a8d7d..d42d82b77 100644 --- a/vendor/sdl2/sdl_log.odin +++ b/vendor/sdl2/sdl_log.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } MAX_LOG_MESSAGE :: 4096 diff --git a/vendor/sdl2/sdl_messagebox.odin b/vendor/sdl2/sdl_messagebox.odin index d8a07c1e2..c66cc4911 100644 --- a/vendor/sdl2/sdl_messagebox.odin +++ b/vendor/sdl2/sdl_messagebox.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } MessageBoxFlag :: enum u32 { _ = 0, diff --git a/vendor/sdl2/sdl_metal.odin b/vendor/sdl2/sdl_metal.odin index 87a0313ef..953c6d45f 100644 --- a/vendor/sdl2/sdl_metal.odin +++ b/vendor/sdl2/sdl_metal.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } MetalView :: distinct rawptr diff --git a/vendor/sdl2/sdl_mouse.odin b/vendor/sdl2/sdl_mouse.odin index d667addc8..5ca8d9b5e 100644 --- a/vendor/sdl2/sdl_mouse.odin +++ b/vendor/sdl2/sdl_mouse.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } Cursor :: struct {} diff --git a/vendor/sdl2/sdl_mutex.odin b/vendor/sdl2/sdl_mutex.odin index 80d62f7c8..6b9c96319 100644 --- a/vendor/sdl2/sdl_mutex.odin +++ b/vendor/sdl2/sdl_mutex.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } MUTEX_TIMEDOUT :: 1 MUTEX_MAXWAIT :: ~u32(0) diff --git a/vendor/sdl2/sdl_pixels.odin b/vendor/sdl2/sdl_pixels.odin index 22f6db440..3cd2da5f4 100644 --- a/vendor/sdl2/sdl_pixels.odin +++ b/vendor/sdl2/sdl_pixels.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } ALPHA_OPAQUE :: 255 ALPHA_TRANSPARENT :: 0 diff --git a/vendor/sdl2/sdl_rect.odin b/vendor/sdl2/sdl_rect.odin index 929897c26..b0d6242be 100644 --- a/vendor/sdl2/sdl_rect.odin +++ b/vendor/sdl2/sdl_rect.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } Point :: struct { x: c.int, diff --git a/vendor/sdl2/sdl_render.odin b/vendor/sdl2/sdl_render.odin index c92fd3eda..435c40570 100644 --- a/vendor/sdl2/sdl_render.odin +++ b/vendor/sdl2/sdl_render.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } RendererFlag :: enum u32 { SOFTWARE = 0, /**< The renderer is a software fallback */ diff --git a/vendor/sdl2/sdl_rwops.odin b/vendor/sdl2/sdl_rwops.odin index 590815c90..3bee66290 100644 --- a/vendor/sdl2/sdl_rwops.odin +++ b/vendor/sdl2/sdl_rwops.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } /* RWops Types */ RWOPS_UNKNOWN :: 0 /**< Unknown stream type */ diff --git a/vendor/sdl2/sdl_stdinc.odin b/vendor/sdl2/sdl_stdinc.odin index bf098a591..9bd5df4da 100644 --- a/vendor/sdl2/sdl_stdinc.odin +++ b/vendor/sdl2/sdl_stdinc.odin @@ -5,10 +5,10 @@ import "core:intrinsics" import "core:runtime" _, _ :: intrinsics, runtime -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } bool :: distinct b32 #assert(size_of(bool) == size_of(c.int)) diff --git a/vendor/sdl2/sdl_surface.odin b/vendor/sdl2/sdl_surface.odin index c0b20be63..e5a5da7ef 100644 --- a/vendor/sdl2/sdl_surface.odin +++ b/vendor/sdl2/sdl_surface.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } SWSURFACE :: 0 /**< Just here for compatibility */ PREALLOC :: 0x00000001 /**< Surface uses preallocated memory */ diff --git a/vendor/sdl2/sdl_system.odin b/vendor/sdl2/sdl_system.odin index 31f1b590b..89ae4c707 100644 --- a/vendor/sdl2/sdl_system.odin +++ b/vendor/sdl2/sdl_system.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } // General @(default_calling_convention="c", link_prefix="SDL_") diff --git a/vendor/sdl2/sdl_syswm.odin b/vendor/sdl2/sdl_syswm.odin index e374e72b7..37da1d298 100644 --- a/vendor/sdl2/sdl_syswm.odin +++ b/vendor/sdl2/sdl_syswm.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } SYSWM_TYPE :: enum c.int { UNKNOWN, diff --git a/vendor/sdl2/sdl_thread.odin b/vendor/sdl2/sdl_thread.odin index cbaf3ac00..98354438b 100644 --- a/vendor/sdl2/sdl_thread.odin +++ b/vendor/sdl2/sdl_thread.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } Thread :: struct {} diff --git a/vendor/sdl2/sdl_timer.odin b/vendor/sdl2/sdl_timer.odin index 5b26c7346..357fdd437 100644 --- a/vendor/sdl2/sdl_timer.odin +++ b/vendor/sdl2/sdl_timer.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } TimerCallback :: proc "c" (interval: u32, param: rawptr) -> u32 TimerID :: distinct c.int diff --git a/vendor/sdl2/sdl_touch.odin b/vendor/sdl2/sdl_touch.odin index c393b74ef..d90939cb9 100644 --- a/vendor/sdl2/sdl_touch.odin +++ b/vendor/sdl2/sdl_touch.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } TouchID :: distinct i64 FingerID :: distinct i64 diff --git a/vendor/sdl2/sdl_video.odin b/vendor/sdl2/sdl_video.odin index 97a134739..01aaee1e7 100644 --- a/vendor/sdl2/sdl_video.odin +++ b/vendor/sdl2/sdl_video.odin @@ -2,10 +2,10 @@ package sdl2 import "core:c" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } DisplayMode :: struct { format: u32, /**< pixel format */ diff --git a/vendor/sdl2/sdl_vulkan.odin b/vendor/sdl2/sdl_vulkan.odin index 97a41bacf..66b054524 100644 --- a/vendor/sdl2/sdl_vulkan.odin +++ b/vendor/sdl2/sdl_vulkan.odin @@ -3,10 +3,10 @@ package sdl2 import "core:c" import vk "vendor:vulkan" -when ODIN_OS == "windows" { foreign import lib "SDL2.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } VkInstance :: vk.Instance VkSurfaceKHR :: vk.SurfaceKHR diff --git a/vendor/sdl2/ttf/sdl_ttf.odin b/vendor/sdl2/ttf/sdl_ttf.odin index 6b41f07c2..20db09729 100644 --- a/vendor/sdl2/ttf/sdl_ttf.odin +++ b/vendor/sdl2/ttf/sdl_ttf.odin @@ -3,10 +3,10 @@ package sdl2_ttf import "core:c" import SDL ".." -when ODIN_OS == "windows" { foreign import lib "SDL2_ttf.lib" } -when ODIN_OS == "linux" { foreign import lib "system:SDL2_ttf" } -when ODIN_OS == "darwin" { foreign import lib "system:SDL2_ttf" } -when ODIN_OS == "freebsd" { foreign import lib "system:SDL2_ttf" } +when ODIN_OS == .Windows { foreign import lib "SDL2_ttf.lib" } +when ODIN_OS == .Linux { foreign import lib "system:SDL2_ttf" } +when ODIN_OS == .Darwin { foreign import lib "system:SDL2_ttf" } +when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_ttf" } bool :: SDL.bool diff --git a/vendor/stb/image/stb_image.odin b/vendor/stb/image/stb_image.odin index 9e72760ab..8a3582792 100644 --- a/vendor/stb/image/stb_image.odin +++ b/vendor/stb/image/stb_image.odin @@ -4,8 +4,8 @@ import c "core:c/libc" #assert(size_of(c.int) == size_of(b32)) -when ODIN_OS == "windows" { foreign import stbi "../lib/stb_image.lib" } -when ODIN_OS == "linux" { foreign import stbi "../lib/stb_image.a" } +when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib" } +when ODIN_OS == .Linux { foreign import stbi "../lib/stb_image.a" } #assert(size_of(b32) == size_of(c.int)) diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin index bee29a15e..65bf3e4a9 100644 --- a/vendor/stb/image/stb_image_resize.odin +++ b/vendor/stb/image/stb_image_resize.odin @@ -2,8 +2,8 @@ package stb_image import c "core:c/libc" -when ODIN_OS == "windows" { foreign import lib "../lib/stb_image_resize.lib" } -when ODIN_OS == "linux" { foreign import lib "../lib/stb_image_resize.a" } +when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib" } +when ODIN_OS == .Linux { foreign import lib "../lib/stb_image_resize.a" } ////////////////////////////////////////////////////////////////////////////// // diff --git a/vendor/stb/image/stb_image_write.odin b/vendor/stb/image/stb_image_write.odin index 1f0cfce85..67f4299fa 100644 --- a/vendor/stb/image/stb_image_write.odin +++ b/vendor/stb/image/stb_image_write.odin @@ -2,8 +2,8 @@ package stb_image import c "core:c/libc" -when ODIN_OS == "windows" { foreign import stbiw "../lib/stb_image_write.lib" } -when ODIN_OS == "linux" { foreign import stbiw "../lib/stb_image_write.a" } +when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" } +when ODIN_OS == .Linux { foreign import stbiw "../lib/stb_image_write.a" } write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int) diff --git a/vendor/stb/rect_pack/stb_rect_pack.odin b/vendor/stb/rect_pack/stb_rect_pack.odin index 4142a73ec..f84f1cedc 100644 --- a/vendor/stb/rect_pack/stb_rect_pack.odin +++ b/vendor/stb/rect_pack/stb_rect_pack.odin @@ -4,8 +4,8 @@ import c "core:c/libc" #assert(size_of(b32) == size_of(c.int)) -when ODIN_OS == "windows" { foreign import lib "../lib/stb_rect_pack.lib" } -when ODIN_OS == "linux" { foreign import lib "../lib/stb_rect_pack.a" } +when ODIN_OS == .Windows { foreign import lib "../lib/stb_rect_pack.lib" } +when ODIN_OS == .Linux { foreign import lib "../lib/stb_rect_pack.a" } Coord :: distinct c.int _MAXVAL :: max(Coord) diff --git a/vendor/stb/truetype/stb_truetype.odin b/vendor/stb/truetype/stb_truetype.odin index 3abb187c2..cf4af15e9 100644 --- a/vendor/stb/truetype/stb_truetype.odin +++ b/vendor/stb/truetype/stb_truetype.odin @@ -3,8 +3,8 @@ package stb_truetype import c "core:c" import stbrp "vendor:stb/rect_pack" -when ODIN_OS == "windows" { foreign import stbtt "../lib/stb_truetype.lib" } -when ODIN_OS == "linux" { foreign import stbtt "../lib/stb_truetype.a" } +when ODIN_OS == .Windows { foreign import stbtt "../lib/stb_truetype.lib" } +when ODIN_OS == .Linux { foreign import stbtt "../lib/stb_truetype.a" } /////////////////////////////////////////////////////////////////////////////// diff --git a/vendor/stb/vorbis/stb_vorbis.odin b/vendor/stb/vorbis/stb_vorbis.odin index 7ec248df5..f35b58e04 100644 --- a/vendor/stb/vorbis/stb_vorbis.odin +++ b/vendor/stb/vorbis/stb_vorbis.odin @@ -3,8 +3,8 @@ package stb_vorbis import c "core:c/libc" -when ODIN_OS == "windows" { foreign import lib "../lib/stb_vorbis.lib" } -when ODIN_OS == "linux" { foreign import lib "../lib/stb_vorbis.a" } +when ODIN_OS == .Windows { foreign import lib "../lib/stb_vorbis.lib" } +when ODIN_OS == .Linux { foreign import lib "../lib/stb_vorbis.a" } diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index 1525f4e15..e7fb234c8 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -591,7 +591,7 @@ MAX_GLOBAL_PRIORITY_SIZE_EXT :: 16 f.write(""" import "core:c" -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { \timport win32 "core:sys/windows" \tHINSTANCE :: win32.HINSTANCE diff --git a/vendor/vulkan/structs.odin b/vendor/vulkan/structs.odin index 4d90a53fa..3c655a4fa 100644 --- a/vendor/vulkan/structs.odin +++ b/vendor/vulkan/structs.odin @@ -5,7 +5,7 @@ package vulkan import "core:c" -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { import win32 "core:sys/windows" HINSTANCE :: win32.HINSTANCE From 77b91352aeb72d9b22a05e3094607a8a5ab4e091 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Jan 2022 19:58:35 +0000 Subject: [PATCH 0026/1052] Add `Odin_OS_Type` and `Odin_Arch_Type` to `core:runtime` --- core/runtime/core.odin | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index cd76b0bb5..6c2ab1405 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -386,6 +386,35 @@ Raw_Cstring :: struct { } +/* + // Defined internally by the compiler + Odin_OS_Type :: enum int { + Unknown, + Windows, + Darwin, + Linux, + Essence, + FreeBSD, + WASI, + JS, + Freestanding, + } +*/ +Odin_OS_Type :: type_of(ODIN_OS) + +/* + // Defined internally by the compiler + Odin_Arch_Type :: enum int { + Unknown, + amd64, + i386, + arm64, + wasm32, + wasm64, + } +*/ +Odin_Arch_Type :: type_of(ODIN_ARCH) + /* // Defined internally by the compiler Odin_Build_Mode_Type :: enum int { From f2f20def37a1cbe57ceddf6d9ee33c1015432fca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Jan 2022 20:02:41 +0000 Subject: [PATCH 0027/1052] Update demo.odin --- examples/demo/demo.odin | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 3e34e3d49..13dcf9466 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -244,10 +244,10 @@ control_flow :: proc() { // A switch statement is another way to write a sequence of if-else statements. // In Odin, the default case is denoted as a case without any expression. - switch arch := ODIN_ARCH; arch { - case "386": + #partial switch arch := ODIN_ARCH; arch { + case .i386: fmt.println("32-bit") - case "amd64": + case .amd64: fmt.println("64-bit") case: // default fmt.println("Unsupported architecture") @@ -363,12 +363,12 @@ control_flow :: proc() { */ // Example - when ODIN_ARCH == "386" { + when ODIN_ARCH == .i386 { fmt.println("32 bit") - } else when ODIN_ARCH == "amd64" { + } else when ODIN_ARCH == .amd64 { fmt.println("64 bit") } else { - fmt.println("Unsupported architecture") + fmt.println("Unknown architecture") } // The when statement is very useful for writing platform specific code. // This is akin to the #if construct in C’s preprocessor however, in Odin, @@ -1100,7 +1100,7 @@ prefix_table := [?]string{ } threading_example :: proc() { - if ODIN_OS == "darwin" { + if ODIN_OS == .Darwin { // TODO: Fix threads on darwin/macOS return } @@ -1606,13 +1606,13 @@ where_clauses :: proc() { } -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import kernel32 "system:kernel32.lib" } foreign_system :: proc() { fmt.println("\n#foreign system") - when ODIN_OS == "windows" { + when ODIN_OS == .Windows { // It is sometimes necessarily to interface with foreign code, // such as a C library. In Odin, this is achieved through the // foreign system. You can “import” a library into the code From 6223f48c3fc096b543a51aa1c993a6f1127f2a0f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Jan 2022 20:08:24 +0000 Subject: [PATCH 0028/1052] Update tests --- tests/core/crypto/test_core_crypto_modern.odin | 2 +- tests/core/image/test_core_image.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/crypto/test_core_crypto_modern.odin b/tests/core/crypto/test_core_crypto_modern.odin index 71adad137..6d1ae0047 100644 --- a/tests/core/crypto/test_core_crypto_modern.odin +++ b/tests/core/crypto/test_core_crypto_modern.odin @@ -308,7 +308,7 @@ test_x25519 :: proc(t: ^testing.T) { test_rand_bytes :: proc(t: ^testing.T) { log(t, "Testing rand_bytes") - if ODIN_OS != "linux" { + if ODIN_OS != .Linux { log(t, "rand_bytes not supported - skipping") return } diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 23a7c2561..124166245 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -1785,7 +1785,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b } mode: int = 0 - when ODIN_OS == "linux" || ODIN_OS == "darwin" { + when ODIN_OS == .Linux || ODIN_OS == .Darwin { // NOTE(justasd): 644 (owner read, write; group read; others read) mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH } From 540c5400a0c7b2e3cc40bba4e00f4b13c18f9d7c Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sun, 23 Jan 2022 23:13:32 +0100 Subject: [PATCH 0029/1052] Adds several system calls and the beginning of odin wrappers for them This also adds all systemcall numbers from the xnu kernel / and additional helpers for some of the calls to make it easier to call them from odin --- core/sys/darwin/xnu_system_call_helpers.odin | 180 ++++++ core/sys/darwin/xnu_system_call_numbers.odin | 558 ++++++++++++++++++ core/sys/darwin/xnu_system_call_wrappers.odin | 419 +++++++++++++ 3 files changed, 1157 insertions(+) create mode 100644 core/sys/darwin/xnu_system_call_helpers.odin create mode 100644 core/sys/darwin/xnu_system_call_numbers.odin create mode 100644 core/sys/darwin/xnu_system_call_wrappers.odin diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin new file mode 100644 index 000000000..eabbb73df --- /dev/null +++ b/core/sys/darwin/xnu_system_call_helpers.odin @@ -0,0 +1,180 @@ +package sys + +import "core:strings" +import "core:c" +import "core:os" +import "core:fmt" + +// this package uses the sys prefix for the proc names to indicate that these aren't native syscalls but directly call such +sys_write_string :: proc (fd: c.int, message: string) -> bool { + return syscall_write(fd, strings.ptr_from_string(message), cast(u64)len(message)) +} + +Offset_From :: enum c.int { + SEEK_SET = 0, // the offset is set to offset bytes. + SEEK_CUR = 1, // the offset is set to its current location plus offset bytes. + SEEK_END = 2, // the offset is set to the size of the file plus offset bytes. + SEEK_HOLE = 3, // the offset is set to the start of the next hole greater than or equal to the supplied offset. + SEEK_DATA = 4, // the offset is set to the start of the next non-hole file region greater than or equal to the supplied offset. +} + +Open_Flags_Enum :: enum u8 { + RDONLY, /* open for reading only */ + WRONLY, /* open for writing only */ + RDWR, /* open for reading and writing */ + + NONBLOCK, /* no delay */ + APPEND, /* set append mode */ + CREAT, /* create if nonexistant */ + TRUNC, /* truncate to zero length */ + EXCL, /* error if already exists */ + SHLOCK, /* open with shared file lock */ + EXLOCK, /* open with exclusive file lock */ + DIRECTORY, /* restrict open to only directories */ + NOFOLLOW, /* don't follow symlinks */ + SYMLINK, /* allow open of a symlink */ + EVTONLY, /* descriptor requested for event notifications only */ + CLOEXEC, /* causes the descriptor to be closed if you use any of the exec like functions */ + NOFOLLOW_ANY, /* no symlinks allowed in path */ +} +Open_Flags :: bit_set[Open_Flags_Enum; u16] + +Permission_Enum :: enum u8 { + /* For owner */ + PERMISSION_OWNER_READ, /* R for owner */ + PERMISSION_OWNER_WRITE, /* W for owner */ + PERMISSION_OWNER_EXECUTE, /* X for owner */ + //IRWXU, /* RWX mask for owner */ + + /* For group */ + PERMISSION_GROUP_READ, /* R for group */ + PERMISSION_GROUP_WRITE, /* W for group */ + PERMISSION_GROUP_EXECUTE, /* X for group */ + //IRWXG, /* RWX mask for group */ + + /* For other */ + PERMISSION_OTHER_READ, /* R for other */ + PERMISSION_OTHER_WRITE, /* W for other */ + PERMISSION_OTHER_EXECUTE, /* X for other */ + //IRWXO, /* RWX mask for other */ + + /* Special */ + PERMISSION_SET_USER_ON_EXECUTION, /* set user id on execution */ + PERMISSION_SET_GROUP_ON_EXECUTION, /* set group id on execution */ + + /* ?? */ + PERMISSION_ISVTX, /* save swapped text even after use */ +} +Permission :: bit_set[Permission_Enum; u16] + +PERMISSION_NONE_NONE :: Permission{} +PERMISSION_OWNER_ALL :: Permission{.PERMISSION_OWNER_READ, .PERMISSION_OWNER_WRITE, .PERMISSION_OWNER_EXECUTE} +PERMISSION_GROUP_ALL :: Permission{.PERMISSION_GROUP_READ, .PERMISSION_GROUP_WRITE, .PERMISSION_GROUP_EXECUTE} +PERMISSION_OTHER_ALL :: Permission{.PERMISSION_OTHER_READ, .PERMISSION_OTHER_WRITE, .PERMISSION_OTHER_EXECUTE} +PERMISSION_ALL_ALL :: PERMISSION_OWNER_ALL | PERMISSION_GROUP_ALL | PERMISSION_OTHER_ALL + +_sys_permission_mode :: #force_inline proc (mode: Permission) -> u32 { + cflags: u32 = 0; + + cflags |= PERMISSION_MASK_IRUSR * u32(Permission.PERMISSION_OWNER_READ in mode) + cflags |= PERMISSION_MASK_IWUSR * u32(Permission.PERMISSION_OWNER_WRITE in mode) + cflags |= PERMISSION_MASK_IXUSR * u32(Permission.PERMISSION_OWNER_WRITE in mode) + cflags |= PERMISSION_MASK_IRGRP * u32(Permission.PERMISSION_GROUP_READ in mode) + cflags |= PERMISSION_MASK_IWGRP * u32(Permission.PERMISSION_GROUP_WRITE in mode) + cflags |= PERMISSION_MASK_IXGRP * u32(Permission.PERMISSION_GROUP_WRITE in mode) + cflags |= PERMISSION_MASK_IROTH * u32(Permission.PERMISSION_OTHER_READ in mode) + cflags |= PERMISSION_MASK_IWOTH * u32(Permission.PERMISSION_OTHER_WRITE in mode) + cflags |= PERMISSION_MASK_IXOTH * u32(Permission.PERMISSION_OTHER_WRITE in mode) + + return cflags +} + +sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, bool) { + + cmode: u32 = 0; + cflags: u32 = 0; + cpath: cstring = strings.clone_to_cstring(path); + defer delete(cpath) + + cflags = _sys_permission_mode(mode) + + cmode |= OPEN_FLAG_RDONLY * u32(Open_Flags.RDONLY in oflag) + cmode |= OPEN_FLAG_WRONLY * u32(Open_Flags.WRONLY in oflag) + cmode |= OPEN_FLAG_RDWR * u32(Open_Flags.RDWR in oflag) + cmode |= OPEN_FLAG_NONBLOCK * u32(Open_Flags.NONBLOCK in oflag) + cmode |= OPEN_FLAG_CREAT * u32(Open_Flags.CREAT in oflag) + cmode |= OPEN_FLAG_APPEND * u32(Open_Flags.APPEND in oflag) + cmode |= OPEN_FLAG_TRUNC * u32(Open_Flags.TRUNC in oflag) + cmode |= OPEN_FLAG_EXCL * u32(Open_Flags.EXCL in oflag) + cmode |= OPEN_FLAG_SHLOCK * u32(Open_Flags.SHLOCK in oflag) + cmode |= OPEN_FLAG_EXLOCK * u32(Open_Flags.EXLOCK in oflag) + cmode |= OPEN_FLAG_DIRECTORY * u32(Open_Flags.DIRECTORY in oflag) + cmode |= OPEN_FLAG_NOFOLLOW * u32(Open_Flags.NOFOLLOW in oflag) + cmode |= OPEN_FLAG_SYMLINK * u32(Open_Flags.SYMLINK in oflag) + cmode |= OPEN_FLAG_EVTONLY * u32(Open_Flags.EVTONLY in oflag) + cmode |= OPEN_FLAG_CLOEXEC * u32(Open_Flags.CLOEXEC in oflag) + cmode |= OPEN_FLAG_NOFOLLOW_ANY * u32(Open_Flags.NOFOLLOW_ANY in oflag) + + result := syscall_open(cpath, cmode, cflags) + state := result != -1 + + if state && cflags != 0 { + state = (syscall_fchmod(result, cflags) != -1) + } + + return result * cast(c.int)state, state +} + +sys_mkdir :: proc(path: string, mode: Permission) -> bool { + cpath: cstring = strings.clone_to_cstring(path) + defer delete(cpath) + cflags := _sys_permission_mode(mode) + return syscall_mkdir(cpath, cflags) != -1 +} + +sys_mkdir_at :: proc(fd: c.int, path: string, mode: Permission) -> bool { + cpath: cstring = strings.clone_to_cstring(path) + defer delete(cpath) + cflags := _sys_permission_mode(mode) + return syscall_mkdir_at(fd, cpath, cflags) != -1 +} + +sys_rmdir :: proc(path: string, mode: Permission) -> bool { + cpath: cstring = strings.clone_to_cstring(path) + defer delete(cpath) + cflags := _sys_permission_mode(mode) + return syscall_rmdir(cpath, cflags) != -1 +} + +sys_rename :: proc(path: string, new_path: string) -> bool { + cpath: cstring = strings.clone_to_cstring(path) + defer delete(cpath) + cnpath: cstring = strings.clone_to_cstring(new_path) + defer delete(cnpath) + return syscall_rename(cpath, cnpath) != -1 +} + +sys_rename_at :: proc(fd: c.int, path: string, to_fd: c.int, new_path: string) -> bool { + cpath: cstring = strings.clone_to_cstring(path) + defer delete(cpath) + cnpath: cstring = strings.clone_to_cstring(new_path) + defer delete(cnpath) + return syscall_rename_at(fd, cpath, to_fd, cnpath) != -1 +} + +sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 { + return syscall_lseek(fd, offset, cast(c.int)whence) +} + +sys_chmod :: proc(path: string, mode: Permission) -> bool { + cpath: cstring = strings.clone_to_cstring(path) + defer delete(cpath) + cmode := _sys_permission_mode(mode); + return syscall_chmod(cpath, cmode) != -1 +} + +sys_lstat :: proc(path: string, status: ^stat) -> bool { + cpath: cstring = strings.clone_to_cstring(path) + defer delete(cpath) + return syscall_lstat(cpath, status) != -1 +} diff --git a/core/sys/darwin/xnu_system_call_numbers.odin b/core/sys/darwin/xnu_system_call_numbers.odin new file mode 100644 index 000000000..4aba8a830 --- /dev/null +++ b/core/sys/darwin/xnu_system_call_numbers.odin @@ -0,0 +1,558 @@ +package sys + +unix_offset_syscall :: proc(number: System_Call_Number) -> uintptr { + return uintptr(number) + uintptr(0x2000000) +} + +System_Call_Number :: enum uintptr { + /* 0 syscall */ + exit = 1, + fork = 2, + read = 3, + write = 4, + open = 5, + close = 6, + wait4 = 7, + /* 8 old creat */ + link = 9, + unlink = 10, + /* 11 old execv */ + chdir = 12, + fchdir = 13, + mknod = 14, + chmod = 15, + chown = 16, + /* 17 old break */ + getfsstat = 18, + /* 19 old lseek */ + getpid = 20, + /* 21 old mount */ + /* 22 old umount */ + setuid = 23, + getuid = 24, + geteuid = 25, + ptrace = 26, + recvmsg = 27, + sendmsg = 28, + recvfrom = 29, + accept = 30, + getpeername = 31, + getsockname = 32, + access = 33, + chflags = 34, + fchflags = 35, + sync = 36, + kill = 37, + /* 38 old stat */ + getppid = 39, + /* 40 old lstat */ + dup = 41, + pipe = 42, + getegid = 43, + /* 44 old profil */ + /* 45 old ktrace */ + sigaction = 46, + getgid = 47, + sigprocmask = 48, + getlogin = 49, + setlogin = 50, + acct = 51, + sigpending = 52, + sigaltstack = 53, + ioctl = 54, + reboot = 55, + revoke = 56, + symlink = 57, + readlink = 58, + execve = 59, + umask = 60, + chroot = 61, + /* 62 old fstat */ + /* 63 used internally and reserved */ + /* getpagesize = 64, invalid */ + msync = 65, + vfork = 66, + /* 67 old vread */ + /* 68 old vwrite */ + /* 69 old sbrk */ + /* 70 old sstk */ + /* 71 old mmap */ + /* 72 old vadvise */ + munmap = 73, + mprotect = 74, + madvise = 75, + /* 76 old vhangup */ + /* 77 old vlimit */ + mincore = 78, + getgroups = 79, + setgroups = 80, + getpgrp = 81, + setpgid = 82, + setitimer = 83, + /* 84 old wait */ + swapon = 85, + getitimer = 86, + /* 87 old gethostname */ + /* 88 old sethostname */ + getdtablesize = 89, + dup2 = 90, + /* 91 old getdopt */ + fcntl = 92, + select = 93, + /* 94 old setdopt */ + fsync = 95, + setpriority = 96, + socket = 97, + connect = 98, + /* 99 old accept */ + getpriority = 100, + /* 101 old send */ + /* 102 old recv */ + /* 103 old sigreturn */ + bind = 104, + setsockopt = 105, + listen = 106, + /* 107 old vtimes */ + /* 108 old sigvec */ + /* 109 old sigblock */ + /* 110 old sigsetmask */ + sigsuspend = 111, + /* 112 old sigstack */ + /* 113 old recvmsg */ + /* 114 old sendmsg */ + /* 115 old vtrace */ + gettimeofday = 116, + getrusage = 117, + getsockopt = 118, + /* 119 old resuba */ + readv = 120, + writev = 121, + settimeofday = 122, + fchown = 123, + fchmod = 124, + /* 125 old recvfrom */ + setreuid = 126, + setregid = 127, + rename = 128, + /* 129 old truncate */ + /* 130 old ftruncate */ + flock = 131, + mkfifo = 132, + sendto = 133, + shutdown = 134, + socketpair = 135, + mkdir = 136, + rmdir = 137, + utimes = 138, + futimes = 139, + adjtime = 140, + /* 141 old getpeername */ + gethostuuid = 142, + /* 143 old sethostid */ + /* 144 old getrlimit */ + /* 145 old setrlimit */ + /* 146 old killpg */ + setsid = 147, + /* 148 old setquota */ + /* 149 old qquota */ + /* 150 old getsockname */ + getpgid = 151, + setprivexec = 152, + pread = 153, + pwrite = 154, + nfssvc = 155, + /* 156 old getdirentries */ + statfs = 157, + fstatfs = 158, + unmount = 159, + /* 160 old async_daemon */ + getfh = 161, + /* 162 old getdomainname */ + /* 163 old setdomainname */ + /* 164 */ + quotactl = 165, + /* 166 old exportfs */ + mount = 167, + /* 168 old ustat */ + csops = 169, + csops_audittoken = 170, + /* 171 old wait3 */ + /* 172 old rpause */ + waitid = 173, + /* 174 old getdents */ + /* 175 old gc_control */ + /* 176 old add_profil */ + kdebug_typefilter = 177, + kdebug_trace_string = 178, + kdebug_trace64 = 179, + kdebug_trace = 180, + setgid = 181, + setegid = 182, + seteuid = 183, + sigreturn = 184, + /* 185 old chud */ + thread_selfcounts = 186, + fdatasync = 187, + stat = 188, + fstat = 189, + lstat = 190, + pathconf = 191, + fpathconf = 192, + /* 193 old getfsstat */ + getrlimit = 194, + setrlimit = 195, + getdirentries = 196, + mmap = 197, + /* 198 old __syscall */ + lseek = 199, + truncate = 200, + ftruncate = 201, + sysctl = 202, + mlock = 203, + munlock = 204, + undelete = 205, + /* 206 old ATsocket */ + /* 207 old ATgetmsg */ + /* 208 old ATputmsg */ + /* 209 old ATsndreq */ + /* 210 old ATsndrsp */ + /* 211 old ATgetreq */ + /* 212 old ATgetrsp */ + /* 213 Reserved for AppleTalk */ + /* 214 */ + /* 215 */ + open_dprotected_np = 216, + fsgetpath_ext = 217, + /* 218 old lstatv */ + /* 219 old fstatv */ + getattrlist = 220, + setattrlist = 221, + getdirentriesattr = 222, + exchangedata = 223, + /* 224 old checkuseraccess or fsgetpath */ + searchfs = 225, + delete = 226, + copyfile = 227, + fgetattrlist = 228, + fsetattrlist = 229, + poll = 230, + /* 231 old watchevent */ + /* 232 old waitevent */ + /* 233 old modwatch */ + getxattr = 234, + fgetxattr = 235, + setxattr = 236, + fsetxattr = 237, + removexattr = 238, + fremovexattr = 239, + listxattr = 240, + flistxattr = 241, + fsctl = 242, + initgroups = 243, + posix_spawn = 244, + ffsctl = 245, + /* 246 */ + nfsclnt = 247, + fhopen = 248, + /* 249 */ + minherit = 250, + semsys = 251, + msgsys = 252, + shmsys = 253, + semctl = 254, + semget = 255, + semop = 256, + /* 257 old semconfig */ + msgctl = 258, + msgget = 259, + msgsnd = 260, + msgrcv = 261, + shmat = 262, + shmctl = 263, + shmdt = 264, + shmget = 265, + shm_open = 266, + shm_unlink = 267, + sem_open = 268, + sem_close = 269, + sem_unlink = 270, + sem_wait = 271, + sem_trywait = 272, + sem_post = 273, + sysctlbyname = 274, + /* 275 old sem_init */ + /* 276 old sem_destroy */ + open_extended = 277, + umask_extended = 278, + stat_extended = 279, + lstat_extended = 280, + fstat_extended = 281, + chmod_extended = 282, + fchmod_extended = 283, + access_extended = 284, + settid = 285, + gettid = 286, + setsgroups = 287, + getsgroups = 288, + setwgroups = 289, + getwgroups = 290, + mkfifo_extended = 291, + mkdir_extended = 292, + identitysvc = 293, + shared_region_check_np = 294, + /* 295 old shared_region_map_np */ + vm_pressure_monitor = 296, + psynch_rw_longrdlock = 297, + psynch_rw_yieldwrlock = 298, + psynch_rw_downgrade = 299, + psynch_rw_upgrade = 300, + psynch_mutexwait = 301, + psynch_mutexdrop = 302, + psynch_cvbroad = 303, + psynch_cvsignal = 304, + psynch_cvwait = 305, + psynch_rw_rdlock = 306, + psynch_rw_wrlock = 307, + psynch_rw_unlock = 308, + psynch_rw_unlock2 = 309, + getsid = 310, + settid_with_pid = 311, + psynch_cvclrprepost = 312, + aio_fsync = 313, + aio_return = 314, + aio_suspend = 315, + aio_cancel = 316, + aio_error = 317, + aio_read = 318, + aio_write = 319, + lio_listio = 320, + /* 321 old __pthread_cond_wait */ + iopolicysys = 322, + process_policy = 323, + mlockall = 324, + munlockall = 325, + /* 326 */ + issetugid = 327, + __pthread_kill = 328, + __pthread_sigmask = 329, + __sigwait = 330, + __disable_threadsignal = 331, + __pthread_markcancel = 332, + __pthread_canceled = 333, + __semwait_signal = 334, + /* 335 old utrace */ + proc_info = 336, + sendfile = 337, + stat64 = 338, + fstat64 = 339, + lstat64 = 340, + stat64_extended = 341, + lstat64_extended = 342, + fstat64_extended = 343, + getdirentries64 = 344, + statfs64 = 345, + fstatfs64 = 346, + getfsstat64 = 347, + __pthread_chdir = 348, + __pthread_fchdir = 349, + audit = 350, + auditon = 351, + /* 352 */ + getauid = 353, + setauid = 354, + /* 355 old getaudit */ + /* 356 old setaudit */ + getaudit_addr = 357, + setaudit_addr = 358, + auditctl = 359, + bsdthread_create = 360, + bsdthread_terminate = 361, + kqueue = 362, + kevent = 363, + lchown = 364, + /* 365 old stack_snapshot */ + bsdthread_register = 366, + workq_open = 367, + workq_kernreturn = 368, + kevent64 = 369, + __old_semwait_signal = 370, + __old_semwait_signal_nocancel = 371, + thread_selfid = 372, + ledger = 373, + kevent_qos = 374, + kevent_id = 375, + /* 376 */ + /* 377 */ + /* 378 */ + /* 379 */ + __mac_execve = 380, + __mac_syscall = 381, + __mac_get_file = 382, + __mac_set_file = 383, + __mac_get_link = 384, + __mac_set_link = 385, + __mac_get_proc = 386, + __mac_set_proc = 387, + __mac_get_fd = 388, + __mac_set_fd = 389, + __mac_get_pid = 390, + /* 391 */ + /* 392 */ + /* 393 */ + pselect = 394, + pselect_nocancel = 395, + read_nocancel = 396, + write_nocancel = 397, + open_nocancel = 398, + close_nocancel = 399, + wait4_nocancel = 400, + recvmsg_nocancel = 401, + sendmsg_nocancel = 402, + recvfrom_nocancel = 403, + accept_nocancel = 404, + msync_nocancel = 405, + fcntl_nocancel = 406, + select_nocancel = 407, + fsync_nocancel = 408, + connect_nocancel = 409, + sigsuspend_nocancel = 410, + readv_nocancel = 411, + writev_nocancel = 412, + sendto_nocancel = 413, + pread_nocancel = 414, + pwrite_nocancel = 415, + waitid_nocancel = 416, + poll_nocancel = 417, + msgsnd_nocancel = 418, + msgrcv_nocancel = 419, + sem_wait_nocancel = 420, + aio_suspend_nocancel = 421, + __sigwait_nocancel = 422, + __semwait_signal_nocancel = 423, + __mac_mount = 424, + __mac_get_mount = 425, + __mac_getfsstat = 426, + fsgetpath = 427, + audit_session_self = 428, + audit_session_join = 429, + fileport_makeport = 430, + fileport_makefd = 431, + audit_session_port = 432, + pid_suspend = 433, + pid_resume = 434, + pid_hibernate = 435, + pid_shutdown_sockets = 436, + /* 437 old shared_region_slide_np */ + shared_region_map_and_slide_np = 438, + kas_info = 439, + memorystatus_control = 440, + guarded_open_np = 441, + guarded_close_np = 442, + guarded_kqueue_np = 443, + change_fdguard_np = 444, + usrctl = 445, + proc_rlimit_control = 446, + connectx = 447, + disconnectx = 448, + peeloff = 449, + socket_delegate = 450, + telemetry = 451, + proc_uuid_policy = 452, + memorystatus_get_level = 453, + system_override = 454, + vfs_purge = 455, + sfi_ctl = 456, + sfi_pidctl = 457, + coalition = 458, + coalition_info = 459, + necp_match_policy = 460, + getattrlistbulk = 461, + clonefileat = 462, + openat = 463, + openat_nocancel = 464, + renameat = 465, + faccessat = 466, + fchmodat = 467, + fchownat = 468, + fstatat = 469, + fstatat64 = 470, + linkat = 471, + unlinkat = 472, + readlinkat = 473, + symlinkat = 474, + mkdirat = 475, + getattrlistat = 476, + proc_trace_log = 477, + bsdthread_ctl = 478, + openbyid_np = 479, + recvmsg_x = 480, + sendmsg_x = 481, + thread_selfusage = 482, + csrctl = 483, + guarded_open_dprotected_np = 484, + guarded_write_np = 485, + guarded_pwrite_np = 486, + guarded_writev_np = 487, + renameatx_np = 488, + mremap_encrypted = 489, + netagent_trigger = 490, + stack_snapshot_with_config = 491, + microstackshot = 492, + grab_pgo_data = 493, + persona = 494, + /* 495 */ + mach_eventlink_signal = 496, + mach_eventlink_wait_until = 497, + mach_eventlink_signal_wait_until = 498, + work_interval_ctl = 499, + getentropy = 500, + necp_open = 501, + necp_client_action = 502, + nexus_open = 503, // for those who are intressted http://newosxbook.com/bonus/vol1ch16.html + nexus_register = 504, + nexus_deregister = 505, + nexus_create = 506, + nexus_destroy = 507, + nexus_get_opt = 508, + nexus_set_opt = 509, + channel_open = 510, + channel_get_info = 511, + channel_sync = 512, + channel_get_opt = 513, + channel_set_opt = 514, + ulock_wait = 515, + ulock_wake = 516, + fclonefileat = 517, + fs_snapshot = 518, + register_uexc_handler = 519, + terminate_with_payload = 520, + abort_with_payload = 521, + necp_session_open = 522, + necp_session_action = 523, + setattrlistat = 524, + net_qos_guideline = 525, + fmount = 526, + ntp_adjtime = 527, + ntp_gettime = 528, + os_fault_with_payload = 529, + kqueue_workloop_ctl = 530, + mach_bridge_remote_time = 531, + coalition_ledger = 532, + log_data = 533, + memorystatus_available_memory = 534, + objc_bp_assist_cfg_np = 535, + shared_region_map_and_slide_2_np = 536, + pivot_root = 537, + task_inspect_for_pid = 538, + task_read_for_pid = 539, + preadv = 540, + pwritev = 541, + preadv_nocancel = 542, + pwritev_nocancel = 543, + ulock_wait2 = 544, + proc_info_extended_id = 545, + tracker_action = 546, + debug_syscall_reject = 547, + MAXSYSCALL = 548, + /* invalid = 63, */ +} diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin new file mode 100644 index 000000000..a584299f8 --- /dev/null +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -0,0 +1,419 @@ +package sys + +import "core:c" +import "core:intrinsics" + +/* flock */ +LOCK_SH :: 1 /* shared lock */ +LOCK_EX :: 2 /* exclusive lock */ +LOCK_NB :: 4 /* don't block when locking */ +LOCK_UN :: 8 /* unlock */ + +/* sys/unistd.h for access */ +F_OK :: c.int(0); /* test for existence of file */ +X_OK :: c.int((1 << 0)); /* test for execute or search permission */ +W_OK :: c.int((1 << 1)); /* test for write permission */ +R_OK :: c.int((1 << 2)); /* test for read permission */ + +/* copyfile flags */ +COPYFILE_ACL :: (1 << 0) +COPYFILE_STAT :: (1 << 1) +COPYFILE_XATTR :: (1 << 2) +COPYFILE_DATA :: (1 << 3) + +COPYFILE_SECURITY :: (COPYFILE_STAT | COPYFILE_ACL) +COPYFILE_METADATA :: (COPYFILE_SECURITY | COPYFILE_XATTR) +COPYFILE_ALL :: (COPYFILE_METADATA | COPYFILE_DATA) + +/* syslimits.h */ +PATH_MAX :: 1024; /* max bytes in pathname */ + +/* param.h */ +MAXPATHLEN :: PATH_MAX; + +/* proc_info.h */ +DARWIN_PROC_PIDPATHINFO_SIZE :: MAXPATHLEN; +DARWIN_PROC_PIDPATHINFO :: 11; + +DARWIN_PROC_ALL_PIDS :: c.int(1); +DARWIN_PROC_PGRP_ONLY :: c.int(2); +DARWIN_PROC_TTY_ONLY :: c.int(3); +DARWIN_PROC_UID_ONLY :: c.int(4); +DARWIN_PROC_RUID_ONLY :: c.int(5); +DARWIN_PROC_PPID_ONLY :: c.int(6); +DARWIN_PROC_KDBG_ONLY :: c.int(7); + +DARWIN_PROC_INFO_CALL_LISTPIDS :: c.int(0x1); +DARWIN_PROC_INFO_CALL_PIDINFO :: c.int(0x2); +DARWIN_PROC_INFO_CALL_PIDFDINFO :: c.int(0x3); +DARWIN_PROC_INFO_CALL_KERNMSGBUF :: c.int(0x4); +DARWIN_PROC_INFO_CALL_SETCONTROL :: c.int(0x5); +DARWIN_PROC_INFO_CALL_PIDFILEPORTINFO :: c.int(0x6); +DARWIN_PROC_INFO_CALL_TERMINATE :: c.int(0x7); +DARWIN_PROC_INFO_CALL_DIRTYCONTROL :: c.int(0x8); +DARWIN_PROC_INFO_CALL_PIDRUSAGE :: c.int(0x9); +DARWIN_PROC_INFO_CALL_PIDORIGINATORINFO :: c.int(0xa); +DARWIN_PROC_INFO_CALL_LISTCOALITIONS :: c.int(0xb); +DARWIN_PROC_INFO_CALL_CANUSEFGHW :: c.int(0xc); +DARWIN_PROC_INFO_CALL_PIDDYNKQUEUEINFO :: c.int(0xd); +DARWIN_PROC_INFO_CALL_UDATA_INFO :: c.int(0xe); + +/* mmap flags */ +MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */ +MAP_FILE :: 0x0000 /* map from file (default) */ +MAP_FIXED :: 0x0010 /* [MF|SHM] interpret addr exactly */ +MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */ +MAP_PRIVATE :: 0x0002 /* [MF|SHM] changes are private */ +MAP_SHARED :: 0x0001 /* [MF|SHM] share changes */ +MAP_NOCACHE :: 0x0400 /* don't cache pages for this mapping */ +MAP_JIT :: 0x0800 /* Allocate a region that will be used for JIT purposes */ +MAP_32BIT :: 0x8000 /* Return virtual addresses <4G only */ + +/* mmap prot flags */ +PROT_NONE :: 0x00 /* [MC2] no permissions */ +PROT_READ :: 0x01 /* [MC2] pages can be read */ +PROT_WRITE :: 0x02 /* [MC2] pages can be written */ +PROT_EXEC :: 0x04 /* [MC2] pages can be executed */ + +/* For owner Mode/Permission Flags for Open etc. */ +PERMISSION_MASK_IRWXU :: 0o000700 /* RWX mask for owner */ +PERMISSION_MASK_IRUSR :: 0o000400 /* R for owner */ +PERMISSION_MASK_IWUSR :: 0o000200 /* W for owner */ +PERMISSION_MASK_IXUSR :: 0o000100 /* X for owner */ + +/* For group Mode/Permission Flags for Open etc. */ +PERMISSION_MASK_IRWXG :: 0o000070 /* RWX mask for group */ +PERMISSION_MASK_IRGRP :: 0o000040 /* R for group */ +PERMISSION_MASK_IWGRP :: 0o000020 /* W for group */ +PERMISSION_MASK_IXGRP :: 0o000010 /* X for group */ + +/* For other Mode/Permission Flags for Open etc. */ +PERMISSION_MASK_IRWXO :: 0o000007 /* RWX mask for other */ +PERMISSION_MASK_IROTH :: 0o000004 /* R for other */ +PERMISSION_MASK_IWOTH :: 0o000002 /* W for other */ +PERMISSION_MASK_IXOTH :: 0o000001 /* X for other */ + +/* Special Mode/Permission Flags for Open etc. */ +PERMISSION_MASK_ISUID :: 0o004000 /* set user id on execution */ +PERMISSION_MASK_ISGID :: 0o002000 /* set group id on execution */ +PERMISSION_MASK_ISVTX :: 0o001000 /* save swapped text even after use */ + +OPEN_FLAG_RDONLY :: 0x0000 /* open for reading only */ +OPEN_FLAG_WRONLY :: 0x0001 /* open for writing only */ +OPEN_FLAG_RDWR :: 0x0002 /* open for reading and writing */ + +/* mask for above rd/wr/rdwr flags */ +MASK_ACCMODE :: 0x0003 + +OPEN_FLAG_NONBLOCK :: 0x00000004 /* no delay */ +OPEN_FLAG_APPEND :: 0x00000008 /* set append mode */ +OPEN_FLAG_CREAT :: 0x00000200 /* create if nonexistant */ +OPEN_FLAG_TRUNC :: 0x00000400 /* truncate to zero length */ +OPEN_FLAG_EXCL :: 0x00000800 /* error if already exists */ +OPEN_FLAG_SHLOCK :: 0x00000010 /* open with shared file lock */ +OPEN_FLAG_EXLOCK :: 0x00000020 /* open with exclusive file lock */ +OPEN_FLAG_DIRECTORY :: 0x00100000 /* restrict open to only directories */ +OPEN_FLAG_NOFOLLOW :: 0x00000100 /* don't follow symlinks */ +OPEN_FLAG_SYMLINK :: 0x00200000 /* allow open of a symlink */ +OPEN_FLAG_EVTONLY :: 0x00008000 /* descriptor requested for event notifications only */ +OPEN_FLAG_CLOEXEC :: 0x01000000 /* causes the descriptor to be closed if you use any of the exec like functions */ +OPEN_FLAG_NOFOLLOW_ANY :: 0x20000000 /* no symlinks allowed in path */ + +/* bsd/sys/param.h */ +DARWIN_MAXCOMLEN :: 16; + +/*--==========================================================================--*/ + +__darwin_ino64_t :: u64 +__darwin_time_t :: u32 +__darwin_dev_t :: i32 +__darwin_mode_t :: u16 +__darwin_off_t :: i64 +__darwin_blkcnt_t :: i64 +__darwin_blksize_t :: i32 +__darwin_pid_t :: i32 +__darwin_suseconds_t :: i32 + +time_t :: __darwin_time_t +dev_t :: __darwin_dev_t +mode_t :: u16 +nlink_t :: u16 +uid_t :: u16 +gid_t :: u16 +off_t :: __darwin_off_t +blkcnt_t :: __darwin_blkcnt_t +blksize_t :: __darwin_blksize_t +pid_t :: __darwin_pid_t + +stat :: __DARWIN_STRUCT_STAT64 +timeval :: _STRUCT_TIMEVAL + +/*--==========================================================================--*/ + +/* sys/stat.h */ +__DARWIN_STRUCT_STAT64 :: struct { + st_dev: dev_t, /* [XSI] ID of device containing file */ + st_mode: mode_t, /* [XSI] Mode of file (see below) */ + st_nlink: nlink_t, /* [XSI] Number of hard links */ + st_ino: __darwin_ino64_t, /* [XSI] File serial number */ + st_uid_t: uid_t, /* [XSI] User ID of the file */ + st_gid_t: gid_t, /* [XSI] Group ID of the file */ + st_rdev: dev_t, /* [XSI] Device ID */ + + // __DARWIN_STRUCT_STAT64_TIMES + st_atime: time_t, /* [XSI] Time of last access */ + st_atimensec: i32, /* nsec of last access */ + st_mtime: time_t, /* [XSI] Last data modification time */ + st_mtimensec: i32, /* last data modification nsec */ + st_ctime: time_t, /* [XSI] Time of last status change */ + st_ctimensec: u32, /* nsec of last status change */ + st_birthtime: time_t, /* File creation time(birth) */ + st_birthtimensec: i32, /* nsec of File creation time */ + // end __DARWIN_STRUCT_STAT64_TIMES + + st_size: off_t, /* [XSI] file size, in bytes */ + st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ + st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_flags: u32, /* user defined flags for file */ + st_gen: u32, /* file generation number */ + st_lspare: i32, /* RESERVED: DO NOT USE! */ + st_qspare: [2]i64, /* RESERVED: DO NOT USE! */ +} + +/* sys/_types/_timeval.h */ +_STRUCT_TIMEVAL :: struct { + tv_sec: __darwin_time_t, /* seconds */ + tv_usec: __darwin_suseconds_t, /* microseconds */ +}; + +/* pwd.h */ +_Password_Entry :: struct { + pw_name: cstring, /* username */ + pw_passwd: cstring, /* user password */ + pw_uid: i32, /* user ID */ + pw_gid: i32, /* group ID */ + pw_change: u64, /* password change time */ + pw_class: cstring, /* user access class */ + pw_gecos: cstring, /* full user name */ + pw_dir: cstring, /* home directory */ + pw_shell: cstring, /* shell program */ + pw_expire: u64, /* account expiration */ + pw_fields: i32, /* filled fields */ +}; + +/* processinfo.h */ +_Proc_Bsdinfo :: struct { + pbi_flags: u32, /* if is 64bit; emulated etc */ + pbi_status: u32, + pbi_xstatus: u32, + pbi_pid: u32, + pbi_ppid: u32, + pbi_uid: u32, + pbi_gid: u32, + pbi_ruid: u32, + pbi_rgid: u32, + pbi_svuid: u32, + pbi_svgid: u32, + res: u32, + pbi_comm: [DARWIN_MAXCOMLEN]u8, + pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */ + pbi_nfiles: u32, + pbi_pgid: u32, + pbi_pjobc: u32, + e_tdev: u32, /* controlling tty dev */ + e_tpgid: u32, /* tty process group id */ + pbi_nice: i32, + pbi_start_tvsec: u64, + pbi_start_tvusec: u64, +}; + +/*--==========================================================================--*/ + +syscall_fsync :: #force_inline proc(fildes: c.int) -> bool { + return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.fsync), uintptr(fildes))) +} + +syscall_write :: #force_inline proc (fildes: c.int, buf: ^byte, nbyte: u64) -> bool { + return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.write), uintptr(fildes), uintptr(buf), uintptr(nbyte))) +} + +syscall_read :: #force_inline proc(fildes: c.int, buf: ^byte, nbyte: u64) -> i64 { + return cast(i64)intrinsics.syscall(unix_offset_syscall(.read), uintptr(fildes), uintptr(buf), uintptr(nbyte)) +} + +syscall_open :: #force_inline proc(path: cstring, oflag: u32, mode: u32) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.open), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) +} + +syscall_close :: #force_inline proc(fd: c.int) -> bool { + return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.close), uintptr(fd))) +} + +syscall_fchmod :: #force_inline proc(fildes: c.int, mode: u32) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.fchmod), uintptr(fildes), uintptr(mode))) +} + +syscall_chmod :: #force_inline proc(path: cstring, mode: u32) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.chmod), transmute(uintptr)path, uintptr(mode))) +} + +syscall_mkdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), transmute(uintptr)path, uintptr(mode))) +} + +syscall_mkdir_at :: #force_inline proc(fd: c.int, path: cstring, mode: u32) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), uintptr(fd), transmute(uintptr)path, uintptr(mode))) +} + +syscall_rmdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rmdir), transmute(uintptr)path, uintptr(mode))) +} + +syscall_rename :: #force_inline proc(path_old: cstring, path_new: cstring) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rename), transmute(uintptr)path_old, transmute(uintptr)path_new)) +} + +syscall_rename_at :: #force_inline proc(from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.renameat), uintptr(from_fd), transmute(uintptr)from, uintptr(to_fd), transmute(uintptr)to)) +} + +syscall_lseek :: #force_inline proc(fd: c.int, offset: i64, whence: c.int) -> i64 { + return cast(i64)intrinsics.syscall(unix_offset_syscall(.lseek), uintptr(fd), uintptr(offset), uintptr(whence)) +} + +syscall_gettid :: #force_inline proc() -> u64 { + return cast(u64)intrinsics.syscall(unix_offset_syscall(.gettid)) +} + +syscall_fstat :: #force_inline proc(fd: c.int, status: ^stat) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstat), uintptr(fd), uintptr(status)) +} + +syscall_lstat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.lstat), transmute(uintptr)path, uintptr(status)) +} + +syscall_stat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.stat), transmute(uintptr)path, uintptr(status)) +} + +syscall_fstatat :: #force_inline proc(fd: c.int, path: cstring, status: ^stat) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstatat), uintptr(fd), transmute(uintptr)path, uintptr(status)) +} + +syscall_link :: #force_inline proc(path: cstring, to_link: cstring) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.link), transmute(uintptr)path, transmute(uintptr)to_link) +} + +syscall_linkat :: #force_inline proc(fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.linkat), uintptr(fd), transmute(uintptr)path, uintptr(fd2), transmute(uintptr)to_link) +} + +syscall_readlink :: #force_inline proc(path: cstring, buf: ^u8, buf_size: u64) -> i64 { + return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlink), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) +} + +syscall_readlinkat :: #force_inline proc(fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 { + return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlinkat), uintptr(fd), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) +} + +syscall_access :: #force_inline proc(path: cstring, mode: c.int) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.access), transmute(uintptr)path, uintptr(mode)) +} + +syscall_faccessat :: #force_inline proc(fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.faccessat), uintptr(fd), transmute(uintptr)path, uintptr(mode), uintptr(flag)) +} + +syscall_getdirentries :: #force_inline proc(fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getdirentries), uintptr(fd), uintptr(buf), uintptr(nbytes), uintptr(base_pointer)) +} + +syscall_truncate :: #force_inline proc (path: cstring, length: off_t) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.truncate), transmute(uintptr)path, uintptr(length)) +} + +syscall_ftruncate :: #force_inline proc (fd: c.int, length: off_t) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.ftruncate), uintptr(fd), uintptr(length)) +} + +syscall_sysctl :: #force_inline proc (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctl), uintptr(name), uintptr(namelen), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) +} + +syscall_copyfile :: #force_inline proc(from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.copyfile), transmute(uintptr)from, transmute(uintptr)to, uintptr(state), uintptr(flags)) +} + +// think about this? last arg should be more than one +syscall_fcntl :: #force_inline proc(fd: c.int, cmd: c.int, other: rawptr) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fsctl), uintptr(fd), uintptr(cmd), uintptr(other)) +} + +syscall_exit :: #force_inline proc(code: c.int) { + intrinsics.syscall(unix_offset_syscall(.exit), uintptr(code)) +} + +syscall_kill :: #force_inline proc(pid: pid_t, sig: c.int) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.kill), uintptr(pid), uintptr(sig)) +} + +syscall_dup :: #force_inline proc(fd: c.int) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.dup), uintptr(fd)) +} + +syscall_execve :: #force_inline proc(path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.execve), transmute(uintptr)path, transmute(uintptr)argv, transmute(uintptr)env) +} + +syscall_munmap :: #force_inline proc(addr: rawptr, len: u64) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len)) +} + +syscall_mmap :: #force_inline proc(addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 { + return cast(^u8)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len), uintptr(port), uintptr(flags), uintptr(fd), uintptr(offset)) +} + +syscall_flock :: #force_inline proc(fd: c.int, operation: c.int) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.flock), uintptr(fd), uintptr(operation)) +} + +syscall_utimes :: #force_inline proc(path: cstring, times: ^timeval) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.utimes), transmute(uintptr)path, uintptr(times)) +} + +syscall_futimes :: #force_inline proc(fd: c.int, times: ^timeval) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.futimes), uintptr(fd), uintptr(times)) +} + +syscall_adjtime :: #force_inline proc(delta: ^timeval, old_delta: ^timeval) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.adjtime), uintptr(delta), uintptr(old_delta)) +} + +syscall_sysctlbyname :: #force_inline proc(name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctlbyname), transmute(uintptr)name, uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) +} + +syscall_proc_info :: #force_inline proc(num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.proc_info), uintptr(num), uintptr(pid), uintptr(flavor), uintptr(arg), uintptr(buffer), uintptr(buffer_size)) +} + +syscall_openat :: #force_inline proc(fd: int, path: cstring, oflag: u32, mode: u32) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.openat), uintptr(fd), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) +} + +syscall_getentropy :: #force_inline proc(buf: ^u8, buflen: u64) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(buf), uintptr(buflen)) +} + +syscall_pipe :: #force_inline proc(fds: [^]c.int) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(&fds[0]), uintptr(&fds[1])) +} + +syscall_chdir :: #force_inline proc(path: cstring) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), transmute(uintptr)path) +} + +syscall_fchdir :: #force_inline proc(fd: c.int, path: cstring) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(fd), transmute(uintptr)path) +} \ No newline at end of file From ab3bae5c0265f653c51eebaafdc17f0e16dccb8f Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sun, 23 Jan 2022 23:14:46 +0100 Subject: [PATCH 0030/1052] Fixed package name --- core/sys/darwin/xnu_system_call_helpers.odin | 2 +- core/sys/darwin/xnu_system_call_numbers.odin | 2 +- core/sys/darwin/xnu_system_call_wrappers.odin | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin index eabbb73df..d6bf9fd62 100644 --- a/core/sys/darwin/xnu_system_call_helpers.odin +++ b/core/sys/darwin/xnu_system_call_helpers.odin @@ -1,4 +1,4 @@ -package sys +package darwin import "core:strings" import "core:c" diff --git a/core/sys/darwin/xnu_system_call_numbers.odin b/core/sys/darwin/xnu_system_call_numbers.odin index 4aba8a830..b90373fdc 100644 --- a/core/sys/darwin/xnu_system_call_numbers.odin +++ b/core/sys/darwin/xnu_system_call_numbers.odin @@ -1,4 +1,4 @@ -package sys +package darwin unix_offset_syscall :: proc(number: System_Call_Number) -> uintptr { return uintptr(number) + uintptr(0x2000000) diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index a584299f8..4cf86862f 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -1,4 +1,4 @@ -package sys +package darwin import "core:c" import "core:intrinsics" From 1243b1a58c5a15aab7a5272e73bfaa6aa6b79ce7 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sun, 23 Jan 2022 23:16:57 +0100 Subject: [PATCH 0031/1052] Fixed cyclic imports which where not needed --- core/sys/darwin/xnu_system_call_helpers.odin | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin index d6bf9fd62..f9844a73f 100644 --- a/core/sys/darwin/xnu_system_call_helpers.odin +++ b/core/sys/darwin/xnu_system_call_helpers.odin @@ -2,8 +2,6 @@ package darwin import "core:strings" import "core:c" -import "core:os" -import "core:fmt" // this package uses the sys prefix for the proc names to indicate that these aren't native syscalls but directly call such sys_write_string :: proc (fd: c.int, message: string) -> bool { From 42ab882db4a6d5765c68021ade010b468ff4531e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jan 2022 15:56:26 +0000 Subject: [PATCH 0032/1052] Remove debug code --- src/check_expr.cpp | 1 - src/checker.cpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 81f69055a..1742ef2d8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3419,7 +3419,6 @@ void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_typ if (operand->value.kind == ExactValue_String) { String key = operand->value.value_string; if (is_type_string(operand->type) && is_type_enum(target_type)) { - gb_printf_err("HERE!\n"); Type *et = base_type(target_type); check_did_you_mean_type(key, et->Enum.fields, "."); } diff --git a/src/checker.cpp b/src/checker.cpp index 55a3892e5..b81d9987b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1618,9 +1618,6 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) { // NOTE(bill): map entries grow linearly and in order ti_index = c->info->type_info_types.count; array_add(&c->info->type_info_types, t); - if (t->kind == Type_Named && t->Named.name == "A") { - gb_printf_err("HERE!\n"); - } } map_set(&c->checker->info.type_info_map, t, ti_index); From f20105ddfee6d9a2aa02452e459c42c7f0310e76 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jan 2022 23:07:06 +0000 Subject: [PATCH 0033/1052] Update docs for packages fmt and io --- core/fmt/fmt.odin | 33 +++++++++++++++++++++++++++------ core/fmt/fmt_js.odin | 7 ++++++- core/fmt/fmt_os.odin | 10 +++++++++- core/io/io.odin | 41 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 2cc192c12..932fc0bb8 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -11,6 +11,7 @@ import "core:time" import "core:unicode/utf8" import "core:intrinsics" +// Internal data structure that stores the required information for formatted printing Info :: struct { minus: bool, plus: bool, @@ -46,9 +47,13 @@ Register_User_Formatter_Error :: enum { // it is prefixed with `_` rather than marked with a private attribute so that users can access it if necessary _user_formatters: ^map[typeid]User_Formatter +// set_user_formatters assigns m to a global value allowing the user have custom print formatting for specific +// types set_user_formatters :: proc(m: ^map[typeid]User_Formatter) { _user_formatters = m } +// register_user_formatter assigns a formatter to a specific typeid. set_user_formatters must be called +// before any use of this procedure. register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Register_User_Formatter_Error { if _user_formatters == nil { return .No_User_Formatter @@ -61,7 +66,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist } -// aprint* procedures return a string that was allocated with the current context +// aprint procedure return a string that was allocated with the current context // They must be freed accordingly aprint :: proc(args: ..any, sep := " ") -> string { str: strings.Builder @@ -69,12 +74,16 @@ aprint :: proc(args: ..any, sep := " ") -> string { sbprint(buf=&str, args=args, sep=sep) return strings.to_string(str) } +// aprintln procedure return a string that was allocated with the current context +// They must be freed accordingly aprintln :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.init_builder(&str) sbprintln(buf=&str, args=args, sep=sep) return strings.to_string(str) } +// aprintf procedure return a string that was allocated with the current context +// They must be freed accordingly aprintf :: proc(fmt: string, args: ..any) -> string { str: strings.Builder strings.init_builder(&str) @@ -83,19 +92,21 @@ aprintf :: proc(fmt: string, args: ..any) -> string { } -// tprint* procedures return a string that was allocated with the current context's temporary allocator +// tprint procedure return a string that was allocated with the current context's temporary allocator tprint :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.init_builder(&str, context.temp_allocator) sbprint(buf=&str, args=args, sep=sep) return strings.to_string(str) } +// tprintln procedure return a string that was allocated with the current context's temporary allocator tprintln :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.init_builder(&str, context.temp_allocator) sbprintln(buf=&str, args=args, sep=sep) return strings.to_string(str) } +// tprintf procedure return a string that was allocated with the current context's temporary allocator tprintf :: proc(fmt: string, args: ..any) -> string { str: strings.Builder strings.init_builder(&str, context.temp_allocator) @@ -104,21 +115,24 @@ tprintf :: proc(fmt: string, args: ..any) -> string { } -// bprint* procedures return a string using a buffer from an array +// bprint procedures return a string using a buffer from an array bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { sb := strings.builder_from_slice(buf[0:len(buf)]) return sbprint(buf=&sb, args=args, sep=sep) } +// bprintln procedures return a string using a buffer from an array bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string { sb := strings.builder_from_slice(buf[0:len(buf)]) return sbprintln(buf=&sb, args=args, sep=sep) } +// bprintf procedures return a string using a buffer from an array bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string { sb := strings.builder_from_slice(buf[0:len(buf)]) return sbprintf(&sb, fmt, ..args) } +// formatted assert assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_location) -> bool { if !condition { p := context.assertion_failure_proc @@ -131,6 +145,7 @@ assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_locati return condition } +// formatted panic panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { p := context.assertion_failure_proc if p == nil { @@ -142,24 +157,26 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { - - +// sbprint formats using the default print settings and writes to buf sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { wprint(w=strings.to_writer(buf), args=args, sep=sep) return strings.to_string(buf^) } +// sbprintln formats using the default print settings and writes to buf sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { wprintln(w=strings.to_writer(buf), args=args, sep=sep) return strings.to_string(buf^) } +// sbprintf formats according to the specififed format string and writes to buf sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string { wprintf(w=strings.to_writer(buf), fmt=fmt, args=args) return strings.to_string(buf^) } +// wprint formats using the default print settings and writes to w wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int { fi: Info fi.writer = w @@ -194,6 +211,7 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int { return int(size1 - size0) } +// wprintln formats using the default print settings and writes to w wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int { fi: Info fi.writer = w @@ -214,6 +232,7 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int { return int(size1 - size0) } +// wprintf formats according to the specififed format string and writes to w wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi: Info arg_index: int = 0 @@ -493,11 +512,13 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { return int(size1 - size0) } +// wprint_type is a utility procedure to write a ^runtime.Type_Info value to w wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) { n, err := reflect.write_type(w, info) io.flush(auto_cast w) return n, err } +// wprint_typeid is a utility procedure to write a typeid value to w wprint_typeid :: proc(w: io.Writer, id: typeid) -> (int, io.Error) { n, err := reflect.write_type(w, type_info_of(id)) io.flush(auto_cast w) @@ -829,7 +850,7 @@ _pad :: proc(fi: ^Info, s: string) { fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { switch verb { - case 'f', 'F', 'v': + case 'f', 'F', 'g', 'G', 'v': prec: int = 3 if fi.prec_set { prec = fi.prec diff --git a/core/fmt/fmt_js.odin b/core/fmt/fmt_js.odin index bcd9688a1..7a9876127 100644 --- a/core/fmt/fmt_js.odin +++ b/core/fmt/fmt_js.odin @@ -34,11 +34,16 @@ stderr := io.Writer{ }, } -// print* procedures return the number of bytes written +// print formats using the default print settings and writes to stdout print :: proc(args: ..any, sep := " ") -> int { return wprint(w=stdout, args=args, sep=sep) } +// println formats using the default print settings and writes to stdout println :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stdout, args=args, sep=sep) } +// printf formats according to the specififed format string and writes to stdout printf :: proc(fmt: string, args: ..any) -> int { return wprintf(stdout, fmt, ..args) } +// eprint formats using the default print settings and writes to stderr eprint :: proc(args: ..any, sep := " ") -> int { return wprint(w=stderr, args=args, sep=sep) } +// eprintln formats using the default print settings and writes to stderr eprintln :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stderr, args=args, sep=sep) } +// eprintf formats according to the specififed format string and writes to stderr eprintf :: proc(fmt: string, args: ..any) -> int { return wprintf(stderr, fmt, ..args) } diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin index 7434d939d..f5c8d75bd 100644 --- a/core/fmt/fmt_os.odin +++ b/core/fmt/fmt_os.odin @@ -5,15 +5,18 @@ import "core:runtime" import "core:os" import "core:io" +// fprint formats using the default print settings and writes to fd fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int { w := io.to_writer(os.stream_from_handle(fd)) return wprint(w=w, args=args, sep=sep) } +// fprintln formats using the default print settings and writes to fd fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int { w := io.to_writer(os.stream_from_handle(fd)) return wprintln(w=w, args=args, sep=sep) } +// fprintf formats according to the specififed format string and writes to fd fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { w := io.to_writer(os.stream_from_handle(fd)) return wprintf(w, fmt, ..args) @@ -27,11 +30,16 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) { return wprint_typeid(w, id) } -// print* procedures return the number of bytes written +// print formats using the default print settings and writes to os.stdout print :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) } +// println formats using the default print settings and writes to os.stdout println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) } +// printf formats according to the specififed format string and writes to os.stdout printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) } +// eprint formats using the default print settings and writes to os.stderr eprint :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) } +// eprintln formats using the default print settings and writes to os.stderr eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) } +// eprintf formats according to the specififed format string and writes to os.stderr eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) } diff --git a/core/io/io.odin b/core/io/io.odin index b4757f8e5..e9d839efb 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -1,9 +1,13 @@ +// package io provides basic interfaces for generic data stream primitives. +// The purpose of this package is wrap existing data structures and their +// operations into an abstracted stream interface. package io import "core:intrinsics" import "core:runtime" import "core:unicode/utf8" +// Seek whence values Seek_From :: enum { Start = 0, // seek relative to the origin of the file Current = 1, // seek relative to the current offset @@ -139,6 +143,10 @@ destroy :: proc(s: Stream) -> Error { return .Empty } +// read reads up to len(p) bytes into s. It returns the number of bytes read and any error if occurred. +// +// When read encounters an .EOF or error after successfully reading n > 0 bytes, it returns the number of +// bytes read along with the error. read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) { if s.stream_vtable != nil && s.impl_read != nil { n, err = s->impl_read(p) @@ -150,6 +158,7 @@ read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) { return 0, .Empty } +// write writes up to len(p) bytes into s. It returns the number of bytes written and any error if occurred. write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) { if s.stream_vtable != nil && s.impl_write != nil { n, err = s->impl_write(p) @@ -161,6 +170,13 @@ write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Erro return 0, .Empty } +// seek sets the offset of the next read or write to offset. +// +// .Start means seek relative to the origin of the file. +// .Current means seek relative to the current offset. +// .End means seek relative to the end. +// +// seek returns the new offset to the start of the file/stream, and any error if occurred. seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { if s.stream_vtable != nil && s.impl_seek != nil { return s->impl_seek(offset, whence) @@ -168,6 +184,8 @@ seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error) return 0, .Empty } +// The behaviour of close after the first call is stream implementation defined. +// Different streams may document their own behaviour. close :: proc(s: Closer) -> Error { if s.stream_vtable != nil && s.impl_close != nil { return s->impl_close() @@ -184,6 +202,7 @@ flush :: proc(s: Flusher) -> Error { return .None } +// size returns the size of the stream. If the stream does not support querying its size, 0 will be returned. size :: proc(s: Stream) -> i64 { if s.stream_vtable == nil { return 0 @@ -214,7 +233,12 @@ size :: proc(s: Stream) -> i64 { - +// read_at reads len(p) bytes into p starting with the provided offset in the underlying Reader_At stream r. +// It returns the number of bytes read and any error if occurred. +// +// When read_at returns n < len(p), it returns a non-nil Error explaining why. +// +// If n == len(p), err may be either nil or .EOF read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: int, err: Error) { defer if n_read != nil { n_read^ += n @@ -245,6 +269,11 @@ read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: } +// write_at writes len(p) bytes into p starting with the provided offset in the underlying Writer_At stream w. +// It returns the number of bytes written and any error if occurred. +// +// If write_at is writing to a Writer_At which has a seek offset, then write_at should not affect the underlying +// seek offset. write_at :: proc(w: Writer_At, p: []byte, offset: i64, n_written: ^int = nil) -> (n: int, err: Error) { defer if n_written != nil { n_written^ += n @@ -294,6 +323,7 @@ read_from :: proc(w: Reader_From, r: Reader) -> (n: i64, err: Error) { } +// read_byte reads and returns the next byte from r. read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) { defer if err == nil && n_read != nil { n_read^ += 1 @@ -347,6 +377,7 @@ _write_byte :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> (err: Err return err } +// read_rune reads a single UTF-8 encoded Unicode codepoint and returns the rune and its size in bytes. read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) { defer if err == nil && n_read != nil { n_read^ += size @@ -405,10 +436,12 @@ unread_rune :: proc(s: Rune_Scanner) -> Error { } +// write_string writes the contents of the string s to w. write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, err: Error) { return write(s, transmute([]byte)str, n_written) } +// write_rune writes a UTF-8 encoded rune to w. write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) { defer if err == nil && n_written != nil { n_written^ += size @@ -430,12 +463,16 @@ write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err } - +// read_full expected exactly len(buf) bytes from r into buf. read_full :: proc(r: Reader, buf: []byte) -> (n: int, err: Error) { return read_at_least(r, buf, len(buf)) } +// read_at_least reads from r into buf until it has read at least min bytes. It returns the number +// of bytes copied and an error if fewer bytes were read. `.EOF` is only returned if no bytes were read. +// `.Unexpected_EOF` is returned when an `.EOF ` is returned by the passed Reader after reading +// fewer than min bytes. If len(buf) is less than min, `.Short_Buffer` is returned. read_at_least :: proc(r: Reader, buf: []byte, min: int) -> (n: int, err: Error) { if len(buf) < min { return 0, .Short_Buffer From fe0b5bf4e27912c49f6c5eab817cbf514b0b22e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jan 2022 23:28:59 +0000 Subject: [PATCH 0034/1052] Parse comments on enums fields --- src/check_expr.cpp | 7 +++++++ src/check_type.cpp | 23 ++++++++++++----------- src/docs_writer.cpp | 11 ++++++----- src/entity.cpp | 2 ++ src/parser.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- src/parser.hpp | 6 ++++++ 6 files changed, 74 insertions(+), 17 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1742ef2d8..725b57f33 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9341,6 +9341,13 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { str = gb_string_appendc(str, " = "); str = write_expr_to_string(str, fv->value, shorthand); case_end; + case_ast_node(fv, EnumFieldValue, node); + str = write_expr_to_string(str, fv->name, shorthand); + if (fv->value) { + str = gb_string_appendc(str, " = "); + str = write_expr_to_string(str, fv->value, shorthand); + } + case_end; case_ast_node(ht, HelperType, node); str = gb_string_appendc(str, "#type "); diff --git a/src/check_type.cpp b/src/check_type.cpp index 2a7479d68..a6d82c86e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -732,20 +732,19 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast Ast *ident = nullptr; Ast *init = nullptr; u32 entity_flags = 0; - if (field->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, field); - if (fv->field == nullptr || fv->field->kind != Ast_Ident) { - error(field, "An enum field's name must be an identifier"); - continue; - } - ident = fv->field; - init = fv->value; - } else if (field->kind == Ast_Ident) { - ident = field; - } else { + if (field->kind != Ast_EnumFieldValue) { error(field, "An enum field's name must be an identifier"); continue; } + ident = field->EnumFieldValue.name; + init = field->EnumFieldValue.value; + if (ident == nullptr || ident->kind != Ast_Ident) { + error(field, "An enum field's name must be an identifier"); + continue; + } + CommentGroup *docs = field->EnumFieldValue.docs; + CommentGroup *comment = field->EnumFieldValue.comment; + String name = ident->Ident.token.string; if (init != nullptr) { @@ -803,6 +802,8 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast e->flags |= EntityFlag_Visited; e->state = EntityState_Resolved; e->Constant.flags |= entity_flags; + e->Constant.docs = docs; + e->Constant.comment = comment; if (scope_lookup_current(ctx->scope, name) != nullptr) { error(ident, "'%.*s' is already declared in this enumeration", LIT(name)); diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 825ca113f..b1b9450df 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -811,11 +811,12 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { comment = e->decl_info->comment; docs = e->decl_info->docs; } - if (!comment && e->kind == Entity_Variable) { - comment = e->Variable.comment; - } - if (!docs && e->kind == Entity_Variable) { - docs = e->Variable.docs; + if (e->kind == Entity_Variable) { + if (!comment) { comment = e->Variable.comment; } + if (!docs) { docs = e->Variable.docs; } + } else if (e->kind == Entity_Constant) { + if (!comment) { comment = e->Constant.comment; } + if (!docs) { docs = e->Constant.docs; } } String link_name = {}; diff --git a/src/entity.cpp b/src/entity.cpp index 0f8bfa456..a0438a9f4 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -161,6 +161,8 @@ struct Entity { ParameterValue param_value; u32 flags; i32 field_group_index; + CommentGroup *docs; + CommentGroup *comment; } Constant; struct { Ast *init_expr; // only used for some variables within procedure bodies diff --git a/src/parser.cpp b/src/parser.cpp index 076c698ff..ebe65cee1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -693,6 +693,16 @@ Ast *ast_field_value(AstFile *f, Ast *field, Ast *value, Token eq) { return result; } + +Ast *ast_enum_field_value(AstFile *f, Ast *name, Ast *value, CommentGroup *docs, CommentGroup *comment) { + Ast *result = alloc_ast_node(f, Ast_EnumFieldValue); + result->EnumFieldValue.name = name; + result->EnumFieldValue.value = value; + result->EnumFieldValue.docs = docs; + result->EnumFieldValue.comment = comment; + return result; +} + Ast *ast_compound_lit(AstFile *f, Ast *type, Array const &elems, Token open, Token close) { Ast *result = alloc_ast_node(f, Ast_CompoundLit); result->CompoundLit.type = type; @@ -1689,6 +1699,36 @@ Array parse_element_list(AstFile *f) { return elems; } +Array parse_enum_field_list(AstFile *f) { + auto elems = array_make(heap_allocator()); + + while (f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { + CommentGroup *docs = f->lead_comment; + CommentGroup *comment = nullptr; + Ast *name = parse_value(f); + Ast *value = nullptr; + if (f->curr_token.kind == Token_Eq) { + Token eq = expect_token(f, Token_Eq); + value = parse_value(f); + } + + comment = f->line_comment; + + Ast *elem = ast_enum_field_value(f, name, value, docs, comment); + array_add(&elems, elem); + + if (!allow_token(f, Token_Comma)) { + break; + } + + if (!elem->EnumFieldValue.comment) { + elem->EnumFieldValue.comment = f->line_comment; + } + } + + return elems; +} Ast *parse_literal_value(AstFile *f, Ast *type) { Array elems = {}; @@ -2449,7 +2489,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { skip_possible_newline_for_literal(f); Token open = expect_token(f, Token_OpenBrace); - Array values = parse_element_list(f); + Array values = parse_enum_field_list(f); Token close = expect_closing_brace_of_field_list(f); return ast_enum_type(f, token, base_type, values); diff --git a/src/parser.hpp b/src/parser.hpp index b83822cbf..b005a4465 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -383,6 +383,12 @@ AST_KIND(_ExprBegin, "", bool) \ void *sce_temp_data; \ }) \ AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \ + AST_KIND(EnumFieldValue, "enum field value", struct { \ + Ast *name; \ + Ast *value; \ + CommentGroup *docs; \ + CommentGroup *comment; \ + }) \ AST_KIND(TernaryIfExpr, "ternary if expression", struct { Ast *x, *cond, *y; }) \ AST_KIND(TernaryWhenExpr, "ternary when expression", struct { Ast *x, *cond, *y; }) \ AST_KIND(OrElseExpr, "or_else expression", struct { Ast *x; Token token; Ast *y; }) \ From c0479f1564119603f022f5f3d22dd8dc3a1e5983 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jan 2022 23:42:04 +0000 Subject: [PATCH 0035/1052] Handle line comment better --- src/parser.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index ebe65cee1..108411cd0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1244,7 +1244,7 @@ CommentGroup *consume_comment_group(AstFile *f, isize n, isize *end_line_) { return comments; } -void comsume_comment_groups(AstFile *f, Token prev) { +void consume_comment_groups(AstFile *f, Token prev) { if (f->curr_token.kind == Token_Comment) { CommentGroup *comment = nullptr; isize end_line = 0; @@ -1288,7 +1288,7 @@ Token advance_token(AstFile *f) { if (ok) { switch (f->curr_token.kind) { case Token_Comment: - comsume_comment_groups(f, prev); + consume_comment_groups(f, prev); break; case Token_Semicolon: if (ignore_newlines(f) && f->curr_token.string == "\n") { @@ -1699,6 +1699,16 @@ Array parse_element_list(AstFile *f) { return elems; } +CommentGroup *consume_line_comment(AstFile *f) { + CommentGroup *comment = f->line_comment; + if (f->line_comment == f->lead_comment) { + f->lead_comment = nullptr; + } + f->line_comment = nullptr; + return comment; + +} + Array parse_enum_field_list(AstFile *f) { auto elems = array_make(heap_allocator()); @@ -1713,7 +1723,7 @@ Array parse_enum_field_list(AstFile *f) { value = parse_value(f); } - comment = f->line_comment; + comment = consume_line_comment(f); Ast *elem = ast_enum_field_value(f, name, value, docs, comment); array_add(&elems, elem); @@ -1723,7 +1733,7 @@ Array parse_enum_field_list(AstFile *f) { } if (!elem->EnumFieldValue.comment) { - elem->EnumFieldValue.comment = f->line_comment; + elem->EnumFieldValue.comment = consume_line_comment(f); } } @@ -5438,7 +5448,7 @@ bool parse_file(Parser *p, AstFile *f) { String filepath = f->tokenizer.fullpath; String base_dir = dir_from_path(filepath); if (f->curr_token.kind == Token_Comment) { - comsume_comment_groups(f, f->prev_token); + consume_comment_groups(f, f->prev_token); } CommentGroup *docs = f->lead_comment; From 65f8722afc0680b7b7fa47fd7060fd434243ae3c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 25 Jan 2022 12:18:10 +0100 Subject: [PATCH 0036/1052] zlib: update Huffman builder. --- core/compress/zlib/zlib.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index 9ae980042..4d575c7e6 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -111,9 +111,9 @@ ZFAST_MASK :: ((1 << ZFAST_BITS) - 1) */ Huffman_Table :: struct { fast: [1 << ZFAST_BITS]u16, - firstcode: [16]u16, + firstcode: [17]u16, maxcode: [17]int, - firstsymbol: [16]u16, + firstsymbol: [17]u16, size: [288]u8, value: [288]u16, } @@ -244,7 +244,7 @@ allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_T @(optimization_mode="speed") build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) { sizes: [HUFFMAN_MAX_BITS+1]int - next_code: [HUFFMAN_MAX_BITS]int + next_code: [HUFFMAN_MAX_BITS+1]int k := int(0) @@ -256,14 +256,14 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) { } sizes[0] = 0 - for i in 1..<(HUFFMAN_MAX_BITS+1) { + for i in 1 ..< HUFFMAN_MAX_BITS { if sizes[i] > (1 << uint(i)) { return E_Deflate.Huffman_Bad_Sizes } } code := int(0) - for i in 1.. Date: Tue, 25 Jan 2022 12:39:06 +0000 Subject: [PATCH 0037/1052] Disable early return from `check_proc_info` --- src/checker.cpp | 13 +++++++------ src/llvm_backend_proc.cpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index b81d9987b..9be64e369 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4855,12 +4855,13 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc return false; } - if (pt->is_polymorphic && pt->is_poly_specialized) { - if ((e->flags & EntityFlag_Used) == 0) { - // NOTE(bill, 2019-08-31): It was never used, don't check - return false; - } - } + // NOTE(bill, 2022-01-25): Appears to be not needed any more + // if (pt->is_polymorphic && pt->is_poly_specialized) { + // if ((e->flags & EntityFlag_Used) == 0) { + // // NOTE(bill, 2019-08-31): It was never used, don't check + // return false; + // } + // } bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0; bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b35c6c304..9f9fe7c7a 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -61,7 +61,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) GB_ASSERT(entity != nullptr); GB_ASSERT(entity->kind == Entity_Procedure); if (!entity->Procedure.is_foreign) { - GB_ASSERT(entity->flags & EntityFlag_ProcBodyChecked); + GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s", LIT(entity->token.string), type_to_string(entity->type)); } String link_name = {}; From a3e7b2baa1ede7ba328a9ec6b249051347ef4cae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jan 2022 12:42:45 +0000 Subject: [PATCH 0038/1052] Revert change --- src/checker.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index 9be64e369..b81d9987b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4855,13 +4855,12 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc return false; } - // NOTE(bill, 2022-01-25): Appears to be not needed any more - // if (pt->is_polymorphic && pt->is_poly_specialized) { - // if ((e->flags & EntityFlag_Used) == 0) { - // // NOTE(bill, 2019-08-31): It was never used, don't check - // return false; - // } - // } + if (pt->is_polymorphic && pt->is_poly_specialized) { + if ((e->flags & EntityFlag_Used) == 0) { + // NOTE(bill, 2019-08-31): It was never used, don't check + return false; + } + } bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0; bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; From f16f1d932ef36c67dab0b7c8cd6898f9811d6f75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jan 2022 14:24:15 +0000 Subject: [PATCH 0039/1052] Fix #1448 --- src/check_expr.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 725b57f33..276e9d0bb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5755,8 +5755,12 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type ctx.curr_proc_sig = e->type; GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); + bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); decl->where_clauses_evaluated = true; + + if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { + check_procedure_later(c, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + } } return data; } @@ -5769,6 +5773,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type Entity *e = entity_of_node(ident); + CallArgumentData data = {}; CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data); gb_unused(err); @@ -5777,7 +5782,6 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type if (entity_to_use != nullptr) { update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); } - if (data.gen_entity != nullptr) { Entity *e = data.gen_entity; DeclInfo *decl = data.gen_entity->decl_info; @@ -5789,8 +5793,12 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type ctx.curr_proc_sig = e->type; GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); + bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); decl->where_clauses_evaluated = true; + + if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { + check_procedure_later(c, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + } } return data; } From dd3322ac1fb139b639306831849d0264dcd13d6c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jan 2022 14:34:48 +0000 Subject: [PATCH 0040/1052] Update all_main.odin to include all the crypto packages --- examples/all/all_main.odin | 81 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index c24238602..199f406f7 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -5,25 +5,66 @@ package all import bufio "core:bufio" import bytes "core:bytes" + import c "core:c" import libc "core:c/libc" + import compress "core:compress" import gzip "core:compress/gzip" import zlib "core:compress/zlib" + import container "core:container" +import bit_array "core:container/bit_array" +import priority_queue "core:container/priority_queue" +import queue "core:container/queue" +import small_array "core:container/queue" + +import crypto "core:crypto" +import blake "core:crypto/blake" +import blake2b "core:crypto/blake2b" +import blake2s "core:crypto/blake2s" +import chacha20 "core:crypto/chacha20" +import chacha20poly1305 "core:crypto/chacha20poly1305" +import gost "core:crypto/gost" +import groestl "core:crypto/groestl" +import haval "core:crypto/haval" +import jh "core:crypto/jh" +import keccak "core:crypto/keccak" +import md2 "core:crypto/md2" +import md4 "core:crypto/md4" +import md5 "core:crypto/md5" +import poly1305 "core:crypto/poly1305" +import ripemd "core:crypto/ripemd" +import sha1 "core:crypto/sha1" +import sha2 "core:crypto/sha2" +import sha3 "core:crypto/sha3" +import shake "core:crypto/shake" +import sm3 "core:crypto/sm3" +import streebog "core:crypto/streebog" +import tiger "core:crypto/tiger" +import tiger2 "core:crypto/tiger2" +import crypto_util "core:crypto/util" +import whirlpool "core:crypto/whirlpool" +import x25519 "core:crypto/x25519" + import dynlib "core:dynlib" + import encoding "core:encoding" import base32 "core:encoding/base32" import base64 "core:encoding/base64" import csv "core:encoding/csv" import hxa "core:encoding/hxa" import json "core:encoding/json" + import fmt "core:fmt" import hash "core:hash" + import image "core:image" import png "core:image/png" + import io "core:io" import log "core:log" + import math "core:math" import big "core:math/big" import bits "core:math/bits" @@ -32,16 +73,22 @@ import linalg "core:math/linalg" import glm "core:math/linalg/glsl" import hlm "core:math/linalg/hlsl" import rand "core:math/rand" + import mem "core:mem" +// import virtual "core:mem/virtual" + import ast "core:odin/ast" import doc_format "core:odin/doc-format" import odin_format "core:odin/format" import odin_parser "core:odin/parser" import odin_printer "core:odin/printer" import odin_tokenizer "core:odin/tokenizer" + import os "core:os" + import slashpath "core:path/slashpath" import filepath "core:path/filepath" + import reflect "core:reflect" import runtime "core:runtime" import slice "core:slice" @@ -50,9 +97,11 @@ import strconv "core:strconv" import strings "core:strings" import sync "core:sync" import sync2 "core:sync/sync2" +import testing "core:testing" import scanner "core:text/scanner" import thread "core:thread" import time "core:time" + import unicode "core:unicode" import utf8 "core:unicode/utf8" import utf16 "core:unicode/utf16" @@ -68,6 +117,37 @@ _ :: compress _ :: gzip _ :: zlib _ :: container +_ :: bit_array +_ :: priority_queue +_ :: queue +_ :: small_array +_ :: crypto +_ :: blake +_ :: blake2b +_ :: blake2s +_ :: chacha20 +_ :: chacha20poly1305 +_ :: gost +_ :: groestl +_ :: haval +_ :: jh +_ :: keccak +_ :: md2 +_ :: md4 +_ :: md5 +_ :: poly1305 +_ :: ripemd +_ :: sha1 +_ :: sha2 +_ :: sha3 +_ :: shake +_ :: sm3 +_ :: streebog +_ :: tiger +_ :: tiger2 +_ :: crypto_util +_ :: whirlpool +_ :: x25519 _ :: dynlib _ :: encoding _ :: base32 @@ -107,6 +187,7 @@ _ :: strconv _ :: strings _ :: sync _ :: sync2 +_ :: testing _ :: scanner _ :: thread _ :: time From 515fd2a228835afa71cefec645b906729cda399e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 25 Jan 2022 17:08:32 +0100 Subject: [PATCH 0041/1052] bit_array: Fix initial size. --- core/container/bit_array/bit_array.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 61f6f86e8..0fa80c623 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -88,7 +88,7 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) - res = Bit_Array{ bias = min_index, } - return res, resize_if_needed(&res, size_in_bits) + return res, resize_if_needed(&res, legs) } /* From 1bf8328606ba83f943eb2568c89dab38b0b1dd94 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jan 2022 16:40:25 +0000 Subject: [PATCH 0042/1052] Strip unneeded semicolons --- core/crypto/blake/blake.odin | 8 ++++---- core/crypto/blake2b/blake2b.odin | 2 +- core/crypto/blake2s/blake2s.odin | 2 +- core/crypto/gost/gost.odin | 2 +- core/crypto/groestl/groestl.odin | 8 ++++---- core/crypto/haval/haval.odin | 30 ++++++++++++++-------------- core/crypto/jh/jh.odin | 8 ++++---- core/crypto/keccak/keccak.odin | 8 ++++---- core/crypto/md2/md2.odin | 2 +- core/crypto/md4/md4.odin | 2 +- core/crypto/md5/md5.odin | 2 +- core/crypto/ripemd/ripemd.odin | 8 ++++---- core/crypto/sha1/sha1.odin | 2 +- core/crypto/sha2/sha2.odin | 8 ++++---- core/crypto/sha3/sha3.odin | 8 ++++---- core/crypto/shake/shake.odin | 4 ++-- core/crypto/sm3/sm3.odin | 2 +- core/crypto/streebog/streebog.odin | 4 ++-- core/crypto/tiger/tiger.odin | 6 +++--- core/crypto/tiger2/tiger2.odin | 6 +++--- core/crypto/whirlpool/whirlpool.odin | 2 +- 21 files changed, 62 insertions(+), 62 deletions(-) diff --git a/core/crypto/blake/blake.odin b/core/crypto/blake/blake.odin index 81924ab1e..5fc0a02b9 100644 --- a/core/crypto/blake/blake.odin +++ b/core/crypto/blake/blake.odin @@ -44,7 +44,7 @@ hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -123,7 +123,7 @@ hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -202,7 +202,7 @@ hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -281,7 +281,7 @@ hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index 6d4689b88..e75d74197 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -46,7 +46,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index ad2e800fd..831335081 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -47,7 +47,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/gost/gost.odin b/core/crypto/gost/gost.odin index eed684f72..1d0274fae 100644 --- a/core/crypto/gost/gost.odin +++ b/core/crypto/gost/gost.odin @@ -41,7 +41,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/groestl/groestl.odin b/core/crypto/groestl/groestl.odin index 5434e31e0..8e5a2440d 100644 --- a/core/crypto/groestl/groestl.odin +++ b/core/crypto/groestl/groestl.odin @@ -44,7 +44,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -123,7 +123,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -202,7 +202,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -281,7 +281,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/core/crypto/haval/haval.odin b/core/crypto/haval/haval.odin index 442a348e9..811ecf95d 100644 --- a/core/crypto/haval/haval.odin +++ b/core/crypto/haval/haval.odin @@ -50,7 +50,7 @@ hash_bytes_128_3 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128_3 will hash the given input and write the @@ -135,7 +135,7 @@ hash_bytes_128_4 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128_4 will hash the given input and write the @@ -220,7 +220,7 @@ hash_bytes_128_5 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128_5 will hash the given input and write the @@ -305,7 +305,7 @@ hash_bytes_160_3 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160_3 will hash the given input and write the @@ -390,7 +390,7 @@ hash_bytes_160_4 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160_4 will hash the given input and write the @@ -475,7 +475,7 @@ hash_bytes_160_5 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160_5 will hash the given input and write the @@ -560,7 +560,7 @@ hash_bytes_192_3 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_192_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash); + hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_192_3 will hash the given input and write the @@ -645,7 +645,7 @@ hash_bytes_192_4 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_192_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash); + hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_192_4 will hash the given input and write the @@ -730,7 +730,7 @@ hash_bytes_192_5 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_192_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash); + hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_192_5 will hash the given input and write the @@ -815,7 +815,7 @@ hash_bytes_224_3 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224_3 will hash the given input and write the @@ -900,7 +900,7 @@ hash_bytes_224_4 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224_4 will hash the given input and write the @@ -985,7 +985,7 @@ hash_bytes_224_5 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224_5 will hash the given input and write the @@ -1070,7 +1070,7 @@ hash_bytes_256_3 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256_3 will hash the given input and write the @@ -1155,7 +1155,7 @@ hash_bytes_256_4 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256_4 will hash the given input and write the @@ -1240,7 +1240,7 @@ hash_bytes_256_5 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256_5 will hash the given input and write the diff --git a/core/crypto/jh/jh.odin b/core/crypto/jh/jh.odin index 4ebc0e5cb..42c2d1d34 100644 --- a/core/crypto/jh/jh.odin +++ b/core/crypto/jh/jh.odin @@ -44,7 +44,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -123,7 +123,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -202,7 +202,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -281,7 +281,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index f5d4826b1..aeb5aac52 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -49,7 +49,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -131,7 +131,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -213,7 +213,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -295,7 +295,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/core/crypto/md2/md2.odin b/core/crypto/md2/md2.odin index 102c1b8b4..711e6e9f6 100644 --- a/core/crypto/md2/md2.odin +++ b/core/crypto/md2/md2.odin @@ -40,7 +40,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/md4/md4.odin b/core/crypto/md4/md4.odin index d944daa1d..b2651225b 100644 --- a/core/crypto/md4/md4.odin +++ b/core/crypto/md4/md4.odin @@ -44,7 +44,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index 9129e6384..30a556102 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -43,7 +43,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/ripemd/ripemd.odin b/core/crypto/ripemd/ripemd.odin index c475c4803..702d29037 100644 --- a/core/crypto/ripemd/ripemd.odin +++ b/core/crypto/ripemd/ripemd.odin @@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128 will hash the given input and write the @@ -121,7 +121,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160 will hash the given input and write the @@ -197,7 +197,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -273,7 +273,7 @@ hash_bytes_320 :: proc(data: []byte) -> [DIGEST_SIZE_320]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_320 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_320(transmute([]byte)(data), hash); + hash_bytes_to_buffer_320(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_320 will hash the given input and write the diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index e8df3c7f6..b0dbd7dc8 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -43,7 +43,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 2178b70b5..7c7b2da81 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -48,7 +48,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -127,7 +127,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -206,7 +206,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -285,7 +285,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 2eceeaff6..1202f8b23 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -47,7 +47,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -126,7 +126,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -205,7 +205,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -284,7 +284,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 9fdc3ebf1..525dcfbd3 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -46,7 +46,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128 will hash the given input and write the @@ -128,7 +128,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index e72973e33..74c9f22e2 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -42,7 +42,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/core/crypto/streebog/streebog.odin b/core/crypto/streebog/streebog.odin index deb71120d..f85977cba 100644 --- a/core/crypto/streebog/streebog.odin +++ b/core/crypto/streebog/streebog.odin @@ -44,7 +44,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -122,7 +122,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/core/crypto/tiger/tiger.odin b/core/crypto/tiger/tiger.odin index 4ea80c66c..cf6159fad 100644 --- a/core/crypto/tiger/tiger.odin +++ b/core/crypto/tiger/tiger.odin @@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128 will hash the given input and write the @@ -124,7 +124,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160 will hash the given input and write the @@ -203,7 +203,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192(transmute([]byte)(data), hash); + hash_bytes_to_buffer_192(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_192 will hash the given input and write the diff --git a/core/crypto/tiger2/tiger2.odin b/core/crypto/tiger2/tiger2.odin index 84333f344..e8f2c4edb 100644 --- a/core/crypto/tiger2/tiger2.odin +++ b/core/crypto/tiger2/tiger2.odin @@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128 will hash the given input and write the @@ -124,7 +124,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160 will hash the given input and write the @@ -203,7 +203,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192(transmute([]byte)(data), hash); + hash_bytes_to_buffer_192(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_192 will hash the given input and write the diff --git a/core/crypto/whirlpool/whirlpool.odin b/core/crypto/whirlpool/whirlpool.odin index 255f57bc2..0cfef7c6b 100644 --- a/core/crypto/whirlpool/whirlpool.odin +++ b/core/crypto/whirlpool/whirlpool.odin @@ -42,7 +42,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the From fb86c23dbd4c6e9dc82fcc72deb1ad59af5e07f0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jan 2022 16:41:31 +0000 Subject: [PATCH 0043/1052] Keep -vet happy --- core/container/queue/queue.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/container/queue/queue.odin b/core/container/queue/queue.odin index feca6934c..8ca3a85ac 100644 --- a/core/container/queue/queue.odin +++ b/core/container/queue/queue.odin @@ -2,6 +2,7 @@ package container_queue import "core:builtin" import "core:runtime" +_ :: runtime // Dynamically resizable double-ended queue/ring-buffer Queue :: struct($T: typeid) { From 081a5a52a621f3577255b30a4fa35c9b458d5689 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 26 Jan 2022 16:09:22 +0000 Subject: [PATCH 0044/1052] Add ODIN_ERROR_POS_STYLE environment variable Allowing for two different error message styles: default or odin path(line:column) message unix path:line:column: message --- src/build_settings.cpp | 51 +++++++++++++++++++++++++++++++++++++++++- src/error.cpp | 4 ++++ src/tokenizer.cpp | 8 ------- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b4a934ec8..d7253f865 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -165,6 +165,11 @@ enum TimingsExportFormat : i32 { TimingsExportCSV = 2, }; +enum ErrorPosStyle { + ErrorPosStyle_Default, // path(line:column) msg + ErrorPosStyle_Unix, // path:line:column: msg +}; + // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -175,7 +180,9 @@ struct BuildContext { String ODIN_ROOT; // Odin ROOT bool ODIN_DEBUG; // Odin in debug mode bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not -bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) + bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) + + ErrorPosStyle ODIN_ERROR_POS_STYLE; TargetEndianKind endian_kind; @@ -254,6 +261,7 @@ bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil isize thread_count; PtrMap defined_values; + }; @@ -843,6 +851,22 @@ bool has_asm_extension(String const &path) { return false; } +// temporary +char *token_pos_to_string(TokenPos const &pos) { + gbString s = gb_string_make_reserve(temporary_allocator(), 128); + String file = get_file_path_string(pos.file_id); + switch (build_context.ODIN_ERROR_POS_STYLE) { + default: /*fallthrough*/ + case ErrorPosStyle_Default: + s = gb_string_append_fmt(s, "%.*s(%d:%d)", LIT(file), pos.line, pos.column); + break; + case ErrorPosStyle_Unix: + s = gb_string_append_fmt(s, "%.*s:%d:%d:", LIT(file), pos.line, pos.column); + break; + } + return s; +} + void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; @@ -855,6 +879,31 @@ void init_build_context(TargetMetrics *cross_target) { bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VERSION = ODIN_VERSION; bc->ODIN_ROOT = odin_root_dir(); + + { + char const *found = gb_get_env("ODIN_ERROR_POS_STYLE", permanent_allocator()); + if (found) { + ErrorPosStyle kind = ErrorPosStyle_Default; + String style = make_string_c(found); + style = string_trim_whitespace(style); + if (style == "" || style == "default" || style == "odin") { + kind = ErrorPosStyle_Default; + } else if (style == "unix" || style == "gcc" || style == "clang" || style == "llvm") { + kind = ErrorPosStyle_Unix; + } else { + gb_printf_err("Invalid ODIN_ERROR_POS_STYLE: got %.*s\n", LIT(style)); + gb_printf_err("Valid formats:\n"); + gb_printf_err("\t\"default\" or \"odin\"\n"); + gb_printf_err("\t\tpath(line:column) message)\n"); + gb_printf_err("\t\"unix\"\n"); + gb_printf_err("\t\tpath:line:column: message)\n"); + gb_exit(1); + } + + build_context.ODIN_ERROR_POS_STYLE = kind; + } + } + bc->copy_file_contents = true; diff --git a/src/error.cpp b/src/error.cpp index b08ff99df..faf4d11fb 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -33,6 +33,10 @@ void init_global_error_collector(void) { } +// temporary +// defined in build_settings.cpp +char *token_pos_to_string(TokenPos const &pos); + bool set_file_path_string(i32 index, String const &path) { bool ok = false; GB_ASSERT(index >= 0); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 20815fd16..40bc5c220 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -201,14 +201,6 @@ struct TokenPos { i32 column; // starting at 1 }; -// temporary -char *token_pos_to_string(TokenPos const &pos) { - gbString s = gb_string_make_reserve(temporary_allocator(), 128); - String file = get_file_path_string(pos.file_id); - s = gb_string_append_fmt(s, "%.*s(%d:%d)", LIT(file), pos.line, pos.column); - return s; -} - i32 token_pos_cmp(TokenPos const &a, TokenPos const &b) { if (a.offset != b.offset) { return (a.offset < b.offset) ? -1 : +1; From b190404b217f59b9bed65bdf588a4e0369f60a95 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 26 Jan 2022 16:37:16 +0000 Subject: [PATCH 0045/1052] Fix double map dereference indexing --- src/llvm_backend_expr.cpp | 6 ++++-- src/llvm_backend_general.cpp | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 1f0ed6434..9b2e26434 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3460,7 +3460,8 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); if (is_type_map(t)) { - lbValue map_val = lb_build_addr_ptr(p, ie->expr); + lbAddr map_addr = lb_build_addr(p, ie->expr); + lbValue map_val = lb_addr_load(p, map_addr); if (deref) { map_val = lb_emit_load(p, map_val); } @@ -3469,7 +3470,8 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { key = lb_emit_conv(p, key, t->Map.key); Type *result_type = type_of_expr(expr); - return lb_addr_map(map_val, key, t, result_type); + lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val); + return lb_addr_map(map_ptr, key, t, result_type); } switch (t->kind) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 17eeb0bea..998dce88f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -271,6 +271,10 @@ lbAddr lb_addr(lbValue addr) { lbAddr lb_addr_map(lbValue addr, lbValue map_key, Type *map_type, Type *map_result) { + GB_ASSERT(is_type_pointer(addr.type)); + Type *mt = type_deref(addr.type); + GB_ASSERT(is_type_map(mt)); + lbAddr v = {lbAddr_Map, addr}; v.map.key = map_key; v.map.type = map_type; From 74174eb4ae796d6c161839d91c301229a1884713 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 26 Jan 2022 16:38:12 +0000 Subject: [PATCH 0046/1052] Remove spurious `)` --- src/build_settings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d7253f865..96339be29 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -894,9 +894,9 @@ void init_build_context(TargetMetrics *cross_target) { gb_printf_err("Invalid ODIN_ERROR_POS_STYLE: got %.*s\n", LIT(style)); gb_printf_err("Valid formats:\n"); gb_printf_err("\t\"default\" or \"odin\"\n"); - gb_printf_err("\t\tpath(line:column) message)\n"); + gb_printf_err("\t\tpath(line:column) message\n"); gb_printf_err("\t\"unix\"\n"); - gb_printf_err("\t\tpath:line:column: message)\n"); + gb_printf_err("\t\tpath:line:column: message\n"); gb_exit(1); } From 070b4507686570335cb3624ef1ede6f442bd4866 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 26 Jan 2022 17:34:39 +0000 Subject: [PATCH 0047/1052] Add `ODIN_ERROR_POS_STYLE` constant and change `runtime.print_caller_location` based on that constant --- core/runtime/print.odin | 20 +++++++++++++++----- src/build_settings.cpp | 2 ++ src/checker.cpp | 10 ++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 8a14eba08..8c0b65864 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -143,11 +143,21 @@ print_int :: proc "contextless" (x: int) { print_i64(i64(x)) } print_caller_location :: proc "contextless" (using loc: Source_Code_Location) { print_string(file_path) - print_byte('(') - print_u64(u64(line)) - print_byte(':') - print_u64(u64(column)) - print_byte(')') + when ODIN_ERROR_POS_STYLE == .Default { + print_byte('(') + print_u64(u64(line)) + print_byte(':') + print_u64(u64(column)) + print_byte(')') + } else when ODIN_ERROR_POS_STYLE == .Unix { + print_byte(':') + print_u64(u64(line)) + print_byte(':') + print_u64(u64(column)) + print_byte(':') + } else { + #panic("unhandled ODIN_ERROR_POS_STYLE") + } } print_typeid :: proc "contextless" (id: typeid) { if id == nil { diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 96339be29..610e4f847 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -168,6 +168,8 @@ enum TimingsExportFormat : i32 { enum ErrorPosStyle { ErrorPosStyle_Default, // path(line:column) msg ErrorPosStyle_Unix, // path:line:column: msg + + ErrorPosStyle_COUNT }; // This stores the information for the specify architecture of this build diff --git a/src/checker.cpp b/src/checker.cpp index b81d9987b..e0c756bb8 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -893,6 +893,16 @@ void init_universal(void) { add_global_enum_constant(fields, "ODIN_ENDIAN", target_endians[bc->metrics.arch]); } + { + GlobalEnumValue values[ErrorPosStyle_COUNT] = { + {"Default", ErrorPosStyle_Default}, + {"Unix", ErrorPosStyle_Unix}, + }; + + auto fields = add_global_enum_type(str_lit("Odin_Error_Pos_Style_Type"), values, gb_count_of(values)); + add_global_enum_constant(fields, "ODIN_ERROR_POS_STYLE", build_context.ODIN_ERROR_POS_STYLE); + } + add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG); add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT); From 498f68c06b64b9e5bd6a8bd2aef2fb71ecabe5fc Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 26 Jan 2022 14:37:15 -0500 Subject: [PATCH 0048/1052] avoid segfault on map resize --- src/llvm_backend_general.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 998dce88f..2fc21b534 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1602,8 +1602,9 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return llvm_type; } llvm_type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef found_val = *found; map_set(&m->types, type, llvm_type); - lb_clone_struct_type(llvm_type, *found); + lb_clone_struct_type(llvm_type, found_val); return llvm_type; } } From 7e11f3cc4bd888ab57beedd94952a5ead8888d2e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 26 Jan 2022 23:31:47 +0000 Subject: [PATCH 0049/1052] Update doc format to allow for aliases --- src/docs_format.cpp | 13 +++++++++++-- src/docs_writer.cpp | 33 ++++++++++++++------------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 39f2e307c..01320e2b9 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -154,6 +154,7 @@ enum OdinDocEntityKind : u32 { OdinDocEntity_ProcGroup = 5, OdinDocEntity_ImportName = 6, OdinDocEntity_LibraryName = 7, + OdinDocEntity_Builtin = 8, }; enum OdinDocEntityFlag : u64 { @@ -170,6 +171,8 @@ enum OdinDocEntityFlag : u64 { OdinDocEntityFlag_Type_Alias = 1ull<<20, + OdinDocEntityFlag_Builtin_Procedure = 1ull<<30, + OdinDocEntityFlag_Var_Thread_Local = 1ull<<40, OdinDocEntityFlag_Var_Static = 1ull<<41, @@ -201,15 +204,21 @@ enum OdinDocPkgFlags : u32 { OdinDocPkgFlag_Init = 1<<2, }; +struct OdinDocScopeEntry { + OdinDocString name; + OdinDocEntityIndex entity; +}; + struct OdinDocPkg { OdinDocString fullpath; OdinDocString name; u32 flags; OdinDocString docs; - OdinDocArray files; - OdinDocArray entities; + OdinDocArray files; + OdinDocArray entries; }; + struct OdinDocHeader { OdinDocHeaderBase base; diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index b1b9450df..290153ea3 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -819,6 +819,7 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { if (!docs) { docs = e->Constant.docs; } } + String name = e->token.string; String link_name = {}; OdinDocEntityKind kind = OdinDocEntity_Invalid; @@ -834,6 +835,7 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { case Entity_ProcGroup: kind = OdinDocEntity_ProcGroup; break; case Entity_ImportName: kind = OdinDocEntity_ImportName; break; case Entity_LibraryName: kind = OdinDocEntity_LibraryName; break; + case Entity_Builtin: kind = OdinDocEntity_Builtin; break; } switch (e->kind) { @@ -899,7 +901,7 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { doc_entity.kind = kind; doc_entity.flags = flags; doc_entity.pos = odin_doc_token_pos_cast(w, e->token.pos); - doc_entity.name = odin_doc_write_string(w, e->token.string); + doc_entity.name = odin_doc_write_string(w, name); doc_entity.type = 0; // Set later doc_entity.init_string = init_string; doc_entity.comment = odin_doc_comment_group_string(w, comment); @@ -976,7 +978,7 @@ void odin_doc_update_entities(OdinDocWriter *w) { -OdinDocArray odin_doc_add_pkg_entities(OdinDocWriter *w, AstPackage *pkg) { +OdinDocArray odin_doc_add_pkg_entries(OdinDocWriter *w, AstPackage *pkg) { if (pkg->scope == nullptr) { return {}; } @@ -984,14 +986,14 @@ OdinDocArray odin_doc_add_pkg_entities(OdinDocWriter *w, Ast return {}; } - auto entities = array_make(heap_allocator(), 0, pkg->scope->elements.entries.count); - defer (array_free(&entities)); + auto entries = array_make(heap_allocator(), 0, w->entity_cache.entries.count); + defer (array_free(&entries)); for_array(i, pkg->scope->elements.entries) { + String name = pkg->scope->elements.entries[i].key.string; Entity *e = pkg->scope->elements.entries[i].value; switch (e->kind) { case Entity_Invalid: - case Entity_Builtin: case Entity_Nil: case Entity_Label: continue; @@ -1002,18 +1004,10 @@ OdinDocArray odin_doc_add_pkg_entities(OdinDocWriter *w, Ast case Entity_ProcGroup: case Entity_ImportName: case Entity_LibraryName: + case Entity_Builtin: // Fine break; } - array_add(&entities, e); - } - gb_sort_array(entities.data, entities.count, cmp_entities_for_printing); - - auto entity_indices = array_make(heap_allocator(), 0, w->entity_cache.entries.count); - defer (array_free(&entity_indices)); - - for_array(i, entities) { - Entity *e = entities[i]; if (e->pkg != pkg) { continue; } @@ -1024,12 +1018,13 @@ OdinDocArray odin_doc_add_pkg_entities(OdinDocWriter *w, Ast continue; } - OdinDocEntityIndex doc_entity_index = 0; - doc_entity_index = odin_doc_add_entity(w, e); - array_add(&entity_indices, doc_entity_index); + OdinDocScopeEntry entry = {}; + entry.name = odin_doc_write_string(w, name); + entry.entity = odin_doc_add_entity(w, e); + array_add(&entries, entry); } - return odin_write_slice(w, entity_indices.data, entity_indices.count); + return odin_write_slice(w, entries.data, entries.count); } @@ -1097,7 +1092,7 @@ void odin_doc_write_docs(OdinDocWriter *w) { } doc_pkg.files = odin_write_slice(w, file_indices.data, file_indices.count); - doc_pkg.entities = odin_doc_add_pkg_entities(w, pkg); + doc_pkg.entries = odin_doc_add_pkg_entries(w, pkg); if (dst) { *dst = doc_pkg; From 32b37f3429c18d9514091f4bde0a842eb2e70da7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Jan 2022 00:08:05 +0000 Subject: [PATCH 0050/1052] Support built-in procedures for doc format --- src/docs_format.cpp | 5 +++-- src/docs_writer.cpp | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 01320e2b9..7ce93d2bf 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -15,7 +15,7 @@ struct OdinDocVersionType { #define OdinDocVersionType_Major 0 #define OdinDocVersionType_Minor 2 -#define OdinDocVersionType_Patch 3 +#define OdinDocVersionType_Patch 4 struct OdinDocHeaderBase { u8 magic[8]; @@ -171,7 +171,8 @@ enum OdinDocEntityFlag : u64 { OdinDocEntityFlag_Type_Alias = 1ull<<20, - OdinDocEntityFlag_Builtin_Procedure = 1ull<<30, + OdinDocEntityFlag_Builtin_Pkg_Builtin = 1ull<<30, + OdinDocEntityFlag_Builtin_Pkg_Intrinsics = 1ull<<31, OdinDocEntityFlag_Var_Thread_Local = 1ull<<40, OdinDocEntityFlag_Var_Static = 1ull<<41, diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 290153ea3..8b752ab71 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -821,6 +821,7 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { String name = e->token.string; String link_name = {}; + TokenPos pos = e->token.pos; OdinDocEntityKind kind = OdinDocEntity_Invalid; u64 flags = 0; @@ -865,6 +866,24 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { if (e->Procedure.is_export) { flags |= OdinDocEntityFlag_Export; } link_name = e->Procedure.link_name; break; + case Entity_Builtin: + { + auto bp = builtin_procs[e->Builtin.id]; + pos = {}; + name = bp.name; + switch (bp.pkg) { + case BuiltinProcPkg_builtin: + flags |= OdinDocEntityFlag_Builtin_Pkg_Builtin; + break; + case BuiltinProcPkg_intrinsics: + flags |= OdinDocEntityFlag_Builtin_Pkg_Intrinsics; + break; + default: + GB_PANIC("Unhandled BuiltinProcPkg"); + } + GB_PANIC("HERE"); + } + break; } if (e->flags & EntityFlag_Param) { @@ -900,7 +919,7 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { doc_entity.kind = kind; doc_entity.flags = flags; - doc_entity.pos = odin_doc_token_pos_cast(w, e->token.pos); + doc_entity.pos = odin_doc_token_pos_cast(w, pos); doc_entity.name = odin_doc_write_string(w, name); doc_entity.type = 0; // Set later doc_entity.init_string = init_string; @@ -1011,7 +1030,7 @@ OdinDocArray odin_doc_add_pkg_entries(OdinDocWriter *w, AstPa if (e->pkg != pkg) { continue; } - if (!is_entity_exported(e)) { + if (!is_entity_exported(e, true)) { continue; } if (e->token.string.len == 0) { From 16786aac78e343fb11a5bd6c971ebb17ccd36f5c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Jan 2022 12:33:34 +0000 Subject: [PATCH 0051/1052] Correct int31_max etc --- core/math/rand/rand.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 9bd30c216..04e2c6414 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -70,7 +70,7 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 { if n&(n-1) == 0 { return int31(r) & (n-1) } - max := i32((1<<31) - 1 - (1<<31)&u32(n)) + max := i32((1<<31) - 1 - (1<<31)%u32(n)) v := int31(r) for v > max { v = int31(r) @@ -85,7 +85,7 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 { if n&(n-1) == 0 { return int63(r) & (n-1) } - max := i64((1<<63) - 1 - (1<<63)&u64(n)) + max := i64((1<<63) - 1 - (1<<63)%u64(n)) v := int63(r) for v > max { v = int63(r) @@ -100,7 +100,7 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 { if n&(n-1) == 0 { return int127(r) & (n-1) } - max := i128((1<<63) - 1 - (1<<63)&u128(n)) + max := i128((1<<127) - 1 - (1<<127)%u128(n)) v := int127(r) for v > max { v = int127(r) From 4dc29d141f5423c6b0f8d963b60d18eee988a8ab Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 27 Jan 2022 14:24:33 +0100 Subject: [PATCH 0052/1052] Fix `core:odin/parser` not setting the inline flag correctly. --- core/odin/parser/parser.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index e8c2c848d..56e1708e4 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2168,7 +2168,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ } switch e in &ast.unparen_expr(expr).derived { - case ast.Proc_Lit: + case ast.Proc_Lit: if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal") } @@ -2319,7 +2319,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return rt case "force_inline", "force_no_inline": - return parse_inlining_operand(p, lhs, tok) + return parse_inlining_operand(p, lhs, name) case: expr := parse_expr(p, lhs) te := ast.new(ast.Tag_Expr, tok.pos, expr.pos) From ff5e03677366141516b86783f4f3031c6f5e83ab Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 27 Jan 2022 14:27:26 +0100 Subject: [PATCH 0053/1052] Trim whitespaces --- core/odin/parser/parser.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 56e1708e4..0ebabfd70 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2168,7 +2168,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ } switch e in &ast.unparen_expr(expr).derived { - case ast.Proc_Lit: + case ast.Proc_Lit: if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal") } From 28bc274449e77569d997b0dc327c097098daf80d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 27 Jan 2022 14:58:45 +0100 Subject: [PATCH 0054/1052] Fix DEFLATE stored block handling. --- core/compress/zlib/zlib.odin | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index 4d575c7e6..d4c0f332c 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -538,19 +538,20 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all final = compress.read_bits_lsb(z, 1) type = compress.read_bits_lsb(z, 2) - // fmt.printf("Final: %v | Type: %v\n", final, type); + // fmt.printf("Final: %v | Type: %v\n", final, type) switch type { case 0: + // fmt.printf("Method 0: STORED\n") // Uncompressed block // Discard bits until next byte boundary compress.discard_to_next_byte_lsb(z) - uncompressed_len := i16(compress.read_bits_lsb(z, 16)) - length_check := i16(compress.read_bits_lsb(z, 16)) + uncompressed_len := u16(compress.read_bits_lsb(z, 16)) + length_check := u16(compress.read_bits_lsb(z, 16)) - // fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check); + // fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check) if ~uncompressed_len != length_check { @@ -567,10 +568,12 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all write_byte(z, u8(lit)) uncompressed_len -= 1 } + assert(uncompressed_len == 0) + case 3: return E_Deflate.BType_3 case: - // log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type); + // fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type) if type == 1 { // Use fixed code lengths. build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return From 24e7356825a473cba0a1e9962470be73d60ad248 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Jan 2022 16:08:47 +0000 Subject: [PATCH 0055/1052] Add `#no_type_assert` and `#type_assert` to disable implicit type assertions with `x.(T)` --- src/check_expr.cpp | 8 ++++ src/check_stmt.cpp | 8 ++++ src/checker.cpp | 12 ++++++ src/llvm_backend_expr.cpp | 76 ++++++++++++++++++++---------------- src/llvm_backend_stmt.cpp | 7 ++++ src/llvm_backend_utility.cpp | 41 ++++++++++++------- src/parser.cpp | 36 +++++++++++++++++ src/parser.hpp | 4 ++ 8 files changed, 144 insertions(+), 48 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 276e9d0bb..fb5a90f5a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6883,6 +6883,14 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type out &= ~StateFlag_no_bounds_check; } + if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } else if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } + c->state_flags = out; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 94b7561c7..f9e55ab37 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -490,6 +490,14 @@ void check_stmt(CheckerContext *ctx, Ast *node, u32 flags) { out &= ~StateFlag_no_bounds_check; } + if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } else if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } + ctx->state_flags = out; } diff --git a/src/checker.cpp b/src/checker.cpp index e0c756bb8..038709056 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4875,6 +4875,9 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0; bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; + bool type_assert = (pi->tags & ProcTag_type_assert) != 0; + bool no_type_assert = (pi->tags & ProcTag_no_type_assert) != 0; + if (bounds_check) { ctx.state_flags |= StateFlag_bounds_check; ctx.state_flags &= ~StateFlag_no_bounds_check; @@ -4882,6 +4885,15 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc ctx.state_flags |= StateFlag_no_bounds_check; ctx.state_flags &= ~StateFlag_bounds_check; } + + if (type_assert) { + ctx.state_flags |= StateFlag_type_assert; + ctx.state_flags &= ~StateFlag_no_type_assert; + } else if (no_type_assert) { + ctx.state_flags |= StateFlag_no_type_assert; + ctx.state_flags &= ~StateFlag_type_assert; + } + if (pi->body != nullptr && e != nullptr) { GB_ASSERT((e->flags & EntityFlag_ProcBodyChecked) == 0); } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 9b2e26434..ea031ee56 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2768,28 +2768,30 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { Type *src_type = type_deref(v.type); Type *dst_type = type; - lbValue src_tag = {}; - lbValue dst_tag = {}; - if (is_type_union_maybe_pointer(src_type)) { - src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); - dst_tag = lb_const_bool(p->module, t_bool, true); - } else { - src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); - dst_tag = lb_const_union_tag(p->module, src_type, dst_type); + + if ((p->state_flags & StateFlag_no_type_assert) == 0) { + lbValue src_tag = {}; + lbValue dst_tag = {}; + if (is_type_union_maybe_pointer(src_type)) { + src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); + dst_tag = lb_const_bool(p->module, t_bool, true); + } else { + src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); + dst_tag = lb_const_union_tag(p->module, src_type, dst_type); + } + lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); + auto args = array_make(permanent_allocator(), 6); + args[0] = ok; + + args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); + args[2] = lb_const_int(p->module, t_i32, pos.line); + args[3] = lb_const_int(p->module, t_i32, pos.column); + + args[4] = lb_typeid(p->module, src_type); + args[5] = lb_typeid(p->module, dst_type); + lb_emit_runtime_call(p, "type_assertion_check", args); } - lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - auto args = array_make(permanent_allocator(), 6); - args[0] = ok; - - args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(p->module, t_i32, pos.line); - args[3] = lb_const_int(p->module, t_i32, pos.column); - - args[4] = lb_typeid(p->module, src_type); - args[5] = lb_typeid(p->module, dst_type); - lb_emit_runtime_call(p, "type_assertion_check", args); - lbValue data_ptr = v; return lb_emit_conv(p, data_ptr, tv.type); } else if (is_type_any(t)) { @@ -2797,23 +2799,23 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { if (is_type_pointer(v.type)) { v = lb_emit_load(p, v); } - lbValue data_ptr = lb_emit_struct_ev(p, v, 0); - lbValue any_id = lb_emit_struct_ev(p, v, 1); - lbValue id = lb_typeid(p->module, type); + if ((p->state_flags & StateFlag_no_type_assert) == 0) { + lbValue any_id = lb_emit_struct_ev(p, v, 1); + lbValue id = lb_typeid(p->module, type); + lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); + auto args = array_make(permanent_allocator(), 6); + args[0] = ok; - lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - auto args = array_make(permanent_allocator(), 6); - args[0] = ok; + args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); + args[2] = lb_const_int(p->module, t_i32, pos.line); + args[3] = lb_const_int(p->module, t_i32, pos.column); - args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(p->module, t_i32, pos.line); - args[3] = lb_const_int(p->module, t_i32, pos.column); - - args[4] = any_id; - args[5] = id; - lb_emit_runtime_call(p, "type_assertion_check", args); + args[4] = any_id; + args[5] = id; + lb_emit_runtime_call(p, "type_assertion_check", args); + } return lb_emit_conv(p, data_ptr, tv.type); } else { @@ -2843,6 +2845,14 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { out &= ~StateFlag_bounds_check; } + if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } else if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } + p->state_flags = out; } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 3375ceda9..916c0433e 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1991,6 +1991,13 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { out |= StateFlag_no_bounds_check; out &= ~StateFlag_bounds_check; } + if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } else if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } p->state_flags = out; } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 5b1b11b44..7e2bd7daa 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -626,6 +626,12 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p lbValue value_ = lb_address_from_load_or_generate_local(p, value); + if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) { + // just do a bit cast of the data at the front + lbValue ptr = lb_emit_conv(p, value_, alloc_type_pointer(type)); + return lb_emit_load(p, ptr); + } + lbValue tag = {}; lbValue dst_tag = {}; lbValue cond = {}; @@ -666,23 +672,22 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p lb_start_block(p, end_block); if (!is_tuple) { - { - // NOTE(bill): Panic on invalid conversion - Type *dst_type = tuple->Tuple.variables[0]->type; + GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0); + // NOTE(bill): Panic on invalid conversion + Type *dst_type = tuple->Tuple.variables[0]->type; - lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), 7); - args[0] = ok; + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); + auto args = array_make(permanent_allocator(), 7); + args[0] = ok; - args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(m, t_i32, pos.line); - args[3] = lb_const_int(m, t_i32, pos.column); + args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); + args[2] = lb_const_int(m, t_i32, pos.line); + args[3] = lb_const_int(m, t_i32, pos.column); - args[4] = lb_typeid(m, src_type); - args[5] = lb_typeid(m, dst_type); - args[6] = lb_emit_conv(p, value_, t_rawptr); - lb_emit_runtime_call(p, "type_assertion_check2", args); - } + args[4] = lb_typeid(m, src_type); + args[5] = lb_typeid(m, dst_type); + args[6] = lb_emit_conv(p, value_, t_rawptr); + lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); } @@ -706,6 +711,13 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos } Type *dst_type = tuple->Tuple.variables[0]->type; + if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) { + // just do a bit cast of the data at the front + lbValue ptr = lb_emit_struct_ev(p, value, 0); + ptr = lb_emit_conv(p, ptr, alloc_type_pointer(type)); + return lb_addr(ptr); + } + lbAddr v = lb_add_local_generated(p, tuple, true); lbValue dst_typeid = lb_typeid(m, dst_type); @@ -731,7 +743,6 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos if (!is_tuple) { // NOTE(bill): Panic on invalid conversion - lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); auto args = array_make(permanent_allocator(), 7); args[0] = ok; diff --git a/src/parser.cpp b/src/parser.cpp index 108411cd0..9cc9adfc9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1843,6 +1843,8 @@ void parse_proc_tags(AstFile *f, u64 *tags) { ELSE_IF_ADD_TAG(require_results) ELSE_IF_ADD_TAG(bounds_check) ELSE_IF_ADD_TAG(no_bounds_check) + ELSE_IF_ADD_TAG(type_assert) + ELSE_IF_ADD_TAG(no_type_assert) else { syntax_error(tag_expr, "Unknown procedure type tag #%.*s", LIT(tag_name)); } @@ -1853,6 +1855,10 @@ void parse_proc_tags(AstFile *f, u64 *tags) { if ((*tags & ProcTag_bounds_check) && (*tags & ProcTag_no_bounds_check)) { syntax_error(f->curr_token, "You cannot apply both #bounds_check and #no_bounds_check to a procedure"); } + + if ((*tags & ProcTag_type_assert) && (*tags & ProcTag_no_type_assert)) { + syntax_error(f->curr_token, "You cannot apply both #type_assert and #no_type_assert to a procedure"); + } } @@ -2000,11 +2006,23 @@ Ast *parse_check_directive_for_statement(Ast *s, Token const &tag_token, u16 sta syntax_error(tag_token, "#bounds_check and #no_bounds_check cannot be applied together"); } break; + case StateFlag_type_assert: + if ((s->state_flags & StateFlag_no_type_assert) != 0) { + syntax_error(tag_token, "#type_assert and #no_type_assert cannot be applied together"); + } + break; + case StateFlag_no_type_assert: + if ((s->state_flags & StateFlag_type_assert) != 0) { + syntax_error(tag_token, "#type_assert and #no_type_assert cannot be applied together"); + } + break; } switch (state_flag) { case StateFlag_bounds_check: case StateFlag_no_bounds_check: + case StateFlag_type_assert: + case StateFlag_no_type_assert: switch (s->kind) { case Ast_BlockStmt: case Ast_IfStmt: @@ -2128,6 +2146,12 @@ Ast *parse_operand(AstFile *f, bool lhs) { } else if (name.string == "no_bounds_check") { Ast *operand = parse_expr(f, lhs); return parse_check_directive_for_statement(operand, name, StateFlag_no_bounds_check); + } else if (name.string == "type_assert") { + Ast *operand = parse_expr(f, lhs); + return parse_check_directive_for_statement(operand, name, StateFlag_type_assert); + } else if (name.string == "no_type_assert") { + Ast *operand = parse_expr(f, lhs); + return parse_check_directive_for_statement(operand, name, StateFlag_no_type_assert); } else if (name.string == "relative") { Ast *tag = ast_basic_directive(f, token, name); tag = parse_call_expr(f, tag); @@ -2224,6 +2248,12 @@ Ast *parse_operand(AstFile *f, bool lhs) { if (tags & ProcTag_bounds_check) { body->state_flags |= StateFlag_bounds_check; } + if (tags & ProcTag_no_type_assert) { + body->state_flags |= StateFlag_no_type_assert; + } + if (tags & ProcTag_type_assert) { + body->state_flags |= StateFlag_type_assert; + } return ast_proc_lit(f, type, body, tags, where_token, where_clauses); } else if (allow_token(f, Token_do)) { @@ -4611,6 +4641,12 @@ Ast *parse_stmt(AstFile *f) { } else if (tag == "no_bounds_check") { s = parse_stmt(f); return parse_check_directive_for_statement(s, name, StateFlag_no_bounds_check); + } else if (tag == "type_assert") { + s = parse_stmt(f); + return parse_check_directive_for_statement(s, name, StateFlag_type_assert); + } else if (tag == "no_type_assert") { + s = parse_stmt(f); + return parse_check_directive_for_statement(s, name, StateFlag_no_type_assert); } else if (tag == "partial") { s = parse_stmt(f); switch (s->kind) { diff --git a/src/parser.hpp b/src/parser.hpp index b005a4465..656f709e8 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -226,6 +226,8 @@ enum ProcInlining { enum ProcTag { ProcTag_bounds_check = 1<<0, ProcTag_no_bounds_check = 1<<1, + ProcTag_type_assert = 1<<2, + ProcTag_no_type_assert = 1<<3, ProcTag_require_results = 1<<4, ProcTag_optional_ok = 1<<5, @@ -258,6 +260,8 @@ ProcCallingConvention default_calling_convention(void) { enum StateFlag : u8 { StateFlag_bounds_check = 1<<0, StateFlag_no_bounds_check = 1<<1, + StateFlag_type_assert = 1<<2, + StateFlag_no_type_assert = 1<<3, StateFlag_BeenHandled = 1<<7, }; From 2aa783179e8ea968e6f093ed9b63ae2f8bd8be43 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Jan 2022 16:08:58 +0000 Subject: [PATCH 0056/1052] Update doc_format.odin --- core/odin/doc-format/doc_format.odin | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index 59eafdc09..62682004d 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -11,7 +11,7 @@ String :: distinct Array(byte) Version_Type_Major :: 0 Version_Type_Minor :: 2 -Version_Type_Patch :: 3 +Version_Type_Patch :: 4 Version_Type :: struct { major, minor, patch: u8, @@ -77,9 +77,15 @@ Pkg :: struct { flags: Pkg_Flags, docs: String, files: Array(File_Index), - entities: Array(Entity_Index), + entries: Array(Scope_Entry), } +Scope_Entry :: struct { + name: String, + entity: Entity_Index, +} + + Entity_Kind :: enum u32le { Invalid = 0, Constant = 1, @@ -89,6 +95,7 @@ Entity_Kind :: enum u32le { Proc_Group = 5, Import_Name = 6, Library_Name = 7, + Builtin = 8, } Entity_Flag :: enum u32le { @@ -105,6 +112,9 @@ Entity_Flag :: enum u32le { Type_Alias = 20, + Builtin_Pkg_Builtin = 30, + Builtin_Pkg_Intrinsics = 31, + Var_Thread_Local = 40, Var_Static = 41, From 5eea23cf76037bac4576959c306f82ad0aeded96 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Jan 2022 16:09:05 +0000 Subject: [PATCH 0057/1052] Fix typo --- core/builtin/builtin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/builtin/builtin.odin b/core/builtin/builtin.odin index 74283720f..259fdef37 100644 --- a/core/builtin/builtin.odin +++ b/core/builtin/builtin.odin @@ -2,7 +2,7 @@ package builtin nil :: nil; -false :: 0!==0; +false :: 0!=0; true :: 0==0; ODIN_OS :: ODIN_OS; From 3165b7cf95ad3b0773dd1ee36561dbdcea51f047 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Jan 2022 16:09:33 +0000 Subject: [PATCH 0058/1052] Add `rand.exp_float64` --- core/math/rand/exp.odin | 214 +++++++++++++++++++++++++++++++++++++ core/math/rand/normal.odin | 14 ++- 2 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 core/math/rand/exp.odin diff --git a/core/math/rand/exp.odin b/core/math/rand/exp.odin new file mode 100644 index 000000000..c0f92e99c --- /dev/null +++ b/core/math/rand/exp.odin @@ -0,0 +1,214 @@ +package rand + +import "core:math" + +// exp_float64 returns a exponential distribution in the range (0, max(f64)], +// with an exponential distribution who rate parameter is 1 (lambda) and whose mean +// is 1 (1/lambda). +// +// To produce a distribution with a differetn rate parameter, divide the result by +// the desired rate parameter +// +// "The Ziggurat Method for Generating Random Variables" +// Authors: George Marsaglia, Wai Wan Tsang +// Submitted: 2000-04-15. Published: 2000-10-02. +// https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf] +// https://www.jstatsoft.org/article/view/v005i08 [web page] +// +exp_float64 :: proc(r: ^Rand = nil) -> f64 { + re :: 7.69711747013104972 + + @(static) + ke := [256]u32{ + 0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990, + 0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8, + 0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78, + 0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651, + 0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca, + 0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8, + 0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea, + 0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba, + 0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed, + 0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662, + 0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3, + 0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace, + 0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6, + 0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7, + 0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415, + 0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4, + 0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36, + 0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46, + 0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac, + 0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245, + 0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52, + 0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06, + 0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0, + 0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9, + 0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76, + 0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516, + 0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289, + 0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed, + 0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb, + 0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e, + 0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a, + 0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1, + 0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b, + 0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621, + 0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d, + 0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3, + 0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73, + 0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88, + 0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a, + 0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb, + 0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176, + 0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be, + 0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192, + 0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed, + 0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936, + 0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b, + 0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4, + 0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1, + 0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482, + 0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023, + 0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d, + 0xe6da6ecf, + } + @(static) + we := [256]f32{ + 2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11, + 3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11, + 5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11, + 7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11, + 9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10, + 1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10, + 1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10, + 1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10, + 1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10, + 1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10, + 1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10, + 1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10, + 1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10, + 1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10, + 2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10, + 2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10, + 2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10, + 2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10, + 2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10, + 2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10, + 2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10, + 2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10, + 2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10, + 2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10, + 3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10, + 3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10, + 3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10, + 3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10, + 3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10, + 3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10, + 3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10, + 3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10, + 3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10, + 4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10, + 4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10, + 4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10, + 4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10, + 4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10, + 4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10, + 4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10, + 4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10, + 5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10, + 5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10, + 5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10, + 5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10, + 5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10, + 5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10, + 6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10, + 6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10, + 6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10, + 6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10, + 6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10, + 7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10, + 7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10, + 7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10, + 8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10, + 8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10, + 8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10, + 9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10, + 9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09, + 1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09, + 1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09, + 1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09, + 1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09, + } + @(static) + fe := [256]f32{ + 1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933, + 0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686, + 0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665, + 0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967, + 0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896, + 0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092, + 0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386, + 0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495, + 0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752, + 0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325, + 0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955, + 0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694, + 0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218, + 0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763, + 0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044, + 0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796, + 0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408, + 0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928, + 0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393, + 0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625, + 0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107, + 0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878, + 0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438, + 0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682, + 0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852, + 0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479, + 0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354, + 0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494, + 0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119, + 0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624, + 0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574, + 0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672, + 0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763, + 0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816, + 0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919, + 0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274, + 0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195, + 0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106, + 0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434, + 0.062193416, 0.060783047, 0.059384305, 0.057997175, + 0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236, + 0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623, + 0.043502413, 0.042254124, 0.041017443, 0.039792392, + 0.038578995, 0.037377283, 0.036187284, 0.035009038, + 0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566, + 0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421, + 0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867, + 0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392, + 0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414, + 0.008780315, 0.007963077, 0.0071633533, 0.006381906, + 0.0056196423, 0.0048776558, 0.004157295, 0.0034602648, + 0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693, + 0.00045413437, + } + + for { + j := uint32(r) + i := j & 0xFF + x := f64(j) * f64(we[i]) + if j < ke[i] { + return x + } + if i == 0 { + return re - math.ln(float64(r)) + } + if fe[i]+f32(float64(r))*(fe[i-1]-fe[i]) < f32(math.exp(-x)) { + return x + } + } +} \ No newline at end of file diff --git a/core/math/rand/normal.odin b/core/math/rand/normal.odin index 4a77543ba..a9edd0f19 100644 --- a/core/math/rand/normal.odin +++ b/core/math/rand/normal.odin @@ -2,6 +2,12 @@ package rand import "core:math" + +// norm_float64 returns a normally distributed f64 in the range -max(f64) through +max(f64) inclusive, +// with a standard normal distribution with a mean of 0 and standard deviation of 1. +// +// sample = norm_float64() * std_dev + mean +// // // Normal distribution // @@ -11,12 +17,6 @@ import "core:math" // https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf] // https://www.jstatsoft.org/article/view/v005i08 [web page] // - -// norm_float64 returns a normally distributed f64 in the range -max(f64) through +max(f64) inclusive, -// with a standard normal distribution with a mean of 0 and standard deviation of 1. -// -// sample = norm_float64() * std_dev + mean -// norm_float64 :: proc(r: ^Rand = nil) -> f64 { rn :: 3.442619855899 @@ -49,7 +49,6 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 { 0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a, 0x7ba90bdc, 0x7a722176, 0x77d664e5, } - @(static) wn := [128]f32{ 1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10, @@ -85,7 +84,6 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 { 1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09, 1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09, } - @(static) fn := [128]f32{ 1.00000000, 0.9635997, 0.9362827, 0.9130436, 0.89228165, From 38249372957db6a84151d14def3f50c02fe585b5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Jan 2022 16:30:22 +0000 Subject: [PATCH 0059/1052] Remove debug code --- src/docs_writer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 8b752ab71..0474ce8ff 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -881,7 +881,6 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { default: GB_PANIC("Unhandled BuiltinProcPkg"); } - GB_PANIC("HERE"); } break; } From 2f3c5336d95be028fac795fe75b70fc271b15800 Mon Sep 17 00:00:00 2001 From: powerc9000 Date: Thu, 9 Dec 2021 13:03:27 -0700 Subject: [PATCH 0060/1052] Fix mutex and conditions trying to be destroyed twice in unix --- core/thread/thread_unix.odin | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index cee278c7a..6cb91df86 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -167,8 +167,6 @@ _join_multiple :: proc(threads: ..^Thread) { _destroy :: proc(t: ^Thread) { _join(t) - sync.condition_destroy(&t.start_gate) - sync.mutex_destroy(&t.start_mutex) t.unix_thread = {} free(t, t.creation_allocator) } From 62cc752066ee3e07ca5523932aa4a6cdd839475b Mon Sep 17 00:00:00 2001 From: Jesse Stiller Date: Sun, 30 Jan 2022 13:57:01 +1000 Subject: [PATCH 0061/1052] Added round to HLSL and GLSL, and isinf/isfinite + isnan to HLSL --- core/math/linalg/glsl/linalg_glsl.odin | 19 +++++ core/math/linalg/hlsl/linalg_hlsl.odin | 80 +++++++++++++++++++++ core/math/linalg/hlsl/linalg_hlsl_math.odin | 5 ++ 3 files changed, 104 insertions(+) diff --git a/core/math/linalg/glsl/linalg_glsl.odin b/core/math/linalg/glsl/linalg_glsl.odin index 7bc68b964..74753f66f 100644 --- a/core/math/linalg/glsl/linalg_glsl.odin +++ b/core/math/linalg/glsl/linalg_glsl.odin @@ -473,6 +473,25 @@ floor_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {floor(x.x), floor(x.y), fl floor_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {floor(x.x), floor(x.y), floor(x.z), floor(x.w)} } + +round :: proc{ + round_f32, + round_f64, + round_vec2, + round_vec3, + round_vec4, + round_dvec2, + round_dvec3, + round_dvec4, +} +round_vec2 :: proc "c" (x: vec2) -> vec2 { return {round(x.x), round(x.y)} } +round_vec3 :: proc "c" (x: vec3) -> vec3 { return {round(x.x), round(x.y), round(x.z)} } +round_vec4 :: proc "c" (x: vec4) -> vec4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} } +round_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {round(x.x), round(x.y)} } +round_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {round(x.x), round(x.y), round(x.z)} } +round_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} } + + ceil :: proc{ ceil_f32, ceil_f64, diff --git a/core/math/linalg/hlsl/linalg_hlsl.odin b/core/math/linalg/hlsl/linalg_hlsl.odin index 4391975ba..3f73dcd1f 100644 --- a/core/math/linalg/hlsl/linalg_hlsl.odin +++ b/core/math/linalg/hlsl/linalg_hlsl.odin @@ -551,6 +551,23 @@ floor_double2 :: proc "c" (x: double2) -> double2 { return {floor(x.x), floor(x. floor_double3 :: proc "c" (x: double3) -> double3 { return {floor(x.x), floor(x.y), floor(x.z)} } floor_double4 :: proc "c" (x: double4) -> double4 { return {floor(x.x), floor(x.y), floor(x.z), floor(x.w)} } +round :: proc{ + round_float, + round_double, + round_float2, + round_float3, + round_float4, + round_double2, + round_double3, + round_double4, +} +round_float2 :: proc "c" (x: float2) -> float2 { return {round(x.x), round(x.y)} } +round_float3 :: proc "c" (x: float3) -> float3 { return {round(x.x), round(x.y), round(x.z)} } +round_float4 :: proc "c" (x: float4) -> float4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} } +round_double2 :: proc "c" (x: double2) -> double2 { return {round(x.x), round(x.y)} } +round_double3 :: proc "c" (x: double3) -> double3 { return {round(x.x), round(x.y), round(x.z)} } +round_double4 :: proc "c" (x: double4) -> double4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} } + ceil :: proc{ ceil_float, @@ -570,6 +587,69 @@ ceil_double3 :: proc "c" (x: double3) -> double3 { return {ceil(x.x), ceil(x.y), ceil_double4 :: proc "c" (x: double4) -> double4 { return {ceil(x.x), ceil(x.y), ceil(x.z), ceil(x.w)} } +isfinite_float :: proc "c" (x: float) -> bool { return !isinf_float(x) } +isfinite_float2 :: proc "c" (x: float2) -> bool2 { return {isfinite_float(x.x), isfinite_float(x.y)} } +isfinite_float3 :: proc "c" (x: float3) -> bool3 { return {isfinite_float(x.x), isfinite_float(x.y), isfinite_float(x.z)} } +isfinite_float4 :: proc "c" (x: float4) -> bool4 { return {isfinite_float(x.x), isfinite_float(x.y), isfinite_float(x.z), isfinite_float(x.w)} } +isfinite_double :: proc "c" (x: double) -> bool { return !isinf_double(x) } +isfinite_double2 :: proc "c" (x: double2) -> bool2 { return {isfinite_double(x.x), isfinite_double(x.y)} } +isfinite_double3 :: proc "c" (x: double3) -> bool3 { return {isfinite_double(x.x), isfinite_double(x.y), isfinite_double(x.z)} } +isfinite_double4 :: proc "c" (x: double4) -> bool4 { return {isfinite_double(x.x), isfinite_double(x.y), isfinite_double(x.z), isfinite_double(x.w)} } + +// isfinite is the opposite of isinf and returns true if the number is neither positive-infinite or negative-infinite +isfinite :: proc{ + isfinite_float, + isfinite_float2, + isfinite_float3, + isfinite_float4, + isfinite_double, + isfinite_double2, + isfinite_double3, + isfinite_double4, +} + + +isinf_float :: proc "c" (x: float) -> bool { return x * 0.5 == x } +isinf_float2 :: proc "c" (x: float2) -> bool2 { return {isinf_float(x.x), isinf_float(x.y)} } +isinf_float3 :: proc "c" (x: float3) -> bool3 { return {isinf_float(x.x), isinf_float(x.y), isinf_float(x.z)} } +isinf_float4 :: proc "c" (x: float4) -> bool4 { return {isinf_float(x.x), isinf_float(x.y), isinf_float(x.z), isinf_float(x.w)} } +isinf_double :: proc "c" (x: double) -> bool { return x * 0.5 == x } +isinf_double2 :: proc "c" (x: double2) -> bool2 { return {isinf_double(x.x), isinf_double(x.y)} } +isinf_double3 :: proc "c" (x: double3) -> bool3 { return {isinf_double(x.x), isinf_double(x.y), isinf_double(x.z)} } +isinf_double4 :: proc "c" (x: double4) -> bool4 { return {isinf_double(x.x), isinf_double(x.y), isinf_double(x.z), isinf_double(x.w)} } + +// isinf is the opposite of isfinite and returns true if the number is either positive-infinite or negative-infinite +isinf :: proc{ + isinf_float, + isinf_float2, + isinf_float3, + isinf_float4, + isinf_double, + isinf_double2, + isinf_double3, + isinf_double4, +} + + +isnan_float2 :: proc "c" (x: float2) -> bool2 { return {isnan_float(x.x), isnan_float(x.y)} } +isnan_float3 :: proc "c" (x: float3) -> bool3 { return {isnan_float(x.x), isnan_float(x.y), isnan_float(x.z)} } +isnan_float4 :: proc "c" (x: float4) -> bool4 { return {isnan_float(x.x), isnan_float(x.y), isnan_float(x.z), isnan_float(x.w)} } +isnan_double2 :: proc "c" (x: double2) -> bool2 { return {isnan_double(x.x), isnan_double(x.y)} } +isnan_double3 :: proc "c" (x: double3) -> bool3 { return {isnan_double(x.x), isnan_double(x.y), isnan_double(x.z)} } +isnan_double4 :: proc "c" (x: double4) -> bool4 { return {isnan_double(x.x), isnan_double(x.y), isnan_double(x.z), isnan_double(x.w)} } + +// isnan returns true if the input value is the special case of Not-A-Number +isnan :: proc{ + isnan_float, + isnan_float2, + isnan_float3, + isnan_float4, + isnan_double, + isnan_double2, + isnan_double3, + isnan_double4, +} + fmod :: proc{ fmod_float, fmod_double, diff --git a/core/math/linalg/hlsl/linalg_hlsl_math.odin b/core/math/linalg/hlsl/linalg_hlsl_math.odin index d884c3d31..91c542b59 100644 --- a/core/math/linalg/hlsl/linalg_hlsl_math.odin +++ b/core/math/linalg/hlsl/linalg_hlsl_math.odin @@ -26,7 +26,9 @@ log10_float :: proc "c" (x: float) -> float { return math.log(x, 10) } exp2_float :: proc "c" (x: float) -> float { return math.pow(float(2), x) } sign_float :: proc "c" (x: float) -> float { return math.sign(x) } floor_float :: proc "c" (x: float) -> float { return math.floor(x) } +round_float :: proc "c" (x: float) -> float { return math.round(x) } ceil_float :: proc "c" (x: float) -> float { return math.ceil(x) } +isnan_float :: proc "c" (x: float) -> bool { return math.classify(x) == .NaN} fmod_float :: proc "c" (x, y: float) -> float { return math.mod(x, y) } frac_float :: proc "c" (x: float) -> float { if x >= 0 { @@ -35,6 +37,7 @@ frac_float :: proc "c" (x: float) -> float { return math.trunc(-x) + x } + cos_double :: proc "c" (x: double) -> double { return math.cos(x) } sin_double :: proc "c" (x: double) -> double { return math.sin(x) } tan_double :: proc "c" (x: double) -> double { return math.tan(x) } @@ -59,7 +62,9 @@ log10_double :: proc "c" (x: double) -> double { return math.log(x, 10) exp2_double :: proc "c" (x: double) -> double { return math.pow(double(2), x) } sign_double :: proc "c" (x: double) -> double { return math.sign(x) } floor_double :: proc "c" (x: double) -> double { return math.floor(x) } +round_double :: proc "c" (x: double) -> double { return math.round(x) } ceil_double :: proc "c" (x: double) -> double { return math.ceil(x) } +isnan_double :: proc "c" (x: double) -> bool { return math.classify(x) == .NaN} fmod_double :: proc "c" (x, y: double) -> double { return math.mod(x, y) } frac_double :: proc "c" (x: double) -> double { if x >= 0 { From ebb8ca7c264c9b5b98e1388fcb2c6ef8bdc28d59 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 30 Jan 2022 21:35:05 +0000 Subject: [PATCH 0062/1052] Add `round` to linalg_glsl_math.odin --- core/math/linalg/glsl/linalg_glsl_math.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/math/linalg/glsl/linalg_glsl_math.odin b/core/math/linalg/glsl/linalg_glsl_math.odin index 68f43a2f7..968a3fa5e 100644 --- a/core/math/linalg/glsl/linalg_glsl_math.odin +++ b/core/math/linalg/glsl/linalg_glsl_math.odin @@ -23,6 +23,7 @@ log_f32 :: proc "c" (x: f32) -> f32 { return math.ln(x) } exp2_f32 :: proc "c" (x: f32) -> f32 { return math.pow(f32(2), x) } sign_f32 :: proc "c" (x: f32) -> f32 { return math.sign(x) } floor_f32 :: proc "c" (x: f32) -> f32 { return math.floor(x) } +round_f32 :: proc "c" (x: f32) -> f32 { return math.round(x) } ceil_f32 :: proc "c" (x: f32) -> f32 { return math.ceil(x) } mod_f32 :: proc "c" (x, y: f32) -> f32 { return math.mod(x, y) } fract_f32 :: proc "c" (x: f32) -> f32 { @@ -53,6 +54,7 @@ log_f64 :: proc "c" (x: f64) -> f64 { return math.ln(x) } exp2_f64 :: proc "c" (x: f64) -> f64 { return math.pow(f64(2), x) } sign_f64 :: proc "c" (x: f64) -> f64 { return math.sign(x) } floor_f64 :: proc "c" (x: f64) -> f64 { return math.floor(x) } +round_f64 :: proc "c" (x: f64) -> f64 { return math.round(x) } ceil_f64 :: proc "c" (x: f64) -> f64 { return math.ceil(x) } mod_f64 :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) } fract_f64 :: proc "c" (x: f64) -> f64 { From 35a826a0fdab5320462e9574f2a2f791bd913980 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 30 Jan 2022 21:38:34 +0000 Subject: [PATCH 0063/1052] Update CI to do `odin check examples/all` --- .github/workflows/ci.yml | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6742b56f3..575d2406d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,13 +17,16 @@ jobs: run: ./odin report timeout-minutes: 1 - name: Odin check - run: ./odin check examples/demo/demo.odin -vet + run: ./odin check examples/demo -vet timeout-minutes: 10 - name: Odin run - run: ./odin run examples/demo/demo.odin + run: ./odin run examples/demo timeout-minutes: 10 - name: Odin run -debug - run: ./odin run examples/demo/demo.odin -debug + run: ./odin run examples/demo -debug + timeout-minutes: 10 + - name: Odin check examples/local + run: ./odin check examples/all timeout-minutes: 10 - name: Core library tests run: | @@ -54,13 +57,16 @@ jobs: run: ./odin report timeout-minutes: 1 - name: Odin check - run: ./odin check examples/demo/demo.odin -vet + run: ./odin check examples/demo -vet timeout-minutes: 10 - name: Odin run - run: ./odin run examples/demo/demo.odin + run: ./odin run examples/demo timeout-minutes: 10 - name: Odin run -debug - run: ./odin run examples/demo/demo.odin -debug + run: ./odin run examples/demo -debug + timeout-minutes: 10 + - name: Odin check examples/local + run: ./odin check examples/all timeout-minutes: 10 - name: Core library tests run: | @@ -91,19 +97,24 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin check examples/demo/demo.odin -vet + odin check examples/demo -vet timeout-minutes: 10 - name: Odin run shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin run examples/demo/demo.odin + odin run examples/demo timeout-minutes: 10 - name: Odin run -debug shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin run examples/demo/demo.odin -debug + odin run examples/demo -debug + timeout-minutes: 10 + - name: Odin check examples/local + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat + odin check examples/all timeout-minutes: 10 - name: Core library tests shell: cmd From 1502066303fdb448ce83350419bb4b74fa9d6289 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 30 Jan 2022 21:43:42 +0000 Subject: [PATCH 0064/1052] Correct CI --- .github/workflows/ci.yml | 7 ++++--- examples/all/all_main.odin | 2 -- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 575d2406d..fcb909a14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Odin run -debug run: ./odin run examples/demo -debug timeout-minutes: 10 - - name: Odin check examples/local + - name: Odin check examples/all run: ./odin check examples/all timeout-minutes: 10 - name: Core library tests @@ -65,7 +65,7 @@ jobs: - name: Odin run -debug run: ./odin run examples/demo -debug timeout-minutes: 10 - - name: Odin check examples/local + - name: Odin check examples/all run: ./odin check examples/all timeout-minutes: 10 - name: Core library tests @@ -111,7 +111,8 @@ jobs: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat odin run examples/demo -debug timeout-minutes: 10 - - name: Odin check examples/local + - name: Odin check examples/all + shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat odin check examples/all diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 199f406f7..b520faf4d 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -13,7 +13,6 @@ import compress "core:compress" import gzip "core:compress/gzip" import zlib "core:compress/zlib" -import container "core:container" import bit_array "core:container/bit_array" import priority_queue "core:container/priority_queue" import queue "core:container/queue" @@ -49,7 +48,6 @@ import x25519 "core:crypto/x25519" import dynlib "core:dynlib" -import encoding "core:encoding" import base32 "core:encoding/base32" import base64 "core:encoding/base64" import csv "core:encoding/csv" From 44ec95a983facb42ee815e12cf3355ae68406757 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 30 Jan 2022 21:55:55 +0000 Subject: [PATCH 0065/1052] Fix all_main.odin --- examples/all/all_main.odin | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index b520faf4d..1f4d4357c 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -114,7 +114,6 @@ _ :: libc _ :: compress _ :: gzip _ :: zlib -_ :: container _ :: bit_array _ :: priority_queue _ :: queue @@ -147,7 +146,6 @@ _ :: crypto_util _ :: whirlpool _ :: x25519 _ :: dynlib -_ :: encoding _ :: base32 _ :: base64 _ :: csv From da1edac56debf698d493b87a09cfd65f504bb51a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 31 Jan 2022 11:29:05 +0000 Subject: [PATCH 0066/1052] Enforce `-strict-style` in CI --- .github/workflows/ci.yml | 6 +++--- core/os/os_darwin.odin | 6 +++--- core/testing/runner_other.odin | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcb909a14..a1f96d20b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: run: ./odin run examples/demo -debug timeout-minutes: 10 - name: Odin check examples/all - run: ./odin check examples/all + run: ./odin check examples/all -strict-style timeout-minutes: 10 - name: Core library tests run: | @@ -66,7 +66,7 @@ jobs: run: ./odin run examples/demo -debug timeout-minutes: 10 - name: Odin check examples/all - run: ./odin check examples/all + run: ./odin check examples/all -strict-style timeout-minutes: 10 - name: Core library tests run: | @@ -115,7 +115,7 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin check examples/all + odin check examples/all -strict-style timeout-minutes: 10 - name: Core library tests shell: cmd diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index b32453a5d..ef1d6185a 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -296,7 +296,7 @@ foreign libc { @(link_name="readdir_r$INODE64") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int --- - @(link_name="fchmod") _unix_fchmod :: proc(fildes: Handle, mode: u16) -> c.int ---; + @(link_name="fchmod") _unix_fchmod :: proc(fildes: Handle, mode: u16) -> c.int --- @(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr --- @(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr --- @@ -307,7 +307,7 @@ foreign libc { @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- - @(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---; + @(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } @@ -324,7 +324,7 @@ get_last_error :: proc() -> int { } get_last_error_string :: proc() -> string { - return cast(string)_darwin_string_error(cast(c.int)get_last_error()); + return cast(string)_darwin_string_error(cast(c.int)get_last_error()) } open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) { diff --git a/core/testing/runner_other.odin b/core/testing/runner_other.odin index 3978a3c83..f3271d209 100644 --- a/core/testing/runner_other.odin +++ b/core/testing/runner_other.odin @@ -6,7 +6,7 @@ import "core:time" run_internal_test :: proc(t: ^T, it: Internal_Test) { // TODO(bill): Catch panics on other platforms - it.p(t); + it.p(t) } _fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) { From 1a9ec776cbd183d74a6d62cc4b4ef8c0fa8f085d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 31 Jan 2022 12:43:20 +0000 Subject: [PATCH 0067/1052] Unify logic for `slice.sort*` related procedures --- core/slice/sort.odin | 493 +---------------------------------- core/slice/sort_private.odin | 177 +++++++++++++ 2 files changed, 182 insertions(+), 488 deletions(-) create mode 100644 core/slice/sort_private.odin diff --git a/core/slice/sort.odin b/core/slice/sort.odin index d9755ad0e..24bce79af 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -1,10 +1,5 @@ package slice -import "core:intrinsics" -_ :: intrinsics - -ORD :: intrinsics.type_is_ordered - Ordering :: enum { Less = -1, Equal = 0, @@ -38,7 +33,7 @@ cmp_proc :: proc($E: typeid) -> (proc(E, E) -> Ordering) where ORD(E) { sort :: proc(data: $T/[]$E) where ORD(E) { when size_of(E) != 0 { if n := len(data); n > 1 { - _quick_sort(data, 0, n, _max_depth(n)) + _quick_sort_general(data, 0, n, _max_depth(n), struct{}{}, .Ordered) } } } @@ -48,7 +43,7 @@ sort :: proc(data: $T/[]$E) where ORD(E) { sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) { when size_of(E) != 0 { if n := len(data); n > 1 { - _quick_sort_less(data, 0, n, _max_depth(n), less) + _quick_sort_general(data, 0, n, _max_depth(n), less, .Less) } } } @@ -56,7 +51,7 @@ sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) { sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) { when size_of(E) != 0 { if n := len(data); n > 1 { - _quick_sort_cmp(data, 0, n, _max_depth(n), cmp) + _quick_sort_general(data, 0, n, _max_depth(n), cmp, .Cmp) } } } @@ -79,6 +74,7 @@ is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool { return true } +is_sorted_by_cmp :: is_sorted_cmp is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool { for i := len(array)-1; i > 0; i -= 1 { if cmp(array[i], array[i-1]) == .Equal { @@ -140,489 +136,10 @@ is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K return true } - - @(private) -_max_depth :: proc(n: int) -> int { // 2*ceil(log2(n+1)) - depth: int +_max_depth :: proc(n: int) -> (depth: int) { // 2*ceil(log2(n+1)) for i := n; i > 0; i >>= 1 { depth += 1 } return depth * 2 } - -@(private) -_quick_sort :: proc(data: $T/[]$E, a, b, max_depth: int) where ORD(E) #no_bounds_check { - median3 :: proc(data: T, m1, m0, m2: int) #no_bounds_check { - if data[m1] < data[m0] { - swap(data, m1, m0) - } - if data[m2] < data[m1] { - swap(data, m2, m1) - if data[m1] < data[m0] { - swap(data, m1, m0) - } - } - } - - do_pivot :: proc(data: T, lo, hi: int) -> (midlo, midhi: int) #no_bounds_check { - m := int(uint(lo+hi)>>1) - if hi-lo > 40 { - s := (hi-lo)/8 - median3(data, lo, lo+s, lo+s*2) - median3(data, m, m-s, m+s) - median3(data, hi-1, hi-1-s, hi-1-s*2) - } - median3(data, lo, m, hi-1) - - - pivot := lo - a, c := lo+1, hi-1 - - for ; a < c && data[a] < data[pivot]; a += 1 { - } - b := a - - for { - for ; b < c && !(data[pivot] < data[b]); b += 1 { // data[b] <= pivot - } - for ; b < c && data[pivot] < data[c-1]; c -=1 { // data[c-1] > pivot - } - if b >= c { - break - } - - swap(data, b, c-1) - b += 1 - c -= 1 - } - - protect := hi-c < 5 - if !protect && hi-c < (hi-lo)/4 { - dups := 0 - if !(data[pivot] < data[hi-1]) { - swap(data, c, hi-1) - c += 1 - dups += 1 - } - if !(data[b-1] < data[pivot]) { - b -= 1 - dups += 1 - } - - if !(data[m] < data[pivot]) { - swap(data, m, b-1) - b -= 1 - dups += 1 - } - protect = dups > 1 - } - if protect { - for { - for ; a < b && !(data[b-1] < data[pivot]); b -= 1 { - } - for ; a < b && data[a] < data[pivot]; a += 1 { - } - if a >= b { - break - } - swap(data, a, b-1) - a += 1 - b -= 1 - } - } - swap(data, pivot, b-1) - return b-1, c - } - - - a, b, max_depth := a, b, max_depth - - if b-a > 12 { // only use shell sort for lengths <= 12 - if max_depth == 0 { - _heap_sort(data, a, b) - return - } - max_depth -= 1 - mlo, mhi := do_pivot(data, a, b) - if mlo-a < b-mhi { - _quick_sort(data, a, mlo, max_depth) - a = mhi - } else { - _quick_sort(data, mhi, b, max_depth) - b = mlo - } - } - if b-a > 1 { - // Shell short with gap 6 - for i in a+6.. a && data[j] < data[j-1]; j -= 1 { - swap(data, j, j-1) - } - } -} - -@(private) -_heap_sort :: proc(data: $T/[]$E, a, b: int) where ORD(E) #no_bounds_check { - sift_down :: proc(data: T, lo, hi, first: int) #no_bounds_check { - root := lo - for { - child := 2*root + 1 - if child >= hi { - break - } - if child+1 < hi && data[first+child] < data[first+child+1] { - child += 1 - } - if !(data[first+root] < data[first+child]) { - return - } - swap(data, first+root, first+child) - root = child - } - } - - - first, lo, hi := a, 0, b-a - - for i := (hi-1)/2; i >= 0; i -= 1 { - sift_down(data, i, hi, first) - } - - for i := hi-1; i >= 0; i -= 1 { - swap(data, first, first+i) - sift_down(data, lo, i, first) - } -} - - - - - - -@(private) -_quick_sort_less :: proc(data: $T/[]$E, a, b, max_depth: int, less: proc(i, j: E) -> bool) #no_bounds_check { - median3 :: proc(data: T, m1, m0, m2: int, less: proc(i, j: E) -> bool) #no_bounds_check { - if less(data[m1], data[m0]) { - swap(data, m1, m0) - } - if less(data[m2], data[m1]) { - swap(data, m2, m1) - if less(data[m1], data[m0]) { - swap(data, m1, m0) - } - } - } - - do_pivot :: proc(data: T, lo, hi: int, less: proc(i, j: E) -> bool) -> (midlo, midhi: int) #no_bounds_check { - m := int(uint(lo+hi)>>1) - if hi-lo > 40 { - s := (hi-lo)/8 - median3(data, lo, lo+s, lo+s*2, less) - median3(data, m, m-s, m+s, less) - median3(data, hi-1, hi-1-s, hi-1-s*2, less) - } - median3(data, lo, m, hi-1, less) - - pivot := lo - a, c := lo+1, hi-1 - - for ; a < c && less(data[a], data[pivot]); a += 1 { - } - b := a - - for { - for ; b < c && !less(data[pivot], data[b]); b += 1 { // data[b] <= pivot - } - for ; b < c && less(data[pivot], data[c-1]); c -=1 { // data[c-1] > pivot - } - if b >= c { - break - } - - swap(data, b, c-1) - b += 1 - c -= 1 - } - - protect := hi-c < 5 - if !protect && hi-c < (hi-lo)/4 { - dups := 0 - if !less(data[pivot], data[hi-1]) { - swap(data, c, hi-1) - c += 1 - dups += 1 - } - if !less(data[b-1], data[pivot]) { - b -= 1 - dups += 1 - } - - if !less(data[m], data[pivot]) { - swap(data, m, b-1) - b -= 1 - dups += 1 - } - protect = dups > 1 - } - if protect { - for { - for ; a < b && !less(data[b-1], data[pivot]); b -= 1 { - } - for ; a < b && less(data[a], data[pivot]); a += 1 { - } - if a >= b { - break - } - swap(data, a, b-1) - a += 1 - b -= 1 - } - } - swap(data, pivot, b-1) - return b-1, c - } - - - a, b, max_depth := a, b, max_depth - - if b-a > 12 { // only use shell sort for lengths <= 12 - if max_depth == 0 { - _heap_sort_less(data, a, b, less) - return - } - max_depth -= 1 - mlo, mhi := do_pivot(data, a, b, less) - if mlo-a < b-mhi { - _quick_sort_less(data, a, mlo, max_depth, less) - a = mhi - } else { - _quick_sort_less(data, mhi, b, max_depth, less) - b = mlo - } - } - if b-a > 1 { - // Shell short with gap 6 - for i in a+6.. bool) #no_bounds_check { - for i in a+1.. a && less(data[j], data[j-1]); j -= 1 { - swap(data, j, j-1) - } - } -} - -@(private) -_heap_sort_less :: proc(data: $T/[]$E, a, b: int, less: proc(i, j: E) -> bool) #no_bounds_check { - sift_down :: proc(data: T, lo, hi, first: int, less: proc(i, j: E) -> bool) #no_bounds_check { - root := lo - for { - child := 2*root + 1 - if child >= hi { - break - } - if child+1 < hi && less(data[first+child], data[first+child+1]) { - child += 1 - } - if !less(data[first+root], data[first+child]) { - return - } - swap(data, first+root, first+child) - root = child - } - } - - - first, lo, hi := a, 0, b-a - - for i := (hi-1)/2; i >= 0; i -= 1 { - sift_down(data, i, hi, first, less) - } - - for i := hi-1; i >= 0; i -= 1 { - swap(data, first, first+i) - sift_down(data, lo, i, first, less) - } -} - - - - - - -@(private) -_quick_sort_cmp :: proc(data: $T/[]$E, a, b, max_depth: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check { - median3 :: proc(data: T, m1, m0, m2: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check { - if cmp(data[m1], data[m0]) == .Less { - swap(data, m1, m0) - } - if cmp(data[m2], data[m1]) == .Less { - swap(data, m2, m1) - if cmp(data[m1], data[m0]) == .Less { - swap(data, m1, m0) - } - } - } - - do_pivot :: proc(data: T, lo, hi: int, cmp: proc(i, j: E) -> Ordering) -> (midlo, midhi: int) #no_bounds_check { - m := int(uint(lo+hi)>>1) - if hi-lo > 40 { - s := (hi-lo)/8 - median3(data, lo, lo+s, lo+s*2, cmp) - median3(data, m, m-s, m+s, cmp) - median3(data, hi-1, hi-1-s, hi-1-s*2, cmp) - } - median3(data, lo, m, hi-1, cmp) - - pivot := lo - a, c := lo+1, hi-1 - - for ; a < c && cmp(data[a], data[pivot]) == .Less; a += 1 { - } - b := a - - for { - for ; b < c && cmp(data[pivot], data[b]) >= .Equal; b += 1 { // data[b] <= pivot - } - for ; b < c && cmp(data[pivot], data[c-1]) == .Less; c -=1 { // data[c-1] > pivot - } - if b >= c { - break - } - - swap(data, b, c-1) - b += 1 - c -= 1 - } - - protect := hi-c < 5 - if !protect && hi-c < (hi-lo)/4 { - dups := 0 - if cmp(data[pivot], data[hi-1]) != .Less { - swap(data, c, hi-1) - c += 1 - dups += 1 - } - if cmp(data[b-1], data[pivot]) != .Less { - b -= 1 - dups += 1 - } - - if cmp(data[m], data[pivot]) != .Less { - swap(data, m, b-1) - b -= 1 - dups += 1 - } - protect = dups > 1 - } - if protect { - for { - for ; a < b && cmp(data[b-1], data[pivot]) >= .Equal; b -= 1 { - } - for ; a < b && cmp(data[a], data[pivot]) == .Less; a += 1 { - } - if a >= b { - break - } - swap(data, a, b-1) - a += 1 - b -= 1 - } - } - swap(data, pivot, b-1) - return b-1, c - } - - - a, b, max_depth := a, b, max_depth - - if b-a > 12 { // only use shell sort for lengths <= 12 - if max_depth == 0 { - _heap_sort_cmp(data, a, b, cmp) - return - } - max_depth -= 1 - mlo, mhi := do_pivot(data, a, b, cmp) - if mlo-a < b-mhi { - _quick_sort_cmp(data, a, mlo, max_depth, cmp) - a = mhi - } else { - _quick_sort_cmp(data, mhi, b, max_depth, cmp) - b = mlo - } - } - if b-a > 1 { - // Shell short with gap 6 - for i in a+6.. Ordering) #no_bounds_check { - for i in a+1.. a && cmp(data[j], data[j-1]) == .Less; j -= 1 { - swap(data, j, j-1) - } - } -} - -@(private) -_heap_sort_cmp :: proc(data: $T/[]$E, a, b: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check { - sift_down :: proc(data: T, lo, hi, first: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check { - root := lo - for { - child := 2*root + 1 - if child >= hi { - break - } - if child+1 < hi && cmp(data[first+child], data[first+child+1]) == .Less { - child += 1 - } - if cmp(data[first+root], data[first+child]) >= .Equal { - return - } - swap(data, first+root, first+child) - root = child - } - } - - - first, lo, hi := a, 0, b-a - - for i := (hi-1)/2; i >= 0; i -= 1 { - sift_down(data, i, hi, first, cmp) - } - - for i := hi-1; i >= 0; i -= 1 { - swap(data, first, first+i) - sift_down(data, lo, i, first, cmp) - } -} - - - diff --git a/core/slice/sort_private.odin b/core/slice/sort_private.odin new file mode 100644 index 000000000..3b990c1e7 --- /dev/null +++ b/core/slice/sort_private.odin @@ -0,0 +1,177 @@ +//+private +package slice + +import "core:intrinsics" +_ :: intrinsics + +ORD :: intrinsics.type_is_ordered + +Sort_Kind :: enum { + Ordered, + Less, + Cmp, +} + +_quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check { + less :: #force_inline proc(a, b: $E, call: $P) -> bool { + when KIND == .Ordered { + return a < b + } else when KIND == .Less { + return call(a, b) + } else when KIND == .Cmp { + return call(a, b) == .Less + } else { + #panic("unhandled Sort_Kind") + } + } + + insertion_sort :: proc(data: $T/[]$E, a, b: int, call: P) #no_bounds_check { + for i in a+1.. a && less(data[j], data[j-1], call); j -= 1 { + swap(data, j, j-1) + } + } + } + + heap_sort :: proc(data: $T/[]$E, a, b: int, call: P) #no_bounds_check { + sift_down :: proc(data: T, lo, hi, first: int, call: P) #no_bounds_check { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && less(data[first+child], data[first+child+1], call) { + child += 1 + } + if !less(data[first+root], data[first+child], call) { + return + } + swap(data, first+root, first+child) + root = child + } + } + + + first, lo, hi := a, 0, b-a + + for i := (hi-1)/2; i >= 0; i -= 1 { + sift_down(data, i, hi, first, call) + } + + for i := hi-1; i >= 0; i -= 1 { + swap(data, first, first+i) + sift_down(data, lo, i, first, call) + } + } + + median3 :: proc(data: T, m1, m0, m2: int, call: P) #no_bounds_check { + if less(data[m1], data[m0], call) { + swap(data, m1, m0) + } + if less(data[m2], data[m1], call) { + swap(data, m2, m1) + if less(data[m1], data[m0], call) { + swap(data, m1, m0) + } + } + } + + do_pivot :: proc(data: T, lo, hi: int, call: P) -> (midlo, midhi: int) #no_bounds_check { + m := int(uint(lo+hi)>>1) + if hi-lo > 40 { + s := (hi-lo)/8 + median3(data, lo, lo+s, lo+s*2, call) + median3(data, m, m-s, m+s, call) + median3(data, hi-1, hi-1-s, hi-1-s*2, call) + } + median3(data, lo, m, hi-1, call) + + pivot := lo + a, c := lo+1, hi-1 + + + for ; a < c && less(data[a], data[pivot], call); a += 1 { + } + b := a + + for { + for ; b < c && !less(data[pivot], data[b], call); b += 1 { // data[b] <= pivot + } + for ; b < c && less(data[pivot], data[c-1], call); c -=1 { // data[c-1] > pivot + } + if b >= c { + break + } + + swap(data, b, c-1) + b += 1 + c -= 1 + } + + protect := hi-c < 5 + if !protect && hi-c < (hi-lo)/4 { + dups := 0 + if !less(data[pivot], data[hi-1], call) { + swap(data, c, hi-1) + c += 1 + dups += 1 + } + if !less(data[b-1], data[pivot], call) { + b -= 1 + dups += 1 + } + + if !less(data[m], data[pivot], call) { + swap(data, m, b-1) + b -= 1 + dups += 1 + } + protect = dups > 1 + } + if protect { + for { + for ; a < b && !less(data[b-1], data[pivot], call); b -= 1 { + } + for ; a < b && less(data[a], data[pivot], call); a += 1 { + } + if a >= b { + break + } + swap(data, a, b-1) + a += 1 + b -= 1 + } + } + swap(data, pivot, b-1) + return b-1, c + } + + + a, b, max_depth := a, b, max_depth + + if b-a > 12 { // only use shell sort for lengths <= 12 + if max_depth == 0 { + heap_sort(data, a, b, call) + return + } + max_depth -= 1 + mlo, mhi := do_pivot(data, a, b, call) + if mlo-a < b-mhi { + _quick_sort_general(data, a, mlo, max_depth, call, KIND) + a = mhi + } else { + _quick_sort_general(data, mhi, b, max_depth, call, KIND) + b = mlo + } + } + if b-a > 1 { + // Shell short with gap 6 + for i in a+6.. Date: Mon, 31 Jan 2022 15:55:52 +0000 Subject: [PATCH 0068/1052] Add `slice.stable_sort*` procedures --- core/slice/slice.odin | 24 ++++++++++++------------ core/slice/sort.odin | 26 ++++++++++++++++++++++++++ core/slice/sort_private.odin | 23 +++++++++++++++++++++++ 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 426829a22..5fecc76b1 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -305,21 +305,21 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) - } scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U)->V, allocator := context.allocator) -> []V { - if len(s) == 0 { return {} } + if len(s) == 0 { return {} } - res := make([]V, len(s), allocator) - p := as_ptr(s) - q := as_ptr(res) - r := initializer + res := make([]V, len(s), allocator) + p := as_ptr(s) + q := as_ptr(res) + r := initializer - for l := len(s); l > 0; l -= 1 { - r = f(r, p[0]) - q[0] = r - p = p[1:] - q = q[1:] - } + for l := len(s); l > 0; l -= 1 { + r = f(r, p[0]) + q[0] = r + p = p[1:] + q = q[1:] + } - return res + return res } diff --git a/core/slice/sort.odin b/core/slice/sort.odin index 24bce79af..8a2dec039 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -56,6 +56,32 @@ sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) { } } +// stable_sort sorts a slice +stable_sort :: proc(data: $T/[]$E) where ORD(E) { + when size_of(E) != 0 { + if n := len(data); n > 1 { + _stable_sort_general(data, struct{}{}, .Ordered) + } + } +} + +// stable_sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j" +stable_sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) { + when size_of(E) != 0 { + if n := len(data); n > 1 { + _stable_sort_general(data, less, .Less) + } + } +} + +stable_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) { + when size_of(E) != 0 { + if n := len(data); n > 1 { + _stable_sort_general(data, cmp, .Cmp) + } + } +} + is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) { for i := len(array)-1; i > 0; i -= 1 { if array[i] < array[i-1] { diff --git a/core/slice/sort_private.odin b/core/slice/sort_private.odin index 3b990c1e7..05e4d5eed 100644 --- a/core/slice/sort_private.odin +++ b/core/slice/sort_private.odin @@ -175,3 +175,26 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND insertion_sort(data, a, b, call) } } + + +// merge sort +_stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check { + less :: #force_inline proc(a, b: $E, call: $P) -> bool { + when KIND == .Ordered { + return a < b + } else when KIND == .Less { + return call(a, b) + } else when KIND == .Cmp { + return call(a, b) == .Less + } else { + #panic("unhandled Sort_Kind") + } + } + + n := len(data) + for i in 1.. 0 && less(data[j], data[j-1], call); j -= 1 { + swap(data, j, j-1) + } + } +} From 2f1aeaf757bce1ebc37bd5e63dfcdfe22685deaf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 31 Jan 2022 15:56:40 +0000 Subject: [PATCH 0069/1052] Remove the unneeded `$` --- core/slice/sort_private.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/slice/sort_private.odin b/core/slice/sort_private.odin index 05e4d5eed..7abd2f1ce 100644 --- a/core/slice/sort_private.odin +++ b/core/slice/sort_private.odin @@ -13,7 +13,7 @@ Sort_Kind :: enum { } _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check { - less :: #force_inline proc(a, b: $E, call: $P) -> bool { + less :: #force_inline proc(a, b: E, call: P) -> bool { when KIND == .Ordered { return a < b } else when KIND == .Less { @@ -179,7 +179,7 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND // merge sort _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check { - less :: #force_inline proc(a, b: $E, call: $P) -> bool { + less :: #force_inline proc(a, b: E, call: P) -> bool { when KIND == .Ordered { return a < b } else when KIND == .Less { From 67ba05cb7cfee60daaf257230ddbc4f1e0a9f8ac Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 31 Jan 2022 19:33:02 +0000 Subject: [PATCH 0070/1052] Correct false positive check in `check_unique_package_names` --- src/checker.cpp | 10 ++++++++-- src/parser.cpp | 5 +++++ src/parser_pos.cpp | 6 ++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index 038709056..d9a1af0d1 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5307,12 +5307,18 @@ void check_unique_package_names(Checker *c) { string_map_set(&pkgs, key, pkg); continue; } + auto *this = pkg->files[0]->pkg_decl; + auto *other = (*found)->files[0]->pkg_decl; + if (this == other) { + // NOTE(bill): A false positive was found, ignore it + continue; + } - error(pkg->files[0]->pkg_decl, "Duplicate declaration of 'package %.*s'", LIT(name)); + error(this, "Duplicate declaration of 'package %.*s'", LIT(name)); error_line("\tA package name must be unique\n" "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n" "\tA package name is required for link name prefixing to have a consistent ABI\n"); - error((*found)->files[0]->pkg_decl, "found at previous location"); + error(other, "found at previous location"); } } diff --git a/src/parser.cpp b/src/parser.cpp index 9cc9adfc9..7a858e520 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -183,6 +183,11 @@ Ast *clone_ast(Ast *node) { n->FieldValue.value = clone_ast(n->FieldValue.value); break; + case Ast_EnumFieldValue: + n->EnumFieldValue.name = clone_ast(n->EnumFieldValue.name); + n->EnumFieldValue.value = clone_ast(n->EnumFieldValue.value); + break; + case Ast_TernaryIfExpr: n->TernaryIfExpr.x = clone_ast(n->TernaryIfExpr.x); n->TernaryIfExpr.cond = clone_ast(n->TernaryIfExpr.cond); diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 6ef0db215..54c3ec1f1 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -39,6 +39,7 @@ Token ast_token(Ast *node) { case Ast_SliceExpr: return node->SliceExpr.open; case Ast_Ellipsis: return node->Ellipsis.token; case Ast_FieldValue: return node->FieldValue.eq; + case Ast_EnumFieldValue: return ast_token(node->EnumFieldValue.name); case Ast_DerefExpr: return node->DerefExpr.op; case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x); case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x); @@ -178,6 +179,11 @@ Token ast_end_token(Ast *node) { } return node->Ellipsis.token; case Ast_FieldValue: return ast_end_token(node->FieldValue.value); + case Ast_EnumFieldValue: + if (node->EnumFieldValue.value) { + return ast_end_token(node->EnumFieldValue.value); + } + return ast_end_token(node->EnumFieldValue.name); case Ast_DerefExpr: return node->DerefExpr.op; case Ast_TernaryIfExpr: return ast_end_token(node->TernaryIfExpr.y); case Ast_TernaryWhenExpr: return ast_end_token(node->TernaryWhenExpr.y); From 85706d559d06998895b27710f5e4f4643443b032 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 31 Jan 2022 20:19:46 +0000 Subject: [PATCH 0071/1052] Fix typo --- src/checker.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index d9a1af0d1..d50d4d176 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5307,18 +5307,18 @@ void check_unique_package_names(Checker *c) { string_map_set(&pkgs, key, pkg); continue; } - auto *this = pkg->files[0]->pkg_decl; - auto *other = (*found)->files[0]->pkg_decl; - if (this == other) { + auto *curr = pkg->files[0]->pkg_decl; + auto *prev = (*found)->files[0]->pkg_decl; + if (curr == prev) { // NOTE(bill): A false positive was found, ignore it continue; } - error(this, "Duplicate declaration of 'package %.*s'", LIT(name)); + error(curr, "Duplicate declaration of 'package %.*s'", LIT(name)); error_line("\tA package name must be unique\n" "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n" "\tA package name is required for link name prefixing to have a consistent ABI\n"); - error(other, "found at previous location"); + error(prev, "found at previous location"); } } From eac74631ecb74689dbe6bb1e1d07cd15f1fc677a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Feb 2022 14:11:19 +0000 Subject: [PATCH 0072/1052] Correct debug information logic for procedure parameters --- src/llvm_backend.hpp | 1 + src/llvm_backend_debug.cpp | 71 ++++++++++++++++++++++++++++++++++++++ src/llvm_backend_proc.cpp | 9 ++--- 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 49f675a49..d7093bc63 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -232,6 +232,7 @@ struct lbTargetList { enum lbProcedureFlag : u32 { lbProcedureFlag_WithoutMemcpyPass = 1<<0, + lbProcedureFlag_DebugAllocaCopy = 1<<1, }; struct lbCopyElisionHint { diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 7a2b00fe9..f60096aad 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -965,6 +965,77 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T LLVMDIBuilderInsertDeclareBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); } + +void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number) { + if (p->debug_info == nullptr) { + return; + } + if (type == nullptr) { + return; + } + if (type == t_invalid) { + return; + } + if (p->body == nullptr) { + return; + } + + lbModule *m = p->module; + String const &name = token.string; + if (name == "" || name == "_") { + return; + } + + if (lb_get_llvm_metadata(m, ptr) != nullptr) { + // Already been set + return; + } + + + AstFile *file = p->body->file(); + + LLVMMetadataRef llvm_scope = lb_get_current_debug_scope(p); + LLVMMetadataRef llvm_file = lb_get_llvm_metadata(m, file); + GB_ASSERT(llvm_scope != nullptr); + if (llvm_file == nullptr) { + llvm_file = LLVMDIScopeGetFile(llvm_scope); + } + + if (llvm_file == nullptr) { + return; + } + + LLVMDIFlags flags = LLVMDIFlagZero; + LLVMBool always_preserve = build_context.optimization_level == 0; + + LLVMMetadataRef debug_type = lb_debug_type(m, type); + + LLVMMetadataRef var_info = LLVMDIBuilderCreateParameterVariable( + m->debug_builder, llvm_scope, + cast(char const *)name.text, cast(size_t)name.len, + arg_number, + llvm_file, token.pos.line, + debug_type, + always_preserve, flags + ); + + LLVMValueRef storage = ptr; + LLVMValueRef instr = ptr; + LLVMBasicBlockRef block = p->decl_block->block; + LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); + LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); + lb_set_llvm_metadata(m, ptr, llvm_expr); + if (LLVMIsAAllocaInst(instr)) { + LLVMDIBuilderInsertDeclareBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); + } else { + // NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block + // The reason is that if the parameter is at index 0 and a pointer, there is not such things as an + // instruction "before" it. + LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); + } +} + + void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) { if (!p->debug_info || !p->body) { return; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 9f9fe7c7a..7a6fac603 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -473,6 +473,8 @@ void lb_begin_procedure_body(lbProcedure *p) { } lbArgType *arg_type = &ft->args[param_index]; + defer (param_index += 1); + if (arg_type->kind == lbArg_Ignore) { continue; } else if (arg_type->kind == lbArg_Direct) { @@ -487,20 +489,19 @@ void lb_begin_procedure_body(lbProcedure *p) { param.type = e->type; lbValue ptr = lb_address_from_load_or_generate_local(p, param); + GB_ASSERT(LLVMIsAAllocaInst(ptr.value)); lb_add_entity(p->module, e, ptr); - // lb_add_debug_local_variable(p, ptr.value, e->type, e->token); + lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1); } } else if (arg_type->kind == lbArg_Indirect) { if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { lbValue ptr = {}; ptr.value = LLVMGetParam(p->value, param_offset+param_index); ptr.type = alloc_type_pointer(e->type); - lb_add_entity(p->module, e, ptr); - // lb_add_debug_local_variable(p, ptr.value, e->type, e->token); + lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1); } } - param_index += 1; } } From 8c9505505a0bf335a990b5ca05650aa6dcd08c30 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Feb 2022 15:23:49 +0000 Subject: [PATCH 0073/1052] Add allocator parameter to `rand.perm` --- core/math/rand/rand.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 04e2c6414..29254d8f4 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -142,8 +142,8 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) { } // perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n) -perm :: proc(n: int, r: ^Rand = nil) -> []int { - m := make([]int, n) +perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int { + m := make([]int, n, allocator) for i := 0; i < n; i += 1 { j := int_max(i+1, r) m[i] = m[j] From a04d849e30da1252e56d29ee18e2a51a5b6cb0d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Feb 2022 15:24:37 +0000 Subject: [PATCH 0074/1052] `core:container/lru` --- core/container/lru/lru_cache.odin | 183 ++++++++++++++++++++++++++++++ examples/all/all_main.odin | 3 +- 2 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 core/container/lru/lru_cache.odin diff --git a/core/container/lru/lru_cache.odin b/core/container/lru/lru_cache.odin new file mode 100644 index 000000000..02bb20da0 --- /dev/null +++ b/core/container/lru/lru_cache.odin @@ -0,0 +1,183 @@ +package container_lru + +import "core:intrinsics" +import "core:mem" +_ :: intrinsics +_ :: mem + +Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) { + prev, next: ^Node(Key, Value), + key: Key, + value: Value, +} + +// Cache is an LRU cache. It automatically removes entries as new entries are +// added if the capacity is reached. Entries are removed based on how recently +// they were used where the oldest entries are removed first. +Cache :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) { + head: ^Node(Key, Value), + tail: ^Node(Key, Value), + + entries: map[Key]^Node(Key, Value), + + count: int, + capacity: int, + + node_allocator: mem.Allocator, + + on_remove: proc(key: Key, value: Value, user_data: rawptr), + on_remove_user_data: rawptr, + call_on_remove_on_destroy: bool, +} + +// init initializes a Cache +init :: proc(c: ^$C/Cache($Key, $Value), capacity: int, entries_allocator := context.allocator, node_allocator := context.allocator) { + c.entries.allocator = entries_allocator + c.node_allocator = node_allocator + c.capacity = capacity +} + +// destroy deinitializes a Cache +destroy :: proc(c: ^$C/Cache($Key, $Value)) { + for _, node in c.entries { + if c.call_on_remove_on_destroy && c.on_remove != nil { + c.on_remove(node.key, node.value, c.on_remove_user_data) + } + free(node, c.node_allocator) + } + clear(&c.entries) + delete(c.entries) + c.head = nil + c.tail = nil + c.count = 0 +} + +// set the given key value pair. This operation updates the recent usage of the item. +set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> mem.Allocator_Error { + if e, ok := c.entries[key]; ok { + e.value = value + return nil + } + + e := new(Node(Key, Value), c.node_allocator) or_return + e.key = key + e.value = value + + _push_front_node(c, e) + if c.count > c.capacity { + _remove_node(c, c.tail) + } + + c.entries[key] = e + return nil +} + +// get a value from the cache from a given key. This operation updates the usage of the item. +get :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok { + e: ^Node(Key, Value) + e, ok = c.entries[key] + if !ok { + return + } + _pop_node(c, e) + _push_front_node(c, e) + return e.value, true +} + +// get_ptr gets the pointer to a value the cache from a given key. This operation updates the usage of the item. +get_ptr :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: ^Value, ok: bool) #optional_ok { + e: ^Node(Key, Value) + e, ok = c.entries[key] + if !ok { + return + } + _pop_node(c, e) + _push_front_node(c, e) + return &e.value, true +} + +// peek gets the value from the cache from a given key without updating the recent usage. +peek :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok { + e: ^Node(Key, Value) + e, ok = c.entries[key] + if !ok { + return + } + return e.value, true +} + +// exists checks for the existence of a value from a given key without updating the recent usage. +exists :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool { + return key in c.entries +} + +// remove removes an item from the cache. +remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool { + e, ok := c.entries[key] + if !ok { + return false + } + _remove_node(c, e) + return true +} + + +@(private) +_remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) { + if c.head == node { + c.head = node.next + } + if c.tail == node { + c.tail = node.prev + } + if node.prev != nil { + node.prev.next = node.next + } + if node.next != nil { + node.next.prev = node.prev + } + node.prev = nil + node.next = nil + + c.count -= 1 + + delete_key(&c.entries, node.key) + + if c.on_remove != nil { + c.on_remove(node.key, node.value, c.on_remove_user_data) + } + + free(node, c.node_allocator) + +} + +@(private) +_push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) { + if c.head != nil { + e.next = c.head + e.next.prev = e + } + c.head = e + if c.tail == nil { + c.tail = e + } + e.prev = nil + + c.count += 1 +} + +@(private) +_pop_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) { + if e == nil { + return + } + if e.prev != nil { + e.prev.next = e.next + } + + if e.next != nil { + e.next.prev = e.prev + } + e.prev = nil + e.next = nil +} \ No newline at end of file diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 1f4d4357c..e38dd5150 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -16,7 +16,8 @@ import zlib "core:compress/zlib" import bit_array "core:container/bit_array" import priority_queue "core:container/priority_queue" import queue "core:container/queue" -import small_array "core:container/queue" +import small_array "core:container/small_array" +import lru "core:container/lru" import crypto "core:crypto" import blake "core:crypto/blake" From 78815778ee399b4df1c5f7c44522c792b9dc3e23 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 2 Feb 2022 15:28:49 +0000 Subject: [PATCH 0075/1052] Add `//+private file` to complement `//+private` (`//+private package`) --- src/checker.cpp | 9 ++++++--- src/entity.cpp | 2 +- src/parser.cpp | 12 ++++++++++-- src/parser.hpp | 8 +++++--- src/string.cpp | 12 ++++++++++-- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index d50d4d176..4dcb5120f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3467,9 +3467,12 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (entity_visibility_kind == EntityVisiblity_Public && (c->scope->flags&ScopeFlag_File) && - c->scope->file && - (c->scope->file->flags & AstFile_IsPrivate)) { - entity_visibility_kind = EntityVisiblity_PrivateToPackage; + c->scope->file) { + if (c->scope->file->flags & AstFile_IsPrivatePkg) { + entity_visibility_kind = EntityVisiblity_PrivateToPackage; + } else if (c->scope->file->flags & AstFile_IsPrivateFile) { + entity_visibility_kind = EntityVisiblity_PrivateToFile; + } } if (entity_visibility_kind != EntityVisiblity_Public && !(c->scope->flags&ScopeFlag_File)) { diff --git a/src/entity.cpp b/src/entity.cpp index a0438a9f4..8327a517e 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -245,7 +245,7 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) { if (e->flags & EntityFlag_NotExported) { return false; } - if (e->file != nullptr && (e->file->flags & AstFile_IsPrivate) != 0) { + if (e->file != nullptr && (e->file->flags & (AstFile_IsPrivatePkg|AstFile_IsPrivateFile)) != 0) { return false; } diff --git a/src/parser.cpp b/src/parser.cpp index 7a858e520..bf8c909c2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5535,8 +5535,16 @@ bool parse_file(Parser *p, AstFile *f) { if (!parse_build_tag(tok, lc)) { return false; } - } else if (lc == "+private") { - f->flags |= AstFile_IsPrivate; + } else if (string_starts_with(lc, str_lit("+private"))) { + f->flags |= AstFile_IsPrivatePkg; + String command = string_trim_starts_with(lc, str_lit("+private ")); + if (lc == "+private") { + f->flags |= AstFile_IsPrivatePkg; + } else if (command == "package") { + f->flags |= AstFile_IsPrivatePkg; + } else if (command == "file") { + f->flags |= AstFile_IsPrivateFile; + } } else if (lc == "+lazy") { if (build_context.ignore_lazy) { // Ignore diff --git a/src/parser.hpp b/src/parser.hpp index 656f709e8..0712e83cb 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -78,9 +78,11 @@ struct ImportedFile { }; enum AstFileFlag : u32 { - AstFile_IsPrivate = 1<<0, - AstFile_IsTest = 1<<1, - AstFile_IsLazy = 1<<2, + AstFile_IsPrivatePkg = 1<<0, + AstFile_IsPrivateFile = 1<<1, + + AstFile_IsTest = 1<<3, + AstFile_IsLazy = 1<<4, }; enum AstDelayQueueKind { diff --git a/src/string.cpp b/src/string.cpp index 800378689..eb6058f78 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -195,8 +195,6 @@ template bool operator > (String const &a, char const (&b)[N]) { retu template bool operator <= (String const &a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); } template bool operator >= (String const &a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); } - - gb_inline bool string_starts_with(String const &s, String const &prefix) { if (prefix.len > s.len) { return false; @@ -230,6 +228,16 @@ gb_inline bool string_ends_with(String const &s, u8 suffix) { return s[s.len-1] == suffix; } + + +gb_inline String string_trim_starts_with(String const &s, String const &prefix) { + if (string_starts_with(s, prefix)) { + return substring(s, prefix.len, s.len); + } + return s; +} + + gb_inline isize string_extension_position(String const &str) { isize dot_pos = -1; isize i = str.len; From 5db603ded27b8cb6dac444fa660009fd7ecc5184 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 2 Feb 2022 15:39:41 +0000 Subject: [PATCH 0076/1052] Minor sanity clean up --- src/parser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parser.cpp b/src/parser.cpp index bf8c909c2..6db71bc4a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5538,6 +5538,7 @@ bool parse_file(Parser *p, AstFile *f) { } else if (string_starts_with(lc, str_lit("+private"))) { f->flags |= AstFile_IsPrivatePkg; String command = string_trim_starts_with(lc, str_lit("+private ")); + command = string_trim_whitespace(command); if (lc == "+private") { f->flags |= AstFile_IsPrivatePkg; } else if (command == "package") { From e190c024fd374aff56f8cd0cf81a16ef4b4b0542 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Wed, 2 Feb 2022 20:07:38 +0100 Subject: [PATCH 0077/1052] Fix logic in `is_nil` procedure: a non_nil slice means there is data to check. --- core/reflect/reflect.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 7f64d0974..05b3a5da0 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -234,7 +234,7 @@ is_nil :: proc(v: any) -> bool { return true } data := as_bytes(v) - if data != nil { + if data == nil { return true } for v in data { From 35533a7baab4cbea175e5585f7e661abddb7a44d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 2 Feb 2022 23:38:32 +0000 Subject: [PATCH 0078/1052] Update `core:container/lru` to support `clear` and take a boolean to indicate whether or not to call the `on_remove` procedure on `clear` or `destroy` --- core/container/lru/lru_cache.odin | 37 +++++++++++++++++++------------ 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/core/container/lru/lru_cache.odin b/core/container/lru/lru_cache.odin index 02bb20da0..f8e6f7b46 100644 --- a/core/container/lru/lru_cache.odin +++ b/core/container/lru/lru_cache.odin @@ -1,9 +1,9 @@ package container_lru +import "core:runtime" import "core:intrinsics" -import "core:mem" +_ :: runtime _ :: intrinsics -_ :: mem Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) { prev, next: ^Node(Key, Value), @@ -23,11 +23,10 @@ Cache :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key count: int, capacity: int, - node_allocator: mem.Allocator, + node_allocator: runtime.Allocator, on_remove: proc(key: Key, value: Value, user_data: rawptr), on_remove_user_data: rawptr, - call_on_remove_on_destroy: bool, } // init initializes a Cache @@ -37,23 +36,28 @@ init :: proc(c: ^$C/Cache($Key, $Value), capacity: int, entries_allocator := con c.capacity = capacity } -// destroy deinitializes a Cache -destroy :: proc(c: ^$C/Cache($Key, $Value)) { +// destroy deinitializes a Cachem +destroy :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) { + clear(c, call_on_remove) + delete(c.entries) +} + +// clear the contents of a Cache +clear :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) { for _, node in c.entries { - if c.call_on_remove_on_destroy && c.on_remove != nil { - c.on_remove(node.key, node.value, c.on_remove_user_data) + if call_on_remove { + _call_on_remove(c, node) } free(node, c.node_allocator) } - clear(&c.entries) - delete(c.entries) + runtime.clear(&c.entries) c.head = nil c.tail = nil c.count = 0 } // set the given key value pair. This operation updates the recent usage of the item. -set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> mem.Allocator_Error { +set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Allocator_Error { if e, ok := c.entries[key]; ok { e.value = value return nil @@ -143,14 +147,19 @@ _remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) { delete_key(&c.entries, node.key) - if c.on_remove != nil { - c.on_remove(node.key, node.value, c.on_remove_user_data) - } + _call_on_remove(c, node) free(node, c.node_allocator) } +@(private) +_call_on_remove :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) { + if c.on_remove != nil { + c.on_remove(node.key, node.value, c.on_remove_user_data) + } +} + @(private) _push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) { if c.head != nil { From df8bdac33f9c8333db64516f27b3c2b727ff7d2b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Feb 2022 00:31:36 +0000 Subject: [PATCH 0079/1052] Initialize the `global_rand` with the `intrinsics.read_cycle_counter()` value --- core/math/rand/rand.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 29254d8f4..19e475835 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -1,5 +1,7 @@ package rand +import "core:intrinsics" + Rand :: struct { state: u64, inc: u64, @@ -7,9 +9,7 @@ Rand :: struct { @(private) -_GLOBAL_SEED_DATA := 1234567890 -@(private) -global_rand := create(u64(uintptr(&_GLOBAL_SEED_DATA))) +global_rand := create(u64(intrinsics.read_cycle_counter())) set_global_seed :: proc(seed: u64) { init(&global_rand, seed) From 35c90fe12413335962cad02d77a4894079b00a5d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Feb 2022 13:34:31 +0000 Subject: [PATCH 0080/1052] Fix type alias declaration evaluation problem (#854 #1439) --- src/check_decl.cpp | 39 +++++++++++++++- src/check_expr.cpp | 113 +++++++++++++++++++++++++++++++++++++++------ src/checker.cpp | 3 -- 3 files changed, 137 insertions(+), 18 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f9bc17ba4..193c28aea 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -385,7 +385,44 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Operand operand = {}; if (init != nullptr) { - Entity *entity = nullptr; + Entity *entity = check_entity_from_ident_or_selector(ctx, init); + if (entity != nullptr && entity->kind == Entity_TypeName) { + // NOTE(bill, 2022-02-03): This is used to solve the problem caused by type aliases + // being "confused" as constants + // + // A :: B + // C :: proc "c" (^A) + // B :: struct {x: C} + // + // A gets evaluated first, and then checks B. + // B then checks C. + // C then tries to check A which is unresolved but thought to be a constant. + // Therefore within C's check, A errs as "not a type". + // + // This is because a const declaration may or may not be a type and this cannot + // be determined from a syntactical standpoint. + // This check allows the compiler to override the entity to be checked as a type. + // + // There is no problem if B is prefixed with the `#type` helper enforcing at + // both a syntax and semantic level that B must be a type. + // + // A :: #type B + // + // This approach is not fool proof and can fail in case such as: + // + // X :: type_of(x) + // X :: Foo(int).Type + // + // Since even these kind of declarations may cause weird checking cycles. + // For the time being, these are going to be treated as an unfortunate error + // until there is a proper delaying system to try declaration again if they + // have failed. + + e->kind = Entity_TypeName; + check_type_decl(ctx, e, init, named_type); + return; + } + entity = nullptr; if (init->kind == Ast_Ident) { entity = check_ident(ctx, &operand, init, nullptr, e->type, true); } else if (init->kind == Ast_SelectorExpr) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fb5a90f5a..88296611b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1286,7 +1286,6 @@ bool check_cycle(CheckerContext *c, Entity *curr, bool report) { return false; } - Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name) { GB_ASSERT(n->kind == Ast_Ident); o->mode = Addressing_Invalid; @@ -1422,8 +1421,12 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ case Entity_TypeName: o->mode = Addressing_Type; if (check_cycle(c, e, true)) { - type = t_invalid; + o->type = t_invalid; } + if (o->type != nullptr && type->kind == Type_Named && o->type->Named.type_name->TypeName.is_type_alias) { + o->type = base_type(o->type); + } + break; case Entity_ImportName: @@ -4064,6 +4067,98 @@ Type *determine_swizzle_array_type(Type *original_type, Type *type_hint, isize n } +bool is_entity_declared_for_selector(Entity *entity, Scope *import_scope, bool *allow_builtin) { + bool is_declared = entity != nullptr; + if (is_declared) { + if (entity->kind == Entity_Builtin) { + // NOTE(bill): Builtin's are in the universal scope which is part of every scopes hierarchy + // This means that we should just ignore the found result through it + *allow_builtin = entity->scope == import_scope || entity->scope != builtin_pkg->scope; + } else if ((entity->scope->flags&ScopeFlag_Global) == ScopeFlag_Global && (import_scope->flags&ScopeFlag_Global) == 0) { + is_declared = false; + } + } + return is_declared; +} + +// NOTE(bill, 2022-02-03): see `check_const_decl` for why it exists reasoning +Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node) { + if (node->kind == Ast_Ident) { + String name = node->Ident.token.string; + return scope_lookup(c->scope, name); + } else if (node->kind == Ast_SelectorExpr) { + ast_node(se, SelectorExpr, node); + if (!c->allow_arrow_right_selector_expr && se->token.kind == Token_ArrowRight) { + return nullptr; + } + + Ast *op_expr = se->expr; + Ast *selector = unparen_expr(se->selector); + if (selector == nullptr) { + return nullptr; + } + if (selector->kind != Ast_Ident) { + return nullptr; + } + + Entity *entity = nullptr; + Entity *expr_entity = nullptr; + bool check_op_expr = true; + + if (op_expr->kind == Ast_Ident) { + String op_name = op_expr->Ident.token.string; + Entity *e = scope_lookup(c->scope, op_name); + add_entity_use(c, op_expr, e); + expr_entity = e; + + if (e != nullptr && e->kind == Entity_ImportName && selector->kind == Ast_Ident) { + // IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile + // It pretty much needs to be in this order and this way + // If you can clean this up, please do but be really careful + String import_name = op_name; + Scope *import_scope = e->ImportName.scope; + String entity_name = selector->Ident.token.string; + + check_op_expr = false; + entity = scope_lookup_current(import_scope, entity_name); + bool allow_builtin = false; + if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) { + return nullptr; + } + + check_entity_decl(c, entity, nullptr, nullptr); + if (entity->kind == Entity_ProcGroup) { + return entity; + } + GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind])); + } + } + + Operand operand = {}; + if (check_op_expr) { + check_expr_base(c, &operand, op_expr, nullptr); + if (operand.mode == Addressing_Invalid) { + return nullptr; + } + } + + if (entity == nullptr && selector->kind == Ast_Ident) { + String field_name = selector->Ident.token.string; + if (is_type_dynamic_array(type_deref(operand.type))) { + init_mem_allocator(c->checker); + } + auto sel = lookup_field(operand.type, field_name, operand.mode == Addressing_Type); + entity = sel.entity; + } + + if (entity != nullptr) { + return entity; + } + } + return nullptr; +} + + Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *type_hint) { ast_node(se, SelectorExpr, node); @@ -4112,18 +4207,8 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ check_op_expr = false; entity = scope_lookup_current(import_scope, entity_name); - bool is_declared = entity != nullptr; bool allow_builtin = false; - if (is_declared) { - if (entity->kind == Entity_Builtin) { - // NOTE(bill): Builtin's are in the universal scope which is part of every scopes hierarchy - // This means that we should just ignore the found result through it - allow_builtin = entity->scope == import_scope || entity->scope != builtin_pkg->scope; - } else if ((entity->scope->flags&ScopeFlag_Global) == ScopeFlag_Global && (import_scope->flags&ScopeFlag_Global) == 0) { - is_declared = false; - } - } - if (!is_declared) { + if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) { error(op_expr, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name)); operand->mode = Addressing_Invalid; operand->expr = node; @@ -4213,7 +4298,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } } - if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) { + if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) { // TODO(bill): Simd_Vector swizzling String field_name = selector->Ident.token.string; diff --git a/src/checker.cpp b/src/checker.cpp index 4dcb5120f..c4423b2bc 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3563,9 +3563,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (is_ast_type(init)) { e = alloc_entity_type_name(d->scope, token, nullptr); - // if (vd->type != nullptr) { - // error(name, "A type declaration cannot have an type parameter"); - // } } else if (init->kind == Ast_ProcLit) { if (c->scope->flags&ScopeFlag_Type) { error(name, "Procedure declarations are not allowed within a struct"); From cf9f3d5e2d33a9004a322db980de307de13dc3a0 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Thu, 3 Feb 2022 15:50:39 +0100 Subject: [PATCH 0081/1052] fix logic in bswap_128 --- core/runtime/internal.odin | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 7b283a132..c07bcc60d 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -37,10 +37,8 @@ bswap_64 :: proc "contextless" (x: u64) -> u64 { bswap_128 :: proc "contextless" (x: u128) -> u128 { z := transmute([4]u32)x - z[0] = bswap_32(z[3]) - z[1] = bswap_32(z[2]) - z[2] = bswap_32(z[1]) - z[3] = bswap_32(z[0]) + z[0], z[3] = bswap_32(z[3]), bswap_32(z[0]) + z[1], z[2] = bswap_32(z[2]), bswap_32(z[1]) return transmute(u128)z } From 76edfae0e0a1da7435f8f0e30a53ae4a70c74ba7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 4 Feb 2022 12:08:20 +0000 Subject: [PATCH 0082/1052] `core:container/topological_sort` --- .../topological_sort/topological_sort.odin | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 core/container/topological_sort/topological_sort.odin diff --git a/core/container/topological_sort/topological_sort.odin b/core/container/topological_sort/topological_sort.odin new file mode 100644 index 000000000..4b69930d5 --- /dev/null +++ b/core/container/topological_sort/topological_sort.odin @@ -0,0 +1,98 @@ +// The following is a generic O(V+E) topological sorter implementation. +// This is the fastest known method for topological sorting and Odin's +// map type is being used to accelerate lookups. +package container_topological_sort + +import "core:intrinsics" +import "core:runtime" +_ :: intrinsics +_ :: runtime + + +Relations :: struct($K: typeid) where intrinsics.type_is_valid_map_key(K) { + dependents: map[K]bool, + dependencies: int, +} + +Sorter :: struct(K: typeid) where intrinsics.type_is_valid_map_key(K) { + relations: map[K]Relations(K), + dependents_allocator: runtime.Allocator, +} + +@(private="file") +make_relations :: proc(sorter: ^$S/Sorter($K)) -> (r: Relations(K)) { + r.dependents.allocator = sorter.dependents_allocator + return +} + + +init :: proc(sorter: ^$S/Sorter($K)) { + sorter.relations = make(map[K]Relations(K)) + sorter.dependents_allocator = context.allocator +} + +destroy :: proc(sorter: ^$S/Sorter($K)) { + for _, v in &sorter.relations { + delete(v.dependents) + } + delete(sorter.relations) +} + +add_key :: proc(sorter: ^$S/Sorter($K), key: K) -> bool { + if key in sorter.relations { + return false + } + sorter.relations[key] = make_relations(sorter) + return true +} + +add_dependency :: proc(sorter: ^$S/Sorter($K), key, dependency: K) -> bool { + if key == dependency { + return false + } + + find := &sorter.relations[dependency] + if find == nil { + find = map_insert(&sorter.relations, dependency, make_relations(sorter)) + } + + if find.dependents[key] { + return true + } + find.dependents[key] = true + + find = &sorter.relations[key] + if find == nil { + find = map_insert(&sorter.relations, key, make_relations(sorter)) + } + + find.dependencies += 1 + + return true +} + +sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) { + relations := &sorter.relations + + for k, v in relations { + if v.dependencies == 0 { + append(&sorted, k) + } + } + + for root in &sorted do for k, _ in relations[root].dependents { + relation := &relations[k] + relation.dependencies -= 1 + if relation.dependencies == 0 { + append(&sorted, k) + } + } + + for k, v in relations { + if v.dependencies != 0 { + append(&cycled, k) + } + } + + return +} \ No newline at end of file From 48af78e46981540b9071b382052777060ba83c23 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Fri, 4 Feb 2022 22:12:07 +0100 Subject: [PATCH 0083/1052] add `iterator` to `core:container/bit_array` --- core/container/bit_array/bit_array.odin | 43 ++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 0fa80c623..f06cf74e7 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -11,11 +11,52 @@ INDEX_SHIFT :: 6 @(private="file") INDEX_MASK :: 63 +@(private="file") +NUM_BITS :: 64 + Bit_Array :: struct { bits: [dynamic]u64, bias: int, } +Bit_Array_Iterator :: struct { + array: ^Bit_Array, + current_word: uint, + current_bit: uint, +} + +/* + In: + - it: ^Bit_Array_Iterator - the iterator struct that holds the state. + + Out: + - index: int - the next set bit of the Bit_Array referenced by `it`. + - ok: bool - `true` if the iterator returned a valid index, + `false` if there were no more bits set +*/ +iterator :: proc (it: ^Bit_Array_Iterator) -> (int, bool) { + words := it.array.bits + // if the word is empty or we have already gone over all the bits in it, + // b.current_bit is greater than the index of any set bit in the word, + // meaning that word >> b.current_bit == 0. + for it.current_word < len(words) && (words[it.current_word] >> it.current_bit == 0) { + it.current_word += 1 + it.current_bit = 0 + } + + if it.current_word >= len(words) { return 0, false } + + // since we exited the loop and didn't return, this word has some bits higher than + // or equal to `it.current_bit` set. + offset := intrinsics.count_trailing_zeros(words[it.current_word] >> it.current_bit) + // skip over the bit, if the resulting it.current_bit is over 63, + // it is handled by the initial for loop in the next iteration. + it.current_bit += uint(offset) + defer it.current_bit += 1 + return int(it.current_word * NUM_BITS + it.current_bit) + it.array.bias, true +} + + /* In: - ba: ^Bit_Array - a pointer to the Bit Array @@ -121,4 +162,4 @@ resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocat resize(&ba.bits, legs + 1) } return len(ba.bits) > legs -} \ No newline at end of file +} From b54fc96b1e36ff83922d7af9d8126e3fff0d8078 Mon Sep 17 00:00:00 2001 From: ap29600 <66381278+ap29600@users.noreply.github.com> Date: Fri, 4 Feb 2022 22:39:47 +0100 Subject: [PATCH 0084/1052] rename `iterator` proc to `next`, add named return values --- core/container/bit_array/bit_array.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index f06cf74e7..bf2ae3a40 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -34,7 +34,7 @@ Bit_Array_Iterator :: struct { - ok: bool - `true` if the iterator returned a valid index, `false` if there were no more bits set */ -iterator :: proc (it: ^Bit_Array_Iterator) -> (int, bool) { +next :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { words := it.array.bits // if the word is empty or we have already gone over all the bits in it, // b.current_bit is greater than the index of any set bit in the word, From 3a81f2ab898d537bba51b9ea81e047652112574e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 4 Feb 2022 22:40:15 +0000 Subject: [PATCH 0085/1052] Correct the type aliasing problem, caused by aliases (of aliases)+ --- src/check_decl.cpp | 1 + src/check_expr.cpp | 5 +++- src/checker.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 193c28aea..2454feb33 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -387,6 +387,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, if (init != nullptr) { Entity *entity = check_entity_from_ident_or_selector(ctx, init); if (entity != nullptr && entity->kind == Entity_TypeName) { + // @TypeAliasingProblem // NOTE(bill, 2022-02-03): This is used to solve the problem caused by type aliases // being "confused" as constants // diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 88296611b..e1c9bde84 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4088,7 +4088,7 @@ Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node) { return scope_lookup(c->scope, name); } else if (node->kind == Ast_SelectorExpr) { ast_node(se, SelectorExpr, node); - if (!c->allow_arrow_right_selector_expr && se->token.kind == Token_ArrowRight) { + if (se->token.kind == Token_ArrowRight) { return nullptr; } @@ -4108,6 +4108,9 @@ Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node) { if (op_expr->kind == Ast_Ident) { String op_name = op_expr->Ident.token.string; Entity *e = scope_lookup(c->scope, op_name); + if (e == nullptr) { + return nullptr; + } add_entity_use(c, op_expr, e); expr_entity = e; diff --git a/src/checker.cpp b/src/checker.cpp index c4423b2bc..c90f357dd 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3665,6 +3665,59 @@ void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) { check_collect_entities(&c, block->stmts); } +bool correct_single_type_alias(CheckerContext *c, Entity *e) { + if (e->kind == Entity_Constant) { + DeclInfo *d = e->decl_info; + if (d != nullptr && d->init_expr != nullptr) { + Ast *init = d->init_expr; + Entity *alias_of = check_entity_from_ident_or_selector(c, init); + if (alias_of != nullptr && alias_of->kind == Entity_TypeName) { + e->kind = Entity_TypeName; + return true; + } + } + } + return false; +} + +bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) { + isize n = s->elements.entries.count; + bool correction = false; + for (isize i = n-1; i >= 0; i--) { + correction |= correct_single_type_alias(c, s->elements.entries[i].value); + } + return correction; +} +bool correct_type_alias_in_scope_forwards(CheckerContext *c, Scope *s) { + isize n = s->elements.entries.count; + bool correction = false; + for (isize i = 0; i < n; i++) { + correction |= correct_single_type_alias(c, s->elements.entries[i].value); + } + return correction; +} + + +void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { + // NOTE(bill, 2022-02-04): This is used to solve the problem caused by type aliases + // of type aliases being "confused" as constants + // + // A :: C + // B :: A + // C :: struct {b: ^B} + // + // See @TypeAliasingProblem for more information + for (;;) { + bool corrections = false; + corrections |= correct_type_alias_in_scope_backwards(c, s); + corrections |= correct_type_alias_in_scope_forwards(c, s); + if (!corrections) { + return; + } + } +} + + // NOTE(bill): If file_scopes == nullptr, this will act like a local scope void check_collect_entities(CheckerContext *c, Slice const &nodes) { AstFile *curr_file = nullptr; @@ -3736,6 +3789,7 @@ void check_collect_entities(CheckerContext *c, Slice const &nodes) { } } + // correct_type_aliases(c); // NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something // declared after this stmt in source @@ -4381,10 +4435,11 @@ bool collect_file_decls(CheckerContext *ctx, Slice const &decls) { for_array(i, decls) { if (collect_file_decl(ctx, decls[i])) { + correct_type_aliases_in_scope(ctx, ctx->scope); return true; } } - + correct_type_aliases_in_scope(ctx, ctx->scope); return false; } @@ -4654,6 +4709,15 @@ void check_import_entities(Checker *c) { } add_untyped_expressions(ctx.info, &untyped); } + + for_array(i, pkg->files) { + AstFile *f = pkg->files[i]; + reset_checker_context(&ctx, f, &untyped); + ctx.collect_delayed_decls = false; + + correct_type_aliases_in_scope(&ctx, pkg->scope); + } + for_array(i, pkg->files) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); From d5384c5aa4d823fbd527fb82e9eb5559b4266dfd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 4 Feb 2022 22:45:13 +0000 Subject: [PATCH 0086/1052] Only check idents in the alias (of alias)+ problem --- src/check_decl.cpp | 2 +- src/check_expr.cpp | 4 ++-- src/checker.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 2454feb33..63fc777c0 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -385,7 +385,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Operand operand = {}; if (init != nullptr) { - Entity *entity = check_entity_from_ident_or_selector(ctx, init); + Entity *entity = check_entity_from_ident_or_selector(ctx, init, false); if (entity != nullptr && entity->kind == Entity_TypeName) { // @TypeAliasingProblem // NOTE(bill, 2022-02-03): This is used to solve the problem caused by type aliases diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e1c9bde84..d51444b4d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4082,11 +4082,11 @@ bool is_entity_declared_for_selector(Entity *entity, Scope *import_scope, bool * } // NOTE(bill, 2022-02-03): see `check_const_decl` for why it exists reasoning -Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node) { +Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node, bool ident_only) { if (node->kind == Ast_Ident) { String name = node->Ident.token.string; return scope_lookup(c->scope, name); - } else if (node->kind == Ast_SelectorExpr) { + } else if (!ident_only) if (node->kind == Ast_SelectorExpr) { ast_node(se, SelectorExpr, node); if (se->token.kind == Token_ArrowRight) { return nullptr; diff --git a/src/checker.cpp b/src/checker.cpp index c90f357dd..188d68502 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3670,7 +3670,7 @@ bool correct_single_type_alias(CheckerContext *c, Entity *e) { DeclInfo *d = e->decl_info; if (d != nullptr && d->init_expr != nullptr) { Ast *init = d->init_expr; - Entity *alias_of = check_entity_from_ident_or_selector(c, init); + Entity *alias_of = check_entity_from_ident_or_selector(c, init, true); if (alias_of != nullptr && alias_of->kind == Entity_TypeName) { e->kind = Entity_TypeName; return true; From 1553137c2365c3980488a6455fd83f0fcb9e28ca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 00:04:02 +0000 Subject: [PATCH 0087/1052] Change behaviour of `A :: distinct Enum_Type` to be more intuitive --- src/check_decl.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 63fc777c0..f6dade812 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -238,6 +238,51 @@ isize total_attribute_count(DeclInfo *decl) { return attribute_count; } +Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) { + // NOTE(bill, 2022-02-05): Stupid edge case for `distinct` declarations + // + // X :: enum {A, B, C} + // Y :: distinct X + // + // To make Y be just like X, it will need to copy the elements of X and change their type + // so that they match Y rather than X. + GB_ASSERT(original_enum_type != nullptr); + GB_ASSERT(named_type != nullptr); + GB_ASSERT(original_enum_type->kind == Type_Enum); + GB_ASSERT(named_type->kind == Type_Named); + + Scope *parent = original_enum_type->Enum.scope->parent; + Scope *scope = create_scope(nullptr, parent); + + + Type *et = alloc_type_enum(); + et->Enum.base_type = original_enum_type->Enum.base_type; + et->Enum.min_value = original_enum_type->Enum.min_value; + et->Enum.max_value = original_enum_type->Enum.max_value; + et->Enum.min_value_index = original_enum_type->Enum.min_value_index; + et->Enum.max_value_index = original_enum_type->Enum.max_value_index; + et->Enum.scope = scope; + + auto fields = array_make(permanent_allocator(), original_enum_type->Enum.fields.count); + for_array(i, fields) { + Entity *old = original_enum_type->Enum.fields[i]; + + Entity *e = alloc_entity_constant(scope, old->token, named_type, old->Constant.value); + e->file = old->file; + e->identifier = clone_ast(old->identifier); + e->flags |= EntityFlag_Visited; + e->state = EntityState_Resolved; + e->Constant.flags = old->Constant.flags; + e->Constant.docs = old->Constant.docs; + e->Constant.comment = old->Constant.comment; + + fields[i] = e; + add_entity(ctx, scope, nullptr, e); + add_entity_use(ctx, e->identifier, e); + } + et->Enum.fields = fields; + return et; +} void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) { GB_ASSERT(e->type == nullptr); @@ -258,7 +303,11 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) Type *bt = check_type_expr(ctx, te, named); check_type_path_pop(ctx); - named->Named.base = base_type(bt); + Type *base = base_type(bt); + if (is_distinct && bt->kind == Type_Named && base->kind == Type_Enum) { + base = clone_enum_type(ctx, base, named); + } + named->Named.base = base; if (is_distinct && is_type_typeid(e->type)) { error(init_expr, "'distinct' cannot be applied to 'typeid'"); From 97be86710306702a672309b23fbe8d38f1e6eeec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 13:01:15 +0000 Subject: [PATCH 0088/1052] Rename `#partial[Enum]Type` to `#sparse[Enum]Type` for non-contiguous enum fields --- core/reflect/types.odin | 3 +++ core/runtime/core.odin | 1 + core/runtime/print.odin | 3 +++ src/check_type.cpp | 13 +++++++------ src/llvm_backend_type.cpp | 4 +++- src/parser.cpp | 2 +- src/types.cpp | 4 ++++ 7 files changed, 22 insertions(+), 8 deletions(-) diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 74778013a..a9a4a8d48 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -472,6 +472,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - write_type(w, info.elem, &n) or_return case Type_Info_Enumerated_Array: + if info.is_sparse { + io.write_string(w, "#sparse", &n) or_return + } io.write_string(w, "[", &n) or_return write_type(w, info.index, &n) or_return io.write_string(w, "]", &n) or_return diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 424650828..35144473b 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -95,6 +95,7 @@ Type_Info_Enumerated_Array :: struct { count: int, min_value: Type_Info_Enum_Value, max_value: Type_Info_Enum_Value, + is_sparse: bool, } Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int} Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int} diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 8c0b65864..06740bc75 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -260,6 +260,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) { print_type(info.elem) case Type_Info_Enumerated_Array: + if info.is_sparse { + print_string("#sparse") + } print_byte('[') print_type(info.index) print_byte(']') diff --git a/src/check_type.cpp b/src/check_type.cpp index a6d82c86e..6d3e32466 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2713,29 +2713,30 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t Type *t = alloc_type_enumerated_array(elem, index, bt->Enum.min_value, bt->Enum.max_value, Token_Invalid); - bool is_partial = false; + bool is_sparse = false; if (at->tag != nullptr) { GB_ASSERT(at->tag->kind == Ast_BasicDirective); String name = at->tag->BasicDirective.name.string; - if (name == "partial") { - is_partial = true; + if (name == "sparse") { + is_sparse = true; } else { error(at->tag, "Invalid tag applied to an enumerated array, got #%.*s", LIT(name)); } } - if (!is_partial && t->EnumeratedArray.count > bt->Enum.fields.count) { + if (!is_sparse && t->EnumeratedArray.count > bt->Enum.fields.count) { error(e, "Non-contiguous enumeration used as an index in an enumerated array"); long long ea_count = cast(long long)t->EnumeratedArray.count; long long enum_count = cast(long long)bt->Enum.fields.count; error_line("\tenumerated array length: %lld\n", ea_count); error_line("\tenum field count: %lld\n", enum_count); - error_line("\tSuggestion: prepend #partial to the enumerated array to allow for non-named elements\n"); + error_line("\tSuggestion: prepend #sparse to the enumerated array to allow for non-contiguous elements\n"); if (2*enum_count < ea_count) { error_line("\tWarning: the number of named elements is much smaller than the length of the array, are you sure this is what you want?\n"); - error_line("\t this warning will be removed if #partial is applied\n"); + error_line("\t this warning will be removed if #sparse is applied\n"); } } + t->EnumeratedArray.is_sparse = is_sparse; *type = t; diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index e1332c6f3..1d6297164 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -454,7 +454,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da case Type_EnumeratedArray: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr); - LLVMValueRef vals[6] = { + LLVMValueRef vals[7] = { lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value, lb_get_type_info_ptr(m, t->EnumeratedArray.index).value, lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value, @@ -463,6 +463,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da // Unions LLVMConstNull(lb_type(m, t_type_info_enum_value)), LLVMConstNull(lb_type(m, t_type_info_enum_value)), + + lb_const_bool(m, t_bool, t->EnumeratedArray.is_sparse).value, }; lbValue res = {}; diff --git a/src/parser.cpp b/src/parser.cpp index 6db71bc4a..7302b18a9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2134,7 +2134,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { break; } return original_type; - } else if (name.string == "partial") { + } else if (name.string == "sparse") { Ast *tag = ast_basic_directive(f, token, name); Ast *original_type = parse_type(f); Ast *type = unparen_expr(original_type); diff --git a/src/types.cpp b/src/types.cpp index 07951196a..e0d35a12c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -221,6 +221,7 @@ struct TypeProc { ExactValue *max_value; \ i64 count; \ TokenKind op; \ + bool is_sparse; \ }) \ TYPE_KIND(Slice, struct { Type *elem; }) \ TYPE_KIND(DynamicArray, struct { Type *elem; }) \ @@ -3830,6 +3831,9 @@ gbString write_type_to_string(gbString str, Type *type) { break; case Type_EnumeratedArray: + if (type->EnumeratedArray.is_sparse) { + str = gb_string_appendc(str, "#sparse"); + } str = gb_string_append_rune(str, '['); str = write_type_to_string(str, type->EnumeratedArray.index); str = gb_string_append_rune(str, ']'); From 6418ec3b21de26bac4b291a2ad8e58c011c21c38 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 13:09:16 +0000 Subject: [PATCH 0089/1052] Correct `#sparse` usage and error messages --- core/math/big/common.odin | 2 +- examples/demo/demo.odin | 14 +++++++------- src/parser.cpp | 16 ++++++++++++++++ src/parser.hpp | 1 + 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 2b34a9163..e1198c352 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -172,7 +172,7 @@ Error :: enum int { Unimplemented = 127, } -Error_String :: #partial [Error]string{ +Error_String :: #sparse[Error]string{ .Okay = "Okay", .Out_Of_Memory = "Out of memory", .Invalid_Pointer = "Invalid pointer", diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 3e34e3d49..8c6ea0fa4 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1921,14 +1921,14 @@ constant_literal_expressions :: proc() { fmt.println("-------") - Partial_Baz :: enum{A=5, B, C, D=16} - #assert(len(Partial_Baz) < len(#partial [Partial_Baz]int)) - PARTIAL_ENUM_ARRAY_CONST :: #partial [Partial_Baz]int{.A ..= .C = 1, .D = 16} + Sparse_Baz :: enum{A=5, B, C, D=16} + #assert(len(Sparse_Baz) < len(#sparse[Sparse_Baz]int)) + SPARSE_ENUM_ARRAY_CONST :: #sparse[Sparse_Baz]int{.A ..= .C = 1, .D = 16} - fmt.println(PARTIAL_ENUM_ARRAY_CONST[.A]) - fmt.println(PARTIAL_ENUM_ARRAY_CONST[.B]) - fmt.println(PARTIAL_ENUM_ARRAY_CONST[.C]) - fmt.println(PARTIAL_ENUM_ARRAY_CONST[.D]) + fmt.println(SPARSE_ENUM_ARRAY_CONST[.A]) + fmt.println(SPARSE_ENUM_ARRAY_CONST[.B]) + fmt.println(SPARSE_ENUM_ARRAY_CONST[.C]) + fmt.println(SPARSE_ENUM_ARRAY_CONST[.D]) fmt.println("-------") diff --git a/src/parser.cpp b/src/parser.cpp index 7302b18a9..0914c77ca 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2134,6 +2134,22 @@ Ast *parse_operand(AstFile *f, bool lhs) { break; } return original_type; + } else if (name.string == "partial") { + Ast *tag = ast_basic_directive(f, token, name); + Ast *original_expr = parse_expr(f, lhs); + Ast *expr = unparen_expr(original_expr); + switch (expr->kind) { + case Ast_ArrayType: + syntax_error(expr, "#partial has been replaced with #sparse for non-contiguous enumerated array types"); + break; + case Ast_CompoundLit: + expr->CompoundLit.tag = tag; + break; + default: + syntax_error(expr, "Expected a compound literal after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[expr->kind])); + break; + } + return original_expr; } else if (name.string == "sparse") { Ast *tag = ast_basic_directive(f, token, name); Ast *original_type = parse_type(f); diff --git a/src/parser.hpp b/src/parser.hpp index 0712e83cb..ff0df0382 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -350,6 +350,7 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = { Slice elems; \ Token open, close; \ i64 max_count; \ + Ast *tag; \ }) \ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ From e870041fe6171b7e88cde672a3e5478d3786b3c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 13:11:41 +0000 Subject: [PATCH 0090/1052] Fix `#sparse` usage --- core/compress/gzip/gzip.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/compress/gzip/gzip.odin b/core/compress/gzip/gzip.odin index 1a72500bf..0ed805ef8 100644 --- a/core/compress/gzip/gzip.odin +++ b/core/compress/gzip/gzip.odin @@ -66,7 +66,7 @@ OS :: enum u8 { _Unknown = 14, Unknown = 255, } -OS_Name :: #partial [OS]string{ +OS_Name :: #sparse[OS]string{ .FAT = "FAT", .Amiga = "Amiga", .VMS = "VMS/OpenVMS", From b8c4bf2afb39ca2980b2827aa1775b35728bb195 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 14:02:21 +0000 Subject: [PATCH 0091/1052] Add `#partial [Enum]Type{...}` support to check for missing enumerated array fields --- core/compress/gzip/gzip.odin | 1 + core/math/big/common.odin | 1 + src/check_expr.cpp | 145 +++++++++++++++++++++++++++++++++++ src/check_stmt.cpp | 90 +--------------------- 4 files changed, 149 insertions(+), 88 deletions(-) diff --git a/core/compress/gzip/gzip.odin b/core/compress/gzip/gzip.odin index 0ed805ef8..96e9c49a0 100644 --- a/core/compress/gzip/gzip.odin +++ b/core/compress/gzip/gzip.odin @@ -67,6 +67,7 @@ OS :: enum u8 { Unknown = 255, } OS_Name :: #sparse[OS]string{ + ._Unknown = "", .FAT = "FAT", .Amiga = "Amiga", .VMS = "VMS/OpenVMS", diff --git a/core/math/big/common.odin b/core/math/big/common.odin index e1198c352..74a641d83 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -182,6 +182,7 @@ Error_String :: #sparse[Error]string{ .Max_Iterations_Reached = "Max iterations reached", .Buffer_Overflow = "Buffer overflow", .Integer_Overflow = "Integer overflow", + .Integer_Underflow = "Integer underflow", .Division_by_Zero = "Division by zero", .Math_Domain_Error = "Math domain error", diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d51444b4d..40777df2a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6956,6 +6956,100 @@ void check_matrix_index_expr(CheckerContext *c, Operand *o, Ast *node, Type *typ } +struct TypeAndToken { + Type *type; + Token token; +}; + +void add_constant_switch_case(CheckerContext *ctx, PtrMap *seen, Operand operand, bool use_expr = true) { + if (operand.mode != Addressing_Constant) { + return; + } + if (operand.value.kind == ExactValue_Invalid) { + return; + } + + uintptr key = hash_exact_value(operand.value); + TypeAndToken *found = map_get(seen, key); + if (found != nullptr) { + isize count = multi_map_count(seen, key); + TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count); + + multi_map_get_all(seen, key, taps); + for (isize i = 0; i < count; i++) { + TypeAndToken tap = taps[i]; + if (!are_types_identical(operand.type, tap.type)) { + continue; + } + + TokenPos pos = tap.token.pos; + if (use_expr) { + gbString expr_str = expr_to_string(operand.expr); + error(operand.expr, + "Duplicate case '%s'\n" + "\tprevious case at %s", + expr_str, + token_pos_to_string(pos)); + gb_string_free(expr_str); + } else { + error(operand.expr, "Duplicate case found with previous case at %s", token_pos_to_string(pos)); + } + return; + } + } + + TypeAndToken tap = {operand.type, ast_token(operand.expr)}; + multi_map_insert(seen, key, tap); +} + +typedef PtrMap SeenMap; + +void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Operand const &x, Operand const &lhs, Operand const &rhs) { + if (is_type_enum(x.type)) { + // TODO(bill): Fix this logic so it's fast!!! + + i64 v0 = exact_value_to_i64(lhs.value); + i64 v1 = exact_value_to_i64(rhs.value); + Operand v = {}; + v.mode = Addressing_Constant; + v.type = x.type; + v.expr = x.expr; + + Type *bt = base_type(x.type); + GB_ASSERT(bt->kind == Type_Enum); + for (i64 vi = v0; vi <= v1; vi++) { + if (upper_op != Token_GtEq && vi == v1) { + break; + } + + bool found = false; + for_array(j, bt->Enum.fields) { + Entity *f = bt->Enum.fields[j]; + GB_ASSERT(f->kind == Entity_Constant); + + i64 fv = exact_value_to_i64(f->Constant.value); + if (fv == vi) { + found = true; + break; + } + } + if (found) { + v.value = exact_value_i64(vi); + add_constant_switch_case(ctx, seen, v); + } + } + } else { + add_constant_switch_case(ctx, seen, lhs); + if (upper_op == Token_GtEq) { + add_constant_switch_case(ctx, seen, rhs); + } + } +} +void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, Operand const &x) { + add_constant_switch_case(ctx, seen, x); +} + + ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { u32 prev_state_flags = c->state_flags; defer (c->state_flags = prev_state_flags); @@ -7863,6 +7957,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (bet == t_invalid) { break; } + bool is_partial = cl->tag && (cl->tag->BasicDirective.name.string == "partial"); + + SeenMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue + map_init(&seen, heap_allocator()); + defer (map_destroy(&seen)); if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { RangeCache rc = range_cache_make(heap_allocator()); @@ -7936,6 +8035,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type check_assignment(c, &operand, elem_type, context_name); is_constant = is_constant && operand.mode == Addressing_Constant; + + add_to_seen_map(c, &seen, op.kind, x, x, y); } else { Operand op_index = {}; check_expr_with_type_hint(c, &op_index, fv->field, index_type); @@ -7971,6 +8072,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type check_assignment(c, &operand, elem_type, context_name); is_constant = is_constant && operand.mode == Addressing_Constant; + + add_to_seen_map(c, &seen, op_index); } } @@ -8006,11 +8109,53 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } } + bool was_error = false; if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { if (0 < max && max < t->EnumeratedArray.count) { error(node, "Expected %lld values for this enumerated array literal, got %lld", cast(long long)t->EnumeratedArray.count, cast(long long)max); + was_error = true; } else { error(node, "Enumerated array literals must only have 'field = value' elements, bare elements are not allowed"); + was_error = true; + } + } + + // NOTE(bill): Check for missing cases when `#partial literal` is not present + if (cl->elems.count > 0 && !was_error && !is_partial) { + Type *et = base_type(index_type); + GB_ASSERT(et->kind == Type_Enum); + auto fields = et->Enum.fields; + + auto unhandled = array_make(temporary_allocator(), 0, fields.count); + + for_array(i, fields) { + Entity *f = fields[i]; + if (f->kind != Entity_Constant) { + continue; + } + ExactValue v = f->Constant.value; + auto found = map_get(&seen, hash_exact_value(v)); + if (!found) { + array_add(&unhandled, f); + } + } + + if (unhandled.count > 0) { + begin_error_block(); + defer (end_error_block()); + + if (unhandled.count == 1) { + error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string)); + } else { + error_no_newline(node, "Unhandled enumerated array cases: "); + for_array(i, unhandled) { + Entity *f = unhandled[i]; + error_line("\t%.*s\n", LIT(f->token.string)); + } + } + error_line("\n"); + + error_line("\tSuggestion: Was '#partial %s {...}' wanted?\n", type_to_string(index_type)); } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index f9e55ab37..50b7c3233 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -697,54 +697,6 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b return true; } - -struct TypeAndToken { - Type *type; - Token token; -}; - - -void add_constant_switch_case(CheckerContext *ctx, PtrMap *seen, Operand operand, bool use_expr = true) { - if (operand.mode != Addressing_Constant) { - return; - } - if (operand.value.kind == ExactValue_Invalid) { - return; - } - - uintptr key = hash_exact_value(operand.value); - TypeAndToken *found = map_get(seen, key); - if (found != nullptr) { - isize count = multi_map_count(seen, key); - TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count); - - multi_map_get_all(seen, key, taps); - for (isize i = 0; i < count; i++) { - TypeAndToken tap = taps[i]; - if (!are_types_identical(operand.type, tap.type)) { - continue; - } - - TokenPos pos = tap.token.pos; - if (use_expr) { - gbString expr_str = expr_to_string(operand.expr); - error(operand.expr, - "Duplicate case '%s'\n" - "\tprevious case at %s", - expr_str, - token_pos_to_string(pos)); - gb_string_free(expr_str); - } else { - error(operand.expr, "Duplicate case found with previous case at %s", token_pos_to_string(pos)); - } - return; - } - } - - TypeAndToken tap = {operand.type, ast_token(operand.expr)}; - multi_map_insert(seen, key, tap); -} - void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(irs, UnrollRangeStmt, node); check_open_scope(ctx, node); @@ -1032,45 +984,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { Operand b1 = rhs; check_comparison(ctx, &a1, &b1, Token_LtEq); - if (is_type_enum(x.type)) { - // TODO(bill): Fix this logic so it's fast!!! - - i64 v0 = exact_value_to_i64(lhs.value); - i64 v1 = exact_value_to_i64(rhs.value); - Operand v = {}; - v.mode = Addressing_Constant; - v.type = x.type; - v.expr = x.expr; - - Type *bt = base_type(x.type); - GB_ASSERT(bt->kind == Type_Enum); - for (i64 vi = v0; vi <= v1; vi++) { - if (upper_op != Token_GtEq && vi == v1) { - break; - } - - bool found = false; - for_array(j, bt->Enum.fields) { - Entity *f = bt->Enum.fields[j]; - GB_ASSERT(f->kind == Entity_Constant); - - i64 fv = exact_value_to_i64(f->Constant.value); - if (fv == vi) { - found = true; - break; - } - } - if (found) { - v.value = exact_value_i64(vi); - add_constant_switch_case(ctx, &seen, v); - } - } - } else { - add_constant_switch_case(ctx, &seen, lhs); - if (upper_op == Token_GtEq) { - add_constant_switch_case(ctx, &seen, rhs); - } - } + add_to_seen_map(ctx, &seen, upper_op, x, lhs, rhs); if (is_type_string(x.type)) { // NOTE(bill): Force dependency for strings here @@ -1115,7 +1029,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { continue; } update_untyped_expr_type(ctx, z.expr, x.type, !is_type_untyped(x.type)); - add_constant_switch_case(ctx, &seen, y); + add_to_seen_map(ctx, &seen, y); } } } From dd84b61cc83c6bb3a179375f0a37adf6782b3be8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 14:07:17 +0000 Subject: [PATCH 0092/1052] Correct `add_to_seen_map` logic --- src/check_expr.cpp | 10 +++++++--- src/check_stmt.cpp | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 40777df2a..b2ce6c897 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7018,7 +7018,7 @@ void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Ope Type *bt = base_type(x.type); GB_ASSERT(bt->kind == Type_Enum); for (i64 vi = v0; vi <= v1; vi++) { - if (upper_op != Token_GtEq && vi == v1) { + if (upper_op != Token_LtEq && vi == v1) { break; } @@ -7040,7 +7040,7 @@ void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Ope } } else { add_constant_switch_case(ctx, seen, lhs); - if (upper_op == Token_GtEq) { + if (upper_op == Token_LtEq) { add_constant_switch_case(ctx, seen, rhs); } } @@ -8036,7 +8036,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type is_constant = is_constant && operand.mode == Addressing_Constant; - add_to_seen_map(c, &seen, op.kind, x, x, y); + TokenKind upper_op = Token_LtEq; + if (op.kind == Token_RangeHalf) { + upper_op = Token_Lt; + } + add_to_seen_map(c, &seen, upper_op, x, x, y); } else { Operand op_index = {}; check_expr_with_type_hint(c, &op_index, fv->field, index_type); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 50b7c3233..0d18af199 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -961,9 +961,9 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { TokenKind upper_op = Token_Invalid; switch (be->op.kind) { - case Token_Ellipsis: upper_op = Token_GtEq; break; - case Token_RangeFull: upper_op = Token_GtEq; break; - case Token_RangeHalf: upper_op = Token_Gt; break; + case Token_Ellipsis: upper_op = Token_LtEq; break; + case Token_RangeFull: upper_op = Token_LtEq; break; + case Token_RangeHalf: upper_op = Token_Lt; break; default: GB_PANIC("Invalid range operator"); break; } From cf246f65ff72db870313627b7db3b83601364385 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 14:31:22 +0000 Subject: [PATCH 0093/1052] Add check for variables which are both shadowing and unused by default --- src/checker.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index 188d68502..b62ef7c4c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -504,6 +504,7 @@ enum VettedEntityKind { VettedEntity_Unused, VettedEntity_Shadowed, + VettedEntity_Shadowed_And_Unused, }; struct VettedEntity { VettedEntityKind kind; @@ -625,12 +626,18 @@ void check_scope_usage(Checker *c, Scope *scope) { MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) { Entity *e = scope->elements.entries[i].value; if (e == nullptr) continue; - VettedEntity ve = {}; - if (vet_unused && check_vet_unused(c, e, &ve)) { - array_add(&vetted_entities, ve); - } - if (vet_shadowing && check_vet_shadowing(c, e, &ve)) { - array_add(&vetted_entities, ve); + VettedEntity ve_unused = {}; + VettedEntity ve_shadowed = {}; + bool is_unused = vet_unused && check_vet_unused(c, e, &ve_unused); + bool is_shadowed = vet_shadowing && check_vet_shadowing(c, e, &ve_shadowed); + if (is_unused && is_shadowed) { + VettedEntity ve_both = ve_shadowed; + ve_both.kind = VettedEntity_Shadowed_And_Unused; + array_add(&vetted_entities, ve_both); + } else if (is_unused) { + array_add(&vetted_entities, ve_unused); + } else if (is_shadowed) { + array_add(&vetted_entities, ve_shadowed); } } @@ -642,16 +649,18 @@ void check_scope_usage(Checker *c, Scope *scope) { Entity *other = ve.other; String name = e->token.string; - if (build_context.vet) { + if (ve.kind == VettedEntity_Shadowed_And_Unused) { + error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line); + } else if (build_context.vet) { switch (ve.kind) { case VettedEntity_Unused: error(e->token, "'%.*s' declared but not used", LIT(name)); break; case VettedEntity_Shadowed: if (e->flags&EntityFlag_Using) { - error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %lld", LIT(name), cast(long long)other->token.pos.line); + error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %d", LIT(name), other->token.pos.line); } else { - error(e->token, "Declaration of '%.*s' shadows declaration at line %lld", LIT(name), cast(long long)other->token.pos.line); + error(e->token, "Declaration of '%.*s' shadows declaration at line %d", LIT(name), other->token.pos.line); } break; default: From 3439139b1c763fe239967bd8c90d8ccbc1e0867f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 14:34:29 +0000 Subject: [PATCH 0094/1052] Minor clean up --- src/check_expr.cpp | 5 +++-- src/check_stmt.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b2ce6c897..d90f93180 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6961,7 +6961,9 @@ struct TypeAndToken { Token token; }; -void add_constant_switch_case(CheckerContext *ctx, PtrMap *seen, Operand operand, bool use_expr = true) { +typedef PtrMap SeenMap; + +void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Operand operand, bool use_expr = true) { if (operand.mode != Addressing_Constant) { return; } @@ -7002,7 +7004,6 @@ void add_constant_switch_case(CheckerContext *ctx, PtrMap multi_map_insert(seen, key, tap); } -typedef PtrMap SeenMap; void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Operand const &x, Operand const &lhs, Operand const &rhs) { if (is_type_enum(x.type)) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 0d18af199..2d85db82c 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -921,7 +921,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { } } - PtrMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue + SeenMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue map_init(&seen, heap_allocator()); defer (map_destroy(&seen)); From a4308e7246a995c745b120debbb61be9e1f19a38 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 14:45:59 +0000 Subject: [PATCH 0095/1052] Improve union variant assignment determination --- src/check_expr.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d90f93180..d6b454bf4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -673,6 +673,42 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type return 1; } } + + // TODO(bill): Determine which rule is a better on in practice + #if 1 + if (dst->Union.variants.count == 1) { + Type *vt = dst->Union.variants[0]; + i64 score = check_distance_between_types(c, operand, vt); + if (score >= 0) { + return score+2; + } + } + #else + // NOTE(bill): check to see you can assign to it with one of the variants? + i64 prev_lowest_score = -1; + i64 lowest_score = -1; + for_array(i, dst->Union.variants) { + Type *vt = dst->Union.variants[i]; + i64 score = check_distance_between_types(c, operand, vt); + if (score >= 0) { + if (lowest_score < 0) { + lowest_score = score; + } else { + if (prev_lowest_score < 0) { + prev_lowest_score = lowest_score; + } else { + prev_lowest_score = gb_min(prev_lowest_score, lowest_score); + } + lowest_score = gb_min(lowest_score, score); + } + } + } + if (lowest_score >= 0) { + if (prev_lowest_score != lowest_score) { // remove possible ambiguities + return lowest_score+2; + } + } + #endif } if (is_type_relative_pointer(dst)) { From 23c3573c307fc9b1c7aa2af2b445090543fd60d3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 14:56:06 +0000 Subject: [PATCH 0096/1052] Minor correction to error message suggestion --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d6b454bf4..4184d5b30 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8196,7 +8196,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } error_line("\n"); - error_line("\tSuggestion: Was '#partial %s {...}' wanted?\n", type_to_string(index_type)); + error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type)); } } From 67ce0ec29f55621a36ddc1bde83f23a51c9ce355 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 14:58:13 +0000 Subject: [PATCH 0097/1052] Improve printing for unhandled cases by adding a new line before the cases --- src/check_expr.cpp | 2 +- src/check_stmt.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4184d5b30..4664d2244 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8188,7 +8188,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (unhandled.count == 1) { error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string)); } else { - error_no_newline(node, "Unhandled enumerated array cases: "); + error(node, "Unhandled enumerated array cases:"); for_array(i, unhandled) { Entity *f = unhandled[i]; error_line("\t%.*s\n", LIT(f->token.string)); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 2d85db82c..7cae1893f 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1065,7 +1065,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { if (unhandled.count == 1) { error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string)); } else { - error_no_newline(node, "Unhandled switch cases: "); + error(node, "Unhandled switch cases:"); for_array(i, unhandled) { Entity *f = unhandled[i]; error_line("\t%.*s\n", LIT(f->token.string)); From c6ab8f82c88f7d5470fa2fb0459d09ba8a67a287 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 15:17:47 +0000 Subject: [PATCH 0098/1052] Code refactor to aid development --- src/check_expr.cpp | 3552 ++++++++++++++++++++++---------------------- 1 file changed, 1811 insertions(+), 1741 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4664d2244..fb58839bc 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7086,6 +7086,1805 @@ void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, Operand const &x) { add_constant_switch_case(ctx, seen, x); } +ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ast_node(bd, BasicDirective, node); + + ExprKind kind = Expr_Expr; + + o->mode = Addressing_Constant; + String name = bd->name.string; + if (name == "file") { + o->type = t_untyped_string; + o->value = exact_value_string(get_file_path_string(bd->token.pos.file_id)); + } else if (name == "line") { + o->type = t_untyped_integer; + o->value = exact_value_i64(bd->token.pos.line); + } else if (name == "procedure") { + if (c->curr_proc_decl == nullptr) { + error(node, "#procedure may only be used within procedures"); + o->type = t_untyped_string; + o->value = exact_value_string(str_lit("")); + } else { + o->type = t_untyped_string; + o->value = exact_value_string(c->proc_name); + } + } else if (name == "caller_location") { + init_core_source_code_location(c->checker); + error(node, "#caller_location may only be used as a default argument parameter"); + o->type = t_source_code_location; + o->mode = Addressing_Value; + } else { + if (name == "location") { + init_core_source_code_location(c->checker); + error(node, "'#%.*s' must be used in a call expression", LIT(name)); + o->type = t_source_code_location; + o->mode = Addressing_Value; + } else if ( + name == "assert" || + name == "defined" || + name == "config" || + name == "load" || + name == "load_hash" || + name == "load_or" + ) { + error(node, "'#%.*s' must be used as a call", LIT(name)); + o->type = t_invalid; + o->mode = Addressing_Invalid; + } else { + error(node, "Unknown directive: #%.*s", LIT(name)); + o->type = t_invalid; + o->mode = Addressing_Invalid; + } + + } + return kind; +} + +ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ExprKind kind = Expr_Expr; + Operand cond = {Addressing_Invalid}; + ast_node(te, TernaryIfExpr, node); + check_expr(c, &cond, te->cond); + node->viral_state_flags |= te->cond->viral_state_flags; + + if (cond.mode != Addressing_Invalid && !is_type_boolean(cond.type)) { + error(te->cond, "Non-boolean condition in ternary if expression"); + } + + Operand x = {Addressing_Invalid}; + Operand y = {Addressing_Invalid}; + check_expr_or_type(c, &x, te->x, type_hint); + node->viral_state_flags |= te->x->viral_state_flags; + + if (te->y != nullptr) { + check_expr_or_type(c, &y, te->y, type_hint); + node->viral_state_flags |= te->y->viral_state_flags; + } else { + error(node, "A ternary expression must have an else clause"); + return kind; + } + + if (x.type == nullptr || x.type == t_invalid || + y.type == nullptr || y.type == t_invalid) { + return kind; + } + + convert_to_typed(c, &x, y.type); + if (x.mode == Addressing_Invalid) { + return kind; + } + convert_to_typed(c, &y, x.type); + if (y.mode == Addressing_Invalid) { + x.mode = Addressing_Invalid; + return kind; + } + + if (!ternary_compare_types(x.type, y.type)) { + gbString its = type_to_string(x.type); + gbString ets = type_to_string(y.type); + error(node, "Mismatched types in ternary if expression, %s vs %s", its, ets); + gb_string_free(ets); + gb_string_free(its); + return kind; + } + + o->type = x.type; + if (is_type_untyped_nil(o->type) || is_type_untyped_undef(o->type)) { + o->type = y.type; + } + + o->mode = Addressing_Value; + o->expr = node; + if (type_hint != nullptr && is_type_untyped(o->type)) { + if (check_cast_internal(c, &x, type_hint) && + check_cast_internal(c, &y, type_hint)) { + convert_to_typed(c, o, type_hint); + update_untyped_expr_type(c, node, type_hint, !is_type_untyped(type_hint)); + } + } + return kind; +} + +ExprKind check_ternary_when_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ExprKind kind = Expr_Expr; + Operand cond = {}; + ast_node(te, TernaryWhenExpr, node); + check_expr(c, &cond, te->cond); + node->viral_state_flags |= te->cond->viral_state_flags; + + if (cond.mode != Addressing_Constant || !is_type_boolean(cond.type)) { + error(te->cond, "Expected a constant boolean condition in ternary when expression"); + return kind; + } + + if (cond.value.value_bool) { + check_expr_or_type(c, o, te->x, type_hint); + node->viral_state_flags |= te->x->viral_state_flags; + } else { + if (te->y != nullptr) { + check_expr_or_type(c, o, te->y, type_hint); + node->viral_state_flags |= te->y->viral_state_flags; + } else { + error(node, "A ternary when expression must have an else clause"); + return kind; + } + } + return kind; +} + +ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ast_node(oe, OrElseExpr, node); + + String name = oe->token.string; + Ast *arg = oe->x; + Ast *default_value = oe->y; + + Operand x = {}; + Operand y = {}; + check_multi_expr_with_type_hint(c, &x, arg, type_hint); + if (x.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } + + check_multi_expr_with_type_hint(c, &y, default_value, x.type); + error_operand_no_value(&y); + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } + + Type *left_type = nullptr; + Type *right_type = nullptr; + check_or_else_split_types(c, &x, name, &left_type, &right_type); + add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); + + if (left_type != nullptr) { + check_assignment(c, &y, left_type, name); + } else { + check_or_else_expr_no_value_error(c, name, x, type_hint); + } + + if (left_type == nullptr) { + left_type = t_invalid; + } + o->mode = Addressing_Value; + o->type = left_type; + o->expr = node; + return Expr_Expr; +} + +ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ast_node(re, OrReturnExpr, node); + + String name = re->token.string; + Operand x = {}; + check_multi_expr_with_type_hint(c, &x, re->expr, type_hint); + if (x.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } + + Type *left_type = nullptr; + Type *right_type = nullptr; + check_or_return_split_types(c, &x, name, &left_type, &right_type); + add_type_and_value(&c->checker->info, re->expr, x.mode, x.type, x.value); + + if (right_type == nullptr) { + check_or_else_expr_no_value_error(c, name, x, type_hint); + } else { + Type *proc_type = base_type(c->curr_proc_sig); + GB_ASSERT(proc_type->kind == Type_Proc); + Type *result_type = proc_type->Proc.results; + if (result_type == nullptr) { + error(node, "'%.*s' requires the current procedure to have at least one return value", LIT(name)); + } else { + GB_ASSERT(result_type->kind == Type_Tuple); + + auto const &vars = result_type->Tuple.variables; + Type *end_type = vars[vars.count-1]->type; + + if (vars.count > 1) { + if (!proc_type->Proc.has_named_results) { + error(node, "'%.*s' within a procedure with more than 1 return value requires that the return values are named, allowing for early return", LIT(name)); + } + } + + Operand rhs = {}; + rhs.type = right_type; + rhs.mode = Addressing_Value; + + // TODO(bill): better error message + if (!check_is_assignable_to(c, &rhs, end_type)) { + gbString a = type_to_string(right_type); + gbString b = type_to_string(end_type); + gbString ret_type = type_to_string(result_type); + error(node, "Cannot assign end value of type '%s' to '%s' in '%.*s'", a, b, LIT(name)); + if (vars.count == 1) { + error_line("\tProcedure return value type: %s\n", ret_type); + } else { + error_line("\tProcedure return value types: (%s)\n", ret_type); + } + gb_string_free(ret_type); + gb_string_free(b); + gb_string_free(a); + } + } + } + + o->expr = node; + o->type = left_type; + if (left_type != nullptr) { + o->mode = Addressing_Value; + } else { + o->mode = Addressing_NoValue; + } + + if (c->curr_proc_sig == nullptr) { + error(node, "'%.*s' can only be used within a procedure", LIT(name)); + } + + if (c->in_defer) { + error(node, "'or_return' cannot be used within a defer statement"); + } + + return Expr_Expr; +} + +ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ExprKind kind = Expr_Expr; + ast_node(cl, CompoundLit, node); + + Type *type = type_hint; + if (type != nullptr && is_type_untyped(type)) { + type = nullptr; + } + bool is_to_be_determined_array_count = false; + bool is_constant = true; + if (cl->type != nullptr) { + type = nullptr; + + // [?]Type + if (cl->type->kind == Ast_ArrayType && cl->type->ArrayType.count != nullptr) { + Ast *count = cl->type->ArrayType.count; + if (count->kind == Ast_UnaryExpr && + count->UnaryExpr.op.kind == Token_Question) { + type = alloc_type_array(check_type(c, cl->type->ArrayType.elem), -1); + is_to_be_determined_array_count = true; + } + if (cl->elems.count > 0) { + if (cl->type->ArrayType.tag != nullptr) { + Ast *tag = cl->type->ArrayType.tag; + GB_ASSERT(tag->kind == Ast_BasicDirective); + String name = tag->BasicDirective.name.string; + if (name == "soa") { + error(node, "#soa arrays are not supported for compound literals"); + return kind; + } + } + } + } + if (cl->type->kind == Ast_DynamicArrayType && cl->type->DynamicArrayType.tag != nullptr) { + if (cl->elems.count > 0) { + Ast *tag = cl->type->DynamicArrayType.tag; + GB_ASSERT(tag->kind == Ast_BasicDirective); + String name = tag->BasicDirective.name.string; + if (name == "soa") { + error(node, "#soa arrays are not supported for compound literals"); + return kind; + } + } + } + + if (type == nullptr) { + type = check_type(c, cl->type); + } + } + + if (type == nullptr) { + error(node, "Missing type in compound literal"); + return kind; + } + + + Type *t = base_type(type); + if (is_type_polymorphic(t)) { + gbString str = type_to_string(type); + error(node, "Cannot use a polymorphic type for a compound literal, got '%s'", str); + o->expr = node; + o->type = type; + gb_string_free(str); + return kind; + } + + + switch (t->kind) { + case Type_Struct: { + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + if (t->Struct.is_raw_union) { + if (cl->elems.count > 0) { + // NOTE: unions cannot be constant + is_constant = false; + + if (cl->elems[0]->kind != Ast_FieldValue) { + gbString type_str = type_to_string(type); + error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str); + gb_string_free(type_str); + } else { + if (cl->elems.count != 1) { + gbString type_str = type_to_string(type); + error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); + gb_string_free(type_str); + } else { + Ast *elem = cl->elems[0]; + ast_node(fv, FieldValue, elem); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(elem, "Invalid field name '%s' in structure literal", expr_str); + gb_string_free(expr_str); + break; + } + + String name = fv->field->Ident.token.string; + + Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + bool is_unknown = sel.entity == nullptr; + if (is_unknown) { + error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); + break; + } + + if (sel.index.count > 1) { + error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); + break; + } + + Entity *field = t->Struct.fields[sel.index[0]]; + add_entity_use(c, fv->field, field); + + Operand o = {}; + check_expr_or_type(c, &o, fv->value, field->type); + + + check_assignment(c, &o, field->type, str_lit("structure literal")); + } + + } + } + break; + } + + + isize field_count = t->Struct.fields.count; + isize min_field_count = t->Struct.fields.count; + for (isize i = min_field_count-1; i >= 0; i--) { + Entity *e = t->Struct.fields[i]; + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + min_field_count--; + } else { + break; + } + } + + if (cl->elems[0]->kind == Ast_FieldValue) { + bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(elem, "Invalid field name '%s' in structure literal", expr_str); + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.token.string; + + Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + bool is_unknown = sel.entity == nullptr; + if (is_unknown) { + error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); + continue; + } + + if (sel.index.count > 1) { + error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); + continue; + } + + Entity *field = t->Struct.fields[sel.index[0]]; + add_entity_use(c, fv->field, field); + + if (fields_visited[sel.index[0]]) { + error(elem, "Duplicate field '%.*s' in structure literal", LIT(name)); + continue; + } + + fields_visited[sel.index[0]] = true; + + Operand o = {}; + check_expr_or_type(c, &o, fv->value, field->type); + + if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + is_constant = false; + } + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &o); + } + + check_assignment(c, &o, field->type, str_lit("structure literal")); + } + } else { + bool seen_field_value = false; + + for_array(index, cl->elems) { + Entity *field = nullptr; + Ast *elem = cl->elems[index]; + if (elem->kind == Ast_FieldValue) { + seen_field_value = true; + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } else if (seen_field_value) { + error(elem, "Value elements cannot be used after a 'field = value'"); + continue; + } + if (index >= field_count) { + error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count); + break; + } + + if (field == nullptr) { + field = t->Struct.fields[index]; + } + + Operand o = {}; + check_expr_or_type(c, &o, elem, field->type); + + if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + is_constant = false; + } + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &o); + } + + check_assignment(c, &o, field->type, str_lit("structure literal")); + } + if (cl->elems.count < field_count) { + if (min_field_count < field_count) { + if (cl->elems.count < min_field_count) { + error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count); + } + } else { + error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count); + } + } + } + + break; + } + + case Type_Slice: + case Type_Array: + case Type_DynamicArray: + case Type_SimdVector: + case Type_Matrix: + { + Type *elem_type = nullptr; + String context_name = {}; + i64 max_type_count = -1; + if (t->kind == Type_Slice) { + elem_type = t->Slice.elem; + context_name = str_lit("slice literal"); + } else if (t->kind == Type_Array) { + elem_type = t->Array.elem; + context_name = str_lit("array literal"); + if (!is_to_be_determined_array_count) { + max_type_count = t->Array.count; + } + } else if (t->kind == Type_DynamicArray) { + elem_type = t->DynamicArray.elem; + context_name = str_lit("dynamic array literal"); + is_constant = false; + + if (!build_context.no_dynamic_literals) { + add_package_dependency(c, "runtime", "__dynamic_array_reserve"); + add_package_dependency(c, "runtime", "__dynamic_array_append"); + } + } else if (t->kind == Type_SimdVector) { + elem_type = t->SimdVector.elem; + context_name = str_lit("simd vector literal"); + max_type_count = t->SimdVector.count; + } else if (t->kind == Type_Matrix) { + elem_type = t->Matrix.elem; + context_name = str_lit("matrix literal"); + max_type_count = t->Matrix.row_count*t->Matrix.column_count; + } else { + GB_PANIC("unreachable"); + } + + + i64 max = 0; + + Type *bet = base_type(elem_type); + if (!elem_type_can_be_constant(bet)) { + is_constant = false; + } + + if (bet == t_invalid) { + break; + } + + if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { + if (is_type_simd_vector(t)) { + error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals"); + } else { + RangeCache rc = range_cache_make(heap_allocator()); + defer (range_cache_destroy(&rc)); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + + if (is_ast_range(fv->field)) { + Token op = fv->field->BinaryExpr.op; + + Operand x = {}; + Operand y = {}; + bool ok = check_range(c, fv->field, &x, &y, nullptr); + if (!ok) { + continue; + } + if (x.mode != Addressing_Constant || !is_type_integer(core_type(x.type))) { + error(x.expr, "Expected a constant integer as an array field"); + continue; + } + + if (y.mode != Addressing_Constant || !is_type_integer(core_type(y.type))) { + error(y.expr, "Expected a constant integer as an array field"); + continue; + } + + i64 lo = exact_value_to_i64(x.value); + i64 hi = exact_value_to_i64(y.value); + i64 max_index = hi; + if (op.kind == Token_RangeHalf) { // ..< (exclusive) + hi -= 1; + } else { // .. (inclusive) + max_index += 1; + } + + bool new_range = range_cache_add_range(&rc, lo, hi); + if (!new_range) { + error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name)); + continue; + } + + + if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name)); + continue; + } + if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name)); + continue; + } + + if (max < hi) { + max = max_index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } else { + Operand op_index = {}; + check_expr(c, &op_index, fv->field); + + if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { + error(elem, "Expected a constant integer as an array field"); + continue; + } + // add_type_and_value(c->info, op_index.expr, op_index.mode, op_index.type, op_index.value); + + i64 index = exact_value_to_i64(op_index.value); + + if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); + continue; + } + + bool new_index = range_cache_add_index(&rc, index); + if (!new_index) { + error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); + continue; + } + + if (max < index+1) { + max = index+1; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } + } + + cl->max_count = max; + } + + } else { + isize index = 0; + for (; index < cl->elems.count; index++) { + Ast *e = cl->elems[index]; + if (e == nullptr) { + error(node, "Invalid literal element"); + continue; + } + + if (e->kind == Ast_FieldValue) { + error(e, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + + if (0 <= max_type_count && max_type_count <= index) { + error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, e, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } + + if (max < index) { + max = index; + } + } + + + if (t->kind == Type_Array) { + if (is_to_be_determined_array_count) { + t->Array.count = max; + } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < t->Array.count) { + error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); + } + } + } + + + if (t->kind == Type_SimdVector) { + if (!is_constant) { + error(node, "Expected all constant elements for a simd vector"); + } + } + + + if (t->kind == Type_DynamicArray) { + if (build_context.no_dynamic_literals && cl->elems.count) { + error(node, "Compound literals of dynamic types have been disabled"); + } + } + + if (t->kind == Type_Matrix) { + if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < max_type_count) { + error(node, "Expected %lld values for this matrix literal, got %lld", cast(long long)max_type_count, cast(long long)max); + } + } + } + + break; + } + + case Type_EnumeratedArray: + { + Type *elem_type = t->EnumeratedArray.elem; + Type *index_type = t->EnumeratedArray.index; + String context_name = str_lit("enumerated array literal"); + i64 max_type_count = t->EnumeratedArray.count; + + gbString index_type_str = type_to_string(index_type); + defer (gb_string_free(index_type_str)); + + i64 total_lo = exact_value_to_i64(*t->EnumeratedArray.min_value); + i64 total_hi = exact_value_to_i64(*t->EnumeratedArray.max_value); + + String total_lo_string = {}; + String total_hi_string = {}; + GB_ASSERT(is_type_enum(index_type)); + { + Type *bt = base_type(index_type); + GB_ASSERT(bt->kind == Type_Enum); + for_array(i, bt->Enum.fields) { + Entity *f = bt->Enum.fields[i]; + if (f->kind != Entity_Constant) { + continue; + } + if (total_lo_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, *t->EnumeratedArray.min_value)) { + total_lo_string = f->token.string; + } + if (total_hi_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, *t->EnumeratedArray.max_value)) { + total_hi_string = f->token.string; + } + if (total_lo_string.len != 0 && total_hi_string.len != 0) { + break; + } + } + } + + i64 max = 0; + + Type *bet = base_type(elem_type); + if (!elem_type_can_be_constant(bet)) { + is_constant = false; + } + + if (bet == t_invalid) { + break; + } + bool is_partial = cl->tag && (cl->tag->BasicDirective.name.string == "partial"); + + SeenMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue + map_init(&seen, heap_allocator()); + defer (map_destroy(&seen)); + + if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { + RangeCache rc = range_cache_make(heap_allocator()); + defer (range_cache_destroy(&rc)); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + + if (is_ast_range(fv->field)) { + Token op = fv->field->BinaryExpr.op; + + Operand x = {}; + Operand y = {}; + bool ok = check_range(c, fv->field, &x, &y, nullptr, index_type); + if (!ok) { + continue; + } + if (x.mode != Addressing_Constant || !are_types_identical(x.type, index_type)) { + error(x.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); + continue; + } + + if (y.mode != Addressing_Constant || !are_types_identical(x.type, index_type)) { + error(y.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); + continue; + } + + i64 lo = exact_value_to_i64(x.value); + i64 hi = exact_value_to_i64(y.value); + i64 max_index = hi; + if (op.kind == Token_RangeHalf) { + hi -= 1; + } + + bool new_range = range_cache_add_range(&rc, lo, hi); + if (!new_range) { + gbString lo_str = expr_to_string(x.expr); + gbString hi_str = expr_to_string(y.expr); + error(elem, "Overlapping field range index %s %.*s %s for %.*s", lo_str, LIT(op.string), hi_str, LIT(context_name)); + gb_string_free(hi_str); + gb_string_free(lo_str); + continue; + } + + + // NOTE(bill): These are sanity checks for invalid enum values + if (max_type_count >= 0 && (lo < total_lo || lo > total_hi)) { + gbString lo_str = expr_to_string(x.expr); + error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", lo_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); + gb_string_free(lo_str); + continue; + } + if (max_type_count >= 0 && (hi < 0 || hi > total_hi)) { + gbString hi_str = expr_to_string(y.expr); + error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", hi_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); + gb_string_free(hi_str); + continue; + } + + if (max < hi) { + max = max_index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + + TokenKind upper_op = Token_LtEq; + if (op.kind == Token_RangeHalf) { + upper_op = Token_Lt; + } + add_to_seen_map(c, &seen, upper_op, x, x, y); + } else { + Operand op_index = {}; + check_expr_with_type_hint(c, &op_index, fv->field, index_type); + + if (op_index.mode != Addressing_Constant || !are_types_identical(op_index.type, index_type)) { + error(op_index.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); + continue; + } + + i64 index = exact_value_to_i64(op_index.value); + + if (max_type_count >= 0 && (index < total_lo || index > total_hi)) { + gbString idx_str = expr_to_string(op_index.expr); + error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", idx_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); + gb_string_free(idx_str); + continue; + } + + bool new_index = range_cache_add_index(&rc, index); + if (!new_index) { + gbString idx_str = expr_to_string(op_index.expr); + error(elem, "Duplicate field index %s for %.*s", idx_str, LIT(context_name)); + gb_string_free(idx_str); + continue; + } + + if (max < index+1) { + max = index+1; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + + add_to_seen_map(c, &seen, op_index); + } + } + + cl->max_count = max; + + } else { + isize index = 0; + for (; index < cl->elems.count; index++) { + Ast *e = cl->elems[index]; + if (e == nullptr) { + error(node, "Invalid literal element"); + continue; + } + + if (e->kind == Ast_FieldValue) { + error(e, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + + if (0 <= max_type_count && max_type_count <= index) { + error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, e, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } + + if (max < index) { + max = index; + } + } + + bool was_error = false; + if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < t->EnumeratedArray.count) { + error(node, "Expected %lld values for this enumerated array literal, got %lld", cast(long long)t->EnumeratedArray.count, cast(long long)max); + was_error = true; + } else { + error(node, "Enumerated array literals must only have 'field = value' elements, bare elements are not allowed"); + was_error = true; + } + } + + // NOTE(bill): Check for missing cases when `#partial literal` is not present + if (cl->elems.count > 0 && !was_error && !is_partial) { + Type *et = base_type(index_type); + GB_ASSERT(et->kind == Type_Enum); + auto fields = et->Enum.fields; + + auto unhandled = array_make(temporary_allocator(), 0, fields.count); + + for_array(i, fields) { + Entity *f = fields[i]; + if (f->kind != Entity_Constant) { + continue; + } + ExactValue v = f->Constant.value; + auto found = map_get(&seen, hash_exact_value(v)); + if (!found) { + array_add(&unhandled, f); + } + } + + if (unhandled.count > 0) { + begin_error_block(); + defer (end_error_block()); + + if (unhandled.count == 1) { + error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string)); + } else { + error(node, "Unhandled enumerated array cases:"); + for_array(i, unhandled) { + Entity *f = unhandled[i]; + error_line("\t%.*s\n", LIT(f->token.string)); + } + } + error_line("\n"); + + error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type)); + } + } + + break; + } + + case Type_Basic: { + if (!is_type_any(t)) { + if (cl->elems.count != 0) { + error(node, "Illegal compound literal"); + } + break; + } + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + { // Checker values + Type *field_types[2] = {t_rawptr, t_typeid}; + isize field_count = 2; + if (cl->elems[0]->kind == Ast_FieldValue) { + bool fields_visited[2] = {}; + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a 'any' literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(elem, "Invalid field name '%s' in 'any' literal", expr_str); + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.token.string; + + Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + if (sel.entity == nullptr) { + error(elem, "Unknown field '%.*s' in 'any' literal", LIT(name)); + continue; + } + + isize index = sel.index[0]; + + if (fields_visited[index]) { + error(elem, "Duplicate field '%.*s' in 'any' literal", LIT(name)); + continue; + } + + fields_visited[index] = true; + check_expr(c, o, fv->value); + + // NOTE(bill): 'any' literals can never be constant + is_constant = false; + + check_assignment(c, o, field_types[index], str_lit("'any' literal")); + } + } else { + for_array(index, cl->elems) { + Ast *elem = cl->elems[index]; + if (elem->kind == Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a 'any' literal is not allowed"); + continue; + } + + + check_expr(c, o, elem); + if (index >= field_count) { + error(o->expr, "Too many values in 'any' literal, expected %td", field_count); + break; + } + + // NOTE(bill): 'any' literals can never be constant + is_constant = false; + + check_assignment(c, o, field_types[index], str_lit("'any' literal")); + } + if (cl->elems.count < field_count) { + error(cl->close, "Too few values in 'any' literal, expected %td, got %td", field_count, cl->elems.count); + } + } + } + + break; + } + + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + is_constant = false; + { // Checker values + bool key_is_typeid = is_type_typeid(t->Map.key); + bool value_is_typeid = is_type_typeid(t->Map.value); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Only 'field = value' elements are allowed in a map literal"); + continue; + } + ast_node(fv, FieldValue, elem); + + if (key_is_typeid) { + check_expr_or_type(c, o, fv->field, t->Map.key); + } else { + check_expr_with_type_hint(c, o, fv->field, t->Map.key); + } + check_assignment(c, o, t->Map.key, str_lit("map literal")); + if (o->mode == Addressing_Invalid) { + continue; + } + + if (value_is_typeid) { + check_expr_or_type(c, o, fv->value, t->Map.value); + } else { + check_expr_with_type_hint(c, o, fv->value, t->Map.value); + } + check_assignment(c, o, t->Map.value, str_lit("map literal")); + } + } + + if (build_context.no_dynamic_literals && cl->elems.count) { + error(node, "Compound literals of dynamic types have been disabled"); + } else { + add_package_dependency(c, "runtime", "__dynamic_map_reserve"); + add_package_dependency(c, "runtime", "__dynamic_map_set"); + } + break; + } + + case Type_BitSet: { + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + Type *et = base_type(t->BitSet.elem); + isize field_count = 0; + if (et->kind == Type_Enum) { + field_count = et->Enum.fields.count; + } + + if (cl->elems[0]->kind == Ast_FieldValue) { + error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed"); + is_constant = false; + } else { + for_array(index, cl->elems) { + Ast *elem = cl->elems[index]; + if (elem->kind == Ast_FieldValue) { + error(elem, "'field = value' in a bit_set a literal is not allowed"); + continue; + } + + check_expr_with_type_hint(c, o, elem, et); + + if (is_constant) { + is_constant = o->mode == Addressing_Constant; + } + + check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); + if (o->mode == Addressing_Constant) { + i64 lower = t->BitSet.lower; + i64 upper = t->BitSet.upper; + i64 v = exact_value_to_i64(o->value); + if (lower <= v && v <= upper) { + // okay + } else { + error(elem, "Bit field value out of bounds, %lld not in the range %lld .. %lld", v, lower, upper); + continue; + } + } + } + } + break; + } + + default: { + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + + gbString str = type_to_string(type); + error(node, "Invalid compound literal type '%s'", str); + gb_string_free(str); + return kind; + } + } + + if (is_constant) { + o->mode = Addressing_Constant; + + if (is_type_bit_set(type)) { + // NOTE(bill): Encode as an integer + + i64 lower = base_type(type)->BitSet.lower; + + u64 bits = 0; + for_array(index, cl->elems) { + Ast *elem = cl->elems[index]; + GB_ASSERT(elem->kind != Ast_FieldValue); + TypeAndValue tav = elem->tav; + ExactValue i = exact_value_to_integer(tav.value); + if (i.kind != ExactValue_Integer) { + continue; + } + i64 val = big_int_to_i64(&i.value_integer); + val -= lower; + u64 bit = u64(1ll<value = exact_value_u64(bits); + } else if (is_type_constant_type(type) && cl->elems.count == 0) { + ExactValue value = exact_value_compound(node); + Type *bt = core_type(type); + if (bt->kind == Type_Basic) { + if (bt->Basic.flags & BasicFlag_Boolean) { + value = exact_value_bool(false); + } else if (bt->Basic.flags & BasicFlag_Integer) { + value = exact_value_i64(0); + } else if (bt->Basic.flags & BasicFlag_Unsigned) { + value = exact_value_i64(0); + } else if (bt->Basic.flags & BasicFlag_Float) { + value = exact_value_float(0); + } else if (bt->Basic.flags & BasicFlag_Complex) { + value = exact_value_complex(0, 0); + } else if (bt->Basic.flags & BasicFlag_Quaternion) { + value = exact_value_quaternion(0, 0, 0, 0); + } else if (bt->Basic.flags & BasicFlag_Pointer) { + value = exact_value_pointer(0); + } else if (bt->Basic.flags & BasicFlag_String) { + String empty_string = {}; + value = exact_value_string(empty_string); + } else if (bt->Basic.flags & BasicFlag_Rune) { + value = exact_value_i64(0); + } + } + + o->value = value; + } else { + o->value = exact_value_compound(node); + } + } else { + o->mode = Addressing_Value; + } + o->type = type; + return kind; +} + +ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ExprKind kind = Expr_Expr; + ast_node(ta, TypeAssertion, node); + check_expr(c, o, ta->expr); + node->viral_state_flags |= ta->expr->viral_state_flags; + + if (o->mode == Addressing_Invalid) { + o->expr = node; + return kind; + } + if (o->mode == Addressing_Constant) { + gbString expr_str = expr_to_string(o->expr); + error(o->expr, "A type assertion cannot be applied to a constant expression: '%s'", expr_str); + gb_string_free(expr_str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + if (is_type_untyped(o->type)) { + gbString expr_str = expr_to_string(o->expr); + error(o->expr, "A type assertion cannot be applied to an untyped expression: '%s'", expr_str); + gb_string_free(expr_str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + Type *src = type_deref(o->type); + Type *bsrc = base_type(src); + + + if (ta->type != nullptr && ta->type->kind == Ast_UnaryExpr && ta->type->UnaryExpr.op.kind == Token_Question) { + if (!is_type_union(src)) { + gbString str = type_to_string(o->type); + error(o->expr, "Type assertions with .? can only operate on unions, got %s", str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + if (bsrc->Union.variants.count != 1 && type_hint != nullptr) { + bool allowed = false; + for_array(i, bsrc->Union.variants) { + Type *vt = bsrc->Union.variants[i]; + if (are_types_identical(vt, type_hint)) { + allowed = true; + add_type_info_type(c, vt); + break; + } + } + if (allowed) { + add_type_info_type(c, o->type); + o->type = type_hint; + o->mode = Addressing_OptionalOk; + return kind; + } + } + + if (bsrc->Union.variants.count != 1) { + error(o->expr, "Type assertions with .? can only operate on unions with 1 variant, got %lld", cast(long long)bsrc->Union.variants.count); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + add_type_info_type(c, o->type); + add_type_info_type(c, bsrc->Union.variants[0]); + + o->type = bsrc->Union.variants[0]; + o->mode = Addressing_OptionalOk; + } else { + Type *t = check_type(c, ta->type); + Type *dst = t; + + if (is_type_union(src)) { + bool ok = false; + for_array(i, bsrc->Union.variants) { + Type *vt = bsrc->Union.variants[i]; + if (are_types_identical(vt, dst)) { + ok = true; + break; + } + } + + if (!ok) { + gbString expr_str = expr_to_string(o->expr); + gbString dst_type_str = type_to_string(t); + defer (gb_string_free(expr_str)); + defer (gb_string_free(dst_type_str)); + if (bsrc->Union.variants.count == 0) { + error(o->expr, "Cannot type assert '%s' to '%s' as this is an empty union", expr_str, dst_type_str); + } else { + error(o->expr, "Cannot type assert '%s' to '%s' as it is not a variant of that union", expr_str, dst_type_str); + } + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + add_type_info_type(c, o->type); + add_type_info_type(c, t); + + o->type = t; + o->mode = Addressing_OptionalOk; + } else if (is_type_any(src)) { + o->type = t; + o->mode = Addressing_OptionalOk; + + add_type_info_type(c, o->type); + add_type_info_type(c, t); + } else { + gbString str = type_to_string(o->type); + error(o->expr, "Type assertions can only operate on unions and 'any', got %s", str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + } + + if ((c->state_flags & StateFlag_no_type_assert) == 0) { + add_package_dependency(c, "runtime", "type_assertion_check"); + add_package_dependency(c, "runtime", "type_assertion_check2"); + } + return kind; +} + +ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ast_node(se, SelectorCallExpr, node); + // IMPORTANT NOTE(bill, 2020-05-22): This is a complete hack to get a shorthand which is extremely useful for vtables + // COM APIs is a great example of where this kind of thing is extremely useful + // General idea: + // + // x->y(123) == x.y(x, 123) + // + // How this has been implemented at the moment is quite hacky but it's done so to reduce need for huge backend changes + // Just regenerating a new AST aids things + // + // TODO(bill): Is this a good hack or not? + // + // NOTE(bill, 2020-05-22): I'm going to regret this decision, ain't I? + + + if (se->modified_call) { + // Prevent double evaluation + o->expr = node; + o->type = node->tav.type; + o->value = node->tav.value; + o->mode = node->tav.mode; + return Expr_Expr; + } + + bool allow_arrow_right_selector_expr; + allow_arrow_right_selector_expr = c->allow_arrow_right_selector_expr; + c->allow_arrow_right_selector_expr = true; + Operand x = {}; + ExprKind kind = check_expr_base(c, &x, se->expr, nullptr); + c->allow_arrow_right_selector_expr = allow_arrow_right_selector_expr; + + if (x.mode == Addressing_Invalid || x.type == t_invalid) { + o->mode = Addressing_Invalid; + o->type = t_invalid; + o->expr = node; + return kind; + } + if (!is_type_proc(x.type)) { + gbString type_str = type_to_string(x.type); + error(se->call, "Selector call expressions expect a procedure type for the call, got '%s'", type_str); + gb_string_free(type_str); + + o->mode = Addressing_Invalid; + o->type = t_invalid; + o->expr = node; + return Expr_Stmt; + } + + ast_node(ce, CallExpr, se->call); + + GB_ASSERT(x.expr->kind == Ast_SelectorExpr); + + Ast *first_arg = x.expr->SelectorExpr.expr; + GB_ASSERT(first_arg != nullptr); + + Type *pt = base_type(x.type); + GB_ASSERT(pt->kind == Type_Proc); + Type *first_type = nullptr; + String first_arg_name = {}; + if (pt->Proc.param_count > 0) { + Entity *f = pt->Proc.params->Tuple.variables[0]; + first_type = f->type; + first_arg_name = f->token.string; + } + if (first_arg_name.len == 0) { + first_arg_name = str_lit("_"); + } + + if (first_type == nullptr) { + error(se->call, "Selector call expressions expect a procedure type for the call with at least 1 parameter"); + o->mode = Addressing_Invalid; + o->type = t_invalid; + o->expr = node; + return Expr_Stmt; + } + + Operand y = {}; + y.mode = first_arg->tav.mode; + y.type = first_arg->tav.type; + y.value = first_arg->tav.value; + if (check_is_assignable_to(c, &y, first_type)) { + // Do nothing, it's valid + } else { + Operand z = y; + z.type = type_deref(y.type); + if (check_is_assignable_to(c, &z, first_type)) { + // NOTE(bill): AST GENERATION HACK! + Token op = {Token_Pointer}; + first_arg = ast_deref_expr(first_arg->file(), first_arg, op); + } else if (y.mode == Addressing_Variable) { + Operand w = y; + w.type = alloc_type_pointer(y.type); + if (check_is_assignable_to(c, &w, first_type)) { + // NOTE(bill): AST GENERATION HACK! + Token op = {Token_And}; + first_arg = ast_unary_expr(first_arg->file(), op, first_arg); + } + } + } + + if (ce->args.count > 0) { + bool fail = false; + bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue); + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != Ast_FieldValue; + } else { + mix = arg->kind == Ast_FieldValue; + } + if (mix) { + fail = true; + break; + } + } + if (!fail && first_is_field_value) { + Token op = {Token_Eq}; + AstFile *f = first_arg->file(); + first_arg = ast_field_value(f, ast_ident(f, make_token_ident(first_arg_name)), first_arg, op); + } + } + + + + auto modified_args = slice_make(heap_allocator(), ce->args.count+1); + modified_args[0] = first_arg; + slice_copy(&modified_args, ce->args, 1); + ce->args = modified_args; + se->modified_call = true; + + allow_arrow_right_selector_expr = c->allow_arrow_right_selector_expr; + c->allow_arrow_right_selector_expr = true; + check_expr_base(c, o, se->call, type_hint); + c->allow_arrow_right_selector_expr = allow_arrow_right_selector_expr; + + o->expr = node; + return Expr_Expr; +} + + +ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ExprKind kind = Expr_Expr; + ast_node(ie, IndexExpr, node); + check_expr(c, o, ie->expr); + node->viral_state_flags |= ie->expr->viral_state_flags; + if (o->mode == Addressing_Invalid) { + o->expr = node; + return kind; + } + + Type *t = base_type(type_deref(o->type)); + bool is_ptr = is_type_pointer(o->type); + bool is_const = o->mode == Addressing_Constant; + + if (is_type_map(t)) { + Operand key = {}; + if (is_type_typeid(t->Map.key)) { + check_expr_or_type(c, &key, ie->index, t->Map.key); + } else { + check_expr_with_type_hint(c, &key, ie->index, t->Map.key); + } + check_assignment(c, &key, t->Map.key, str_lit("map index")); + if (key.mode == Addressing_Invalid) { + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + o->mode = Addressing_MapIndex; + o->type = t->Map.value; + o->expr = node; + + add_package_dependency(c, "runtime", "__dynamic_map_get"); + add_package_dependency(c, "runtime", "__dynamic_map_set"); + return Expr_Expr; + } + + i64 max_count = -1; + bool valid = check_set_index_data(o, t, is_ptr, &max_count, o->type); + + if (is_const) { + if (is_type_array(t)) { + // OKay + } else if (is_type_slice(t)) { + // Okay + } else if (is_type_enumerated_array(t)) { + // Okay + } else if (is_type_string(t)) { + // Okay + } else if (is_type_relative_slice(t)) { + // Okay + } else if (is_type_matrix(t)) { + // Okay + } else { + valid = false; + } + } + + if (!valid) { + gbString str = expr_to_string(o->expr); + gbString type_str = type_to_string(o->type); + defer (gb_string_free(str)); + defer (gb_string_free(type_str)); + if (is_const) { + error(o->expr, "Cannot index constant '%s' of type '%s'", str, type_str); + } else { + error(o->expr, "Cannot index '%s' of type '%s'", str, type_str); + } + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + if (ie->index == nullptr) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Missing index for '%s'", str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + Type *index_type_hint = nullptr; + if (is_type_enumerated_array(t)) { + Type *bt = base_type(t); + GB_ASSERT(bt->kind == Type_EnumeratedArray); + index_type_hint = bt->EnumeratedArray.index; + } + + i64 index = 0; + bool ok = check_index_value(c, t, false, ie->index, max_count, &index, index_type_hint); + if (is_const) { + if (index < 0) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Cannot index a constant '%s'", str); + error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } else if (ok) { + ExactValue value = type_and_value_of_expr(ie->expr).value; + o->mode = Addressing_Constant; + bool success = false; + bool finish = false; + o->value = get_constant_field_single(c, value, cast(i32)index, &success, &finish); + if (!success) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index); + error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + } + } + + if (type_hint != nullptr && is_type_matrix(t)) { + // TODO(bill): allow matrix columns to be assignable to other types which are the same internally + // if a type hint exists + } + return kind; +} + +ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { + ExprKind kind = Expr_Stmt; + ast_node(se, SliceExpr, node); + check_expr(c, o, se->expr); + node->viral_state_flags |= se->expr->viral_state_flags; + + if (o->mode == Addressing_Invalid) { + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + bool valid = false; + i64 max_count = -1; + Type *t = base_type(type_deref(o->type)); + switch (t->kind) { + case Type_Basic: + if (t->Basic.kind == Basic_string || t->Basic.kind == Basic_UntypedString) { + valid = true; + if (o->mode == Addressing_Constant) { + max_count = o->value.value_string.len; + } + o->type = type_deref(o->type); + } + break; + + case Type_Array: + valid = true; + max_count = t->Array.count; + if (o->mode != Addressing_Variable && !is_type_pointer(o->type)) { + gbString str = expr_to_string(node); + error(node, "Cannot slice array '%s', value is not addressable", str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + o->type = alloc_type_slice(t->Array.elem); + break; + + case Type_MultiPointer: + valid = true; + o->type = type_deref(o->type); + break; + + case Type_Slice: + valid = true; + o->type = type_deref(o->type); + break; + + case Type_DynamicArray: + valid = true; + o->type = alloc_type_slice(t->DynamicArray.elem); + break; + + case Type_Struct: + if (is_type_soa_struct(t)) { + valid = true; + o->type = make_soa_struct_slice(c, nullptr, nullptr, t->Struct.soa_elem); + } + break; + + case Type_RelativeSlice: + valid = true; + o->type = t->RelativeSlice.slice_type; + if (o->mode != Addressing_Variable) { + gbString str = expr_to_string(node); + error(node, "Cannot relative slice '%s', value is not addressable", str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + break; + } + + if (!valid) { + gbString str = expr_to_string(o->expr); + gbString type_str = type_to_string(o->type); + error(o->expr, "Cannot slice '%s' of type '%s'", str, type_str); + gb_string_free(type_str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + if (se->low == nullptr && se->high != nullptr) { + // It is okay to continue as it will assume the 1st index is zero + } + + i64 indices[2] = {}; + Ast *nodes[2] = {se->low, se->high}; + for (isize i = 0; i < gb_count_of(nodes); i++) { + i64 index = max_count; + if (nodes[i] != nullptr) { + i64 capacity = -1; + if (max_count >= 0) { + capacity = max_count; + } + i64 j = 0; + if (check_index_value(c, t, true, nodes[i], capacity, &j)) { + index = j; + } + + node->viral_state_flags |= nodes[i]->viral_state_flags; + } else if (i == 0) { + index = 0; + } + indices[i] = index; + } + + for (isize i = 0; i < gb_count_of(indices); i++) { + i64 a = indices[i]; + for (isize j = i+1; j < gb_count_of(indices); j++) { + i64 b = indices[j]; + if (a > b && b >= 0) { + error(se->close, "Invalid slice indices: [%td > %td]", a, b); + } + } + } + + if (max_count < 0) { + if (o->mode == Addressing_Constant) { + gbString s = expr_to_string(se->expr); + error(se->expr, "Cannot slice constant value '%s'", s); + gb_string_free(s); + } + } + + if (t->kind == Type_MultiPointer && se->high != nullptr) { + /* + x[:] -> [^]T + x[i:] -> [^]T + x[:n] -> []T + x[i:n] -> []T + */ + o->type = alloc_type_slice(t->MultiPointer.elem); + } + + o->mode = Addressing_Value; + + if (is_type_string(t) && max_count >= 0) { + bool all_constant = true; + for (isize i = 0; i < gb_count_of(nodes); i++) { + if (nodes[i] != nullptr) { + TypeAndValue tav = type_and_value_of_expr(nodes[i]); + if (tav.mode != Addressing_Constant) { + all_constant = false; + break; + } + } + } + if (!all_constant) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Cannot slice '%s' with non-constant indices", str); + error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + gb_string_free(str); + o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring + o->expr = node; + return kind; + } + + String s = {}; + if (o->value.kind == ExactValue_String) { + s = o->value.value_string; + } + + o->mode = Addressing_Constant; + o->type = t; + o->value = exact_value_string(substring(s, cast(isize)indices[0], cast(isize)indices[1])); + } + return kind; +} ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { u32 prev_state_flags = c->state_flags; @@ -7189,52 +8988,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_end; case_ast_node(bd, BasicDirective, node); - o->mode = Addressing_Constant; - String name = bd->name.string; - if (name == "file") { - o->type = t_untyped_string; - o->value = exact_value_string(get_file_path_string(bd->token.pos.file_id)); - } else if (name == "line") { - o->type = t_untyped_integer; - o->value = exact_value_i64(bd->token.pos.line); - } else if (name == "procedure") { - if (c->curr_proc_decl == nullptr) { - error(node, "#procedure may only be used within procedures"); - o->type = t_untyped_string; - o->value = exact_value_string(str_lit("")); - } else { - o->type = t_untyped_string; - o->value = exact_value_string(c->proc_name); - } - } else if (name == "caller_location") { - init_core_source_code_location(c->checker); - error(node, "#caller_location may only be used as a default argument parameter"); - o->type = t_source_code_location; - o->mode = Addressing_Value; - } else { - if (name == "location") { - init_core_source_code_location(c->checker); - error(node, "'#%.*s' must be used in a call expression", LIT(name)); - o->type = t_source_code_location; - o->mode = Addressing_Value; - } else if ( - name == "assert" || - name == "defined" || - name == "config" || - name == "load" || - name == "load_hash" || - name == "load_or" - ) { - error(node, "'#%.*s' must be used as a call", LIT(name)); - o->type = t_invalid; - o->mode = Addressing_Invalid; - } else { - error(node, "Unknown directive: #%.*s", LIT(name)); - o->type = t_invalid; - o->mode = Addressing_Invalid; - } - - } + kind = check_basic_directive_expr(c, o, node, type_hint); case_end; case_ast_node(pg, ProcGroup, node); @@ -7283,1165 +9037,23 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_end; case_ast_node(te, TernaryIfExpr, node); - Operand cond = {Addressing_Invalid}; - check_expr(c, &cond, te->cond); - node->viral_state_flags |= te->cond->viral_state_flags; - - if (cond.mode != Addressing_Invalid && !is_type_boolean(cond.type)) { - error(te->cond, "Non-boolean condition in ternary if expression"); - } - - Operand x = {Addressing_Invalid}; - Operand y = {Addressing_Invalid}; - check_expr_or_type(c, &x, te->x, type_hint); - node->viral_state_flags |= te->x->viral_state_flags; - - if (te->y != nullptr) { - check_expr_or_type(c, &y, te->y, type_hint); - node->viral_state_flags |= te->y->viral_state_flags; - } else { - error(node, "A ternary expression must have an else clause"); - return kind; - } - - if (x.type == nullptr || x.type == t_invalid || - y.type == nullptr || y.type == t_invalid) { - return kind; - } - - convert_to_typed(c, &x, y.type); - if (x.mode == Addressing_Invalid) { - return kind; - } - convert_to_typed(c, &y, x.type); - if (y.mode == Addressing_Invalid) { - x.mode = Addressing_Invalid; - return kind; - } - - if (!ternary_compare_types(x.type, y.type)) { - gbString its = type_to_string(x.type); - gbString ets = type_to_string(y.type); - error(node, "Mismatched types in ternary if expression, %s vs %s", its, ets); - gb_string_free(ets); - gb_string_free(its); - return kind; - } - - o->type = x.type; - if (is_type_untyped_nil(o->type) || is_type_untyped_undef(o->type)) { - o->type = y.type; - } - - o->mode = Addressing_Value; - o->expr = node; - if (type_hint != nullptr && is_type_untyped(o->type)) { - if (check_cast_internal(c, &x, type_hint) && - check_cast_internal(c, &y, type_hint)) { - convert_to_typed(c, o, type_hint); - update_untyped_expr_type(c, node, type_hint, !is_type_untyped(type_hint)); - } - } + kind = check_ternary_if_expr(c, o, node, type_hint); case_end; case_ast_node(te, TernaryWhenExpr, node); - Operand cond = {}; - check_expr(c, &cond, te->cond); - node->viral_state_flags |= te->cond->viral_state_flags; - - if (cond.mode != Addressing_Constant || !is_type_boolean(cond.type)) { - error(te->cond, "Expected a constant boolean condition in ternary when expression"); - return kind; - } - - if (cond.value.value_bool) { - check_expr_or_type(c, o, te->x, type_hint); - node->viral_state_flags |= te->x->viral_state_flags; - } else { - if (te->y != nullptr) { - check_expr_or_type(c, o, te->y, type_hint); - node->viral_state_flags |= te->y->viral_state_flags; - } else { - error(node, "A ternary when expression must have an else clause"); - return kind; - } - } + kind = check_ternary_when_expr(c, o, node, type_hint); case_end; case_ast_node(oe, OrElseExpr, node); - String name = oe->token.string; - Ast *arg = oe->x; - Ast *default_value = oe->y; - - Operand x = {}; - Operand y = {}; - check_multi_expr_with_type_hint(c, &x, arg, type_hint); - if (x.mode == Addressing_Invalid) { - o->mode = Addressing_Value; - o->type = t_invalid; - o->expr = node; - return Expr_Expr; - } - - check_multi_expr_with_type_hint(c, &y, default_value, x.type); - error_operand_no_value(&y); - if (y.mode == Addressing_Invalid) { - o->mode = Addressing_Value; - o->type = t_invalid; - o->expr = node; - return Expr_Expr; - } - - Type *left_type = nullptr; - Type *right_type = nullptr; - check_or_else_split_types(c, &x, name, &left_type, &right_type); - add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); - - if (left_type != nullptr) { - check_assignment(c, &y, left_type, name); - } else { - check_or_else_expr_no_value_error(c, name, x, type_hint); - } - - if (left_type == nullptr) { - left_type = t_invalid; - } - o->mode = Addressing_Value; - o->type = left_type; - o->expr = node; - return Expr_Expr; + return check_or_else_expr(c, o, node, type_hint); case_end; case_ast_node(re, OrReturnExpr, node); - String name = re->token.string; - Operand x = {}; - check_multi_expr_with_type_hint(c, &x, re->expr, type_hint); - if (x.mode == Addressing_Invalid) { - o->mode = Addressing_Value; - o->type = t_invalid; - o->expr = node; - return Expr_Expr; - } - - Type *left_type = nullptr; - Type *right_type = nullptr; - check_or_return_split_types(c, &x, name, &left_type, &right_type); - add_type_and_value(&c->checker->info, re->expr, x.mode, x.type, x.value); - - if (right_type == nullptr) { - check_or_else_expr_no_value_error(c, name, x, type_hint); - } else { - Type *proc_type = base_type(c->curr_proc_sig); - GB_ASSERT(proc_type->kind == Type_Proc); - Type *result_type = proc_type->Proc.results; - if (result_type == nullptr) { - error(node, "'%.*s' requires the current procedure to have at least one return value", LIT(name)); - } else { - GB_ASSERT(result_type->kind == Type_Tuple); - - auto const &vars = result_type->Tuple.variables; - Type *end_type = vars[vars.count-1]->type; - - if (vars.count > 1) { - if (!proc_type->Proc.has_named_results) { - error(node, "'%.*s' within a procedure with more than 1 return value requires that the return values are named, allowing for early return", LIT(name)); - } - } - - Operand rhs = {}; - rhs.type = right_type; - rhs.mode = Addressing_Value; - - // TODO(bill): better error message - if (!check_is_assignable_to(c, &rhs, end_type)) { - gbString a = type_to_string(right_type); - gbString b = type_to_string(end_type); - gbString ret_type = type_to_string(result_type); - error(node, "Cannot assign end value of type '%s' to '%s' in '%.*s'", a, b, LIT(name)); - if (vars.count == 1) { - error_line("\tProcedure return value type: %s\n", ret_type); - } else { - error_line("\tProcedure return value types: (%s)\n", ret_type); - } - gb_string_free(ret_type); - gb_string_free(b); - gb_string_free(a); - } - } - } - - o->expr = node; - o->type = left_type; - if (left_type != nullptr) { - o->mode = Addressing_Value; - } else { - o->mode = Addressing_NoValue; - } - - if (c->curr_proc_sig == nullptr) { - error(node, "'%.*s' can only be used within a procedure", LIT(name)); - } - - if (c->in_defer) { - error(node, "'or_return' cannot be used within a defer statement"); - } - - return Expr_Expr; + return check_or_return_expr(c, o, node, type_hint); case_end; case_ast_node(cl, CompoundLit, node); - Type *type = type_hint; - if (type != nullptr && is_type_untyped(type)) { - type = nullptr; - } - bool is_to_be_determined_array_count = false; - bool is_constant = true; - if (cl->type != nullptr) { - type = nullptr; - - // [?]Type - if (cl->type->kind == Ast_ArrayType && cl->type->ArrayType.count != nullptr) { - Ast *count = cl->type->ArrayType.count; - if (count->kind == Ast_UnaryExpr && - count->UnaryExpr.op.kind == Token_Question) { - type = alloc_type_array(check_type(c, cl->type->ArrayType.elem), -1); - is_to_be_determined_array_count = true; - } - if (cl->elems.count > 0) { - if (cl->type->ArrayType.tag != nullptr) { - Ast *tag = cl->type->ArrayType.tag; - GB_ASSERT(tag->kind == Ast_BasicDirective); - String name = tag->BasicDirective.name.string; - if (name == "soa") { - error(node, "#soa arrays are not supported for compound literals"); - return kind; - } - } - } - } - if (cl->type->kind == Ast_DynamicArrayType && cl->type->DynamicArrayType.tag != nullptr) { - if (cl->elems.count > 0) { - Ast *tag = cl->type->DynamicArrayType.tag; - GB_ASSERT(tag->kind == Ast_BasicDirective); - String name = tag->BasicDirective.name.string; - if (name == "soa") { - error(node, "#soa arrays are not supported for compound literals"); - return kind; - } - } - } - - if (type == nullptr) { - type = check_type(c, cl->type); - } - } - - if (type == nullptr) { - error(node, "Missing type in compound literal"); - return kind; - } - - - Type *t = base_type(type); - if (is_type_polymorphic(t)) { - gbString str = type_to_string(type); - error(node, "Cannot use a polymorphic type for a compound literal, got '%s'", str); - o->expr = node; - o->type = type; - gb_string_free(str); - return kind; - } - - - switch (t->kind) { - case Type_Struct: { - if (cl->elems.count == 0) { - break; // NOTE(bill): No need to init - } - if (t->Struct.is_raw_union) { - if (cl->elems.count > 0) { - // NOTE: unions cannot be constant - is_constant = false; - - if (cl->elems[0]->kind != Ast_FieldValue) { - gbString type_str = type_to_string(type); - error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str); - gb_string_free(type_str); - } else { - if (cl->elems.count != 1) { - gbString type_str = type_to_string(type); - error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); - gb_string_free(type_str); - } else { - Ast *elem = cl->elems[0]; - ast_node(fv, FieldValue, elem); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(elem, "Invalid field name '%s' in structure literal", expr_str); - gb_string_free(expr_str); - break; - } - - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); - bool is_unknown = sel.entity == nullptr; - if (is_unknown) { - error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); - break; - } - - if (sel.index.count > 1) { - error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); - break; - } - - Entity *field = t->Struct.fields[sel.index[0]]; - add_entity_use(c, fv->field, field); - - Operand o = {}; - check_expr_or_type(c, &o, fv->value, field->type); - - - check_assignment(c, &o, field->type, str_lit("structure literal")); - } - - } - } - break; - } - - - isize field_count = t->Struct.fields.count; - isize min_field_count = t->Struct.fields.count; - for (isize i = min_field_count-1; i >= 0; i--) { - Entity *e = t->Struct.fields[i]; - GB_ASSERT(e->kind == Entity_Variable); - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - min_field_count--; - } else { - break; - } - } - - if (cl->elems[0]->kind == Ast_FieldValue) { - bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind != Ast_FieldValue) { - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } - ast_node(fv, FieldValue, elem); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(elem, "Invalid field name '%s' in structure literal", expr_str); - gb_string_free(expr_str); - continue; - } - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); - bool is_unknown = sel.entity == nullptr; - if (is_unknown) { - error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); - continue; - } - - if (sel.index.count > 1) { - error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); - continue; - } - - Entity *field = t->Struct.fields[sel.index[0]]; - add_entity_use(c, fv->field, field); - - if (fields_visited[sel.index[0]]) { - error(elem, "Duplicate field '%.*s' in structure literal", LIT(name)); - continue; - } - - fields_visited[sel.index[0]] = true; - - Operand o = {}; - check_expr_or_type(c, &o, fv->value, field->type); - - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { - is_constant = false; - } - if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); - } - - check_assignment(c, &o, field->type, str_lit("structure literal")); - } - } else { - bool seen_field_value = false; - - for_array(index, cl->elems) { - Entity *field = nullptr; - Ast *elem = cl->elems[index]; - if (elem->kind == Ast_FieldValue) { - seen_field_value = true; - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } else if (seen_field_value) { - error(elem, "Value elements cannot be used after a 'field = value'"); - continue; - } - if (index >= field_count) { - error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count); - break; - } - - if (field == nullptr) { - field = t->Struct.fields[index]; - } - - Operand o = {}; - check_expr_or_type(c, &o, elem, field->type); - - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { - is_constant = false; - } - if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); - } - - check_assignment(c, &o, field->type, str_lit("structure literal")); - } - if (cl->elems.count < field_count) { - if (min_field_count < field_count) { - if (cl->elems.count < min_field_count) { - error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count); - } - } else { - error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count); - } - } - } - - break; - } - - case Type_Slice: - case Type_Array: - case Type_DynamicArray: - case Type_SimdVector: - case Type_Matrix: - { - Type *elem_type = nullptr; - String context_name = {}; - i64 max_type_count = -1; - if (t->kind == Type_Slice) { - elem_type = t->Slice.elem; - context_name = str_lit("slice literal"); - } else if (t->kind == Type_Array) { - elem_type = t->Array.elem; - context_name = str_lit("array literal"); - if (!is_to_be_determined_array_count) { - max_type_count = t->Array.count; - } - } else if (t->kind == Type_DynamicArray) { - elem_type = t->DynamicArray.elem; - context_name = str_lit("dynamic array literal"); - is_constant = false; - - if (!build_context.no_dynamic_literals) { - add_package_dependency(c, "runtime", "__dynamic_array_reserve"); - add_package_dependency(c, "runtime", "__dynamic_array_append"); - } - } else if (t->kind == Type_SimdVector) { - elem_type = t->SimdVector.elem; - context_name = str_lit("simd vector literal"); - max_type_count = t->SimdVector.count; - } else if (t->kind == Type_Matrix) { - elem_type = t->Matrix.elem; - context_name = str_lit("matrix literal"); - max_type_count = t->Matrix.row_count*t->Matrix.column_count; - } else { - GB_PANIC("unreachable"); - } - - - i64 max = 0; - - Type *bet = base_type(elem_type); - if (!elem_type_can_be_constant(bet)) { - is_constant = false; - } - - if (bet == t_invalid) { - break; - } - - if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { - if (is_type_simd_vector(t)) { - error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals"); - } else { - RangeCache rc = range_cache_make(heap_allocator()); - defer (range_cache_destroy(&rc)); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind != Ast_FieldValue) { - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } - ast_node(fv, FieldValue, elem); - - if (is_ast_range(fv->field)) { - Token op = fv->field->BinaryExpr.op; - - Operand x = {}; - Operand y = {}; - bool ok = check_range(c, fv->field, &x, &y, nullptr); - if (!ok) { - continue; - } - if (x.mode != Addressing_Constant || !is_type_integer(core_type(x.type))) { - error(x.expr, "Expected a constant integer as an array field"); - continue; - } - - if (y.mode != Addressing_Constant || !is_type_integer(core_type(y.type))) { - error(y.expr, "Expected a constant integer as an array field"); - continue; - } - - i64 lo = exact_value_to_i64(x.value); - i64 hi = exact_value_to_i64(y.value); - i64 max_index = hi; - if (op.kind == Token_RangeHalf) { // ..< (exclusive) - hi -= 1; - } else { // .. (inclusive) - max_index += 1; - } - - bool new_range = range_cache_add_range(&rc, lo, hi); - if (!new_range) { - error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name)); - continue; - } - - - if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name)); - continue; - } - if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name)); - continue; - } - - if (max < hi) { - max = max_index; - } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, fv->value, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; - } else { - Operand op_index = {}; - check_expr(c, &op_index, fv->field); - - if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { - error(elem, "Expected a constant integer as an array field"); - continue; - } - // add_type_and_value(c->info, op_index.expr, op_index.mode, op_index.type, op_index.value); - - i64 index = exact_value_to_i64(op_index.value); - - if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); - continue; - } - - bool new_index = range_cache_add_index(&rc, index); - if (!new_index) { - error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); - continue; - } - - if (max < index+1) { - max = index+1; - } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, fv->value, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; - } - } - - cl->max_count = max; - } - - } else { - isize index = 0; - for (; index < cl->elems.count; index++) { - Ast *e = cl->elems[index]; - if (e == nullptr) { - error(node, "Invalid literal element"); - continue; - } - - if (e->kind == Ast_FieldValue) { - error(e, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } - - if (0 <= max_type_count && max_type_count <= index) { - error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); - } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, e, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; - } - - if (max < index) { - max = index; - } - } - - - if (t->kind == Type_Array) { - if (is_to_be_determined_array_count) { - t->Array.count = max; - } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { - if (0 < max && max < t->Array.count) { - error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); - } - } - } - - - if (t->kind == Type_SimdVector) { - if (!is_constant) { - error(node, "Expected all constant elements for a simd vector"); - } - } - - - if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count) { - error(node, "Compound literals of dynamic types have been disabled"); - } - } - - if (t->kind == Type_Matrix) { - if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { - if (0 < max && max < max_type_count) { - error(node, "Expected %lld values for this matrix literal, got %lld", cast(long long)max_type_count, cast(long long)max); - } - } - } - - break; - } - - case Type_EnumeratedArray: - { - Type *elem_type = t->EnumeratedArray.elem; - Type *index_type = t->EnumeratedArray.index; - String context_name = str_lit("enumerated array literal"); - i64 max_type_count = t->EnumeratedArray.count; - - gbString index_type_str = type_to_string(index_type); - defer (gb_string_free(index_type_str)); - - i64 total_lo = exact_value_to_i64(*t->EnumeratedArray.min_value); - i64 total_hi = exact_value_to_i64(*t->EnumeratedArray.max_value); - - String total_lo_string = {}; - String total_hi_string = {}; - GB_ASSERT(is_type_enum(index_type)); - { - Type *bt = base_type(index_type); - GB_ASSERT(bt->kind == Type_Enum); - for_array(i, bt->Enum.fields) { - Entity *f = bt->Enum.fields[i]; - if (f->kind != Entity_Constant) { - continue; - } - if (total_lo_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, *t->EnumeratedArray.min_value)) { - total_lo_string = f->token.string; - } - if (total_hi_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, *t->EnumeratedArray.max_value)) { - total_hi_string = f->token.string; - } - if (total_lo_string.len != 0 && total_hi_string.len != 0) { - break; - } - } - } - - i64 max = 0; - - Type *bet = base_type(elem_type); - if (!elem_type_can_be_constant(bet)) { - is_constant = false; - } - - if (bet == t_invalid) { - break; - } - bool is_partial = cl->tag && (cl->tag->BasicDirective.name.string == "partial"); - - SeenMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue - map_init(&seen, heap_allocator()); - defer (map_destroy(&seen)); - - if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { - RangeCache rc = range_cache_make(heap_allocator()); - defer (range_cache_destroy(&rc)); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind != Ast_FieldValue) { - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } - ast_node(fv, FieldValue, elem); - - if (is_ast_range(fv->field)) { - Token op = fv->field->BinaryExpr.op; - - Operand x = {}; - Operand y = {}; - bool ok = check_range(c, fv->field, &x, &y, nullptr, index_type); - if (!ok) { - continue; - } - if (x.mode != Addressing_Constant || !are_types_identical(x.type, index_type)) { - error(x.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); - continue; - } - - if (y.mode != Addressing_Constant || !are_types_identical(x.type, index_type)) { - error(y.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); - continue; - } - - i64 lo = exact_value_to_i64(x.value); - i64 hi = exact_value_to_i64(y.value); - i64 max_index = hi; - if (op.kind == Token_RangeHalf) { - hi -= 1; - } - - bool new_range = range_cache_add_range(&rc, lo, hi); - if (!new_range) { - gbString lo_str = expr_to_string(x.expr); - gbString hi_str = expr_to_string(y.expr); - error(elem, "Overlapping field range index %s %.*s %s for %.*s", lo_str, LIT(op.string), hi_str, LIT(context_name)); - gb_string_free(hi_str); - gb_string_free(lo_str); - continue; - } - - - // NOTE(bill): These are sanity checks for invalid enum values - if (max_type_count >= 0 && (lo < total_lo || lo > total_hi)) { - gbString lo_str = expr_to_string(x.expr); - error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", lo_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); - gb_string_free(lo_str); - continue; - } - if (max_type_count >= 0 && (hi < 0 || hi > total_hi)) { - gbString hi_str = expr_to_string(y.expr); - error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", hi_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); - gb_string_free(hi_str); - continue; - } - - if (max < hi) { - max = max_index; - } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, fv->value, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; - - TokenKind upper_op = Token_LtEq; - if (op.kind == Token_RangeHalf) { - upper_op = Token_Lt; - } - add_to_seen_map(c, &seen, upper_op, x, x, y); - } else { - Operand op_index = {}; - check_expr_with_type_hint(c, &op_index, fv->field, index_type); - - if (op_index.mode != Addressing_Constant || !are_types_identical(op_index.type, index_type)) { - error(op_index.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); - continue; - } - - i64 index = exact_value_to_i64(op_index.value); - - if (max_type_count >= 0 && (index < total_lo || index > total_hi)) { - gbString idx_str = expr_to_string(op_index.expr); - error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", idx_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); - gb_string_free(idx_str); - continue; - } - - bool new_index = range_cache_add_index(&rc, index); - if (!new_index) { - gbString idx_str = expr_to_string(op_index.expr); - error(elem, "Duplicate field index %s for %.*s", idx_str, LIT(context_name)); - gb_string_free(idx_str); - continue; - } - - if (max < index+1) { - max = index+1; - } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, fv->value, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; - - add_to_seen_map(c, &seen, op_index); - } - } - - cl->max_count = max; - - } else { - isize index = 0; - for (; index < cl->elems.count; index++) { - Ast *e = cl->elems[index]; - if (e == nullptr) { - error(node, "Invalid literal element"); - continue; - } - - if (e->kind == Ast_FieldValue) { - error(e, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } - - if (0 <= max_type_count && max_type_count <= index) { - error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); - } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, e, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; - } - - if (max < index) { - max = index; - } - } - - bool was_error = false; - if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { - if (0 < max && max < t->EnumeratedArray.count) { - error(node, "Expected %lld values for this enumerated array literal, got %lld", cast(long long)t->EnumeratedArray.count, cast(long long)max); - was_error = true; - } else { - error(node, "Enumerated array literals must only have 'field = value' elements, bare elements are not allowed"); - was_error = true; - } - } - - // NOTE(bill): Check for missing cases when `#partial literal` is not present - if (cl->elems.count > 0 && !was_error && !is_partial) { - Type *et = base_type(index_type); - GB_ASSERT(et->kind == Type_Enum); - auto fields = et->Enum.fields; - - auto unhandled = array_make(temporary_allocator(), 0, fields.count); - - for_array(i, fields) { - Entity *f = fields[i]; - if (f->kind != Entity_Constant) { - continue; - } - ExactValue v = f->Constant.value; - auto found = map_get(&seen, hash_exact_value(v)); - if (!found) { - array_add(&unhandled, f); - } - } - - if (unhandled.count > 0) { - begin_error_block(); - defer (end_error_block()); - - if (unhandled.count == 1) { - error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string)); - } else { - error(node, "Unhandled enumerated array cases:"); - for_array(i, unhandled) { - Entity *f = unhandled[i]; - error_line("\t%.*s\n", LIT(f->token.string)); - } - } - error_line("\n"); - - error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type)); - } - } - - break; - } - - case Type_Basic: { - if (!is_type_any(t)) { - if (cl->elems.count != 0) { - error(node, "Illegal compound literal"); - } - break; - } - if (cl->elems.count == 0) { - break; // NOTE(bill): No need to init - } - { // Checker values - Type *field_types[2] = {t_rawptr, t_typeid}; - isize field_count = 2; - if (cl->elems[0]->kind == Ast_FieldValue) { - bool fields_visited[2] = {}; - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind != Ast_FieldValue) { - error(elem, "Mixture of 'field = value' and value elements in a 'any' literal is not allowed"); - continue; - } - ast_node(fv, FieldValue, elem); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(elem, "Invalid field name '%s' in 'any' literal", expr_str); - gb_string_free(expr_str); - continue; - } - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); - if (sel.entity == nullptr) { - error(elem, "Unknown field '%.*s' in 'any' literal", LIT(name)); - continue; - } - - isize index = sel.index[0]; - - if (fields_visited[index]) { - error(elem, "Duplicate field '%.*s' in 'any' literal", LIT(name)); - continue; - } - - fields_visited[index] = true; - check_expr(c, o, fv->value); - - // NOTE(bill): 'any' literals can never be constant - is_constant = false; - - check_assignment(c, o, field_types[index], str_lit("'any' literal")); - } - } else { - for_array(index, cl->elems) { - Ast *elem = cl->elems[index]; - if (elem->kind == Ast_FieldValue) { - error(elem, "Mixture of 'field = value' and value elements in a 'any' literal is not allowed"); - continue; - } - - - check_expr(c, o, elem); - if (index >= field_count) { - error(o->expr, "Too many values in 'any' literal, expected %td", field_count); - break; - } - - // NOTE(bill): 'any' literals can never be constant - is_constant = false; - - check_assignment(c, o, field_types[index], str_lit("'any' literal")); - } - if (cl->elems.count < field_count) { - error(cl->close, "Too few values in 'any' literal, expected %td, got %td", field_count, cl->elems.count); - } - } - } - - break; - } - - case Type_Map: { - if (cl->elems.count == 0) { - break; - } - is_constant = false; - { // Checker values - bool key_is_typeid = is_type_typeid(t->Map.key); - bool value_is_typeid = is_type_typeid(t->Map.value); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind != Ast_FieldValue) { - error(elem, "Only 'field = value' elements are allowed in a map literal"); - continue; - } - ast_node(fv, FieldValue, elem); - - if (key_is_typeid) { - check_expr_or_type(c, o, fv->field, t->Map.key); - } else { - check_expr_with_type_hint(c, o, fv->field, t->Map.key); - } - check_assignment(c, o, t->Map.key, str_lit("map literal")); - if (o->mode == Addressing_Invalid) { - continue; - } - - if (value_is_typeid) { - check_expr_or_type(c, o, fv->value, t->Map.value); - } else { - check_expr_with_type_hint(c, o, fv->value, t->Map.value); - } - check_assignment(c, o, t->Map.value, str_lit("map literal")); - } - } - - if (build_context.no_dynamic_literals && cl->elems.count) { - error(node, "Compound literals of dynamic types have been disabled"); - } else { - add_package_dependency(c, "runtime", "__dynamic_map_reserve"); - add_package_dependency(c, "runtime", "__dynamic_map_set"); - } - break; - } - - case Type_BitSet: { - if (cl->elems.count == 0) { - break; // NOTE(bill): No need to init - } - Type *et = base_type(t->BitSet.elem); - isize field_count = 0; - if (et->kind == Type_Enum) { - field_count = et->Enum.fields.count; - } - - if (cl->elems[0]->kind == Ast_FieldValue) { - error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed"); - is_constant = false; - } else { - for_array(index, cl->elems) { - Ast *elem = cl->elems[index]; - if (elem->kind == Ast_FieldValue) { - error(elem, "'field = value' in a bit_set a literal is not allowed"); - continue; - } - - check_expr_with_type_hint(c, o, elem, et); - - if (is_constant) { - is_constant = o->mode == Addressing_Constant; - } - - check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); - if (o->mode == Addressing_Constant) { - i64 lower = t->BitSet.lower; - i64 upper = t->BitSet.upper; - i64 v = exact_value_to_i64(o->value); - if (lower <= v && v <= upper) { - // okay - } else { - error(elem, "Bit field value out of bounds, %lld not in the range %lld .. %lld", v, lower, upper); - continue; - } - } - } - } - break; - } - - default: { - if (cl->elems.count == 0) { - break; // NOTE(bill): No need to init - } - - gbString str = type_to_string(type); - error(node, "Invalid compound literal type '%s'", str); - gb_string_free(str); - return kind; - } - } - - if (is_constant) { - o->mode = Addressing_Constant; - - if (is_type_bit_set(type)) { - // NOTE(bill): Encode as an integer - - i64 lower = base_type(type)->BitSet.lower; - - u64 bits = 0; - for_array(index, cl->elems) { - Ast *elem = cl->elems[index]; - GB_ASSERT(elem->kind != Ast_FieldValue); - TypeAndValue tav = elem->tav; - ExactValue i = exact_value_to_integer(tav.value); - if (i.kind != ExactValue_Integer) { - continue; - } - i64 val = big_int_to_i64(&i.value_integer); - val -= lower; - u64 bit = u64(1ll<value = exact_value_u64(bits); - } else if (is_type_constant_type(type) && cl->elems.count == 0) { - ExactValue value = exact_value_compound(node); - Type *bt = core_type(type); - if (bt->kind == Type_Basic) { - if (bt->Basic.flags & BasicFlag_Boolean) { - value = exact_value_bool(false); - } else if (bt->Basic.flags & BasicFlag_Integer) { - value = exact_value_i64(0); - } else if (bt->Basic.flags & BasicFlag_Unsigned) { - value = exact_value_i64(0); - } else if (bt->Basic.flags & BasicFlag_Float) { - value = exact_value_float(0); - } else if (bt->Basic.flags & BasicFlag_Complex) { - value = exact_value_complex(0, 0); - } else if (bt->Basic.flags & BasicFlag_Quaternion) { - value = exact_value_quaternion(0, 0, 0, 0); - } else if (bt->Basic.flags & BasicFlag_Pointer) { - value = exact_value_pointer(0); - } else if (bt->Basic.flags & BasicFlag_String) { - String empty_string = {}; - value = exact_value_string(empty_string); - } else if (bt->Basic.flags & BasicFlag_Rune) { - value = exact_value_i64(0); - } - } - - o->value = value; - } else { - o->value = exact_value_compound(node); - } - } else { - o->mode = Addressing_Value; - } - o->type = type; + kind = check_compound_literal(c, o, node, type_hint); case_end; case_ast_node(pe, ParenExpr, node); @@ -8461,127 +9073,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_end; case_ast_node(ta, TypeAssertion, node); - check_expr(c, o, ta->expr); - node->viral_state_flags |= ta->expr->viral_state_flags; - - if (o->mode == Addressing_Invalid) { - o->expr = node; - return kind; - } - if (o->mode == Addressing_Constant) { - gbString expr_str = expr_to_string(o->expr); - error(o->expr, "A type assertion cannot be applied to a constant expression: '%s'", expr_str); - gb_string_free(expr_str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - if (is_type_untyped(o->type)) { - gbString expr_str = expr_to_string(o->expr); - error(o->expr, "A type assertion cannot be applied to an untyped expression: '%s'", expr_str); - gb_string_free(expr_str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - Type *src = type_deref(o->type); - Type *bsrc = base_type(src); - - - if (ta->type != nullptr && ta->type->kind == Ast_UnaryExpr && ta->type->UnaryExpr.op.kind == Token_Question) { - if (!is_type_union(src)) { - gbString str = type_to_string(o->type); - error(o->expr, "Type assertions with .? can only operate on unions, got %s", str); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - if (bsrc->Union.variants.count != 1 && type_hint != nullptr) { - bool allowed = false; - for_array(i, bsrc->Union.variants) { - Type *vt = bsrc->Union.variants[i]; - if (are_types_identical(vt, type_hint)) { - allowed = true; - add_type_info_type(c, vt); - break; - } - } - if (allowed) { - add_type_info_type(c, o->type); - o->type = type_hint; - o->mode = Addressing_OptionalOk; - return kind; - } - } - - if (bsrc->Union.variants.count != 1) { - error(o->expr, "Type assertions with .? can only operate on unions with 1 variant, got %lld", cast(long long)bsrc->Union.variants.count); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - add_type_info_type(c, o->type); - add_type_info_type(c, bsrc->Union.variants[0]); - - o->type = bsrc->Union.variants[0]; - o->mode = Addressing_OptionalOk; - } else { - Type *t = check_type(c, ta->type); - Type *dst = t; - - if (is_type_union(src)) { - bool ok = false; - for_array(i, bsrc->Union.variants) { - Type *vt = bsrc->Union.variants[i]; - if (are_types_identical(vt, dst)) { - ok = true; - break; - } - } - - if (!ok) { - gbString expr_str = expr_to_string(o->expr); - gbString dst_type_str = type_to_string(t); - defer (gb_string_free(expr_str)); - defer (gb_string_free(dst_type_str)); - if (bsrc->Union.variants.count == 0) { - error(o->expr, "Cannot type assert '%s' to '%s' as this is an empty union", expr_str, dst_type_str); - } else { - error(o->expr, "Cannot type assert '%s' to '%s' as it is not a variant of that union", expr_str, dst_type_str); - } - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - add_type_info_type(c, o->type); - add_type_info_type(c, t); - - o->type = t; - o->mode = Addressing_OptionalOk; - } else if (is_type_any(src)) { - o->type = t; - o->mode = Addressing_OptionalOk; - - add_type_info_type(c, o->type); - add_type_info_type(c, t); - } else { - gbString str = type_to_string(o->type); - error(o->expr, "Type assertions can only operate on unions and 'any', got %s", str); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - } - - add_package_dependency(c, "runtime", "type_assertion_check"); - add_package_dependency(c, "runtime", "type_assertion_check2"); + kind = check_type_assertion(c, o, node, type_hint); case_end; case_ast_node(tc, TypeCast, node); @@ -8669,443 +9161,19 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_end; case_ast_node(se, SelectorCallExpr, node); - // IMPORTANT NOTE(bill, 2020-05-22): This is a complete hack to get a shorthand which is extremely useful for vtables - // COM APIs is a great example of where this kind of thing is extremely useful - // General idea: - // - // x->y(123) == x.y(x, 123) - // - // How this has been implemented at the moment is quite hacky but it's done so to reduce need for huge backend changes - // Just regenerating a new AST aids things - // - // TODO(bill): Is this a good hack or not? - // - // NOTE(bill, 2020-05-22): I'm going to regret this decision, ain't I? - - - if (se->modified_call) { - // Prevent double evaluation - o->expr = node; - o->type = node->tav.type; - o->value = node->tav.value; - o->mode = node->tav.mode; - return Expr_Expr; - } - - bool allow_arrow_right_selector_expr; - allow_arrow_right_selector_expr = c->allow_arrow_right_selector_expr; - c->allow_arrow_right_selector_expr = true; - Operand x = {}; - ExprKind kind = check_expr_base(c, &x, se->expr, nullptr); - c->allow_arrow_right_selector_expr = allow_arrow_right_selector_expr; - - if (x.mode == Addressing_Invalid || x.type == t_invalid) { - o->mode = Addressing_Invalid; - o->type = t_invalid; - o->expr = node; - return kind; - } - if (!is_type_proc(x.type)) { - gbString type_str = type_to_string(x.type); - error(se->call, "Selector call expressions expect a procedure type for the call, got '%s'", type_str); - gb_string_free(type_str); - - o->mode = Addressing_Invalid; - o->type = t_invalid; - o->expr = node; - return Expr_Stmt; - } - - ast_node(ce, CallExpr, se->call); - - GB_ASSERT(x.expr->kind == Ast_SelectorExpr); - - Ast *first_arg = x.expr->SelectorExpr.expr; - GB_ASSERT(first_arg != nullptr); - - Type *pt = base_type(x.type); - GB_ASSERT(pt->kind == Type_Proc); - Type *first_type = nullptr; - String first_arg_name = {}; - if (pt->Proc.param_count > 0) { - Entity *f = pt->Proc.params->Tuple.variables[0]; - first_type = f->type; - first_arg_name = f->token.string; - } - if (first_arg_name.len == 0) { - first_arg_name = str_lit("_"); - } - - if (first_type == nullptr) { - error(se->call, "Selector call expressions expect a procedure type for the call with at least 1 parameter"); - o->mode = Addressing_Invalid; - o->type = t_invalid; - o->expr = node; - return Expr_Stmt; - } - - Operand y = {}; - y.mode = first_arg->tav.mode; - y.type = first_arg->tav.type; - y.value = first_arg->tav.value; - if (check_is_assignable_to(c, &y, first_type)) { - // Do nothing, it's valid - } else { - Operand z = y; - z.type = type_deref(y.type); - if (check_is_assignable_to(c, &z, first_type)) { - // NOTE(bill): AST GENERATION HACK! - Token op = {Token_Pointer}; - first_arg = ast_deref_expr(first_arg->file(), first_arg, op); - } else if (y.mode == Addressing_Variable) { - Operand w = y; - w.type = alloc_type_pointer(y.type); - if (check_is_assignable_to(c, &w, first_type)) { - // NOTE(bill): AST GENERATION HACK! - Token op = {Token_And}; - first_arg = ast_unary_expr(first_arg->file(), op, first_arg); - } - } - } - - if (ce->args.count > 0) { - bool fail = false; - bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue); - for_array(i, ce->args) { - Ast *arg = ce->args[i]; - bool mix = false; - if (first_is_field_value) { - mix = arg->kind != Ast_FieldValue; - } else { - mix = arg->kind == Ast_FieldValue; - } - if (mix) { - fail = true; - break; - } - } - if (!fail && first_is_field_value) { - Token op = {Token_Eq}; - AstFile *f = first_arg->file(); - first_arg = ast_field_value(f, ast_ident(f, make_token_ident(first_arg_name)), first_arg, op); - } - } - - - - auto modified_args = slice_make(heap_allocator(), ce->args.count+1); - modified_args[0] = first_arg; - slice_copy(&modified_args, ce->args, 1); - ce->args = modified_args; - se->modified_call = true; - - allow_arrow_right_selector_expr = c->allow_arrow_right_selector_expr; - c->allow_arrow_right_selector_expr = true; - check_expr_base(c, o, se->call, type_hint); - c->allow_arrow_right_selector_expr = allow_arrow_right_selector_expr; - - o->expr = node; - return Expr_Expr; + return check_selector_call_expr(c, o, node, type_hint); case_end; - case_ast_node(ise, ImplicitSelectorExpr, node); return check_implicit_selector_expr(c, o, node, type_hint); case_end; case_ast_node(ie, IndexExpr, node); - check_expr(c, o, ie->expr); - node->viral_state_flags |= ie->expr->viral_state_flags; - if (o->mode == Addressing_Invalid) { - o->expr = node; - return kind; - } - - Type *t = base_type(type_deref(o->type)); - bool is_ptr = is_type_pointer(o->type); - bool is_const = o->mode == Addressing_Constant; - - if (is_type_map(t)) { - Operand key = {}; - if (is_type_typeid(t->Map.key)) { - check_expr_or_type(c, &key, ie->index, t->Map.key); - } else { - check_expr_with_type_hint(c, &key, ie->index, t->Map.key); - } - check_assignment(c, &key, t->Map.key, str_lit("map index")); - if (key.mode == Addressing_Invalid) { - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - o->mode = Addressing_MapIndex; - o->type = t->Map.value; - o->expr = node; - - add_package_dependency(c, "runtime", "__dynamic_map_get"); - add_package_dependency(c, "runtime", "__dynamic_map_set"); - return Expr_Expr; - } - - i64 max_count = -1; - bool valid = check_set_index_data(o, t, is_ptr, &max_count, o->type); - - if (is_const) { - if (is_type_array(t)) { - // OKay - } else if (is_type_slice(t)) { - // Okay - } else if (is_type_enumerated_array(t)) { - // Okay - } else if (is_type_string(t)) { - // Okay - } else if (is_type_relative_slice(t)) { - // Okay - } else if (is_type_matrix(t)) { - // Okay - } else { - valid = false; - } - } - - if (!valid) { - gbString str = expr_to_string(o->expr); - gbString type_str = type_to_string(o->type); - defer (gb_string_free(str)); - defer (gb_string_free(type_str)); - if (is_const) { - error(o->expr, "Cannot index constant '%s' of type '%s'", str, type_str); - } else { - error(o->expr, "Cannot index '%s' of type '%s'", str, type_str); - } - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - if (ie->index == nullptr) { - gbString str = expr_to_string(o->expr); - error(o->expr, "Missing index for '%s'", str); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - Type *index_type_hint = nullptr; - if (is_type_enumerated_array(t)) { - Type *bt = base_type(t); - GB_ASSERT(bt->kind == Type_EnumeratedArray); - index_type_hint = bt->EnumeratedArray.index; - } - - i64 index = 0; - bool ok = check_index_value(c, t, false, ie->index, max_count, &index, index_type_hint); - if (is_const) { - if (index < 0) { - gbString str = expr_to_string(o->expr); - error(o->expr, "Cannot index a constant '%s'", str); - error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } else if (ok) { - ExactValue value = type_and_value_of_expr(ie->expr).value; - o->mode = Addressing_Constant; - bool success = false; - bool finish = false; - o->value = get_constant_field_single(c, value, cast(i32)index, &success, &finish); - if (!success) { - gbString str = expr_to_string(o->expr); - error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index); - error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - } - } - - if (type_hint != nullptr && is_type_matrix(t)) { - // TODO(bill): allow matrix columns to be assignable to other types which are the same internally - // if a type hint exists - } - + kind = check_index_expr(c, o, node, type_hint); case_end; case_ast_node(se, SliceExpr, node); - check_expr(c, o, se->expr); - node->viral_state_flags |= se->expr->viral_state_flags; - - if (o->mode == Addressing_Invalid) { - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - bool valid = false; - i64 max_count = -1; - Type *t = base_type(type_deref(o->type)); - switch (t->kind) { - case Type_Basic: - if (t->Basic.kind == Basic_string || t->Basic.kind == Basic_UntypedString) { - valid = true; - if (o->mode == Addressing_Constant) { - max_count = o->value.value_string.len; - } - o->type = type_deref(o->type); - } - break; - - case Type_Array: - valid = true; - max_count = t->Array.count; - if (o->mode != Addressing_Variable && !is_type_pointer(o->type)) { - gbString str = expr_to_string(node); - error(node, "Cannot slice array '%s', value is not addressable", str); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - o->type = alloc_type_slice(t->Array.elem); - break; - - case Type_MultiPointer: - valid = true; - o->type = type_deref(o->type); - break; - - case Type_Slice: - valid = true; - o->type = type_deref(o->type); - break; - - case Type_DynamicArray: - valid = true; - o->type = alloc_type_slice(t->DynamicArray.elem); - break; - - case Type_Struct: - if (is_type_soa_struct(t)) { - valid = true; - o->type = make_soa_struct_slice(c, nullptr, nullptr, t->Struct.soa_elem); - } - break; - - case Type_RelativeSlice: - valid = true; - o->type = t->RelativeSlice.slice_type; - if (o->mode != Addressing_Variable) { - gbString str = expr_to_string(node); - error(node, "Cannot relative slice '%s', value is not addressable", str); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - break; - } - - if (!valid) { - gbString str = expr_to_string(o->expr); - gbString type_str = type_to_string(o->type); - error(o->expr, "Cannot slice '%s' of type '%s'", str, type_str); - gb_string_free(type_str); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } - - if (se->low == nullptr && se->high != nullptr) { - // It is okay to continue as it will assume the 1st index is zero - } - - i64 indices[2] = {}; - Ast *nodes[2] = {se->low, se->high}; - for (isize i = 0; i < gb_count_of(nodes); i++) { - i64 index = max_count; - if (nodes[i] != nullptr) { - i64 capacity = -1; - if (max_count >= 0) { - capacity = max_count; - } - i64 j = 0; - if (check_index_value(c, t, true, nodes[i], capacity, &j)) { - index = j; - } - - node->viral_state_flags |= nodes[i]->viral_state_flags; - } else if (i == 0) { - index = 0; - } - indices[i] = index; - } - - for (isize i = 0; i < gb_count_of(indices); i++) { - i64 a = indices[i]; - for (isize j = i+1; j < gb_count_of(indices); j++) { - i64 b = indices[j]; - if (a > b && b >= 0) { - error(se->close, "Invalid slice indices: [%td > %td]", a, b); - } - } - } - - if (max_count < 0) { - if (o->mode == Addressing_Constant) { - gbString s = expr_to_string(se->expr); - error(se->expr, "Cannot slice constant value '%s'", s); - gb_string_free(s); - } - } - - if (t->kind == Type_MultiPointer && se->high != nullptr) { - /* - x[:] -> [^]T - x[i:] -> [^]T - x[:n] -> []T - x[i:n] -> []T - */ - o->type = alloc_type_slice(t->MultiPointer.elem); - } - - o->mode = Addressing_Value; - - if (is_type_string(t) && max_count >= 0) { - bool all_constant = true; - for (isize i = 0; i < gb_count_of(nodes); i++) { - if (nodes[i] != nullptr) { - TypeAndValue tav = type_and_value_of_expr(nodes[i]); - if (tav.mode != Addressing_Constant) { - all_constant = false; - break; - } - } - } - if (!all_constant) { - gbString str = expr_to_string(o->expr); - error(o->expr, "Cannot slice '%s' with non-constant indices", str); - error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); - gb_string_free(str); - o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring - o->expr = node; - return kind; - } - - String s = {}; - if (o->value.kind == ExactValue_String) { - s = o->value.value_string; - } - - o->mode = Addressing_Constant; - o->type = t; - o->value = exact_value_string(substring(s, cast(isize)indices[0], cast(isize)indices[1])); - } - + kind = check_slice_expr(c, o, node, type_hint); case_end; case_ast_node(mie, MatrixIndexExpr, node); @@ -9230,6 +9298,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type return kind; } + + ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = check_expr_base_internal(c, o, node, type_hint); if (o->type != nullptr && core_type(o->type) == nullptr) { From 445ca705210999e106b6aeb265cfb2979cbd857c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Feb 2022 16:11:48 +0000 Subject: [PATCH 0099/1052] Correct implicit union cast --- src/check_expr.cpp | 11 +++++++++++ src/llvm_backend_expr.cpp | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fb58839bc..3f31ac810 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -508,6 +508,10 @@ bool check_cast_internal(CheckerContext *c, Operand *x, Type *type); #define MAXIMUM_TYPE_DISTANCE 10 i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type) { + if (c == nullptr) { + GB_ASSERT(operand->mode == Addressing_Value); + GB_ASSERT(is_type_typed(operand->type)); + } if (operand->mode == Addressing_Invalid || type == t_invalid) { return -1; @@ -818,6 +822,13 @@ bool check_is_assignable_to(CheckerContext *c, Operand *operand, Type *type) { return check_is_assignable_to_with_score(c, operand, type, &score); } +bool internal_check_is_assignable_to(Type *src, Type *dst) { + Operand x = {}; + x.type = src; + x.mode = Addressing_Value; + return check_is_assignable_to(nullptr, &x, dst); +} + AstPackage *get_package_of_type(Type *type) { for (;;) { if (type == nullptr) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index ea031ee56..715b7df78 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1834,6 +1834,15 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return lb_addr_load(p, parent); } } + if (dst->Union.variants.count == 1) { + Type *vt = dst->Union.variants[0]; + if (internal_check_is_assignable_to(src, vt)) { + value = lb_emit_conv(p, value, vt); + lbAddr parent = lb_add_local_generated(p, t, true); + lb_emit_store_union_variant(p, parent.addr, value, vt); + return lb_addr_load(p, parent); + } + } } // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's From bccbdefde952f605bde620c8d9d0c7f9a5dfc3e0 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Sat, 5 Feb 2022 18:00:59 +0100 Subject: [PATCH 0100/1052] Update interface to allow more modes of iteration It's now possible to iterate over: - all keys in the range min_value ..= max_value, with `iterate_all` - all set keys in the bit array, with `iterate_set` - all unset keys in the range min_value ..= max_value, with `iterate_unset` `Bit_Array` now stores the `max_value` provided during construction, and updates it when a key that was previously out of range is set. --- core/container/bit_array/bit_array.odin | 113 +++++++++++++++++++----- 1 file changed, 91 insertions(+), 22 deletions(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index bf2ae3a40..0a92e3dc4 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -17,12 +17,24 @@ NUM_BITS :: 64 Bit_Array :: struct { bits: [dynamic]u64, bias: int, + max_index: int, } Bit_Array_Iterator :: struct { array: ^Bit_Array, - current_word: uint, - current_bit: uint, + word_idx: int, + bit_idx: uint, +} + +/* + In: + - ba: ^Bit_Array - the array to iterate over + + Out: + - it: ^Bit_Array_Iterator - the iterator that holds iteration state +*/ +make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) { + return Bit_Array_Iterator { array = ba } } /* @@ -30,30 +42,85 @@ Bit_Array_Iterator :: struct { - it: ^Bit_Array_Iterator - the iterator struct that holds the state. Out: - - index: int - the next set bit of the Bit_Array referenced by `it`. - - ok: bool - `true` if the iterator returned a valid index, - `false` if there were no more bits set + - set: bool - the state of the bit at `index` + - index: int - the next bit of the Bit_Array referenced by `it`. + - ok: bool - `true` if the iterator returned a valid index, + `false` if there were no more bits */ -next :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { - words := it.array.bits - // if the word is empty or we have already gone over all the bits in it, - // b.current_bit is greater than the index of any set bit in the word, - // meaning that word >> b.current_bit == 0. - for it.current_word < len(words) && (words[it.current_word] >> it.current_bit == 0) { - it.current_word += 1 - it.current_bit = 0 +iterate_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) { + index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias + if index > it.array.max_index { return false, 0, false } + + word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0 + set = (word >> it.bit_idx & 1) == 1 + + it.bit_idx += 1 + if it.bit_idx >= NUM_BITS { + it.bit_idx = 0 + it.word_idx += 1 } - if it.current_word >= len(words) { return 0, false } + return set, index, true +} - // since we exited the loop and didn't return, this word has some bits higher than - // or equal to `it.current_bit` set. - offset := intrinsics.count_trailing_zeros(words[it.current_word] >> it.current_bit) - // skip over the bit, if the resulting it.current_bit is over 63, - // it is handled by the initial for loop in the next iteration. - it.current_bit += uint(offset) - defer it.current_bit += 1 - return int(it.current_word * NUM_BITS + it.current_bit) + it.array.bias, true +/* + In: + - it: ^Bit_Array_Iterator - the iterator struct that holds the state. + + Out: + - index: int - the next set bit of the Bit_Array referenced by `it`. + - ok: bool - `true` if the iterator returned a valid index, + `false` if there were no more bits set +*/ +iterate_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { + return iterate_internal_(it, true) +} + +/* + In: + - it: ^Bit_Array_Iterator - the iterator struct that holds the state. + + Out: + - index: int - the next unset bit of the Bit_Array referenced by `it`. + - ok: bool - `true` if the iterator returned a valid index, + `false` if there were no more unset bits +*/ +iterate_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { + return iterate_internal_(it, false) +} + +@(private="file") +iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) { + word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0 + when ! ITERATE_SET_BITS { word = ~word } + + // if the word is empty or we have already gone over all the bits in it, + // b.bit_idx is greater than the index of any set bit in the word, + // meaning that word >> b.bit_idx == 0. + for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 { + it.word_idx += 1 + it.bit_idx = 0 + word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0 + when ! ITERATE_SET_BITS { word = ~word } + } + + // if we are iterating the set bits, reaching the end of the array means we have no more bits to check + when ITERATE_SET_BITS { + if it.word_idx >= len(it.array.bits) { + return 0, false + } + } + + // reaching here means that the word has some set bits + it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx)) + index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias + + it.bit_idx += 1 + if it.bit_idx >= NUM_BITS { + it.bit_idx = 0 + it.word_idx += 1 + } + return index, index <= it.array.max_index } @@ -111,6 +178,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator resize_if_needed(ba, leg_index) or_return + if idx > ba.max_index { ba.max_index = idx } ba.bits[leg_index] |= 1 << uint(bit_index) return true } @@ -128,6 +196,7 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) - res = Bit_Array{ bias = min_index, + max_index = max_index, } return res, resize_if_needed(&res, legs) } From b6ebfe4b2c1445f59ed35c20bf8d4ba8910b59de Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Sat, 5 Feb 2022 18:11:48 +0100 Subject: [PATCH 0101/1052] rename iterator procedures --- core/container/bit_array/bit_array.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 0a92e3dc4..5fbac69af 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -47,7 +47,7 @@ make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) { - ok: bool - `true` if the iterator returned a valid index, `false` if there were no more bits */ -iterate_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) { +iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) { index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias if index > it.array.max_index { return false, 0, false } @@ -72,7 +72,7 @@ iterate_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: boo - ok: bool - `true` if the iterator returned a valid index, `false` if there were no more bits set */ -iterate_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { +iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { return iterate_internal_(it, true) } @@ -85,7 +85,7 @@ iterate_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { - ok: bool - `true` if the iterator returned a valid index, `false` if there were no more unset bits */ -iterate_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { +iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { return iterate_internal_(it, false) } From 697f8c7ee6ef3d0af4d8e44163e770ef1f2227c5 Mon Sep 17 00:00:00 2001 From: ap29600 <66381278+ap29600@users.noreply.github.com> Date: Sat, 5 Feb 2022 18:46:25 +0100 Subject: [PATCH 0102/1052] replace a branch with `max` in `core:container/bit_array.set` --- core/container/bit_array/bit_array.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 5fbac69af..5eebe1bcb 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -178,7 +178,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator resize_if_needed(ba, leg_index) or_return - if idx > ba.max_index { ba.max_index = idx } + ba.max_index = max(idx, ba.max_index) ba.bits[leg_index] |= 1 << uint(bit_index) return true } From a571153458211ba34973811eae9057140634b509 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sat, 5 Feb 2022 20:45:32 +0100 Subject: [PATCH 0103/1052] Adds missing calls for os --- core/os/os_darwin.odin | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index adb490e4f..948f68410 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -296,6 +296,9 @@ foreign libc { @(link_name="readdir_r$INODE64") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int --- + @(link_name="rename") _unix_rename :: proc(old: cstring, new: cstring) -> c.int --- + @(link_name="remove") _unix_remove :: proc(path: cstring) -> c.int --- + @(link_name="fchmod") _unix_fchmod :: proc(fildes: Handle, mode: u16) -> c.int --- @(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr --- @@ -412,6 +415,65 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } +is_file_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISREG(cast(u32)s.mode) +} + +is_file_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISREG(cast(u32)s.mode) +} + + +is_dir_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISDIR(cast(u32)s.mode) +} + +is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISDIR(cast(u32)s.mode) +} + +is_file :: proc {is_file_path, is_file_handle} +is_dir :: proc {is_dir_path, is_dir_handle} + + +rename :: proc(old: string, new: string) -> bool { + old_cstr := strings.clone_to_cstring(old, context.temp_allocator) + new_cstr := strings.clone_to_cstring(new, context.temp_allocator) + return _unix_rename(old_cstr, new_cstr) != -1 +} + +remove :: proc(path: string) -> bool { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + return _unix_remove(path) != -1 +} @private _stat :: proc(path: string) -> (OS_Stat, Errno) { From de7e6121866e9fcbe5c9f7fda2a594fa243942b5 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sat, 5 Feb 2022 20:45:55 +0100 Subject: [PATCH 0104/1052] Ignores DS_Store files which MacOS uses for Indexing or some crap --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 0d606498e..abbdccecd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs +# For macOS +.DS_Store + # Build results [Dd]ebug/ [Dd]ebugPublic/ From 3edf638cc6c40e0c05e041359372200150ebc0f8 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sat, 5 Feb 2022 20:54:27 +0100 Subject: [PATCH 0105/1052] Fixed Typo --- core/os/os_darwin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 948f68410..48fcbc724 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -472,7 +472,7 @@ rename :: proc(old: string, new: string) -> bool { remove :: proc(path: string) -> bool { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _unix_remove(path) != -1 + return _unix_remove(path_cstr) != -1 } @private From a724573bb3338e3f096134cbf35325b2dedffb18 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sat, 5 Feb 2022 21:16:58 +0100 Subject: [PATCH 0106/1052] Fixes fopendir and readdir_r for arm64 or seemingly doing so --- core/os/os_darwin.odin | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 48fcbc724..e64542f84 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -290,10 +290,15 @@ foreign libc { @(link_name="fstat64") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int --- @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t --- @(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int --- - @(link_name="fdopendir$INODE64") _unix_fdopendir :: proc(fd: Handle) -> Dir --- + + @(link_name="fdopendir$INODE64") _unix_fdopendir_amd64 :: proc(fd: Handle) -> Dir --- + @(link_name="readdir_r$INODE64") _unix_readdir_r_amd64 :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- + @(link_name="fdopendir") _unix_fdopendir_arm64 :: proc(fd: Handle) -> Dir --- + @(link_name="readdir_r") _unix_readdir_r_arm64 :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- + @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- - @(link_name="readdir_r$INODE64") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- + @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int --- @(link_name="rename") _unix_rename :: proc(old: cstring, new: cstring) -> c.int --- @@ -315,6 +320,14 @@ foreign libc { @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } +when ODIN_ARCH != "arm64" { + _unix_fdopendir :: proc {_unix_fdopendir_amd64} + _unix_readdir_r :: proc {_unix_readdir_r_amd64} +} else { + _unix_fdopendir :: proc {_unix_fdopendir_arm64} + _unix_readdir_r :: proc {_unix_readdir_r_arm64} +} + foreign dl { @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr --- @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr --- From a3d99765cc1012c2bb3e4f7e953c8126a9c158d2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 5 Feb 2022 22:18:22 +0100 Subject: [PATCH 0107/1052] mem: Add `doc.odin` with `Tracking_Allocator` example. --- core/mem/doc.odin | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 core/mem/doc.odin diff --git a/core/mem/doc.odin b/core/mem/doc.odin new file mode 100644 index 000000000..2a5ee06d3 --- /dev/null +++ b/core/mem/doc.odin @@ -0,0 +1,34 @@ +/* +package mem implements various types of allocators. + + +An example of how to use the `Tracking_Allocator` to track subsequent allocations +in your program and report leaks and bad frees: + +```odin +package foo + +import "core:mem" +import "core:fmt" + +_main :: proc() { + do stuff +} + +main :: proc() { + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + _main() + + for _, v in track.allocation_map { + fmt.printf("%v leaked %v bytes", v.location, v.size) + } + for bf in track.bad_free_array { + fmt.printf("%v allocation %p was freed badly", bf.location, bf.memory) + } +} +``` +*/ +package mem \ No newline at end of file From 8b1100bf2b2488c181f7f8112cf079c475f5f59c Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sat, 5 Feb 2022 23:12:55 +0100 Subject: [PATCH 0108/1052] os.open does r/d as default which makes a call to open a dir invalid this should fix this problem --- core/path/filepath/walk.odin | 2 +- tools/odinfmt/main.odin | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin index 29d4fd5b1..dad63cc09 100644 --- a/core/path/filepath/walk.odin +++ b/core/path/filepath/walk.odin @@ -71,7 +71,7 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc) -> (err: os.Errno, skip_ @(private) read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Errno) { - f, err := os.open(dir_name) + f, err := os.open(dir_name, os.O_RDONLY) if err != 0 { return nil, err } diff --git a/tools/odinfmt/main.odin b/tools/odinfmt/main.odin index bc1b521ca..cebb20888 100644 --- a/tools/odinfmt/main.odin +++ b/tools/odinfmt/main.odin @@ -114,7 +114,6 @@ main :: proc() { filepath.walk(path, walk_files); for file in files { - fmt.println(file); backup_path := strings.concatenate({file, "_bk"}); defer delete(backup_path); From 19aec13a1060a521913abc6bd669080171d43594 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Feb 2022 11:42:59 +0000 Subject: [PATCH 0109/1052] Support rank-2 arrays (matrix-like) for `transpose` --- src/check_builtin.cpp | 38 ++++++++++++++++++++++++++++++++++++-- src/llvm_backend_expr.cpp | 21 +++++++++++++++++++++ src/types.cpp | 19 +++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a42741976..d3a3103b1 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2183,9 +2183,43 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } operand->mode = Addressing_Value; - if (is_type_array(t)) { + if (t->kind == Type_Array) { + i32 rank = type_math_rank(t); // Do nothing - operand->type = x.type; + operand->type = x.type; + if (rank > 2) { + gbString s = type_to_string(x.type); + error(call, "'%.*s' expects a matrix or array with a rank of 2, got %s of rank %d", LIT(builtin_name), s, rank); + gb_string_free(s); + return false; + } else if (rank == 2) { + Type *inner = base_type(t->Array.elem); + GB_ASSERT(inner->kind == Type_Array); + Type *elem = inner->Array.elem; + Type *array_inner = alloc_type_array(elem, t->Array.count); + Type *array_outer = alloc_type_array(array_inner, inner->Array.count); + operand->type = array_outer; + + i64 elements = t->Array.count*inner->Array.count; + i64 size = type_size_of(operand->type); + if (!is_type_valid_for_matrix_elems(elem)) { + gbString s = type_to_string(x.type); + error(call, "'%.*s' expects a matrix or array with a base element type of an integer, float, or complex number, got %s", LIT(builtin_name), s); + gb_string_free(s); + } else if (elements > MATRIX_ELEMENT_COUNT_MAX) { + gbString s = type_to_string(x.type); + error(call, "'%.*s' expects a matrix or array with a maximum of %d elements, got %s with %lld elements", LIT(builtin_name), MATRIX_ELEMENT_COUNT_MAX, s, elements); + gb_string_free(s); + } else if (elements > MATRIX_ELEMENT_COUNT_MAX) { + gbString s = type_to_string(x.type); + error(call, "'%.*s' expects a matrix or array with non-zero elements, got %s", LIT(builtin_name), MATRIX_ELEMENT_COUNT_MAX, s); + gb_string_free(s); + } else if (size > MATRIX_ELEMENT_MAX_SIZE) { + gbString s = type_to_string(x.type); + error(call, "Too large of a type for '%.*s', got %s of size %lld, maximum size %d", LIT(builtin_name), s, cast(long long)size, MATRIX_ELEMENT_MAX_SIZE); + gb_string_free(s); + } + } } else { GB_ASSERT(t->kind == Type_Matrix); operand->type = alloc_type_matrix(t->Matrix.elem, t->Matrix.column_count, t->Matrix.row_count); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 715b7df78..29a86d116 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -580,6 +580,27 @@ LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) { lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) { if (is_type_array(m.type)) { + i32 rank = type_math_rank(m.type); + if (rank == 2) { + lbAddr addr = lb_add_local_generated(p, type, false); + lbValue dst = addr.addr; + lbValue src = m; + i32 n = cast(i32)get_array_type_count(m.type); + i32 m = cast(i32)get_array_type_count(type); + // m.type == [n][m]T + // type == [m][n]T + + for (i32 j = 0; j < m; j++) { + lbValue dst_col = lb_emit_struct_ep(p, dst, j); + for (i32 i = 0; i < n; i++) { + lbValue dst_row = lb_emit_struct_ep(p, dst_col, i); + lbValue src_col = lb_emit_struct_ev(p, src, i); + lbValue src_row = lb_emit_struct_ev(p, src_col, j); + lb_emit_store(p, dst_row, src_row); + } + } + return lb_addr_load(p, addr); + } // no-op m.type = type; return m; diff --git a/src/types.cpp b/src/types.cpp index e0d35a12c..9ee6ba359 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -363,6 +363,7 @@ enum TypeInfoFlag : u32 { enum : int { MATRIX_ELEMENT_COUNT_MIN = 1, MATRIX_ELEMENT_COUNT_MAX = 16, + MATRIX_ELEMENT_MAX_SIZE = MATRIX_ELEMENT_COUNT_MAX * (2 * 8), // complex128 }; @@ -1583,6 +1584,24 @@ Type *core_array_type(Type *t) { } } +i32 type_math_rank(Type *t) { + i32 rank = 0; + for (;;) { + t = base_type(t); + switch (t->kind) { + case Type_Array: + rank += 1; + t = t->Array.elem; + break; + case Type_Matrix: + rank += 2; + t = t->Matrix.elem; + break; + default: + return rank; + } + } +} Type *base_complex_elem_type(Type *t) { From 0c16f27814a344f0694b8d4ae580f82393a0d540 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Feb 2022 11:50:27 +0000 Subject: [PATCH 0110/1052] Update parser for `#sparse` --- core/odin/parser/parser.odin | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 0ebabfd70..cc802e7d2 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2273,6 +2273,24 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return original_type case "partial": + tag := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) + tag.tok = tok + tag.name = name.text + original_expr := parse_expr(p, lhs) + expr := ast.unparen_expr(original_expr) + switch t in &expr.derived { + case ast.Comp_Lit: + t.tag = tag + case ast.Array_Type: + t.tag = tag + error(p, tok.pos, "#%s has been replaced with #sparse for non-contiguous enumerated array types", name.text) + case: + error(p, tok.pos, "expected a compound literal after #%s", name.text) + + } + return original_expr + + case "sparse": tag := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) tag.tok = tok tag.name = name.text From cda9fd527199a6046b1a442ed634ac282df4d799 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Feb 2022 11:59:12 +0000 Subject: [PATCH 0111/1052] Add `tag` to `ast.Comp_Lit` --- core/odin/ast/ast.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 9db57541b..8eb0def44 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -151,6 +151,7 @@ Comp_Lit :: struct { open: tokenizer.Pos, elems: []^Expr, close: tokenizer.Pos, + tag: ^Expr, } From ad6ea3d6aa564ad228cf8883a8fd858135a16030 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Feb 2022 13:31:16 +0000 Subject: [PATCH 0112/1052] Replace `any` with `union` for subtyping in `core:odin/ast` --- core/odin/ast/ast.odin | 177 ++++++++++++++++++++++++++- core/odin/ast/clone.odin | 187 +++++++++++++++++------------ core/odin/ast/walk.odin | 154 ++++++++++++------------ core/odin/parser/parser.odin | 180 ++++++++++++++-------------- core/odin/printer/visit.odin | 226 ++++++++++++++++++++--------------- 5 files changed, 581 insertions(+), 343 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 8eb0def44..740299539 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -34,7 +34,7 @@ Node :: struct { pos: tokenizer.Pos, end: tokenizer.Pos, state_flags: Node_State_Flags, - derived: any, + derived: Any_Node, } Comment_Group :: struct { @@ -88,9 +88,11 @@ File :: struct { Expr :: struct { using expr_base: Node, + derived_expr: Any_Expr, } Stmt :: struct { using stmt_base: Node, + derived_stmt: Any_Stmt, } Decl :: struct { using decl_base: Stmt, @@ -541,7 +543,7 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) { return } for { - e, ok := val.derived.(Paren_Expr) + e, ok := val.derived.(^Paren_Expr) if !ok || e.expr == nil { break } @@ -758,4 +760,173 @@ Matrix_Type :: struct { row_count: ^Expr, column_count: ^Expr, elem: ^Expr, -} \ No newline at end of file +} + + +Any_Node :: union { + ^Package, + ^File, + ^Comment_Group, + + ^Bad_Expr, + ^Ident, + ^Implicit, + ^Undef, + ^Basic_Lit, + ^Basic_Directive, + ^Ellipsis, + ^Proc_Lit, + ^Comp_Lit, + ^Tag_Expr, + ^Unary_Expr, + ^Binary_Expr, + ^Paren_Expr, + ^Selector_Expr, + ^Implicit_Selector_Expr, + ^Selector_Call_Expr, + ^Index_Expr, + ^Deref_Expr, + ^Slice_Expr, + ^Matrix_Index_Expr, + ^Call_Expr, + ^Field_Value, + ^Ternary_If_Expr, + ^Ternary_When_Expr, + ^Or_Else_Expr, + ^Or_Return_Expr, + ^Type_Assertion, + ^Type_Cast, + ^Auto_Cast, + ^Inline_Asm_Expr, + + ^Proc_Group, + + ^Typeid_Type, + ^Helper_Type, + ^Distinct_Type, + ^Poly_Type, + ^Proc_Type, + ^Pointer_Type, + ^Multi_Pointer_Type, + ^Array_Type, + ^Dynamic_Array_Type, + ^Struct_Type, + ^Union_Type, + ^Enum_Type, + ^Bit_Set_Type, + ^Map_Type, + ^Relative_Type, + ^Matrix_Type, + + ^Bad_Stmt, + ^Empty_Stmt, + ^Expr_Stmt, + ^Tag_Stmt, + ^Assign_Stmt, + ^Block_Stmt, + ^If_Stmt, + ^When_Stmt, + ^Return_Stmt, + ^Defer_Stmt, + ^For_Stmt, + ^Range_Stmt, + ^Inline_Range_Stmt, + ^Case_Clause, + ^Switch_Stmt, + ^Type_Switch_Stmt, + ^Branch_Stmt, + ^Using_Stmt, + + ^Bad_Decl, + ^Value_Decl, + ^Package_Decl, + ^Import_Decl, + ^Foreign_Block_Decl, + ^Foreign_Import_Decl, + + ^Attribute, + ^Field, + ^Field_List, +} + + +Any_Expr :: union { + ^Bad_Expr, + ^Ident, + ^Implicit, + ^Undef, + ^Basic_Lit, + ^Basic_Directive, + ^Ellipsis, + ^Proc_Lit, + ^Comp_Lit, + ^Tag_Expr, + ^Unary_Expr, + ^Binary_Expr, + ^Paren_Expr, + ^Selector_Expr, + ^Implicit_Selector_Expr, + ^Selector_Call_Expr, + ^Index_Expr, + ^Deref_Expr, + ^Slice_Expr, + ^Matrix_Index_Expr, + ^Call_Expr, + ^Field_Value, + ^Ternary_If_Expr, + ^Ternary_When_Expr, + ^Or_Else_Expr, + ^Or_Return_Expr, + ^Type_Assertion, + ^Type_Cast, + ^Auto_Cast, + ^Inline_Asm_Expr, + + ^Proc_Group, + + ^Typeid_Type, + ^Helper_Type, + ^Distinct_Type, + ^Poly_Type, + ^Proc_Type, + ^Pointer_Type, + ^Multi_Pointer_Type, + ^Array_Type, + ^Dynamic_Array_Type, + ^Struct_Type, + ^Union_Type, + ^Enum_Type, + ^Bit_Set_Type, + ^Map_Type, + ^Relative_Type, + ^Matrix_Type, +} + + +Any_Stmt :: union { + ^Bad_Stmt, + ^Empty_Stmt, + ^Expr_Stmt, + ^Tag_Stmt, + ^Assign_Stmt, + ^Block_Stmt, + ^If_Stmt, + ^When_Stmt, + ^Return_Stmt, + ^Defer_Stmt, + ^For_Stmt, + ^Range_Stmt, + ^Inline_Range_Stmt, + ^Case_Clause, + ^Switch_Stmt, + ^Type_Switch_Stmt, + ^Branch_Stmt, + ^Using_Stmt, + + ^Bad_Decl, + ^Value_Decl, + ^Package_Decl, + ^Import_Decl, + ^Foreign_Block_Decl, + ^Foreign_Import_Decl, +} diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 1e3058678..723f7b90d 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -1,16 +1,25 @@ package odin_ast +import "core:intrinsics" import "core:mem" import "core:fmt" +import "core:reflect" import "core:odin/tokenizer" +_ :: intrinsics new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { n, _ := mem.new(T) n.pos = pos n.end = end - n.derived = n^ + n.derived = n base: ^Node = n // dummy check _ = base // "Use" type to make -vet happy + when intrinsics.type_has_field(T, "derived_expr") { + n.derived_expr = n + } + when intrinsics.type_has_field(T, "derived_stmt") { + n.derived_stmt = n + } return n } @@ -61,228 +70,248 @@ clone_node :: proc(node: ^Node) -> ^Node { size := size_of(Node) align := align_of(Node) - ti := type_info_of(node.derived.id) + ti := reflect.union_variant_type_info(node.derived) if ti != nil { size = ti.size align = ti.align } - switch in node.derived { - case Package, File: + #partial switch in node.derived { + case ^Package, ^File: panic("Cannot clone this node type") } res := cast(^Node)mem.alloc(size, align) src: rawptr = node if node.derived != nil { - src = node.derived.data + src = (^rawptr)(&node.derived)^ } mem.copy(res, src, size) - res.derived.data = rawptr(res) - res.derived.id = node.derived.id + res_any: any + res_any.data = res + res_any.id = ti.id - switch r in &res.derived { - case Bad_Expr: - case Ident: - case Implicit: - case Undef: - case Basic_Lit: + reflect.set_union_value(res.derived, res_any) - case Ellipsis: + derived_expr := reflect.struct_field_value_by_name(res_any, "derived_expr", true) + derived_stmt := reflect.struct_field_value_by_name(res_any, "derived_stmt", true) + reflect.set_union_value(res.derived, derived_expr) + reflect.set_union_value(res.derived, derived_stmt) + + switch r in res.derived { + case ^Package, ^File: + case ^Bad_Expr: + case ^Ident: + case ^Implicit: + case ^Undef: + case ^Basic_Lit: + case ^Basic_Directive: + case ^Comment_Group: + + case ^Ellipsis: r.expr = clone(r.expr) - case Proc_Lit: + case ^Proc_Lit: r.type = auto_cast clone(r.type) r.body = clone(r.body) - case Comp_Lit: + case ^Comp_Lit: r.type = clone(r.type) r.elems = clone(r.elems) - case Tag_Expr: + case ^Tag_Expr: r.expr = clone(r.expr) - case Unary_Expr: + case ^Unary_Expr: r.expr = clone(r.expr) - case Binary_Expr: + case ^Binary_Expr: r.left = clone(r.left) r.right = clone(r.right) - case Paren_Expr: + case ^Paren_Expr: r.expr = clone(r.expr) - case Selector_Expr: + case ^Selector_Expr: r.expr = clone(r.expr) r.field = auto_cast clone(r.field) - case Implicit_Selector_Expr: + case ^Implicit_Selector_Expr: r.field = auto_cast clone(r.field) - case Selector_Call_Expr: + case ^Selector_Call_Expr: r.expr = clone(r.expr) r.call = auto_cast clone(r.call) - case Index_Expr: + case ^Index_Expr: r.expr = clone(r.expr) r.index = clone(r.index) - case Matrix_Index_Expr: + case ^Matrix_Index_Expr: r.expr = clone(r.expr) r.row_index = clone(r.row_index) r.column_index = clone(r.column_index) - case Deref_Expr: + case ^Deref_Expr: r.expr = clone(r.expr) - case Slice_Expr: + case ^Slice_Expr: r.expr = clone(r.expr) r.low = clone(r.low) r.high = clone(r.high) - case Call_Expr: + case ^Call_Expr: r.expr = clone(r.expr) r.args = clone(r.args) - case Field_Value: + case ^Field_Value: r.field = clone(r.field) r.value = clone(r.value) - case Ternary_If_Expr: + case ^Ternary_If_Expr: r.x = clone(r.x) r.cond = clone(r.cond) r.y = clone(r.y) - case Ternary_When_Expr: + case ^Ternary_When_Expr: r.x = clone(r.x) r.cond = clone(r.cond) r.y = clone(r.y) - case Or_Else_Expr: + case ^Or_Else_Expr: r.x = clone(r.x) r.y = clone(r.y) - case Or_Return_Expr: + case ^Or_Return_Expr: r.expr = clone(r.expr) - case Type_Assertion: + case ^Type_Assertion: r.expr = clone(r.expr) r.type = clone(r.type) - case Type_Cast: + case ^Type_Cast: r.type = clone(r.type) r.expr = clone(r.expr) - case Auto_Cast: + case ^Auto_Cast: r.expr = clone(r.expr) - case Inline_Asm_Expr: + case ^Inline_Asm_Expr: r.param_types = clone(r.param_types) r.return_type = clone(r.return_type) r.constraints_string = clone(r.constraints_string) r.asm_string = clone(r.asm_string) - case Bad_Stmt: + case ^Bad_Stmt: // empty - case Empty_Stmt: + case ^Empty_Stmt: // empty - case Expr_Stmt: + case ^Expr_Stmt: r.expr = clone(r.expr) - case Tag_Stmt: + case ^Tag_Stmt: r.stmt = clone(r.stmt) - case Assign_Stmt: + case ^Assign_Stmt: r.lhs = clone(r.lhs) r.rhs = clone(r.rhs) - case Block_Stmt: + case ^Block_Stmt: r.label = clone(r.label) r.stmts = clone(r.stmts) - case If_Stmt: + case ^If_Stmt: r.label = clone(r.label) r.init = clone(r.init) r.cond = clone(r.cond) r.body = clone(r.body) r.else_stmt = clone(r.else_stmt) - case When_Stmt: + case ^When_Stmt: r.cond = clone(r.cond) r.body = clone(r.body) r.else_stmt = clone(r.else_stmt) - case Return_Stmt: + case ^Return_Stmt: r.results = clone(r.results) - case Defer_Stmt: + case ^Defer_Stmt: r.stmt = clone(r.stmt) - case For_Stmt: + case ^For_Stmt: r.label = clone(r.label) r.init = clone(r.init) r.cond = clone(r.cond) r.post = clone(r.post) r.body = clone(r.body) - case Range_Stmt: + case ^Range_Stmt: r.label = clone(r.label) r.vals = clone(r.vals) r.expr = clone(r.expr) r.body = clone(r.body) - case Case_Clause: + case ^Inline_Range_Stmt: + r.label = clone(r.label) + r.val0 = clone(r.val0) + r.val1 = clone(r.val1) + r.expr = clone(r.expr) + r.body = clone(r.body) + case ^Case_Clause: r.list = clone(r.list) r.body = clone(r.body) - case Switch_Stmt: + case ^Switch_Stmt: r.label = clone(r.label) r.init = clone(r.init) r.cond = clone(r.cond) r.body = clone(r.body) - case Type_Switch_Stmt: + case ^Type_Switch_Stmt: r.label = clone(r.label) r.tag = clone(r.tag) r.expr = clone(r.expr) r.body = clone(r.body) - case Branch_Stmt: + case ^Branch_Stmt: r.label = auto_cast clone(r.label) - case Using_Stmt: + case ^Using_Stmt: r.list = clone(r.list) - case Bad_Decl: - case Value_Decl: + case ^Bad_Decl: + case ^Value_Decl: r.attributes = clone(r.attributes) r.names = clone(r.names) r.type = clone(r.type) r.values = clone(r.values) - case Package_Decl: - case Import_Decl: - case Foreign_Block_Decl: + case ^Package_Decl: + case ^Import_Decl: + case ^Foreign_Block_Decl: r.attributes = clone(r.attributes) r.foreign_library = clone(r.foreign_library) r.body = clone(r.body) - case Foreign_Import_Decl: + case ^Foreign_Import_Decl: r.name = auto_cast clone(r.name) - case Proc_Group: + case ^Proc_Group: r.args = clone(r.args) - case Attribute: + case ^Attribute: r.elems = clone(r.elems) - case Field: + case ^Field: r.names = clone(r.names) r.type = clone(r.type) r.default_value = clone(r.default_value) - case Field_List: + case ^Field_List: r.list = clone(r.list) - case Typeid_Type: + case ^Typeid_Type: r.specialization = clone(r.specialization) - case Helper_Type: + case ^Helper_Type: r.type = clone(r.type) - case Distinct_Type: + case ^Distinct_Type: r.type = clone(r.type) - case Poly_Type: + case ^Poly_Type: r.type = auto_cast clone(r.type) r.specialization = clone(r.specialization) - case Proc_Type: + case ^Proc_Type: r.params = auto_cast clone(r.params) r.results = auto_cast clone(r.results) - case Pointer_Type: + case ^Pointer_Type: r.elem = clone(r.elem) - case Multi_Pointer_Type: + case ^Multi_Pointer_Type: r.elem = clone(r.elem) - case Array_Type: + case ^Array_Type: r.len = clone(r.len) r.elem = clone(r.elem) - case Dynamic_Array_Type: + case ^Dynamic_Array_Type: r.elem = clone(r.elem) - case Struct_Type: + case ^Struct_Type: r.poly_params = auto_cast clone(r.poly_params) r.align = clone(r.align) r.fields = auto_cast clone(r.fields) - case Union_Type: + case ^Union_Type: r.poly_params = auto_cast clone(r.poly_params) r.align = clone(r.align) r.variants = clone(r.variants) - case Enum_Type: + case ^Enum_Type: r.base_type = clone(r.base_type) r.fields = clone(r.fields) - case Bit_Set_Type: + case ^Bit_Set_Type: r.elem = clone(r.elem) r.underlying = clone(r.underlying) - case Map_Type: + case ^Map_Type: r.key = clone(r.key) r.value = clone(r.value) - case Matrix_Type: + case ^Matrix_Type: r.row_count = clone(r.row_count) r.column_count = clone(r.column_count) r.elem = clone(r.elem) + case ^Relative_Type: + r.tag = clone(r.tag) + r.type = clone(r.type) case: fmt.panicf("Unhandled node kind: %T", r) } diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index d0d17cc9e..7241d283f 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -59,64 +59,64 @@ walk :: proc(v: ^Visitor, node: ^Node) { } switch n in &node.derived { - case File: + case ^File: if n.docs != nil { walk(v, n.docs) } walk_stmt_list(v, n.decls[:]) - case Package: + case ^Package: for _, f in n.files { walk(v, f) } - case Comment_Group: + case ^Comment_Group: // empty - case Bad_Expr: - case Ident: - case Implicit: - case Undef: - case Basic_Lit: - case Basic_Directive: - case Ellipsis: + case ^Bad_Expr: + case ^Ident: + case ^Implicit: + case ^Undef: + case ^Basic_Lit: + case ^Basic_Directive: + case ^Ellipsis: if n.expr != nil { walk(v, n.expr) } - case Proc_Lit: + case ^Proc_Lit: walk(v, n.type) walk(v, n.body) walk_expr_list(v, n.where_clauses) - case Comp_Lit: + case ^Comp_Lit: if n.type != nil { walk(v, n.type) } walk_expr_list(v, n.elems) - case Tag_Expr: + case ^Tag_Expr: walk(v, n.expr) - case Unary_Expr: + case ^Unary_Expr: walk(v, n.expr) - case Binary_Expr: + case ^Binary_Expr: walk(v, n.left) walk(v, n.right) - case Paren_Expr: + case ^Paren_Expr: walk(v, n.expr) - case Selector_Expr: + case ^Selector_Expr: walk(v, n.expr) walk(v, n.field) - case Implicit_Selector_Expr: + case ^Implicit_Selector_Expr: walk(v, n.field) - case Selector_Call_Expr: + case ^Selector_Call_Expr: walk(v, n.expr) walk(v, n.call) - case Index_Expr: + case ^Index_Expr: walk(v, n.expr) walk(v, n.index) - case Matrix_Index_Expr: + case ^Matrix_Index_Expr: walk(v, n.expr) walk(v, n.row_index) walk(v, n.column_index) - case Deref_Expr: + case ^Deref_Expr: walk(v, n.expr) - case Slice_Expr: + case ^Slice_Expr: walk(v, n.expr) if n.low != nil { walk(v, n.low) @@ -124,57 +124,57 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.high != nil { walk(v, n.high) } - case Call_Expr: + case ^Call_Expr: walk(v, n.expr) walk_expr_list(v, n.args) - case Field_Value: + case ^Field_Value: walk(v, n.field) walk(v, n.value) - case Ternary_If_Expr: + case ^Ternary_If_Expr: walk(v, n.x) walk(v, n.cond) walk(v, n.y) - case Ternary_When_Expr: + case ^Ternary_When_Expr: walk(v, n.x) walk(v, n.cond) walk(v, n.y) - case Or_Else_Expr: + case ^Or_Else_Expr: walk(v, n.x) walk(v, n.y) - case Or_Return_Expr: + case ^Or_Return_Expr: walk(v, n.expr) - case Type_Assertion: + case ^Type_Assertion: walk(v, n.expr) if n.type != nil { walk(v, n.type) } - case Type_Cast: + case ^Type_Cast: walk(v, n.type) walk(v, n.expr) - case Auto_Cast: + case ^Auto_Cast: walk(v, n.expr) - case Inline_Asm_Expr: + case ^Inline_Asm_Expr: walk_expr_list(v, n.param_types) walk(v, n.return_type) walk(v, n.constraints_string) walk(v, n.asm_string) - case Bad_Stmt: - case Empty_Stmt: - case Expr_Stmt: + case ^Bad_Stmt: + case ^Empty_Stmt: + case ^Expr_Stmt: walk(v, n.expr) - case Tag_Stmt: + case ^Tag_Stmt: walk(v, n.stmt) - case Assign_Stmt: + case ^Assign_Stmt: walk_expr_list(v, n.lhs) walk_expr_list(v, n.rhs) - case Block_Stmt: + case ^Block_Stmt: if n.label != nil { walk(v, n.label) } walk_stmt_list(v, n.stmts) - case If_Stmt: + case ^If_Stmt: if n.label != nil { walk(v, n.label) } @@ -186,17 +186,17 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.else_stmt != nil { walk(v, n.else_stmt) } - case When_Stmt: + case ^When_Stmt: walk(v, n.cond) walk(v, n.body) if n.else_stmt != nil { walk(v, n.else_stmt) } - case Return_Stmt: + case ^Return_Stmt: walk_expr_list(v, n.results) - case Defer_Stmt: + case ^Defer_Stmt: walk(v, n.stmt) - case For_Stmt: + case ^For_Stmt: if n.label != nil { walk(v, n.label) } @@ -210,7 +210,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.post) } walk(v, n.body) - case Range_Stmt: + case ^Range_Stmt: if n.label != nil { walk(v, n.label) } @@ -221,7 +221,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk(v, n.expr) walk(v, n.body) - case Inline_Range_Stmt: + case ^Inline_Range_Stmt: if n.label != nil { walk(v, n.label) } @@ -233,10 +233,10 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk(v, n.expr) walk(v, n.body) - case Case_Clause: + case ^Case_Clause: walk_expr_list(v, n.list) walk_stmt_list(v, n.body) - case Switch_Stmt: + case ^Switch_Stmt: if n.label != nil { walk(v, n.label) } @@ -247,7 +247,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.cond) } walk(v, n.body) - case Type_Switch_Stmt: + case ^Type_Switch_Stmt: if n.label != nil { walk(v, n.label) } @@ -258,16 +258,16 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.expr) } walk(v, n.body) - case Branch_Stmt: + case ^Branch_Stmt: if n.label != nil { walk(v, n.label) } - case Using_Stmt: + case ^Using_Stmt: walk_expr_list(v, n.list) - case Bad_Decl: - case Value_Decl: + case ^Bad_Decl: + case ^Value_Decl: if n.docs != nil { walk(v, n.docs) } @@ -280,21 +280,21 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.comment != nil { walk(v, n.comment) } - case Package_Decl: + case ^Package_Decl: if n.docs != nil { walk(v, n.docs) } if n.comment != nil { walk(v, n.comment) } - case Import_Decl: + case ^Import_Decl: if n.docs != nil { walk(v, n.docs) } if n.comment != nil { walk(v, n.comment) } - case Foreign_Block_Decl: + case ^Foreign_Block_Decl: if n.docs != nil { walk(v, n.docs) } @@ -303,7 +303,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.foreign_library) } walk(v, n.body) - case Foreign_Import_Decl: + case ^Foreign_Import_Decl: if n.docs != nil { walk(v, n.docs) } @@ -313,11 +313,11 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.comment) } - case Proc_Group: + case ^Proc_Group: walk_expr_list(v, n.args) - case Attribute: + case ^Attribute: walk_expr_list(v, n.elems) - case Field: + case ^Field: if n.docs != nil { walk(v, n.docs) } @@ -331,31 +331,31 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.comment != nil { walk(v, n.comment) } - case Field_List: + case ^Field_List: for x in n.list { walk(v, x) } - case Typeid_Type: + case ^Typeid_Type: if n.specialization != nil { walk(v, n.specialization) } - case Helper_Type: + case ^Helper_Type: walk(v, n.type) - case Distinct_Type: + case ^Distinct_Type: walk(v, n.type) - case Poly_Type: + case ^Poly_Type: walk(v, n.type) if n.specialization != nil { walk(v, n.specialization) } - case Proc_Type: + case ^Proc_Type: walk(v, n.params) walk(v, n.results) - case Pointer_Type: + case ^Pointer_Type: walk(v, n.elem) - case Multi_Pointer_Type: + case ^Multi_Pointer_Type: walk(v, n.elem) - case Array_Type: + case ^Array_Type: if n.tag != nil { walk(v, n.tag) } @@ -363,12 +363,12 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.len) } walk(v, n.elem) - case Dynamic_Array_Type: + case ^Dynamic_Array_Type: if n.tag != nil { walk(v, n.tag) } walk(v, n.elem) - case Struct_Type: + case ^Struct_Type: if n.poly_params != nil { walk(v, n.poly_params) } @@ -377,7 +377,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk_expr_list(v, n.where_clauses) walk(v, n.fields) - case Union_Type: + case ^Union_Type: if n.poly_params != nil { walk(v, n.poly_params) } @@ -386,23 +386,23 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk_expr_list(v, n.where_clauses) walk_expr_list(v, n.variants) - case Enum_Type: + case ^Enum_Type: if n.base_type != nil { walk(v, n.base_type) } walk_expr_list(v, n.fields) - case Bit_Set_Type: + case ^Bit_Set_Type: walk(v, n.elem) if n.underlying != nil { walk(v, n.underlying) } - case Map_Type: + case ^Map_Type: walk(v, n.key) walk(v, n.value) - case Relative_Type: + case ^Relative_Type: walk(v, n.tag) walk(v, n.type) - case Matrix_Type: + case ^Matrix_Type: walk(v, n.row_count) walk(v, n.column_count) walk(v, n.elem) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index cc802e7d2..7cce986ae 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -195,10 +195,10 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool { for p.curr_tok.kind != .EOF { stmt := parse_stmt(p) if stmt != nil { - if _, ok := stmt.derived.(ast.Empty_Stmt); !ok { + if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok { append(&p.file.decls, stmt) - if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil { - if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok { + if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil { + if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok { error(p, stmt.pos, "procedure literal evaluated but not used") } } @@ -447,7 +447,7 @@ is_blank_ident_token :: proc(tok: tokenizer.Token) -> bool { return false } is_blank_ident_node :: proc(node: ^ast.Node) -> bool { - if ident, ok := node.derived.(ast.Ident); ok { + if ident, ok := node.derived.(^ast.Ident); ok { return is_blank_ident(ident.name) } return true @@ -490,34 +490,34 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool { return true } - switch n in node.derived { - case ast.Empty_Stmt, ast.Block_Stmt: + #partial switch n in node.derived { + case ^ast.Empty_Stmt, ^ast.Block_Stmt: return true - case ast.If_Stmt, ast.When_Stmt, - ast.For_Stmt, ast.Range_Stmt, ast.Inline_Range_Stmt, - ast.Switch_Stmt, ast.Type_Switch_Stmt: + case ^ast.If_Stmt, ^ast.When_Stmt, + ^ast.For_Stmt, ^ast.Range_Stmt, ^ast.Inline_Range_Stmt, + ^ast.Switch_Stmt, ^ast.Type_Switch_Stmt: return true - case ast.Helper_Type: + case ^ast.Helper_Type: return is_semicolon_optional_for_node(p, n.type) - case ast.Distinct_Type: + case ^ast.Distinct_Type: return is_semicolon_optional_for_node(p, n.type) - case ast.Pointer_Type: + case ^ast.Pointer_Type: return is_semicolon_optional_for_node(p, n.elem) - case ast.Struct_Type, ast.Union_Type, ast.Enum_Type: + case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type: // Require semicolon within a procedure body return p.curr_proc == nil - case ast.Proc_Lit: + case ^ast.Proc_Lit: return true - case ast.Package_Decl, ast.Import_Decl, ast.Foreign_Import_Decl: + case ^ast.Package_Decl, ^ast.Import_Decl, ^ast.Foreign_Import_Decl: return true - case ast.Foreign_Block_Decl: + case ^ast.Foreign_Block_Decl: return is_semicolon_optional_for_node(p, n.body) - case ast.Value_Decl: + case ^ast.Value_Decl: if n.is_mutable { return false } @@ -629,10 +629,10 @@ parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt { p.curr_tok.kind != .EOF { stmt := parse_stmt(p) if stmt != nil { - if _, ok := stmt.derived.(ast.Empty_Stmt); !ok { + if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok { append(&list, stmt) - if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil { - if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok { + if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil { + if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok { error(p, stmt.pos, "procedure literal evaluated but not used") } } @@ -710,7 +710,7 @@ convert_stmt_to_expr :: proc(p: ^Parser, stmt: ^ast.Stmt, kind: string) -> ^ast. if stmt == nil { return nil } - if es, ok := stmt.derived.(ast.Expr_Stmt); ok { + if es, ok := stmt.derived.(^ast.Expr_Stmt); ok { return es.expr } error(p, stmt.pos, "expected %s, found a simple statement", kind) @@ -852,7 +852,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { if p.curr_tok.kind != .Semicolon { cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In}) - if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == .In { + if as, ok := cond.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In { is_range = true } } @@ -894,7 +894,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { if is_range { - assign_stmt := cond.derived.(ast.Assign_Stmt) + assign_stmt := cond.derived.(^ast.Assign_Stmt) vals := assign_stmt.lhs[:] rhs: ^ast.Expr @@ -975,7 +975,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { tag = as } else { tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In}) - if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In { + if as, ok := tag.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In { is_type_switch = true } else if parse_control_statement_semicolon_separator(p) { init = tag @@ -1062,14 +1062,14 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: skip_possible_newline(p) decl := parse_stmt(p) - switch d in &decl.derived { - case ast.Value_Decl: + #partial switch d in decl.derived_stmt { + case ^ast.Value_Decl: if d.docs == nil { d.docs = docs } append(&d.attributes, attribute) - case ast.Foreign_Block_Decl: + case ^ast.Foreign_Block_Decl: if d.docs == nil { d.docs = docs } append(&d.attributes, attribute) - case ast.Foreign_Import_Decl: + case ^ast.Foreign_Import_Decl: if d.docs == nil { d.docs = docs } append(&d.attributes, attribute) case: @@ -1083,11 +1083,11 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt { decl := parse_stmt(p) - switch in decl.derived { - case ast.Empty_Stmt, ast.Bad_Stmt, ast.Bad_Decl: + #partial switch in decl.derived_stmt { + case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl: // Ignore return nil - case ast.When_Stmt, ast.Value_Decl: + case ^ast.When_Stmt, ^ast.Value_Decl: return decl } @@ -1291,13 +1291,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { case .Defer: tok := advance_token(p) stmt := parse_stmt(p) - switch s in stmt.derived { - case ast.Empty_Stmt: + #partial switch s in stmt.derived_stmt { + case ^ast.Empty_Stmt: error(p, s.pos, "empty statement after defer (e.g. ';')") - case ast.Defer_Stmt: + case ^ast.Defer_Stmt: error(p, s.pos, "you cannot defer a defer statement") stmt = s.stmt - case ast.Return_Stmt: + case ^ast.Return_Stmt: error(p, s.pos, "you cannot defer a return statement") } ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end) @@ -1369,8 +1369,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { expect_token_after(p, .Colon, "identifier list") decl := parse_value_decl(p, list, docs) if decl != nil { - switch d in &decl.derived { - case ast.Value_Decl: + #partial switch d in decl.derived_stmt { + case ^ast.Value_Decl: d.is_using = true return decl } @@ -1401,9 +1401,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { return stmt case "partial": stmt := parse_stmt(p) - switch s in &stmt.derived { - case ast.Switch_Stmt: s.partial = true - case ast.Type_Switch_Stmt: s.partial = true + #partial switch s in stmt.derived_stmt { + case ^ast.Switch_Stmt: s.partial = true + case ^ast.Type_Switch_Stmt: s.partial = true case: error(p, stmt.pos, "#partial can only be applied to a switch statement") } return stmt @@ -1548,11 +1548,11 @@ parse_body :: proc(p: ^Parser) -> ^ast.Block_Stmt { } convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt { - switch s in stmt.derived { - case ast.Block_Stmt: + #partial switch s in stmt.derived_stmt { + case ^ast.Block_Stmt: error(p, stmt.pos, "expected a normal statement rather than a block statement") return stmt - case ast.Empty_Stmt: + case ^ast.Empty_Stmt: error(p, stmt.pos, "expected a non-empty statement") } @@ -1629,10 +1629,10 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags, id: ^ast.Expr = ident.expr - switch n in ident.expr.derived { - case ast.Ident: - case ast.Bad_Expr: - case ast.Poly_Type: + #partial switch n in ident.expr.derived_expr { + case ^ast.Ident: + case ^ast.Bad_Expr: + case ^ast.Poly_Type: if allow_poly_names { if n.specialization == nil { break @@ -1794,21 +1794,21 @@ check_procedure_name_list :: proc(p: ^Parser, names: []^ast.Expr) -> bool { return false } - _, first_is_polymorphic := names[0].derived.(ast.Poly_Type) + _, first_is_polymorphic := names[0].derived.(^ast.Poly_Type) any_polymorphic_names := first_is_polymorphic for i := 1; i < len(names); i += 1 { name := names[i] if first_is_polymorphic { - if _, ok := name.derived.(ast.Poly_Type); ok { + if _, ok := name.derived.(^ast.Poly_Type); ok { any_polymorphic_names = true } else { error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers") return any_polymorphic_names } } else { - if _, ok := name.derived.(ast.Poly_Type); ok { + if _, ok := name.derived.(^ast.Poly_Type); ok { any_polymorphic_names = true error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers") return any_polymorphic_names @@ -1873,7 +1873,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags if type == nil { return false } - _, ok := type.derived.(ast.Ellipsis) + _, ok := type.derived.(^ast.Ellipsis) return ok } @@ -1891,7 +1891,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags type = parse_var_type(p, allowed_flags) tt := ast.unparen_expr(type) if is_signature && !any_polymorphic_names { - if ti, ok := tt.derived.(ast.Typeid_Type); ok && ti.specialization != nil { + if ti, ok := tt.derived.(^ast.Typeid_Type); ok && ti.specialization != nil { error(p, tt.pos, "specialization of typeid is not allowed without polymorphic names") } } @@ -1967,7 +1967,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags p.curr_tok.kind != .EOF { prefix_flags := parse_field_prefixes(p) param := parse_var_type(p, allowed_flags & {.Typeid_Token, .Ellipsis}) - if _, ok := param.derived.(ast.Ellipsis); ok { + if _, ok := param.derived.(^ast.Ellipsis); ok { if seen_ellipsis { error(p, param.pos, "extra variadic parameter after ellipsis") } @@ -1994,8 +1994,8 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags names := make([]^ast.Expr, 1) names[0] = ast.new(ast.Ident, tok.pos, end_pos(tok)) - switch ident in &names[0].derived { - case ast.Ident: + #partial switch ident in names[0].derived_expr { + case ^ast.Ident: ident.name = tok.text case: unreachable() @@ -2125,12 +2125,12 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type { loop: for param in params.list { if param.type != nil { - if _, ok := param.type.derived.(ast.Poly_Type); ok { + if _, ok := param.type.derived.(^ast.Poly_Type); ok { is_generic = true break loop } for name in param.names { - if _, ok := name.derived.(ast.Poly_Type); ok { + if _, ok := name.derived.(^ast.Poly_Type); ok { is_generic = true break loop } @@ -2167,13 +2167,13 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ } } - switch e in &ast.unparen_expr(expr).derived { - case ast.Proc_Lit: + #partial switch e in ast.unparen_expr(expr).derived_expr { + case ^ast.Proc_Lit: if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal") } e.inlining = pi - case ast.Call_Expr: + case ^ast.Call_Expr: if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call") } @@ -2264,9 +2264,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { bd.name = name.text original_type := parse_type(p) type := ast.unparen_expr(original_type) - switch t in &type.derived { - case ast.Array_Type: t.tag = bd - case ast.Dynamic_Array_Type: t.tag = bd + #partial switch t in type.derived_expr { + case ^ast.Array_Type: t.tag = bd + case ^ast.Dynamic_Array_Type: t.tag = bd case: error(p, original_type.pos, "expected an array type after #%s", name.text) } @@ -2278,10 +2278,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tag.name = name.text original_expr := parse_expr(p, lhs) expr := ast.unparen_expr(original_expr) - switch t in &expr.derived { - case ast.Comp_Lit: + #partial switch t in expr.derived_expr { + case ^ast.Comp_Lit: t.tag = tag - case ast.Array_Type: + case ^ast.Array_Type: t.tag = tag error(p, tok.pos, "#%s has been replaced with #sparse for non-contiguous enumerated array types", name.text) case: @@ -2296,8 +2296,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tag.name = name.text original_type := parse_type(p) type := ast.unparen_expr(original_type) - switch t in &type.derived { - case ast.Array_Type: + #partial switch t in type.derived_expr { + case ^ast.Array_Type: t.tag = tag case: error(p, tok.pos, "expected an enumerated array type after #%s", name.text) @@ -2677,7 +2677,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { variants: [dynamic]^ast.Expr for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { type := parse_type(p) - if _, ok := type.derived.(ast.Bad_Expr); !ok { + if _, ok := type.derived.(^ast.Bad_Expr); !ok { append(&variants, type) } if !allow_token(p, .Comma) { @@ -2852,19 +2852,19 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool { if val == nil { return false } - switch _ in val.derived { - case ast.Bad_Expr, - ast.Ident, - ast.Selector_Expr, - ast.Array_Type, - ast.Struct_Type, - ast.Union_Type, - ast.Enum_Type, - ast.Dynamic_Array_Type, - ast.Map_Type, - ast.Bit_Set_Type, - ast.Matrix_Type, - ast.Call_Expr: + #partial switch _ in val.derived_expr { + case ^ast.Bad_Expr, + ^ast.Ident, + ^ast.Selector_Expr, + ^ast.Array_Type, + ^ast.Struct_Type, + ^ast.Union_Type, + ^ast.Enum_Type, + ^ast.Dynamic_Array_Type, + ^ast.Map_Type, + ^ast.Bit_Set_Type, + ^ast.Matrix_Type, + ^ast.Call_Expr: return true } return false @@ -2986,7 +2986,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr { ce.close = close.pos o := ast.unparen_expr(operand) - if se, ok := o.derived.(ast.Selector_Expr); ok && se.op.kind == .Arrow_Right { + if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right { sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end) sce.expr = o sce.call = ce @@ -3416,13 +3416,13 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { stmt := parse_stmt(p) if stmt != nil { - switch n in &stmt.derived { - case ast.Block_Stmt: n.label = label - case ast.If_Stmt: n.label = label - case ast.For_Stmt: n.label = label - case ast.Switch_Stmt: n.label = label - case ast.Type_Switch_Stmt: n.label = label - case ast.Range_Stmt: n.label = label + #partial switch n in stmt.derived_stmt { + case ^ast.Block_Stmt: n.label = label + case ^ast.If_Stmt: n.label = label + case ^ast.For_Stmt: n.label = label + case ^ast.Switch_Stmt: n.label = label + case ^ast.Type_Switch_Stmt: n.label = label + case ^ast.Range_Stmt: n.label = label } } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 023583bde..9eba29987 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -342,16 +342,16 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { return } - switch v in &decl.derived { - case Expr_Stmt: + #partial switch v in decl.derived_stmt { + case ^Expr_Stmt: move_line(p, decl.pos) visit_expr(p, v.expr) if p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case When_Stmt: + case ^When_Stmt: visit_stmt(p, cast(^Stmt)decl) - case Foreign_Import_Decl: + case ^Foreign_Import_Decl: if len(v.attributes) > 0 { sort.sort(sort_attribute(&v.attributes)) move_line(p, v.attributes[0].pos) @@ -370,7 +370,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { for path in v.fullpaths { push_ident_token(p, path, 0) } - case Foreign_Block_Decl: + case ^Foreign_Block_Decl: if len(v.attributes) > 0 { sort.sort(sort_attribute(&v.attributes)) move_line(p, v.attributes[0].pos) @@ -383,7 +383,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { visit_expr(p, v.foreign_library) visit_stmt(p, v.body) - case Import_Decl: + case ^Import_Decl: move_line(p, decl.pos) if v.name.text != "" { @@ -395,7 +395,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { push_ident_token(p, v.fullpath, 1) } - case Value_Decl: + case ^Value_Decl: if len(v.attributes) > 0 { sort.sort(sort_attribute(&v.attributes)) move_line(p, v.attributes[0].pos) @@ -446,10 +446,10 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { add_semicolon := true for value in v.values { - switch a in value.derived { - case Union_Type, Enum_Type, Struct_Type: + #partial switch a in value.derived { + case ^Union_Type, ^Enum_Type, ^Struct_Type: add_semicolon = false || called_in_stmt - case Proc_Lit: + case ^Proc_Lit: add_semicolon = false } } @@ -516,23 +516,34 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener return } - switch v in stmt.derived { - case Import_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - case Value_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - case Foreign_Import_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - case Foreign_Block_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - } - switch v in stmt.derived { - case Using_Stmt: + switch v in stmt.derived_stmt { + case ^Bad_Stmt: + case ^Bad_Decl: + case ^Package_Decl: + + case ^Empty_Stmt: + push_generic_token(p, .Semicolon, 0) + case ^Tag_Stmt: + push_generic_token(p, .Hash, 1) + push_generic_token(p, v.op.kind, 1, v.op.text) + visit_stmt(p, v.stmt) + + + case ^Import_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + case ^Value_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + case ^Foreign_Import_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + case ^Foreign_Block_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + + case ^Using_Stmt: move_line(p, v.pos) push_generic_token(p, .Using, 1) @@ -542,7 +553,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case Block_Stmt: + case ^Block_Stmt: move_line(p, v.pos) if v.pos.line == v.end.line { @@ -572,7 +583,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_end_brace(p, v.end) } } - case If_Stmt: + case ^If_Stmt: move_line(p, v.pos) if v.label != nil { @@ -595,7 +606,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener uses_do := false - if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { + if check_stmt, ok := v.body.derived.(^Block_Stmt); ok && check_stmt.uses_do { uses_do = true } @@ -626,7 +637,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.else_stmt) } - case Switch_Stmt: + case ^Switch_Stmt: move_line(p, v.pos) if v.label != nil { @@ -654,7 +665,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_expr(p, v.cond) visit_stmt(p, v.body) - case Case_Clause: + case ^Case_Clause: move_line(p, v.pos) if !p.config.indent_cases { @@ -678,7 +689,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if !p.config.indent_cases { indent(p) } - case Type_Switch_Stmt: + case ^Type_Switch_Stmt: move_line(p, v.pos) hint_current_line(p, {.Switch_Stmt}) @@ -696,7 +707,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.tag) visit_stmt(p, v.body) - case Assign_Stmt: + case ^Assign_Stmt: move_line(p, v.pos) hint_current_line(p, {.Assign}) @@ -710,13 +721,13 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if block_stmt && p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case Expr_Stmt: + case ^Expr_Stmt: move_line(p, v.pos) visit_expr(p, v.expr) if block_stmt && p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case For_Stmt: + case ^For_Stmt: // this should be simplified move_line(p, v.pos) @@ -753,7 +764,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.body) - case Inline_Range_Stmt: + case ^Inline_Range_Stmt: move_line(p, v.pos) if v.label != nil { @@ -779,7 +790,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_expr(p, v.expr) visit_stmt(p, v.body) - case Range_Stmt: + case ^Range_Stmt: move_line(p, v.pos) if v.label != nil { @@ -805,7 +816,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_expr(p, v.expr) visit_stmt(p, v.body) - case Return_Stmt: + case ^Return_Stmt: move_line(p, v.pos) push_generic_token(p, .Return, 1) @@ -817,7 +828,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if block_stmt && p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case Defer_Stmt: + case ^Defer_Stmt: move_line(p, v.pos) push_generic_token(p, .Defer, 0) @@ -826,7 +837,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case When_Stmt: + case ^When_Stmt: move_line(p, v.pos) push_generic_token(p, .When, 1) visit_expr(p, v.cond) @@ -846,7 +857,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.else_stmt) } - case Branch_Stmt: + case ^Branch_Stmt: move_line(p, v.pos) push_generic_token(p, v.tok.kind, 0) @@ -918,8 +929,15 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { set_source_position(p, expr.pos) - switch v in expr.derived { - case Inline_Asm_Expr: + switch v in expr.derived_expr { + case ^Bad_Expr: + + case ^Tag_Expr: + push_generic_token(p, .Hash, 1) + push_generic_token(p, v.op.kind, 1, v.op.text) + visit_expr(p, v.expr) + + case ^Inline_Asm_Expr: push_generic_token(p, v.tok.kind, 1, v.tok.text) push_generic_token(p, .Open_Paren, 1) @@ -936,42 +954,42 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Comma, 0) visit_expr(p, v.constraints_string) push_generic_token(p, .Close_Brace, 0) - case Undef: + case ^Undef: push_generic_token(p, .Undef, 1) - case Auto_Cast: + case ^Auto_Cast: push_generic_token(p, v.op.kind, 1) visit_expr(p, v.expr) - case Ternary_If_Expr: + case ^Ternary_If_Expr: visit_expr(p, v.x) push_generic_token(p, v.op1.kind, 1) visit_expr(p, v.cond) push_generic_token(p, v.op2.kind, 1) visit_expr(p, v.y) - case Ternary_When_Expr: + case ^Ternary_When_Expr: visit_expr(p, v.x) push_generic_token(p, v.op1.kind, 1) visit_expr(p, v.cond) push_generic_token(p, v.op2.kind, 1) visit_expr(p, v.y) - case Or_Else_Expr: + case ^Or_Else_Expr: visit_expr(p, v.x) push_generic_token(p, v.token.kind, 1) visit_expr(p, v.y) - case Or_Return_Expr: + case ^Or_Return_Expr: visit_expr(p, v.expr) push_generic_token(p, v.token.kind, 1) - case Selector_Call_Expr: + case ^Selector_Call_Expr: visit_expr(p, v.call.expr) push_generic_token(p, .Open_Paren, 1) visit_exprs(p, v.call.args, {.Add_Comma}) push_generic_token(p, .Close_Paren, 0) - case Ellipsis: + case ^Ellipsis: push_generic_token(p, .Ellipsis, 1) visit_expr(p, v.expr) - case Relative_Type: + case ^Relative_Type: visit_expr(p, v.tag) visit_expr(p, v.type) - case Slice_Expr: + case ^Slice_Expr: visit_expr(p, v.expr) push_generic_token(p, .Open_Bracket, 0) visit_expr(p, v.low) @@ -981,37 +999,37 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_expr(p, v.high) } push_generic_token(p, .Close_Bracket, 0) - case Ident: + case ^Ident: if .Enforce_Poly_Names in options { push_generic_token(p, .Dollar, 1) push_ident_token(p, v.name, 0) } else { push_ident_token(p, v.name, 1) } - case Deref_Expr: + case ^Deref_Expr: visit_expr(p, v.expr) push_generic_token(p, v.op.kind, 0) - case Type_Cast: + case ^Type_Cast: push_generic_token(p, v.tok.kind, 1) push_generic_token(p, .Open_Paren, 0) visit_expr(p, v.type) push_generic_token(p, .Close_Paren, 0) merge_next_token(p) visit_expr(p, v.expr) - case Basic_Directive: + case ^Basic_Directive: push_generic_token(p, v.tok.kind, 1) push_ident_token(p, v.name, 0) - case Distinct_Type: + case ^Distinct_Type: push_generic_token(p, .Distinct, 1) visit_expr(p, v.type) - case Dynamic_Array_Type: + case ^Dynamic_Array_Type: visit_expr(p, v.tag) push_generic_token(p, .Open_Bracket, 1) push_generic_token(p, .Dynamic, 0) push_generic_token(p, .Close_Bracket, 0) merge_next_token(p) visit_expr(p, v.elem) - case Bit_Set_Type: + case ^Bit_Set_Type: push_generic_token(p, .Bit_Set, 1) push_generic_token(p, .Open_Bracket, 0) @@ -1023,7 +1041,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } push_generic_token(p, .Close_Bracket, 0) - case Union_Type: + case ^Union_Type: push_generic_token(p, .Union, 1) push_poly_params(p, v.poly_params) @@ -1045,7 +1063,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_exprs(p, v.variants, {.Add_Comma, .Trailing}) visit_end_brace(p, v.end) } - case Enum_Type: + case ^Enum_Type: push_generic_token(p, .Enum, 1) hint_current_line(p, {.Enum}) @@ -1068,7 +1086,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } set_source_position(p, v.end) - case Struct_Type: + case ^Struct_Type: push_generic_token(p, .Struct, 1) hint_current_line(p, {.Struct}) @@ -1103,7 +1121,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } set_source_position(p, v.end) - case Proc_Lit: + case ^Proc_Lit: switch v.inlining { case .None: case .Inline: @@ -1112,7 +1130,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_ident_token(p, "#force_no_inline", 0) } - visit_proc_type(p, v.type^, true) + visit_proc_type(p, v.type, true) push_where_clauses(p, v.where_clauses) @@ -1122,16 +1140,16 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } else { push_generic_token(p, .Undef, 1) } - case Proc_Type: + case ^Proc_Type: visit_proc_type(p, v) - case Basic_Lit: + case ^Basic_Lit: push_generic_token(p, v.tok.kind, 1, v.tok.text) - case Binary_Expr: + case ^Binary_Expr: visit_binary_expr(p, v) - case Implicit_Selector_Expr: + case ^Implicit_Selector_Expr: push_generic_token(p, .Period, 1) push_ident_token(p, v.field.name, 0) - case Call_Expr: + case ^Call_Expr: visit_expr(p, v.expr) push_format_token(p, @@ -1146,27 +1164,34 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis) push_generic_token(p, .Close_Paren, 0) - case Typeid_Type: + case ^Typeid_Type: push_generic_token(p, .Typeid, 1) if v.specialization != nil { push_generic_token(p, .Quo, 0) visit_expr(p, v.specialization) } - case Selector_Expr: + case ^Selector_Expr: visit_expr(p, v.expr) push_generic_token(p, v.op.kind, 0) visit_expr(p, v.field) - case Paren_Expr: + case ^Paren_Expr: push_generic_token(p, .Open_Paren, 1) visit_expr(p, v.expr) push_generic_token(p, .Close_Paren, 0) - case Index_Expr: + case ^Index_Expr: visit_expr(p, v.expr) push_generic_token(p, .Open_Bracket, 0) visit_expr(p, v.index) push_generic_token(p, .Close_Bracket, 0) - case Proc_Group: + case ^Matrix_Index_Expr: + visit_expr(p, v.expr) + push_generic_token(p, .Open_Bracket, 0) + visit_expr(p, v.row_index) + push_generic_token(p, .Comma, 0) + visit_expr(p, v.column_index) + push_generic_token(p, .Close_Bracket, 0) + case ^Proc_Group: push_generic_token(p, v.tok.kind, 1) if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { @@ -1181,7 +1206,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Close_Brace, 0) } - case Comp_Lit: + case ^Comp_Lit: if v.type != nil { visit_expr(p, v.type) } @@ -1198,18 +1223,18 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Close_Brace, 0) } - case Unary_Expr: + case ^Unary_Expr: push_generic_token(p, v.op.kind, 1) merge_next_token(p) visit_expr(p, v.expr) - case Field_Value: + case ^Field_Value: visit_expr(p, v.field) push_generic_token(p, .Eq, 1) visit_expr(p, v.value) - case Type_Assertion: + case ^Type_Assertion: visit_expr(p, v.expr) - if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { + if unary, ok := v.type.derived.(^Unary_Expr); ok && unary.op.text == "?" { push_generic_token(p, .Period, 0) visit_expr(p, v.type) } else { @@ -1219,13 +1244,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Close_Paren, 0) } - case Pointer_Type: + case ^Pointer_Type: push_generic_token(p, .Pointer, 1) merge_next_token(p) visit_expr(p, v.elem) - case Implicit: + case ^Implicit: push_generic_token(p, v.tok.kind, 1) - case Poly_Type: + case ^Poly_Type: push_generic_token(p, .Dollar, 1) merge_next_token(p) visit_expr(p, v.type) @@ -1235,22 +1260,35 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { merge_next_token(p) visit_expr(p, v.specialization) } - case Array_Type: + case ^Array_Type: visit_expr(p, v.tag) push_generic_token(p, .Open_Bracket, 1) visit_expr(p, v.len) push_generic_token(p, .Close_Bracket, 0) merge_next_token(p) visit_expr(p, v.elem) - case Map_Type: + case ^Map_Type: push_generic_token(p, .Map, 1) push_generic_token(p, .Open_Bracket, 0) visit_expr(p, v.key) push_generic_token(p, .Close_Bracket, 0) merge_next_token(p) visit_expr(p, v.value) - case Helper_Type: + case ^Helper_Type: visit_expr(p, v.type) + case ^Multi_Pointer_Type: + push_generic_token(p, .Open_Bracket, 1) + push_generic_token(p, .Pointer, 0) + push_generic_token(p, .Close_Bracket, 0) + visit_expr(p, v.elem) + case ^Matrix_Type: + push_generic_token(p, .Matrix, 1) + push_generic_token(p, .Open_Bracket, 0) + visit_expr(p, v.row_count) + push_generic_token(p, .Comma, 0) + visit_expr(p, v.column_count) + push_generic_token(p, .Close_Bracket, 0) + visit_expr(p, v.elem) case: panic(fmt.aprint(expr.derived)) } @@ -1348,7 +1386,7 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := List_Opt } } -visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := false) { +visit_proc_type :: proc(p: ^Printer, proc_type: ^ast.Proc_Type, is_proc_lit := false) { if is_proc_lit { push_format_token(p, Format_Token { kind = .Proc, @@ -1392,7 +1430,7 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa } else if len(proc_type.results.list) == 1 { for name in proc_type.results.list[0].names { - if ident, ok := name.derived.(ast.Ident); ok { + if ident, ok := name.derived.(^ast.Ident); ok { if ident.name != "_" { use_parens = true } @@ -1410,19 +1448,19 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa } } -visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { +visit_binary_expr :: proc(p: ^Printer, binary: ^ast.Binary_Expr) { move_line(p, binary.left.pos) - if v, ok := binary.left.derived.(ast.Binary_Expr); ok { + if v, ok := binary.left.derived.(^ast.Binary_Expr); ok { visit_binary_expr(p, v) } else { visit_expr(p, binary.left) } either_implicit_selector := false - if _, ok := binary.left.derived.(ast.Implicit_Selector_Expr); ok { + if _, ok := binary.left.derived.(^ast.Implicit_Selector_Expr); ok { either_implicit_selector = true - } else if _, ok := binary.right.derived.(ast.Implicit_Selector_Expr); ok { + } else if _, ok := binary.right.derived.(^ast.Implicit_Selector_Expr); ok { either_implicit_selector = true } @@ -1439,7 +1477,7 @@ visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { move_line(p, binary.right.pos) - if v, ok := binary.right.derived.(ast.Binary_Expr); ok { + if v, ok := binary.right.derived.(^ast.Binary_Expr); ok { visit_binary_expr(p, v) } else { visit_expr(p, binary.right) @@ -1499,7 +1537,7 @@ visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := named := false for name in field.names { - if ident, ok := name.derived.(ast.Ident); ok { + if ident, ok := name.derived.(^ast.Ident); ok { //for some reason the parser uses _ to mean empty if ident.name != "_" || !remove_blank { named = true From 9cbf46e6898a6d60e8e8580aad93773c193ba22f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 7 Feb 2022 11:00:38 +0000 Subject: [PATCH 0113/1052] Fix constant multi pointer declarations through integers --- src/llvm_backend_const.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 5862a7add..8f17a1cfb 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -115,8 +115,8 @@ LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) { - GB_ASSERT(is_type_pointer(value.type)); - GB_ASSERT(is_type_pointer(t)); + GB_ASSERT(is_type_internally_pointer_like(value.type)); + GB_ASSERT(is_type_internally_pointer_like(t)); GB_ASSERT(lb_is_const(value)); lbValue res = {}; @@ -175,7 +175,7 @@ LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize } LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) { - GB_ASSERT(is_type_pointer(data.type)); + GB_ASSERT(is_type_pointer(data.type) || is_type_multi_pointer(data.type)); GB_ASSERT(are_types_identical(len.type, t_int)); LLVMValueRef vals[2] = { data.value, @@ -568,7 +568,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } case ExactValue_Integer: - if (is_type_pointer(type)) { + if (is_type_pointer(type) || is_type_multi_pointer(type)) { LLVMTypeRef t = lb_type(m, original_type); LLVMValueRef i = lb_big_int_to_llvm(m, t_uintptr, &value.value_integer); res.value = LLVMConstIntToPtr(i, t); From 3c2ed3bb69df24ba162e5f2ea8f61ee3f7fd8e2f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 7 Feb 2022 11:37:13 +0000 Subject: [PATCH 0114/1052] Correct `//+private file` bug --- src/checker.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index b62ef7c4c..7fb4fdb29 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3477,11 +3477,11 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (entity_visibility_kind == EntityVisiblity_Public && (c->scope->flags&ScopeFlag_File) && c->scope->file) { - if (c->scope->file->flags & AstFile_IsPrivatePkg) { - entity_visibility_kind = EntityVisiblity_PrivateToPackage; - } else if (c->scope->file->flags & AstFile_IsPrivateFile) { + if (c->scope->file->flags & AstFile_IsPrivateFile) { entity_visibility_kind = EntityVisiblity_PrivateToFile; - } + } else if (c->scope->file->flags & AstFile_IsPrivatePkg) { + entity_visibility_kind = EntityVisiblity_PrivateToPackage; + } } if (entity_visibility_kind != EntityVisiblity_Public && !(c->scope->flags&ScopeFlag_File)) { From 817bc7434dfd0ebfeb1310c22741b9d66af67ac2 Mon Sep 17 00:00:00 2001 From: NoahR02 Date: Tue, 8 Feb 2022 06:16:10 -0500 Subject: [PATCH 0115/1052] Ports OpenSimplex2 from https://github.com/KdotJPG/OpenSimplex2 to Odin. Adds tests for the noise procedures. --- core/math/noise/internal.odin | 734 ++++++++++++++++++ core/math/noise/opensimplex2.odin | 171 ++++ tests/core/Makefile | 7 +- tests/core/build.bat | 7 +- .../core/math/noise/test_core_math_noise.odin | 153 ++++ 5 files changed, 1069 insertions(+), 3 deletions(-) create mode 100644 core/math/noise/internal.odin create mode 100644 core/math/noise/opensimplex2.odin create mode 100644 tests/core/math/noise/test_core_math_noise.odin diff --git a/core/math/noise/internal.odin b/core/math/noise/internal.odin new file mode 100644 index 000000000..5837f9235 --- /dev/null +++ b/core/math/noise/internal.odin @@ -0,0 +1,734 @@ +/* + OpenSimplex2 noise implementation. + + Ported from https://github.com/KdotJPG/OpenSimplex2. + Copyright 2022 Yuki2 (https://github.com/NoahR02) +*/ +//+private +package math_noise + +/* + Private implementation details follow. +*/ + +PRIME_X :: i64(0x5205402B9270C86F) +PRIME_Y :: i64(0x598CD327003817B5) +PRIME_Z :: i64(0x5BCC226E9FA0BACB) +PRIME_W :: i64(0x56CC5227E58F554B) + +HASH_MULTIPLIER :: i64(0x53A3F72DEEC546F5) +SEED_FLIP_3D :: i64(-0x52D547B2E96ED629) +SEED_OFFSET_4D :: i64(0xE83DC3E0DA7164D) + +ROOT_2_OVER_2 :: f64(0.7071067811865476) +SKEW_2D :: f64(0.366025403784439) +UNSKEW_2D :: f64(-0.21132486540518713) +ROOT_3_OVER_3 :: f64(0.577350269189626) + +FALLBACK_ROTATE_3D :: f64(2.0) / f64(3.0) +ROTATE_3D_ORTHOGONALIZER :: f64(UNSKEW_2D) + +SKEW_4D :: f32(0hbe0d8369) +UNSKEW_4D :: f32(0.309016994374947) +LATTICE_STEP_4D :: f32(0.2) + +N_GRADS_2D_EXPONENT :: 7 +N_GRADS_3D_EXPONENT :: 8 +N_GRADS_4D_EXPONENT :: 9 +N_GRADS_2D :: 1 << N_GRADS_2D_EXPONENT +N_GRADS_3D :: 1 << N_GRADS_3D_EXPONENT +N_GRADS_4D :: 1 << N_GRADS_4D_EXPONENT + +NORMALIZER_2D :: f64(0.01001634121365712) +NORMALIZER_3D :: f64(0.07969837668935331) +NORMALIZER_4D :: f64(0.0220065933241897) +RSQUARED_2D :: f32(0.5) +RSQUARED_3D :: f32(0.6) +RSQUARED_4D :: f32(0.6) + +GRADIENTS_2D := [N_GRADS_2D * 2]f32{ + 0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975, + 0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975, + 0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d, + 0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a, + 0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d, + 0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a, + 0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975, + 0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975, + 0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d, + 0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a, + 0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d, + 0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a, + 0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975, + 0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975, + 0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d, + 0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a, + 0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d, + 0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a, + 0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975, + 0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975, + 0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d, + 0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a, + 0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d, + 0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a, + 0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975, + 0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975, + 0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d, + 0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a, + 0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d, + 0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a, + 0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975, + 0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975, +} + +GRADIENTS_3D := [N_GRADS_3D * 4]f32{ + 0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, + 0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, + 0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000, + 0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, + 0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000, + 0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, + 0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000, + 0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000, + 0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000, + 0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, + 0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, + 0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000, + 0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, + 0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000, + 0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, + 0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000, + 0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000, + 0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000, + 0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, + 0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, + 0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000, + 0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, + 0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000, + 0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, + 0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000, + 0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000, + 0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000, + 0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, + 0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, + 0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000, + 0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, + 0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000, + 0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, + 0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000, + 0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000, + 0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000, + 0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, + 0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, + 0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000, + 0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000, + 0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, + 0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000, + 0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, + 0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000, + 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000, + 0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000, + 0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000, + 0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000, + 0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000, + 0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000, + 0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000, + 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, + 0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, + 0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, + 0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, +} + +GRADIENTS_4D := [N_GRADS_4D * 4]f32{ + 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966, + 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418, + 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c, + 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507, + 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d, + 0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf, + 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0, + 0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00, + 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d, + 0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf, + 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0, + 0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00, + 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d, + 0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf, + 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, + 0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00, + 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, + 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, + 0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, + 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, + 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, + 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, + 0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d, + 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564, + 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, + 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, + 0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d, + 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564, + 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, + 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, + 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252, + 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c, + 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966, + 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418, + 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c, + 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507, + 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966, + 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418, + 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c, + 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507, + 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d, + 0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf, + 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0, + 0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00, + 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c, + 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5, + 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966, + 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716, + 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d, + 0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf, + 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0, + 0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00, + 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c, + 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5, + 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966, + 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716, + 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d, + 0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf, + 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, + 0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00, + 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c, + 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5, + 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, + 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716, + 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252, + 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a, + 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, + 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18, + 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d, + 0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee, + 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, + 0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670, + 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d, + 0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee, + 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, + 0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670, + 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, + 0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee, + 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee, + 0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670, + 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966, + 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418, + 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c, + 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507, + 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d, + 0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf, + 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0, + 0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00, + 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d, + 0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf, + 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0, + 0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00, + 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d, + 0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf, + 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, + 0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00, + 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, + 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, + 0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, + 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, + 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, + 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, + 0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d, + 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564, + 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, + 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, + 0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d, + 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564, + 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, + 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, + 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252, + 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c, + 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966, + 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418, + 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c, + 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507, + 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966, + 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418, + 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c, + 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507, + 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d, + 0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf, + 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0, + 0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00, + 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c, + 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5, + 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966, + 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716, + 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d, + 0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf, + 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0, + 0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00, + 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c, + 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5, + 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966, + 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716, + 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d, + 0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf, + 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, + 0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00, + 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c, + 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5, + 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, + 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716, + 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252, + 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a, + 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, + 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18, + 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d, + 0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee, + 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, + 0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670, + 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d, + 0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee, + 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, + 0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670, + 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, + 0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee, + 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee, + 0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670, + 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966, + 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418, + 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c, + 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507, + 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d, + 0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf, + 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0, + 0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00, + 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d, + 0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf, + 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0, + 0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00, + 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d, + 0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf, + 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, + 0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00, + 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, + 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, + 0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, + 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, + 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, + 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, + 0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d, + 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564, + 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, + 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, + 0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d, + 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564, + 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, + 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, + 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252, + 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c, + 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966, + 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418, + 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c, + 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507, + 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966, + 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418, + 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c, + 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507, + 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d, + 0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf, + 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0, + 0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00, + 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c, + 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5, + 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966, + 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716, + 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d, + 0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf, + 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0, + 0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00, + 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c, + 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5, + 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966, + 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716, + 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d, + 0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf, + 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, + 0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00, + 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c, + 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5, + 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, + 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716, + 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252, + 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a, + 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, + 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18, + 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d, + 0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee, + 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, + 0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670, + 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d, + 0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee, + 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, + 0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670, + 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, + 0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee, + 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee, + 0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670, + 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966, + 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418, + 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c, + 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507, + 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d, + 0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf, + 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0, + 0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00, + 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d, + 0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf, + 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0, + 0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00, + 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d, + 0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf, + 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, + 0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00, +} + +/* + 2D Simplex noise base. +*/ +_internal_noise_2d_unskewed_base :: proc(seed: i64, coord: Vec2) -> (value: f32) { + // Get base points and offsets. + base := [2]i64{fast_floor(coord.x), fast_floor(coord.y)} + i := [2]f32{f32(coord.x - f64(base.x)), f32(coord.y - f64(base.y))} + + // Prime pre-multiplication for hash. + bp := base * [2]i64{PRIME_X, PRIME_Y} + + // Unskew. + t := f32(i.x + i.y) * f32(UNSKEW_2D) + d0 := i + [2]f32{t, t} + + // First vertex. + a0 := RSQUARED_2D - d0.x * d0.x - d0.y * d0.y + if a0 > 0 { + value = (a0 * a0) * (a0 * a0) * grad(seed, [2]i64{bp.x, bp.y}, d0) + } + + // Second vertex. + a1 := f32(2 * (1 + 2 * UNSKEW_2D) * (1 / UNSKEW_2D + 2)) * t + f32(-2 * (1 + 2 * UNSKEW_2D) * (1 + 2 * UNSKEW_2D)) + a0 + if a1 > 0 { + d1 := d0 - [2]f32{f32(1 + 2 * UNSKEW_2D), f32(1 + 2 * UNSKEW_2D)} + value += (a1 * a1) * (a1 * a1) * grad(seed, [2]i64{bp.x + PRIME_X, bp.y + PRIME_Y}, d1) + } + + // Third vertex. + if d0.y > d0.x { + d2 := d0 - [2]f32{f32(UNSKEW_2D), f32(UNSKEW_2D + 1)} + a2 := RSQUARED_2D - d2.x * d2.x - d2.y * d2.y + if(a2 > 0) { + value += (a2 * a2) * (a2 * a2) * grad(seed, [2]i64{bp.x, bp.y + PRIME_Y}, d2) + } + } else { + d2 := d0 - [2]f32{f32(UNSKEW_2D + 1), f32(UNSKEW_2D)} + a2 := RSQUARED_2D - d2.x * d2.x - d2.y * d2.y + if(a2 > 0) { + value += (a2 * a2) * (a2 * a2) * grad(seed, [2]i64{bp.x + PRIME_X, bp.y}, d2) + } + } + + return +} + + +/* + Generate overlapping cubic lattices for 3D OpenSimplex2 noise. +*/ +_internal_noise_3d_unrotated_base :: proc(seed: i64, coord: Vec3) -> (value: f32) { + seed := seed + // Get base points and offsets. + // xr, yr, zr := coord.x, coord.y, coord.z + + rb := [3]i64{fast_round(coord.x), fast_round(coord.y), fast_round(coord.z)} + ri := [3]f32{f32(coord.x - f64(rb.x)), f32(coord.y - f64(rb.y)), f32(coord.z - f64(rb.z))} + + // -1 if positive, 1 if negative. + i_sign := [3]i64{i64(-1.0 - ri.x) | 1, i64(-1.0 - ri.y) | 1, i64(-1.0 - ri.z) | 1} + f_sign := [3]f32{f32(i_sign.x), f32(i_sign.y), f32(i_sign.z)} + + // Compute absolute values, using the above as a shortcut. This was faster in my tests for some reason. + a0 := f_sign * -ri + + // Prime pre-multiplication for hash. + rbp := rb * [3]i64{PRIME_X, PRIME_Y, PRIME_Z} + + // Loop: Pick an edge on each lattice copy. + a := (RSQUARED_3D - ri.x * ri.x) - (ri.y * ri.y + ri.z * ri.z) + + l := 0 + for { + defer l += 1 + + // Closest point on cube. + if a > 0 { + a2 := a * a; a4 := a2 * a2 + value += a4 * grad(seed, rbp, ri) + } + + // Second-closest point. + if a0.x >= a0.y && a0.x >= a0.z { + b := a + a0.x + a0.x + if b > 1 { + b -= 1 + b2 := b * b; b4 := b2 * b2 + value += b4 * grad(seed, [3]i64{rbp.x - i_sign.x * PRIME_X, rbp.y, rbp.z}, [3]f32{ri.x + f_sign.x, ri.y, ri.z}) + } + } else if a0.y > a0.x && a0.y >= a0.z { + b := a + a0.y + a0.y + if b > 1 { + b -= 1 + b2 := b * b; b4 := b2 * b2 + value += b4 * grad(seed, [3]i64{rbp.x, rbp.y - i_sign.y * PRIME_Y, rbp.z}, [3]f32{ri.x, ri.y + f_sign.y, ri.z}) + } + } else { + b := a + a0.z + a0.z + if b > 1 { + b -= 1 + b2 := b * b; b4 := b2 * b2 + value += b4 * grad(seed, [3]i64{rbp.x, rbp.y, rbp.z - i_sign.z * PRIME_Z}, [3]f32{ri.x, ri.y, ri.z + f_sign.z}) + } + } + + // Break from loop if we're done, skipping updates below. + if l == 1 { + break + } + + // Update absolute value. + a0 = 0.5 - a0 + + // Update relative coordinate. + ri = a0 * f_sign + + // Update falloff. + a += (0.75 - a0.x) - (a0.y + a0.z) + + // Update prime for hash. + rbp += [3]i64{i_sign.x >> 1, i_sign.y >> 1, i_sign.z >> 1} & {PRIME_X, PRIME_Y, PRIME_Z} + + // Update the reverse sign indicators. + i_sign = -i_sign + f_sign = -f_sign + + // And finally update the seed for the other lattice copy. + seed ~= SEED_FLIP_3D + } + + return value +} + +/* + 4D OpenSimplex2 noise base. +*/ +_internal_noise_4d_unskewed_base :: proc(seed: i64, coord: Vec4) -> (value: f32) { + seed := seed + + // Get base points and offsets + base := [4]i64{fast_floor(coord.x), fast_floor(coord.y), fast_floor(coord.z), fast_floor(coord.w)} + si := [4]f32{f32(coord.x - f64(base.x)), f32(coord.y - f64(base.y)), f32(coord.z - f64(base.z)), f32(coord.w - f64(base.w))} + + // Determine which lattice we can be confident has a contributing point its corresponding cell's base simplex. + // We only look at the spaces between the diagonal planes. This proved effective in all of my tests. + si_sum := (si.x + si.y) + (si.z + si.w) + starting_lattice := i64(si_sum * 1.25) + + // Offset for seed based on first lattice copy. + seed += starting_lattice * SEED_OFFSET_4D + + // Offset for lattice point relative positions (skewed) + starting_lattice_offset := f32(starting_lattice) * -LATTICE_STEP_4D + si += starting_lattice_offset + + // Prep for vertex contributions. + ssi := (si_sum + starting_lattice_offset * 4) * UNSKEW_4D + + // Prime pre-multiplication for hash. + svp := base * [4]i64{PRIME_X, PRIME_Y, PRIME_Z, PRIME_W} + + // Five points to add, total, from five copies of the A4 lattice. + for i : i64 = 0; ; i += 1 { + + // Next point is the closest vertex on the 4-simplex whose base vertex is the aforementioned vertex. + score := 1.0 + ssi * (-1.0 / UNSKEW_4D) // Seems slightly faster than 1.0-xsi-ysi-zsi-wsi + if si.x >= si.x && si.x >= si.z && si.x >= si.w && si.x >= score { + svp.x += PRIME_X + si.x -= 1 + ssi -= UNSKEW_4D + } + else if si.y > si.x && si.y >= si.z && si.y >= si.w && si.y >= score { + svp.y += PRIME_Y + si.y -= 1 + ssi -= UNSKEW_4D + } + else if si.z > si.x && si.z > si.y && si.z >= si.w && si.z >= score { + svp.z += PRIME_Z + si.z -= 1 + ssi -= UNSKEW_4D + } + else if si.w > si.x && si.w > si.y && si.w > si.z && si.w >= score { + svp.w += PRIME_W + si.w -= 1 + ssi -= UNSKEW_4D + } + + // gradient contribution with falloff. + d := si + ssi + a := (d.x * d.x + d.y * d.y) + (d.z * d.z + d.w * d.w) + + if a < RSQUARED_4D { + a -= RSQUARED_4D + a *= a; a4 := a * a + value += a4 * grad(seed, svp, d) + } + + // Break from loop if we're done, skipping updates below. + if i == 4 { + break + } + + // Update for next lattice copy shifted down by <-0.2, -0.2, -0.2, -0.2>. + si += LATTICE_STEP_4D + ssi += LATTICE_STEP_4D * 4 * UNSKEW_4D + seed -= SEED_OFFSET_4D + + // Because we don't always start on the same lattice copy, there's a special reset case. + if i == starting_lattice { + svp -= {PRIME_X, PRIME_Y, PRIME_Z, PRIME_W} + seed += SEED_OFFSET_4D * 5 + } + } + return +} + +/* + Utility functions +*/ +@(optimization_mode="speed") +grad_2d :: proc(seed: i64, svp: [2]i64, delta: [2]f32) -> (value: f32) { + hash := seed ~ svp.x ~ svp.y + hash *= HASH_MULTIPLIER + hash ~= hash >> (64 - N_GRADS_2D_EXPONENT + 1) + + gi := hash & ((N_GRADS_2D - 1) << 1) + return GRADIENTS_2D[gi] * delta.x + GRADIENTS_2D[gi | 1] * delta.y +} + +@(optimization_mode="speed") +grad_3d :: proc(seed: i64, rvp: [3]i64, delta: [3]f32) -> (value: f32) { + hash := (seed ~ rvp.x) ~ (rvp.y ~ rvp.z) + hash *= HASH_MULTIPLIER + hash ~= hash >> (64 - N_GRADS_3D_EXPONENT + 2) + + gi := hash & ((N_GRADS_3D - 1) << 2) + return GRADIENTS_3D[gi] * delta.x + GRADIENTS_3D[gi | 1] * delta.y + GRADIENTS_3D[gi | 2] * delta.z +} + +@(optimization_mode="speed") +grad_4d :: proc(seed: i64, svp: [4]i64, delta: [4]f32) -> (value: f32) { + hash := seed ~ (svp.x ~ svp.y) ~ (svp.z ~ svp.w) + hash *= HASH_MULTIPLIER + hash ~= hash >> (64 - N_GRADS_4D_EXPONENT + 2) + + gi := hash & ((N_GRADS_4D - 1) << 2) + return (GRADIENTS_4D[gi] * delta.x + GRADIENTS_4D[gi | 1] * delta.y) + (GRADIENTS_4D[gi | 2] * delta.z + GRADIENTS_4D[gi | 3] * delta.w) +} + +grad :: proc {grad_2d, grad_3d, grad_4d} + +@(optimization_mode="speed") +fast_floor :: proc(x: f64) -> (floored: i64) { + xi := i64(x) + return x < f64(xi) ? xi - 1 : xi +} + +@(optimization_mode="speed") +fast_round :: proc(x: f64) -> (rounded: i64) { + return x < 0 ? i64(x - 0.5) : i64(x + 0.5) +} \ No newline at end of file diff --git a/core/math/noise/opensimplex2.odin b/core/math/noise/opensimplex2.odin new file mode 100644 index 000000000..d90dafdf5 --- /dev/null +++ b/core/math/noise/opensimplex2.odin @@ -0,0 +1,171 @@ +/* + OpenSimplex2 noise implementation. + + Ported from https://github.com/KdotJPG/OpenSimplex2. + Copyright 2022 Yuki2 (https://github.com/NoahR02) +*/ +package math_noise + +/* + Input coordinate vectors +*/ +Vec2 :: [2]f64 +Vec3 :: [3]f64 +Vec4 :: [4]f64 + +/* + Noise Evaluators +*/ + +/* + 2D Simplex noise, standard lattice orientation. +*/ +noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) { + // Get points for A2* lattice + skew := SKEW_2D * (coord.x + coord.y) + skewed := coord + skew + + return _internal_noise_2d_unskewed_base(seed, skewed) +} + +/* + 2D Simplex noise, with Y pointing down the main diagonal. + Might be better for a 2D sandbox style game, where Y is vertical. + Probably slightly less optimal for heightmaps or continent maps, + unless your map is centered around an equator. It's a subtle + difference, but the option is here to make it an easy choice. +*/ +noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) { + // Skew transform and rotation baked into one. + xx := coord.x * ROOT_2_OVER_2 + yy := coord.y * (ROOT_2_OVER_2 * (1 + 2 * SKEW_2D)) + return _internal_noise_2d_unskewed_base(seed, Vec2{yy + xx, yy - xx}) +} + + +/* + 3D OpenSimplex2 noise, with better visual isotropy in (X, Y). + Recommended for 3D terrain and time-varied animations. + The Z coordinate should always be the "different" coordinate in whatever your use case is. + If Y is vertical in world coordinates, call `noise_3d_improve_xz(x, z, Y)` or use `noise_3d_xz_before_y`. + If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, y, Z)`. + For a time varied animation, call `noise_3d_improve_xz(x, y, T)`. +*/ +noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) { + /* + Re-orient the cubic lattices without skewing, so Z points up the main lattice diagonal, + and the planes formed by XY are moved far out of alignment with the cube faces. + Orthonormal rotation. Not a skew transform. + */ + xy := coord.x + coord.y + s2 := xy * ROTATE_3D_ORTHOGONALIZER + zz := coord.z * ROOT_3_OVER_3 + + r := Vec3{coord.x + s2 + zz, coord.y + s2 + zz, xy * -ROOT_3_OVER_3 + zz} + + // Evaluate both lattices to form a BCC lattice. + return _internal_noise_3d_unrotated_base(seed, r) +} + +/* + 3D OpenSimplex2 noise, with better visual isotropy in (X, Z). + Recommended for 3D terrain and time-varied animations. + The Y coordinate should always be the "different" coordinate in whatever your use case is. + If Y is vertical in world coordinates, call `noise_3d_improve_xz(x, Y, z)`. + If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, Z, y)` or use `noise_3d_improve_xy`. + For a time varied animation, call `noise_3d_improve_xz(x, T, y)` or use `noise_3d_improve_xy`. +*/ +noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) { + /* + Re-orient the cubic lattices without skewing, so Y points up the main lattice diagonal, + and the planes formed by XZ are moved far out of alignment with the cube faces. + Orthonormal rotation. Not a skew transform. + */ + xz := coord.x + coord.z + s2 := xz * ROTATE_3D_ORTHOGONALIZER + yy := coord.y * ROOT_3_OVER_3 + + r := Vec3{coord.x + s2 + yy, xz * -ROOT_3_OVER_3 + yy, coord.z + s2 + yy} + + // Evaluate both lattices to form a BCC lattice. + return _internal_noise_3d_unrotated_base(seed, r) +} + +/* + 3D OpenSimplex2 noise, fallback rotation option + Use `noise_3d_improve_xy` or `noise_3d_improve_xz` instead, wherever appropriate. + They have less diagonal bias. This function's best use is as a fallback. +*/ +noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) { + /* + Re-orient the cubic lattices via rotation, to produce a familiar look. + Orthonormal rotation. Not a skew transform. + */ + bias := FALLBACK_ROTATE_3D * (coord.x + coord.y + coord.z) + biased := bias - coord + // Evaluate both lattices to form a BCC lattice. + return _internal_noise_3d_unrotated_base(seed, biased) +} + + +/* + 4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_improve_xy` + and W for an extra degree of freedom. W repeats eventually. + Recommended for time-varied animations which texture a 3D object (W=time) + in a space where Z is vertical. +*/ +noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32) { + xy := coord.x + coord.y + s2 := xy * -0.21132486540518699998 + zz := coord.z * 0.28867513459481294226 + ww := coord.w * 0.2236067977499788 + + xr, yr : f64 = coord.x + (zz + ww + s2), coord.y + (zz + ww + s2) + zr : f64 = xy * -0.57735026918962599998 + (zz + ww) + wr : f64 = coord.z * -0.866025403784439 + ww + + return _internal_noise_4d_unskewed_base(seed, Vec4{xr, yr, zr, wr}) +} + +/* + 4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_improve_xz` + and W for an extra degree of freedom. W repeats eventually. + Recommended for time-varied animations which texture a 3D object (W=time) + in a space where Y is vertical. +*/ +noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32) { + xz := coord.x + coord.z + s2 := xz * -0.21132486540518699998 + yy := coord.y * 0.28867513459481294226 + ww := coord.w * 0.2236067977499788 + + xr, zr : f64 = coord.x + (yy + ww + s2), coord.z + (yy + ww + s2) + yr := xz * -0.57735026918962599998 + (yy + ww) + wr := coord.y * -0.866025403784439 + ww + + return _internal_noise_4d_unskewed_base(seed, Vec4{xr, yr, zr, wr}) +} + +/* + 4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_fallback` + and W for an extra degree of freedom. W repeats eventually. + Recommended for time-varied animations which texture a 3D object (W=time) + where there isn't a clear distinction between horizontal and vertical +*/ +noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) { + xyz := coord.x + coord.y + coord.z + ww := coord.w * 0.2236067977499788 + s2 := xyz * -0.16666666666666666 + ww + + skewed := Vec4{coord.x + s2, coord.y + s2, coord.z + s2, -0.5 * xyz + ww} + return _internal_noise_4d_unskewed_base(seed, skewed) +} + +/* + 4D OpenSimplex2 noise, fallback lattice orientation. +*/ +noise_4d_fallback :: proc(seed: i64, coord: Vec4) -> (value: f32) { + // Get points for A4 lattice + skew := f64(SKEW_4D) * (coord.x + coord.y + coord.z + coord.w) + return _internal_noise_4d_unskewed_base(seed, coord + skew) +} \ No newline at end of file diff --git a/tests/core/Makefile b/tests/core/Makefile index 0f0ffe4d6..1c2cee6bd 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,7 +1,7 @@ ODIN=../../odin PYTHON=$(shell which python3) -all: download_test_assets image_test compress_test strings_test hash_test crypto_test +all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test download_test_assets: $(PYTHON) download_assets.py @@ -19,4 +19,7 @@ hash_test: $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check crypto_test: - $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check \ No newline at end of file + $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check + +noise_test: + $(ODIN) run math/noise -out=test_noise \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index 176b7f175..6af39e688 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -35,4 +35,9 @@ echo --- echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding %COMMON% \ No newline at end of file +%PATH_TO_ODIN% run encoding %COMMON% + +echo --- +echo Running core:math/noise tests +echo --- +%PATH_TO_ODIN% run math/noise %COMMON% \ No newline at end of file diff --git a/tests/core/math/noise/test_core_math_noise.odin b/tests/core/math/noise/test_core_math_noise.odin new file mode 100644 index 000000000..a3ac1b955 --- /dev/null +++ b/tests/core/math/noise/test_core_math_noise.odin @@ -0,0 +1,153 @@ +package test_core_math_noise + +import "core:testing" +import "core:math/noise" +import "core:fmt" + +TEST_count := 0 +TEST_fail := 0 + +V2 :: noise.Vec2 +V3 :: noise.Vec3 +V4 :: noise.Vec4 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + noise_test(&t) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +Test_Vector :: struct { + seed: i64, + coord: union {V2, V3, V4}, + expected: f32, + + test_proc: union { + proc(_: i64, _: V2) -> f32, + proc(_: i64, _: V3) -> f32, + proc(_: i64, _: V4) -> f32, + }, +} + +SEED_1 :: 2324223232 +SEED_2 :: 932466901 +SEED_3 :: 9321 + +COORD_1 :: V4{ 242.0, 3433.0, 920.0, 222312.0} +COORD_2 :: V4{ 590.0, 9411.0, 5201.0, 942124256.0} +COORD_3 :: V4{12090.0, 19411.0, 81950901.0, 4224219.0} + +Noise_Tests := []Test_Vector{ + /* + `noise_2d` tests. + */ + {SEED_1, COORD_1.xy, 0.25010583, noise.noise_2d}, + {SEED_2, COORD_2.xy, -0.92513955, noise.noise_2d}, + {SEED_3, COORD_3.xy, 0.67327416, noise.noise_2d}, + + /* + `noise_2d_improve_x` tests. + */ + {SEED_1, COORD_1.xy, 0.17074019, noise.noise_2d_improve_x}, + {SEED_2, COORD_2.xy, 0.72330487, noise.noise_2d_improve_x}, + {SEED_3, COORD_3.xy, -0.032076947, noise.noise_2d_improve_x}, + + /* + `noise_3d_improve_xy` tests. + */ + {SEED_1, COORD_1.xyz, 0.14819577, noise.noise_3d_improve_xy}, + {SEED_2, COORD_2.xyz, -0.065345764, noise.noise_3d_improve_xy}, + {SEED_3, COORD_3.xyz, -0.37761918, noise.noise_3d_improve_xy}, + + /* + `noise_3d_improve_xz` tests. + */ + {SEED_1, COORD_1.xyz, -0.50075006, noise.noise_3d_improve_xz}, + {SEED_2, COORD_2.xyz, -0.36039603, noise.noise_3d_improve_xz}, + {SEED_3, COORD_3.xyz, -0.3479203, noise.noise_3d_improve_xz}, + + /* + `noise_3d_fallback` tests. + */ + {SEED_1, COORD_1.xyz, 0.6557345, noise.noise_3d_fallback}, + {SEED_2, COORD_2.xyz, 0.55452216, noise.noise_3d_fallback}, + {SEED_3, COORD_3.xyz, -0.26408964, noise.noise_3d_fallback}, + + /* + `noise_3d_fallback` tests. + */ + {SEED_1, COORD_1.xyz, 0.6557345, noise.noise_3d_fallback}, + {SEED_2, COORD_2.xyz, 0.55452216, noise.noise_3d_fallback}, + {SEED_3, COORD_3.xyz, -0.26408964, noise.noise_3d_fallback}, + + /* + `noise_4d_improve_xyz_improve_xy` tests. + */ + {SEED_1, COORD_1, 0.44929826, noise.noise_4d_improve_xyz_improve_xy}, + {SEED_2, COORD_2, -0.13270882, noise.noise_4d_improve_xyz_improve_xy}, + {SEED_3, COORD_3, 0.10298563, noise.noise_4d_improve_xyz_improve_xy}, + + /* + `noise_4d_improve_xyz_improve_xz` tests. + */ + {SEED_1, COORD_1, -0.078514606, noise.noise_4d_improve_xyz_improve_xz}, + {SEED_2, COORD_2, -0.032157656, noise.noise_4d_improve_xyz_improve_xz}, + {SEED_3, COORD_3, -0.38607058, noise.noise_4d_improve_xyz_improve_xz}, + + /* + `noise_4d_improve_xyz` tests. + */ + {SEED_1, COORD_1, -0.4442258, noise.noise_4d_improve_xyz}, + {SEED_2, COORD_2, 0.36822623, noise.noise_4d_improve_xyz}, + {SEED_3, COORD_3, 0.22628775, noise.noise_4d_improve_xyz}, + + /* + `noise_4d_fallback` tests. + */ + {SEED_1, COORD_1, -0.14233987, noise.noise_4d_fallback}, + {SEED_2, COORD_2, 0.1354035, noise.noise_4d_fallback}, + {SEED_3, COORD_3, 0.14565045, noise.noise_4d_fallback}, + + // TODO: Output according to C# - Figure out which of these two is right (and why). + // {SEED_1, COORD_1, -0.14233987, noise.noise_4d_fallback}, + // {SEED_2, COORD_2, 0.1354035, noise.noise_4d_fallback}, + // {SEED_3, COORD_3, 0.14565045, noise.noise_4d_fallback}, +} + +noise_test :: proc(t: ^testing.T) { + for test in Noise_Tests { + output: f32 + + switch coord in test.coord { + case V2: + output = test.test_proc.(proc(_: i64, _: V2) -> f32)(test.seed, test.coord.(V2)) + case V3: + output = test.test_proc.(proc(_: i64, _: V3) -> f32)(test.seed, test.coord.(V3)) + case V4: + output = test.test_proc.(proc(_: i64, _: V4) -> f32)(test.seed, test.coord.(V4)) + } + + error := fmt.tprintf("Seed %v, Coord: %v, Expected: %3.8f. Got %3.8f", test.seed, test.coord, test.expected, output) + expect(t, test.expected == output, error) + } +} \ No newline at end of file From accb35506f5c0b66fa25fb7ccec7e97a9da61d8e Mon Sep 17 00:00:00 2001 From: NoahR02 Date: Tue, 8 Feb 2022 06:25:07 -0500 Subject: [PATCH 0116/1052] Ports OpenSimplex2 from https://github.com/KdotJPG/OpenSimplex2 to Odin. Adds tests for the noise procedures. --- tests/core/math/noise/test_core_math_noise.odin | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/core/math/noise/test_core_math_noise.odin b/tests/core/math/noise/test_core_math_noise.odin index a3ac1b955..c3a3e4228 100644 --- a/tests/core/math/noise/test_core_math_noise.odin +++ b/tests/core/math/noise/test_core_math_noise.odin @@ -128,10 +128,6 @@ Noise_Tests := []Test_Vector{ {SEED_2, COORD_2, 0.1354035, noise.noise_4d_fallback}, {SEED_3, COORD_3, 0.14565045, noise.noise_4d_fallback}, - // TODO: Output according to C# - Figure out which of these two is right (and why). - // {SEED_1, COORD_1, -0.14233987, noise.noise_4d_fallback}, - // {SEED_2, COORD_2, 0.1354035, noise.noise_4d_fallback}, - // {SEED_3, COORD_3, 0.14565045, noise.noise_4d_fallback}, } noise_test :: proc(t: ^testing.T) { From 30bb2382aa0c7a9d6407c0b28258cd9fd00c560d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Feb 2022 11:48:59 +0000 Subject: [PATCH 0117/1052] Correct simple boolean intrinsics --- src/check_builtin.cpp | 5 +++-- src/checker_builtin_procs.hpp | 4 ---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d3a3103b1..1fb3d6037 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3344,9 +3344,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_type_is_simple_compare: case BuiltinProc_type_is_dereferenceable: case BuiltinProc_type_is_valid_map_key: + case BuiltinProc_type_is_valid_matrix_elements: case BuiltinProc_type_is_named: case BuiltinProc_type_is_pointer: case BuiltinProc_type_is_array: + case BuiltinProc_type_is_enumerated_array: case BuiltinProc_type_is_slice: case BuiltinProc_type_is_dynamic_array: case BuiltinProc_type_is_map: @@ -3354,10 +3356,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_type_is_union: case BuiltinProc_type_is_enum: case BuiltinProc_type_is_proc: - case BuiltinProc_type_is_bit_field: - case BuiltinProc_type_is_bit_field_value: case BuiltinProc_type_is_bit_set: case BuiltinProc_type_is_simd_vector: + case BuiltinProc_type_is_matrix: case BuiltinProc_type_is_specialized_polymorphic_record: case BuiltinProc_type_is_unspecialized_polymorphic_record: case BuiltinProc_type_has_nil: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index e8f5174c0..d833a055f 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -213,8 +213,6 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_union, BuiltinProc_type_is_enum, BuiltinProc_type_is_proc, - BuiltinProc_type_is_bit_field, - BuiltinProc_type_is_bit_field_value, BuiltinProc_type_is_bit_set, BuiltinProc_type_is_simd_vector, BuiltinProc_type_is_matrix, @@ -466,8 +464,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_bit_field_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From 83e9a6b417c449e0ffa413f4841ce0d19b1c7732 Mon Sep 17 00:00:00 2001 From: CiD- Date: Tue, 8 Feb 2022 09:21:43 -0500 Subject: [PATCH 0118/1052] fix -vet for filepath/match.odin --- core/path/filepath/match.odin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin index cba44953d..bde7f5393 100644 --- a/core/path/filepath/match.odin +++ b/core/path/filepath/match.odin @@ -227,11 +227,10 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str return m[:], .None } - temp_buf: [8]byte - dir, file := split(pattern) volume_len := 0 when ODIN_OS == "windows" { + temp_buf: [8]byte volume_len, dir = clean_glob_path_windows(dir, temp_buf[:]) } else { dir = clean_glob_path(dir) From 0cc40db565a9c4b99e6fa0844b9ac512558626e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Feb 2022 17:04:55 +0000 Subject: [PATCH 0119/1052] Begin work on support objc intrinsics --- src/check_builtin.cpp | 223 +++++++++++++++++++++++++++++++++- src/check_decl.cpp | 3 + src/checker.cpp | 36 ++++++ src/checker.hpp | 15 ++- src/checker_builtin_procs.hpp | 6 + src/entity.cpp | 1 + src/llvm_backend.cpp | 59 ++++++++- src/llvm_backend.hpp | 6 +- src/llvm_backend_general.cpp | 8 +- src/llvm_backend_proc.cpp | 3 + src/llvm_backend_utility.cpp | 96 +++++++++++++++ src/types.cpp | 10 ++ 12 files changed, 459 insertions(+), 7 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1fb3d6037..8ada77b12 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -143,6 +143,219 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na } +bool does_require_msgSend_stret(Type *return_type) { + if (return_type == nullptr) { + return false; + } + if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { + i64 struct_limit = type_size_of(t_uintptr) << 1; + return type_size_of(return_type) > struct_limit; + } + if (build_context.metrics.arch == TargetArch_arm64) { + return false; + } + + // if (build_context.metrics.arch == TargetArch_arm32) { + // i64 struct_limit = type_size_of(t_uintptr); + // // NOTE(bill): This is technically wrong + // return is_type_struct(return_type) && !is_type_raw_union(return_type) && type_size_of(return_type) > struct_limit; + // } + GB_PANIC("unsupported architecture"); + return false; +} + +ObjcMsgKind get_objc_proc_kind(Type *return_type) { + if (return_type == nullptr) { + return ObjcMsg_normal; + } + + if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { + if (is_type_float(return_type)) { + return ObjcMsg_fpret; + } + if (build_context.metrics.arch == TargetArch_amd64) { + if (is_type_complex(return_type)) { + // URL: https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/message.h#L143-L159 + return ObjcMsg_fpret; + } + } + } + if (build_context.metrics.arch != TargetArch_arm64) { + if (does_require_msgSend_stret(return_type)) { + return ObjcMsg_stret; + } + } + return ObjcMsg_normal; +} + +void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types) { + ObjcMsgKind kind = get_objc_proc_kind(return_type); + + Scope *scope = create_scope(c->info, nullptr); + + // NOTE(bill, 2022-02-08): the backend's ABI handling should handle this correctly, I hope + Type *params = alloc_type_tuple(); + { + auto variables = array_make(permanent_allocator(), 0, param_types.count); + + for_array(i, param_types) { + Type *type = param_types[i]; + Entity *param = alloc_entity_param(scope, blank_token, type, false, true); + array_add(&variables, param); + } + params->Tuple.variables = slice_from_array(variables); + } + + Type *results = alloc_type_tuple(); + if (return_type) { + auto variables = array_make(permanent_allocator(), 1); + results->Tuple.variables = slice_from_array(variables); + Entity *param = alloc_entity_param(scope, blank_token, return_type, false, true); + results->Tuple.variables[0] = param; + } + + + ObjcMsgData data = {}; + data.kind = kind; + data.proc_type = alloc_type_proc(scope, params, param_types.count, results, results->Tuple.variables.count, false, ProcCC_CDecl); + + mutex_lock(&c->info->objc_types_mutex); + map_set(&c->info->objc_msgSend_types, call, data); + mutex_unlock(&c->info->objc_types_mutex); + + add_package_dependency(c, "runtime", "objc_lookUpClass"); + add_package_dependency(c, "runtime", "sel_registerName"); + + add_package_dependency(c, "runtime", "objc_msgSend"); + add_package_dependency(c, "runtime", "objc_msgSend_fpret"); + add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); + add_package_dependency(c, "runtime", "objc_msgSend_stret"); +} + +bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { + auto const is_constant_string = [](CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) -> bool { + Operand op = {}; + check_expr(c, &op, expr); + if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) { + if (name_) *name_ = op.value.value_string; + return true; + } + gbString e = expr_to_string(op.expr); + gbString t = type_to_string(op.type); + error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + }; + String builtin_name = builtin_procs[id].name; + + if (build_context.metrics.os != TargetOs_darwin) { + error(call, "'%.*s' only works on darwin", LIT(builtin_name)); + return false; + } + + + ast_node(ce, CallExpr, call); + switch (id) { + default: + GB_PANIC("Implement objective built-in procedure: %.*s", LIT(builtin_name)); + return false; + + case BuiltinProc_objc_send: { + Type *return_type = nullptr; + + Operand rt = {}; + check_expr_or_type(c, &rt, ce->args[0]); + if (rt.mode == Addressing_Type) { + return_type = rt.type; + } else if (is_operand_nil(rt)) { + return_type = nullptr; + } else { + gbString e = expr_to_string(rt.expr); + error(rt.expr, "'%.*s' expected a type or nil to define the return type of the Objective-C call, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + + operand->type = return_type; + operand->mode = return_type ? Addressing_Value : Addressing_NoValue; + + String class_name = {}; + String sel_name = {}; + + Type *sel_type = t_objc_SEL; + Operand self = {}; + check_expr_or_type(c, &self, ce->args[1]); + if (self.mode == Addressing_Type) { + if (!internal_check_is_assignable_to(self.type, t_objc_object)) { + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got type %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (!(self.type->kind == Type_Named && + self.type->Named.type_name != nullptr && + self.type->Named.type_name->TypeName.objc_class_name != "")) { + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=) , got type %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + sel_type = t_objc_Class; + } else if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) { + gbString e = expr_to_string(self.expr); + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s'3 expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind); + gb_string_free(t); + gb_string_free(e); + return false; + } else if (!is_type_pointer(self.type)) { + gbString e = expr_to_string(self.expr); + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a pointer of a value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } else { + Type *type = type_deref(self.type); + if (!(type->kind == Type_Named && + type->Named.type_name != nullptr && + type->Named.type_name->TypeName.objc_class_name != "")) { + gbString t = type_to_string(type); + error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=) , got type %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + } + + + if (!is_constant_string(c, builtin_name, ce->args[2], &sel_name)) { + return false; + } + + isize const arg_offset = 1; + auto param_types = slice_make(permanent_allocator(), ce->args.count-arg_offset); + param_types[0] = t_objc_id; + param_types[1] = sel_type; + + for (isize i = 2+arg_offset; i < ce->args.count; i++) { + Operand x = {}; + check_expr(c, &x, ce->args[i]); + param_types[i-arg_offset] = x.type; + } + + add_objc_proc_type(c, call, return_type, param_types); + + return true; + } break; + + case BuiltinProc_objc_create: { + GB_PANIC("TODO: BuiltinProc_objc_create"); + return false; + } break; + } +} bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); @@ -179,6 +392,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_len: case BuiltinProc_min: case BuiltinProc_max: + case BuiltinProc_objc_send: + case BuiltinProc_objc_create: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -202,7 +417,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } - String builtin_name = builtin_procs[id].name;; + String builtin_name = builtin_procs[id].name; if (ce->args.count > 0) { @@ -219,6 +434,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name)); break; + case BuiltinProc_objc_send: + case BuiltinProc_objc_create: + return check_builtin_objc_procedure(c, operand, call, id, type_hint); + case BuiltinProc___entry_point: operand->mode = Addressing_NoValue; operand->type = nullptr; @@ -3815,6 +4034,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = t_hasher_proc; break; } + + } return true; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f6dade812..243dbbbc6 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -338,6 +338,9 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) if (decl != nullptr) { AttributeContext ac = {}; check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac); + if (e->kind == Entity_TypeName && ac.objc_class != "") { + e->TypeName.objc_class_name = ac.objc_class; + } } diff --git a/src/checker.cpp b/src/checker.cpp index 7fb4fdb29..2ab487592 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -841,6 +841,17 @@ void add_global_enum_constant(Slice const &fields, char const *name, i GB_PANIC("Unfound enum value for global constant: %s %lld", name, cast(long long)value); } +Type *add_global_type_name(Scope *scope, String const &type_name, Type *backing_type) { + Entity *e = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved); + Type *named_type = alloc_type_named(type_name, backing_type, e); + e->type = named_type; + set_base_type(named_type, backing_type); + if (scope_insert(scope, e)) { + compiler_error("double declaration of %.*s", LIT(e->token.string)); + } + return named_type; +} + void init_universal(void) { BuildContext *bc = &build_context; @@ -985,6 +996,17 @@ void init_universal(void) { t_f64_ptr = alloc_type_pointer(t_f64); t_u8_slice = alloc_type_slice(t_u8); t_string_slice = alloc_type_slice(t_string); + + // intrinsics types for objective-c stuff + { + t_objc_object = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_object"), alloc_type_struct()); + t_objc_selector = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_selector"), alloc_type_struct()); + t_objc_class = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_class"), alloc_type_struct()); + + t_objc_id = alloc_type_pointer(t_objc_object); + t_objc_SEL = alloc_type_pointer(t_objc_selector); + t_objc_Class = alloc_type_pointer(t_objc_class); + } } @@ -1041,6 +1063,9 @@ void init_checker_info(CheckerInfo *i) { semaphore_init(&i->collect_semaphore); mpmc_init(&i->intrinsics_entry_point_usage, a, 1<<10); // just waste some memory here, even if it probably never used + + mutex_init(&i->objc_types_mutex); + map_init(&i->objc_msgSend_types, a); } void destroy_checker_info(CheckerInfo *i) { @@ -1073,6 +1098,9 @@ void destroy_checker_info(CheckerInfo *i) { mutex_destroy(&i->type_and_value_mutex); mutex_destroy(&i->identifier_uses_mutex); mutex_destroy(&i->foreign_mutex); + + mutex_destroy(&i->objc_types_mutex); + map_destroy(&i->objc_msgSend_types); } CheckerContext make_checker_context(Checker *c) { @@ -3161,6 +3189,14 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) { } else if (name == "private") { // NOTE(bill): Handled elsewhere `check_collect_value_decl` return true; + } else if (name == "objc_class") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind != ExactValue_String || ev.value_string == "") { + error(elem, "Expected a non-empty string value for '%.*s'", LIT(name)); + } else { + ac->objc_class = ev.value_string; + } + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index 9a8753efd..b812e10a4 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -107,6 +107,7 @@ struct AttributeContext { String thread_local_model; String deprecated_message; String warning_message; + String objc_class; DeferredProcedure deferred_procedure; bool is_export : 1; bool is_static : 1; @@ -267,6 +268,17 @@ struct UntypedExprInfo { typedef PtrMap UntypedExprInfoMap; typedef MPMCQueue ProcBodyQueue; +enum ObjcMsgKind : u32 { + ObjcMsg_normal, + ObjcMsg_fpret, + ObjcMsg_fp2ret, + ObjcMsg_stret, +}; +struct ObjcMsgData { + ObjcMsgKind kind; + Type *proc_type; +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -340,7 +352,8 @@ struct CheckerInfo { MPMCQueue intrinsics_entry_point_usage; - + BlockingMutex objc_types_mutex; + PtrMap objc_msgSend_types; }; struct CheckerContext { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index d833a055f..1a9d7d7a0 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -250,6 +250,9 @@ BuiltinProc__type_end, BuiltinProc___entry_point, + BuiltinProc_objc_send, + BuiltinProc_objc_create, + BuiltinProc_COUNT, }; gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { @@ -500,4 +503,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + + {STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_create"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, }; diff --git a/src/entity.cpp b/src/entity.cpp index 8327a517e..4d5b3b9e1 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -186,6 +186,7 @@ struct Entity { Type * type_parameter_specialization; String ir_mangled_name; bool is_type_alias; + String objc_class_name; } TypeName; struct { u64 tags; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 304effb7f..7941c65a3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -652,7 +652,53 @@ lbProcedure *lb_create_startup_type_info(lbModule *m) { return p; } -lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, Array &global_variables) { // Startup Runtime +lbProcedure *lb_create_objc_names(lbModule *main_module) { + if (build_context.metrics.os != TargetOs_darwin) { + return nullptr; + } + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl); + lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit("__$init_objc_names"), proc_type); + p->is_startup = true; + return p; +} + +void lb_finalize_objc_names(lbProcedure *p) { + if (p == nullptr) { + return; + } + lbModule *m = p->module; + + LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); + lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); + LLVMFinalizeFunctionPassManager(default_function_pass_manager); + + LLVMSetLinkage(p->value, LLVMInternalLinkage); + lb_begin_procedure_body(p); + for_array(i, m->objc_classes.entries) { + auto const &entry = m->objc_classes.entries[i]; + String name = entry.key.string; + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); + lb_addr_store(p, entry.value, ptr); + } + + for_array(i, m->objc_selectors.entries) { + auto const &entry = m->objc_selectors.entries[i]; + String name = entry.key.string; + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); + lb_addr_store(p, entry.value, ptr); + } + + lb_end_procedure_body(p); + + lb_run_function_pass_manager(default_function_pass_manager, p); + +} + +lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, lbProcedure *objc_names, Array &global_variables) { // Startup Runtime LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(main_module->mod); lb_populate_function_pass_manager(main_module, default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); @@ -666,6 +712,10 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + if (objc_names) { + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); + } + for_array(i, global_variables) { auto *var = &global_variables[i]; if (var->is_initialized) { @@ -1570,8 +1620,10 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Runtime Type Information Creation"); lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); + lbProcedure *objc_names = lb_create_objc_names(default_module); + TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); - lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); + lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, objc_names, global_variables); gb_unused(startup_runtime); TIME_SECTION("LLVM Global Procedures and Types"); @@ -1650,6 +1702,8 @@ void lb_generate_code(lbGenerator *gen) { } } + lb_finalize_objc_names(objc_names); + if (build_context.ODIN_DEBUG) { TIME_SECTION("LLVM Debug Info Complete Types and Finalize"); for_array(j, gen->modules.entries) { @@ -1662,6 +1716,7 @@ void lb_generate_code(lbGenerator *gen) { } + TIME_SECTION("LLVM Function Pass"); for_array(i, gen->modules.entries) { lbModule *m = gen->modules.entries[i].value; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index d7093bc63..087cda22a 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -144,6 +144,9 @@ struct lbModule { PtrMap debug_values; Array debug_incomplete_types; + + StringMap objc_classes; + StringMap objc_selectors; }; struct lbGenerator { @@ -293,7 +296,6 @@ struct lbProcedure { bool lb_init_generator(lbGenerator *gen, Checker *c); -void lb_generate_module(lbGenerator *gen); String lb_mangle_name(lbModule *m, Entity *e); String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); @@ -366,7 +368,7 @@ lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx); lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p); -lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}); +lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr); lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, i32 param_index=0, bool force_no_init=false); void lb_add_foreign_library_path(lbModule *m, Entity *e); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 2fc21b534..1c98aa77f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -72,6 +72,9 @@ void lb_init_module(lbModule *m, Checker *c) { map_init(&m->debug_values, a); array_init(&m->debug_incomplete_types, a, 0, 1024); + + string_map_init(&m->objc_classes, a); + string_map_init(&m->objc_selectors, a); } bool lb_init_generator(lbGenerator *gen, Checker *c) { @@ -2450,7 +2453,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) { return {}; } -lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { +lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) { GB_ASSERT(type != nullptr); type = default_type(type); @@ -2476,6 +2479,9 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { lb_add_entity(m, e, g); lb_add_member(m, name, g); + + if (entity_) *entity_ = e; + return lb_addr(g); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7a6fac603..6de0aaed7 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2106,6 +2106,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.type = t_uintptr; return res; } + + case BuiltinProc_objc_send: + return lb_handle_obj_send(p, expr); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 7e2bd7daa..d92f711ba 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1819,3 +1819,99 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) { LLVMSetVisibility(value, LLVMDefaultVisibility); LLVMAddTargetDependentFunctionAttr(value, "wasm-export-name", alloc_cstring(permanent_allocator(), export_name)); } + + +lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name); + +lbValue lb_handle_obj_id(lbProcedure *p, Ast *expr) { + TypeAndValue const &tav = type_and_value_of_expr(expr); + if (tav.mode == Addressing_Type) { + Type *type = tav.type; + GB_ASSERT_MSG(type->kind == Type_Named, "%s", type_to_string(type)); + Entity *e = type->Named.type_name; + GB_ASSERT(e->kind == Entity_TypeName); + String name = e->TypeName.objc_class_name; + + lbAddr *found = string_map_get(&p->module->objc_classes, name); + if (found) { + return lb_addr_load(p, *found); + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_classes, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_classes, name, local_addr); + } + return lb_addr_load(p, local_addr); + } + } + + return lb_build_expr(p, expr); +} + + +lbValue lb_handle_obj_selector(lbProcedure *p, String const &name) { + lbAddr *found = string_map_get(&p->module->objc_selectors, name); + if (found) { + return lb_addr_load(p, *found); + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_selectors, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_selectors, name, local_addr); + } + return lb_addr_load(p, local_addr); + } +} + + +lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + lbModule *m = p->module; + CheckerInfo *info = m->info; + ObjcMsgData data = map_must_get(&info->objc_msgSend_types, expr); + GB_ASSERT(data.proc_type != nullptr); + + GB_ASSERT(ce->args.count >= 3); + auto args = array_make(permanent_allocator(), 0, ce->args.count-1); + + lbValue id = lb_handle_obj_id(p, ce->args[1]); + Ast *sel_expr = ce->args[2]; + GB_ASSERT(sel_expr->tav.value.kind == ExactValue_String); + lbValue sel = lb_handle_obj_selector(p, sel_expr->tav.value.value_string); + + array_add(&args, id); + array_add(&args, sel); + for (isize i = 3; i < ce->args.count; i++) { + lbValue arg = lb_build_expr(p, ce->args[i]); + array_add(&args, arg); + } + + + lbValue the_proc = {}; + switch (data.kind) { + default: + GB_PANIC("unhandled ObjcMsgKind %u", data.kind); + break; + case ObjcMsg_normal: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend")); break; + case ObjcMsg_fpret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fpret")); break; + case ObjcMsg_fp2ret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fp2ret")); break; + case ObjcMsg_stret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_stret")); break; + } + + the_proc = lb_emit_conv(p, the_proc, data.proc_type); + + return lb_emit_call(p, the_proc, args); +} diff --git a/src/types.cpp b/src/types.cpp index 9ee6ba359..cdb31c6e1 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -685,6 +685,16 @@ gb_global Type *t_map_header = nullptr; gb_global Type *t_equal_proc = nullptr; gb_global Type *t_hasher_proc = nullptr; +gb_global Type *t_objc_object = nullptr; +gb_global Type *t_objc_selector = nullptr; +gb_global Type *t_objc_class = nullptr; + +gb_global Type *t_objc_id = nullptr; +gb_global Type *t_objc_SEL = nullptr; +gb_global Type *t_objc_Class = nullptr; + + + gb_global RecursiveMutex g_type_mutex; struct TypePath; From 05dd3d490de3bf10c56e65987fbbe3024b84a4a6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Feb 2022 17:33:55 +0000 Subject: [PATCH 0120/1052] Correct objc_class propagation for parapoly structs --- src/check_type.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/check_type.cpp b/src/check_type.cpp index 6d3e32466..e1a0df7e6 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -323,6 +323,8 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t } named_type->Named.type_name = e; + GB_ASSERT(original_type->kind == Type_Named); + e->TypeName.objc_class_name = original_type->Named.type_name->TypeName.objc_class_name; mutex_lock(&ctx->info->gen_types_mutex); auto *found_gen_types = map_get(&ctx->info->gen_types, original_type); From c5d348515dcddbd2c29aca79f1863dd36af5476a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Feb 2022 22:59:37 +0000 Subject: [PATCH 0121/1052] Add `intrinsics.type_is_subtype_of`; `intrinsics.objc_selector_name` --- src/check_builtin.cpp | 42 +++++++++++++++++++++++++++++---- src/check_expr.cpp | 36 ---------------------------- src/checker_builtin_procs.hpp | 8 +++++-- src/llvm_backend_proc.cpp | 3 +++ src/llvm_backend_utility.cpp | 11 +++++++++ src/types.cpp | 44 +++++++++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 43 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8ada77b12..df22d82e2 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -350,9 +350,15 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call return true; } break; - case BuiltinProc_objc_create: { - GB_PANIC("TODO: BuiltinProc_objc_create"); - return false; + case BuiltinProc_objc_selector_name: { + String sel_name = {}; + if (!is_constant_string(c, builtin_name, ce->args[0], &sel_name)) { + return false; + } + + operand->type = t_objc_SEL; + operand->mode = Addressing_Value; + return true; } break; } } @@ -392,8 +398,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_len: case BuiltinProc_min: case BuiltinProc_max: + case BuiltinProc_type_is_subtype_of: case BuiltinProc_objc_send: - case BuiltinProc_objc_create: + case BuiltinProc_objc_selector_name: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -435,7 +442,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; case BuiltinProc_objc_send: - case BuiltinProc_objc_create: + case BuiltinProc_objc_selector_name: return check_builtin_objc_procedure(c, operand, call, id, type_hint); case BuiltinProc___entry_point: @@ -3945,6 +3952,31 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; + case BuiltinProc_type_is_subtype_of: + { + Operand op_src = {}; + Operand op_dst = {}; + + check_expr_or_type(c, &op_src, ce->args[0]); + if (op_src.mode != Addressing_Type) { + gbString e = expr_to_string(op_src.expr); + error(op_src.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + check_expr_or_type(c, &op_dst, ce->args[1]); + if (op_dst.mode != Addressing_Type) { + gbString e = expr_to_string(op_dst.expr); + error(op_dst.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + + operand->value = exact_value_bool(is_type_subtype_of(op_src.type, op_dst.type)); + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + } break; + case BuiltinProc_type_field_index_of: { Operand op = {}; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3f31ac810..6db17a316 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -228,42 +228,6 @@ void check_scope_decls(CheckerContext *c, Slice const &nodes, isize reser } } - -isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false) { - Type *prev_src = src; - src = type_deref(src); - if (!src_is_ptr) { - src_is_ptr = src != prev_src; - } - src = base_type(src); - - if (!is_type_struct(src)) { - return 0; - } - - for_array(i, src->Struct.fields) { - Entity *f = src->Struct.fields[i]; - if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) { - continue; - } - - if (are_types_identical(f->type, dst)) { - return level+1; - } - if (src_is_ptr && is_type_pointer(dst)) { - if (are_types_identical(f->type, type_deref(dst))) { - return level+1; - } - } - isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr); - if (nested_level > 0) { - return nested_level; - } - } - - return 0; -} - bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_entity, Type *type, Array *param_operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { /////////////////////////////////////////////////////////////////////////////// diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 1a9d7d7a0..c14c18412 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -241,6 +241,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_polymorphic_record_parameter_count, BuiltinProc_type_polymorphic_record_parameter_value, + BuiltinProc_type_is_subtype_of, + BuiltinProc_type_field_index_of, BuiltinProc_type_equal_proc, @@ -251,7 +253,7 @@ BuiltinProc__type_end, BuiltinProc___entry_point, BuiltinProc_objc_send, - BuiltinProc_objc_create, + BuiltinProc_objc_selector_name, BuiltinProc_COUNT, }; @@ -494,6 +496,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_polymorphic_record_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_subtype_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -505,5 +509,5 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("objc_create"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_selector_name"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, }; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 6de0aaed7..caa3dfa1a 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2109,6 +2109,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_objc_send: return lb_handle_obj_send(p, expr); + + case BuiltinProc_objc_selector_name: + return lb_handle_obj_selector_name(p, expr); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index d92f711ba..8ef66df7a 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1915,3 +1915,14 @@ lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { return lb_emit_call(p, the_proc, args); } + + +lbValue lb_handle_obj_selector_name(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + return lb_handle_obj_selector(p, name); + +} \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index cdb31c6e1..024d644a2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3748,6 +3748,50 @@ i64 type_offset_of_from_selection(Type *type, Selection sel) { return offset; } +isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false) { + Type *prev_src = src; + src = type_deref(src); + if (!src_is_ptr) { + src_is_ptr = src != prev_src; + } + src = base_type(src); + + if (!is_type_struct(src)) { + return 0; + } + + for_array(i, src->Struct.fields) { + Entity *f = src->Struct.fields[i]; + if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) { + continue; + } + + if (are_types_identical(f->type, dst)) { + return level+1; + } + if (src_is_ptr && is_type_pointer(dst)) { + if (are_types_identical(f->type, type_deref(dst))) { + return level+1; + } + } + isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr); + if (nested_level > 0) { + return nested_level; + } + } + + return 0; +} + +bool is_type_subtype_of(Type *src, Type *dst) { + if (are_types_identical(src, dst)) { + return true; + } + + return 0 < check_is_assignable_to_using_subtype(src, dst, 0, is_type_pointer(src)); +} + + Type *get_struct_field_type(Type *t, isize index) { t = base_type(type_deref(t)); From 340838c8789385212eb3225c15cabbd38b51dbea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Feb 2022 23:00:00 +0000 Subject: [PATCH 0122/1052] Add procs_darwin.odin --- core/runtime/procs_darwin.odin | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 core/runtime/procs_darwin.odin diff --git a/core/runtime/procs_darwin.odin b/core/runtime/procs_darwin.odin new file mode 100644 index 000000000..79fd777d7 --- /dev/null +++ b/core/runtime/procs_darwin.odin @@ -0,0 +1,20 @@ +//+private +package runtime + +foreign import "system:Foundation.framework" + +import "core:intrinsics" + +objc_id :: ^intrinsics.objc_object +objc_Class :: ^intrinsics.objc_class +objc_SEL :: ^intrinsics.objc_selector + +foreign Foundation { + objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class --- + sel_registerName :: proc "c" (name: cstring) -> objc_SEL --- + + objc_msgSend :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) --- + objc_msgSend_fpret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 --- + objc_msgSend_fp2ret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> complex128 --- + objc_msgSend_stret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) --- +} From b95ade40c075ed23525f28d571b0175040194ed2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Feb 2022 00:19:20 +0000 Subject: [PATCH 0123/1052] Begin work on `core:sys/darwin/Foundation` --- core/sys/darwin/Foundation/Foundation.odin | 1 + core/sys/darwin/Foundation/NSArray.odin | 26 ++++ .../darwin/Foundation/NSAutoreleasePool.odin | 15 +++ core/sys/darwin/Foundation/NSData.odin | 12 ++ core/sys/darwin/Foundation/NSDate.odin | 8 ++ core/sys/darwin/Foundation/NSDictionary.odin | 27 +++++ core/sys/darwin/Foundation/NSLock.odin | 29 +++++ .../sys/darwin/Foundation/NSNotification.odin | 16 +++ core/sys/darwin/Foundation/NSNumber.odin | 45 +++++++ core/sys/darwin/Foundation/NSObject.odin | 66 +++++++++++ core/sys/darwin/Foundation/NSRange.odin | 22 ++++ core/sys/darwin/Foundation/NSString.odin | 112 ++++++++++++++++++ core/sys/darwin/Foundation/NSTypes.odin | 35 ++++++ 13 files changed, 414 insertions(+) create mode 100644 core/sys/darwin/Foundation/Foundation.odin create mode 100644 core/sys/darwin/Foundation/NSArray.odin create mode 100644 core/sys/darwin/Foundation/NSAutoreleasePool.odin create mode 100644 core/sys/darwin/Foundation/NSData.odin create mode 100644 core/sys/darwin/Foundation/NSDate.odin create mode 100644 core/sys/darwin/Foundation/NSDictionary.odin create mode 100644 core/sys/darwin/Foundation/NSLock.odin create mode 100644 core/sys/darwin/Foundation/NSNotification.odin create mode 100644 core/sys/darwin/Foundation/NSNumber.odin create mode 100644 core/sys/darwin/Foundation/NSObject.odin create mode 100644 core/sys/darwin/Foundation/NSRange.odin create mode 100644 core/sys/darwin/Foundation/NSString.odin create mode 100644 core/sys/darwin/Foundation/NSTypes.odin diff --git a/core/sys/darwin/Foundation/Foundation.odin b/core/sys/darwin/Foundation/Foundation.odin new file mode 100644 index 000000000..c69b10ddb --- /dev/null +++ b/core/sys/darwin/Foundation/Foundation.odin @@ -0,0 +1 @@ +package objc_Foundation diff --git a/core/sys/darwin/Foundation/NSArray.odin b/core/sys/darwin/Foundation/NSArray.odin new file mode 100644 index 000000000..7544c278c --- /dev/null +++ b/core/sys/darwin/Foundation/NSArray.odin @@ -0,0 +1,26 @@ +package objc_Foundation + +import "core:intrinsics" + +@(objc_class="NSArray") +Array :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {using _: Copying(Array(T))} + +Array_initWithObjects :: proc(self: ^$A/Array($T), objects: [^]^Object, count: UInteger) -> ^A { + return msgSend(^A, "initWithObjects:count:", objects, count) +} + +Array_initWithCoder :: proc(self: ^$A/Array($T), coder: ^Coder) -> ^A { + return msgSend(^A, "initWithCoder:", coder) +} + +Array_objectAtIndex :: proc(self: ^Array($T), index: UInteger) -> ^Object { + return msgSend(^Object, self, "objectAtIndex:", index) +} + +Array_object :: proc(self: ^Array($T), index: UInteger) -> ^T { + return (^T)(Array_objectAtIndex(self, index)) +} + +Array_count :: proc(self: ^Array($T)) -> UInteger { + return msgSend(UInteger, self, "count") +} diff --git a/core/sys/darwin/Foundation/NSAutoreleasePool.odin b/core/sys/darwin/Foundation/NSAutoreleasePool.odin new file mode 100644 index 000000000..5ff2a6f1d --- /dev/null +++ b/core/sys/darwin/Foundation/NSAutoreleasePool.odin @@ -0,0 +1,15 @@ +package objc_Foundation + +@(objc_class="NSAutoreleasePool") +AutoreleasePool :: struct {using _: Object} + +AutoreleasePool_drain :: proc(self: ^AutoreleasePool) { + msgSend(nil, self, "drain") +} +AutoreleasePool_addObject :: proc(self: ^AutoreleasePool, obj: ^Object) { + msgSend(nil, self, "addObject:", obj) +} +AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) { + msgSend(nil, self, "showPools") +} + diff --git a/core/sys/darwin/Foundation/NSData.odin b/core/sys/darwin/Foundation/NSData.odin new file mode 100644 index 000000000..93bb3ae0e --- /dev/null +++ b/core/sys/darwin/Foundation/NSData.odin @@ -0,0 +1,12 @@ +package objc_Foundation + +@(objc_class="NSData") +Data :: struct {using _: Copying(Data)} + +Data_mutableBytes :: proc(self: ^Data) -> rawptr { + return msgSend(rawptr, self, "mutableBytes") +} + +Data_length :: proc(self: ^Data) -> UInteger { + return msgSend(UInteger, self, "length") +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSDate.odin b/core/sys/darwin/Foundation/NSDate.odin new file mode 100644 index 000000000..4b298ee24 --- /dev/null +++ b/core/sys/darwin/Foundation/NSDate.odin @@ -0,0 +1,8 @@ +package objc_Foundation + +@(objc_class="NSDate") +Date :: struct {using _: Copying(Date)} + +Date_dateWithTimeIntervalSinceNow :: proc(secs: TimeInterval) -> ^Date { + return msgSend(^Date, Date, "dateWithTimeIntervalSinceNow:", secs) +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSDictionary.odin b/core/sys/darwin/Foundation/NSDictionary.odin new file mode 100644 index 000000000..19ea8a491 --- /dev/null +++ b/core/sys/darwin/Foundation/NSDictionary.odin @@ -0,0 +1,27 @@ +package objc_Foundation + +@(objc_class="NSDictionary") +Dictionary :: struct {using _: Copying(Dictionary)} + +Dictionary_dictionary :: proc() -> ^Dictionary { + return msgSend(^Dictionary, Dictionary, "dictionary") +} + +Dictionary_dictionaryWithObject :: proc(object: ^Object, forKey: ^Object) -> ^Dictionary { + return msgSend(^Dictionary, Dictionary, "dictionaryWithObject:forKey:", object, forKey) +} + +Dictionary_dictionaryWithObjects :: proc(objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { + return msgSend(^Dictionary, Dictionary, "dictionaryWithObjects:forKeys:count", objects, forKeys, count) +} + + +Dictionary_initWithObjects :: proc(self: ^Dictionary, objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { + return msgSend(^Dictionary, self, "initWithObjects:forKeys:count", objects, forKeys, count) +} + +Dictionary_objectForKey :: proc(self: ^Dictionary, key: ^Object) -> ^Object { + return msgSend(^Dictionary, self, "objectForKey:", key) +} + +// TODO(bill): enumerator \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSLock.odin b/core/sys/darwin/Foundation/NSLock.odin new file mode 100644 index 000000000..0e76dfc62 --- /dev/null +++ b/core/sys/darwin/Foundation/NSLock.odin @@ -0,0 +1,29 @@ +package objc_Foundation + +Locking :: struct($T: typeid) {using _: Object} + +Locking_lock :: proc(self: ^Locking($T)) { + msgSend(nil, self, "lock") +} +Locking_unlock :: proc(self: ^Locking($T)) { + msgSend(nil, self, "unlock") +} + +@(objc_class="NSCondition") +Condition :: struct {using _: Locking(Condition) } + +Condition_wait :: proc(self: ^Condition) { + msgSend(nil, self, "wait") +} + +Condition_waitUntilDate :: proc(self: ^Condition, limit: ^Date) -> BOOL { + return msgSend(BOOL, self, "waitUntilDate:", limit) +} + +Condition_signal :: proc(self: ^Condition) { + msgSend(nil, self, "signal") +} + +Condition_broadcast :: proc(self: ^Condition) { + msgSend(nil, self, "broadcast") +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSNotification.odin b/core/sys/darwin/Foundation/NSNotification.odin new file mode 100644 index 000000000..fa9160cc8 --- /dev/null +++ b/core/sys/darwin/Foundation/NSNotification.odin @@ -0,0 +1,16 @@ +package objc_Foundation + +@(objc_class="NSNotification") +Notification :: struct{using _: Object} + +Notification_name :: proc(self: ^Notification) -> ^String { + return msgSend(^String, self, "name") +} + +Notification_object :: proc(self: ^Notification) -> ^Object { + return msgSend(^Object, self, "object") +} + +Notification_userInfo :: proc(self: ^Notification) -> ^Dictionary { + return msgSend(^Dictionary, self, "userInfo") +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSNumber.odin b/core/sys/darwin/Foundation/NSNumber.odin new file mode 100644 index 000000000..d41f1e6d2 --- /dev/null +++ b/core/sys/darwin/Foundation/NSNumber.odin @@ -0,0 +1,45 @@ +package objc_Foundation + +@(objc_class="NSValue") +Value :: struct{using _: Copying(Value)} + + +@(objc_class="NSNumber") +Number :: struct{using _: Copying(Number), using _: Value} + + +Value_valueWithBytes :: proc(value: rawptr, type: cstring) -> ^Value { + return msgSend(^Value, Value, "valueWithBytes:objCType:", value, type) +} + +Value_valueWithPointer :: proc(pointer: rawptr) -> ^Value { + return msgSend(^Value, Value, "valueWithPointer:", pointer) +} + +Value_initWithBytes :: proc(value: rawptr, type: cstring) -> ^Value { + return msgSend(^Value, Value, "initWithBytes:objCType:", value, type) +} + +Value_initWithCoder :: proc(coder: ^Coder) -> ^Value { + return msgSend(^Value, Value, "initWithCoder:", coder) +} + +Value_getValue :: proc(self: ^Value, value: rawptr, size: UInteger) { + msgSend(nil, self, "getValue:size:", value, size) +} + + +Value_objCType :: proc(self: ^Value) -> cstring { + return msgSend(cstring, self, "objCType") +} + +Value_isEqualToValue :: proc(self, other: ^Value) -> BOOL { + return msgSend(BOOL, self, "isEqualToValue:", other) +} + +Value_pointerValue :: proc(self: ^Value) -> rawptr { + return msgSend(rawptr, self, "pointerValue") +} + + +// TODO(bill): Number methods \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin new file mode 100644 index 000000000..cf15dd68d --- /dev/null +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -0,0 +1,66 @@ +package objc_Foundation + +import "core:intrinsics" + +methodSignatureForSelector :: proc "c" (obj: ^Object, selector: SEL) -> rawptr { + return msgSend(rawptr, obj, "methodSignatureForSelector:", selector) +} + +respondsToSelector :: proc "c" (obj: ^Object, selector: SEL) -> BOOL { + return msgSend(BOOL, obj, "respondsToSelector:", selector) +} + +msgSendSafeCheck :: proc "c" (obj: ^Object, selector: SEL) -> BOOL { + return respondsToSelector(obj, selector) || methodSignatureForSelector(obj, selector) != nil +} + + +@(objc_class="NSObject") +Object :: struct {using _: intrinsics.objc_object} + +@(objc_class="NSObject") +Copying :: struct($T: typeid) {using _: Object} + +alloc :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) { + return msgSend(^T, T, "alloc") +} +init :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object){ + return msgSend(^T, self, "init") +} +retain :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) { + return msgSend(^T, self, "retain") +} +release :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) { + msgSend(nil, self, "release") +} +retainCount :: proc(self: ^$T) -> UInteger where intrinsics.type_is_subtype_of(T, Object) { + return msgSend(UInteger, self, "retainCount") +} + +copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Object) { + return msgSend(^T, self, "copy") +} + +hash :: proc(self: ^Object) -> UInteger { + return msgSend(UInteger, self, "hash") +} + +isEqual :: proc(self, pObject: ^Object) -> BOOL { + return msgSend(BOOL, self, "isEqual:", pObject) +} + +description :: proc(self: ^Object) -> ^String { + return msgSend(^String, self, "description") +} + +debugDescription :: proc(self: ^Object) -> ^String { + if msgSendSafeCheck(self, intrinsics.objc_selector_name("debugDescription")) { + return msgSend(^String, self, "debugDescription") + } + return nil +} + + +@(objc_class="NSCoder") +Coder :: struct {using _: Object} +// TODO(bill): Implement all the methods for this massive type \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSRange.odin b/core/sys/darwin/Foundation/NSRange.odin new file mode 100644 index 000000000..74ce595a3 --- /dev/null +++ b/core/sys/darwin/Foundation/NSRange.odin @@ -0,0 +1,22 @@ +package objc_Foundation + +Range :: struct { + location: UInteger, + length: UInteger, +} + +Range_Make :: proc(loc, len: UInteger) -> Range { + return Range{loc, len} +} + +Range_Equal :: proc(a, b: Range) -> BOOL { + return a == b +} + +Range_LocationInRange :: proc(self: Range, loc: UInteger) -> BOOL { + return !((loc < self.location) && ((loc - self.location) < self.length)) +} + +Range_Max :: proc(self: Range) -> UInteger { + return self.location + self.length +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin new file mode 100644 index 000000000..857e27f12 --- /dev/null +++ b/core/sys/darwin/Foundation/NSString.odin @@ -0,0 +1,112 @@ +package objc_Foundation + +foreign import "system:Foundation.framework" + +@(objc_class="NSString") +String :: struct {using _: Copying(String)} + +StringEncoding :: enum UInteger { + ASCII = 1, + NEXTSTEP = 2, + JapaneseEUC = 3, + UTF8 = 4, + ISOLatin1 = 5, + Symbol = 6, + NonLossyASCII = 7, + ShiftJIS = 8, + ISOLatin2 = 9, + Unicode = 10, + WindowsCP1251 = 11, + WindowsCP1252 = 12, + WindowsCP1253 = 13, + WindowsCP1254 = 14, + WindowsCP1250 = 15, + ISO2022JP = 21, + MacOSRoman = 30, + + UTF16 = Unicode, + + UTF16BigEndian = 0x90000100, + UTF16LittleEndian = 0x94000100, + + UTF32 = 0x8c000100, + UTF32BigEndian = 0x98000100, + UTF32LittleEndian = 0x9c000100, +} + +StringCompareOptions :: distinct bit_set[StringCompareOption; UInteger] +StringCompareOption :: enum UInteger { + CaseInsensitive = 0, + LiteralSearch = 1, + BackwardsSearch = 2, + AnchoredSearch = 3, + NumericSearch = 6, + DiacriticInsensitive = 7, + WidthInsensitive = 8, + ForcedOrdering = 9, + RegularExpression = 10, +} + +unichar :: distinct u16 + +foreign Foundation { + __CFStringMakeConstantString :: proc "c" (c: cstring) -> ^String --- +} + +AT :: MakeConstantString +MakeConstantString :: proc "c" (#const c: cstring) -> ^String { + return __CFStringMakeConstantString(c) +} + + +String_initWithString :: proc(self: ^String, other: ^String) -> ^String { + return msgSend(^String, self, "initWithString:", other) +} + +String_initWithCString :: proc(self: ^String, pString: cstring, encoding: StringEncoding) -> ^String { + return msgSend(^String, self, "initWithCstring:encoding:", pString, encoding) +} + +String_initWithBytesNoCopy :: proc(self: ^String, pBytes: rawptr, length: UInteger, encoding: StringEncoding, freeWhenDone: bool) -> ^String { + return msgSend(^String, self, "initWithBytesNoCopy:length:encoding:freeWhenDone:", pBytes, length, encoding, freeWhenDone) +} + +String_initWithOdinString :: proc(self: ^String, str: string) -> ^String { + return String_initWithBytesNoCopy(self, raw_data(str), UInteger(len(str)), .UTF8, false) +} + +String_characterAtIndex :: proc(self: ^String, index: UInteger) -> unichar { + return msgSend(unichar, self, "characterAtIndex:", index) +} + +String_length :: proc(self: ^String) -> UInteger { + return msgSend(UInteger, self, "length") +} + +String_cStringUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> cstring { + return msgSend(cstring, self, "cStringUsingEncoding:", encoding) +} + +String_UTFString :: proc(self: ^String) -> cstring { + return msgSend(cstring, self, "UTFString") +} + +String_OdinString :: proc(self: ^String) -> string { + return string(String_UTFString(self)) +} + +String_maximumLengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger { + return msgSend(UInteger, self, "maximumLengthOfBytesUsingEncoding:", encoding) +} + +String_lengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger { + return msgSend(UInteger, self, "lengthOfBytesUsingEncoding:", encoding) +} + +String_isEqualToString :: proc(self, other: ^String) -> BOOL { + return msgSend(BOOL, self, "isEqualToString:", other) +} + +String_rangeOfString :: proc(self, other: ^String, options: StringCompareOptions) -> Range { + return msgSend(Range, self, "rangeOfString:options:", other, options) +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSTypes.odin b/core/sys/darwin/Foundation/NSTypes.odin new file mode 100644 index 000000000..47f75630f --- /dev/null +++ b/core/sys/darwin/Foundation/NSTypes.odin @@ -0,0 +1,35 @@ +package objc_Foundation + +import "core:intrinsics" + +@(private) msgSend :: intrinsics.objc_send + +id :: ^intrinsics.objc_object +SEL :: ^intrinsics.objc_selector +Class :: ^intrinsics.objc_class + +TimeInterval :: distinct f64 +Integer :: distinct int +UInteger :: distinct uint + +IntegerMax :: max(Integer) +Integermin :: min(Integer) +UIntegerMax :: max(UInteger) + +BOOL :: bool // TODO(bill): should this be `distinct`? +YES :: true +NO :: false + +OperatingSystemVersion :: struct #packed { + majorVersion: Integer, + minorVersion: Integer, + patchVersion: Integer, +} + +ComparisonResult :: enum Integer { + OrderedAscending = -1, + OrderedSame = 0, + OrderedDescending = 1, +} + +NotFound :: IntegerMax From 5f2514db635a94937d214be4c4af16eaf8a5dcde Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Feb 2022 11:50:11 +0000 Subject: [PATCH 0124/1052] Add NSNumber and NSURL --- core/sys/darwin/Foundation/NSArray.odin | 4 +- core/sys/darwin/Foundation/NSNumber.odin | 104 +++++++++++++++++++++-- core/sys/darwin/Foundation/NSURL.odin | 15 ++++ 3 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 core/sys/darwin/Foundation/NSURL.odin diff --git a/core/sys/darwin/Foundation/NSArray.odin b/core/sys/darwin/Foundation/NSArray.odin index 7544c278c..a58543d7a 100644 --- a/core/sys/darwin/Foundation/NSArray.odin +++ b/core/sys/darwin/Foundation/NSArray.odin @@ -3,7 +3,9 @@ package objc_Foundation import "core:intrinsics" @(objc_class="NSArray") -Array :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {using _: Copying(Array(T))} +Array :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { + using _: Copying(Array(T)), +} Array_initWithObjects :: proc(self: ^$A/Array($T), objects: [^]^Object, count: UInteger) -> ^A { return msgSend(^A, "initWithObjects:count:", objects, count) diff --git a/core/sys/darwin/Foundation/NSNumber.odin b/core/sys/darwin/Foundation/NSNumber.odin index d41f1e6d2..3b8e59419 100644 --- a/core/sys/darwin/Foundation/NSNumber.odin +++ b/core/sys/darwin/Foundation/NSNumber.odin @@ -1,13 +1,13 @@ package objc_Foundation +import "core:c" + +#assert(size_of(c.long) == size_of(int)) +#assert(size_of(c.ulong) == size_of(uint)) + @(objc_class="NSValue") Value :: struct{using _: Copying(Value)} - -@(objc_class="NSNumber") -Number :: struct{using _: Copying(Number), using _: Value} - - Value_valueWithBytes :: proc(value: rawptr, type: cstring) -> ^Value { return msgSend(^Value, Value, "valueWithBytes:objCType:", value, type) } @@ -42,4 +42,96 @@ Value_pointerValue :: proc(self: ^Value) -> rawptr { } -// TODO(bill): Number methods \ No newline at end of file +@(objc_class="NSNumber") +Number :: struct{using _: Copying(Number), using _: Value} + + +Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) } +Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) } +Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) } +Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) } +Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) } +Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) } +Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) } +Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) } +Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) } +Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) } +Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) } +Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) } +Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) } + +Number_number :: proc{ + Number_numberWithI8, + Number_numberWithU8, + Number_numberWithI16, + Number_numberWithU16, + Number_numberWithI32, + Number_numberWithU32, + Number_numberWithInt, + Number_numberWithUint, + Number_numberWithU64, + Number_numberWithI64, + Number_numberWithF32, + Number_numberWithF64, + Number_numberWithBool, +} + +Number_initWithI8 :: proc(self: ^Number, value: i8) -> ^Number { return msgSend(^Number, self, "initWithChar:", value) } +Number_initWithU8 :: proc(self: ^Number, value: u8) -> ^Number { return msgSend(^Number, self, "initWithUnsignedChar:", value) } +Number_initWithI16 :: proc(self: ^Number, value: i16) -> ^Number { return msgSend(^Number, self, "initWithShort:", value) } +Number_initWithU16 :: proc(self: ^Number, value: u16) -> ^Number { return msgSend(^Number, self, "initWithUnsignedShort:", value) } +Number_initWithI32 :: proc(self: ^Number, value: i32) -> ^Number { return msgSend(^Number, self, "initWithInt:", value) } +Number_initWithU32 :: proc(self: ^Number, value: u32) -> ^Number { return msgSend(^Number, self, "initWithUnsignedInt:", value) } +Number_initWithInt :: proc(self: ^Number, value: int) -> ^Number { return msgSend(^Number, self, "initWithLong:", value) } +Number_initWithUint :: proc(self: ^Number, value: uint) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLong:", value) } +Number_initWithU64 :: proc(self: ^Number, value: u64) -> ^Number { return msgSend(^Number, self, "initWithLongLong:", value) } +Number_initWithI64 :: proc(self: ^Number, value: i64) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLongLong:", value) } +Number_initWithF32 :: proc(self: ^Number, value: f32) -> ^Number { return msgSend(^Number, self, "initWithFloat:", value) } +Number_initWithF64 :: proc(self: ^Number, value: f64) -> ^Number { return msgSend(^Number, self, "initWithDouble:", value) } +Number_initWithBool :: proc(self: ^Number, value: BOOL) -> ^Number { return msgSend(^Number, self, "initWithBool:", value) } + + +Number_init :: proc{ + Number_initWithI8, + Number_initWithU8, + Number_initWithI16, + Number_initWithU16, + Number_initWithI32, + Number_initWithU32, + Number_initWithInt, + Number_initWithUint, + Number_initWithU64, + Number_initWithI64, + Number_initWithF32, + Number_initWithF64, + Number_initWithBool, +} + +Number_i8Value :: proc(self: ^Number) -> i8 { return msgSend(i8, self, "charValue") } +Number_u8Value :: proc(self: ^Number) -> u8 { return msgSend(u8, self, "unsignedCharValue") } +Number_i16Value :: proc(self: ^Number) -> i16 { return msgSend(i16, self, "shortValue") } +Number_u16Value :: proc(self: ^Number) -> u16 { return msgSend(u16, self, "unsignedShortValue") } +Number_i32Value :: proc(self: ^Number) -> i32 { return msgSend(i32, self, "intValue") } +Number_u32Value :: proc(self: ^Number) -> u32 { return msgSend(u32, self, "unsignedIntValue") } +Number_intValue :: proc(self: ^Number) -> int { return msgSend(int, self, "longValue") } +Number_uintValue :: proc(self: ^Number) -> uint { return msgSend(uint, self, "unsignedLongValue") } +Number_u64Value :: proc(self: ^Number) -> u64 { return msgSend(u64, self, "longLongValue") } +Number_i64Value :: proc(self: ^Number) -> i64 { return msgSend(i64, self, "unsignedLongLongValue") } +Number_f32Value :: proc(self: ^Number) -> f32 { return msgSend(f32, self, "floatValue") } +Number_f64Value :: proc(self: ^Number) -> f64 { return msgSend(f64, self, "doubleValue") } +Number_boolValue :: proc(self: ^Number) -> BOOL { return msgSend(BOOL, self, "boolValue") } +Number_integerValue :: proc(self: ^Number) -> Integer { return msgSend(Integer, self, "integerValue") } +Number_uintegerValue :: proc(self: ^Number) -> UInteger { return msgSend(UInteger, self, "unsignedIntegerValue") } +Number_stringValue :: proc(self: ^Number) -> ^String { return msgSend(^String, self, "stringValue") } + +Number_compare :: proc(a, b: ^Number) -> ComparisonResult { + return msgSend(ComparisonResult, a, "compare:", b) +} + +Number_isEqualToNumber :: proc(a, b: ^Number) -> BOOL { + return msgSend(BOOL, a, "isEqualToNumber:", b) +} + +Number_descriptionWithLocale :: proc(self: ^Number, locale: ^Object) -> ^String { + return msgSend(^String, self, "descriptionWithLocale:", locale) +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSURL.odin b/core/sys/darwin/Foundation/NSURL.odin new file mode 100644 index 000000000..f4f776130 --- /dev/null +++ b/core/sys/darwin/Foundation/NSURL.odin @@ -0,0 +1,15 @@ +package objc_Foundation + +@(objc_class="NSURL") +URL :: struct{using _: Copying(URL)} + +URL_initWithString :: proc(self: ^URL, value: ^String) -> ^URL { + return msgSend(^URL, self, "initWithString:", value) +} +URL_initFileURLWithPath :: proc(self: ^URL, path: ^String) -> ^URL { + return msgSend(^URL, self, "initFileURLWithPath:", path) +} + +URL_fileSystemRepresentation :: proc(self: ^URL) -> ^String { + return msgSend(^String, self, "fileSystemRepresentation") +} \ No newline at end of file From 768c2684d01ac77c7e15d4a24a48f21a8fbc8abc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Feb 2022 12:19:59 +0000 Subject: [PATCH 0125/1052] Add NSBundle, NSError, NSEnumerator --- core/sys/darwin/Foundation/NSArray.odin | 4 +- core/sys/darwin/Foundation/NSBundle.odin | 161 +++++++++++++++++++ core/sys/darwin/Foundation/NSDictionary.odin | 8 +- core/sys/darwin/Foundation/NSEnumerator.odin | 37 +++++ core/sys/darwin/Foundation/NSError.odin | 68 ++++++++ 5 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 core/sys/darwin/Foundation/NSBundle.odin create mode 100644 core/sys/darwin/Foundation/NSEnumerator.odin create mode 100644 core/sys/darwin/Foundation/NSError.odin diff --git a/core/sys/darwin/Foundation/NSArray.odin b/core/sys/darwin/Foundation/NSArray.odin index a58543d7a..435e239a2 100644 --- a/core/sys/darwin/Foundation/NSArray.odin +++ b/core/sys/darwin/Foundation/NSArray.odin @@ -19,8 +19,8 @@ Array_objectAtIndex :: proc(self: ^Array($T), index: UInteger) -> ^Object { return msgSend(^Object, self, "objectAtIndex:", index) } -Array_object :: proc(self: ^Array($T), index: UInteger) -> ^T { - return (^T)(Array_objectAtIndex(self, index)) +Array_object :: proc(self: ^Array($T), index: UInteger) -> T { + return (T)(Array_objectAtIndex(self, index)) } Array_count :: proc(self: ^Array($T)) -> UInteger { diff --git a/core/sys/darwin/Foundation/NSBundle.odin b/core/sys/darwin/Foundation/NSBundle.odin new file mode 100644 index 000000000..375e15b65 --- /dev/null +++ b/core/sys/darwin/Foundation/NSBundle.odin @@ -0,0 +1,161 @@ +package objc_Foundation + +@(objc_class="NSBundle") +Bundle :: struct { using _: Object } + +Bundle_mainBundle :: proc() -> ^Bundle { + return msgSend(^Bundle, Bundle, "mainBundle") +} + +Bundle_bundleWithPath :: proc(path: ^String) -> ^Bundle { + return msgSend(^Bundle, Bundle, "bundleWithPath:", path) +} + +Bundle_bundleWithURL :: proc(url: ^URL) -> ^Bundle { + return msgSend(^Bundle, Bundle, "bundleWithUrl:", url) +} +Bundle_bundle :: proc{ + Bundle_bundleWithPath, + Bundle_bundleWithURL, +} + + +Bundle_initWithPath :: proc(self: ^Bundle, path: ^String) -> ^Bundle { + return msgSend(^Bundle, self, "initWithPath:", path) +} + +Bundle_initWithURL :: proc(self: ^Bundle, url: ^URL) -> ^Bundle { + return msgSend(^Bundle, self, "initWithUrl:", url) +} +Bundle_init :: proc{ + Bundle_initWithPath, + Bundle_initWithURL, +} + + +Bundle_allBundles :: proc() -> (all: ^Array(^Bundle)) { + return msgSend(type_of(all), Bundle, "allBundles") +} + +Bundle_allFrameworks :: proc() -> (all: ^Array(^Object)) { + return msgSend(type_of(all), Bundle, "allFrameworks") +} + +Bundle_load :: proc(self: ^Bundle) -> BOOL { + return msgSend(BOOL, self, "load") +} +Bundle_unload :: proc(self: ^Bundle) -> BOOL { + return msgSend(BOOL, self, "unload") +} + +Bundle_isLoaded :: proc(self: ^Bundle) -> BOOL { + return msgSend(BOOL, self, "isLoaded") +} + +Bundle_preflightAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) { + ok = msgSend(BOOL, self, "preflightAndReturnError:", &error) + return +} + +Bundle_loadAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) { + ok = msgSend(BOOL, self, "loadAndReturnError:", &error) + return +} + +Bundle_bundleURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "bundleURL") +} + +Bundle_resourceURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "resourceURL") +} + +Bundle_executableURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "executableURL") +} + +Bundle_URLForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^URL { + return msgSend(^URL, self, "URLForAuxiliaryExecutable:", executableName) +} + +Bundle_privateFrameworksURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "privateFrameworksURL") +} + +Bundle_sharedFrameworksURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "sharedFrameworksURL") +} + + +Bundle_sharedSupportURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "sharedSupportURL") +} + +Bundle_builtInPlugInsURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "builtInPlugInsURL") +} + +Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL { + return msgSend(^URL, self, "appStoreReceiptURL") +} + + + + +Bundle_bundlePath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "bundlePath") +} + +Bundle_resourcePath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "resourcePath") +} + +Bundle_executablePath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "executablePath") +} + +Bundle_PathForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^String { + return msgSend(^String, self, "PathForAuxiliaryExecutable:", executableName) +} + +Bundle_privateFrameworksPath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "privateFrameworksPath") +} + +Bundle_sharedFrameworksPath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "sharedFrameworksPath") +} + + +Bundle_sharedSupportPath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "sharedSupportPath") +} + +Bundle_builtInPlugInsPath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "builtInPlugInsPath") +} + +Bundle_appStoreReceiptPath :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "appStoreReceiptPath") +} + +Bundle_bundleIdentifier :: proc(self: ^Bundle) -> ^String { + return msgSend(^String, self, "bundleIdentifier") +} + + +Bundle_infoDictionary :: proc(self: ^Bundle) -> ^Dictionary { + return msgSend(^Dictionary, self, "infoDictionary") +} + +Bundle_localizedInfoDictionary :: proc(self: ^Bundle) -> ^Dictionary { + return msgSend(^Dictionary, self, "localizedInfoDictionary") +} + +Bundle_objectForInfoDictionaryKey :: proc(self: ^Bundle, key: ^String) -> ^Object { + return msgSend(^Object, self, "objectForInfoDictionaryKey:", key) +} + +Bundle_localizedStringForKey :: proc(self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String { + return msgSend(^String, self, "localizedStringForKey:value:table:", key, value, tableName) +} diff --git a/core/sys/darwin/Foundation/NSDictionary.odin b/core/sys/darwin/Foundation/NSDictionary.odin index 19ea8a491..f82b8cffd 100644 --- a/core/sys/darwin/Foundation/NSDictionary.odin +++ b/core/sys/darwin/Foundation/NSDictionary.odin @@ -24,4 +24,10 @@ Dictionary_objectForKey :: proc(self: ^Dictionary, key: ^Object) -> ^Object { return msgSend(^Dictionary, self, "objectForKey:", key) } -// TODO(bill): enumerator \ No newline at end of file +Dictionary_count :: proc(self: ^Dictionary) -> UInteger { + return msgSend(UInteger, self, "count") +} + +Dictionary_keyEnumerator :: proc(self: ^Dictionary, $KeyType: typeid) -> (enumerator: ^Enumerator(KeyType)) { + return msgSend(type_of(enumerator), self, "keyEnumerator") +} diff --git a/core/sys/darwin/Foundation/NSEnumerator.odin b/core/sys/darwin/Foundation/NSEnumerator.odin new file mode 100644 index 000000000..b6adf2b98 --- /dev/null +++ b/core/sys/darwin/Foundation/NSEnumerator.odin @@ -0,0 +1,37 @@ +package objc_Foundation + +import "core:c" +import "core:intrinsics" + +FastEnumerationState :: struct #packed { + state: c.ulong, + itemsPtr: [^]^Object, + mutationsPtr: [^]c.ulong, + extra: [5]c.ulong, +} + +@(objc_class="NSFastEnumeration") +FastEnumeration :: struct {using _: Object} + +@(objc_class="NSEnumerator") +Enumerator :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { + using _: FastEnumeration, +} + +FastEnumeration_countByEnumerating :: proc(self: ^FastEnumeration, state: ^FastEnumerationState, buffer: [^]^Object, len: UInteger) -> UInteger { + return msgSend(UInteger, self, "countByEnumeratingWithState:objects:count:", state, buffer, len) +} + +Enumerator_nextObject :: proc(self: ^$E/Enumerator($T)) -> T { + return msgSend(T, self, "nextObject") +} + +Enumerator_allObjects :: proc(self: ^$E/Enumerator($T)) -> (all: Array(T)) { + return msgSend(type_of(all), self, "allObjects") +} + +Enumerator_iterator :: proc(self: ^$E/Enumerator($T)) -> (obj: T, ok: bool) { + obj = msgSend(T, self, "nextObject") + ok = obj != nil + return +} diff --git a/core/sys/darwin/Foundation/NSError.odin b/core/sys/darwin/Foundation/NSError.odin new file mode 100644 index 000000000..85ff5514a --- /dev/null +++ b/core/sys/darwin/Foundation/NSError.odin @@ -0,0 +1,68 @@ +package objc_Foundation + +foreign import "system:Foundation.framework" + +ErrorDomain :: ^String + +foreign Foundation { + CocoaErrorDomain: ErrorDomain + POSIXErrorDomain: ErrorDomain + OSStatusErrorDomain: ErrorDomain + MachErrorDomain: ErrorDomain +} + +ErrorUserInfoKey :: ^String + +foreign Foundation { + UnderlyingErrorKey: ErrorUserInfoKey + LocalizedDescriptionKey: ErrorUserInfoKey + LocalizedFailureReasonErrorKey: ErrorUserInfoKey + LocalizedRecoverySuggestionErrorKey: ErrorUserInfoKey + LocalizedRecoveryOptionsErrorKey: ErrorUserInfoKey + RecoveryAttempterErrorKey: ErrorUserInfoKey + HelpAnchorErrorKey: ErrorUserInfoKey + DebugDescriptionErrorKey: ErrorUserInfoKey + LocalizedFailureErrorKey: ErrorUserInfoKey + StringEncodingErrorKey: ErrorUserInfoKey + URLErrorKey: ErrorUserInfoKey + FilePathErrorKey: ErrorUserInfoKey +} + +@(objc_class="NSError") +Error :: struct { using _: Copying(Error) } + +Error_errorWithDomain :: proc(domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error { + return msgSend(^Error, Error, "errorWithDomain:code:userInfo:", domain, code, userInfo) +} + +Error_initWithDomain :: proc(self: ^Error, domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error { + return msgSend(^Error, self, "initWithDomain:code:userInfo:", domain, code, userInfo) +} + +Error_code :: proc(self: ^Error) -> Integer { + return msgSend(Integer, self, "code") +} + +Error_domain :: proc(self: ^Error) -> ErrorDomain { + return msgSend(ErrorDomain, self, "domain") +} + +Error_userInfo :: proc(self: ^Error) -> ^Dictionary { + return msgSend(^Dictionary, self, "userInfo") +} + +Error_localizedDescription :: proc(self: ^Error) -> ^String { + return msgSend(^String, self, "localizedDescription") +} + +Error_localizedRecoveryOptions :: proc(self: ^Error) -> (options: ^Array(^Object)) { + return msgSend(type_of(options), self, "localizedRecoveryOptions") +} + +Error_localizedRecoverySuggestion :: proc(self: ^Error) -> ^String { + return msgSend(^String, self, "localizedRecoverySuggestion") +} + +Error_localizedFailureReason :: proc(self: ^Error) -> ^String { + return msgSend(^String, self, "localizedFailureReason") +} \ No newline at end of file From ef98e92e8de11a65583ca7bca008e70a33249b01 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Feb 2022 12:23:41 +0000 Subject: [PATCH 0126/1052] Remove unneeded file --- core/sys/darwin/Foundation/Foundation.odin | 1 - 1 file changed, 1 deletion(-) delete mode 100644 core/sys/darwin/Foundation/Foundation.odin diff --git a/core/sys/darwin/Foundation/Foundation.odin b/core/sys/darwin/Foundation/Foundation.odin deleted file mode 100644 index c69b10ddb..000000000 --- a/core/sys/darwin/Foundation/Foundation.odin +++ /dev/null @@ -1 +0,0 @@ -package objc_Foundation From b6abaf739ccaa226f2ddf808639994d2c0577258 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Feb 2022 12:29:52 +0000 Subject: [PATCH 0127/1052] Add missing calls for `Object`; Add `scoped_autoreleasepool` --- core/sys/darwin/Foundation/NSAutoreleasePool.odin | 5 +++++ core/sys/darwin/Foundation/NSObject.odin | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/core/sys/darwin/Foundation/NSAutoreleasePool.odin b/core/sys/darwin/Foundation/NSAutoreleasePool.odin index 5ff2a6f1d..47cbc0e9a 100644 --- a/core/sys/darwin/Foundation/NSAutoreleasePool.odin +++ b/core/sys/darwin/Foundation/NSAutoreleasePool.odin @@ -13,3 +13,8 @@ AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) { msgSend(nil, self, "showPools") } + +@(deferred_out=AutoreleasePool_drain) +scoped_autoreleasepool :: proc() -> ^AutoreleasePool { + return init(alloc(AutoreleasePool)) +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin index cf15dd68d..5e2f85ceb 100644 --- a/core/sys/darwin/Foundation/NSObject.odin +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -33,14 +33,19 @@ retain :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) { release :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) { msgSend(nil, self, "release") } +autorelease :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) { + msgSend(nil, self, "autorelease") +} retainCount :: proc(self: ^$T) -> UInteger where intrinsics.type_is_subtype_of(T, Object) { return msgSend(UInteger, self, "retainCount") } + copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, self, "copy") } + hash :: proc(self: ^Object) -> UInteger { return msgSend(UInteger, self, "hash") } @@ -60,6 +65,10 @@ debugDescription :: proc(self: ^Object) -> ^String { return nil } +bridgingCast :: proc($T: typeid, obj: ^Object) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { + return (T)(obj) +} + @(objc_class="NSCoder") Coder :: struct {using _: Object} From 42a1c58a8090bb3f5f6ac46db5f82edc3df49213 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Feb 2022 21:42:20 +0000 Subject: [PATCH 0128/1052] Update Foundation linking --- core/sys/darwin/Foundation/NSError.odin | 32 ++++++++++++------------ core/sys/darwin/Foundation/NSNumber.odin | 30 +++++++++++----------- core/sys/darwin/Foundation/NSObject.odin | 2 +- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/core/sys/darwin/Foundation/NSError.odin b/core/sys/darwin/Foundation/NSError.odin index 85ff5514a..aebf01035 100644 --- a/core/sys/darwin/Foundation/NSError.odin +++ b/core/sys/darwin/Foundation/NSError.odin @@ -5,27 +5,27 @@ foreign import "system:Foundation.framework" ErrorDomain :: ^String foreign Foundation { - CocoaErrorDomain: ErrorDomain - POSIXErrorDomain: ErrorDomain - OSStatusErrorDomain: ErrorDomain - MachErrorDomain: ErrorDomain + @(linkage="weak") CocoaErrorDomain: ErrorDomain + @(linkage="weak") POSIXErrorDomain: ErrorDomain + @(linkage="weak") OSStatusErrorDomain: ErrorDomain + @(linkage="weak") MachErrorDomain: ErrorDomain } ErrorUserInfoKey :: ^String foreign Foundation { - UnderlyingErrorKey: ErrorUserInfoKey - LocalizedDescriptionKey: ErrorUserInfoKey - LocalizedFailureReasonErrorKey: ErrorUserInfoKey - LocalizedRecoverySuggestionErrorKey: ErrorUserInfoKey - LocalizedRecoveryOptionsErrorKey: ErrorUserInfoKey - RecoveryAttempterErrorKey: ErrorUserInfoKey - HelpAnchorErrorKey: ErrorUserInfoKey - DebugDescriptionErrorKey: ErrorUserInfoKey - LocalizedFailureErrorKey: ErrorUserInfoKey - StringEncodingErrorKey: ErrorUserInfoKey - URLErrorKey: ErrorUserInfoKey - FilePathErrorKey: ErrorUserInfoKey + @(linkage="weak") UnderlyingErrorKey: ErrorUserInfoKey + @(linkage="weak") LocalizedDescriptionKey: ErrorUserInfoKey + @(linkage="weak") LocalizedFailureReasonErrorKey: ErrorUserInfoKey + @(linkage="weak") LocalizedRecoverySuggestionErrorKey: ErrorUserInfoKey + @(linkage="weak") LocalizedRecoveryOptionsErrorKey: ErrorUserInfoKey + @(linkage="weak") RecoveryAttempterErrorKey: ErrorUserInfoKey + @(linkage="weak") HelpAnchorErrorKey: ErrorUserInfoKey + @(linkage="weak") DebugDescriptionErrorKey: ErrorUserInfoKey + @(linkage="weak") LocalizedFailureErrorKey: ErrorUserInfoKey + @(linkage="weak") StringEncodingErrorKey: ErrorUserInfoKey + @(linkage="weak") URLErrorKey: ErrorUserInfoKey + @(linkage="weak") FilePathErrorKey: ErrorUserInfoKey } @(objc_class="NSError") diff --git a/core/sys/darwin/Foundation/NSNumber.odin b/core/sys/darwin/Foundation/NSNumber.odin index 3b8e59419..2630e6daa 100644 --- a/core/sys/darwin/Foundation/NSNumber.odin +++ b/core/sys/darwin/Foundation/NSNumber.odin @@ -16,8 +16,8 @@ Value_valueWithPointer :: proc(pointer: rawptr) -> ^Value { return msgSend(^Value, Value, "valueWithPointer:", pointer) } -Value_initWithBytes :: proc(value: rawptr, type: cstring) -> ^Value { - return msgSend(^Value, Value, "initWithBytes:objCType:", value, type) +Value_initWithBytes :: proc(self: ^Value, value: rawptr, type: cstring) -> ^Value { + return msgSend(^Value, self, "initWithBytes:objCType:", value, type) } Value_initWithCoder :: proc(coder: ^Coder) -> ^Value { @@ -46,19 +46,19 @@ Value_pointerValue :: proc(self: ^Value) -> rawptr { Number :: struct{using _: Copying(Number), using _: Value} -Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) } -Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) } -Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) } -Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) } -Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) } -Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) } -Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) } -Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) } -Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) } -Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) } -Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) } -Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) } -Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) } +Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) } +Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) } +Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) } +Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) } +Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) } +Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) } +Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) } +Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) } +Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) } +Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) } +Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) } +Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) } +Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) } Number_number :: proc{ Number_numberWithI8, diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin index 5e2f85ceb..d61f8e947 100644 --- a/core/sys/darwin/Foundation/NSObject.odin +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -24,7 +24,7 @@ Copying :: struct($T: typeid) {using _: Object} alloc :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, T, "alloc") } -init :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object){ +init :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, self, "init") } retain :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) { From c3809d7b84fedb633eaf599bcb9a8cb0534ba2ee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Feb 2022 21:46:26 +0000 Subject: [PATCH 0129/1052] Fix typo --- core/sys/darwin/Foundation/NSString.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin index 857e27f12..86c8cabea 100644 --- a/core/sys/darwin/Foundation/NSString.odin +++ b/core/sys/darwin/Foundation/NSString.odin @@ -87,12 +87,12 @@ String_cStringUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> return msgSend(cstring, self, "cStringUsingEncoding:", encoding) } -String_UTFString :: proc(self: ^String) -> cstring { - return msgSend(cstring, self, "UTFString") +String_UTF8String :: proc(self: ^String) -> cstring { + return msgSend(cstring, self, "UTF8String") } String_OdinString :: proc(self: ^String) -> string { - return string(String_UTFString(self)) + return string(String_UTF8String(self)) } String_maximumLengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger { From 416413bebfcddf2b7ae2bf20fb01b675339297eb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Feb 2022 14:35:10 +0000 Subject: [PATCH 0130/1052] Begin work on `Metal` --- vendor/Metal/MTLAccelerationStructure.odin | 270 ++++++++++++++++++ .../Metal/MTLAccelerationStructureTypes.odin | 10 + vendor/Metal/MTLRenderPipeline.odin | 74 +++++ .../Metal/MTLStageInputOutputDescriptor.odin | 76 +++++ vendor/Metal/Metal.odin | 22 ++ vendor/Metal/NSBuffer.odin | 5 + vendor/Metal/NSResource.odin | 5 + 7 files changed, 462 insertions(+) create mode 100644 vendor/Metal/MTLAccelerationStructure.odin create mode 100644 vendor/Metal/MTLAccelerationStructureTypes.odin create mode 100644 vendor/Metal/MTLRenderPipeline.odin create mode 100644 vendor/Metal/MTLStageInputOutputDescriptor.odin create mode 100644 vendor/Metal/Metal.odin create mode 100644 vendor/Metal/NSBuffer.odin create mode 100644 vendor/Metal/NSResource.odin diff --git a/vendor/Metal/MTLAccelerationStructure.odin b/vendor/Metal/MTLAccelerationStructure.odin new file mode 100644 index 000000000..342df3d07 --- /dev/null +++ b/vendor/Metal/MTLAccelerationStructure.odin @@ -0,0 +1,270 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +AccelerationStructureUsage :: distinct bit_set[AccelerationStructureUsageFlag; NS.UInteger] +AccelerationStructureUsageFlag :: enum NS.UInteger { + Refit = 0, + PreferFastBuild = 1, + ExtendedLimits = 2, +} +AccelerationStructureUsageNone :: AccelerationStructureUsage{} + +AccelerationStructureInstanceOptions :: distinct bit_set[AccelerationStructureInstanceOption; u32] +AccelerationStructureInstanceOption :: enum u32 { + DisableTriangleCulling = 0, + TriangleFrontFacingWindingCounterClockwise = 1, + Opaque = 2, + NonOpaque = 3, +} +AccelerationStructureInstanceOptionNone :: AccelerationStructureInstanceOptions{} + +MotionBorderMode :: enum u32 { + Clamp = 0, + Vanish = 1, +} + +AccelerationStructureInstanceDescriptor :: struct #packed { + transformationMatrix: PackedFloat4x3, + options: AccelerationStructureInstanceOptions, + mask: u32, + intersectionFunctionTableOffset: u32, + accelerationStructureIndex: u32, +} + +AccelerationStructureUserIDInstanceDescriptor :: struct #packed { + transformationMatrix: PackedFloat4x3, + options: AccelerationStructureInstanceOptions, + mask: u32, + intersectionFunctionTableOffset: u32, + accelerationStructureIndex: u32, + userID: u32, +} + +AccelerationStructureInstanceDescriptorType :: enum NS.UInteger { + Default = 0, + UserID = 1, + Motion = 2, +} + +AccelerationStructureMotionInstanceDescriptor :: struct #packed { + options: AccelerationStructureInstanceOptions, + mask: u32, + intersectionFunctionTableOffset: u32, + accelerationStructureIndex: u32, + userID: u32, + motionTransformsStartIndex: u32, + motionTransformsCount: u32, + motionStartBorderMode: MotionBorderMode, + motionEndBorderMode: MotionBorderMode, + motionStartTime: f32, + motionEndTime: f32, +} + +@(objc_class="NSAccelerationStructureDescriptor") +AccelerationStructureDescriptor :: struct { using _: NS.Copying(AccelerationStructureDescriptor) } + +@(objc_class="NSAccelerationStructureGeometryDescriptor") +AccelerationStructureGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureGeometryDescriptor) } + +@(objc_class="NSPrimitiveAccelerationStructureDescriptor") +PrimitiveAccelerationStructureDescriptor :: struct { using _: NS.Copying(PrimitiveAccelerationStructureDescriptor), using _: AccelerationStructureDescriptor } + +@(objc_class="NSAccelerationStructureTriangleGeometryDescriptor") +AccelerationStructureTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureTriangleGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } + +@(objc_class="NSAccelerationStructureBoundingBoxGeometryDescriptor") +AccelerationStructureBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureBoundingBoxGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } + +@(objc_class="NSMotionKeyframeData") +MotionKeyframeData :: struct { using _: NS.Object } + +@(objc_class="NSAccelerationStructureMotionTriangleGeometryDescriptor") +AccelerationStructureMotionTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionTriangleGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } + +@(objc_class="NSAccelerationStructureMotionBoundingBoxGeometryDescriptor") +AccelerationStructureMotionBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionBoundingBoxGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } + +@(objc_class="NSInstanceAccelerationStructureDescriptor") +InstanceAccelerationStructureDescriptor :: struct { using _: NS.Copying(InstanceAccelerationStructureDescriptor), using _: AccelerationStructureGeometryDescriptor } + +@(objc_class="NSAccelerationStructure") +AccelerationStructure :: struct { using _: NS.Object } + + + +AccelerationStructureDescriptor_usage :: proc(self: ^AccelerationStructureDescriptor) -> AccelerationStructureUsage { + return msgSend(AccelerationStructureUsage, self, "usage") +} + +AccelerationStructureGeometryDescriptor_intersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "intersectionFunctionTableOffset") +} + +AccelerationStructureGeometryDescriptor_setIntersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor, intersectionFunctionTableOffset: NS.UInteger) { + msgSend(nil, self, "setIntersectionFunctionTableOffset:", intersectionFunctionTableOffset) +} + +AccelerationStructureGeometryDescriptor_opaque :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { + return msgSend(BOOL, self, "opaque") +} + +AccelerationStructureGeometryDescriptor_setOpaque :: proc(self: ^AccelerationStructureGeometryDescriptor, opaque: BOOL) { + msgSend(nil, self, "setOpaque:", opaque) +} + +AccelerationStructureGeometryDescriptor_allowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { + return msgSend(BOOL, self, "allowDuplicateIntersectionFunctionInvocation") +} + +AccelerationStructureGeometryDescriptor_setAllowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor, allowDuplicateIntersectionFunctionInvocation: BOOL) { + msgSend(nil, self, "setAllowDuplicateIntersectionFunctionInvocation:", allowDuplicateIntersectionFunctionInvocation) +} + + +AccelerationStructureGeometryDescriptor_label :: proc(self: ^AccelerationStructureGeometryDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} + +AccelerationStructureGeometryDescriptor_setLabel :: proc(self: ^AccelerationStructureGeometryDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +PrimitiveAccelerationStructureDescriptor_geometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (descriptors: ^NS.Array(^NS.Object)) { + return msgSend(type_of(descriptors), self, "geometryDescriptors") +} + +PrimitiveAccelerationStructureDescriptor_setGeometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor, descriptors: ^NS.Array(^NS.Object)) { + msgSend(nil, self, "setGeometryDescriptors:", descriptors) +} + +PrimitiveAccelerationStructureDescriptor_motionStartBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> MotionBorderMode { + return msgSend(MotionBorderMode, self, "motionStartBorderMode") +} +PrimitiveAccelerationStructureDescriptor_setMotionStartBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionStartBorderMode: MotionBorderMode) { + msgSend(nil, self, "setMotionStartBorderMode:", motionStartBorderMode) +} + +PrimitiveAccelerationStructureDescriptor_motionEndBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> MotionBorderMode { + return msgSend(MotionBorderMode, self, "motionEndBorderMode") +} +PrimitiveAccelerationStructureDescriptor_setMotionEndBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionEndBorderMode: MotionBorderMode) { + msgSend(nil, self, "setMotionEndBorderMode:", motionEndBorderMode) +} + +PrimitiveAccelerationStructureDescriptor_motionStartTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (motionStartTime: f32) { + return msgSend(f32, self, "motionStartTime") +} +PrimitiveAccelerationStructureDescriptor_setMotionStartTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionStartTime: f32) { + msgSend(nil, self, "setMotionStartTime:", motionStartTime) +} + + +PrimitiveAccelerationStructureDescriptor_motionEndTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (motionEndTime: f32) { + return msgSend(f32, self, "motionEndTime") +} +PrimitiveAccelerationStructureDescriptor_setMotionEndTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionEndTime: f32) { + msgSend(nil, self, "setMotionEndTime:", motionEndTime) +} + + +PrimitiveAccelerationStructureDescriptor_motionKeyframeCount :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (motionKeyframeCount: NS.UInteger) { + return msgSend(NS.UInteger, self, "motionKeyframeCount") +} +PrimitiveAccelerationStructureDescriptor_setmotionKeyframeCount :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionKeyframeCount: NS.UInteger) { + msgSend(nil, self, "setMotionKeyframeCount:", motionKeyframeCount) +} + +PrimitiveAccelerationStructureDescriptor_descriptor :: proc() -> ^PrimitiveAccelerationStructureDescriptor { + return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "descriptor") +} + + +AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "vertexBuffer") +} +AccelerationStructureTriangleGeometryDescriptor_setVertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, buffer: ^Buffer) { + msgSend(nil, self, "setVertexBuffer:", buffer) +} + +AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "vertexBufferOffset") +} +AccelerationStructureTriangleGeometryDescriptor_setVertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBufferOffset: NS.UInteger) { + msgSend(nil, self, "setVertexBufferOffset:", vertexBufferOffset) +} + +AccelerationStructureTriangleGeometryDescriptor_vertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "vertexStride") +} +AccelerationStructureTriangleGeometryDescriptor_setVertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexStride: NS.UInteger) { + msgSend(nil, self, "setVertexStride:", vertexStride) +} + +AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "indexBuffer") +} +AccelerationStructureTriangleGeometryDescriptor_setIndexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, buffer: ^Buffer) { + msgSend(nil, self, "setIndexBuffer:", buffer) +} + +AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "indexBufferOffset") +} +AccelerationStructureTriangleGeometryDescriptor_setIndexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBufferOffset: NS.UInteger) { + msgSend(nil, self, "setIndexBufferOffset:", indexBufferOffset) +} + + + +AccelerationStructureTriangleGeometryDescriptor_indexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> IndexType { + return msgSend(IndexType, self, "indexType") +} +AccelerationStructureTriangleGeometryDescriptor_setIndexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indextype: IndexType) { + msgSend(nil, self, "setIndexType:", indextype) +} + +AccelerationStructureTriangleGeometryDescriptor_triangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "triangleCount") +} +AccelerationStructureTriangleGeometryDescriptor_setTriangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, triangleCount: NS.UInteger) { + msgSend(nil, self, "setTriangleCount", triangleCount) +} + + +AccelerationStructureTriangleGeometryDescriptor_descriptor :: proc() -> ^AccelerationStructureTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "descriptor") +} + +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "boundingBoxBuffer") +} + +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, buffer: ^Buffer) { + msgSend(nil, self, "setBoundingBoxBuffer:", buffer) +} + +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxBufferOffset") +} + +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBufferOffset: NS.UInteger) { + msgSend(nil, self, "setBoundingBoxBufferOffset:", boundingBoxBufferOffset) +} + + +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxStride") +} + +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxStride: NS.UInteger) { + msgSend(nil, self, "setBoundingBoxStride:", boundingBoxStride) +} + +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxCount") +} + +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxCount: NS.UInteger) { + msgSend(nil, self, "setBoundingBoxCount:", boundingBoxCount) +} diff --git a/vendor/Metal/MTLAccelerationStructureTypes.odin b/vendor/Metal/MTLAccelerationStructureTypes.odin new file mode 100644 index 000000000..eba672836 --- /dev/null +++ b/vendor/Metal/MTLAccelerationStructureTypes.odin @@ -0,0 +1,10 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +PackedFloat3 :: distinct [3]f32 +PackedFloat4x3 :: distinct [4]PackedFloat3 + +AxisAlignedBoundingBox :: struct{ + min, ax: PackedFloat3, +} \ No newline at end of file diff --git a/vendor/Metal/MTLRenderPipeline.odin b/vendor/Metal/MTLRenderPipeline.odin new file mode 100644 index 000000000..c05c02c64 --- /dev/null +++ b/vendor/Metal/MTLRenderPipeline.odin @@ -0,0 +1,74 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +BlendFactor :: enum NS.UInteger { + Zero = 0, + One = 1, + SourceColor = 2, + OneMinusSourceColor = 3, + SourceAlpha = 4, + OneMinusSourceAlpha = 5, + DestinationColor = 6, + OneMinusDestinationColor = 7, + DestinationAlpha = 8, + OneMinusDestinationAlpha = 9, + SourceAlphaSaturated = 10, + BlendColor = 11, + OneMinusBlendColor = 12, + BlendAlpha = 13, + OneMinusBlendAlpha = 14, + Source1Color = 15, + OneMinusSource1Color = 16, + Source1Alpha = 17, + OneMinusSource1Alpha = 18, +} + +BlendOperation :: enum NS.UInteger { + Add = 0, + Subtract = 1, + ReverseSubtract = 2, + Min = 3, + Max = 4, +} + +ColorWriteMaskOption :: enum NS.UInteger { + Alpha = 0, + Blue = 1, + Green = 2, + Red = 3, +} +ColorWriteMask :: distinct bit_set[ColorWriteMaskOption; NS.UInteger] +ColorWriteMaskNone :: ColorWriteMask{} +ColorWriteMaskAll :: ColorWriteMask{.Alpha, .Blue, .Green, .Red} + +PrimitiveTopologyClass :: enum NS.UInteger { + ClassUnspecified = 0, + ClassPoint = 1, + ClassLine = 2, + ClassTriangle = 3, +} + +TessellationPartitionMode :: enum NS.UInteger { + ModePow2 = 0, + ModeInteger = 1, + ModeFractionalOdd = 2, + ModeFractionalEven = 3, +} + +TessellationFactorStepFunction :: enum NS.UInteger { + Constant = 0, + PerPatch = 1, + PerInstance = 2, + PerPatchAndPerInstance = 3, +} + +TessellationFactorFormat :: enum NS.UInteger { + Half = 0, +} + +TessellationControlPointIndexType :: enum NS.UInteger { + None = 0, + UInt16 = 1, + UInt32 = 2, +} diff --git a/vendor/Metal/MTLStageInputOutputDescriptor.odin b/vendor/Metal/MTLStageInputOutputDescriptor.odin new file mode 100644 index 000000000..98ff66ce5 --- /dev/null +++ b/vendor/Metal/MTLStageInputOutputDescriptor.odin @@ -0,0 +1,76 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + + +AttributeFormat :: enum NS.UInteger { + Invalid = 0, + UChar2 = 1, + UChar3 = 2, + UChar4 = 3, + Char2 = 4, + Char3 = 5, + Char4 = 6, + UChar2Normalized = 7, + UChar3Normalized = 8, + UChar4Normalized = 9, + Char2Normalized = 10, + Char3Normalized = 11, + Char4Normalized = 12, + UShort2 = 13, + UShort3 = 14, + UShort4 = 15, + Short2 = 16, + Short3 = 17, + Short4 = 18, + UShort2Normalized = 19, + UShort3Normalized = 20, + UShort4Normalized = 21, + Short2Normalized = 22, + Short3Normalized = 23, + Short4Normalized = 24, + Half2 = 25, + Half3 = 26, + Half4 = 27, + Float = 28, + Float2 = 29, + Float3 = 30, + Float4 = 31, + Int = 32, + Int2 = 33, + Int3 = 34, + Int4 = 35, + UInt = 36, + UInt2 = 37, + UInt3 = 38, + UInt4 = 39, + Int1010102Normalized = 40, + UInt1010102Normalized = 41, + UChar4Normalized_BGRA = 42, + UChar = 45, + Char = 46, + UCharNormalized = 47, + CharNormalized = 48, + UShort = 49, + Short = 50, + UShortNormalized = 51, + ShortNormalized = 52, + Half = 53, +} + +IndexType :: enum NS.UInteger { + UInt16 = 0, + UInt32 = 1, +} + +StepFunction :: enum NS.UInteger { + Constant = 0, + PerVertex = 1, + PerInstance = 2, + PerPatch = 3, + PerPatchControlPoint = 4, + ThreadPositionInGridX = 5, + ThreadPositionInGridY = 6, + ThreadPositionInGridXIndexed = 7, + ThreadPositionInGridYIndexed = 8, +} \ No newline at end of file diff --git a/vendor/Metal/Metal.odin b/vendor/Metal/Metal.odin new file mode 100644 index 000000000..eefada00d --- /dev/null +++ b/vendor/Metal/Metal.odin @@ -0,0 +1,22 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" +import "core:intrinsics" + +alloc :: NS.alloc +init :: NS.init +retain :: NS.retain +release :: NS.release +autorelease :: NS.autorelease +retainCount :: NS.retainCount +copy :: NS.copy +hash :: NS.hash +isEqual :: NS.isEqual +description :: NS.description +debugDescription :: NS.debugDescription +bridgingCast :: NS.bridgingCast + +@(private) +msgSend :: intrinsics.objc_send + +BOOL :: NS.BOOL \ No newline at end of file diff --git a/vendor/Metal/NSBuffer.odin b/vendor/Metal/NSBuffer.odin new file mode 100644 index 000000000..9f7a83c1a --- /dev/null +++ b/vendor/Metal/NSBuffer.odin @@ -0,0 +1,5 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +Buffer :: struct { using _: Resource } \ No newline at end of file diff --git a/vendor/Metal/NSResource.odin b/vendor/Metal/NSResource.odin new file mode 100644 index 000000000..34bc0267c --- /dev/null +++ b/vendor/Metal/NSResource.odin @@ -0,0 +1,5 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +Resource :: struct { using _: NS.Object } \ No newline at end of file From f77cd5533d8fdda0abc9052e63c1f13a57db73ae Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Fri, 11 Feb 2022 08:10:48 -0800 Subject: [PATCH 0131/1052] Add fork and personality --- core/os/os_linux.odin | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 3288388ea..3a9136b43 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -11,6 +11,7 @@ import "core:intrinsics" import "core:sys/unix" Handle :: distinct i32 +Pid :: distinct i32 File_Time :: distinct u64 Errno :: distinct i32 @@ -150,6 +151,8 @@ ERFKILL: Errno : 132 /* Operation not possible due to RF-kill */ EHWPOISON: Errno : 133 /* Memory page has hardware error */ +ADDR_NO_RANDOMIZE :: 0x40000 + O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 O_RDWR :: 0x00002 @@ -270,6 +273,15 @@ AT_FDCWD :: -100 AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) +_unix_personality :: proc(persona: u64) -> int { + return int(intrinsics.syscall(unix.SYS_personality, uintptr(persona))) +} + +_unix_fork :: proc() -> Pid { + res := int(intrinsics.syscall(unix.SYS_fork)) + return -1 if res < 0 else Pid(res) +} + _unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle { when ODIN_ARCH != "arm64" { res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) @@ -431,6 +443,22 @@ get_last_error :: proc() -> int { return __errno_location()^ } +personality :: proc(persona: u64) -> (Errno) { + res := _unix_personality(persona) + if res == -1 { + return _get_errno(res) + } + return ERROR_NONE +} + +fork :: proc() -> (Pid, Errno) { + pid := _unix_fork() + if pid == -1 { + return -1, _get_errno(int(pid)) + } + return pid, ERROR_NONE +} + open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { cstr := strings.clone_to_cstring(path) handle := _unix_open(cstr, flags, mode) From 251edf7bc7eff05b1dcead77133fe1a3ec2e973c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Fri, 11 Feb 2022 17:22:14 +0100 Subject: [PATCH 0132/1052] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a1f96d20b..c62fcd36b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,7 +79,7 @@ jobs: make timeout-minutes: 10 build_windows: - runs-on: windows-latest + runs-on: windows-2019 steps: - uses: actions/checkout@v1 - name: build Odin From 1c57d1c01921284e82329933df558bf9edd317bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Fri, 11 Feb 2022 17:22:33 +0100 Subject: [PATCH 0133/1052] Update nightly.yml --- .github/workflows/nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 2b33c45a8..7175843f5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -7,7 +7,7 @@ on: jobs: build_windows: - runs-on: windows-latest + runs-on: windows-2019 steps: - uses: actions/checkout@v1 - name: build Odin From f8afda3b221f6c2279a393c2c0fb8ab7ea1d59df Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 11 Feb 2022 22:54:51 +0000 Subject: [PATCH 0134/1052] Add more objc attributes --- core/sys/darwin/Foundation/NSArray.odin | 36 +++-- .../darwin/Foundation/NSAutoreleasePool.odin | 15 +- core/sys/darwin/Foundation/NSBundle.odin | 56 +++++-- core/sys/darwin/Foundation/NSData.odin | 12 ++ core/sys/darwin/Foundation/NSDate.odin | 12 ++ core/sys/darwin/Foundation/NSDictionary.odin | 18 +++ core/sys/darwin/Foundation/NSEnumerator.odin | 15 +- core/sys/darwin/Foundation/NSError.odin | 22 ++- core/sys/darwin/Foundation/NSLock.odin | 24 +++ .../sys/darwin/Foundation/NSNotification.odin | 15 ++ core/sys/darwin/Foundation/NSNumber.odin | 145 ++++++++++-------- core/sys/darwin/Foundation/NSObject.odin | 36 +++-- core/sys/darwin/Foundation/NSString.odin | 24 +++ core/sys/darwin/Foundation/NSURL.odin | 12 ++ src/check_builtin.cpp | 8 +- src/check_decl.cpp | 63 ++++++++ src/check_type.cpp | 2 + src/checker.cpp | 50 +++++- src/checker.hpp | 6 +- src/entity.cpp | 23 +++ src/llvm_backend_expr.cpp | 11 +- src/main.cpp | 32 +--- src/string.cpp | 31 ++++ src/types.cpp | 62 ++++++++ 24 files changed, 588 insertions(+), 142 deletions(-) diff --git a/core/sys/darwin/Foundation/NSArray.odin b/core/sys/darwin/Foundation/NSArray.odin index 435e239a2..e17223ff7 100644 --- a/core/sys/darwin/Foundation/NSArray.odin +++ b/core/sys/darwin/Foundation/NSArray.odin @@ -3,26 +3,40 @@ package objc_Foundation import "core:intrinsics" @(objc_class="NSArray") -Array :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { - using _: Copying(Array(T)), +Array :: struct { + using _: Copying(Array), } -Array_initWithObjects :: proc(self: ^$A/Array($T), objects: [^]^Object, count: UInteger) -> ^A { - return msgSend(^A, "initWithObjects:count:", objects, count) +@(objc_type=Array, objc_class_name="alloc") +Array_alloc :: proc() -> ^Array { + return msgSend(^Array, Array, "alloc") } -Array_initWithCoder :: proc(self: ^$A/Array($T), coder: ^Coder) -> ^A { - return msgSend(^A, "initWithCoder:", coder) +@(objc_type=Array, objc_name="init") +Array_init :: proc(self: ^Array) -> ^Array { + return msgSend(^Array, self, "init") } -Array_objectAtIndex :: proc(self: ^Array($T), index: UInteger) -> ^Object { +@(objc_type=Array, objc_name="initWithObjects") +Array_initWithObjects :: proc(self: ^Array, objects: [^]^Object, count: UInteger) -> ^Array { + return msgSend(^Array, self, "initWithObjects:count:", objects, count) +} + +@(objc_type=Array, objc_name="initWithCoder") +Array_initWithCoder :: proc(self: ^Array, coder: ^Coder) -> ^Array { + return msgSend(^Array, self, "initWithCoder:", coder) +} + +@(objc_type=Array, objc_name="object") +Array_object :: proc(self: ^Array, index: UInteger) -> ^Object { return msgSend(^Object, self, "objectAtIndex:", index) } - -Array_object :: proc(self: ^Array($T), index: UInteger) -> T { - return (T)(Array_objectAtIndex(self, index)) +@(objc_type=Array, objc_name="objectAs") +Array_objectAs :: proc(self: ^Array, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { + return (T)(Array_object(self, index)) } -Array_count :: proc(self: ^Array($T)) -> UInteger { +@(objc_type=Array, objc_name="count") +Array_count :: proc(self: ^Array) -> UInteger { return msgSend(UInteger, self, "count") } diff --git a/core/sys/darwin/Foundation/NSAutoreleasePool.odin b/core/sys/darwin/Foundation/NSAutoreleasePool.odin index 47cbc0e9a..17ec88ba1 100644 --- a/core/sys/darwin/Foundation/NSAutoreleasePool.odin +++ b/core/sys/darwin/Foundation/NSAutoreleasePool.odin @@ -3,12 +3,25 @@ package objc_Foundation @(objc_class="NSAutoreleasePool") AutoreleasePool :: struct {using _: Object} +@(objc_type=AutoreleasePool, objc_class_name="alloc") +AutoreleasePool_alloc :: proc() -> ^AutoreleasePool { + return msgSend(^AutoreleasePool, AutoreleasePool, "alloc") +} + +@(objc_type=AutoreleasePool, objc_name="init") +AutoreleasePool_init :: proc(self: ^AutoreleasePool) -> ^AutoreleasePool { + return msgSend(^AutoreleasePool, self, "init") +} + +@(objc_type=AutoreleasePool, objc_name="drain") AutoreleasePool_drain :: proc(self: ^AutoreleasePool) { msgSend(nil, self, "drain") } +@(objc_type=AutoreleasePool, objc_name="addObject") AutoreleasePool_addObject :: proc(self: ^AutoreleasePool, obj: ^Object) { msgSend(nil, self, "addObject:", obj) } +@(objc_type=AutoreleasePool, objc_name="showPools") AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) { msgSend(nil, self, "showPools") } @@ -16,5 +29,5 @@ AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) { @(deferred_out=AutoreleasePool_drain) scoped_autoreleasepool :: proc() -> ^AutoreleasePool { - return init(alloc(AutoreleasePool)) + return AutoreleasePool.alloc()->init() } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSBundle.odin b/core/sys/darwin/Foundation/NSBundle.odin index 375e15b65..a18809b7e 100644 --- a/core/sys/darwin/Foundation/NSBundle.odin +++ b/core/sys/darwin/Foundation/NSBundle.odin @@ -3,98 +3,120 @@ package objc_Foundation @(objc_class="NSBundle") Bundle :: struct { using _: Object } +@(objc_type=Bundle, objc_class_name="mainBundle") Bundle_mainBundle :: proc() -> ^Bundle { return msgSend(^Bundle, Bundle, "mainBundle") } +@(objc_type=Bundle, objc_class_name="bundleWithPath") Bundle_bundleWithPath :: proc(path: ^String) -> ^Bundle { return msgSend(^Bundle, Bundle, "bundleWithPath:", path) } +@(objc_type=Bundle, objc_class_name="bundleWithURL") Bundle_bundleWithURL :: proc(url: ^URL) -> ^Bundle { return msgSend(^Bundle, Bundle, "bundleWithUrl:", url) } -Bundle_bundle :: proc{ - Bundle_bundleWithPath, - Bundle_bundleWithURL, + + +@(objc_type=Bundle, objc_class_name="alloc") +Bundle_alloc :: proc() -> ^Bundle { + return msgSend(^Bundle, Bundle, "alloc") } +@(objc_type=Bundle, objc_name="init") +Bundle_init :: proc(self: ^Bundle) -> ^Bundle { + return msgSend(^Bundle, self, "init") +} +@(objc_type=Bundle, objc_name="initWithPath") Bundle_initWithPath :: proc(self: ^Bundle, path: ^String) -> ^Bundle { return msgSend(^Bundle, self, "initWithPath:", path) } +@(objc_type=Bundle, objc_name="initWithURL") Bundle_initWithURL :: proc(self: ^Bundle, url: ^URL) -> ^Bundle { return msgSend(^Bundle, self, "initWithUrl:", url) } -Bundle_init :: proc{ - Bundle_initWithPath, - Bundle_initWithURL, -} - -Bundle_allBundles :: proc() -> (all: ^Array(^Bundle)) { +@(objc_type=Bundle, objc_name="allBundles") +Bundle_allBundles :: proc() -> (all: ^Array) { return msgSend(type_of(all), Bundle, "allBundles") } -Bundle_allFrameworks :: proc() -> (all: ^Array(^Object)) { +@(objc_type=Bundle, objc_name="allFrameworks") +Bundle_allFrameworks :: proc() -> (all: ^Array) { return msgSend(type_of(all), Bundle, "allFrameworks") } +@(objc_type=Bundle, objc_name="load") Bundle_load :: proc(self: ^Bundle) -> BOOL { return msgSend(BOOL, self, "load") } +@(objc_type=Bundle, objc_name="unload") Bundle_unload :: proc(self: ^Bundle) -> BOOL { return msgSend(BOOL, self, "unload") } +@(objc_type=Bundle, objc_name="isLoaded") Bundle_isLoaded :: proc(self: ^Bundle) -> BOOL { return msgSend(BOOL, self, "isLoaded") } +@(objc_type=Bundle, objc_name="preflightAndReturnError") Bundle_preflightAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) { ok = msgSend(BOOL, self, "preflightAndReturnError:", &error) return } +@(objc_type=Bundle, objc_name="loadAndReturnError") Bundle_loadAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) { ok = msgSend(BOOL, self, "loadAndReturnError:", &error) return } +@(objc_type=Bundle, objc_name="bundleURL") Bundle_bundleURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "bundleURL") } +@(objc_type=Bundle, objc_name="resourceURL") Bundle_resourceURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "resourceURL") } +@(objc_type=Bundle, objc_name="executableURL") Bundle_executableURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "executableURL") } +@(objc_type=Bundle, objc_name="URLForAuxiliaryExecutable") Bundle_URLForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^URL { return msgSend(^URL, self, "URLForAuxiliaryExecutable:", executableName) } +@(objc_type=Bundle, objc_name="privateFrameworksURL") Bundle_privateFrameworksURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "privateFrameworksURL") } +@(objc_type=Bundle, objc_name="sharedFrameworksURL") Bundle_sharedFrameworksURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "sharedFrameworksURL") } +@(objc_type=Bundle, objc_name="sharedSupportURL") Bundle_sharedSupportURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "sharedSupportURL") } +@(objc_type=Bundle, objc_name="builtInPlugInsURL") Bundle_builtInPlugInsURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "builtInPlugInsURL") } +@(objc_type=Bundle, objc_name="appStoreReceiptURL") Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "appStoreReceiptURL") } @@ -102,60 +124,74 @@ Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL { +@(objc_type=Bundle, objc_name="bundlePath") Bundle_bundlePath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "bundlePath") } +@(objc_type=Bundle, objc_name="resourcePath") Bundle_resourcePath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "resourcePath") } +@(objc_type=Bundle, objc_name="executablePath") Bundle_executablePath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "executablePath") } +@(objc_type=Bundle, objc_name="PathForAuxiliaryExecutable") Bundle_PathForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^String { return msgSend(^String, self, "PathForAuxiliaryExecutable:", executableName) } +@(objc_type=Bundle, objc_name="privateFrameworksPath") Bundle_privateFrameworksPath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "privateFrameworksPath") } +@(objc_type=Bundle, objc_name="sharedFrameworksPath") Bundle_sharedFrameworksPath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "sharedFrameworksPath") } +@(objc_type=Bundle, objc_name="sharedSupportPath") Bundle_sharedSupportPath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "sharedSupportPath") } +@(objc_type=Bundle, objc_name="builtInPlugInsPath") Bundle_builtInPlugInsPath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "builtInPlugInsPath") } +@(objc_type=Bundle, objc_name="appStoreReceiptPath") Bundle_appStoreReceiptPath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "appStoreReceiptPath") } +@(objc_type=Bundle, objc_name="bundleIdentifier") Bundle_bundleIdentifier :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "bundleIdentifier") } +@(objc_type=Bundle, objc_name="infoDictionary") Bundle_infoDictionary :: proc(self: ^Bundle) -> ^Dictionary { return msgSend(^Dictionary, self, "infoDictionary") } +@(objc_type=Bundle, objc_name="localizedInfoDictionary") Bundle_localizedInfoDictionary :: proc(self: ^Bundle) -> ^Dictionary { return msgSend(^Dictionary, self, "localizedInfoDictionary") } +@(objc_type=Bundle, objc_name="objectForInfoDictionaryKey") Bundle_objectForInfoDictionaryKey :: proc(self: ^Bundle, key: ^String) -> ^Object { return msgSend(^Object, self, "objectForInfoDictionaryKey:", key) } +@(objc_type=Bundle, objc_name="localizedStringForKey") Bundle_localizedStringForKey :: proc(self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String { return msgSend(^String, self, "localizedStringForKey:value:table:", key, value, tableName) } diff --git a/core/sys/darwin/Foundation/NSData.odin b/core/sys/darwin/Foundation/NSData.odin index 93bb3ae0e..e28f6a644 100644 --- a/core/sys/darwin/Foundation/NSData.odin +++ b/core/sys/darwin/Foundation/NSData.odin @@ -3,10 +3,22 @@ package objc_Foundation @(objc_class="NSData") Data :: struct {using _: Copying(Data)} +@(objc_type=Data, objc_class_name="alloc") +Data_alloc :: proc() -> ^Data { + return msgSend(^Data, Data, "alloc") +} + +@(objc_type=Data, objc_name="init") +Data_init :: proc(self: ^Data) -> ^Data { + return msgSend(^Data, self, "init") +} + +@(objc_type=Data, objc_name="mutableBytes") Data_mutableBytes :: proc(self: ^Data) -> rawptr { return msgSend(rawptr, self, "mutableBytes") } +@(objc_type=Data, objc_name="length") Data_length :: proc(self: ^Data) -> UInteger { return msgSend(UInteger, self, "length") } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSDate.odin b/core/sys/darwin/Foundation/NSDate.odin index 4b298ee24..85bb14c3e 100644 --- a/core/sys/darwin/Foundation/NSDate.odin +++ b/core/sys/darwin/Foundation/NSDate.odin @@ -3,6 +3,18 @@ package objc_Foundation @(objc_class="NSDate") Date :: struct {using _: Copying(Date)} +@(objc_type=Date, objc_class_name="alloc") +Date_alloc :: proc() -> ^Date { + return msgSend(^Date, Date, "alloc") +} + +@(objc_type=Date, objc_name="init") +Date_init :: proc(self: ^Date) -> ^Date { + return msgSend(^Date, self, "init") +} + + +@(objc_type=Date, objc_name="dateWithTimeIntervalSinceNow") Date_dateWithTimeIntervalSinceNow :: proc(secs: TimeInterval) -> ^Date { return msgSend(^Date, Date, "dateWithTimeIntervalSinceNow:", secs) } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSDictionary.odin b/core/sys/darwin/Foundation/NSDictionary.odin index f82b8cffd..3eb378dc7 100644 --- a/core/sys/darwin/Foundation/NSDictionary.odin +++ b/core/sys/darwin/Foundation/NSDictionary.odin @@ -3,31 +3,49 @@ package objc_Foundation @(objc_class="NSDictionary") Dictionary :: struct {using _: Copying(Dictionary)} +@(objc_type=Dictionary, objc_class_name="dictionary") Dictionary_dictionary :: proc() -> ^Dictionary { return msgSend(^Dictionary, Dictionary, "dictionary") } +@(objc_type=Dictionary, objc_class_name="dictionaryWithObject") Dictionary_dictionaryWithObject :: proc(object: ^Object, forKey: ^Object) -> ^Dictionary { return msgSend(^Dictionary, Dictionary, "dictionaryWithObject:forKey:", object, forKey) } +@(objc_type=Dictionary, objc_class_name="dictionaryWithObjects") Dictionary_dictionaryWithObjects :: proc(objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { return msgSend(^Dictionary, Dictionary, "dictionaryWithObjects:forKeys:count", objects, forKeys, count) } +@(objc_type=Dictionary, objc_class_name="alloc") +Dictionary_alloc :: proc() -> ^Dictionary { + return msgSend(^Dictionary, Dictionary, "alloc") +} + +@(objc_type=Dictionary, objc_name="init") +Dictionary_init :: proc(self: ^Dictionary) -> ^Dictionary { + return msgSend(^Dictionary, self, "init") +} + + +@(objc_type=Dictionary, objc_name="initWithObjects") Dictionary_initWithObjects :: proc(self: ^Dictionary, objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { return msgSend(^Dictionary, self, "initWithObjects:forKeys:count", objects, forKeys, count) } +@(objc_type=Dictionary, objc_name="objectForKey") Dictionary_objectForKey :: proc(self: ^Dictionary, key: ^Object) -> ^Object { return msgSend(^Dictionary, self, "objectForKey:", key) } +@(objc_type=Dictionary, objc_name="count") Dictionary_count :: proc(self: ^Dictionary) -> UInteger { return msgSend(UInteger, self, "count") } +@(objc_type=Dictionary, objc_name="keyEnumerator") Dictionary_keyEnumerator :: proc(self: ^Dictionary, $KeyType: typeid) -> (enumerator: ^Enumerator(KeyType)) { return msgSend(type_of(enumerator), self, "keyEnumerator") } diff --git a/core/sys/darwin/Foundation/NSEnumerator.odin b/core/sys/darwin/Foundation/NSEnumerator.odin index b6adf2b98..8a5a32e69 100644 --- a/core/sys/darwin/Foundation/NSEnumerator.odin +++ b/core/sys/darwin/Foundation/NSEnumerator.odin @@ -18,6 +18,19 @@ Enumerator :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics using _: FastEnumeration, } + +@(objc_type=FastEnumeration, objc_class_name="alloc") +FastEnumeration_alloc :: proc() -> ^FastEnumeration { + return msgSend(^FastEnumeration, FastEnumeration, "alloc") +} + +@(objc_type=FastEnumeration, objc_name="init") +FastEnumeration_init :: proc(self: ^FastEnumeration) -> ^FastEnumeration { + return msgSend(^FastEnumeration, self, "init") +} + + +@(objc_type=FastEnumeration, objc_name="countByEnumerating") FastEnumeration_countByEnumerating :: proc(self: ^FastEnumeration, state: ^FastEnumerationState, buffer: [^]^Object, len: UInteger) -> UInteger { return msgSend(UInteger, self, "countByEnumeratingWithState:objects:count:", state, buffer, len) } @@ -26,7 +39,7 @@ Enumerator_nextObject :: proc(self: ^$E/Enumerator($T)) -> T { return msgSend(T, self, "nextObject") } -Enumerator_allObjects :: proc(self: ^$E/Enumerator($T)) -> (all: Array(T)) { +Enumerator_allObjects :: proc(self: ^$E/Enumerator($T)) -> (all: ^Array) { return msgSend(type_of(all), self, "allObjects") } diff --git a/core/sys/darwin/Foundation/NSError.odin b/core/sys/darwin/Foundation/NSError.odin index aebf01035..bff0088e9 100644 --- a/core/sys/darwin/Foundation/NSError.odin +++ b/core/sys/darwin/Foundation/NSError.odin @@ -31,38 +31,58 @@ foreign Foundation { @(objc_class="NSError") Error :: struct { using _: Copying(Error) } + +@(objc_type=Error, objc_class_name="alloc") +Error_alloc :: proc() -> ^Error { + return msgSend(^Error, Error, "alloc") +} + +@(objc_type=Error, objc_name="init") +Error_init :: proc(self: ^Error) -> ^Error { + return msgSend(^Error, self, "init") +} + +@(objc_type=Error, objc_class_name="errorWithDomain") Error_errorWithDomain :: proc(domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error { return msgSend(^Error, Error, "errorWithDomain:code:userInfo:", domain, code, userInfo) } +@(objc_type=Error, objc_name="initWithDomain") Error_initWithDomain :: proc(self: ^Error, domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error { return msgSend(^Error, self, "initWithDomain:code:userInfo:", domain, code, userInfo) } +@(objc_type=Error, objc_name="code") Error_code :: proc(self: ^Error) -> Integer { return msgSend(Integer, self, "code") } +@(objc_type=Error, objc_name="domain") Error_domain :: proc(self: ^Error) -> ErrorDomain { return msgSend(ErrorDomain, self, "domain") } +@(objc_type=Error, objc_name="userInfo") Error_userInfo :: proc(self: ^Error) -> ^Dictionary { return msgSend(^Dictionary, self, "userInfo") } +@(objc_type=Error, objc_name="localizedDescription") Error_localizedDescription :: proc(self: ^Error) -> ^String { return msgSend(^String, self, "localizedDescription") } -Error_localizedRecoveryOptions :: proc(self: ^Error) -> (options: ^Array(^Object)) { +@(objc_type=Error, objc_name="localizedRecoveryOptions") +Error_localizedRecoveryOptions :: proc(self: ^Error) -> (options: ^Array) { return msgSend(type_of(options), self, "localizedRecoveryOptions") } +@(objc_type=Error, objc_name="localizedRecoverySuggestion") Error_localizedRecoverySuggestion :: proc(self: ^Error) -> ^String { return msgSend(^String, self, "localizedRecoverySuggestion") } +@(objc_type=Error, objc_name="localizedFailureReason") Error_localizedFailureReason :: proc(self: ^Error) -> ^String { return msgSend(^String, self, "localizedFailureReason") } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSLock.odin b/core/sys/darwin/Foundation/NSLock.odin index 0e76dfc62..3bcc06eab 100644 --- a/core/sys/darwin/Foundation/NSLock.odin +++ b/core/sys/darwin/Foundation/NSLock.odin @@ -12,18 +12,42 @@ Locking_unlock :: proc(self: ^Locking($T)) { @(objc_class="NSCondition") Condition :: struct {using _: Locking(Condition) } + +@(objc_type=Condition, objc_class_name="alloc") +Condition_alloc :: proc() -> ^Condition { + return msgSend(^Condition, Condition, "alloc") +} + +@(objc_type=Condition, objc_name="init") +Condition_init :: proc(self: ^Condition) -> ^Condition { + return msgSend(^Condition, self, "init") +} + +@(objc_type=Condition, objc_name="wait") Condition_wait :: proc(self: ^Condition) { msgSend(nil, self, "wait") } +@(objc_type=Condition, objc_name="waitUntilDate") Condition_waitUntilDate :: proc(self: ^Condition, limit: ^Date) -> BOOL { return msgSend(BOOL, self, "waitUntilDate:", limit) } +@(objc_type=Condition, objc_name="signal") Condition_signal :: proc(self: ^Condition) { msgSend(nil, self, "signal") } +@(objc_type=Condition, objc_name="broadcast") Condition_broadcast :: proc(self: ^Condition) { msgSend(nil, self, "broadcast") +} + +@(objc_type=Condition, objc_name="lock") +Condition_lock :: proc(self: ^Condition) { + msgSend(nil, self, "lock") +} +@(objc_type=Condition, objc_name="unlock") +Condition_unlock :: proc(self: ^Condition) { + msgSend(nil, self, "unlock") } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSNotification.odin b/core/sys/darwin/Foundation/NSNotification.odin index fa9160cc8..d8b142e53 100644 --- a/core/sys/darwin/Foundation/NSNotification.odin +++ b/core/sys/darwin/Foundation/NSNotification.odin @@ -3,14 +3,29 @@ package objc_Foundation @(objc_class="NSNotification") Notification :: struct{using _: Object} + +@(objc_type=Notification, objc_class_name="alloc") +Notification_alloc :: proc() -> ^Notification { + return msgSend(^Notification, Notification, "alloc") +} + +@(objc_type=Notification, objc_name="init") +Notification_init :: proc(self: ^Notification) -> ^Notification { + return msgSend(^Notification, self, "init") +} + + +@(objc_type=Notification, objc_name="name") Notification_name :: proc(self: ^Notification) -> ^String { return msgSend(^String, self, "name") } +@(objc_type=Notification, objc_name="object") Notification_object :: proc(self: ^Notification) -> ^Object { return msgSend(^Object, self, "object") } +@(objc_type=Notification, objc_name="userInfo") Notification_userInfo :: proc(self: ^Notification) -> ^Dictionary { return msgSend(^Dictionary, self, "userInfo") } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSNumber.odin b/core/sys/darwin/Foundation/NSNumber.odin index 2630e6daa..f77b0866a 100644 --- a/core/sys/darwin/Foundation/NSNumber.odin +++ b/core/sys/darwin/Foundation/NSNumber.odin @@ -8,35 +8,53 @@ import "core:c" @(objc_class="NSValue") Value :: struct{using _: Copying(Value)} +@(objc_type=Value, objc_class_name="alloc") +Value_alloc :: proc() -> ^Value { + return msgSend(^Value, Value, "alloc") +} + +@(objc_type=Value, objc_name="init") +Value_init :: proc(self: ^Value) -> ^Value { + return msgSend(^Value, self, "init") +} + +@(objc_type=Value, objc_class_name="valueWithBytes") Value_valueWithBytes :: proc(value: rawptr, type: cstring) -> ^Value { return msgSend(^Value, Value, "valueWithBytes:objCType:", value, type) } +@(objc_type=Value, objc_class_name="valueWithPointer") Value_valueWithPointer :: proc(pointer: rawptr) -> ^Value { return msgSend(^Value, Value, "valueWithPointer:", pointer) } +@(objc_type=Value, objc_name="initWithBytes") Value_initWithBytes :: proc(self: ^Value, value: rawptr, type: cstring) -> ^Value { return msgSend(^Value, self, "initWithBytes:objCType:", value, type) } -Value_initWithCoder :: proc(coder: ^Coder) -> ^Value { - return msgSend(^Value, Value, "initWithCoder:", coder) +@(objc_type=Value, objc_name="initWithCoder") +Value_initWithCoder :: proc(self: ^Value, coder: ^Coder) -> ^Value { + return msgSend(^Value, self, "initWithCoder:", coder) } +@(objc_type=Value, objc_name="getValue") Value_getValue :: proc(self: ^Value, value: rawptr, size: UInteger) { msgSend(nil, self, "getValue:size:", value, size) } +@(objc_type=Value, objc_name="objCType") Value_objCType :: proc(self: ^Value) -> cstring { return msgSend(cstring, self, "objCType") } +@(objc_type=Value, objc_name="isEqualToValue") Value_isEqualToValue :: proc(self, other: ^Value) -> BOOL { return msgSend(BOOL, self, "isEqualToValue:", other) } +@(objc_type=Value, objc_name="pointerValue") Value_pointerValue :: proc(self: ^Value) -> rawptr { return msgSend(rawptr, self, "pointerValue") } @@ -46,19 +64,29 @@ Value_pointerValue :: proc(self: ^Value) -> rawptr { Number :: struct{using _: Copying(Number), using _: Value} -Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) } -Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) } -Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) } -Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) } -Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) } -Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) } -Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) } -Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) } -Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) } -Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) } -Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) } -Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) } -Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) } +@(objc_type=Number, objc_class_name="alloc") +Number_alloc :: proc() -> ^Number { + return msgSend(^Number, Number, "alloc") +} + +@(objc_type=Number, objc_name="init") +Number_init :: proc(self: ^Number) -> ^Number { + return msgSend(^Number, self, "init") +} + +@(objc_type=Number, objc_class_name="numberWithI8") Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) } +@(objc_type=Number, objc_class_name="numberWithU8") Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) } +@(objc_type=Number, objc_class_name="numberWithI16") Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) } +@(objc_type=Number, objc_class_name="numberWithU16") Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) } +@(objc_type=Number, objc_class_name="numberWithI32") Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) } +@(objc_type=Number, objc_class_name="numberWithU32") Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) } +@(objc_type=Number, objc_class_name="numberWithInt") Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) } +@(objc_type=Number, objc_class_name="numberWithUint") Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) } +@(objc_type=Number, objc_class_name="numberWithU64") Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) } +@(objc_type=Number, objc_class_name="numberWithI64") Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) } +@(objc_type=Number, objc_class_name="numberWithF32") Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) } +@(objc_type=Number, objc_class_name="numberWithF64") Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) } +@(objc_type=Number, objc_class_name="numberWithBool") Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) } Number_number :: proc{ Number_numberWithI8, @@ -76,62 +104,49 @@ Number_number :: proc{ Number_numberWithBool, } -Number_initWithI8 :: proc(self: ^Number, value: i8) -> ^Number { return msgSend(^Number, self, "initWithChar:", value) } -Number_initWithU8 :: proc(self: ^Number, value: u8) -> ^Number { return msgSend(^Number, self, "initWithUnsignedChar:", value) } -Number_initWithI16 :: proc(self: ^Number, value: i16) -> ^Number { return msgSend(^Number, self, "initWithShort:", value) } -Number_initWithU16 :: proc(self: ^Number, value: u16) -> ^Number { return msgSend(^Number, self, "initWithUnsignedShort:", value) } -Number_initWithI32 :: proc(self: ^Number, value: i32) -> ^Number { return msgSend(^Number, self, "initWithInt:", value) } -Number_initWithU32 :: proc(self: ^Number, value: u32) -> ^Number { return msgSend(^Number, self, "initWithUnsignedInt:", value) } -Number_initWithInt :: proc(self: ^Number, value: int) -> ^Number { return msgSend(^Number, self, "initWithLong:", value) } -Number_initWithUint :: proc(self: ^Number, value: uint) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLong:", value) } -Number_initWithU64 :: proc(self: ^Number, value: u64) -> ^Number { return msgSend(^Number, self, "initWithLongLong:", value) } -Number_initWithI64 :: proc(self: ^Number, value: i64) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLongLong:", value) } -Number_initWithF32 :: proc(self: ^Number, value: f32) -> ^Number { return msgSend(^Number, self, "initWithFloat:", value) } -Number_initWithF64 :: proc(self: ^Number, value: f64) -> ^Number { return msgSend(^Number, self, "initWithDouble:", value) } -Number_initWithBool :: proc(self: ^Number, value: BOOL) -> ^Number { return msgSend(^Number, self, "initWithBool:", value) } +@(objc_type=Number, objc_name="initWithI8") Number_initWithI8 :: proc(self: ^Number, value: i8) -> ^Number { return msgSend(^Number, self, "initWithChar:", value) } +@(objc_type=Number, objc_name="initWithU8") Number_initWithU8 :: proc(self: ^Number, value: u8) -> ^Number { return msgSend(^Number, self, "initWithUnsignedChar:", value) } +@(objc_type=Number, objc_name="initWithI16") Number_initWithI16 :: proc(self: ^Number, value: i16) -> ^Number { return msgSend(^Number, self, "initWithShort:", value) } +@(objc_type=Number, objc_name="initWithU16") Number_initWithU16 :: proc(self: ^Number, value: u16) -> ^Number { return msgSend(^Number, self, "initWithUnsignedShort:", value) } +@(objc_type=Number, objc_name="initWithI32") Number_initWithI32 :: proc(self: ^Number, value: i32) -> ^Number { return msgSend(^Number, self, "initWithInt:", value) } +@(objc_type=Number, objc_name="initWithU32") Number_initWithU32 :: proc(self: ^Number, value: u32) -> ^Number { return msgSend(^Number, self, "initWithUnsignedInt:", value) } +@(objc_type=Number, objc_name="initWithInt") Number_initWithInt :: proc(self: ^Number, value: int) -> ^Number { return msgSend(^Number, self, "initWithLong:", value) } +@(objc_type=Number, objc_name="initWithUint") Number_initWithUint :: proc(self: ^Number, value: uint) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLong:", value) } +@(objc_type=Number, objc_name="initWithU64") Number_initWithU64 :: proc(self: ^Number, value: u64) -> ^Number { return msgSend(^Number, self, "initWithLongLong:", value) } +@(objc_type=Number, objc_name="initWithI64") Number_initWithI64 :: proc(self: ^Number, value: i64) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLongLong:", value) } +@(objc_type=Number, objc_name="initWithF32") Number_initWithF32 :: proc(self: ^Number, value: f32) -> ^Number { return msgSend(^Number, self, "initWithFloat:", value) } +@(objc_type=Number, objc_name="initWithF64") Number_initWithF64 :: proc(self: ^Number, value: f64) -> ^Number { return msgSend(^Number, self, "initWithDouble:", value) } +@(objc_type=Number, objc_name="initWithBool") Number_initWithBool :: proc(self: ^Number, value: BOOL) -> ^Number { return msgSend(^Number, self, "initWithBool:", value) } -Number_init :: proc{ - Number_initWithI8, - Number_initWithU8, - Number_initWithI16, - Number_initWithU16, - Number_initWithI32, - Number_initWithU32, - Number_initWithInt, - Number_initWithUint, - Number_initWithU64, - Number_initWithI64, - Number_initWithF32, - Number_initWithF64, - Number_initWithBool, +@(objc_type=Number, objc_name="i8Value") Number_i8Value :: proc(self: ^Number) -> i8 { return msgSend(i8, self, "charValue") } +@(objc_type=Number, objc_name="u8Value") Number_u8Value :: proc(self: ^Number) -> u8 { return msgSend(u8, self, "unsignedCharValue") } +@(objc_type=Number, objc_name="i16Value") Number_i16Value :: proc(self: ^Number) -> i16 { return msgSend(i16, self, "shortValue") } +@(objc_type=Number, objc_name="u16Value") Number_u16Value :: proc(self: ^Number) -> u16 { return msgSend(u16, self, "unsignedShortValue") } +@(objc_type=Number, objc_name="i32Value") Number_i32Value :: proc(self: ^Number) -> i32 { return msgSend(i32, self, "intValue") } +@(objc_type=Number, objc_name="u32Value") Number_u32Value :: proc(self: ^Number) -> u32 { return msgSend(u32, self, "unsignedIntValue") } +@(objc_type=Number, objc_name="intValue") Number_intValue :: proc(self: ^Number) -> int { return msgSend(int, self, "longValue") } +@(objc_type=Number, objc_name="uintValue") Number_uintValue :: proc(self: ^Number) -> uint { return msgSend(uint, self, "unsignedLongValue") } +@(objc_type=Number, objc_name="u64Value") Number_u64Value :: proc(self: ^Number) -> u64 { return msgSend(u64, self, "longLongValue") } +@(objc_type=Number, objc_name="i64Value") Number_i64Value :: proc(self: ^Number) -> i64 { return msgSend(i64, self, "unsignedLongLongValue") } +@(objc_type=Number, objc_name="f32Value") Number_f32Value :: proc(self: ^Number) -> f32 { return msgSend(f32, self, "floatValue") } +@(objc_type=Number, objc_name="f64Value") Number_f64Value :: proc(self: ^Number) -> f64 { return msgSend(f64, self, "doubleValue") } +@(objc_type=Number, objc_name="boolValue") Number_boolValue :: proc(self: ^Number) -> BOOL { return msgSend(BOOL, self, "boolValue") } +@(objc_type=Number, objc_name="integerValue") Number_integerValue :: proc(self: ^Number) -> Integer { return msgSend(Integer, self, "integerValue") } +@(objc_type=Number, objc_name="uintegerValue") Number_uintegerValue :: proc(self: ^Number) -> UInteger { return msgSend(UInteger, self, "unsignedIntegerValue") } +@(objc_type=Number, objc_name="stringValue") Number_stringValue :: proc(self: ^Number) -> ^String { return msgSend(^String, self, "stringValue") } + +@(objc_type=Number, objc_name="compare") +Number_compare :: proc(self, other: ^Number) -> ComparisonResult { + return msgSend(ComparisonResult, self, "compare:", other) } -Number_i8Value :: proc(self: ^Number) -> i8 { return msgSend(i8, self, "charValue") } -Number_u8Value :: proc(self: ^Number) -> u8 { return msgSend(u8, self, "unsignedCharValue") } -Number_i16Value :: proc(self: ^Number) -> i16 { return msgSend(i16, self, "shortValue") } -Number_u16Value :: proc(self: ^Number) -> u16 { return msgSend(u16, self, "unsignedShortValue") } -Number_i32Value :: proc(self: ^Number) -> i32 { return msgSend(i32, self, "intValue") } -Number_u32Value :: proc(self: ^Number) -> u32 { return msgSend(u32, self, "unsignedIntValue") } -Number_intValue :: proc(self: ^Number) -> int { return msgSend(int, self, "longValue") } -Number_uintValue :: proc(self: ^Number) -> uint { return msgSend(uint, self, "unsignedLongValue") } -Number_u64Value :: proc(self: ^Number) -> u64 { return msgSend(u64, self, "longLongValue") } -Number_i64Value :: proc(self: ^Number) -> i64 { return msgSend(i64, self, "unsignedLongLongValue") } -Number_f32Value :: proc(self: ^Number) -> f32 { return msgSend(f32, self, "floatValue") } -Number_f64Value :: proc(self: ^Number) -> f64 { return msgSend(f64, self, "doubleValue") } -Number_boolValue :: proc(self: ^Number) -> BOOL { return msgSend(BOOL, self, "boolValue") } -Number_integerValue :: proc(self: ^Number) -> Integer { return msgSend(Integer, self, "integerValue") } -Number_uintegerValue :: proc(self: ^Number) -> UInteger { return msgSend(UInteger, self, "unsignedIntegerValue") } -Number_stringValue :: proc(self: ^Number) -> ^String { return msgSend(^String, self, "stringValue") } - -Number_compare :: proc(a, b: ^Number) -> ComparisonResult { - return msgSend(ComparisonResult, a, "compare:", b) -} - -Number_isEqualToNumber :: proc(a, b: ^Number) -> BOOL { - return msgSend(BOOL, a, "isEqualToNumber:", b) +@(objc_type=Number, objc_name="isEqualToNumber") +Number_isEqualToNumber :: proc(self, other: ^Number) -> BOOL { + return msgSend(BOOL, self, "isEqualToNumber:", other) } +@(objc_type=Number, objc_name="descriptionWithLocale") Number_descriptionWithLocale :: proc(self: ^Number, locale: ^Object) -> ^String { return msgSend(^String, self, "descriptionWithLocale:", locale) } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin index d61f8e947..cd0919edd 100644 --- a/core/sys/darwin/Foundation/NSObject.odin +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -27,37 +27,45 @@ alloc :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) { init :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, self, "init") } -retain :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) { - return msgSend(^T, self, "retain") -} -release :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) { - msgSend(nil, self, "release") -} -autorelease :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) { - msgSend(nil, self, "autorelease") -} -retainCount :: proc(self: ^$T) -> UInteger where intrinsics.type_is_subtype_of(T, Object) { - return msgSend(UInteger, self, "retainCount") -} - - copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, self, "copy") } +@(objc_type=Object, objc_name="retain") +retain :: proc(self: ^Object) { + _ = msgSend(^Object, self, "retain") +} +@(objc_type=Object, objc_name="release") +release :: proc(self: ^Object) { + msgSend(nil, self, "release") +} +@(objc_type=Object, objc_name="autorelease") +autorelease :: proc(self: ^Object) { + msgSend(nil, self, "autorelease") +} +@(objc_type=Object, objc_name="retainCount") +retainCount :: proc(self: ^Object) -> UInteger { + return msgSend(UInteger, self, "retainCount") +} + + +@(objc_type=Object, objc_name="hash") hash :: proc(self: ^Object) -> UInteger { return msgSend(UInteger, self, "hash") } +@(objc_type=Object, objc_name="isEqual") isEqual :: proc(self, pObject: ^Object) -> BOOL { return msgSend(BOOL, self, "isEqual:", pObject) } +@(objc_type=Object, objc_name="description") description :: proc(self: ^Object) -> ^String { return msgSend(^String, self, "description") } +@(objc_type=Object, objc_name="debugDescription") debugDescription :: proc(self: ^Object) -> ^String { if msgSendSafeCheck(self, intrinsics.objc_selector_name("debugDescription")) { return msgSend(^String, self, "debugDescription") diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin index 86c8cabea..06dbc27a3 100644 --- a/core/sys/darwin/Foundation/NSString.odin +++ b/core/sys/darwin/Foundation/NSString.odin @@ -59,54 +59,78 @@ MakeConstantString :: proc "c" (#const c: cstring) -> ^String { } +@(objc_type=String, objc_class_name="alloc") +String_alloc :: proc() -> ^String { + return msgSend(^String, String, "alloc") +} + +@(objc_type=String, objc_name="init") +String_init :: proc(self: ^String) -> ^String { + return msgSend(^String, self, "init") +} + + +@(objc_type=String, objc_name="initWithString") String_initWithString :: proc(self: ^String, other: ^String) -> ^String { return msgSend(^String, self, "initWithString:", other) } +@(objc_type=String, objc_name="initWithCString") String_initWithCString :: proc(self: ^String, pString: cstring, encoding: StringEncoding) -> ^String { return msgSend(^String, self, "initWithCstring:encoding:", pString, encoding) } +@(objc_type=String, objc_name="initWithBytesNoCopy") String_initWithBytesNoCopy :: proc(self: ^String, pBytes: rawptr, length: UInteger, encoding: StringEncoding, freeWhenDone: bool) -> ^String { return msgSend(^String, self, "initWithBytesNoCopy:length:encoding:freeWhenDone:", pBytes, length, encoding, freeWhenDone) } +@(objc_type=String, objc_name="initWithOdinString") String_initWithOdinString :: proc(self: ^String, str: string) -> ^String { return String_initWithBytesNoCopy(self, raw_data(str), UInteger(len(str)), .UTF8, false) } +@(objc_type=String, objc_name="characterAtIndex") String_characterAtIndex :: proc(self: ^String, index: UInteger) -> unichar { return msgSend(unichar, self, "characterAtIndex:", index) } +@(objc_type=String, objc_name="length") String_length :: proc(self: ^String) -> UInteger { return msgSend(UInteger, self, "length") } +@(objc_type=String, objc_name="cStringUsingEncoding") String_cStringUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> cstring { return msgSend(cstring, self, "cStringUsingEncoding:", encoding) } +@(objc_type=String, objc_name="UTF8String") String_UTF8String :: proc(self: ^String) -> cstring { return msgSend(cstring, self, "UTF8String") } +@(objc_type=String, objc_name="OdinString") String_OdinString :: proc(self: ^String) -> string { return string(String_UTF8String(self)) } +@(objc_type=String, objc_name="maximumLengthOfBytesUsingEncoding") String_maximumLengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger { return msgSend(UInteger, self, "maximumLengthOfBytesUsingEncoding:", encoding) } +@(objc_type=String, objc_name="lengthOfBytesUsingEncoding") String_lengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger { return msgSend(UInteger, self, "lengthOfBytesUsingEncoding:", encoding) } +@(objc_type=String, objc_name="isEqualToString") String_isEqualToString :: proc(self, other: ^String) -> BOOL { return msgSend(BOOL, self, "isEqualToString:", other) } +@(objc_type=String, objc_name="rangeOfString") String_rangeOfString :: proc(self, other: ^String, options: StringCompareOptions) -> Range { return msgSend(Range, self, "rangeOfString:options:", other, options) } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSURL.odin b/core/sys/darwin/Foundation/NSURL.odin index f4f776130..42edf91c0 100644 --- a/core/sys/darwin/Foundation/NSURL.odin +++ b/core/sys/darwin/Foundation/NSURL.odin @@ -3,6 +3,18 @@ package objc_Foundation @(objc_class="NSURL") URL :: struct{using _: Copying(URL)} + +@(objc_type=URL, objc_class_name="alloc") +URL_alloc :: proc() -> ^URL { + return msgSend(^URL, URL, "alloc") +} + +@(objc_type=URL, objc_name="init") +URL_init :: proc(self: ^URL) -> ^URL { + return msgSend(^URL, self, "init") +} + + URL_initWithString :: proc(self: ^URL, value: ^String) -> ^URL { return msgSend(^URL, self, "initWithString:", value) } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index df22d82e2..a9ee5d25f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -287,15 +287,13 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call Operand self = {}; check_expr_or_type(c, &self, ce->args[1]); if (self.mode == Addressing_Type) { - if (!internal_check_is_assignable_to(self.type, t_objc_object)) { + if (!is_type_objc_object(self.type)) { gbString t = type_to_string(self.type); error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got type %s", LIT(builtin_name), t); gb_string_free(t); return false; } - if (!(self.type->kind == Type_Named && - self.type->Named.type_name != nullptr && - self.type->Named.type_name->TypeName.objc_class_name != "")) { + if (!has_type_got_objc_class_attribute(self.type)) { gbString t = type_to_string(self.type); error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=) , got type %s", LIT(builtin_name), t); gb_string_free(t); @@ -306,7 +304,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } else if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) { gbString e = expr_to_string(self.expr); gbString t = type_to_string(self.type); - error(self.expr, "'%.*s'3 expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind); + error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind); gb_string_free(t); gb_string_free(e); return false; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 243dbbbc6..1d30088d6 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -340,6 +340,10 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac); if (e->kind == Entity_TypeName && ac.objc_class != "") { e->TypeName.objc_class_name = ac.objc_class; + + if (type_size_of(e->type) > 0) { + error(e->token, "@(objc_class) marked type must be of zero size"); + } } } @@ -822,6 +826,65 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } e->Procedure.optimization_mode = cast(ProcedureOptimizationMode)ac.optimization_mode; + if (ac.objc_name.len || ac.objc_class_name.len || ac.objc_type) { + if (ac.objc_class_name.len && ac.objc_name.len) { + error(e->token, "@(objc_class_name) and @(objc_name) may not be allowed at the same time"); + } else if (ac.objc_type == nullptr) { + if (ac.objc_name.len) { + error(e->token, "@(objc_name) requires that @(objc_type) to be set"); + } else { + error(e->token, "@(objc_class_name) requires that @(objc_type) to be set"); + } + } else { + Type *t = ac.objc_type; + if (t->kind == Type_Named) { + Entity *tn = t->Named.type_name; + + GB_ASSERT(tn->kind == Entity_TypeName); + + if (tn->scope != e->scope) { + error(e->token, "@(objc_name) and @(objc_class_name) attributes may only be applied to procedures and types within the same scope"); + } else { + mutex_lock(&global_type_name_objc_metadata_mutex); + defer (mutex_unlock(&global_type_name_objc_metadata_mutex)); + + if (!tn->TypeName.objc_metadata) { + tn->TypeName.objc_metadata = create_type_name_obj_c_metadata(); + } + auto *md = tn->TypeName.objc_metadata; + mutex_lock(md->mutex); + defer (mutex_unlock(md->mutex)); + + if (ac.objc_name.len) { + bool ok = true; + for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { + if (entry.name == ac.objc_name) { + error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); + ok = false; + break; + } + } + if (ok) { + array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); + } + } else { + bool ok = true; + for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { + if (entry.name == ac.objc_class_name) { + error(e->token, "Previous declaration of @(objc_class_name=\"%.*s\")", LIT(ac.objc_class_name)); + ok = false; + break; + } + } + if (ok) { + array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_class_name, e}); + } + } + } + } + } + } + switch (e->Procedure.optimization_mode) { case ProcedureOptimizationMode_None: diff --git a/src/check_type.cpp b/src/check_type.cpp index e1a0df7e6..32340070e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -325,6 +325,8 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t named_type->Named.type_name = e; GB_ASSERT(original_type->kind == Type_Named); e->TypeName.objc_class_name = original_type->Named.type_name->TypeName.objc_class_name; + // TODO(bill): Is this even correct? Or should the metadata be copied? + e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata; mutex_lock(&ctx->info->gen_types_mutex); auto *found_gen_types = map_get(&ctx->info->gen_types, original_type); diff --git a/src/checker.cpp b/src/checker.cpp index 2ab487592..0dd36987e 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4,7 +4,7 @@ void check_expr(CheckerContext *c, Operand *operand, Ast *expression); void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr); void add_comparison_procedures_for_fields(CheckerContext *c, Type *t); - +Type *check_type(CheckerContext *ctx, Ast *e); bool is_operand_value(Operand o) { switch (o.mode) { @@ -2740,6 +2740,14 @@ ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) { return ev; } +Type *check_decl_attribute_type(CheckerContext *c, Ast *value) { + if (value != nullptr) { + return check_type(c, value); + } + return nullptr; +} + + #define ATTRIBUTE_USER_TAG_NAME "tag" @@ -3039,6 +3047,46 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { error(elem, "Expected a string for '%.*s'", LIT(name)); } return true; + } else if (name == "objc_name") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { + if (string_is_valid_identifier(ev.value_string)) { + ac->objc_name = ev.value_string; + } else { + error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string)); + } + } else { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "objc_class_name") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { + if (string_is_valid_identifier(ev.value_string)) { + ac->objc_class_name = ev.value_string; + } else { + error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string)); + } + } else { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "objc_type") { + if (value == nullptr) { + error(elem, "Expected a type for '%.*s'", LIT(name)); + } else { + Type *objc_type = check_type(c, value); + if (objc_type != nullptr) { + if (!has_type_got_objc_class_attribute(objc_type)) { + gbString t = type_to_string(objc_type); + error(value, "'%.*s' expected a named type with the attribute @(obj_class=), got type %s", LIT(name), t); + gb_string_free(t); + } else { + ac->objc_type = objc_type; + } + } + } + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index b812e10a4..38c8d32f6 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -107,7 +107,6 @@ struct AttributeContext { String thread_local_model; String deprecated_message; String warning_message; - String objc_class; DeferredProcedure deferred_procedure; bool is_export : 1; bool is_static : 1; @@ -119,6 +118,11 @@ struct AttributeContext { bool init : 1; bool set_cold : 1; u32 optimization_mode; // ProcedureOptimizationMode + + String objc_class; + String objc_name; + String objc_class_name; + Type * objc_type; }; AttributeContext make_attribute_context(String link_prefix) { diff --git a/src/entity.cpp b/src/entity.cpp index 4d5b3b9e1..df8ee3faa 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -122,6 +122,28 @@ enum ProcedureOptimizationMode : u32 { ProcedureOptimizationMode_Speed, }; + +BlockingMutex global_type_name_objc_metadata_mutex; + +struct TypeNameObjCMetadataEntry { + String name; + Entity *entity; +}; +struct TypeNameObjCMetadata { + BlockingMutex *mutex; + Array type_entries; + Array value_entries; +}; + +TypeNameObjCMetadata *create_type_name_obj_c_metadata() { + TypeNameObjCMetadata *md = gb_alloc_item(permanent_allocator(), TypeNameObjCMetadata); + md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex); + mutex_init(md->mutex); + array_init(&md->type_entries, heap_allocator()); + array_init(&md->value_entries, heap_allocator()); + return md; +} + // An Entity is a named "thing" in the language struct Entity { EntityKind kind; @@ -187,6 +209,7 @@ struct Entity { String ir_mangled_name; bool is_type_alias; String objc_class_name; + TypeNameObjCMetadata *objc_metadata; } TypeName; struct { u64 tags; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 29a86d116..b2f430cd2 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3320,7 +3320,12 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { Type *type = base_type(tav.type); if (tav.mode == Addressing_Type) { // Addressing_Type - GB_PANIC("Unreachable"); + Selection sel = lookup_field(tav.type, selector, true); + if (sel.pseudo_field) { + GB_ASSERT(sel.entity->kind == Entity_Procedure); + return lb_addr(lb_find_value_from_entity(p->module, sel.entity)); + } + GB_PANIC("Unreachable %.*s", LIT(selector)); } if (se->swizzle_count > 0) { @@ -3347,6 +3352,10 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { Selection sel = lookup_field(type, selector, false); GB_ASSERT(sel.entity != nullptr); + if (sel.pseudo_field) { + GB_ASSERT(sel.entity->kind == Entity_Procedure); + return lb_addr(lb_find_value_from_entity(p->module, sel.entity)); + } { lbAddr addr = lb_build_addr(p, se->expr); diff --git a/src/main.cpp b/src/main.cpp index fe56d451f..bd06193bd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -585,37 +585,6 @@ void usage(String argv0) { print_usage_line(1, "e.g. odin build -help"); } - -bool string_is_valid_identifier(String str) { - if (str.len <= 0) return false; - - isize rune_count = 0; - - isize w = 0; - isize offset = 0; - while (offset < str.len) { - Rune r = 0; - w = utf8_decode(str.text, str.len, &r); - if (r == GB_RUNE_INVALID) { - return false; - } - - if (rune_count == 0) { - if (!rune_is_letter(r)) { - return false; - } - } else { - if (!rune_is_letter(r) && !rune_is_digit(r)) { - return false; - } - } - rune_count += 1; - offset += w; - } - - return true; -} - enum BuildFlagKind { BuildFlag_Invalid, @@ -2447,6 +2416,7 @@ int main(int arg_count, char const **arg_ptr) { virtual_memory_init(); mutex_init(&fullpath_mutex); mutex_init(&hash_exact_value_mutex); + mutex_init(&global_type_name_objc_metadata_mutex); init_string_buffer_memory(); init_string_interner(); diff --git a/src/string.cpp b/src/string.cpp index eb6058f78..bcaf23b9b 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -781,3 +781,34 @@ i32 unquote_string(gbAllocator a, String *s_, u8 quote=0, bool has_carriage_retu return 2; } + + +bool string_is_valid_identifier(String str) { + if (str.len <= 0) return false; + + isize rune_count = 0; + + isize w = 0; + isize offset = 0; + while (offset < str.len) { + Rune r = 0; + w = utf8_decode(str.text, str.len, &r); + if (r == GB_RUNE_INVALID) { + return false; + } + + if (rune_count == 0) { + if (!rune_is_letter(r)) { + return false; + } + } else { + if (!rune_is_letter(r) && !rune_is_digit(r)) { + return false; + } + } + rune_count += 1; + offset += w; + } + + return true; +} diff --git a/src/types.cpp b/src/types.cpp index 024d644a2..78958146b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -393,6 +393,7 @@ struct Selection { bool indirect; // Set if there was a pointer deref anywhere down the line u8 swizzle_count; // maximum components = 4 u8 swizzle_indices; // 2 bits per component, representing which swizzle index + bool pseudo_field; }; Selection empty_selection = {0}; @@ -2782,6 +2783,7 @@ Selection lookup_field_from_index(Type *type, i64 index) { } Entity *scope_lookup_current(Scope *s, String const &name); +bool has_type_got_objc_class_attribute(Type *t); Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) { GB_ASSERT(type_ != nullptr); @@ -2794,9 +2796,40 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty bool is_ptr = type != type_; sel.indirect = sel.indirect || is_ptr; + Type *original_type = type; + type = base_type(type); if (is_type) { + if (has_type_got_objc_class_attribute(original_type) && original_type->kind == Type_Named) { + Entity *e = original_type->Named.type_name; + GB_ASSERT(e->kind == Entity_TypeName); + if (e->TypeName.objc_metadata) { + auto *md = e->TypeName.objc_metadata; + mutex_lock(md->mutex); + defer (mutex_unlock(md->mutex)); + for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { + GB_ASSERT(entry.entity->kind == Entity_Procedure); + if (entry.name == field_name) { + sel.entity = entry.entity; + sel.pseudo_field = true; + return sel; + } + } + } + if (type->kind == Type_Struct) { + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + if (f->flags&EntityFlag_Using) { + sel = lookup_field_with_selection(f->type, field_name, is_type, sel, allow_blank_ident); + if (sel.entity) { + return sel; + } + } + } + } + } + if (is_type_enum(type)) { // NOTE(bill): These may not have been added yet, so check in case for_array(i, type->Enum.fields) { @@ -2843,6 +2876,24 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty } else if (type->kind == Type_Union) { } else if (type->kind == Type_Struct) { + if (has_type_got_objc_class_attribute(original_type) && original_type->kind == Type_Named) { + Entity *e = original_type->Named.type_name; + GB_ASSERT(e->kind == Entity_TypeName); + if (e->TypeName.objc_metadata) { + auto *md = e->TypeName.objc_metadata; + mutex_lock(md->mutex); + defer (mutex_unlock(md->mutex)); + for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { + GB_ASSERT(entry.entity->kind == Entity_Procedure); + if (entry.name == field_name) { + sel.entity = entry.entity; + sel.pseudo_field = true; + return sel; + } + } + } + } + for_array(i, type->Struct.fields) { Entity *f = type->Struct.fields[i]; if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { @@ -3792,6 +3843,17 @@ bool is_type_subtype_of(Type *src, Type *dst) { } +bool has_type_got_objc_class_attribute(Type *t) { + return t->kind == Type_Named && t->Named.type_name != nullptr && t->Named.type_name->TypeName.objc_class_name != ""; +} + + + +bool is_type_objc_object(Type *t) { + bool internal_check_is_assignable_to(Type *src, Type *dst); + + return internal_check_is_assignable_to(t, t_objc_object); +} Type *get_struct_field_type(Type *t, isize index) { t = base_type(type_deref(t)); From acaae1357cf7d9a5b3cd94df123a8942c8290192 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 17:30:32 +0000 Subject: [PATCH 0135/1052] Update Metal for the full API Methods need better names --- vendor/Metal/MTLAccelerationStructure.odin | 270 - .../Metal/MTLAccelerationStructureTypes.odin | 10 - vendor/Metal/MTLRenderPipeline.odin | 74 - .../Metal/MTLStageInputOutputDescriptor.odin | 76 - vendor/Metal/Metal.odin | 22 - vendor/Metal/MetalClasses.odin | 8076 +++++++++++++++++ vendor/Metal/MetalEnums.odin | 961 ++ vendor/Metal/MetalErrors.odin | 39 + vendor/Metal/MetalTypes.odin | 198 + vendor/Metal/NSBuffer.odin | 5 - vendor/Metal/NSResource.odin | 5 - 11 files changed, 9274 insertions(+), 462 deletions(-) delete mode 100644 vendor/Metal/MTLAccelerationStructure.odin delete mode 100644 vendor/Metal/MTLAccelerationStructureTypes.odin delete mode 100644 vendor/Metal/MTLRenderPipeline.odin delete mode 100644 vendor/Metal/MTLStageInputOutputDescriptor.odin delete mode 100644 vendor/Metal/Metal.odin create mode 100644 vendor/Metal/MetalClasses.odin create mode 100644 vendor/Metal/MetalEnums.odin create mode 100644 vendor/Metal/MetalErrors.odin create mode 100644 vendor/Metal/MetalTypes.odin delete mode 100644 vendor/Metal/NSBuffer.odin delete mode 100644 vendor/Metal/NSResource.odin diff --git a/vendor/Metal/MTLAccelerationStructure.odin b/vendor/Metal/MTLAccelerationStructure.odin deleted file mode 100644 index 342df3d07..000000000 --- a/vendor/Metal/MTLAccelerationStructure.odin +++ /dev/null @@ -1,270 +0,0 @@ -package objc_Metal - -import NS "core:sys/darwin/Foundation" - -AccelerationStructureUsage :: distinct bit_set[AccelerationStructureUsageFlag; NS.UInteger] -AccelerationStructureUsageFlag :: enum NS.UInteger { - Refit = 0, - PreferFastBuild = 1, - ExtendedLimits = 2, -} -AccelerationStructureUsageNone :: AccelerationStructureUsage{} - -AccelerationStructureInstanceOptions :: distinct bit_set[AccelerationStructureInstanceOption; u32] -AccelerationStructureInstanceOption :: enum u32 { - DisableTriangleCulling = 0, - TriangleFrontFacingWindingCounterClockwise = 1, - Opaque = 2, - NonOpaque = 3, -} -AccelerationStructureInstanceOptionNone :: AccelerationStructureInstanceOptions{} - -MotionBorderMode :: enum u32 { - Clamp = 0, - Vanish = 1, -} - -AccelerationStructureInstanceDescriptor :: struct #packed { - transformationMatrix: PackedFloat4x3, - options: AccelerationStructureInstanceOptions, - mask: u32, - intersectionFunctionTableOffset: u32, - accelerationStructureIndex: u32, -} - -AccelerationStructureUserIDInstanceDescriptor :: struct #packed { - transformationMatrix: PackedFloat4x3, - options: AccelerationStructureInstanceOptions, - mask: u32, - intersectionFunctionTableOffset: u32, - accelerationStructureIndex: u32, - userID: u32, -} - -AccelerationStructureInstanceDescriptorType :: enum NS.UInteger { - Default = 0, - UserID = 1, - Motion = 2, -} - -AccelerationStructureMotionInstanceDescriptor :: struct #packed { - options: AccelerationStructureInstanceOptions, - mask: u32, - intersectionFunctionTableOffset: u32, - accelerationStructureIndex: u32, - userID: u32, - motionTransformsStartIndex: u32, - motionTransformsCount: u32, - motionStartBorderMode: MotionBorderMode, - motionEndBorderMode: MotionBorderMode, - motionStartTime: f32, - motionEndTime: f32, -} - -@(objc_class="NSAccelerationStructureDescriptor") -AccelerationStructureDescriptor :: struct { using _: NS.Copying(AccelerationStructureDescriptor) } - -@(objc_class="NSAccelerationStructureGeometryDescriptor") -AccelerationStructureGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureGeometryDescriptor) } - -@(objc_class="NSPrimitiveAccelerationStructureDescriptor") -PrimitiveAccelerationStructureDescriptor :: struct { using _: NS.Copying(PrimitiveAccelerationStructureDescriptor), using _: AccelerationStructureDescriptor } - -@(objc_class="NSAccelerationStructureTriangleGeometryDescriptor") -AccelerationStructureTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureTriangleGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } - -@(objc_class="NSAccelerationStructureBoundingBoxGeometryDescriptor") -AccelerationStructureBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureBoundingBoxGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } - -@(objc_class="NSMotionKeyframeData") -MotionKeyframeData :: struct { using _: NS.Object } - -@(objc_class="NSAccelerationStructureMotionTriangleGeometryDescriptor") -AccelerationStructureMotionTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionTriangleGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } - -@(objc_class="NSAccelerationStructureMotionBoundingBoxGeometryDescriptor") -AccelerationStructureMotionBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionBoundingBoxGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } - -@(objc_class="NSInstanceAccelerationStructureDescriptor") -InstanceAccelerationStructureDescriptor :: struct { using _: NS.Copying(InstanceAccelerationStructureDescriptor), using _: AccelerationStructureGeometryDescriptor } - -@(objc_class="NSAccelerationStructure") -AccelerationStructure :: struct { using _: NS.Object } - - - -AccelerationStructureDescriptor_usage :: proc(self: ^AccelerationStructureDescriptor) -> AccelerationStructureUsage { - return msgSend(AccelerationStructureUsage, self, "usage") -} - -AccelerationStructureGeometryDescriptor_intersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "intersectionFunctionTableOffset") -} - -AccelerationStructureGeometryDescriptor_setIntersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor, intersectionFunctionTableOffset: NS.UInteger) { - msgSend(nil, self, "setIntersectionFunctionTableOffset:", intersectionFunctionTableOffset) -} - -AccelerationStructureGeometryDescriptor_opaque :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { - return msgSend(BOOL, self, "opaque") -} - -AccelerationStructureGeometryDescriptor_setOpaque :: proc(self: ^AccelerationStructureGeometryDescriptor, opaque: BOOL) { - msgSend(nil, self, "setOpaque:", opaque) -} - -AccelerationStructureGeometryDescriptor_allowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { - return msgSend(BOOL, self, "allowDuplicateIntersectionFunctionInvocation") -} - -AccelerationStructureGeometryDescriptor_setAllowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor, allowDuplicateIntersectionFunctionInvocation: BOOL) { - msgSend(nil, self, "setAllowDuplicateIntersectionFunctionInvocation:", allowDuplicateIntersectionFunctionInvocation) -} - - -AccelerationStructureGeometryDescriptor_label :: proc(self: ^AccelerationStructureGeometryDescriptor) -> ^NS.String { - return msgSend(^NS.String, self, "label") -} - -AccelerationStructureGeometryDescriptor_setLabel :: proc(self: ^AccelerationStructureGeometryDescriptor, label: ^NS.String) { - msgSend(nil, self, "setLabel:", label) -} - -PrimitiveAccelerationStructureDescriptor_geometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (descriptors: ^NS.Array(^NS.Object)) { - return msgSend(type_of(descriptors), self, "geometryDescriptors") -} - -PrimitiveAccelerationStructureDescriptor_setGeometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor, descriptors: ^NS.Array(^NS.Object)) { - msgSend(nil, self, "setGeometryDescriptors:", descriptors) -} - -PrimitiveAccelerationStructureDescriptor_motionStartBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> MotionBorderMode { - return msgSend(MotionBorderMode, self, "motionStartBorderMode") -} -PrimitiveAccelerationStructureDescriptor_setMotionStartBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionStartBorderMode: MotionBorderMode) { - msgSend(nil, self, "setMotionStartBorderMode:", motionStartBorderMode) -} - -PrimitiveAccelerationStructureDescriptor_motionEndBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> MotionBorderMode { - return msgSend(MotionBorderMode, self, "motionEndBorderMode") -} -PrimitiveAccelerationStructureDescriptor_setMotionEndBorderMode :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionEndBorderMode: MotionBorderMode) { - msgSend(nil, self, "setMotionEndBorderMode:", motionEndBorderMode) -} - -PrimitiveAccelerationStructureDescriptor_motionStartTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (motionStartTime: f32) { - return msgSend(f32, self, "motionStartTime") -} -PrimitiveAccelerationStructureDescriptor_setMotionStartTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionStartTime: f32) { - msgSend(nil, self, "setMotionStartTime:", motionStartTime) -} - - -PrimitiveAccelerationStructureDescriptor_motionEndTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (motionEndTime: f32) { - return msgSend(f32, self, "motionEndTime") -} -PrimitiveAccelerationStructureDescriptor_setMotionEndTime :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionEndTime: f32) { - msgSend(nil, self, "setMotionEndTime:", motionEndTime) -} - - -PrimitiveAccelerationStructureDescriptor_motionKeyframeCount :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> (motionKeyframeCount: NS.UInteger) { - return msgSend(NS.UInteger, self, "motionKeyframeCount") -} -PrimitiveAccelerationStructureDescriptor_setmotionKeyframeCount :: proc(self: ^PrimitiveAccelerationStructureDescriptor, motionKeyframeCount: NS.UInteger) { - msgSend(nil, self, "setMotionKeyframeCount:", motionKeyframeCount) -} - -PrimitiveAccelerationStructureDescriptor_descriptor :: proc() -> ^PrimitiveAccelerationStructureDescriptor { - return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "descriptor") -} - - -AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^Buffer { - return msgSend(^Buffer, self, "vertexBuffer") -} -AccelerationStructureTriangleGeometryDescriptor_setVertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, buffer: ^Buffer) { - msgSend(nil, self, "setVertexBuffer:", buffer) -} - -AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "vertexBufferOffset") -} -AccelerationStructureTriangleGeometryDescriptor_setVertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBufferOffset: NS.UInteger) { - msgSend(nil, self, "setVertexBufferOffset:", vertexBufferOffset) -} - -AccelerationStructureTriangleGeometryDescriptor_vertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "vertexStride") -} -AccelerationStructureTriangleGeometryDescriptor_setVertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexStride: NS.UInteger) { - msgSend(nil, self, "setVertexStride:", vertexStride) -} - -AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^Buffer { - return msgSend(^Buffer, self, "indexBuffer") -} -AccelerationStructureTriangleGeometryDescriptor_setIndexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, buffer: ^Buffer) { - msgSend(nil, self, "setIndexBuffer:", buffer) -} - -AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "indexBufferOffset") -} -AccelerationStructureTriangleGeometryDescriptor_setIndexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBufferOffset: NS.UInteger) { - msgSend(nil, self, "setIndexBufferOffset:", indexBufferOffset) -} - - - -AccelerationStructureTriangleGeometryDescriptor_indexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> IndexType { - return msgSend(IndexType, self, "indexType") -} -AccelerationStructureTriangleGeometryDescriptor_setIndexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indextype: IndexType) { - msgSend(nil, self, "setIndexType:", indextype) -} - -AccelerationStructureTriangleGeometryDescriptor_triangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "triangleCount") -} -AccelerationStructureTriangleGeometryDescriptor_setTriangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, triangleCount: NS.UInteger) { - msgSend(nil, self, "setTriangleCount", triangleCount) -} - - -AccelerationStructureTriangleGeometryDescriptor_descriptor :: proc() -> ^AccelerationStructureTriangleGeometryDescriptor { - return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "descriptor") -} - -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^Buffer { - return msgSend(^Buffer, self, "boundingBoxBuffer") -} - -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, buffer: ^Buffer) { - msgSend(nil, self, "setBoundingBoxBuffer:", buffer) -} - -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "boundingBoxBufferOffset") -} - -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBufferOffset: NS.UInteger) { - msgSend(nil, self, "setBoundingBoxBufferOffset:", boundingBoxBufferOffset) -} - - -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "boundingBoxStride") -} - -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxStride: NS.UInteger) { - msgSend(nil, self, "setBoundingBoxStride:", boundingBoxStride) -} - -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "boundingBoxCount") -} - -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxCount: NS.UInteger) { - msgSend(nil, self, "setBoundingBoxCount:", boundingBoxCount) -} diff --git a/vendor/Metal/MTLAccelerationStructureTypes.odin b/vendor/Metal/MTLAccelerationStructureTypes.odin deleted file mode 100644 index eba672836..000000000 --- a/vendor/Metal/MTLAccelerationStructureTypes.odin +++ /dev/null @@ -1,10 +0,0 @@ -package objc_Metal - -import NS "core:sys/darwin/Foundation" - -PackedFloat3 :: distinct [3]f32 -PackedFloat4x3 :: distinct [4]PackedFloat3 - -AxisAlignedBoundingBox :: struct{ - min, ax: PackedFloat3, -} \ No newline at end of file diff --git a/vendor/Metal/MTLRenderPipeline.odin b/vendor/Metal/MTLRenderPipeline.odin deleted file mode 100644 index c05c02c64..000000000 --- a/vendor/Metal/MTLRenderPipeline.odin +++ /dev/null @@ -1,74 +0,0 @@ -package objc_Metal - -import NS "core:sys/darwin/Foundation" - -BlendFactor :: enum NS.UInteger { - Zero = 0, - One = 1, - SourceColor = 2, - OneMinusSourceColor = 3, - SourceAlpha = 4, - OneMinusSourceAlpha = 5, - DestinationColor = 6, - OneMinusDestinationColor = 7, - DestinationAlpha = 8, - OneMinusDestinationAlpha = 9, - SourceAlphaSaturated = 10, - BlendColor = 11, - OneMinusBlendColor = 12, - BlendAlpha = 13, - OneMinusBlendAlpha = 14, - Source1Color = 15, - OneMinusSource1Color = 16, - Source1Alpha = 17, - OneMinusSource1Alpha = 18, -} - -BlendOperation :: enum NS.UInteger { - Add = 0, - Subtract = 1, - ReverseSubtract = 2, - Min = 3, - Max = 4, -} - -ColorWriteMaskOption :: enum NS.UInteger { - Alpha = 0, - Blue = 1, - Green = 2, - Red = 3, -} -ColorWriteMask :: distinct bit_set[ColorWriteMaskOption; NS.UInteger] -ColorWriteMaskNone :: ColorWriteMask{} -ColorWriteMaskAll :: ColorWriteMask{.Alpha, .Blue, .Green, .Red} - -PrimitiveTopologyClass :: enum NS.UInteger { - ClassUnspecified = 0, - ClassPoint = 1, - ClassLine = 2, - ClassTriangle = 3, -} - -TessellationPartitionMode :: enum NS.UInteger { - ModePow2 = 0, - ModeInteger = 1, - ModeFractionalOdd = 2, - ModeFractionalEven = 3, -} - -TessellationFactorStepFunction :: enum NS.UInteger { - Constant = 0, - PerPatch = 1, - PerInstance = 2, - PerPatchAndPerInstance = 3, -} - -TessellationFactorFormat :: enum NS.UInteger { - Half = 0, -} - -TessellationControlPointIndexType :: enum NS.UInteger { - None = 0, - UInt16 = 1, - UInt32 = 2, -} diff --git a/vendor/Metal/MTLStageInputOutputDescriptor.odin b/vendor/Metal/MTLStageInputOutputDescriptor.odin deleted file mode 100644 index 98ff66ce5..000000000 --- a/vendor/Metal/MTLStageInputOutputDescriptor.odin +++ /dev/null @@ -1,76 +0,0 @@ -package objc_Metal - -import NS "core:sys/darwin/Foundation" - - -AttributeFormat :: enum NS.UInteger { - Invalid = 0, - UChar2 = 1, - UChar3 = 2, - UChar4 = 3, - Char2 = 4, - Char3 = 5, - Char4 = 6, - UChar2Normalized = 7, - UChar3Normalized = 8, - UChar4Normalized = 9, - Char2Normalized = 10, - Char3Normalized = 11, - Char4Normalized = 12, - UShort2 = 13, - UShort3 = 14, - UShort4 = 15, - Short2 = 16, - Short3 = 17, - Short4 = 18, - UShort2Normalized = 19, - UShort3Normalized = 20, - UShort4Normalized = 21, - Short2Normalized = 22, - Short3Normalized = 23, - Short4Normalized = 24, - Half2 = 25, - Half3 = 26, - Half4 = 27, - Float = 28, - Float2 = 29, - Float3 = 30, - Float4 = 31, - Int = 32, - Int2 = 33, - Int3 = 34, - Int4 = 35, - UInt = 36, - UInt2 = 37, - UInt3 = 38, - UInt4 = 39, - Int1010102Normalized = 40, - UInt1010102Normalized = 41, - UChar4Normalized_BGRA = 42, - UChar = 45, - Char = 46, - UCharNormalized = 47, - CharNormalized = 48, - UShort = 49, - Short = 50, - UShortNormalized = 51, - ShortNormalized = 52, - Half = 53, -} - -IndexType :: enum NS.UInteger { - UInt16 = 0, - UInt32 = 1, -} - -StepFunction :: enum NS.UInteger { - Constant = 0, - PerVertex = 1, - PerInstance = 2, - PerPatch = 3, - PerPatchControlPoint = 4, - ThreadPositionInGridX = 5, - ThreadPositionInGridY = 6, - ThreadPositionInGridXIndexed = 7, - ThreadPositionInGridYIndexed = 8, -} \ No newline at end of file diff --git a/vendor/Metal/Metal.odin b/vendor/Metal/Metal.odin deleted file mode 100644 index eefada00d..000000000 --- a/vendor/Metal/Metal.odin +++ /dev/null @@ -1,22 +0,0 @@ -package objc_Metal - -import NS "core:sys/darwin/Foundation" -import "core:intrinsics" - -alloc :: NS.alloc -init :: NS.init -retain :: NS.retain -release :: NS.release -autorelease :: NS.autorelease -retainCount :: NS.retainCount -copy :: NS.copy -hash :: NS.hash -isEqual :: NS.isEqual -description :: NS.description -debugDescription :: NS.debugDescription -bridgingCast :: NS.bridgingCast - -@(private) -msgSend :: intrinsics.objc_send - -BOOL :: NS.BOOL \ No newline at end of file diff --git a/vendor/Metal/MetalClasses.odin b/vendor/Metal/MetalClasses.odin new file mode 100644 index 000000000..138677d0d --- /dev/null +++ b/vendor/Metal/MetalClasses.odin @@ -0,0 +1,8076 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +foreign import "system:Metal.framework" + +@(default_calling_convention="c", link_prefix="MTL") +foreign Metal { + CopyAllDevices :: proc() -> ^NS.Array --- + CopyAllDevicesWithObserver :: proc(observer: ^^NS.Object, handler: DeviceNotificationHandler) -> ^NS.Array --- + CreateSystemDefaultDevice :: proc() -> ^NS.Object --- + RemoveDeviceObserver :: proc(observer: ^NS.Object) --- +} + + + + + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructureBoundingBoxGeometryDescriptor +Class Methods: + alloc + descriptor +Methods: + init + boundingBoxBuffer + boundingBoxBufferOffset + boundingBoxCount + boundingBoxStride + setBoundingBoxBuffer + setBoundingBoxBufferOffset + setBoundingBoxCount + setBoundingBoxStride +*/ +@(objc_class="MTLAccelerationStructureBoundingBoxGeometryDescriptor") +AccelerationStructureBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureBoundingBoxGeometryDescriptor) } + +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="alloc") +AccelerationStructureBoundingBoxGeometryDescriptor_alloc :: proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { + return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, AccelerationStructureBoundingBoxGeometryDescriptor, "alloc") +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="init") +AccelerationStructureBoundingBoxGeometryDescriptor_init :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^AccelerationStructureBoundingBoxGeometryDescriptor { + return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, self, "init") +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxBuffer") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^AccelerationStructureBoundingBoxGeometryDescriptor { + return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, self, "boundingBoxBuffer") +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxBufferOffset") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "boundingBoxBufferOffset") +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxCount") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "boundingBoxCount") +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxStride") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "boundingBoxStride") +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="descriptor") +AccelerationStructureBoundingBoxGeometryDescriptor_descriptor :: proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { + return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, AccelerationStructureBoundingBoxGeometryDescriptor, "descriptor") +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxBuffer") +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBuffer: ^NS.Object) { + msgSend(nil, self, "setBoundingBoxBuffer:", boundingBoxBuffer) +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxBufferOffset") +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBufferOffset: NS.Integer) { + msgSend(nil, self, "setBoundingBoxBufferOffset:", boundingBoxBufferOffset) +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxCount") +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxCount: NS.Integer) { + msgSend(nil, self, "setBoundingBoxCount:", boundingBoxCount) +} +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxStride") +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxStride: NS.Integer) { + msgSend(nil, self, "setBoundingBoxStride:", boundingBoxStride) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructureDescriptor +Class Methods: + alloc +Methods: + init + setUsage + usage +*/ +@(objc_class="MTLAccelerationStructureDescriptor") +AccelerationStructureDescriptor :: struct { using _: NS.Copying(AccelerationStructureDescriptor) } + +@(objc_type=AccelerationStructureDescriptor, objc_class_name="alloc") +AccelerationStructureDescriptor_alloc :: proc() -> ^AccelerationStructureDescriptor { + return msgSend(^AccelerationStructureDescriptor, AccelerationStructureDescriptor, "alloc") +} +@(objc_type=AccelerationStructureDescriptor, objc_name="init") +AccelerationStructureDescriptor_init :: proc(self: ^AccelerationStructureDescriptor) -> ^AccelerationStructureDescriptor { + return msgSend(^AccelerationStructureDescriptor, self, "init") +} +@(objc_type=AccelerationStructureDescriptor, objc_name="setUsage") +AccelerationStructureDescriptor_setUsage :: proc(self: ^AccelerationStructureDescriptor, usage: AccelerationStructureUsage) { + msgSend(nil, self, "setUsage:", usage) +} +@(objc_type=AccelerationStructureDescriptor, objc_name="usage") +AccelerationStructureDescriptor_usage :: proc(self: ^AccelerationStructureDescriptor) -> AccelerationStructureUsage { + return msgSend(AccelerationStructureUsage, self, "usage") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructureGeometryDescriptor +Class Methods: + alloc +Methods: + init + allowDuplicateIntersectionFunctionInvocation + intersectionFunctionTableOffset + opaque + setAllowDuplicateIntersectionFunctionInvocation + setIntersectionFunctionTableOffset + setOpaque +*/ +@(objc_class="MTLAccelerationStructureGeometryDescriptor") +AccelerationStructureGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureGeometryDescriptor) } + +@(objc_type=AccelerationStructureGeometryDescriptor, objc_class_name="alloc") +AccelerationStructureGeometryDescriptor_alloc :: proc() -> ^AccelerationStructureGeometryDescriptor { + return msgSend(^AccelerationStructureGeometryDescriptor, AccelerationStructureGeometryDescriptor, "alloc") +} +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="init") +AccelerationStructureGeometryDescriptor_init :: proc(self: ^AccelerationStructureGeometryDescriptor) -> ^AccelerationStructureGeometryDescriptor { + return msgSend(^AccelerationStructureGeometryDescriptor, self, "init") +} +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="allowDuplicateIntersectionFunctionInvocation") +AccelerationStructureGeometryDescriptor_allowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { + return msgSend(BOOL, self, "allowDuplicateIntersectionFunctionInvocation") +} +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="intersectionFunctionTableOffset") +AccelerationStructureGeometryDescriptor_intersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "intersectionFunctionTableOffset") +} +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="opaque") +AccelerationStructureGeometryDescriptor_opaque :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { + return msgSend(BOOL, self, "opaque") +} +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setAllowDuplicateIntersectionFunctionInvocation") +AccelerationStructureGeometryDescriptor_setAllowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor, allowDuplicateIntersectionFunctionInvocation: BOOL) { + msgSend(nil, self, "setAllowDuplicateIntersectionFunctionInvocation:", allowDuplicateIntersectionFunctionInvocation) +} +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setIntersectionFunctionTableOffset") +AccelerationStructureGeometryDescriptor_setIntersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor, intersectionFunctionTableOffset: NS.Integer) { + msgSend(nil, self, "setIntersectionFunctionTableOffset:", intersectionFunctionTableOffset) +} +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setOpaque") +AccelerationStructureGeometryDescriptor_setOpaque :: proc(self: ^AccelerationStructureGeometryDescriptor, opaque: BOOL) { + msgSend(nil, self, "setOpaque:", opaque) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructureTriangleGeometryDescriptor +Class Methods: + alloc + descriptor +Methods: + init + indexBuffer + indexBufferOffset + indexType + setIndexBuffer + setIndexBufferOffset + setIndexType + setTriangleCount + setVertexBuffer + setVertexBufferOffset + setVertexStride + triangleCount + vertexBuffer + vertexBufferOffset + vertexStride +*/ +@(objc_class="MTLAccelerationStructureTriangleGeometryDescriptor") +AccelerationStructureTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureTriangleGeometryDescriptor) } + +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_class_name="alloc") +AccelerationStructureTriangleGeometryDescriptor_alloc :: proc() -> ^AccelerationStructureTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "alloc") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="init") +AccelerationStructureTriangleGeometryDescriptor_init :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "init") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_class_name="descriptor") +AccelerationStructureTriangleGeometryDescriptor_descriptor :: proc() -> ^AccelerationStructureTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "descriptor") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexBuffer") +AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "indexBuffer") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexBufferOffset") +AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "indexBufferOffset") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexType") +AccelerationStructureTriangleGeometryDescriptor_indexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> IndexType { + return msgSend(IndexType, self, "indexType") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexBuffer") +AccelerationStructureTriangleGeometryDescriptor_setIndexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBuffer: ^NS.Object) { + msgSend(nil, self, "setIndexBuffer:", indexBuffer) +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexBufferOffset") +AccelerationStructureTriangleGeometryDescriptor_setIndexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBufferOffset: NS.Integer) { + msgSend(nil, self, "setIndexBufferOffset:", indexBufferOffset) +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexType") +AccelerationStructureTriangleGeometryDescriptor_setIndexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexType: IndexType) { + msgSend(nil, self, "setIndexType:", indexType) +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setTriangleCount") +AccelerationStructureTriangleGeometryDescriptor_setTriangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, triangleCount: NS.Integer) { + msgSend(nil, self, "setTriangleCount:", triangleCount) +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexBuffer") +AccelerationStructureTriangleGeometryDescriptor_setVertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBuffer: ^NS.Object) { + msgSend(nil, self, "setVertexBuffer:", vertexBuffer) +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexBufferOffset") +AccelerationStructureTriangleGeometryDescriptor_setVertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBufferOffset: NS.Integer) { + msgSend(nil, self, "setVertexBufferOffset:", vertexBufferOffset) +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexStride") +AccelerationStructureTriangleGeometryDescriptor_setVertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexStride: NS.Integer) { + msgSend(nil, self, "setVertexStride:", vertexStride) +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="triangleCount") +AccelerationStructureTriangleGeometryDescriptor_triangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "triangleCount") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBuffer") +AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "vertexBuffer") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBufferOffset") +AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "vertexBufferOffset") +} +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexStride") +AccelerationStructureTriangleGeometryDescriptor_vertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "vertexStride") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Argument +Class Methods: + alloc +Methods: + init + access + arrayLength + bufferAlignment + bufferDataSize + bufferDataType + bufferPointerType + bufferStructType + index + isActive + isDepthTexture + name + textureDataType + textureType + threadgroupMemoryAlignment + threadgroupMemoryDataSize + type +*/ +@(objc_class="MTLArgument") +Argument :: struct { using _: NS.Object } + +@(objc_type=Argument, objc_class_name="alloc") +Argument_alloc :: proc() -> ^Argument { + return msgSend(^Argument, Argument, "alloc") +} +@(objc_type=Argument, objc_name="init") +Argument_init :: proc(self: ^Argument) -> ^Argument { + return msgSend(^Argument, self, "init") +} +@(objc_type=Argument, objc_name="access") +Argument_access :: proc(self: ^Argument) -> ArgumentAccess { + return msgSend(ArgumentAccess, self, "access") +} +@(objc_type=Argument, objc_name="arrayLength") +Argument_arrayLength :: proc(self: ^Argument) -> NS.Integer { + return msgSend(NS.Integer, self, "arrayLength") +} +@(objc_type=Argument, objc_name="bufferAlignment") +Argument_bufferAlignment :: proc(self: ^Argument) -> NS.Integer { + return msgSend(NS.Integer, self, "bufferAlignment") +} +@(objc_type=Argument, objc_name="bufferDataSize") +Argument_bufferDataSize :: proc(self: ^Argument) -> NS.Integer { + return msgSend(NS.Integer, self, "bufferDataSize") +} +@(objc_type=Argument, objc_name="bufferDataType") +Argument_bufferDataType :: proc(self: ^Argument) -> DataType { + return msgSend(DataType, self, "bufferDataType") +} +@(objc_type=Argument, objc_name="bufferPointerType") +Argument_bufferPointerType :: proc(self: ^Argument) -> ^PointerType { + return msgSend(^PointerType, self, "bufferPointerType") +} +@(objc_type=Argument, objc_name="bufferStructType") +Argument_bufferStructType :: proc(self: ^Argument) -> ^StructType { + return msgSend(^StructType, self, "bufferStructType") +} +@(objc_type=Argument, objc_name="index") +Argument_index :: proc(self: ^Argument) -> NS.Integer { + return msgSend(NS.Integer, self, "index") +} +@(objc_type=Argument, objc_name="isActive") +Argument_isActive :: proc(self: ^Argument) -> BOOL { + return msgSend(BOOL, self, "isActive") +} +@(objc_type=Argument, objc_name="isDepthTexture") +Argument_isDepthTexture :: proc(self: ^Argument) -> BOOL { + return msgSend(BOOL, self, "isDepthTexture") +} +@(objc_type=Argument, objc_name="name") +Argument_name :: proc(self: ^Argument) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} +@(objc_type=Argument, objc_name="textureDataType") +Argument_textureDataType :: proc(self: ^Argument) -> DataType { + return msgSend(DataType, self, "textureDataType") +} +@(objc_type=Argument, objc_name="textureType") +Argument_textureType :: proc(self: ^Argument) -> TextureType { + return msgSend(TextureType, self, "textureType") +} +@(objc_type=Argument, objc_name="threadgroupMemoryAlignment") +Argument_threadgroupMemoryAlignment :: proc(self: ^Argument) -> NS.Integer { + return msgSend(NS.Integer, self, "threadgroupMemoryAlignment") +} +@(objc_type=Argument, objc_name="threadgroupMemoryDataSize") +Argument_threadgroupMemoryDataSize :: proc(self: ^Argument) -> NS.Integer { + return msgSend(NS.Integer, self, "threadgroupMemoryDataSize") +} +@(objc_type=Argument, objc_name="type") +Argument_type :: proc(self: ^Argument) -> ArgumentType { + return msgSend(ArgumentType, self, "type") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ArgumentDescriptor +Class Methods: + alloc + argumentDescriptor +Methods: + init + access + arrayLength + constantBlockAlignment + dataType + index + setAccess + setArrayLength + setConstantBlockAlignment + setDataType + setIndex + setTextureType + textureType +*/ +@(objc_class="MTLArgumentDescriptor") +ArgumentDescriptor :: struct { using _: NS.Copying(ArgumentDescriptor) } + +@(objc_type=ArgumentDescriptor, objc_class_name="alloc") +ArgumentDescriptor_alloc :: proc() -> ^ArgumentDescriptor { + return msgSend(^ArgumentDescriptor, ArgumentDescriptor, "alloc") +} +@(objc_type=ArgumentDescriptor, objc_name="init") +ArgumentDescriptor_init :: proc(self: ^ArgumentDescriptor) -> ^ArgumentDescriptor { + return msgSend(^ArgumentDescriptor, self, "init") +} +@(objc_type=ArgumentDescriptor, objc_name="access") +ArgumentDescriptor_access :: proc(self: ^ArgumentDescriptor) -> ArgumentAccess { + return msgSend(ArgumentAccess, self, "access") +} +@(objc_type=ArgumentDescriptor, objc_class_name="argumentDescriptor") +ArgumentDescriptor_argumentDescriptor :: proc() -> ^ArgumentDescriptor { + return msgSend(^ArgumentDescriptor, ArgumentDescriptor, "argumentDescriptor") +} +@(objc_type=ArgumentDescriptor, objc_name="arrayLength") +ArgumentDescriptor_arrayLength :: proc(self: ^ArgumentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "arrayLength") +} +@(objc_type=ArgumentDescriptor, objc_name="constantBlockAlignment") +ArgumentDescriptor_constantBlockAlignment :: proc(self: ^ArgumentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "constantBlockAlignment") +} +@(objc_type=ArgumentDescriptor, objc_name="dataType") +ArgumentDescriptor_dataType :: proc(self: ^ArgumentDescriptor) -> DataType { + return msgSend(DataType, self, "dataType") +} +@(objc_type=ArgumentDescriptor, objc_name="index") +ArgumentDescriptor_index :: proc(self: ^ArgumentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "index") +} +@(objc_type=ArgumentDescriptor, objc_name="setAccess") +ArgumentDescriptor_setAccess :: proc(self: ^ArgumentDescriptor, access: ArgumentAccess) { + msgSend(nil, self, "setAccess:", access) +} +@(objc_type=ArgumentDescriptor, objc_name="setArrayLength") +ArgumentDescriptor_setArrayLength :: proc(self: ^ArgumentDescriptor, arrayLength: NS.Integer) { + msgSend(nil, self, "setArrayLength:", arrayLength) +} +@(objc_type=ArgumentDescriptor, objc_name="setConstantBlockAlignment") +ArgumentDescriptor_setConstantBlockAlignment :: proc(self: ^ArgumentDescriptor, constantBlockAlignment: NS.Integer) { + msgSend(nil, self, "setConstantBlockAlignment:", constantBlockAlignment) +} +@(objc_type=ArgumentDescriptor, objc_name="setDataType") +ArgumentDescriptor_setDataType :: proc(self: ^ArgumentDescriptor, dataType: DataType) { + msgSend(nil, self, "setDataType:", dataType) +} +@(objc_type=ArgumentDescriptor, objc_name="setIndex") +ArgumentDescriptor_setIndex :: proc(self: ^ArgumentDescriptor, index: NS.Integer) { + msgSend(nil, self, "setIndex:", index) +} +@(objc_type=ArgumentDescriptor, objc_name="setTextureType") +ArgumentDescriptor_setTextureType :: proc(self: ^ArgumentDescriptor, textureType: TextureType) { + msgSend(nil, self, "setTextureType:", textureType) +} +@(objc_type=ArgumentDescriptor, objc_name="textureType") +ArgumentDescriptor_textureType :: proc(self: ^ArgumentDescriptor) -> TextureType { + return msgSend(TextureType, self, "textureType") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ArrayType +Class Methods: + alloc +Methods: + init + argumentIndexStride + arrayLength + elementArrayType + elementPointerType + elementStructType + elementTextureReferenceType + elementType + stride +*/ +@(objc_class="MTLArrayType") +ArrayType :: struct { using _: NS.Object } + +@(objc_type=ArrayType, objc_class_name="alloc") +ArrayType_alloc :: proc() -> ^ArrayType { + return msgSend(^ArrayType, ArrayType, "alloc") +} +@(objc_type=ArrayType, objc_name="init") +ArrayType_init :: proc(self: ^ArrayType) -> ^ArrayType { + return msgSend(^ArrayType, self, "init") +} +@(objc_type=ArrayType, objc_name="argumentIndexStride") +ArrayType_argumentIndexStride :: proc(self: ^ArrayType) -> NS.Integer { + return msgSend(NS.Integer, self, "argumentIndexStride") +} +@(objc_type=ArrayType, objc_name="arrayLength") +ArrayType_arrayLength :: proc(self: ^ArrayType) -> NS.Integer { + return msgSend(NS.Integer, self, "arrayLength") +} +@(objc_type=ArrayType, objc_name="elementArrayType") +ArrayType_elementArrayType :: proc(self: ^ArrayType) -> ^ArrayType { + return msgSend(^ArrayType, self, "elementArrayType") +} +@(objc_type=ArrayType, objc_name="elementPointerType") +ArrayType_elementPointerType :: proc(self: ^ArrayType) -> ^PointerType { + return msgSend(^PointerType, self, "elementPointerType") +} +@(objc_type=ArrayType, objc_name="elementStructType") +ArrayType_elementStructType :: proc(self: ^ArrayType) -> ^StructType { + return msgSend(^StructType, self, "elementStructType") +} +@(objc_type=ArrayType, objc_name="elementTextureReferenceType") +ArrayType_elementTextureReferenceType :: proc(self: ^ArrayType) -> ^TextureReferenceType { + return msgSend(^TextureReferenceType, self, "elementTextureReferenceType") +} +@(objc_type=ArrayType, objc_name="elementType") +ArrayType_elementType :: proc(self: ^ArrayType) -> DataType { + return msgSend(DataType, self, "elementType") +} +@(objc_type=ArrayType, objc_name="stride") +ArrayType_stride :: proc(self: ^ArrayType) -> NS.Integer { + return msgSend(NS.Integer, self, "stride") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Attribute +Class Methods: + alloc +Methods: + init + attributeIndex + attributeType + isActive + isPatchControlPointData + isPatchData + name +*/ +@(objc_class="MTLAttribute") +Attribute :: struct { using _: NS.Object } + +@(objc_type=Attribute, objc_class_name="alloc") +Attribute_alloc :: proc() -> ^Attribute { + return msgSend(^Attribute, Attribute, "alloc") +} +@(objc_type=Attribute, objc_name="init") +Attribute_init :: proc(self: ^Attribute) -> ^Attribute { + return msgSend(^Attribute, self, "init") +} +@(objc_type=Attribute, objc_name="attributeIndex") +Attribute_attributeIndex :: proc(self: ^Attribute) -> NS.Integer { + return msgSend(NS.Integer, self, "attributeIndex") +} +@(objc_type=Attribute, objc_name="attributeType") +Attribute_attributeType :: proc(self: ^Attribute) -> DataType { + return msgSend(DataType, self, "attributeType") +} +@(objc_type=Attribute, objc_name="isActive") +Attribute_isActive :: proc(self: ^Attribute) -> BOOL { + return msgSend(BOOL, self, "isActive") +} +@(objc_type=Attribute, objc_name="isPatchControlPointData") +Attribute_isPatchControlPointData :: proc(self: ^Attribute) -> BOOL { + return msgSend(BOOL, self, "isPatchControlPointData") +} +@(objc_type=Attribute, objc_name="isPatchData") +Attribute_isPatchData :: proc(self: ^Attribute) -> BOOL { + return msgSend(BOOL, self, "isPatchData") +} +@(objc_type=Attribute, objc_name="name") +Attribute_name :: proc(self: ^Attribute) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AttributeDescriptor +Class Methods: + alloc +Methods: + init + bufferIndex + format + offset + setBufferIndex + setFormat + setOffset +*/ +@(objc_class="MTLAttributeDescriptor") +AttributeDescriptor :: struct { using _: NS.Copying(AttributeDescriptor) } + +@(objc_type=AttributeDescriptor, objc_class_name="alloc") +AttributeDescriptor_alloc :: proc() -> ^AttributeDescriptor { + return msgSend(^AttributeDescriptor, AttributeDescriptor, "alloc") +} +@(objc_type=AttributeDescriptor, objc_name="init") +AttributeDescriptor_init :: proc(self: ^AttributeDescriptor) -> ^AttributeDescriptor { + return msgSend(^AttributeDescriptor, self, "init") +} +@(objc_type=AttributeDescriptor, objc_name="bufferIndex") +AttributeDescriptor_bufferIndex :: proc(self: ^AttributeDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "bufferIndex") +} +@(objc_type=AttributeDescriptor, objc_name="format") +AttributeDescriptor_format :: proc(self: ^AttributeDescriptor) -> AttributeFormat { + return msgSend(AttributeFormat, self, "format") +} +@(objc_type=AttributeDescriptor, objc_name="offset") +AttributeDescriptor_offset :: proc(self: ^AttributeDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "offset") +} +@(objc_type=AttributeDescriptor, objc_name="setBufferIndex") +AttributeDescriptor_setBufferIndex :: proc(self: ^AttributeDescriptor, bufferIndex: NS.Integer) { + msgSend(nil, self, "setBufferIndex:", bufferIndex) +} +@(objc_type=AttributeDescriptor, objc_name="setFormat") +AttributeDescriptor_setFormat :: proc(self: ^AttributeDescriptor, format: AttributeFormat) { + msgSend(nil, self, "setFormat:", format) +} +@(objc_type=AttributeDescriptor, objc_name="setOffset") +AttributeDescriptor_setOffset :: proc(self: ^AttributeDescriptor, offset: NS.Integer) { + msgSend(nil, self, "setOffset:", offset) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AttributeDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLAttributeDescriptorArray") +AttributeDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=AttributeDescriptorArray, objc_class_name="alloc") +AttributeDescriptorArray_alloc :: proc() -> ^AttributeDescriptorArray { + return msgSend(^AttributeDescriptorArray, AttributeDescriptorArray, "alloc") +} +@(objc_type=AttributeDescriptorArray, objc_name="init") +AttributeDescriptorArray_init :: proc(self: ^AttributeDescriptorArray) -> ^AttributeDescriptorArray { + return msgSend(^AttributeDescriptorArray, self, "init") +} +@(objc_type=AttributeDescriptorArray, objc_name="objectAtIndexedSubscript") +AttributeDescriptorArray_objectAtIndexedSubscript :: proc(self: ^AttributeDescriptorArray, index: ^NS.Object) -> ^AttributeDescriptor { + return msgSend(^AttributeDescriptor, self, "objectAtIndexedSubscript:", index) +} +@(objc_type=AttributeDescriptorArray, objc_name="setObject") +AttributeDescriptorArray_setObject :: proc(self: ^AttributeDescriptorArray, attributeDesc: ^AttributeDescriptor, index: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attributeDesc, index) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BinaryArchiveDescriptor +Class Methods: + alloc +Methods: + init + setUrl + url +*/ +@(objc_class="MTLBinaryArchiveDescriptor") +BinaryArchiveDescriptor :: struct { using _: NS.Copying(BinaryArchiveDescriptor) } + +@(objc_type=BinaryArchiveDescriptor, objc_class_name="alloc") +BinaryArchiveDescriptor_alloc :: proc() -> ^BinaryArchiveDescriptor { + return msgSend(^BinaryArchiveDescriptor, BinaryArchiveDescriptor, "alloc") +} +@(objc_type=BinaryArchiveDescriptor, objc_name="init") +BinaryArchiveDescriptor_init :: proc(self: ^BinaryArchiveDescriptor) -> ^BinaryArchiveDescriptor { + return msgSend(^BinaryArchiveDescriptor, self, "init") +} +@(objc_type=BinaryArchiveDescriptor, objc_name="setUrl") +BinaryArchiveDescriptor_setUrl :: proc(self: ^BinaryArchiveDescriptor, url: ^NS.URL) { + msgSend(nil, self, "setUrl:", url) +} +@(objc_type=BinaryArchiveDescriptor, objc_name="url") +BinaryArchiveDescriptor_url :: proc(self: ^BinaryArchiveDescriptor) -> ^NS.URL { + return msgSend(^NS.URL, self, "url") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BlitPassDescriptor +Class Methods: + alloc + blitPassDescriptor +Methods: + init + sampleBufferAttachments +*/ +@(objc_class="MTLBlitPassDescriptor") +BlitPassDescriptor :: struct { using _: NS.Copying(BlitPassDescriptor) } + +@(objc_type=BlitPassDescriptor, objc_class_name="alloc") +BlitPassDescriptor_alloc :: proc() -> ^BlitPassDescriptor { + return msgSend(^BlitPassDescriptor, BlitPassDescriptor, "alloc") +} +@(objc_type=BlitPassDescriptor, objc_name="init") +BlitPassDescriptor_init :: proc(self: ^BlitPassDescriptor) -> ^BlitPassDescriptor { + return msgSend(^BlitPassDescriptor, self, "init") +} +@(objc_type=BlitPassDescriptor, objc_class_name="blitPassDescriptor") +BlitPassDescriptor_blitPassDescriptor :: proc() -> ^BlitPassDescriptor { + return msgSend(^BlitPassDescriptor, BlitPassDescriptor, "blitPassDescriptor") +} +@(objc_type=BlitPassDescriptor, objc_name="sampleBufferAttachments") +BlitPassDescriptor_sampleBufferAttachments :: proc(self: ^BlitPassDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptorArray { + return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BlitPassSampleBufferAttachmentDescriptor +Class Methods: + alloc +Methods: + init + endOfEncoderSampleIndex + sampleBuffer + setEndOfEncoderSampleIndex + setSampleBuffer + setStartOfEncoderSampleIndex + startOfEncoderSampleIndex +*/ +@(objc_class="MTLBlitPassSampleBufferAttachmentDescriptor") +BlitPassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(BlitPassSampleBufferAttachmentDescriptor) } + +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +BlitPassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^BlitPassSampleBufferAttachmentDescriptor { + return msgSend(^BlitPassSampleBufferAttachmentDescriptor, BlitPassSampleBufferAttachmentDescriptor, "alloc") +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="init") +BlitPassSampleBufferAttachmentDescriptor_init :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { + return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "init") +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") +BlitPassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") +BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { + return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") +BlitPassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { + msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") +BlitPassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { + msgSend(nil, self, "setSampleBuffer:", sampleBuffer) +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") +BlitPassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { + msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") +BlitPassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BlitPassSampleBufferAttachmentDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLBlitPassSampleBufferAttachmentDescriptorArray") +BlitPassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +BlitPassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^BlitPassSampleBufferAttachmentDescriptorArray { + return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, BlitPassSampleBufferAttachmentDescriptorArray, "alloc") +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="init") +BlitPassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray) -> ^BlitPassSampleBufferAttachmentDescriptorArray { + return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, self, "init") +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") +BlitPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^BlitPassSampleBufferAttachmentDescriptor { + return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) +} +@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") +BlitPassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachment: ^BlitPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BufferLayoutDescriptor +Class Methods: + alloc +Methods: + init + setStepFunction + setStepRate + setStride + stepFunction + stepRate + stride +*/ +@(objc_class="MTLBufferLayoutDescriptor") +BufferLayoutDescriptor :: struct { using _: NS.Copying(BufferLayoutDescriptor) } + +@(objc_type=BufferLayoutDescriptor, objc_class_name="alloc") +BufferLayoutDescriptor_alloc :: proc() -> ^BufferLayoutDescriptor { + return msgSend(^BufferLayoutDescriptor, BufferLayoutDescriptor, "alloc") +} +@(objc_type=BufferLayoutDescriptor, objc_name="init") +BufferLayoutDescriptor_init :: proc(self: ^BufferLayoutDescriptor) -> ^BufferLayoutDescriptor { + return msgSend(^BufferLayoutDescriptor, self, "init") +} +@(objc_type=BufferLayoutDescriptor, objc_name="setStepFunction") +BufferLayoutDescriptor_setStepFunction :: proc(self: ^BufferLayoutDescriptor, stepFunction: StepFunction) { + msgSend(nil, self, "setStepFunction:", stepFunction) +} +@(objc_type=BufferLayoutDescriptor, objc_name="setStepRate") +BufferLayoutDescriptor_setStepRate :: proc(self: ^BufferLayoutDescriptor, stepRate: NS.Integer) { + msgSend(nil, self, "setStepRate:", stepRate) +} +@(objc_type=BufferLayoutDescriptor, objc_name="setStride") +BufferLayoutDescriptor_setStride :: proc(self: ^BufferLayoutDescriptor, stride: NS.Integer) { + msgSend(nil, self, "setStride:", stride) +} +@(objc_type=BufferLayoutDescriptor, objc_name="stepFunction") +BufferLayoutDescriptor_stepFunction :: proc(self: ^BufferLayoutDescriptor) -> StepFunction { + return msgSend(StepFunction, self, "stepFunction") +} +@(objc_type=BufferLayoutDescriptor, objc_name="stepRate") +BufferLayoutDescriptor_stepRate :: proc(self: ^BufferLayoutDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "stepRate") +} +@(objc_type=BufferLayoutDescriptor, objc_name="stride") +BufferLayoutDescriptor_stride :: proc(self: ^BufferLayoutDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "stride") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BufferLayoutDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLBufferLayoutDescriptorArray") +BufferLayoutDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=BufferLayoutDescriptorArray, objc_class_name="alloc") +BufferLayoutDescriptorArray_alloc :: proc() -> ^BufferLayoutDescriptorArray { + return msgSend(^BufferLayoutDescriptorArray, BufferLayoutDescriptorArray, "alloc") +} +@(objc_type=BufferLayoutDescriptorArray, objc_name="init") +BufferLayoutDescriptorArray_init :: proc(self: ^BufferLayoutDescriptorArray) -> ^BufferLayoutDescriptorArray { + return msgSend(^BufferLayoutDescriptorArray, self, "init") +} +@(objc_type=BufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") +BufferLayoutDescriptorArray_objectAtIndexedSubscript :: proc(self: ^BufferLayoutDescriptorArray, index: ^NS.Object) -> ^BufferLayoutDescriptor { + return msgSend(^BufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) +} +@(objc_type=BufferLayoutDescriptorArray, objc_name="setObject") +BufferLayoutDescriptorArray_setObject :: proc(self: ^BufferLayoutDescriptorArray, bufferDesc: ^BufferLayoutDescriptor, index: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", bufferDesc, index) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CaptureDescriptor +Class Methods: + alloc +Methods: + init + captureObject + destination + outputURL + setCaptureObject + setDestination + setOutputURL +*/ +@(objc_class="MTLCaptureDescriptor") +CaptureDescriptor :: struct { using _: NS.Copying(CaptureDescriptor) } + +@(objc_type=CaptureDescriptor, objc_class_name="alloc") +CaptureDescriptor_alloc :: proc() -> ^CaptureDescriptor { + return msgSend(^CaptureDescriptor, CaptureDescriptor, "alloc") +} +@(objc_type=CaptureDescriptor, objc_name="init") +CaptureDescriptor_init :: proc(self: ^CaptureDescriptor) -> ^CaptureDescriptor { + return msgSend(^CaptureDescriptor, self, "init") +} +@(objc_type=CaptureDescriptor, objc_name="captureObject") +CaptureDescriptor_captureObject :: proc(self: ^CaptureDescriptor) -> ^CaptureDescriptor { + return msgSend(^CaptureDescriptor, self, "captureObject") +} +@(objc_type=CaptureDescriptor, objc_name="destination") +CaptureDescriptor_destination :: proc(self: ^CaptureDescriptor) -> CaptureDestination { + return msgSend(CaptureDestination, self, "destination") +} +@(objc_type=CaptureDescriptor, objc_name="outputURL") +CaptureDescriptor_outputURL :: proc(self: ^CaptureDescriptor) -> ^NS.URL { + return msgSend(^NS.URL, self, "outputURL") +} +@(objc_type=CaptureDescriptor, objc_name="setCaptureObject") +CaptureDescriptor_setCaptureObject :: proc(self: ^CaptureDescriptor, captureObject: ^NS.Object) { + msgSend(nil, self, "setCaptureObject:", captureObject) +} +@(objc_type=CaptureDescriptor, objc_name="setDestination") +CaptureDescriptor_setDestination :: proc(self: ^CaptureDescriptor, destination: CaptureDestination) { + msgSend(nil, self, "setDestination:", destination) +} +@(objc_type=CaptureDescriptor, objc_name="setOutputURL") +CaptureDescriptor_setOutputURL :: proc(self: ^CaptureDescriptor, outputURL: ^NS.URL) { + msgSend(nil, self, "setOutputURL:", outputURL) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CaptureManager +Class Methods: + alloc + sharedCaptureManager +Methods: + defaultCaptureScope + init + isCapturing + newCaptureScopeWithCommandQueue + newCaptureScopeWithDevice + setDefaultCaptureScope + startCaptureWithCommandQueue + startCaptureWithDescriptor + startCaptureWithDevice + startCaptureWithScope + stopCapture + supportsDestination +*/ +@(objc_class="MTLCaptureManager") +CaptureManager :: struct { using _: NS.Object } + +@(objc_type=CaptureManager, objc_class_name="alloc") +CaptureManager_alloc :: proc() -> ^CaptureManager { + return msgSend(^CaptureManager, CaptureManager, "alloc") +} +@(objc_type=CaptureManager, objc_name="defaultCaptureScope") +CaptureManager_defaultCaptureScope :: proc(self: ^CaptureManager) -> ^CaptureManager { + return msgSend(^CaptureManager, self, "defaultCaptureScope") +} +@(objc_type=CaptureManager, objc_name="init") +CaptureManager_init :: proc(self: ^CaptureManager) -> ^CaptureManager { + return msgSend(^CaptureManager, self, "init") +} +@(objc_type=CaptureManager, objc_name="isCapturing") +CaptureManager_isCapturing :: proc(self: ^CaptureManager) -> BOOL { + return msgSend(BOOL, self, "isCapturing") +} +@(objc_type=CaptureManager, objc_name="newCaptureScopeWithCommandQueue") +CaptureManager_newCaptureScopeWithCommandQueue :: proc(self: ^CaptureManager, commandQueue: ^NS.Object) -> ^CaptureManager { + return msgSend(^CaptureManager, self, "newCaptureScopeWithCommandQueue:", commandQueue) +} +@(objc_type=CaptureManager, objc_name="newCaptureScopeWithDevice") +CaptureManager_newCaptureScopeWithDevice :: proc(self: ^CaptureManager, device: ^NS.Object) -> ^CaptureManager { + return msgSend(^CaptureManager, self, "newCaptureScopeWithDevice:", device) +} +@(objc_type=CaptureManager, objc_name="setDefaultCaptureScope") +CaptureManager_setDefaultCaptureScope :: proc(self: ^CaptureManager, defaultCaptureScope: ^NS.Object) { + msgSend(nil, self, "setDefaultCaptureScope:", defaultCaptureScope) +} +@(objc_type=CaptureManager, objc_class_name="sharedCaptureManager") +CaptureManager_sharedCaptureManager :: proc() -> ^CaptureManager { + return msgSend(^CaptureManager, CaptureManager, "sharedCaptureManager") +} +@(objc_type=CaptureManager, objc_name="startCaptureWithCommandQueue") +CaptureManager_startCaptureWithCommandQueue :: proc(self: ^CaptureManager, commandQueue: ^NS.Object) { + msgSend(nil, self, "startCaptureWithCommandQueue:", commandQueue) +} +@(objc_type=CaptureManager, objc_name="startCaptureWithDescriptor") +CaptureManager_startCaptureWithDescriptor :: proc(self: ^CaptureManager, descriptor: ^CaptureDescriptor, error: ^^NS.Error ) -> BOOL { + return msgSend(BOOL, self, "startCaptureWithDescriptor:error:", descriptor, error) +} +@(objc_type=CaptureManager, objc_name="startCaptureWithDevice") +CaptureManager_startCaptureWithDevice :: proc(self: ^CaptureManager, device: ^NS.Object) { + msgSend(nil, self, "startCaptureWithDevice:", device) +} +@(objc_type=CaptureManager, objc_name="startCaptureWithScope") +CaptureManager_startCaptureWithScope :: proc(self: ^CaptureManager, captureScope: ^NS.Object) { + msgSend(nil, self, "startCaptureWithScope:", captureScope) +} +@(objc_type=CaptureManager, objc_name="stopCapture") +CaptureManager_stopCapture :: proc(self: ^CaptureManager) { + msgSend(nil, self, "stopCapture") +} +@(objc_type=CaptureManager, objc_name="supportsDestination") +CaptureManager_supportsDestination :: proc(self: ^CaptureManager, destination: CaptureDestination) -> BOOL { + return msgSend(BOOL, self, "supportsDestination:", destination) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CommandBufferDescriptor +Class Methods: + alloc +Methods: + init + errorOptions + retainedReferences + setErrorOptions + setRetainedReferences +*/ +@(objc_class="MTLCommandBufferDescriptor") +CommandBufferDescriptor :: struct { using _: NS.Copying(CommandBufferDescriptor) } + +@(objc_type=CommandBufferDescriptor, objc_class_name="alloc") +CommandBufferDescriptor_alloc :: proc() -> ^CommandBufferDescriptor { + return msgSend(^CommandBufferDescriptor, CommandBufferDescriptor, "alloc") +} +@(objc_type=CommandBufferDescriptor, objc_name="init") +CommandBufferDescriptor_init :: proc(self: ^CommandBufferDescriptor) -> ^CommandBufferDescriptor { + return msgSend(^CommandBufferDescriptor, self, "init") +} +@(objc_type=CommandBufferDescriptor, objc_name="errorOptions") +CommandBufferDescriptor_errorOptions :: proc(self: ^CommandBufferDescriptor) -> CommandBufferErrorOption { + return msgSend(CommandBufferErrorOption, self, "errorOptions") +} +@(objc_type=CommandBufferDescriptor, objc_name="retainedReferences") +CommandBufferDescriptor_retainedReferences :: proc(self: ^CommandBufferDescriptor) -> BOOL { + return msgSend(BOOL, self, "retainedReferences") +} +@(objc_type=CommandBufferDescriptor, objc_name="setErrorOptions") +CommandBufferDescriptor_setErrorOptions :: proc(self: ^CommandBufferDescriptor, errorOptions: CommandBufferErrorOption) { + msgSend(nil, self, "setErrorOptions:", errorOptions) +} +@(objc_type=CommandBufferDescriptor, objc_name="setRetainedReferences") +CommandBufferDescriptor_setRetainedReferences :: proc(self: ^CommandBufferDescriptor, retainedReferences: BOOL) { + msgSend(nil, self, "setRetainedReferences:", retainedReferences) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CompileOptions +Class Methods: + alloc +Methods: + init + fastMathEnabled + installName + languageVersion + libraries + libraryType + preprocessorMacros + preserveInvariance + setFastMathEnabled + setInstallName + setLanguageVersion + setLibraries + setLibraryType + setPreprocessorMacros + setPreserveInvariance +*/ +@(objc_class="MTLCompileOptions") +CompileOptions :: struct { using _: NS.Copying(CompileOptions) } + +@(objc_type=CompileOptions, objc_class_name="alloc") +CompileOptions_alloc :: proc() -> ^CompileOptions { + return msgSend(^CompileOptions, CompileOptions, "alloc") +} +@(objc_type=CompileOptions, objc_name="init") +CompileOptions_init :: proc(self: ^CompileOptions) -> ^CompileOptions { + return msgSend(^CompileOptions, self, "init") +} +@(objc_type=CompileOptions, objc_name="fastMathEnabled") +CompileOptions_fastMathEnabled :: proc(self: ^CompileOptions) -> BOOL { + return msgSend(BOOL, self, "fastMathEnabled") +} +@(objc_type=CompileOptions, objc_name="installName") +CompileOptions_installName :: proc(self: ^CompileOptions) -> ^NS.String { + return msgSend(^NS.String, self, "installName") +} +@(objc_type=CompileOptions, objc_name="languageVersion") +CompileOptions_languageVersion :: proc(self: ^CompileOptions) -> LanguageVersion { + return msgSend(LanguageVersion, self, "languageVersion") +} +@(objc_type=CompileOptions, objc_name="libraries") +CompileOptions_libraries :: proc(self: ^CompileOptions) -> ^NS.Array { + return msgSend(^NS.Array, self, "libraries") +} +@(objc_type=CompileOptions, objc_name="libraryType") +CompileOptions_libraryType :: proc(self: ^CompileOptions) -> LibraryType { + return msgSend(LibraryType, self, "libraryType") +} +@(objc_type=CompileOptions, objc_name="preprocessorMacros") +CompileOptions_preprocessorMacros :: proc(self: ^CompileOptions) -> ^NS.Dictionary { + return msgSend(^NS.Dictionary, self, "preprocessorMacros") +} +@(objc_type=CompileOptions, objc_name="preserveInvariance") +CompileOptions_preserveInvariance :: proc(self: ^CompileOptions) -> BOOL { + return msgSend(BOOL, self, "preserveInvariance") +} +@(objc_type=CompileOptions, objc_name="setFastMathEnabled") +CompileOptions_setFastMathEnabled :: proc(self: ^CompileOptions, fastMathEnabled: BOOL) { + msgSend(nil, self, "setFastMathEnabled:", fastMathEnabled) +} +@(objc_type=CompileOptions, objc_name="setInstallName") +CompileOptions_setInstallName :: proc(self: ^CompileOptions, installName: ^NS.String) { + msgSend(nil, self, "setInstallName:", installName) +} +@(objc_type=CompileOptions, objc_name="setLanguageVersion") +CompileOptions_setLanguageVersion :: proc(self: ^CompileOptions, languageVersion: LanguageVersion) { + msgSend(nil, self, "setLanguageVersion:", languageVersion) +} +@(objc_type=CompileOptions, objc_name="setLibraries") +CompileOptions_setLibraries :: proc(self: ^CompileOptions, libraries: ^NS.Array) { + msgSend(nil, self, "setLibraries:", libraries) +} +@(objc_type=CompileOptions, objc_name="setLibraryType") +CompileOptions_setLibraryType :: proc(self: ^CompileOptions, libraryType: LibraryType) { + msgSend(nil, self, "setLibraryType:", libraryType) +} +@(objc_type=CompileOptions, objc_name="setPreprocessorMacros") +CompileOptions_setPreprocessorMacros :: proc(self: ^CompileOptions, preprocessorMacros: ^NS.Dictionary) { + msgSend(nil, self, "setPreprocessorMacros:", preprocessorMacros) +} +@(objc_type=CompileOptions, objc_name="setPreserveInvariance") +CompileOptions_setPreserveInvariance :: proc(self: ^CompileOptions, preserveInvariance: BOOL) { + msgSend(nil, self, "setPreserveInvariance:", preserveInvariance) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ComputePassDescriptor +Class Methods: + alloc + computePassDescriptor +Methods: + init + dispatchType + sampleBufferAttachments + setDispatchType +*/ +@(objc_class="MTLComputePassDescriptor") +ComputePassDescriptor :: struct { using _: NS.Copying(ComputePassDescriptor) } + +@(objc_type=ComputePassDescriptor, objc_class_name="alloc") +ComputePassDescriptor_alloc :: proc() -> ^ComputePassDescriptor { + return msgSend(^ComputePassDescriptor, ComputePassDescriptor, "alloc") +} +@(objc_type=ComputePassDescriptor, objc_name="init") +ComputePassDescriptor_init :: proc(self: ^ComputePassDescriptor) -> ^ComputePassDescriptor { + return msgSend(^ComputePassDescriptor, self, "init") +} +@(objc_type=ComputePassDescriptor, objc_class_name="computePassDescriptor") +ComputePassDescriptor_computePassDescriptor :: proc() -> ^ComputePassDescriptor { + return msgSend(^ComputePassDescriptor, ComputePassDescriptor, "computePassDescriptor") +} +@(objc_type=ComputePassDescriptor, objc_name="dispatchType") +ComputePassDescriptor_dispatchType :: proc(self: ^ComputePassDescriptor) -> DispatchType { + return msgSend(DispatchType, self, "dispatchType") +} +@(objc_type=ComputePassDescriptor, objc_name="sampleBufferAttachments") +ComputePassDescriptor_sampleBufferAttachments :: proc(self: ^ComputePassDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptorArray { + return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") +} +@(objc_type=ComputePassDescriptor, objc_name="setDispatchType") +ComputePassDescriptor_setDispatchType :: proc(self: ^ComputePassDescriptor, dispatchType: DispatchType) { + msgSend(nil, self, "setDispatchType:", dispatchType) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ComputePassSampleBufferAttachmentDescriptor +Class Methods: + alloc +Methods: + init + endOfEncoderSampleIndex + sampleBuffer + setEndOfEncoderSampleIndex + setSampleBuffer + setStartOfEncoderSampleIndex + startOfEncoderSampleIndex +*/ +@(objc_class="MTLComputePassSampleBufferAttachmentDescriptor") +ComputePassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(ComputePassSampleBufferAttachmentDescriptor) } + +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +ComputePassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^ComputePassSampleBufferAttachmentDescriptor { + return msgSend(^ComputePassSampleBufferAttachmentDescriptor, ComputePassSampleBufferAttachmentDescriptor, "alloc") +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="init") +ComputePassSampleBufferAttachmentDescriptor_init :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { + return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "init") +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") +ComputePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") +ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { + return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") +ComputePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { + msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") +ComputePassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { + msgSend(nil, self, "setSampleBuffer:", sampleBuffer) +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") +ComputePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { + msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") +ComputePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ComputePassSampleBufferAttachmentDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLComputePassSampleBufferAttachmentDescriptorArray") +ComputePassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +ComputePassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^ComputePassSampleBufferAttachmentDescriptorArray { + return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, ComputePassSampleBufferAttachmentDescriptorArray, "alloc") +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="init") +ComputePassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray) -> ^ComputePassSampleBufferAttachmentDescriptorArray { + return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, self, "init") +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") +ComputePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ComputePassSampleBufferAttachmentDescriptor { + return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) +} +@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") +ComputePassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachment: ^ComputePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ComputePipelineDescriptor +Class Methods: + alloc +Methods: + init + binaryArchives + buffers + computeFunction + insertLibraries + label + linkedFunctions + maxCallStackDepth + maxTotalThreadsPerThreadgroup + reset + setBinaryArchives + setComputeFunction + setInsertLibraries + setLabel + setLinkedFunctions + setMaxCallStackDepth + setMaxTotalThreadsPerThreadgroup + setStageInputDescriptor + setSupportAddingBinaryFunctions + setSupportIndirectCommandBuffers + setThreadGroupSizeIsMultipleOfThreadExecutionWidth + stageInputDescriptor + supportAddingBinaryFunctions + supportIndirectCommandBuffers + threadGroupSizeIsMultipleOfThreadExecutionWidth +*/ +@(objc_class="MTLComputePipelineDescriptor") +ComputePipelineDescriptor :: struct { using _: NS.Copying(ComputePipelineDescriptor) } + +@(objc_type=ComputePipelineDescriptor, objc_class_name="alloc") +ComputePipelineDescriptor_alloc :: proc() -> ^ComputePipelineDescriptor { + return msgSend(^ComputePipelineDescriptor, ComputePipelineDescriptor, "alloc") +} +@(objc_type=ComputePipelineDescriptor, objc_name="init") +ComputePipelineDescriptor_init :: proc(self: ^ComputePipelineDescriptor) -> ^ComputePipelineDescriptor { + return msgSend(^ComputePipelineDescriptor, self, "init") +} +@(objc_type=ComputePipelineDescriptor, objc_name="binaryArchives") +ComputePipelineDescriptor_binaryArchives :: proc(self: ^ComputePipelineDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "binaryArchives") +} +@(objc_type=ComputePipelineDescriptor, objc_name="buffers") +ComputePipelineDescriptor_buffers :: proc(self: ^ComputePipelineDescriptor) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "buffers") +} +@(objc_type=ComputePipelineDescriptor, objc_name="computeFunction") +ComputePipelineDescriptor_computeFunction :: proc(self: ^ComputePipelineDescriptor) -> ^ComputePipelineDescriptor { + return msgSend(^ComputePipelineDescriptor, self, "computeFunction") +} +@(objc_type=ComputePipelineDescriptor, objc_name="insertLibraries") +ComputePipelineDescriptor_insertLibraries :: proc(self: ^ComputePipelineDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "insertLibraries") +} +@(objc_type=ComputePipelineDescriptor, objc_name="label") +ComputePipelineDescriptor_label :: proc(self: ^ComputePipelineDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=ComputePipelineDescriptor, objc_name="linkedFunctions") +ComputePipelineDescriptor_linkedFunctions :: proc(self: ^ComputePipelineDescriptor) -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, self, "linkedFunctions") +} +@(objc_type=ComputePipelineDescriptor, objc_name="maxCallStackDepth") +ComputePipelineDescriptor_maxCallStackDepth :: proc(self: ^ComputePipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxCallStackDepth") +} +@(objc_type=ComputePipelineDescriptor, objc_name="maxTotalThreadsPerThreadgroup") +ComputePipelineDescriptor_maxTotalThreadsPerThreadgroup :: proc(self: ^ComputePipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +} +@(objc_type=ComputePipelineDescriptor, objc_name="reset") +ComputePipelineDescriptor_reset :: proc(self: ^ComputePipelineDescriptor) { + msgSend(nil, self, "reset") +} +@(objc_type=ComputePipelineDescriptor, objc_name="setBinaryArchives") +ComputePipelineDescriptor_setBinaryArchives :: proc(self: ^ComputePipelineDescriptor, binaryArchives: ^NS.Array) { + msgSend(nil, self, "setBinaryArchives:", binaryArchives) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setComputeFunction") +ComputePipelineDescriptor_setComputeFunction :: proc(self: ^ComputePipelineDescriptor, computeFunction: ^NS.Object) { + msgSend(nil, self, "setComputeFunction:", computeFunction) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setInsertLibraries") +ComputePipelineDescriptor_setInsertLibraries :: proc(self: ^ComputePipelineDescriptor, insertLibraries: ^NS.Array) { + msgSend(nil, self, "setInsertLibraries:", insertLibraries) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setLabel") +ComputePipelineDescriptor_setLabel :: proc(self: ^ComputePipelineDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setLinkedFunctions") +ComputePipelineDescriptor_setLinkedFunctions :: proc(self: ^ComputePipelineDescriptor, linkedFunctions: ^LinkedFunctions) { + msgSend(nil, self, "setLinkedFunctions:", linkedFunctions) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setMaxCallStackDepth") +ComputePipelineDescriptor_setMaxCallStackDepth :: proc(self: ^ComputePipelineDescriptor, maxCallStackDepth: NS.Integer) { + msgSend(nil, self, "setMaxCallStackDepth:", maxCallStackDepth) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setMaxTotalThreadsPerThreadgroup") +ComputePipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: proc(self: ^ComputePipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { + msgSend(nil, self, "setMaxTotalThreadsPerThreadgroup:", maxTotalThreadsPerThreadgroup) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setStageInputDescriptor") +ComputePipelineDescriptor_setStageInputDescriptor :: proc(self: ^ComputePipelineDescriptor, stageInputDescriptor: ^StageInputOutputDescriptor) { + msgSend(nil, self, "setStageInputDescriptor:", stageInputDescriptor) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setSupportAddingBinaryFunctions") +ComputePipelineDescriptor_setSupportAddingBinaryFunctions :: proc(self: ^ComputePipelineDescriptor, supportAddingBinaryFunctions: BOOL) { + msgSend(nil, self, "setSupportAddingBinaryFunctions:", supportAddingBinaryFunctions) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setSupportIndirectCommandBuffers") +ComputePipelineDescriptor_setSupportIndirectCommandBuffers :: proc(self: ^ComputePipelineDescriptor, supportIndirectCommandBuffers: BOOL) { + msgSend(nil, self, "setSupportIndirectCommandBuffers:", supportIndirectCommandBuffers) +} +@(objc_type=ComputePipelineDescriptor, objc_name="setThreadGroupSizeIsMultipleOfThreadExecutionWidth") +ComputePipelineDescriptor_setThreadGroupSizeIsMultipleOfThreadExecutionWidth :: proc(self: ^ComputePipelineDescriptor, threadGroupSizeIsMultipleOfThreadExecutionWidth: BOOL) { + msgSend(nil, self, "setThreadGroupSizeIsMultipleOfThreadExecutionWidth:", threadGroupSizeIsMultipleOfThreadExecutionWidth) +} +@(objc_type=ComputePipelineDescriptor, objc_name="stageInputDescriptor") +ComputePipelineDescriptor_stageInputDescriptor :: proc(self: ^ComputePipelineDescriptor) -> ^StageInputOutputDescriptor { + return msgSend(^StageInputOutputDescriptor, self, "stageInputDescriptor") +} +@(objc_type=ComputePipelineDescriptor, objc_name="supportAddingBinaryFunctions") +ComputePipelineDescriptor_supportAddingBinaryFunctions :: proc(self: ^ComputePipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "supportAddingBinaryFunctions") +} +@(objc_type=ComputePipelineDescriptor, objc_name="supportIndirectCommandBuffers") +ComputePipelineDescriptor_supportIndirectCommandBuffers :: proc(self: ^ComputePipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "supportIndirectCommandBuffers") +} +@(objc_type=ComputePipelineDescriptor, objc_name="threadGroupSizeIsMultipleOfThreadExecutionWidth") +ComputePipelineDescriptor_threadGroupSizeIsMultipleOfThreadExecutionWidth :: proc(self: ^ComputePipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "threadGroupSizeIsMultipleOfThreadExecutionWidth") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ComputePipelineReflection +Class Methods: + alloc +Methods: + init + arguments +*/ +@(objc_class="MTLComputePipelineReflection") +ComputePipelineReflection :: struct { using _: NS.Object } + +@(objc_type=ComputePipelineReflection, objc_class_name="alloc") +ComputePipelineReflection_alloc :: proc() -> ^ComputePipelineReflection { + return msgSend(^ComputePipelineReflection, ComputePipelineReflection, "alloc") +} +@(objc_type=ComputePipelineReflection, objc_name="init") +ComputePipelineReflection_init :: proc(self: ^ComputePipelineReflection) -> ^ComputePipelineReflection { + return msgSend(^ComputePipelineReflection, self, "init") +} +@(objc_type=ComputePipelineReflection, objc_name="arguments") +ComputePipelineReflection_arguments :: proc(self: ^ComputePipelineReflection) -> ^NS.Array { + return msgSend(^NS.Array, self, "arguments") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CounterSampleBufferDescriptor +Class Methods: + alloc +Methods: + init + counterSet + label + sampleCount + setCounterSet + setLabel + setSampleCount + setStorageMode + storageMode +*/ +@(objc_class="MTLCounterSampleBufferDescriptor") +CounterSampleBufferDescriptor :: struct { using _: NS.Copying(CounterSampleBufferDescriptor) } + +@(objc_type=CounterSampleBufferDescriptor, objc_class_name="alloc") +CounterSampleBufferDescriptor_alloc :: proc() -> ^CounterSampleBufferDescriptor { + return msgSend(^CounterSampleBufferDescriptor, CounterSampleBufferDescriptor, "alloc") +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="init") +CounterSampleBufferDescriptor_init :: proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSampleBufferDescriptor { + return msgSend(^CounterSampleBufferDescriptor, self, "init") +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="counterSet") +CounterSampleBufferDescriptor_counterSet :: proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSampleBufferDescriptor { + return msgSend(^CounterSampleBufferDescriptor, self, "counterSet") +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="label") +CounterSampleBufferDescriptor_label :: proc(self: ^CounterSampleBufferDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="sampleCount") +CounterSampleBufferDescriptor_sampleCount :: proc(self: ^CounterSampleBufferDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "sampleCount") +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="setCounterSet") +CounterSampleBufferDescriptor_setCounterSet :: proc(self: ^CounterSampleBufferDescriptor, counterSet: ^NS.Object) { + msgSend(nil, self, "setCounterSet:", counterSet) +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="setLabel") +CounterSampleBufferDescriptor_setLabel :: proc(self: ^CounterSampleBufferDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="setSampleCount") +CounterSampleBufferDescriptor_setSampleCount :: proc(self: ^CounterSampleBufferDescriptor, sampleCount: NS.Integer) { + msgSend(nil, self, "setSampleCount:", sampleCount) +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="setStorageMode") +CounterSampleBufferDescriptor_setStorageMode :: proc(self: ^CounterSampleBufferDescriptor, storageMode: StorageMode) { + msgSend(nil, self, "setStorageMode:", storageMode) +} +@(objc_type=CounterSampleBufferDescriptor, objc_name="storageMode") +CounterSampleBufferDescriptor_storageMode :: proc(self: ^CounterSampleBufferDescriptor) -> StorageMode { + return msgSend(StorageMode, self, "storageMode") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + DepthStencilDescriptor +Class Methods: + alloc +Methods: + init + backFaceStencil + depthCompareFunction + frontFaceStencil + isDepthWriteEnabled + label + setBackFaceStencil + setDepthCompareFunction + setDepthWriteEnabled + setFrontFaceStencil + setLabel +*/ +@(objc_class="MTLDepthStencilDescriptor") +DepthStencilDescriptor :: struct { using _: NS.Copying(DepthStencilDescriptor) } + +@(objc_type=DepthStencilDescriptor, objc_class_name="alloc") +DepthStencilDescriptor_alloc :: proc() -> ^DepthStencilDescriptor { + return msgSend(^DepthStencilDescriptor, DepthStencilDescriptor, "alloc") +} +@(objc_type=DepthStencilDescriptor, objc_name="init") +DepthStencilDescriptor_init :: proc(self: ^DepthStencilDescriptor) -> ^DepthStencilDescriptor { + return msgSend(^DepthStencilDescriptor, self, "init") +} +@(objc_type=DepthStencilDescriptor, objc_name="backFaceStencil") +DepthStencilDescriptor_backFaceStencil :: proc(self: ^DepthStencilDescriptor) -> ^StencilDescriptor { + return msgSend(^StencilDescriptor, self, "backFaceStencil") +} +@(objc_type=DepthStencilDescriptor, objc_name="depthCompareFunction") +DepthStencilDescriptor_depthCompareFunction :: proc(self: ^DepthStencilDescriptor) -> CompareFunction { + return msgSend(CompareFunction, self, "depthCompareFunction") +} +@(objc_type=DepthStencilDescriptor, objc_name="frontFaceStencil") +DepthStencilDescriptor_frontFaceStencil :: proc(self: ^DepthStencilDescriptor) -> ^StencilDescriptor { + return msgSend(^StencilDescriptor, self, "frontFaceStencil") +} +@(objc_type=DepthStencilDescriptor, objc_name="isDepthWriteEnabled") +DepthStencilDescriptor_isDepthWriteEnabled :: proc(self: ^DepthStencilDescriptor) -> BOOL { + return msgSend(BOOL, self, "isDepthWriteEnabled") +} +@(objc_type=DepthStencilDescriptor, objc_name="label") +DepthStencilDescriptor_label :: proc(self: ^DepthStencilDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=DepthStencilDescriptor, objc_name="setBackFaceStencil") +DepthStencilDescriptor_setBackFaceStencil :: proc(self: ^DepthStencilDescriptor, backFaceStencil: ^StencilDescriptor) { + msgSend(nil, self, "setBackFaceStencil:", backFaceStencil) +} +@(objc_type=DepthStencilDescriptor, objc_name="setDepthCompareFunction") +DepthStencilDescriptor_setDepthCompareFunction :: proc(self: ^DepthStencilDescriptor, depthCompareFunction: CompareFunction) { + msgSend(nil, self, "setDepthCompareFunction:", depthCompareFunction) +} +@(objc_type=DepthStencilDescriptor, objc_name="setDepthWriteEnabled") +DepthStencilDescriptor_setDepthWriteEnabled :: proc(self: ^DepthStencilDescriptor, depthWriteEnabled: BOOL) { + msgSend(nil, self, "setDepthWriteEnabled:", depthWriteEnabled) +} +@(objc_type=DepthStencilDescriptor, objc_name="setFrontFaceStencil") +DepthStencilDescriptor_setFrontFaceStencil :: proc(self: ^DepthStencilDescriptor, frontFaceStencil: ^StencilDescriptor) { + msgSend(nil, self, "setFrontFaceStencil:", frontFaceStencil) +} +@(objc_type=DepthStencilDescriptor, objc_name="setLabel") +DepthStencilDescriptor_setLabel :: proc(self: ^DepthStencilDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + FunctionConstant +Class Methods: + alloc +Methods: + init + index + name + required + type +*/ +@(objc_class="MTLFunctionConstant") +FunctionConstant :: struct { using _: NS.Copying(FunctionConstant) } + +@(objc_type=FunctionConstant, objc_class_name="alloc") +FunctionConstant_alloc :: proc() -> ^FunctionConstant { + return msgSend(^FunctionConstant, FunctionConstant, "alloc") +} +@(objc_type=FunctionConstant, objc_name="init") +FunctionConstant_init :: proc(self: ^FunctionConstant) -> ^FunctionConstant { + return msgSend(^FunctionConstant, self, "init") +} +@(objc_type=FunctionConstant, objc_name="index") +FunctionConstant_index :: proc(self: ^FunctionConstant) -> NS.Integer { + return msgSend(NS.Integer, self, "index") +} +@(objc_type=FunctionConstant, objc_name="name") +FunctionConstant_name :: proc(self: ^FunctionConstant) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} +@(objc_type=FunctionConstant, objc_name="required") +FunctionConstant_required :: proc(self: ^FunctionConstant) -> BOOL { + return msgSend(BOOL, self, "required") +} +@(objc_type=FunctionConstant, objc_name="type") +FunctionConstant_type :: proc(self: ^FunctionConstant) -> DataType { + return msgSend(DataType, self, "type") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + FunctionConstantValues +Class Methods: + alloc +Methods: + init + reset + setConstantValue + setConstantValue + setConstantValues +*/ +@(objc_class="MTLFunctionConstantValues") +FunctionConstantValues :: struct { using _: NS.Copying(FunctionConstantValues) } + +@(objc_type=FunctionConstantValues, objc_class_name="alloc") +FunctionConstantValues_alloc :: proc() -> ^FunctionConstantValues { + return msgSend(^FunctionConstantValues, FunctionConstantValues, "alloc") +} +@(objc_type=FunctionConstantValues, objc_name="init") +FunctionConstantValues_init :: proc(self: ^FunctionConstantValues) -> ^FunctionConstantValues { + return msgSend(^FunctionConstantValues, self, "init") +} +@(objc_type=FunctionConstantValues, objc_name="reset") +FunctionConstantValues_reset :: proc(self: ^FunctionConstantValues) { + msgSend(nil, self, "reset") +} +@(objc_type=FunctionConstantValues, objc_name="setConstantValue_type_atIndex_") +FunctionConstantValues_setConstantValue_type_atIndex_ :: proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, index: ^NS.Object) { + msgSend(nil, self, "setConstantValue:type:atIndex:", value, type, index) +} +@(objc_type=FunctionConstantValues, objc_name="setConstantValue_type_withName_") +FunctionConstantValues_setConstantValue_type_withName_ :: proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, name: ^NS.String) { + msgSend(nil, self, "setConstantValue:type:withName:", value, type, name) +} +@(objc_type=FunctionConstantValues, objc_name="setConstantValues") +FunctionConstantValues_setConstantValues :: proc(self: ^FunctionConstantValues, values: rawptr, type: DataType, range: NS.Range) { + msgSend(nil, self, "setConstantValues:type:withRange:", values, type, range) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + FunctionDescriptor +Class Methods: + alloc + functionDescriptor +Methods: + init + constantValues + name + options + setConstantValues + setName + setOptions + setSpecializedName + specializedName +*/ +@(objc_class="MTLFunctionDescriptor") +FunctionDescriptor :: struct { using _: NS.Copying(FunctionDescriptor) } + +@(objc_type=FunctionDescriptor, objc_class_name="alloc") +FunctionDescriptor_alloc :: proc() -> ^FunctionDescriptor { + return msgSend(^FunctionDescriptor, FunctionDescriptor, "alloc") +} +@(objc_type=FunctionDescriptor, objc_name="init") +FunctionDescriptor_init :: proc(self: ^FunctionDescriptor) -> ^FunctionDescriptor { + return msgSend(^FunctionDescriptor, self, "init") +} +@(objc_type=FunctionDescriptor, objc_name="constantValues") +FunctionDescriptor_constantValues :: proc(self: ^FunctionDescriptor) -> ^FunctionConstantValues { + return msgSend(^FunctionConstantValues, self, "constantValues") +} +@(objc_type=FunctionDescriptor, objc_class_name="functionDescriptor") +FunctionDescriptor_functionDescriptor :: proc() -> ^FunctionDescriptor { + return msgSend(^FunctionDescriptor, FunctionDescriptor, "functionDescriptor") +} +@(objc_type=FunctionDescriptor, objc_name="name") +FunctionDescriptor_name :: proc(self: ^FunctionDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} +@(objc_type=FunctionDescriptor, objc_name="options") +FunctionDescriptor_options :: proc(self: ^FunctionDescriptor) -> FunctionOptions { + return msgSend(FunctionOptions, self, "options") +} +@(objc_type=FunctionDescriptor, objc_name="setConstantValues") +FunctionDescriptor_setConstantValues :: proc(self: ^FunctionDescriptor, constantValues: ^FunctionConstantValues) { + msgSend(nil, self, "setConstantValues:", constantValues) +} +@(objc_type=FunctionDescriptor, objc_name="setName") +FunctionDescriptor_setName :: proc(self: ^FunctionDescriptor, name: ^NS.String) { + msgSend(nil, self, "setName:", name) +} +@(objc_type=FunctionDescriptor, objc_name="setOptions") +FunctionDescriptor_setOptions :: proc(self: ^FunctionDescriptor, options: FunctionOptions) { + msgSend(nil, self, "setOptions:", options) +} +@(objc_type=FunctionDescriptor, objc_name="setSpecializedName") +FunctionDescriptor_setSpecializedName :: proc(self: ^FunctionDescriptor, specializedName: ^NS.String) { + msgSend(nil, self, "setSpecializedName:", specializedName) +} +@(objc_type=FunctionDescriptor, objc_name="specializedName") +FunctionDescriptor_specializedName :: proc(self: ^FunctionDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "specializedName") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + IntersectionFunctionDescriptor +Class Methods: + alloc +Methods: + init +*/ +@(objc_class="MTLIntersectionFunctionDescriptor") +IntersectionFunctionDescriptor :: struct { using _: NS.Copying(IntersectionFunctionDescriptor) } + +@(objc_type=IntersectionFunctionDescriptor, objc_class_name="alloc") +IntersectionFunctionDescriptor_alloc :: proc() -> ^IntersectionFunctionDescriptor { + return msgSend(^IntersectionFunctionDescriptor, IntersectionFunctionDescriptor, "alloc") +} +@(objc_type=IntersectionFunctionDescriptor, objc_name="init") +IntersectionFunctionDescriptor_init :: proc(self: ^IntersectionFunctionDescriptor) -> ^IntersectionFunctionDescriptor { + return msgSend(^IntersectionFunctionDescriptor, self, "init") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + HeapDescriptor +Class Methods: + alloc +Methods: + init + cpuCacheMode + hazardTrackingMode + resourceOptions + setCpuCacheMode + setHazardTrackingMode + setResourceOptions + setSize + setStorageMode + setType + size + storageMode + type +*/ +@(objc_class="MTLHeapDescriptor") +HeapDescriptor :: struct { using _: NS.Copying(HeapDescriptor) } + +@(objc_type=HeapDescriptor, objc_class_name="alloc") +HeapDescriptor_alloc :: proc() -> ^HeapDescriptor { + return msgSend(^HeapDescriptor, HeapDescriptor, "alloc") +} +@(objc_type=HeapDescriptor, objc_name="init") +HeapDescriptor_init :: proc(self: ^HeapDescriptor) -> ^HeapDescriptor { + return msgSend(^HeapDescriptor, self, "init") +} +@(objc_type=HeapDescriptor, objc_name="cpuCacheMode") +HeapDescriptor_cpuCacheMode :: proc(self: ^HeapDescriptor) -> CPUCacheMode { + return msgSend(CPUCacheMode, self, "cpuCacheMode") +} +@(objc_type=HeapDescriptor, objc_name="hazardTrackingMode") +HeapDescriptor_hazardTrackingMode :: proc(self: ^HeapDescriptor) -> HazardTrackingMode { + return msgSend(HazardTrackingMode, self, "hazardTrackingMode") +} +@(objc_type=HeapDescriptor, objc_name="resourceOptions") +HeapDescriptor_resourceOptions :: proc(self: ^HeapDescriptor) -> ResourceOptions { + return msgSend(ResourceOptions, self, "resourceOptions") +} +@(objc_type=HeapDescriptor, objc_name="setCpuCacheMode") +HeapDescriptor_setCpuCacheMode :: proc(self: ^HeapDescriptor, cpuCacheMode: CPUCacheMode) { + msgSend(nil, self, "setCpuCacheMode:", cpuCacheMode) +} +@(objc_type=HeapDescriptor, objc_name="setHazardTrackingMode") +HeapDescriptor_setHazardTrackingMode :: proc(self: ^HeapDescriptor, hazardTrackingMode: HazardTrackingMode) { + msgSend(nil, self, "setHazardTrackingMode:", hazardTrackingMode) +} +@(objc_type=HeapDescriptor, objc_name="setResourceOptions") +HeapDescriptor_setResourceOptions :: proc(self: ^HeapDescriptor, resourceOptions: ResourceOptions) { + msgSend(nil, self, "setResourceOptions:", resourceOptions) +} +@(objc_type=HeapDescriptor, objc_name="setSize") +HeapDescriptor_setSize :: proc(self: ^HeapDescriptor, size: NS.Integer) { + msgSend(nil, self, "setSize:", size) +} +@(objc_type=HeapDescriptor, objc_name="setStorageMode") +HeapDescriptor_setStorageMode :: proc(self: ^HeapDescriptor, storageMode: StorageMode) { + msgSend(nil, self, "setStorageMode:", storageMode) +} +@(objc_type=HeapDescriptor, objc_name="setType") +HeapDescriptor_setType :: proc(self: ^HeapDescriptor, type: HeapType) { + msgSend(nil, self, "setType:", type) +} +@(objc_type=HeapDescriptor, objc_name="size") +HeapDescriptor_size :: proc(self: ^HeapDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "size") +} +@(objc_type=HeapDescriptor, objc_name="storageMode") +HeapDescriptor_storageMode :: proc(self: ^HeapDescriptor) -> StorageMode { + return msgSend(StorageMode, self, "storageMode") +} +@(objc_type=HeapDescriptor, objc_name="type") +HeapDescriptor_type :: proc(self: ^HeapDescriptor) -> HeapType { + return msgSend(HeapType, self, "type") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + IndirectCommandBufferDescriptor +Class Methods: + alloc +Methods: + init + commandTypes + inheritBuffers + inheritPipelineState + maxFragmentBufferBindCount + maxKernelBufferBindCount + maxVertexBufferBindCount + setCommandTypes + setInheritBuffers + setInheritPipelineState + setMaxFragmentBufferBindCount + setMaxKernelBufferBindCount + setMaxVertexBufferBindCount +*/ +@(objc_class="MTLIndirectCommandBufferDescriptor") +IndirectCommandBufferDescriptor :: struct { using _: NS.Copying(IndirectCommandBufferDescriptor) } + +@(objc_type=IndirectCommandBufferDescriptor, objc_class_name="alloc") +IndirectCommandBufferDescriptor_alloc :: proc() -> ^IndirectCommandBufferDescriptor { + return msgSend(^IndirectCommandBufferDescriptor, IndirectCommandBufferDescriptor, "alloc") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="init") +IndirectCommandBufferDescriptor_init :: proc(self: ^IndirectCommandBufferDescriptor) -> ^IndirectCommandBufferDescriptor { + return msgSend(^IndirectCommandBufferDescriptor, self, "init") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="commandTypes") +IndirectCommandBufferDescriptor_commandTypes :: proc(self: ^IndirectCommandBufferDescriptor) -> IndirectCommandType { + return msgSend(IndirectCommandType, self, "commandTypes") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="inheritBuffers") +IndirectCommandBufferDescriptor_inheritBuffers :: proc(self: ^IndirectCommandBufferDescriptor) -> BOOL { + return msgSend(BOOL, self, "inheritBuffers") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="inheritPipelineState") +IndirectCommandBufferDescriptor_inheritPipelineState :: proc(self: ^IndirectCommandBufferDescriptor) -> BOOL { + return msgSend(BOOL, self, "inheritPipelineState") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="maxFragmentBufferBindCount") +IndirectCommandBufferDescriptor_maxFragmentBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxFragmentBufferBindCount") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="maxKernelBufferBindCount") +IndirectCommandBufferDescriptor_maxKernelBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxKernelBufferBindCount") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="maxVertexBufferBindCount") +IndirectCommandBufferDescriptor_maxVertexBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxVertexBufferBindCount") +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="setCommandTypes") +IndirectCommandBufferDescriptor_setCommandTypes :: proc(self: ^IndirectCommandBufferDescriptor, commandTypes: IndirectCommandType) { + msgSend(nil, self, "setCommandTypes:", commandTypes) +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="setInheritBuffers") +IndirectCommandBufferDescriptor_setInheritBuffers :: proc(self: ^IndirectCommandBufferDescriptor, inheritBuffers: BOOL) { + msgSend(nil, self, "setInheritBuffers:", inheritBuffers) +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="setInheritPipelineState") +IndirectCommandBufferDescriptor_setInheritPipelineState :: proc(self: ^IndirectCommandBufferDescriptor, inheritPipelineState: BOOL) { + msgSend(nil, self, "setInheritPipelineState:", inheritPipelineState) +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxFragmentBufferBindCount") +IndirectCommandBufferDescriptor_setMaxFragmentBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor, maxFragmentBufferBindCount: NS.Integer) { + msgSend(nil, self, "setMaxFragmentBufferBindCount:", maxFragmentBufferBindCount) +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxKernelBufferBindCount") +IndirectCommandBufferDescriptor_setMaxKernelBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor, maxKernelBufferBindCount: NS.Integer) { + msgSend(nil, self, "setMaxKernelBufferBindCount:", maxKernelBufferBindCount) +} +@(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxVertexBufferBindCount") +IndirectCommandBufferDescriptor_setMaxVertexBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor, maxVertexBufferBindCount: NS.Integer) { + msgSend(nil, self, "setMaxVertexBufferBindCount:", maxVertexBufferBindCount) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + InstanceAccelerationStructureDescriptor +Class Methods: + alloc + descriptor +Methods: + init + instanceCount + instanceDescriptorBuffer + instanceDescriptorBufferOffset + instanceDescriptorStride + instancedAccelerationStructures + setInstanceCount + setInstanceDescriptorBuffer + setInstanceDescriptorBufferOffset + setInstanceDescriptorStride + setInstancedAccelerationStructures +*/ +@(objc_class="MTLInstanceAccelerationStructureDescriptor") +InstanceAccelerationStructureDescriptor :: struct { using _: NS.Copying(InstanceAccelerationStructureDescriptor) } + +@(objc_type=InstanceAccelerationStructureDescriptor, objc_class_name="alloc") +InstanceAccelerationStructureDescriptor_alloc :: proc() -> ^InstanceAccelerationStructureDescriptor { + return msgSend(^InstanceAccelerationStructureDescriptor, InstanceAccelerationStructureDescriptor, "alloc") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="init") +InstanceAccelerationStructureDescriptor_init :: proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { + return msgSend(^InstanceAccelerationStructureDescriptor, self, "init") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_class_name="descriptor") +InstanceAccelerationStructureDescriptor_descriptor :: proc() -> ^InstanceAccelerationStructureDescriptor { + return msgSend(^InstanceAccelerationStructureDescriptor, InstanceAccelerationStructureDescriptor, "descriptor") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceCount") +InstanceAccelerationStructureDescriptor_instanceCount :: proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "instanceCount") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBuffer") +InstanceAccelerationStructureDescriptor_instanceDescriptorBuffer :: proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { + return msgSend(^InstanceAccelerationStructureDescriptor, self, "instanceDescriptorBuffer") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBufferOffset") +InstanceAccelerationStructureDescriptor_instanceDescriptorBufferOffset :: proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "instanceDescriptorBufferOffset") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorStride") +InstanceAccelerationStructureDescriptor_instanceDescriptorStride :: proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "instanceDescriptorStride") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instancedAccelerationStructures") +InstanceAccelerationStructureDescriptor_instancedAccelerationStructures :: proc(self: ^InstanceAccelerationStructureDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "instancedAccelerationStructures") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceCount") +InstanceAccelerationStructureDescriptor_setInstanceCount :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceCount: NS.Integer) { + msgSend(nil, self, "setInstanceCount:", instanceCount) +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorBuffer") +InstanceAccelerationStructureDescriptor_setInstanceDescriptorBuffer :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBuffer: ^NS.Object) { + msgSend(nil, self, "setInstanceDescriptorBuffer:", instanceDescriptorBuffer) +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorBufferOffset") +InstanceAccelerationStructureDescriptor_setInstanceDescriptorBufferOffset :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBufferOffset: NS.Integer) { + msgSend(nil, self, "setInstanceDescriptorBufferOffset:", instanceDescriptorBufferOffset) +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorStride") +InstanceAccelerationStructureDescriptor_setInstanceDescriptorStride :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorStride: NS.Integer) { + msgSend(nil, self, "setInstanceDescriptorStride:", instanceDescriptorStride) +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstancedAccelerationStructures") +InstanceAccelerationStructureDescriptor_setInstancedAccelerationStructures :: proc(self: ^InstanceAccelerationStructureDescriptor, instancedAccelerationStructures: ^NS.Array) { + msgSend(nil, self, "setInstancedAccelerationStructures:", instancedAccelerationStructures) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + IntersectionFunctionTableDescriptor +Class Methods: + alloc + intersectionFunctionTableDescriptor +Methods: + init + functionCount + setFunctionCount +*/ +@(objc_class="MTLIntersectionFunctionTableDescriptor") +IntersectionFunctionTableDescriptor :: struct { using _: NS.Copying(IntersectionFunctionTableDescriptor) } + +@(objc_type=IntersectionFunctionTableDescriptor, objc_class_name="alloc") +IntersectionFunctionTableDescriptor_alloc :: proc() -> ^IntersectionFunctionTableDescriptor { + return msgSend(^IntersectionFunctionTableDescriptor, IntersectionFunctionTableDescriptor, "alloc") +} +@(objc_type=IntersectionFunctionTableDescriptor, objc_name="init") +IntersectionFunctionTableDescriptor_init :: proc(self: ^IntersectionFunctionTableDescriptor) -> ^IntersectionFunctionTableDescriptor { + return msgSend(^IntersectionFunctionTableDescriptor, self, "init") +} +@(objc_type=IntersectionFunctionTableDescriptor, objc_name="functionCount") +IntersectionFunctionTableDescriptor_functionCount :: proc(self: ^IntersectionFunctionTableDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "functionCount") +} +@(objc_type=IntersectionFunctionTableDescriptor, objc_class_name="intersectionFunctionTableDescriptor") +IntersectionFunctionTableDescriptor_intersectionFunctionTableDescriptor :: proc() -> ^IntersectionFunctionTableDescriptor { + return msgSend(^IntersectionFunctionTableDescriptor, IntersectionFunctionTableDescriptor, "intersectionFunctionTableDescriptor") +} +@(objc_type=IntersectionFunctionTableDescriptor, objc_name="setFunctionCount") +IntersectionFunctionTableDescriptor_setFunctionCount :: proc(self: ^IntersectionFunctionTableDescriptor, functionCount: NS.Integer) { + msgSend(nil, self, "setFunctionCount:", functionCount) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + LinkedFunctions +Class Methods: + alloc + linkedFunctions +Methods: + init + binaryFunctions + functions + groups + setBinaryFunctions + setFunctions + setGroups +*/ +@(objc_class="MTLLinkedFunctions") +LinkedFunctions :: struct { using _: NS.Copying(LinkedFunctions) } + +@(objc_type=LinkedFunctions, objc_class_name="alloc") +LinkedFunctions_alloc :: proc() -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, LinkedFunctions, "alloc") +} +@(objc_type=LinkedFunctions, objc_name="init") +LinkedFunctions_init :: proc(self: ^LinkedFunctions) -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, self, "init") +} +@(objc_type=LinkedFunctions, objc_name="binaryFunctions") +LinkedFunctions_binaryFunctions :: proc(self: ^LinkedFunctions) -> ^NS.Array { + return msgSend(^NS.Array, self, "binaryFunctions") +} +@(objc_type=LinkedFunctions, objc_name="functions") +LinkedFunctions_functions :: proc(self: ^LinkedFunctions) -> ^NS.Array { + return msgSend(^NS.Array, self, "functions") +} +@(objc_type=LinkedFunctions, objc_name="groups") +LinkedFunctions_groups :: proc(self: ^LinkedFunctions) -> ^NS.Dictionary { + return msgSend(^NS.Dictionary, self, "groups") +} +@(objc_type=LinkedFunctions, objc_class_name="linkedFunctions") +LinkedFunctions_linkedFunctions :: proc() -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, LinkedFunctions, "linkedFunctions") +} +@(objc_type=LinkedFunctions, objc_name="setBinaryFunctions") +LinkedFunctions_setBinaryFunctions :: proc(self: ^LinkedFunctions, binaryFunctions: ^NS.Array) { + msgSend(nil, self, "setBinaryFunctions:", binaryFunctions) +} +@(objc_type=LinkedFunctions, objc_name="setFunctions") +LinkedFunctions_setFunctions :: proc(self: ^LinkedFunctions, functions: ^NS.Array) { + msgSend(nil, self, "setFunctions:", functions) +} +@(objc_type=LinkedFunctions, objc_name="setGroups") +LinkedFunctions_setGroups :: proc(self: ^LinkedFunctions, groups: ^NS.Dictionary) { + msgSend(nil, self, "setGroups:", groups) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + PipelineBufferDescriptor +Class Methods: + alloc +Methods: + init + mutability + setMutability +*/ +@(objc_class="MTLPipelineBufferDescriptor") +PipelineBufferDescriptor :: struct { using _: NS.Copying(PipelineBufferDescriptor) } + +@(objc_type=PipelineBufferDescriptor, objc_class_name="alloc") +PipelineBufferDescriptor_alloc :: proc() -> ^PipelineBufferDescriptor { + return msgSend(^PipelineBufferDescriptor, PipelineBufferDescriptor, "alloc") +} +@(objc_type=PipelineBufferDescriptor, objc_name="init") +PipelineBufferDescriptor_init :: proc(self: ^PipelineBufferDescriptor) -> ^PipelineBufferDescriptor { + return msgSend(^PipelineBufferDescriptor, self, "init") +} +@(objc_type=PipelineBufferDescriptor, objc_name="mutability") +PipelineBufferDescriptor_mutability :: proc(self: ^PipelineBufferDescriptor) -> Mutability { + return msgSend(Mutability, self, "mutability") +} +@(objc_type=PipelineBufferDescriptor, objc_name="setMutability") +PipelineBufferDescriptor_setMutability :: proc(self: ^PipelineBufferDescriptor, mutability: Mutability) { + msgSend(nil, self, "setMutability:", mutability) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + PipelineBufferDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLPipelineBufferDescriptorArray") +PipelineBufferDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=PipelineBufferDescriptorArray, objc_class_name="alloc") +PipelineBufferDescriptorArray_alloc :: proc() -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, PipelineBufferDescriptorArray, "alloc") +} +@(objc_type=PipelineBufferDescriptorArray, objc_name="init") +PipelineBufferDescriptorArray_init :: proc(self: ^PipelineBufferDescriptorArray) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "init") +} +@(objc_type=PipelineBufferDescriptorArray, objc_name="objectAtIndexedSubscript") +PipelineBufferDescriptorArray_objectAtIndexedSubscript :: proc(self: ^PipelineBufferDescriptorArray, bufferIndex: ^NS.Object) -> ^PipelineBufferDescriptor { + return msgSend(^PipelineBufferDescriptor, self, "objectAtIndexedSubscript:", bufferIndex) +} +@(objc_type=PipelineBufferDescriptorArray, objc_name="setObject") +PipelineBufferDescriptorArray_setObject :: proc(self: ^PipelineBufferDescriptorArray, buffer: ^PipelineBufferDescriptor, bufferIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", buffer, bufferIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + PointerType +Class Methods: + alloc +Methods: + init + access + alignment + dataSize + elementArrayType + elementIsArgumentBuffer + elementStructType + elementType +*/ +@(objc_class="MTLPointerType") +PointerType :: struct { using _: NS.Object } + +@(objc_type=PointerType, objc_class_name="alloc") +PointerType_alloc :: proc() -> ^PointerType { + return msgSend(^PointerType, PointerType, "alloc") +} +@(objc_type=PointerType, objc_name="init") +PointerType_init :: proc(self: ^PointerType) -> ^PointerType { + return msgSend(^PointerType, self, "init") +} +@(objc_type=PointerType, objc_name="access") +PointerType_access :: proc(self: ^PointerType) -> ArgumentAccess { + return msgSend(ArgumentAccess, self, "access") +} +@(objc_type=PointerType, objc_name="alignment") +PointerType_alignment :: proc(self: ^PointerType) -> NS.Integer { + return msgSend(NS.Integer, self, "alignment") +} +@(objc_type=PointerType, objc_name="dataSize") +PointerType_dataSize :: proc(self: ^PointerType) -> NS.Integer { + return msgSend(NS.Integer, self, "dataSize") +} +@(objc_type=PointerType, objc_name="elementArrayType") +PointerType_elementArrayType :: proc(self: ^PointerType) -> ^ArrayType { + return msgSend(^ArrayType, self, "elementArrayType") +} +@(objc_type=PointerType, objc_name="elementIsArgumentBuffer") +PointerType_elementIsArgumentBuffer :: proc(self: ^PointerType) -> BOOL { + return msgSend(BOOL, self, "elementIsArgumentBuffer") +} +@(objc_type=PointerType, objc_name="elementStructType") +PointerType_elementStructType :: proc(self: ^PointerType) -> ^StructType { + return msgSend(^StructType, self, "elementStructType") +} +@(objc_type=PointerType, objc_name="elementType") +PointerType_elementType :: proc(self: ^PointerType) -> DataType { + return msgSend(DataType, self, "elementType") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + PrimitiveAccelerationStructureDescriptor +Class Methods: + alloc + descriptor +Methods: + init + geometryDescriptors + setGeometryDescriptors +*/ +@(objc_class="MTLPrimitiveAccelerationStructureDescriptor") +PrimitiveAccelerationStructureDescriptor :: struct { using _: NS.Copying(PrimitiveAccelerationStructureDescriptor) } + +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_class_name="alloc") +PrimitiveAccelerationStructureDescriptor_alloc :: proc() -> ^PrimitiveAccelerationStructureDescriptor { + return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "alloc") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="init") +PrimitiveAccelerationStructureDescriptor_init :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> ^PrimitiveAccelerationStructureDescriptor { + return msgSend(^PrimitiveAccelerationStructureDescriptor, self, "init") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_class_name="descriptor") +PrimitiveAccelerationStructureDescriptor_descriptor :: proc() -> ^PrimitiveAccelerationStructureDescriptor { + return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "descriptor") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="geometryDescriptors") +PrimitiveAccelerationStructureDescriptor_geometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "geometryDescriptors") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="setGeometryDescriptors") +PrimitiveAccelerationStructureDescriptor_setGeometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor, geometryDescriptors: ^NS.Array) { + msgSend(nil, self, "setGeometryDescriptors:", geometryDescriptors) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RasterizationRateLayerArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLRasterizationRateLayerArray") +RasterizationRateLayerArray :: struct { using _: NS.Object } + +@(objc_type=RasterizationRateLayerArray, objc_class_name="alloc") +RasterizationRateLayerArray_alloc :: proc() -> ^RasterizationRateLayerArray { + return msgSend(^RasterizationRateLayerArray, RasterizationRateLayerArray, "alloc") +} +@(objc_type=RasterizationRateLayerArray, objc_name="init") +RasterizationRateLayerArray_init :: proc(self: ^RasterizationRateLayerArray) -> ^RasterizationRateLayerArray { + return msgSend(^RasterizationRateLayerArray, self, "init") +} +@(objc_type=RasterizationRateLayerArray, objc_name="objectAtIndexedSubscript") +RasterizationRateLayerArray_objectAtIndexedSubscript :: proc(self: ^RasterizationRateLayerArray, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { + return msgSend(^RasterizationRateLayerDescriptor, self, "objectAtIndexedSubscript:", layerIndex) +} +@(objc_type=RasterizationRateLayerArray, objc_name="setObject") +RasterizationRateLayerArray_setObject :: proc(self: ^RasterizationRateLayerArray, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", layer, layerIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RasterizationRateLayerDescriptor +Class Methods: + alloc +Methods: + horizontal + horizontalSampleStorage + init + initWithSampleCount + initWithSampleCount + sampleCount + vertical + verticalSampleStorage +*/ +@(objc_class="MTLRasterizationRateLayerDescriptor") +RasterizationRateLayerDescriptor :: struct { using _: NS.Copying(RasterizationRateLayerDescriptor) } + +@(objc_type=RasterizationRateLayerDescriptor, objc_class_name="alloc") +RasterizationRateLayerDescriptor_alloc :: proc() -> ^RasterizationRateLayerDescriptor { + return msgSend(^RasterizationRateLayerDescriptor, RasterizationRateLayerDescriptor, "alloc") +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="horizontal") +RasterizationRateLayerDescriptor_horizontal :: proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateSampleArray { + return msgSend(^RasterizationRateSampleArray, self, "horizontal") +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="horizontalSampleStorage") +RasterizationRateLayerDescriptor_horizontalSampleStorage :: proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { + return msgSend(^f32, self, "horizontalSampleStorage") +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="init") +RasterizationRateLayerDescriptor_init :: proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateLayerDescriptor { + return msgSend(^RasterizationRateLayerDescriptor, self, "init") +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="initWithSampleCount") +RasterizationRateLayerDescriptor_initWithSampleCount :: proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size) -> ^RasterizationRateLayerDescriptor { + return msgSend(^RasterizationRateLayerDescriptor, self, "initWithSampleCount:", sampleCount) +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="initWithSampleCountWithDimensions") +RasterizationRateLayerDescriptor_initWithSampleCountWithDimensions :: proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size, horizontal: ^f32, vertical: ^f32) -> ^RasterizationRateLayerDescriptor { + return msgSend(^RasterizationRateLayerDescriptor, self, "initWithSampleCount:horizontal:vertical:", sampleCount, horizontal, vertical) +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="sampleCount") +RasterizationRateLayerDescriptor_sampleCount :: proc(self: ^RasterizationRateLayerDescriptor) -> Size { + return msgSend(Size, self, "sampleCount") +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="vertical") +RasterizationRateLayerDescriptor_vertical :: proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateSampleArray { + return msgSend(^RasterizationRateSampleArray, self, "vertical") +} +@(objc_type=RasterizationRateLayerDescriptor, objc_name="verticalSampleStorage") +RasterizationRateLayerDescriptor_verticalSampleStorage :: proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { + return msgSend(^f32, self, "verticalSampleStorage") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RasterizationRateMapDescriptor +Class Methods: + alloc + rasterizationRateMapDescriptorWithScreenSize + rasterizationRateMapDescriptorWithScreenSize + rasterizationRateMapDescriptorWithScreenSize +Methods: + init + label + layerAtIndex + layerCount + layers + screenSize + setLabel + setLayer + setScreenSize +*/ +@(objc_class="MTLRasterizationRateMapDescriptor") +RasterizationRateMapDescriptor :: struct { using _: NS.Copying(RasterizationRateMapDescriptor) } + +@(objc_type=RasterizationRateMapDescriptor, objc_class_name="alloc") +RasterizationRateMapDescriptor_alloc :: proc() -> ^RasterizationRateMapDescriptor { + return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "alloc") +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="init") +RasterizationRateMapDescriptor_init :: proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMapDescriptor { + return msgSend(^RasterizationRateMapDescriptor, self, "init") +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="label") +RasterizationRateMapDescriptor_label :: proc(self: ^RasterizationRateMapDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="layerAtIndex") +RasterizationRateMapDescriptor_layerAtIndex :: proc(self: ^RasterizationRateMapDescriptor, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { + return msgSend(^RasterizationRateLayerDescriptor, self, "layerAtIndex:", layerIndex) +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="layerCount") +RasterizationRateMapDescriptor_layerCount :: proc(self: ^RasterizationRateMapDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "layerCount") +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="layers") +RasterizationRateMapDescriptor_layers :: proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateLayerArray { + return msgSend(^RasterizationRateLayerArray, self, "layers") +} +@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize") +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize :: proc(screenSize: Size) -> ^RasterizationRateMapDescriptor { + return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:", screenSize) +} +@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize_layer_") +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layer_ :: proc(screenSize: Size, layer: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { + return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layer:", screenSize, layer) +} +@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize_layerCount_layers_") +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layerCount_layers_ :: proc(screenSize: Size, layerCount: ^NS.Object, layers: ^^RasterizationRateLayerDescriptor ) -> ^RasterizationRateMapDescriptor { + return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layerCount:layers:", screenSize, layerCount, layers) +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="screenSize") +RasterizationRateMapDescriptor_screenSize :: proc(self: ^RasterizationRateMapDescriptor) -> Size { + return msgSend(Size, self, "screenSize") +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="setLabel") +RasterizationRateMapDescriptor_setLabel :: proc(self: ^RasterizationRateMapDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="setLayer") +RasterizationRateMapDescriptor_setLayer :: proc(self: ^RasterizationRateMapDescriptor, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { + msgSend(nil, self, "setLayer:atIndex:", layer, layerIndex) +} +@(objc_type=RasterizationRateMapDescriptor, objc_name="setScreenSize") +RasterizationRateMapDescriptor_setScreenSize :: proc(self: ^RasterizationRateMapDescriptor, screenSize: Size) { + msgSend(nil, self, "setScreenSize:", screenSize) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RasterizationRateSampleArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLRasterizationRateSampleArray") +RasterizationRateSampleArray :: struct { using _: NS.Object } + +@(objc_type=RasterizationRateSampleArray, objc_class_name="alloc") +RasterizationRateSampleArray_alloc :: proc() -> ^RasterizationRateSampleArray { + return msgSend(^RasterizationRateSampleArray, RasterizationRateSampleArray, "alloc") +} +@(objc_type=RasterizationRateSampleArray, objc_name="init") +RasterizationRateSampleArray_init :: proc(self: ^RasterizationRateSampleArray) -> ^RasterizationRateSampleArray { + return msgSend(^RasterizationRateSampleArray, self, "init") +} +@(objc_type=RasterizationRateSampleArray, objc_name="objectAtIndexedSubscript") +RasterizationRateSampleArray_objectAtIndexedSubscript :: proc(self: ^RasterizationRateSampleArray, index: ^NS.Object) -> ^NS.Number { + return msgSend(^NS.Number, self, "objectAtIndexedSubscript:", index) +} +@(objc_type=RasterizationRateSampleArray, objc_name="setObject") +RasterizationRateSampleArray_setObject :: proc(self: ^RasterizationRateSampleArray, value: ^NS.Number, index: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", value, index) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassAttachmentDescriptor +Class Methods: + alloc +Methods: + init + depthPlane + level + loadAction + resolveDepthPlane + resolveLevel + resolveSlice + resolveTexture + setDepthPlane + setLevel + setLoadAction + setResolveDepthPlane + setResolveLevel + setResolveSlice + setResolveTexture + setSlice + setStoreAction + setStoreActionOptions + setTexture + slice + storeAction + storeActionOptions + texture +*/ +@(objc_class="MTLRenderPassAttachmentDescriptor") +RenderPassAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassAttachmentDescriptor) } + +@(objc_type=RenderPassAttachmentDescriptor, objc_class_name="alloc") +RenderPassAttachmentDescriptor_alloc :: proc() -> ^RenderPassAttachmentDescriptor { + return msgSend(^RenderPassAttachmentDescriptor, RenderPassAttachmentDescriptor, "alloc") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="init") +RenderPassAttachmentDescriptor_init :: proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { + return msgSend(^RenderPassAttachmentDescriptor, self, "init") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="depthPlane") +RenderPassAttachmentDescriptor_depthPlane :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "depthPlane") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="level") +RenderPassAttachmentDescriptor_level :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "level") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="loadAction") +RenderPassAttachmentDescriptor_loadAction :: proc(self: ^RenderPassAttachmentDescriptor) -> LoadAction { + return msgSend(LoadAction, self, "loadAction") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveDepthPlane") +RenderPassAttachmentDescriptor_resolveDepthPlane :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "resolveDepthPlane") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveLevel") +RenderPassAttachmentDescriptor_resolveLevel :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "resolveLevel") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveSlice") +RenderPassAttachmentDescriptor_resolveSlice :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "resolveSlice") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveTexture") +RenderPassAttachmentDescriptor_resolveTexture :: proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { + return msgSend(^RenderPassAttachmentDescriptor, self, "resolveTexture") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setDepthPlane") +RenderPassAttachmentDescriptor_setDepthPlane :: proc(self: ^RenderPassAttachmentDescriptor, depthPlane: NS.Integer) { + msgSend(nil, self, "setDepthPlane:", depthPlane) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setLevel") +RenderPassAttachmentDescriptor_setLevel :: proc(self: ^RenderPassAttachmentDescriptor, level: NS.Integer) { + msgSend(nil, self, "setLevel:", level) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setLoadAction") +RenderPassAttachmentDescriptor_setLoadAction :: proc(self: ^RenderPassAttachmentDescriptor, loadAction: LoadAction) { + msgSend(nil, self, "setLoadAction:", loadAction) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveDepthPlane") +RenderPassAttachmentDescriptor_setResolveDepthPlane :: proc(self: ^RenderPassAttachmentDescriptor, resolveDepthPlane: NS.Integer) { + msgSend(nil, self, "setResolveDepthPlane:", resolveDepthPlane) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveLevel") +RenderPassAttachmentDescriptor_setResolveLevel :: proc(self: ^RenderPassAttachmentDescriptor, resolveLevel: NS.Integer) { + msgSend(nil, self, "setResolveLevel:", resolveLevel) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveSlice") +RenderPassAttachmentDescriptor_setResolveSlice :: proc(self: ^RenderPassAttachmentDescriptor, resolveSlice: NS.Integer) { + msgSend(nil, self, "setResolveSlice:", resolveSlice) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveTexture") +RenderPassAttachmentDescriptor_setResolveTexture :: proc(self: ^RenderPassAttachmentDescriptor, resolveTexture: ^NS.Object) { + msgSend(nil, self, "setResolveTexture:", resolveTexture) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setSlice") +RenderPassAttachmentDescriptor_setSlice :: proc(self: ^RenderPassAttachmentDescriptor, slice: NS.Integer) { + msgSend(nil, self, "setSlice:", slice) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setStoreAction") +RenderPassAttachmentDescriptor_setStoreAction :: proc(self: ^RenderPassAttachmentDescriptor, storeAction: StoreAction) { + msgSend(nil, self, "setStoreAction:", storeAction) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setStoreActionOptions") +RenderPassAttachmentDescriptor_setStoreActionOptions :: proc(self: ^RenderPassAttachmentDescriptor, storeActionOptions: StoreActionOptions) { + msgSend(nil, self, "setStoreActionOptions:", storeActionOptions) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="setTexture") +RenderPassAttachmentDescriptor_setTexture :: proc(self: ^RenderPassAttachmentDescriptor, texture: ^NS.Object) { + msgSend(nil, self, "setTexture:", texture) +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="slice") +RenderPassAttachmentDescriptor_slice :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "slice") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="storeAction") +RenderPassAttachmentDescriptor_storeAction :: proc(self: ^RenderPassAttachmentDescriptor) -> StoreAction { + return msgSend(StoreAction, self, "storeAction") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="storeActionOptions") +RenderPassAttachmentDescriptor_storeActionOptions :: proc(self: ^RenderPassAttachmentDescriptor) -> StoreActionOptions { + return msgSend(StoreActionOptions, self, "storeActionOptions") +} +@(objc_type=RenderPassAttachmentDescriptor, objc_name="texture") +RenderPassAttachmentDescriptor_texture :: proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { + return msgSend(^RenderPassAttachmentDescriptor, self, "texture") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassColorAttachmentDescriptor +Class Methods: + alloc +Methods: + init + clearColor + setClearColor +*/ +@(objc_class="MTLRenderPassColorAttachmentDescriptor") +RenderPassColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassColorAttachmentDescriptor) } + +@(objc_type=RenderPassColorAttachmentDescriptor, objc_class_name="alloc") +RenderPassColorAttachmentDescriptor_alloc :: proc() -> ^RenderPassColorAttachmentDescriptor { + return msgSend(^RenderPassColorAttachmentDescriptor, RenderPassColorAttachmentDescriptor, "alloc") +} +@(objc_type=RenderPassColorAttachmentDescriptor, objc_name="init") +RenderPassColorAttachmentDescriptor_init :: proc(self: ^RenderPassColorAttachmentDescriptor) -> ^RenderPassColorAttachmentDescriptor { + return msgSend(^RenderPassColorAttachmentDescriptor, self, "init") +} +@(objc_type=RenderPassColorAttachmentDescriptor, objc_name="clearColor") +RenderPassColorAttachmentDescriptor_clearColor :: proc(self: ^RenderPassColorAttachmentDescriptor) -> ClearColor { + return msgSend(ClearColor, self, "clearColor") +} +@(objc_type=RenderPassColorAttachmentDescriptor, objc_name="setClearColor") +RenderPassColorAttachmentDescriptor_setClearColor :: proc(self: ^RenderPassColorAttachmentDescriptor, clearColor: ClearColor) { + msgSend(nil, self, "setClearColor:", clearColor) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassColorAttachmentDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLRenderPassColorAttachmentDescriptorArray") +RenderPassColorAttachmentDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_class_name="alloc") +RenderPassColorAttachmentDescriptorArray_alloc :: proc() -> ^RenderPassColorAttachmentDescriptorArray { + return msgSend(^RenderPassColorAttachmentDescriptorArray, RenderPassColorAttachmentDescriptorArray, "alloc") +} +@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="init") +RenderPassColorAttachmentDescriptorArray_init :: proc(self: ^RenderPassColorAttachmentDescriptorArray) -> ^RenderPassColorAttachmentDescriptorArray { + return msgSend(^RenderPassColorAttachmentDescriptorArray, self, "init") +} +@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") +RenderPassColorAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^RenderPassColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassColorAttachmentDescriptor { + return msgSend(^RenderPassColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) +} +@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="setObject") +RenderPassColorAttachmentDescriptorArray_setObject :: proc(self: ^RenderPassColorAttachmentDescriptorArray, attachment: ^RenderPassColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassDepthAttachmentDescriptor +Class Methods: + alloc +Methods: + init + clearDepth + depthResolveFilter + setClearDepth + setDepthResolveFilter +*/ +@(objc_class="MTLRenderPassDepthAttachmentDescriptor") +RenderPassDepthAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassDepthAttachmentDescriptor) } + +@(objc_type=RenderPassDepthAttachmentDescriptor, objc_class_name="alloc") +RenderPassDepthAttachmentDescriptor_alloc :: proc() -> ^RenderPassDepthAttachmentDescriptor { + return msgSend(^RenderPassDepthAttachmentDescriptor, RenderPassDepthAttachmentDescriptor, "alloc") +} +@(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="init") +RenderPassDepthAttachmentDescriptor_init :: proc(self: ^RenderPassDepthAttachmentDescriptor) -> ^RenderPassDepthAttachmentDescriptor { + return msgSend(^RenderPassDepthAttachmentDescriptor, self, "init") +} +@(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="clearDepth") +RenderPassDepthAttachmentDescriptor_clearDepth :: proc(self: ^RenderPassDepthAttachmentDescriptor) -> f64 { + return msgSend(f64, self, "clearDepth") +} +@(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="depthResolveFilter") +RenderPassDepthAttachmentDescriptor_depthResolveFilter :: proc(self: ^RenderPassDepthAttachmentDescriptor) -> MultisampleDepthResolveFilter { + return msgSend(MultisampleDepthResolveFilter, self, "depthResolveFilter") +} +@(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="setClearDepth") +RenderPassDepthAttachmentDescriptor_setClearDepth :: proc(self: ^RenderPassDepthAttachmentDescriptor, clearDepth: f64) { + msgSend(nil, self, "setClearDepth:", clearDepth) +} +@(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="setDepthResolveFilter") +RenderPassDepthAttachmentDescriptor_setDepthResolveFilter :: proc(self: ^RenderPassDepthAttachmentDescriptor, depthResolveFilter: MultisampleDepthResolveFilter) { + msgSend(nil, self, "setDepthResolveFilter:", depthResolveFilter) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassDescriptor +Class Methods: + alloc + renderPassDescriptor +Methods: + init + colorAttachments + defaultRasterSampleCount + depthAttachment + getSamplePositions + imageblockSampleLength + rasterizationRateMap + renderTargetArrayLength + renderTargetHeight + renderTargetWidth + sampleBufferAttachments + setDefaultRasterSampleCount + setDepthAttachment + setImageblockSampleLength + setRasterizationRateMap + setRenderTargetArrayLength + setRenderTargetHeight + setRenderTargetWidth + setSamplePositions + setStencilAttachment + setThreadgroupMemoryLength + setTileHeight + setTileWidth + setVisibilityResultBuffer + stencilAttachment + threadgroupMemoryLength + tileHeight + tileWidth + visibilityResultBuffer +*/ +@(objc_class="MTLRenderPassDescriptor") +RenderPassDescriptor :: struct { using _: NS.Copying(RenderPassDescriptor) } + +@(objc_type=RenderPassDescriptor, objc_class_name="alloc") +RenderPassDescriptor_alloc :: proc() -> ^RenderPassDescriptor { + return msgSend(^RenderPassDescriptor, RenderPassDescriptor, "alloc") +} +@(objc_type=RenderPassDescriptor, objc_name="init") +RenderPassDescriptor_init :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { + return msgSend(^RenderPassDescriptor, self, "init") +} +@(objc_type=RenderPassDescriptor, objc_name="colorAttachments") +RenderPassDescriptor_colorAttachments :: proc(self: ^RenderPassDescriptor) -> ^RenderPassColorAttachmentDescriptorArray { + return msgSend(^RenderPassColorAttachmentDescriptorArray, self, "colorAttachments") +} +@(objc_type=RenderPassDescriptor, objc_name="defaultRasterSampleCount") +RenderPassDescriptor_defaultRasterSampleCount :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "defaultRasterSampleCount") +} +@(objc_type=RenderPassDescriptor, objc_name="depthAttachment") +RenderPassDescriptor_depthAttachment :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDepthAttachmentDescriptor { + return msgSend(^RenderPassDepthAttachmentDescriptor, self, "depthAttachment") +} +@(objc_type=RenderPassDescriptor, objc_name="getSamplePositions") +RenderPassDescriptor_getSamplePositions :: proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) -> ^RenderPassDescriptor { + return msgSend(^RenderPassDescriptor, self, "getSamplePositions:count:", positions, count) +} +@(objc_type=RenderPassDescriptor, objc_name="imageblockSampleLength") +RenderPassDescriptor_imageblockSampleLength :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "imageblockSampleLength") +} +@(objc_type=RenderPassDescriptor, objc_name="rasterizationRateMap") +RenderPassDescriptor_rasterizationRateMap :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { + return msgSend(^RenderPassDescriptor, self, "rasterizationRateMap") +} +@(objc_type=RenderPassDescriptor, objc_class_name="renderPassDescriptor") +RenderPassDescriptor_renderPassDescriptor :: proc() -> ^RenderPassDescriptor { + return msgSend(^RenderPassDescriptor, RenderPassDescriptor, "renderPassDescriptor") +} +@(objc_type=RenderPassDescriptor, objc_name="renderTargetArrayLength") +RenderPassDescriptor_renderTargetArrayLength :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "renderTargetArrayLength") +} +@(objc_type=RenderPassDescriptor, objc_name="renderTargetHeight") +RenderPassDescriptor_renderTargetHeight :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "renderTargetHeight") +} +@(objc_type=RenderPassDescriptor, objc_name="renderTargetWidth") +RenderPassDescriptor_renderTargetWidth :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "renderTargetWidth") +} +@(objc_type=RenderPassDescriptor, objc_name="sampleBufferAttachments") +RenderPassDescriptor_sampleBufferAttachments :: proc(self: ^RenderPassDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptorArray { + return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") +} +@(objc_type=RenderPassDescriptor, objc_name="setDefaultRasterSampleCount") +RenderPassDescriptor_setDefaultRasterSampleCount :: proc(self: ^RenderPassDescriptor, defaultRasterSampleCount: NS.Integer) { + msgSend(nil, self, "setDefaultRasterSampleCount:", defaultRasterSampleCount) +} +@(objc_type=RenderPassDescriptor, objc_name="setDepthAttachment") +RenderPassDescriptor_setDepthAttachment :: proc(self: ^RenderPassDescriptor, depthAttachment: ^RenderPassDepthAttachmentDescriptor) { + msgSend(nil, self, "setDepthAttachment:", depthAttachment) +} +@(objc_type=RenderPassDescriptor, objc_name="setImageblockSampleLength") +RenderPassDescriptor_setImageblockSampleLength :: proc(self: ^RenderPassDescriptor, imageblockSampleLength: NS.Integer) { + msgSend(nil, self, "setImageblockSampleLength:", imageblockSampleLength) +} +@(objc_type=RenderPassDescriptor, objc_name="setRasterizationRateMap") +RenderPassDescriptor_setRasterizationRateMap :: proc(self: ^RenderPassDescriptor, rasterizationRateMap: ^NS.Object) { + msgSend(nil, self, "setRasterizationRateMap:", rasterizationRateMap) +} +@(objc_type=RenderPassDescriptor, objc_name="setRenderTargetArrayLength") +RenderPassDescriptor_setRenderTargetArrayLength :: proc(self: ^RenderPassDescriptor, renderTargetArrayLength: NS.Integer) { + msgSend(nil, self, "setRenderTargetArrayLength:", renderTargetArrayLength) +} +@(objc_type=RenderPassDescriptor, objc_name="setRenderTargetHeight") +RenderPassDescriptor_setRenderTargetHeight :: proc(self: ^RenderPassDescriptor, renderTargetHeight: NS.Integer) { + msgSend(nil, self, "setRenderTargetHeight:", renderTargetHeight) +} +@(objc_type=RenderPassDescriptor, objc_name="setRenderTargetWidth") +RenderPassDescriptor_setRenderTargetWidth :: proc(self: ^RenderPassDescriptor, renderTargetWidth: NS.Integer) { + msgSend(nil, self, "setRenderTargetWidth:", renderTargetWidth) +} +@(objc_type=RenderPassDescriptor, objc_name="setSamplePositions") +RenderPassDescriptor_setSamplePositions :: proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) { + msgSend(nil, self, "setSamplePositions:count:", positions, count) +} +@(objc_type=RenderPassDescriptor, objc_name="setStencilAttachment") +RenderPassDescriptor_setStencilAttachment :: proc(self: ^RenderPassDescriptor, stencilAttachment: ^RenderPassStencilAttachmentDescriptor) { + msgSend(nil, self, "setStencilAttachment:", stencilAttachment) +} +@(objc_type=RenderPassDescriptor, objc_name="setThreadgroupMemoryLength") +RenderPassDescriptor_setThreadgroupMemoryLength :: proc(self: ^RenderPassDescriptor, threadgroupMemoryLength: NS.Integer) { + msgSend(nil, self, "setThreadgroupMemoryLength:", threadgroupMemoryLength) +} +@(objc_type=RenderPassDescriptor, objc_name="setTileHeight") +RenderPassDescriptor_setTileHeight :: proc(self: ^RenderPassDescriptor, tileHeight: NS.Integer) { + msgSend(nil, self, "setTileHeight:", tileHeight) +} +@(objc_type=RenderPassDescriptor, objc_name="setTileWidth") +RenderPassDescriptor_setTileWidth :: proc(self: ^RenderPassDescriptor, tileWidth: NS.Integer) { + msgSend(nil, self, "setTileWidth:", tileWidth) +} +@(objc_type=RenderPassDescriptor, objc_name="setVisibilityResultBuffer") +RenderPassDescriptor_setVisibilityResultBuffer :: proc(self: ^RenderPassDescriptor, visibilityResultBuffer: ^NS.Object) { + msgSend(nil, self, "setVisibilityResultBuffer:", visibilityResultBuffer) +} +@(objc_type=RenderPassDescriptor, objc_name="stencilAttachment") +RenderPassDescriptor_stencilAttachment :: proc(self: ^RenderPassDescriptor) -> ^RenderPassStencilAttachmentDescriptor { + return msgSend(^RenderPassStencilAttachmentDescriptor, self, "stencilAttachment") +} +@(objc_type=RenderPassDescriptor, objc_name="threadgroupMemoryLength") +RenderPassDescriptor_threadgroupMemoryLength :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "threadgroupMemoryLength") +} +@(objc_type=RenderPassDescriptor, objc_name="tileHeight") +RenderPassDescriptor_tileHeight :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "tileHeight") +} +@(objc_type=RenderPassDescriptor, objc_name="tileWidth") +RenderPassDescriptor_tileWidth :: proc(self: ^RenderPassDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "tileWidth") +} +@(objc_type=RenderPassDescriptor, objc_name="visibilityResultBuffer") +RenderPassDescriptor_visibilityResultBuffer :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { + return msgSend(^RenderPassDescriptor, self, "visibilityResultBuffer") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassSampleBufferAttachmentDescriptor +Class Methods: + alloc +Methods: + init + endOfFragmentSampleIndex + endOfVertexSampleIndex + sampleBuffer + setEndOfFragmentSampleIndex + setEndOfVertexSampleIndex + setSampleBuffer + setStartOfFragmentSampleIndex + setStartOfVertexSampleIndex + startOfFragmentSampleIndex + startOfVertexSampleIndex +*/ +@(objc_class="MTLRenderPassSampleBufferAttachmentDescriptor") +RenderPassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassSampleBufferAttachmentDescriptor) } + +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +RenderPassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^RenderPassSampleBufferAttachmentDescriptor { + return msgSend(^RenderPassSampleBufferAttachmentDescriptor, RenderPassSampleBufferAttachmentDescriptor, "alloc") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="init") +RenderPassSampleBufferAttachmentDescriptor_init :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { + return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "init") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="endOfFragmentSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_endOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "endOfFragmentSampleIndex") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="endOfVertexSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_endOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "endOfVertexSampleIndex") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") +RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { + return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfFragmentSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_setEndOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfFragmentSampleIndex: NS.Integer) { + msgSend(nil, self, "setEndOfFragmentSampleIndex:", endOfFragmentSampleIndex) +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfVertexSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_setEndOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfVertexSampleIndex: NS.Integer) { + msgSend(nil, self, "setEndOfVertexSampleIndex:", endOfVertexSampleIndex) +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") +RenderPassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { + msgSend(nil, self, "setSampleBuffer:", sampleBuffer) +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setStartOfFragmentSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_setStartOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfFragmentSampleIndex: NS.Integer) { + msgSend(nil, self, "setStartOfFragmentSampleIndex:", startOfFragmentSampleIndex) +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setStartOfVertexSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_setStartOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfVertexSampleIndex: NS.Integer) { + msgSend(nil, self, "setStartOfVertexSampleIndex:", startOfVertexSampleIndex) +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="startOfFragmentSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_startOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "startOfFragmentSampleIndex") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="startOfVertexSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_startOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "startOfVertexSampleIndex") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassSampleBufferAttachmentDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLRenderPassSampleBufferAttachmentDescriptorArray") +RenderPassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +RenderPassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^RenderPassSampleBufferAttachmentDescriptorArray { + return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, RenderPassSampleBufferAttachmentDescriptorArray, "alloc") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="init") +RenderPassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray) -> ^RenderPassSampleBufferAttachmentDescriptorArray { + return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, self, "init") +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") +RenderPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassSampleBufferAttachmentDescriptor { + return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) +} +@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") +RenderPassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachment: ^RenderPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPassStencilAttachmentDescriptor +Class Methods: + alloc +Methods: + init + clearStencil + setClearStencil + setStencilResolveFilter + stencilResolveFilter +*/ +@(objc_class="MTLRenderPassStencilAttachmentDescriptor") +RenderPassStencilAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassStencilAttachmentDescriptor) } + +@(objc_type=RenderPassStencilAttachmentDescriptor, objc_class_name="alloc") +RenderPassStencilAttachmentDescriptor_alloc :: proc() -> ^RenderPassStencilAttachmentDescriptor { + return msgSend(^RenderPassStencilAttachmentDescriptor, RenderPassStencilAttachmentDescriptor, "alloc") +} +@(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="init") +RenderPassStencilAttachmentDescriptor_init :: proc(self: ^RenderPassStencilAttachmentDescriptor) -> ^RenderPassStencilAttachmentDescriptor { + return msgSend(^RenderPassStencilAttachmentDescriptor, self, "init") +} +@(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="clearStencil") +RenderPassStencilAttachmentDescriptor_clearStencil :: proc(self: ^RenderPassStencilAttachmentDescriptor) -> u32 { + return msgSend(u32, self, "clearStencil") +} +@(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="setClearStencil") +RenderPassStencilAttachmentDescriptor_setClearStencil :: proc(self: ^RenderPassStencilAttachmentDescriptor, clearStencil: u32) { + msgSend(nil, self, "setClearStencil:", clearStencil) +} +@(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="setStencilResolveFilter") +RenderPassStencilAttachmentDescriptor_setStencilResolveFilter :: proc(self: ^RenderPassStencilAttachmentDescriptor, stencilResolveFilter: MultisampleStencilResolveFilter) { + msgSend(nil, self, "setStencilResolveFilter:", stencilResolveFilter) +} +@(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="stencilResolveFilter") +RenderPassStencilAttachmentDescriptor_stencilResolveFilter :: proc(self: ^RenderPassStencilAttachmentDescriptor) -> MultisampleStencilResolveFilter { + return msgSend(MultisampleStencilResolveFilter, self, "stencilResolveFilter") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPipelineColorAttachmentDescriptor +Class Methods: + alloc +Methods: + init + alphaBlendOperation + destinationAlphaBlendFactor + destinationRGBBlendFactor + isBlendingEnabled + pixelFormat + rgbBlendOperation + setAlphaBlendOperation + setBlendingEnabled + setDestinationAlphaBlendFactor + setDestinationRGBBlendFactor + setPixelFormat + setRgbBlendOperation + setSourceAlphaBlendFactor + setSourceRGBBlendFactor + setWriteMask + sourceAlphaBlendFactor + sourceRGBBlendFactor + writeMask +*/ +@(objc_class="MTLRenderPipelineColorAttachmentDescriptor") +RenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPipelineColorAttachmentDescriptor) } + +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_class_name="alloc") +RenderPipelineColorAttachmentDescriptor_alloc :: proc() -> ^RenderPipelineColorAttachmentDescriptor { + return msgSend(^RenderPipelineColorAttachmentDescriptor, RenderPipelineColorAttachmentDescriptor, "alloc") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="init") +RenderPipelineColorAttachmentDescriptor_init :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> ^RenderPipelineColorAttachmentDescriptor { + return msgSend(^RenderPipelineColorAttachmentDescriptor, self, "init") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="alphaBlendOperation") +RenderPipelineColorAttachmentDescriptor_alphaBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendOperation { + return msgSend(BlendOperation, self, "alphaBlendOperation") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="destinationAlphaBlendFactor") +RenderPipelineColorAttachmentDescriptor_destinationAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { + return msgSend(BlendFactor, self, "destinationAlphaBlendFactor") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="destinationRGBBlendFactor") +RenderPipelineColorAttachmentDescriptor_destinationRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { + return msgSend(BlendFactor, self, "destinationRGBBlendFactor") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="isBlendingEnabled") +RenderPipelineColorAttachmentDescriptor_isBlendingEnabled :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BOOL { + return msgSend(BOOL, self, "isBlendingEnabled") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="pixelFormat") +RenderPipelineColorAttachmentDescriptor_pixelFormat :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> PixelFormat { + return msgSend(PixelFormat, self, "pixelFormat") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="rgbBlendOperation") +RenderPipelineColorAttachmentDescriptor_rgbBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendOperation { + return msgSend(BlendOperation, self, "rgbBlendOperation") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setAlphaBlendOperation") +RenderPipelineColorAttachmentDescriptor_setAlphaBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor, alphaBlendOperation: BlendOperation) { + msgSend(nil, self, "setAlphaBlendOperation:", alphaBlendOperation) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setBlendingEnabled") +RenderPipelineColorAttachmentDescriptor_setBlendingEnabled :: proc(self: ^RenderPipelineColorAttachmentDescriptor, blendingEnabled: BOOL) { + msgSend(nil, self, "setBlendingEnabled:", blendingEnabled) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setDestinationAlphaBlendFactor") +RenderPipelineColorAttachmentDescriptor_setDestinationAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, destinationAlphaBlendFactor: BlendFactor) { + msgSend(nil, self, "setDestinationAlphaBlendFactor:", destinationAlphaBlendFactor) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setDestinationRGBBlendFactor") +RenderPipelineColorAttachmentDescriptor_setDestinationRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, destinationRGBBlendFactor: BlendFactor) { + msgSend(nil, self, "setDestinationRGBBlendFactor:", destinationRGBBlendFactor) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setPixelFormat") +RenderPipelineColorAttachmentDescriptor_setPixelFormat :: proc(self: ^RenderPipelineColorAttachmentDescriptor, pixelFormat: PixelFormat) { + msgSend(nil, self, "setPixelFormat:", pixelFormat) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setRgbBlendOperation") +RenderPipelineColorAttachmentDescriptor_setRgbBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor, rgbBlendOperation: BlendOperation) { + msgSend(nil, self, "setRgbBlendOperation:", rgbBlendOperation) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setSourceAlphaBlendFactor") +RenderPipelineColorAttachmentDescriptor_setSourceAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, sourceAlphaBlendFactor: BlendFactor) { + msgSend(nil, self, "setSourceAlphaBlendFactor:", sourceAlphaBlendFactor) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setSourceRGBBlendFactor") +RenderPipelineColorAttachmentDescriptor_setSourceRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, sourceRGBBlendFactor: BlendFactor) { + msgSend(nil, self, "setSourceRGBBlendFactor:", sourceRGBBlendFactor) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setWriteMask") +RenderPipelineColorAttachmentDescriptor_setWriteMask :: proc(self: ^RenderPipelineColorAttachmentDescriptor, writeMask: ColorWriteMask) { + msgSend(nil, self, "setWriteMask:", writeMask) +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="sourceAlphaBlendFactor") +RenderPipelineColorAttachmentDescriptor_sourceAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { + return msgSend(BlendFactor, self, "sourceAlphaBlendFactor") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="sourceRGBBlendFactor") +RenderPipelineColorAttachmentDescriptor_sourceRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { + return msgSend(BlendFactor, self, "sourceRGBBlendFactor") +} +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="writeMask") +RenderPipelineColorAttachmentDescriptor_writeMask :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> ColorWriteMask { + return msgSend(ColorWriteMask, self, "writeMask") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPipelineColorAttachmentDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLRenderPipelineColorAttachmentDescriptorArray") +RenderPipelineColorAttachmentDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_class_name="alloc") +RenderPipelineColorAttachmentDescriptorArray_alloc :: proc() -> ^RenderPipelineColorAttachmentDescriptorArray { + return msgSend(^RenderPipelineColorAttachmentDescriptorArray, RenderPipelineColorAttachmentDescriptorArray, "alloc") +} +@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="init") +RenderPipelineColorAttachmentDescriptorArray_init :: proc(self: ^RenderPipelineColorAttachmentDescriptorArray) -> ^RenderPipelineColorAttachmentDescriptorArray { + return msgSend(^RenderPipelineColorAttachmentDescriptorArray, self, "init") +} +@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") +RenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPipelineColorAttachmentDescriptor { + return msgSend(^RenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) +} +@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") +RenderPipelineColorAttachmentDescriptorArray_setObject :: proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachment: ^RenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPipelineDescriptor +Class Methods: + alloc +Methods: + init + binaryArchives + colorAttachments + depthAttachmentPixelFormat + fragmentBuffers + fragmentFunction + inputPrimitiveTopology + isAlphaToCoverageEnabled + isAlphaToOneEnabled + isRasterizationEnabled + isTessellationFactorScaleEnabled + label + maxTessellationFactor + maxVertexAmplificationCount + rasterSampleCount + reset + sampleCount + setAlphaToCoverageEnabled + setAlphaToOneEnabled + setBinaryArchives + setDepthAttachmentPixelFormat + setFragmentFunction + setInputPrimitiveTopology + setLabel + setMaxTessellationFactor + setMaxVertexAmplificationCount + setRasterSampleCount + setRasterizationEnabled + setSampleCount + setStencilAttachmentPixelFormat + setSupportIndirectCommandBuffers + setTessellationControlPointIndexType + setTessellationFactorFormat + setTessellationFactorScaleEnabled + setTessellationFactorStepFunction + setTessellationOutputWindingOrder + setTessellationPartitionMode + setVertexDescriptor + setVertexFunction + stencilAttachmentPixelFormat + supportIndirectCommandBuffers + tessellationControlPointIndexType + tessellationFactorFormat + tessellationFactorStepFunction + tessellationOutputWindingOrder + tessellationPartitionMode + vertexBuffers + vertexDescriptor + vertexFunction +*/ +@(objc_class="MTLRenderPipelineDescriptor") +RenderPipelineDescriptor :: struct { using _: NS.Copying(RenderPipelineDescriptor) } + +@(objc_type=RenderPipelineDescriptor, objc_class_name="alloc") +RenderPipelineDescriptor_alloc :: proc() -> ^RenderPipelineDescriptor { + return msgSend(^RenderPipelineDescriptor, RenderPipelineDescriptor, "alloc") +} +@(objc_type=RenderPipelineDescriptor, objc_name="init") +RenderPipelineDescriptor_init :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { + return msgSend(^RenderPipelineDescriptor, self, "init") +} +@(objc_type=RenderPipelineDescriptor, objc_name="binaryArchives") +RenderPipelineDescriptor_binaryArchives :: proc(self: ^RenderPipelineDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "binaryArchives") +} +@(objc_type=RenderPipelineDescriptor, objc_name="colorAttachments") +RenderPipelineDescriptor_colorAttachments :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineColorAttachmentDescriptorArray { + return msgSend(^RenderPipelineColorAttachmentDescriptorArray, self, "colorAttachments") +} +@(objc_type=RenderPipelineDescriptor, objc_name="depthAttachmentPixelFormat") +RenderPipelineDescriptor_depthAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor) -> PixelFormat { + return msgSend(PixelFormat, self, "depthAttachmentPixelFormat") +} +@(objc_type=RenderPipelineDescriptor, objc_name="fragmentBuffers") +RenderPipelineDescriptor_fragmentBuffers :: proc(self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "fragmentBuffers") +} +@(objc_type=RenderPipelineDescriptor, objc_name="fragmentFunction") +RenderPipelineDescriptor_fragmentFunction :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { + return msgSend(^RenderPipelineDescriptor, self, "fragmentFunction") +} +@(objc_type=RenderPipelineDescriptor, objc_name="inputPrimitiveTopology") +RenderPipelineDescriptor_inputPrimitiveTopology :: proc(self: ^RenderPipelineDescriptor) -> PrimitiveTopologyClass { + return msgSend(PrimitiveTopologyClass, self, "inputPrimitiveTopology") +} +@(objc_type=RenderPipelineDescriptor, objc_name="isAlphaToCoverageEnabled") +RenderPipelineDescriptor_isAlphaToCoverageEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "isAlphaToCoverageEnabled") +} +@(objc_type=RenderPipelineDescriptor, objc_name="isAlphaToOneEnabled") +RenderPipelineDescriptor_isAlphaToOneEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "isAlphaToOneEnabled") +} +@(objc_type=RenderPipelineDescriptor, objc_name="isRasterizationEnabled") +RenderPipelineDescriptor_isRasterizationEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "isRasterizationEnabled") +} +@(objc_type=RenderPipelineDescriptor, objc_name="isTessellationFactorScaleEnabled") +RenderPipelineDescriptor_isTessellationFactorScaleEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "isTessellationFactorScaleEnabled") +} +@(objc_type=RenderPipelineDescriptor, objc_name="label") +RenderPipelineDescriptor_label :: proc(self: ^RenderPipelineDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=RenderPipelineDescriptor, objc_name="maxTessellationFactor") +RenderPipelineDescriptor_maxTessellationFactor :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxTessellationFactor") +} +@(objc_type=RenderPipelineDescriptor, objc_name="maxVertexAmplificationCount") +RenderPipelineDescriptor_maxVertexAmplificationCount :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxVertexAmplificationCount") +} +@(objc_type=RenderPipelineDescriptor, objc_name="rasterSampleCount") +RenderPipelineDescriptor_rasterSampleCount :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "rasterSampleCount") +} +@(objc_type=RenderPipelineDescriptor, objc_name="reset") +RenderPipelineDescriptor_reset :: proc(self: ^RenderPipelineDescriptor) { + msgSend(nil, self, "reset") +} +@(objc_type=RenderPipelineDescriptor, objc_name="sampleCount") +RenderPipelineDescriptor_sampleCount :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "sampleCount") +} +@(objc_type=RenderPipelineDescriptor, objc_name="setAlphaToCoverageEnabled") +RenderPipelineDescriptor_setAlphaToCoverageEnabled :: proc(self: ^RenderPipelineDescriptor, alphaToCoverageEnabled: BOOL) { + msgSend(nil, self, "setAlphaToCoverageEnabled:", alphaToCoverageEnabled) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setAlphaToOneEnabled") +RenderPipelineDescriptor_setAlphaToOneEnabled :: proc(self: ^RenderPipelineDescriptor, alphaToOneEnabled: BOOL) { + msgSend(nil, self, "setAlphaToOneEnabled:", alphaToOneEnabled) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setBinaryArchives") +RenderPipelineDescriptor_setBinaryArchives :: proc(self: ^RenderPipelineDescriptor, binaryArchives: ^NS.Array) { + msgSend(nil, self, "setBinaryArchives:", binaryArchives) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setDepthAttachmentPixelFormat") +RenderPipelineDescriptor_setDepthAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor, depthAttachmentPixelFormat: PixelFormat) { + msgSend(nil, self, "setDepthAttachmentPixelFormat:", depthAttachmentPixelFormat) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setFragmentFunction") +RenderPipelineDescriptor_setFragmentFunction :: proc(self: ^RenderPipelineDescriptor, fragmentFunction: ^NS.Object) { + msgSend(nil, self, "setFragmentFunction:", fragmentFunction) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setInputPrimitiveTopology") +RenderPipelineDescriptor_setInputPrimitiveTopology :: proc(self: ^RenderPipelineDescriptor, inputPrimitiveTopology: PrimitiveTopologyClass) { + msgSend(nil, self, "setInputPrimitiveTopology:", inputPrimitiveTopology) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setLabel") +RenderPipelineDescriptor_setLabel :: proc(self: ^RenderPipelineDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setMaxTessellationFactor") +RenderPipelineDescriptor_setMaxTessellationFactor :: proc(self: ^RenderPipelineDescriptor, maxTessellationFactor: NS.Integer) { + msgSend(nil, self, "setMaxTessellationFactor:", maxTessellationFactor) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setMaxVertexAmplificationCount") +RenderPipelineDescriptor_setMaxVertexAmplificationCount :: proc(self: ^RenderPipelineDescriptor, maxVertexAmplificationCount: NS.Integer) { + msgSend(nil, self, "setMaxVertexAmplificationCount:", maxVertexAmplificationCount) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setRasterSampleCount") +RenderPipelineDescriptor_setRasterSampleCount :: proc(self: ^RenderPipelineDescriptor, rasterSampleCount: NS.Integer) { + msgSend(nil, self, "setRasterSampleCount:", rasterSampleCount) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setRasterizationEnabled") +RenderPipelineDescriptor_setRasterizationEnabled :: proc(self: ^RenderPipelineDescriptor, rasterizationEnabled: BOOL) { + msgSend(nil, self, "setRasterizationEnabled:", rasterizationEnabled) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setSampleCount") +RenderPipelineDescriptor_setSampleCount :: proc(self: ^RenderPipelineDescriptor, sampleCount: NS.Integer) { + msgSend(nil, self, "setSampleCount:", sampleCount) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setStencilAttachmentPixelFormat") +RenderPipelineDescriptor_setStencilAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor, stencilAttachmentPixelFormat: PixelFormat) { + msgSend(nil, self, "setStencilAttachmentPixelFormat:", stencilAttachmentPixelFormat) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setSupportIndirectCommandBuffers") +RenderPipelineDescriptor_setSupportIndirectCommandBuffers :: proc(self: ^RenderPipelineDescriptor, supportIndirectCommandBuffers: BOOL) { + msgSend(nil, self, "setSupportIndirectCommandBuffers:", supportIndirectCommandBuffers) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setTessellationControlPointIndexType") +RenderPipelineDescriptor_setTessellationControlPointIndexType :: proc(self: ^RenderPipelineDescriptor, tessellationControlPointIndexType: TessellationControlPointIndexType) { + msgSend(nil, self, "setTessellationControlPointIndexType:", tessellationControlPointIndexType) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setTessellationFactorFormat") +RenderPipelineDescriptor_setTessellationFactorFormat :: proc(self: ^RenderPipelineDescriptor, tessellationFactorFormat: TessellationFactorFormat) { + msgSend(nil, self, "setTessellationFactorFormat:", tessellationFactorFormat) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setTessellationFactorScaleEnabled") +RenderPipelineDescriptor_setTessellationFactorScaleEnabled :: proc(self: ^RenderPipelineDescriptor, tessellationFactorScaleEnabled: BOOL) { + msgSend(nil, self, "setTessellationFactorScaleEnabled:", tessellationFactorScaleEnabled) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setTessellationFactorStepFunction") +RenderPipelineDescriptor_setTessellationFactorStepFunction :: proc(self: ^RenderPipelineDescriptor, tessellationFactorStepFunction: TessellationFactorStepFunction) { + msgSend(nil, self, "setTessellationFactorStepFunction:", tessellationFactorStepFunction) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setTessellationOutputWindingOrder") +RenderPipelineDescriptor_setTessellationOutputWindingOrder :: proc(self: ^RenderPipelineDescriptor, tessellationOutputWindingOrder: Winding) { + msgSend(nil, self, "setTessellationOutputWindingOrder:", tessellationOutputWindingOrder) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setTessellationPartitionMode") +RenderPipelineDescriptor_setTessellationPartitionMode :: proc(self: ^RenderPipelineDescriptor, tessellationPartitionMode: TessellationPartitionMode) { + msgSend(nil, self, "setTessellationPartitionMode:", tessellationPartitionMode) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setVertexDescriptor") +RenderPipelineDescriptor_setVertexDescriptor :: proc(self: ^RenderPipelineDescriptor, vertexDescriptor: ^VertexDescriptor) { + msgSend(nil, self, "setVertexDescriptor:", vertexDescriptor) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setVertexFunction") +RenderPipelineDescriptor_setVertexFunction :: proc(self: ^RenderPipelineDescriptor, vertexFunction: ^NS.Object) { + msgSend(nil, self, "setVertexFunction:", vertexFunction) +} +@(objc_type=RenderPipelineDescriptor, objc_name="stencilAttachmentPixelFormat") +RenderPipelineDescriptor_stencilAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor) -> PixelFormat { + return msgSend(PixelFormat, self, "stencilAttachmentPixelFormat") +} +@(objc_type=RenderPipelineDescriptor, objc_name="supportIndirectCommandBuffers") +RenderPipelineDescriptor_supportIndirectCommandBuffers :: proc(self: ^RenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "supportIndirectCommandBuffers") +} +@(objc_type=RenderPipelineDescriptor, objc_name="tessellationControlPointIndexType") +RenderPipelineDescriptor_tessellationControlPointIndexType :: proc(self: ^RenderPipelineDescriptor) -> TessellationControlPointIndexType { + return msgSend(TessellationControlPointIndexType, self, "tessellationControlPointIndexType") +} +@(objc_type=RenderPipelineDescriptor, objc_name="tessellationFactorFormat") +RenderPipelineDescriptor_tessellationFactorFormat :: proc(self: ^RenderPipelineDescriptor) -> TessellationFactorFormat { + return msgSend(TessellationFactorFormat, self, "tessellationFactorFormat") +} +@(objc_type=RenderPipelineDescriptor, objc_name="tessellationFactorStepFunction") +RenderPipelineDescriptor_tessellationFactorStepFunction :: proc(self: ^RenderPipelineDescriptor) -> TessellationFactorStepFunction { + return msgSend(TessellationFactorStepFunction, self, "tessellationFactorStepFunction") +} +@(objc_type=RenderPipelineDescriptor, objc_name="tessellationOutputWindingOrder") +RenderPipelineDescriptor_tessellationOutputWindingOrder :: proc(self: ^RenderPipelineDescriptor) -> Winding { + return msgSend(Winding, self, "tessellationOutputWindingOrder") +} +@(objc_type=RenderPipelineDescriptor, objc_name="tessellationPartitionMode") +RenderPipelineDescriptor_tessellationPartitionMode :: proc(self: ^RenderPipelineDescriptor) -> TessellationPartitionMode { + return msgSend(TessellationPartitionMode, self, "tessellationPartitionMode") +} +@(objc_type=RenderPipelineDescriptor, objc_name="vertexBuffers") +RenderPipelineDescriptor_vertexBuffers :: proc(self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "vertexBuffers") +} +@(objc_type=RenderPipelineDescriptor, objc_name="vertexDescriptor") +RenderPipelineDescriptor_vertexDescriptor :: proc(self: ^RenderPipelineDescriptor) -> ^VertexDescriptor { + return msgSend(^VertexDescriptor, self, "vertexDescriptor") +} +@(objc_type=RenderPipelineDescriptor, objc_name="vertexFunction") +RenderPipelineDescriptor_vertexFunction :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { + return msgSend(^RenderPipelineDescriptor, self, "vertexFunction") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPipelineReflection +Class Methods: + alloc +Methods: + init + fragmentArguments + tileArguments + vertexArguments +*/ +@(objc_class="MTLRenderPipelineReflection") +RenderPipelineReflection :: struct { using _: NS.Object } + +@(objc_type=RenderPipelineReflection, objc_class_name="alloc") +RenderPipelineReflection_alloc :: proc() -> ^RenderPipelineReflection { + return msgSend(^RenderPipelineReflection, RenderPipelineReflection, "alloc") +} +@(objc_type=RenderPipelineReflection, objc_name="init") +RenderPipelineReflection_init :: proc(self: ^RenderPipelineReflection) -> ^RenderPipelineReflection { + return msgSend(^RenderPipelineReflection, self, "init") +} +@(objc_type=RenderPipelineReflection, objc_name="fragmentArguments") +RenderPipelineReflection_fragmentArguments :: proc(self: ^RenderPipelineReflection) -> ^NS.Array { + return msgSend(^NS.Array, self, "fragmentArguments") +} +@(objc_type=RenderPipelineReflection, objc_name="tileArguments") +RenderPipelineReflection_tileArguments :: proc(self: ^RenderPipelineReflection) -> ^NS.Array { + return msgSend(^NS.Array, self, "tileArguments") +} +@(objc_type=RenderPipelineReflection, objc_name="vertexArguments") +RenderPipelineReflection_vertexArguments :: proc(self: ^RenderPipelineReflection) -> ^NS.Array { + return msgSend(^NS.Array, self, "vertexArguments") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ResourceStatePassDescriptor +Class Methods: + alloc + resourceStatePassDescriptor +Methods: + init + sampleBufferAttachments +*/ +@(objc_class="MTLResourceStatePassDescriptor") +ResourceStatePassDescriptor :: struct { using _: NS.Copying(ResourceStatePassDescriptor) } + +@(objc_type=ResourceStatePassDescriptor, objc_class_name="alloc") +ResourceStatePassDescriptor_alloc :: proc() -> ^ResourceStatePassDescriptor { + return msgSend(^ResourceStatePassDescriptor, ResourceStatePassDescriptor, "alloc") +} +@(objc_type=ResourceStatePassDescriptor, objc_name="init") +ResourceStatePassDescriptor_init :: proc(self: ^ResourceStatePassDescriptor) -> ^ResourceStatePassDescriptor { + return msgSend(^ResourceStatePassDescriptor, self, "init") +} +@(objc_type=ResourceStatePassDescriptor, objc_class_name="resourceStatePassDescriptor") +ResourceStatePassDescriptor_resourceStatePassDescriptor :: proc() -> ^ResourceStatePassDescriptor { + return msgSend(^ResourceStatePassDescriptor, ResourceStatePassDescriptor, "resourceStatePassDescriptor") +} +@(objc_type=ResourceStatePassDescriptor, objc_name="sampleBufferAttachments") +ResourceStatePassDescriptor_sampleBufferAttachments :: proc(self: ^ResourceStatePassDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { + return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ResourceStatePassSampleBufferAttachmentDescriptor +Class Methods: + alloc +Methods: + init + endOfEncoderSampleIndex + sampleBuffer + setEndOfEncoderSampleIndex + setSampleBuffer + setStartOfEncoderSampleIndex + startOfEncoderSampleIndex +*/ +@(objc_class="MTLResourceStatePassSampleBufferAttachmentDescriptor") +ResourceStatePassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(ResourceStatePassSampleBufferAttachmentDescriptor) } + +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +ResourceStatePassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptor { + return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, ResourceStatePassSampleBufferAttachmentDescriptor, "alloc") +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="init") +ResourceStatePassSampleBufferAttachmentDescriptor_init :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { + return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "init") +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") +ResourceStatePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") +ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { + return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") +ResourceStatePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { + msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") +ResourceStatePassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { + msgSend(nil, self, "setSampleBuffer:", sampleBuffer) +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") +ResourceStatePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { + msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") +ResourceStatePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ResourceStatePassSampleBufferAttachmentDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLResourceStatePassSampleBufferAttachmentDescriptorArray") +ResourceStatePassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +ResourceStatePassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { + return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, ResourceStatePassSampleBufferAttachmentDescriptorArray, "alloc") +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="init") +ResourceStatePassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray) -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { + return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, self, "init") +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") +ResourceStatePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { + return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) +} +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") +ResourceStatePassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachment: ^ResourceStatePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + SamplerDescriptor +Class Methods: + alloc +Methods: + init + borderColor + compareFunction + label + lodAverage + lodMaxClamp + lodMinClamp + magFilter + maxAnisotropy + minFilter + mipFilter + normalizedCoordinates + rAddressMode + sAddressMode + setBorderColor + setCompareFunction + setLabel + setLodAverage + setLodMaxClamp + setLodMinClamp + setMagFilter + setMaxAnisotropy + setMinFilter + setMipFilter + setNormalizedCoordinates + setRAddressMode + setSAddressMode + setSupportArgumentBuffers + setTAddressMode + supportArgumentBuffers + tAddressMode +*/ +@(objc_class="MTLSamplerDescriptor") +SamplerDescriptor :: struct { using _: NS.Copying(SamplerDescriptor) } + +@(objc_type=SamplerDescriptor, objc_class_name="alloc") +SamplerDescriptor_alloc :: proc() -> ^SamplerDescriptor { + return msgSend(^SamplerDescriptor, SamplerDescriptor, "alloc") +} +@(objc_type=SamplerDescriptor, objc_name="init") +SamplerDescriptor_init :: proc(self: ^SamplerDescriptor) -> ^SamplerDescriptor { + return msgSend(^SamplerDescriptor, self, "init") +} +@(objc_type=SamplerDescriptor, objc_name="borderColor") +SamplerDescriptor_borderColor :: proc(self: ^SamplerDescriptor) -> SamplerBorderColor { + return msgSend(SamplerBorderColor, self, "borderColor") +} +@(objc_type=SamplerDescriptor, objc_name="compareFunction") +SamplerDescriptor_compareFunction :: proc(self: ^SamplerDescriptor) -> CompareFunction { + return msgSend(CompareFunction, self, "compareFunction") +} +@(objc_type=SamplerDescriptor, objc_name="label") +SamplerDescriptor_label :: proc(self: ^SamplerDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=SamplerDescriptor, objc_name="lodAverage") +SamplerDescriptor_lodAverage :: proc(self: ^SamplerDescriptor) -> BOOL { + return msgSend(BOOL, self, "lodAverage") +} +@(objc_type=SamplerDescriptor, objc_name="lodMaxClamp") +SamplerDescriptor_lodMaxClamp :: proc(self: ^SamplerDescriptor) -> f32 { + return msgSend(f32, self, "lodMaxClamp") +} +@(objc_type=SamplerDescriptor, objc_name="lodMinClamp") +SamplerDescriptor_lodMinClamp :: proc(self: ^SamplerDescriptor) -> f32 { + return msgSend(f32, self, "lodMinClamp") +} +@(objc_type=SamplerDescriptor, objc_name="magFilter") +SamplerDescriptor_magFilter :: proc(self: ^SamplerDescriptor) -> SamplerMinMagFilter { + return msgSend(SamplerMinMagFilter, self, "magFilter") +} +@(objc_type=SamplerDescriptor, objc_name="maxAnisotropy") +SamplerDescriptor_maxAnisotropy :: proc(self: ^SamplerDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxAnisotropy") +} +@(objc_type=SamplerDescriptor, objc_name="minFilter") +SamplerDescriptor_minFilter :: proc(self: ^SamplerDescriptor) -> SamplerMinMagFilter { + return msgSend(SamplerMinMagFilter, self, "minFilter") +} +@(objc_type=SamplerDescriptor, objc_name="mipFilter") +SamplerDescriptor_mipFilter :: proc(self: ^SamplerDescriptor) -> SamplerMipFilter { + return msgSend(SamplerMipFilter, self, "mipFilter") +} +@(objc_type=SamplerDescriptor, objc_name="normalizedCoordinates") +SamplerDescriptor_normalizedCoordinates :: proc(self: ^SamplerDescriptor) -> BOOL { + return msgSend(BOOL, self, "normalizedCoordinates") +} +@(objc_type=SamplerDescriptor, objc_name="rAddressMode") +SamplerDescriptor_rAddressMode :: proc(self: ^SamplerDescriptor) -> SamplerAddressMode { + return msgSend(SamplerAddressMode, self, "rAddressMode") +} +@(objc_type=SamplerDescriptor, objc_name="sAddressMode") +SamplerDescriptor_sAddressMode :: proc(self: ^SamplerDescriptor) -> SamplerAddressMode { + return msgSend(SamplerAddressMode, self, "sAddressMode") +} +@(objc_type=SamplerDescriptor, objc_name="setBorderColor") +SamplerDescriptor_setBorderColor :: proc(self: ^SamplerDescriptor, borderColor: SamplerBorderColor) { + msgSend(nil, self, "setBorderColor:", borderColor) +} +@(objc_type=SamplerDescriptor, objc_name="setCompareFunction") +SamplerDescriptor_setCompareFunction :: proc(self: ^SamplerDescriptor, compareFunction: CompareFunction) { + msgSend(nil, self, "setCompareFunction:", compareFunction) +} +@(objc_type=SamplerDescriptor, objc_name="setLabel") +SamplerDescriptor_setLabel :: proc(self: ^SamplerDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=SamplerDescriptor, objc_name="setLodAverage") +SamplerDescriptor_setLodAverage :: proc(self: ^SamplerDescriptor, lodAverage: BOOL) { + msgSend(nil, self, "setLodAverage:", lodAverage) +} +@(objc_type=SamplerDescriptor, objc_name="setLodMaxClamp") +SamplerDescriptor_setLodMaxClamp :: proc(self: ^SamplerDescriptor, lodMaxClamp: f32) { + msgSend(nil, self, "setLodMaxClamp:", lodMaxClamp) +} +@(objc_type=SamplerDescriptor, objc_name="setLodMinClamp") +SamplerDescriptor_setLodMinClamp :: proc(self: ^SamplerDescriptor, lodMinClamp: f32) { + msgSend(nil, self, "setLodMinClamp:", lodMinClamp) +} +@(objc_type=SamplerDescriptor, objc_name="setMagFilter") +SamplerDescriptor_setMagFilter :: proc(self: ^SamplerDescriptor, magFilter: SamplerMinMagFilter) { + msgSend(nil, self, "setMagFilter:", magFilter) +} +@(objc_type=SamplerDescriptor, objc_name="setMaxAnisotropy") +SamplerDescriptor_setMaxAnisotropy :: proc(self: ^SamplerDescriptor, maxAnisotropy: NS.Integer) { + msgSend(nil, self, "setMaxAnisotropy:", maxAnisotropy) +} +@(objc_type=SamplerDescriptor, objc_name="setMinFilter") +SamplerDescriptor_setMinFilter :: proc(self: ^SamplerDescriptor, minFilter: SamplerMinMagFilter) { + msgSend(nil, self, "setMinFilter:", minFilter) +} +@(objc_type=SamplerDescriptor, objc_name="setMipFilter") +SamplerDescriptor_setMipFilter :: proc(self: ^SamplerDescriptor, mipFilter: SamplerMipFilter) { + msgSend(nil, self, "setMipFilter:", mipFilter) +} +@(objc_type=SamplerDescriptor, objc_name="setNormalizedCoordinates") +SamplerDescriptor_setNormalizedCoordinates :: proc(self: ^SamplerDescriptor, normalizedCoordinates: BOOL) { + msgSend(nil, self, "setNormalizedCoordinates:", normalizedCoordinates) +} +@(objc_type=SamplerDescriptor, objc_name="setRAddressMode") +SamplerDescriptor_setRAddressMode :: proc(self: ^SamplerDescriptor, rAddressMode: SamplerAddressMode) { + msgSend(nil, self, "setRAddressMode:", rAddressMode) +} +@(objc_type=SamplerDescriptor, objc_name="setSAddressMode") +SamplerDescriptor_setSAddressMode :: proc(self: ^SamplerDescriptor, sAddressMode: SamplerAddressMode) { + msgSend(nil, self, "setSAddressMode:", sAddressMode) +} +@(objc_type=SamplerDescriptor, objc_name="setSupportArgumentBuffers") +SamplerDescriptor_setSupportArgumentBuffers :: proc(self: ^SamplerDescriptor, supportArgumentBuffers: BOOL) { + msgSend(nil, self, "setSupportArgumentBuffers:", supportArgumentBuffers) +} +@(objc_type=SamplerDescriptor, objc_name="setTAddressMode") +SamplerDescriptor_setTAddressMode :: proc(self: ^SamplerDescriptor, tAddressMode: SamplerAddressMode) { + msgSend(nil, self, "setTAddressMode:", tAddressMode) +} +@(objc_type=SamplerDescriptor, objc_name="supportArgumentBuffers") +SamplerDescriptor_supportArgumentBuffers :: proc(self: ^SamplerDescriptor) -> BOOL { + return msgSend(BOOL, self, "supportArgumentBuffers") +} +@(objc_type=SamplerDescriptor, objc_name="tAddressMode") +SamplerDescriptor_tAddressMode :: proc(self: ^SamplerDescriptor) -> SamplerAddressMode { + return msgSend(SamplerAddressMode, self, "tAddressMode") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + SharedEventHandle +Class Methods: + alloc +Methods: + init + label +*/ +@(objc_class="MTLSharedEventHandle") +SharedEventHandle :: struct { using _: NS.Object } + +@(objc_type=SharedEventHandle, objc_class_name="alloc") +SharedEventHandle_alloc :: proc() -> ^SharedEventHandle { + return msgSend(^SharedEventHandle, SharedEventHandle, "alloc") +} +@(objc_type=SharedEventHandle, objc_name="init") +SharedEventHandle_init :: proc(self: ^SharedEventHandle) -> ^SharedEventHandle { + return msgSend(^SharedEventHandle, self, "init") +} +@(objc_type=SharedEventHandle, objc_name="label") +SharedEventHandle_label :: proc(self: ^SharedEventHandle) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + SharedEventListener +Class Methods: + alloc +Methods: + dispatchQueue + init + initWithDispatchQueue +*/ +@(objc_class="MTLSharedEventListener") +SharedEventListener :: struct { using _: NS.Object } + +@(objc_type=SharedEventListener, objc_class_name="alloc") +SharedEventListener_alloc :: proc() -> ^SharedEventListener { + return msgSend(^SharedEventListener, SharedEventListener, "alloc") +} +@(objc_type=SharedEventListener, objc_name="dispatchQueue") +SharedEventListener_dispatchQueue :: proc(self: ^SharedEventListener) -> NS.Integer { + return msgSend(NS.Integer, self, "dispatchQueue") +} +@(objc_type=SharedEventListener, objc_name="init") +SharedEventListener_init :: proc(self: ^SharedEventListener) -> ^SharedEventListener { + return msgSend(^SharedEventListener, self, "init") +} +@(objc_type=SharedEventListener, objc_name="initWithDispatchQueue") +SharedEventListener_initWithDispatchQueue :: proc(self: ^SharedEventListener, dispatchQueue: ^NS.Object) -> ^SharedEventListener { + return msgSend(^SharedEventListener, self, "initWithDispatchQueue:", dispatchQueue) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + SharedTextureHandle +Class Methods: + alloc +Methods: + init + device + label +*/ +@(objc_class="MTLSharedTextureHandle") +SharedTextureHandle :: struct { using _: NS.Object } + +@(objc_type=SharedTextureHandle, objc_class_name="alloc") +SharedTextureHandle_alloc :: proc() -> ^SharedTextureHandle { + return msgSend(^SharedTextureHandle, SharedTextureHandle, "alloc") +} +@(objc_type=SharedTextureHandle, objc_name="init") +SharedTextureHandle_init :: proc(self: ^SharedTextureHandle) -> ^SharedTextureHandle { + return msgSend(^SharedTextureHandle, self, "init") +} +@(objc_type=SharedTextureHandle, objc_name="device") +SharedTextureHandle_device :: proc(self: ^SharedTextureHandle) -> ^SharedTextureHandle { + return msgSend(^SharedTextureHandle, self, "device") +} +@(objc_type=SharedTextureHandle, objc_name="label") +SharedTextureHandle_label :: proc(self: ^SharedTextureHandle) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + StageInputOutputDescriptor +Class Methods: + alloc + stageInputOutputDescriptor +Methods: + init + attributes + indexBufferIndex + indexType + layouts + reset + setIndexBufferIndex + setIndexType +*/ +@(objc_class="MTLStageInputOutputDescriptor") +StageInputOutputDescriptor :: struct { using _: NS.Copying(StageInputOutputDescriptor) } + +@(objc_type=StageInputOutputDescriptor, objc_class_name="alloc") +StageInputOutputDescriptor_alloc :: proc() -> ^StageInputOutputDescriptor { + return msgSend(^StageInputOutputDescriptor, StageInputOutputDescriptor, "alloc") +} +@(objc_type=StageInputOutputDescriptor, objc_name="init") +StageInputOutputDescriptor_init :: proc(self: ^StageInputOutputDescriptor) -> ^StageInputOutputDescriptor { + return msgSend(^StageInputOutputDescriptor, self, "init") +} +@(objc_type=StageInputOutputDescriptor, objc_name="attributes") +StageInputOutputDescriptor_attributes :: proc(self: ^StageInputOutputDescriptor) -> ^AttributeDescriptorArray { + return msgSend(^AttributeDescriptorArray, self, "attributes") +} +@(objc_type=StageInputOutputDescriptor, objc_name="indexBufferIndex") +StageInputOutputDescriptor_indexBufferIndex :: proc(self: ^StageInputOutputDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "indexBufferIndex") +} +@(objc_type=StageInputOutputDescriptor, objc_name="indexType") +StageInputOutputDescriptor_indexType :: proc(self: ^StageInputOutputDescriptor) -> IndexType { + return msgSend(IndexType, self, "indexType") +} +@(objc_type=StageInputOutputDescriptor, objc_name="layouts") +StageInputOutputDescriptor_layouts :: proc(self: ^StageInputOutputDescriptor) -> ^BufferLayoutDescriptorArray { + return msgSend(^BufferLayoutDescriptorArray, self, "layouts") +} +@(objc_type=StageInputOutputDescriptor, objc_name="reset") +StageInputOutputDescriptor_reset :: proc(self: ^StageInputOutputDescriptor) { + msgSend(nil, self, "reset") +} +@(objc_type=StageInputOutputDescriptor, objc_name="setIndexBufferIndex") +StageInputOutputDescriptor_setIndexBufferIndex :: proc(self: ^StageInputOutputDescriptor, indexBufferIndex: NS.Integer) { + msgSend(nil, self, "setIndexBufferIndex:", indexBufferIndex) +} +@(objc_type=StageInputOutputDescriptor, objc_name="setIndexType") +StageInputOutputDescriptor_setIndexType :: proc(self: ^StageInputOutputDescriptor, indexType: IndexType) { + msgSend(nil, self, "setIndexType:", indexType) +} +@(objc_type=StageInputOutputDescriptor, objc_class_name="stageInputOutputDescriptor") +StageInputOutputDescriptor_stageInputOutputDescriptor :: proc() -> ^StageInputOutputDescriptor { + return msgSend(^StageInputOutputDescriptor, StageInputOutputDescriptor, "stageInputOutputDescriptor") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + StencilDescriptor +Class Methods: + alloc +Methods: + init + depthFailureOperation + depthStencilPassOperation + readMask + setDepthFailureOperation + setDepthStencilPassOperation + setReadMask + setStencilCompareFunction + setStencilFailureOperation + setWriteMask + stencilCompareFunction + stencilFailureOperation + writeMask +*/ +@(objc_class="MTLStencilDescriptor") +StencilDescriptor :: struct { using _: NS.Copying(StencilDescriptor) } + +@(objc_type=StencilDescriptor, objc_class_name="alloc") +StencilDescriptor_alloc :: proc() -> ^StencilDescriptor { + return msgSend(^StencilDescriptor, StencilDescriptor, "alloc") +} +@(objc_type=StencilDescriptor, objc_name="init") +StencilDescriptor_init :: proc(self: ^StencilDescriptor) -> ^StencilDescriptor { + return msgSend(^StencilDescriptor, self, "init") +} +@(objc_type=StencilDescriptor, objc_name="depthFailureOperation") +StencilDescriptor_depthFailureOperation :: proc(self: ^StencilDescriptor) -> StencilOperation { + return msgSend(StencilOperation, self, "depthFailureOperation") +} +@(objc_type=StencilDescriptor, objc_name="depthStencilPassOperation") +StencilDescriptor_depthStencilPassOperation :: proc(self: ^StencilDescriptor) -> StencilOperation { + return msgSend(StencilOperation, self, "depthStencilPassOperation") +} +@(objc_type=StencilDescriptor, objc_name="readMask") +StencilDescriptor_readMask :: proc(self: ^StencilDescriptor) -> u32 { + return msgSend(u32, self, "readMask") +} +@(objc_type=StencilDescriptor, objc_name="setDepthFailureOperation") +StencilDescriptor_setDepthFailureOperation :: proc(self: ^StencilDescriptor, depthFailureOperation: StencilOperation) { + msgSend(nil, self, "setDepthFailureOperation:", depthFailureOperation) +} +@(objc_type=StencilDescriptor, objc_name="setDepthStencilPassOperation") +StencilDescriptor_setDepthStencilPassOperation :: proc(self: ^StencilDescriptor, depthStencilPassOperation: StencilOperation) { + msgSend(nil, self, "setDepthStencilPassOperation:", depthStencilPassOperation) +} +@(objc_type=StencilDescriptor, objc_name="setReadMask") +StencilDescriptor_setReadMask :: proc(self: ^StencilDescriptor, readMask: u32) { + msgSend(nil, self, "setReadMask:", readMask) +} +@(objc_type=StencilDescriptor, objc_name="setStencilCompareFunction") +StencilDescriptor_setStencilCompareFunction :: proc(self: ^StencilDescriptor, stencilCompareFunction: CompareFunction) { + msgSend(nil, self, "setStencilCompareFunction:", stencilCompareFunction) +} +@(objc_type=StencilDescriptor, objc_name="setStencilFailureOperation") +StencilDescriptor_setStencilFailureOperation :: proc(self: ^StencilDescriptor, stencilFailureOperation: StencilOperation) { + msgSend(nil, self, "setStencilFailureOperation:", stencilFailureOperation) +} +@(objc_type=StencilDescriptor, objc_name="setWriteMask") +StencilDescriptor_setWriteMask :: proc(self: ^StencilDescriptor, writeMask: u32) { + msgSend(nil, self, "setWriteMask:", writeMask) +} +@(objc_type=StencilDescriptor, objc_name="stencilCompareFunction") +StencilDescriptor_stencilCompareFunction :: proc(self: ^StencilDescriptor) -> CompareFunction { + return msgSend(CompareFunction, self, "stencilCompareFunction") +} +@(objc_type=StencilDescriptor, objc_name="stencilFailureOperation") +StencilDescriptor_stencilFailureOperation :: proc(self: ^StencilDescriptor) -> StencilOperation { + return msgSend(StencilOperation, self, "stencilFailureOperation") +} +@(objc_type=StencilDescriptor, objc_name="writeMask") +StencilDescriptor_writeMask :: proc(self: ^StencilDescriptor) -> u32 { + return msgSend(u32, self, "writeMask") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + StructMember +Class Methods: + alloc +Methods: + init + argumentIndex + arrayType + dataType + name + offset + pointerType + structType + textureReferenceType +*/ +@(objc_class="MTLStructMember") +StructMember :: struct { using _: NS.Object } + +@(objc_type=StructMember, objc_class_name="alloc") +StructMember_alloc :: proc() -> ^StructMember { + return msgSend(^StructMember, StructMember, "alloc") +} +@(objc_type=StructMember, objc_name="init") +StructMember_init :: proc(self: ^StructMember) -> ^StructMember { + return msgSend(^StructMember, self, "init") +} +@(objc_type=StructMember, objc_name="argumentIndex") +StructMember_argumentIndex :: proc(self: ^StructMember) -> NS.Integer { + return msgSend(NS.Integer, self, "argumentIndex") +} +@(objc_type=StructMember, objc_name="arrayType") +StructMember_arrayType :: proc(self: ^StructMember) -> ^ArrayType { + return msgSend(^ArrayType, self, "arrayType") +} +@(objc_type=StructMember, objc_name="dataType") +StructMember_dataType :: proc(self: ^StructMember) -> DataType { + return msgSend(DataType, self, "dataType") +} +@(objc_type=StructMember, objc_name="name") +StructMember_name :: proc(self: ^StructMember) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} +@(objc_type=StructMember, objc_name="offset") +StructMember_offset :: proc(self: ^StructMember) -> NS.Integer { + return msgSend(NS.Integer, self, "offset") +} +@(objc_type=StructMember, objc_name="pointerType") +StructMember_pointerType :: proc(self: ^StructMember) -> ^PointerType { + return msgSend(^PointerType, self, "pointerType") +} +@(objc_type=StructMember, objc_name="structType") +StructMember_structType :: proc(self: ^StructMember) -> ^StructType { + return msgSend(^StructType, self, "structType") +} +@(objc_type=StructMember, objc_name="textureReferenceType") +StructMember_textureReferenceType :: proc(self: ^StructMember) -> ^TextureReferenceType { + return msgSend(^TextureReferenceType, self, "textureReferenceType") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + StructType +Class Methods: + alloc +Methods: + init + memberByName + members +*/ +@(objc_class="MTLStructType") +StructType :: struct { using _: NS.Object } + +@(objc_type=StructType, objc_class_name="alloc") +StructType_alloc :: proc() -> ^StructType { + return msgSend(^StructType, StructType, "alloc") +} +@(objc_type=StructType, objc_name="init") +StructType_init :: proc(self: ^StructType) -> ^StructType { + return msgSend(^StructType, self, "init") +} +@(objc_type=StructType, objc_name="memberByName") +StructType_memberByName :: proc(self: ^StructType, name: ^NS.String) -> ^StructMember { + return msgSend(^StructMember, self, "memberByName:", name) +} +@(objc_type=StructType, objc_name="members") +StructType_members :: proc(self: ^StructType) -> ^NS.Array { + return msgSend(^NS.Array, self, "members") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + TextureDescriptor +Class Methods: + alloc + texture2DDescriptorWithPixelFormat + textureBufferDescriptorWithPixelFormat + textureCubeDescriptorWithPixelFormat +Methods: + init + allowGPUOptimizedContents + arrayLength + cpuCacheMode + depth + hazardTrackingMode + height + mipmapLevelCount + pixelFormat + resourceOptions + sampleCount + setAllowGPUOptimizedContents + setArrayLength + setCpuCacheMode + setDepth + setHazardTrackingMode + setHeight + setMipmapLevelCount + setPixelFormat + setResourceOptions + setSampleCount + setStorageMode + setSwizzle + setTextureType + setUsage + setWidth + storageMode + swizzle + textureType + usage + width +*/ +@(objc_class="MTLTextureDescriptor") +TextureDescriptor :: struct { using _: NS.Copying(TextureDescriptor) } + +@(objc_type=TextureDescriptor, objc_class_name="alloc") +TextureDescriptor_alloc :: proc() -> ^TextureDescriptor { + return msgSend(^TextureDescriptor, TextureDescriptor, "alloc") +} +@(objc_type=TextureDescriptor, objc_name="init") +TextureDescriptor_init :: proc(self: ^TextureDescriptor) -> ^TextureDescriptor { + return msgSend(^TextureDescriptor, self, "init") +} +@(objc_type=TextureDescriptor, objc_name="allowGPUOptimizedContents") +TextureDescriptor_allowGPUOptimizedContents :: proc(self: ^TextureDescriptor) -> BOOL { + return msgSend(BOOL, self, "allowGPUOptimizedContents") +} +@(objc_type=TextureDescriptor, objc_name="arrayLength") +TextureDescriptor_arrayLength :: proc(self: ^TextureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "arrayLength") +} +@(objc_type=TextureDescriptor, objc_name="cpuCacheMode") +TextureDescriptor_cpuCacheMode :: proc(self: ^TextureDescriptor) -> CPUCacheMode { + return msgSend(CPUCacheMode, self, "cpuCacheMode") +} +@(objc_type=TextureDescriptor, objc_name="depth") +TextureDescriptor_depth :: proc(self: ^TextureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "depth") +} +@(objc_type=TextureDescriptor, objc_name="hazardTrackingMode") +TextureDescriptor_hazardTrackingMode :: proc(self: ^TextureDescriptor) -> HazardTrackingMode { + return msgSend(HazardTrackingMode, self, "hazardTrackingMode") +} +@(objc_type=TextureDescriptor, objc_name="height") +TextureDescriptor_height :: proc(self: ^TextureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "height") +} +@(objc_type=TextureDescriptor, objc_name="mipmapLevelCount") +TextureDescriptor_mipmapLevelCount :: proc(self: ^TextureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "mipmapLevelCount") +} +@(objc_type=TextureDescriptor, objc_name="pixelFormat") +TextureDescriptor_pixelFormat :: proc(self: ^TextureDescriptor) -> PixelFormat { + return msgSend(PixelFormat, self, "pixelFormat") +} +@(objc_type=TextureDescriptor, objc_name="resourceOptions") +TextureDescriptor_resourceOptions :: proc(self: ^TextureDescriptor) -> ResourceOptions { + return msgSend(ResourceOptions, self, "resourceOptions") +} +@(objc_type=TextureDescriptor, objc_name="sampleCount") +TextureDescriptor_sampleCount :: proc(self: ^TextureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "sampleCount") +} +@(objc_type=TextureDescriptor, objc_name="setAllowGPUOptimizedContents") +TextureDescriptor_setAllowGPUOptimizedContents :: proc(self: ^TextureDescriptor, allowGPUOptimizedContents: BOOL) { + msgSend(nil, self, "setAllowGPUOptimizedContents:", allowGPUOptimizedContents) +} +@(objc_type=TextureDescriptor, objc_name="setArrayLength") +TextureDescriptor_setArrayLength :: proc(self: ^TextureDescriptor, arrayLength: NS.Integer) { + msgSend(nil, self, "setArrayLength:", arrayLength) +} +@(objc_type=TextureDescriptor, objc_name="setCpuCacheMode") +TextureDescriptor_setCpuCacheMode :: proc(self: ^TextureDescriptor, cpuCacheMode: CPUCacheMode) { + msgSend(nil, self, "setCpuCacheMode:", cpuCacheMode) +} +@(objc_type=TextureDescriptor, objc_name="setDepth") +TextureDescriptor_setDepth :: proc(self: ^TextureDescriptor, depth: NS.Integer) { + msgSend(nil, self, "setDepth:", depth) +} +@(objc_type=TextureDescriptor, objc_name="setHazardTrackingMode") +TextureDescriptor_setHazardTrackingMode :: proc(self: ^TextureDescriptor, hazardTrackingMode: HazardTrackingMode) { + msgSend(nil, self, "setHazardTrackingMode:", hazardTrackingMode) +} +@(objc_type=TextureDescriptor, objc_name="setHeight") +TextureDescriptor_setHeight :: proc(self: ^TextureDescriptor, height: NS.Integer) { + msgSend(nil, self, "setHeight:", height) +} +@(objc_type=TextureDescriptor, objc_name="setMipmapLevelCount") +TextureDescriptor_setMipmapLevelCount :: proc(self: ^TextureDescriptor, mipmapLevelCount: NS.Integer) { + msgSend(nil, self, "setMipmapLevelCount:", mipmapLevelCount) +} +@(objc_type=TextureDescriptor, objc_name="setPixelFormat") +TextureDescriptor_setPixelFormat :: proc(self: ^TextureDescriptor, pixelFormat: PixelFormat) { + msgSend(nil, self, "setPixelFormat:", pixelFormat) +} +@(objc_type=TextureDescriptor, objc_name="setResourceOptions") +TextureDescriptor_setResourceOptions :: proc(self: ^TextureDescriptor, resourceOptions: ResourceOptions) { + msgSend(nil, self, "setResourceOptions:", resourceOptions) +} +@(objc_type=TextureDescriptor, objc_name="setSampleCount") +TextureDescriptor_setSampleCount :: proc(self: ^TextureDescriptor, sampleCount: NS.Integer) { + msgSend(nil, self, "setSampleCount:", sampleCount) +} +@(objc_type=TextureDescriptor, objc_name="setStorageMode") +TextureDescriptor_setStorageMode :: proc(self: ^TextureDescriptor, storageMode: StorageMode) { + msgSend(nil, self, "setStorageMode:", storageMode) +} +@(objc_type=TextureDescriptor, objc_name="setSwizzle") +TextureDescriptor_setSwizzle :: proc(self: ^TextureDescriptor, swizzle: TextureSwizzleChannels) { + msgSend(nil, self, "setSwizzle:", swizzle) +} +@(objc_type=TextureDescriptor, objc_name="setTextureType") +TextureDescriptor_setTextureType :: proc(self: ^TextureDescriptor, textureType: TextureType) { + msgSend(nil, self, "setTextureType:", textureType) +} +@(objc_type=TextureDescriptor, objc_name="setUsage") +TextureDescriptor_setUsage :: proc(self: ^TextureDescriptor, usage: TextureUsage) { + msgSend(nil, self, "setUsage:", usage) +} +@(objc_type=TextureDescriptor, objc_name="setWidth") +TextureDescriptor_setWidth :: proc(self: ^TextureDescriptor, width: NS.Integer) { + msgSend(nil, self, "setWidth:", width) +} +@(objc_type=TextureDescriptor, objc_name="storageMode") +TextureDescriptor_storageMode :: proc(self: ^TextureDescriptor) -> StorageMode { + return msgSend(StorageMode, self, "storageMode") +} +@(objc_type=TextureDescriptor, objc_name="swizzle") +TextureDescriptor_swizzle :: proc(self: ^TextureDescriptor) -> TextureSwizzleChannels { + return msgSend(TextureSwizzleChannels, self, "swizzle") +} +@(objc_type=TextureDescriptor, objc_class_name="texture2DDescriptorWithPixelFormat") +TextureDescriptor_texture2DDescriptorWithPixelFormat :: proc(pixelFormat: PixelFormat, width: ^NS.Object, height: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { + return msgSend(^TextureDescriptor, TextureDescriptor, "texture2DDescriptorWithPixelFormat:width:height:mipmapped:", pixelFormat, width, height, mipmapped) +} +@(objc_type=TextureDescriptor, objc_class_name="textureBufferDescriptorWithPixelFormat") +TextureDescriptor_textureBufferDescriptorWithPixelFormat :: proc(pixelFormat: PixelFormat, width: ^NS.Object, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { + return msgSend(^TextureDescriptor, TextureDescriptor, "textureBufferDescriptorWithPixelFormat:width:resourceOptions:usage:", pixelFormat, width, resourceOptions, usage) +} +@(objc_type=TextureDescriptor, objc_class_name="textureCubeDescriptorWithPixelFormat") +TextureDescriptor_textureCubeDescriptorWithPixelFormat :: proc(pixelFormat: PixelFormat, size: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { + return msgSend(^TextureDescriptor, TextureDescriptor, "textureCubeDescriptorWithPixelFormat:size:mipmapped:", pixelFormat, size, mipmapped) +} +@(objc_type=TextureDescriptor, objc_name="textureType") +TextureDescriptor_textureType :: proc(self: ^TextureDescriptor) -> TextureType { + return msgSend(TextureType, self, "textureType") +} +@(objc_type=TextureDescriptor, objc_name="usage") +TextureDescriptor_usage :: proc(self: ^TextureDescriptor) -> TextureUsage { + return msgSend(TextureUsage, self, "usage") +} +@(objc_type=TextureDescriptor, objc_name="width") +TextureDescriptor_width :: proc(self: ^TextureDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "width") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + TextureReferenceType +Class Methods: + alloc +Methods: + init + access + isDepthTexture + textureDataType + textureType +*/ +@(objc_class="MTLTextureReferenceType") +TextureReferenceType :: struct { using _: NS.Object } + +@(objc_type=TextureReferenceType, objc_class_name="alloc") +TextureReferenceType_alloc :: proc() -> ^TextureReferenceType { + return msgSend(^TextureReferenceType, TextureReferenceType, "alloc") +} +@(objc_type=TextureReferenceType, objc_name="init") +TextureReferenceType_init :: proc(self: ^TextureReferenceType) -> ^TextureReferenceType { + return msgSend(^TextureReferenceType, self, "init") +} +@(objc_type=TextureReferenceType, objc_name="access") +TextureReferenceType_access :: proc(self: ^TextureReferenceType) -> ArgumentAccess { + return msgSend(ArgumentAccess, self, "access") +} +@(objc_type=TextureReferenceType, objc_name="isDepthTexture") +TextureReferenceType_isDepthTexture :: proc(self: ^TextureReferenceType) -> BOOL { + return msgSend(BOOL, self, "isDepthTexture") +} +@(objc_type=TextureReferenceType, objc_name="textureDataType") +TextureReferenceType_textureDataType :: proc(self: ^TextureReferenceType) -> DataType { + return msgSend(DataType, self, "textureDataType") +} +@(objc_type=TextureReferenceType, objc_name="textureType") +TextureReferenceType_textureType :: proc(self: ^TextureReferenceType) -> TextureType { + return msgSend(TextureType, self, "textureType") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + TileRenderPipelineColorAttachmentDescriptor +Class Methods: + alloc +Methods: + init + pixelFormat + setPixelFormat +*/ +@(objc_class="MTLTileRenderPipelineColorAttachmentDescriptor") +TileRenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(TileRenderPipelineColorAttachmentDescriptor) } + +@(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_class_name="alloc") +TileRenderPipelineColorAttachmentDescriptor_alloc :: proc() -> ^TileRenderPipelineColorAttachmentDescriptor { + return msgSend(^TileRenderPipelineColorAttachmentDescriptor, TileRenderPipelineColorAttachmentDescriptor, "alloc") +} +@(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_name="init") +TileRenderPipelineColorAttachmentDescriptor_init :: proc(self: ^TileRenderPipelineColorAttachmentDescriptor) -> ^TileRenderPipelineColorAttachmentDescriptor { + return msgSend(^TileRenderPipelineColorAttachmentDescriptor, self, "init") +} +@(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_name="pixelFormat") +TileRenderPipelineColorAttachmentDescriptor_pixelFormat :: proc(self: ^TileRenderPipelineColorAttachmentDescriptor) -> PixelFormat { + return msgSend(PixelFormat, self, "pixelFormat") +} +@(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_name="setPixelFormat") +TileRenderPipelineColorAttachmentDescriptor_setPixelFormat :: proc(self: ^TileRenderPipelineColorAttachmentDescriptor, pixelFormat: PixelFormat) { + msgSend(nil, self, "setPixelFormat:", pixelFormat) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + TileRenderPipelineColorAttachmentDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLTileRenderPipelineColorAttachmentDescriptorArray") +TileRenderPipelineColorAttachmentDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_class_name="alloc") +TileRenderPipelineColorAttachmentDescriptorArray_alloc :: proc() -> ^TileRenderPipelineColorAttachmentDescriptorArray { + return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, TileRenderPipelineColorAttachmentDescriptorArray, "alloc") +} +@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="init") +TileRenderPipelineColorAttachmentDescriptorArray_init :: proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray) -> ^TileRenderPipelineColorAttachmentDescriptorArray { + return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, self, "init") +} +@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") +TileRenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^TileRenderPipelineColorAttachmentDescriptor { + return msgSend(^TileRenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) +} +@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") +TileRenderPipelineColorAttachmentDescriptorArray_setObject :: proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachment: ^TileRenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + TileRenderPipelineDescriptor +Class Methods: + alloc +Methods: + init + binaryArchives + colorAttachments + label + maxTotalThreadsPerThreadgroup + rasterSampleCount + reset + setBinaryArchives + setLabel + setMaxTotalThreadsPerThreadgroup + setRasterSampleCount + setThreadgroupSizeMatchesTileSize + setTileFunction + threadgroupSizeMatchesTileSize + tileBuffers + tileFunction +*/ +@(objc_class="MTLTileRenderPipelineDescriptor") +TileRenderPipelineDescriptor :: struct { using _: NS.Copying(TileRenderPipelineDescriptor) } + +@(objc_type=TileRenderPipelineDescriptor, objc_class_name="alloc") +TileRenderPipelineDescriptor_alloc :: proc() -> ^TileRenderPipelineDescriptor { + return msgSend(^TileRenderPipelineDescriptor, TileRenderPipelineDescriptor, "alloc") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="init") +TileRenderPipelineDescriptor_init :: proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineDescriptor { + return msgSend(^TileRenderPipelineDescriptor, self, "init") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="binaryArchives") +TileRenderPipelineDescriptor_binaryArchives :: proc(self: ^TileRenderPipelineDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "binaryArchives") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="colorAttachments") +TileRenderPipelineDescriptor_colorAttachments :: proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineColorAttachmentDescriptorArray { + return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, self, "colorAttachments") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="label") +TileRenderPipelineDescriptor_label :: proc(self: ^TileRenderPipelineDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="maxTotalThreadsPerThreadgroup") +TileRenderPipelineDescriptor_maxTotalThreadsPerThreadgroup :: proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="rasterSampleCount") +TileRenderPipelineDescriptor_rasterSampleCount :: proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "rasterSampleCount") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="reset") +TileRenderPipelineDescriptor_reset :: proc(self: ^TileRenderPipelineDescriptor) { + msgSend(nil, self, "reset") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="setBinaryArchives") +TileRenderPipelineDescriptor_setBinaryArchives :: proc(self: ^TileRenderPipelineDescriptor, binaryArchives: ^NS.Array) { + msgSend(nil, self, "setBinaryArchives:", binaryArchives) +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="setLabel") +TileRenderPipelineDescriptor_setLabel :: proc(self: ^TileRenderPipelineDescriptor, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="setMaxTotalThreadsPerThreadgroup") +TileRenderPipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: proc(self: ^TileRenderPipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { + msgSend(nil, self, "setMaxTotalThreadsPerThreadgroup:", maxTotalThreadsPerThreadgroup) +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="setRasterSampleCount") +TileRenderPipelineDescriptor_setRasterSampleCount :: proc(self: ^TileRenderPipelineDescriptor, rasterSampleCount: NS.Integer) { + msgSend(nil, self, "setRasterSampleCount:", rasterSampleCount) +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="setThreadgroupSizeMatchesTileSize") +TileRenderPipelineDescriptor_setThreadgroupSizeMatchesTileSize :: proc(self: ^TileRenderPipelineDescriptor, threadgroupSizeMatchesTileSize: BOOL) { + msgSend(nil, self, "setThreadgroupSizeMatchesTileSize:", threadgroupSizeMatchesTileSize) +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="setTileFunction") +TileRenderPipelineDescriptor_setTileFunction :: proc(self: ^TileRenderPipelineDescriptor, tileFunction: ^NS.Object) { + msgSend(nil, self, "setTileFunction:", tileFunction) +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="threadgroupSizeMatchesTileSize") +TileRenderPipelineDescriptor_threadgroupSizeMatchesTileSize :: proc(self: ^TileRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "threadgroupSizeMatchesTileSize") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="tileBuffers") +TileRenderPipelineDescriptor_tileBuffers :: proc(self: ^TileRenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "tileBuffers") +} +@(objc_type=TileRenderPipelineDescriptor, objc_name="tileFunction") +TileRenderPipelineDescriptor_tileFunction :: proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineDescriptor { + return msgSend(^TileRenderPipelineDescriptor, self, "tileFunction") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Type +Class Methods: + alloc +Methods: + init + dataType +*/ +@(objc_class="MTLType") +Type :: struct { using _: NS.Object } + +@(objc_type=Type, objc_class_name="alloc") +Type_alloc :: proc() -> ^Type { + return msgSend(^Type, Type, "alloc") +} +@(objc_type=Type, objc_name="init") +Type_init :: proc(self: ^Type) -> ^Type { + return msgSend(^Type, self, "init") +} +@(objc_type=Type, objc_name="dataType") +Type_dataType :: proc(self: ^Type) -> DataType { + return msgSend(DataType, self, "dataType") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VertexAttribute +Class Methods: + alloc +Methods: + init + attributeIndex + attributeType + isActive + isPatchControlPointData + isPatchData + name +*/ +@(objc_class="MTLVertexAttribute") +VertexAttribute :: struct { using _: NS.Object } + +@(objc_type=VertexAttribute, objc_class_name="alloc") +VertexAttribute_alloc :: proc() -> ^VertexAttribute { + return msgSend(^VertexAttribute, VertexAttribute, "alloc") +} +@(objc_type=VertexAttribute, objc_name="init") +VertexAttribute_init :: proc(self: ^VertexAttribute) -> ^VertexAttribute { + return msgSend(^VertexAttribute, self, "init") +} +@(objc_type=VertexAttribute, objc_name="attributeIndex") +VertexAttribute_attributeIndex :: proc(self: ^VertexAttribute) -> NS.Integer { + return msgSend(NS.Integer, self, "attributeIndex") +} +@(objc_type=VertexAttribute, objc_name="attributeType") +VertexAttribute_attributeType :: proc(self: ^VertexAttribute) -> DataType { + return msgSend(DataType, self, "attributeType") +} +@(objc_type=VertexAttribute, objc_name="isActive") +VertexAttribute_isActive :: proc(self: ^VertexAttribute) -> BOOL { + return msgSend(BOOL, self, "isActive") +} +@(objc_type=VertexAttribute, objc_name="isPatchControlPointData") +VertexAttribute_isPatchControlPointData :: proc(self: ^VertexAttribute) -> BOOL { + return msgSend(BOOL, self, "isPatchControlPointData") +} +@(objc_type=VertexAttribute, objc_name="isPatchData") +VertexAttribute_isPatchData :: proc(self: ^VertexAttribute) -> BOOL { + return msgSend(BOOL, self, "isPatchData") +} +@(objc_type=VertexAttribute, objc_name="name") +VertexAttribute_name :: proc(self: ^VertexAttribute) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VertexAttributeDescriptor +Class Methods: + alloc +Methods: + init + bufferIndex + format + offset + setBufferIndex + setFormat + setOffset +*/ +@(objc_class="MTLVertexAttributeDescriptor") +VertexAttributeDescriptor :: struct { using _: NS.Copying(VertexAttributeDescriptor) } + +@(objc_type=VertexAttributeDescriptor, objc_class_name="alloc") +VertexAttributeDescriptor_alloc :: proc() -> ^VertexAttributeDescriptor { + return msgSend(^VertexAttributeDescriptor, VertexAttributeDescriptor, "alloc") +} +@(objc_type=VertexAttributeDescriptor, objc_name="init") +VertexAttributeDescriptor_init :: proc(self: ^VertexAttributeDescriptor) -> ^VertexAttributeDescriptor { + return msgSend(^VertexAttributeDescriptor, self, "init") +} +@(objc_type=VertexAttributeDescriptor, objc_name="bufferIndex") +VertexAttributeDescriptor_bufferIndex :: proc(self: ^VertexAttributeDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "bufferIndex") +} +@(objc_type=VertexAttributeDescriptor, objc_name="format") +VertexAttributeDescriptor_format :: proc(self: ^VertexAttributeDescriptor) -> VertexFormat { + return msgSend(VertexFormat, self, "format") +} +@(objc_type=VertexAttributeDescriptor, objc_name="offset") +VertexAttributeDescriptor_offset :: proc(self: ^VertexAttributeDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "offset") +} +@(objc_type=VertexAttributeDescriptor, objc_name="setBufferIndex") +VertexAttributeDescriptor_setBufferIndex :: proc(self: ^VertexAttributeDescriptor, bufferIndex: NS.Integer) { + msgSend(nil, self, "setBufferIndex:", bufferIndex) +} +@(objc_type=VertexAttributeDescriptor, objc_name="setFormat") +VertexAttributeDescriptor_setFormat :: proc(self: ^VertexAttributeDescriptor, format: VertexFormat) { + msgSend(nil, self, "setFormat:", format) +} +@(objc_type=VertexAttributeDescriptor, objc_name="setOffset") +VertexAttributeDescriptor_setOffset :: proc(self: ^VertexAttributeDescriptor, offset: NS.Integer) { + msgSend(nil, self, "setOffset:", offset) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VertexAttributeDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLVertexAttributeDescriptorArray") +VertexAttributeDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=VertexAttributeDescriptorArray, objc_class_name="alloc") +VertexAttributeDescriptorArray_alloc :: proc() -> ^VertexAttributeDescriptorArray { + return msgSend(^VertexAttributeDescriptorArray, VertexAttributeDescriptorArray, "alloc") +} +@(objc_type=VertexAttributeDescriptorArray, objc_name="init") +VertexAttributeDescriptorArray_init :: proc(self: ^VertexAttributeDescriptorArray) -> ^VertexAttributeDescriptorArray { + return msgSend(^VertexAttributeDescriptorArray, self, "init") +} +@(objc_type=VertexAttributeDescriptorArray, objc_name="objectAtIndexedSubscript") +VertexAttributeDescriptorArray_objectAtIndexedSubscript :: proc(self: ^VertexAttributeDescriptorArray, index: ^NS.Object) -> ^VertexAttributeDescriptor { + return msgSend(^VertexAttributeDescriptor, self, "objectAtIndexedSubscript:", index) +} +@(objc_type=VertexAttributeDescriptorArray, objc_name="setObject") +VertexAttributeDescriptorArray_setObject :: proc(self: ^VertexAttributeDescriptorArray, attributeDesc: ^VertexAttributeDescriptor, index: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", attributeDesc, index) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VertexBufferLayoutDescriptor +Class Methods: + alloc +Methods: + init + setStepFunction + setStepRate + setStride + stepFunction + stepRate + stride +*/ +@(objc_class="MTLVertexBufferLayoutDescriptor") +VertexBufferLayoutDescriptor :: struct { using _: NS.Copying(VertexBufferLayoutDescriptor) } + +@(objc_type=VertexBufferLayoutDescriptor, objc_class_name="alloc") +VertexBufferLayoutDescriptor_alloc :: proc() -> ^VertexBufferLayoutDescriptor { + return msgSend(^VertexBufferLayoutDescriptor, VertexBufferLayoutDescriptor, "alloc") +} +@(objc_type=VertexBufferLayoutDescriptor, objc_name="init") +VertexBufferLayoutDescriptor_init :: proc(self: ^VertexBufferLayoutDescriptor) -> ^VertexBufferLayoutDescriptor { + return msgSend(^VertexBufferLayoutDescriptor, self, "init") +} +@(objc_type=VertexBufferLayoutDescriptor, objc_name="setStepFunction") +VertexBufferLayoutDescriptor_setStepFunction :: proc(self: ^VertexBufferLayoutDescriptor, stepFunction: VertexStepFunction) { + msgSend(nil, self, "setStepFunction:", stepFunction) +} +@(objc_type=VertexBufferLayoutDescriptor, objc_name="setStepRate") +VertexBufferLayoutDescriptor_setStepRate :: proc(self: ^VertexBufferLayoutDescriptor, stepRate: NS.Integer) { + msgSend(nil, self, "setStepRate:", stepRate) +} +@(objc_type=VertexBufferLayoutDescriptor, objc_name="setStride") +VertexBufferLayoutDescriptor_setStride :: proc(self: ^VertexBufferLayoutDescriptor, stride: NS.Integer) { + msgSend(nil, self, "setStride:", stride) +} +@(objc_type=VertexBufferLayoutDescriptor, objc_name="stepFunction") +VertexBufferLayoutDescriptor_stepFunction :: proc(self: ^VertexBufferLayoutDescriptor) -> VertexStepFunction { + return msgSend(VertexStepFunction, self, "stepFunction") +} +@(objc_type=VertexBufferLayoutDescriptor, objc_name="stepRate") +VertexBufferLayoutDescriptor_stepRate :: proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "stepRate") +} +@(objc_type=VertexBufferLayoutDescriptor, objc_name="stride") +VertexBufferLayoutDescriptor_stride :: proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "stride") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VertexBufferLayoutDescriptorArray +Class Methods: + alloc +Methods: + init + objectAtIndexedSubscript + setObject +*/ +@(objc_class="MTLVertexBufferLayoutDescriptorArray") +VertexBufferLayoutDescriptorArray :: struct { using _: NS.Object } + +@(objc_type=VertexBufferLayoutDescriptorArray, objc_class_name="alloc") +VertexBufferLayoutDescriptorArray_alloc :: proc() -> ^VertexBufferLayoutDescriptorArray { + return msgSend(^VertexBufferLayoutDescriptorArray, VertexBufferLayoutDescriptorArray, "alloc") +} +@(objc_type=VertexBufferLayoutDescriptorArray, objc_name="init") +VertexBufferLayoutDescriptorArray_init :: proc(self: ^VertexBufferLayoutDescriptorArray) -> ^VertexBufferLayoutDescriptorArray { + return msgSend(^VertexBufferLayoutDescriptorArray, self, "init") +} +@(objc_type=VertexBufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") +VertexBufferLayoutDescriptorArray_objectAtIndexedSubscript :: proc(self: ^VertexBufferLayoutDescriptorArray, index: ^NS.Object) -> ^VertexBufferLayoutDescriptor { + return msgSend(^VertexBufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) +} +@(objc_type=VertexBufferLayoutDescriptorArray, objc_name="setObject") +VertexBufferLayoutDescriptorArray_setObject :: proc(self: ^VertexBufferLayoutDescriptorArray, bufferDesc: ^VertexBufferLayoutDescriptor, index: ^NS.Object) { + msgSend(nil, self, "setObject:atIndexedSubscript:", bufferDesc, index) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VertexDescriptor +Class Methods: + alloc + vertexDescriptor +Methods: + init + attributes + layouts + reset +*/ +@(objc_class="MTLVertexDescriptor") +VertexDescriptor :: struct { using _: NS.Copying(VertexDescriptor) } + +@(objc_type=VertexDescriptor, objc_class_name="alloc") +VertexDescriptor_alloc :: proc() -> ^VertexDescriptor { + return msgSend(^VertexDescriptor, VertexDescriptor, "alloc") +} +@(objc_type=VertexDescriptor, objc_name="init") +VertexDescriptor_init :: proc(self: ^VertexDescriptor) -> ^VertexDescriptor { + return msgSend(^VertexDescriptor, self, "init") +} +@(objc_type=VertexDescriptor, objc_name="attributes") +VertexDescriptor_attributes :: proc(self: ^VertexDescriptor) -> ^VertexAttributeDescriptorArray { + return msgSend(^VertexAttributeDescriptorArray, self, "attributes") +} +@(objc_type=VertexDescriptor, objc_name="layouts") +VertexDescriptor_layouts :: proc(self: ^VertexDescriptor) -> ^VertexBufferLayoutDescriptorArray { + return msgSend(^VertexBufferLayoutDescriptorArray, self, "layouts") +} +@(objc_type=VertexDescriptor, objc_name="reset") +VertexDescriptor_reset :: proc(self: ^VertexDescriptor) { + msgSend(nil, self, "reset") +} +@(objc_type=VertexDescriptor, objc_class_name="vertexDescriptor") +VertexDescriptor_vertexDescriptor :: proc() -> ^VertexDescriptor { + return msgSend(^VertexDescriptor, VertexDescriptor, "vertexDescriptor") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VisibleFunctionTableDescriptor +Class Methods: + alloc + visibleFunctionTableDescriptor +Methods: + init + functionCount + setFunctionCount +*/ +@(objc_class="MTLVisibleFunctionTableDescriptor") +VisibleFunctionTableDescriptor :: struct { using _: NS.Copying(VisibleFunctionTableDescriptor) } + +@(objc_type=VisibleFunctionTableDescriptor, objc_class_name="alloc") +VisibleFunctionTableDescriptor_alloc :: proc() -> ^VisibleFunctionTableDescriptor { + return msgSend(^VisibleFunctionTableDescriptor, VisibleFunctionTableDescriptor, "alloc") +} +@(objc_type=VisibleFunctionTableDescriptor, objc_name="init") +VisibleFunctionTableDescriptor_init :: proc(self: ^VisibleFunctionTableDescriptor) -> ^VisibleFunctionTableDescriptor { + return msgSend(^VisibleFunctionTableDescriptor, self, "init") +} +@(objc_type=VisibleFunctionTableDescriptor, objc_name="functionCount") +VisibleFunctionTableDescriptor_functionCount :: proc(self: ^VisibleFunctionTableDescriptor) -> NS.Integer { + return msgSend(NS.Integer, self, "functionCount") +} +@(objc_type=VisibleFunctionTableDescriptor, objc_name="setFunctionCount") +VisibleFunctionTableDescriptor_setFunctionCount :: proc(self: ^VisibleFunctionTableDescriptor, functionCount: NS.Integer) { + msgSend(nil, self, "setFunctionCount:", functionCount) +} +@(objc_type=VisibleFunctionTableDescriptor, objc_class_name="visibleFunctionTableDescriptor") +VisibleFunctionTableDescriptor_visibleFunctionTableDescriptor :: proc() -> ^VisibleFunctionTableDescriptor { + return msgSend(^VisibleFunctionTableDescriptor, VisibleFunctionTableDescriptor, "visibleFunctionTableDescriptor") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructure +Class Methods: +Methods: + size +*/ +@(objc_class="MTLAccelerationStructure") +AccelerationStructure :: struct { using _: NS.Object } + +@(objc_type=AccelerationStructure, objc_name="size") +AccelerationStructure_size :: proc(self: ^AccelerationStructure) -> NS.Integer { + return msgSend(NS.Integer, self, "size") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructureCommandEncoder +Class Methods: +Methods: + buildAccelerationStructure + copyAccelerationStructure + copyAndCompactAccelerationStructure + refitAccelerationStructure + sampleCountersInBuffer + updateFence + useHeap + useHeaps + useResource + useResources + waitForFence + writeCompactedAccelerationStructureSize +*/ +@(objc_class="MTLAccelerationStructureCommandEncoder") +AccelerationStructureCommandEncoder :: struct { using _: NS.Object } + +@(objc_type=AccelerationStructureCommandEncoder, objc_name="buildAccelerationStructure") +AccelerationStructureCommandEncoder_buildAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { + msgSend(nil, self, "buildAccelerationStructure:descriptor:scratchBuffer:scratchBufferOffset:", accelerationStructure, descriptor, scratchBuffer, scratchBufferOffset) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAccelerationStructure") +AccelerationStructureCommandEncoder_copyAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { + msgSend(nil, self, "copyAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAndCompactAccelerationStructure") +AccelerationStructureCommandEncoder_copyAndCompactAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { + msgSend(nil, self, "copyAndCompactAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="refitAccelerationStructure") +AccelerationStructureCommandEncoder_refitAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, destinationAccelerationStructure: ^NS.Object, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { + msgSend(nil, self, "refitAccelerationStructure:descriptor:destination:scratchBuffer:scratchBufferOffset:", sourceAccelerationStructure, descriptor, destinationAccelerationStructure, scratchBuffer, scratchBufferOffset) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="sampleCountersInBuffer") +AccelerationStructureCommandEncoder_sampleCountersInBuffer :: proc(self: ^AccelerationStructureCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { + msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="updateFence") +AccelerationStructureCommandEncoder_updateFence :: proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "updateFence:", fence) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="useHeap") +AccelerationStructureCommandEncoder_useHeap :: proc(self: ^AccelerationStructureCommandEncoder, heap: ^NS.Object) { + msgSend(nil, self, "useHeap:", heap) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="useHeaps") +AccelerationStructureCommandEncoder_useHeaps :: proc(self: ^AccelerationStructureCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { + msgSend(nil, self, "useHeaps:count:", heaps, count) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="useResource") +AccelerationStructureCommandEncoder_useResource :: proc(self: ^AccelerationStructureCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { + msgSend(nil, self, "useResource:usage:", resource, usage) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="useResources") +AccelerationStructureCommandEncoder_useResources :: proc(self: ^AccelerationStructureCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { + msgSend(nil, self, "useResources:count:usage:", resources, count, usage) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="waitForFence") +AccelerationStructureCommandEncoder_waitForFence :: proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "waitForFence:", fence) +} +@(objc_type=AccelerationStructureCommandEncoder, objc_name="writeCompactedAccelerationStructureSize") +AccelerationStructureCommandEncoder_writeCompactedAccelerationStructureSize :: proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object) { + msgSend(nil, self, "writeCompactedAccelerationStructureSize:toBuffer:offset:", accelerationStructure, buffer, offset) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ArgumentEncoder +Class Methods: +Methods: + alignment + constantDataAtIndex + device + encodedLength + label + newArgumentEncoderForBufferAtIndex + setAccelerationStructure + setArgumentBuffer + setArgumentBuffer + setBuffer + setBuffers + setComputePipelineState + setComputePipelineStates + setIndirectCommandBuffer + setIndirectCommandBuffers + setIntersectionFunctionTable + setIntersectionFunctionTables + setLabel + setRenderPipelineState + setRenderPipelineStates + setSamplerState + setSamplerStates + setTexture + setTextures + setVisibleFunctionTable + setVisibleFunctionTables +*/ +@(objc_class="MTLArgumentEncoder") +ArgumentEncoder :: struct { using _: NS.Object } + +@(objc_type=ArgumentEncoder, objc_name="alignment") +ArgumentEncoder_alignment :: proc(self: ^ArgumentEncoder) -> NS.Integer { + return msgSend(NS.Integer, self, "alignment") +} +@(objc_type=ArgumentEncoder, objc_name="constantDataAtIndex") +ArgumentEncoder_constantDataAtIndex :: proc(self: ^ArgumentEncoder, index: ^NS.Object) -> rawptr { + return msgSend(rawptr, self, "constantDataAtIndex:", index) +} +@(objc_type=ArgumentEncoder, objc_name="device") +ArgumentEncoder_device :: proc(self: ^ArgumentEncoder) -> ^ArgumentEncoder { + return msgSend(^ArgumentEncoder, self, "device") +} +@(objc_type=ArgumentEncoder, objc_name="encodedLength") +ArgumentEncoder_encodedLength :: proc(self: ^ArgumentEncoder) -> NS.Integer { + return msgSend(NS.Integer, self, "encodedLength") +} +@(objc_type=ArgumentEncoder, objc_name="label") +ArgumentEncoder_label :: proc(self: ^ArgumentEncoder) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=ArgumentEncoder, objc_name="newArgumentEncoderForBufferAtIndex") +ArgumentEncoder_newArgumentEncoderForBufferAtIndex :: proc(self: ^ArgumentEncoder, index: ^NS.Object) -> ^ArgumentEncoder { + return msgSend(^ArgumentEncoder, self, "newArgumentEncoderForBufferAtIndex:", index) +} +@(objc_type=ArgumentEncoder, objc_name="setAccelerationStructure") +ArgumentEncoder_setAccelerationStructure :: proc(self: ^ArgumentEncoder, accelerationStructure: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setAccelerationStructure:atIndex:", accelerationStructure, index) +} +@(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_offset_") +ArgumentEncoder_setArgumentBuffer_offset_ :: proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, offset: ^NS.Object) { + msgSend(nil, self, "setArgumentBuffer:offset:", argumentBuffer, offset) +} +@(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_startOffset_arrayElement_") +ArgumentEncoder_setArgumentBuffer_startOffset_arrayElement_ :: proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, startOffset: ^NS.Object, arrayElement: ^NS.Object) { + msgSend(nil, self, "setArgumentBuffer:startOffset:arrayElement:", argumentBuffer, startOffset, arrayElement) +} +@(objc_type=ArgumentEncoder, objc_name="setBuffer") +ArgumentEncoder_setBuffer :: proc(self: ^ArgumentEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=ArgumentEncoder, objc_name="setBuffers") +ArgumentEncoder_setBuffers :: proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { + msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) +} +@(objc_type=ArgumentEncoder, objc_name="setComputePipelineState") +ArgumentEncoder_setComputePipelineState :: proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setComputePipelineState:atIndex:", pipeline, index) +} +@(objc_type=ArgumentEncoder, objc_name="setComputePipelineStates") +ArgumentEncoder_setComputePipelineStates :: proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setComputePipelineStates:withRange:", pipelines, range) +} +@(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffer") +ArgumentEncoder_setIndirectCommandBuffer :: proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setIndirectCommandBuffer:atIndex:", indirectCommandBuffer, index) +} +@(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffers") +ArgumentEncoder_setIndirectCommandBuffers :: proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setIndirectCommandBuffers:withRange:", buffers, range) +} +@(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTable") +ArgumentEncoder_setIntersectionFunctionTable :: proc(self: ^ArgumentEncoder, intersectionFunctionTable: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setIntersectionFunctionTable:atIndex:", intersectionFunctionTable, index) +} +@(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTables") +ArgumentEncoder_setIntersectionFunctionTables :: proc(self: ^ArgumentEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setIntersectionFunctionTables:withRange:", intersectionFunctionTables, range) +} +@(objc_type=ArgumentEncoder, objc_name="setLabel") +ArgumentEncoder_setLabel :: proc(self: ^ArgumentEncoder, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=ArgumentEncoder, objc_name="setRenderPipelineState") +ArgumentEncoder_setRenderPipelineState :: proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setRenderPipelineState:atIndex:", pipeline, index) +} +@(objc_type=ArgumentEncoder, objc_name="setRenderPipelineStates") +ArgumentEncoder_setRenderPipelineStates :: proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setRenderPipelineStates:withRange:", pipelines, range) +} +@(objc_type=ArgumentEncoder, objc_name="setSamplerState") +ArgumentEncoder_setSamplerState :: proc(self: ^ArgumentEncoder, sampler: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) +} +@(objc_type=ArgumentEncoder, objc_name="setSamplerStates") +ArgumentEncoder_setSamplerStates :: proc(self: ^ArgumentEncoder, samplers: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) +} +@(objc_type=ArgumentEncoder, objc_name="setTexture") +ArgumentEncoder_setTexture :: proc(self: ^ArgumentEncoder, texture: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setTexture:atIndex:", texture, index) +} +@(objc_type=ArgumentEncoder, objc_name="setTextures") +ArgumentEncoder_setTextures :: proc(self: ^ArgumentEncoder, textures: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setTextures:withRange:", textures, range) +} +@(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTable") +ArgumentEncoder_setVisibleFunctionTable :: proc(self: ^ArgumentEncoder, visibleFunctionTable: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setVisibleFunctionTable:atIndex:", visibleFunctionTable, index) +} +@(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTables") +ArgumentEncoder_setVisibleFunctionTables :: proc(self: ^ArgumentEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setVisibleFunctionTables:withRange:", visibleFunctionTables, range) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BinaryArchive +Class Methods: +Methods: + addComputePipelineFunctionsWithDescriptor + addRenderPipelineFunctionsWithDescriptor + addTileRenderPipelineFunctionsWithDescriptor + device + label + serializeToURL + setLabel +*/ +@(objc_class="MTLBinaryArchive") +BinaryArchive :: struct { using _: NS.Copying(BinaryArchive) } + +@(objc_type=BinaryArchive, objc_name="addComputePipelineFunctionsWithDescriptor") +BinaryArchive_addComputePipelineFunctionsWithDescriptor :: proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor, error: ^^NS.Error ) -> BOOL { + return msgSend(BOOL, self, "addComputePipelineFunctionsWithDescriptor:error:", descriptor, error) +} +@(objc_type=BinaryArchive, objc_name="addRenderPipelineFunctionsWithDescriptor") +BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { + return msgSend(BOOL, self, "addRenderPipelineFunctionsWithDescriptor:error:", descriptor, error) +} +@(objc_type=BinaryArchive, objc_name="addTileRenderPipelineFunctionsWithDescriptor") +BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { + return msgSend(BOOL, self, "addTileRenderPipelineFunctionsWithDescriptor:error:", descriptor, error) +} +@(objc_type=BinaryArchive, objc_name="device") +BinaryArchive_device :: proc(self: ^BinaryArchive) -> ^BinaryArchive { + return msgSend(^BinaryArchive, self, "device") +} +@(objc_type=BinaryArchive, objc_name="label") +BinaryArchive_label :: proc(self: ^BinaryArchive) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=BinaryArchive, objc_name="serializeToURL") +BinaryArchive_serializeToURL :: proc(self: ^BinaryArchive, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { + return msgSend(BOOL, self, "serializeToURL:error:", url, error) +} +@(objc_type=BinaryArchive, objc_name="setLabel") +BinaryArchive_setLabel :: proc(self: ^BinaryArchive, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + BlitCommandEncoder +Class Methods: +Methods: + copyFromBuffer + copyFromBuffer + copyFromBuffer + copyFromTexture + copyFromTexture + copyFromTexture + copyFromTexture + copyFromTexture + copyIndirectCommandBuffer + fillBuffer + generateMipmapsForTexture + getTextureAccessCounters + optimizeContentsForCPUAccess + optimizeContentsForCPUAccess + optimizeContentsForGPUAccess + optimizeContentsForGPUAccess + optimizeIndirectCommandBuffer + resetCommandsInBuffer + resetTextureAccessCounters + resolveCounters + sampleCountersInBuffer + synchronizeResource + synchronizeTexture + updateFence + waitForFence +*/ +@(objc_class="MTLBlitCommandEncoder") +BlitCommandEncoder :: struct { using _: NS.Object } + +@(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") +BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { + msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) +} +@(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_") +BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_ :: proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin, options: BlitOption) { + msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:options:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin, options) +} +@(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_") +BlitCommandEncoder_copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_ :: proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, size: ^NS.Object) { + msgSend(nil, self, "copyFromBuffer:sourceOffset:toBuffer:destinationOffset:size:", sourceBuffer, sourceOffset, destinationBuffer, destinationOffset, size) +} +@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_") +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object) { + msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage) +} +@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_") +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object, options: BlitOption) { + msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:options:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage, options) +} +@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { + msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) +} +@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_") +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, sliceCount: ^NS.Object, levelCount: ^NS.Object) { + msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:toTexture:destinationSlice:destinationLevel:sliceCount:levelCount:", sourceTexture, sourceSlice, sourceLevel, destinationTexture, destinationSlice, destinationLevel, sliceCount, levelCount) +} +@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_toTexture_") +BlitCommandEncoder_copyFromTexture_toTexture_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, destinationTexture: ^NS.Object) { + msgSend(nil, self, "copyFromTexture:toTexture:", sourceTexture, destinationTexture) +} +@(objc_type=BlitCommandEncoder, objc_name="copyIndirectCommandBuffer") +BlitCommandEncoder_copyIndirectCommandBuffer :: proc(self: ^BlitCommandEncoder, source: ^NS.Object, sourceRange: NS.Range, destination: ^NS.Object, destinationIndex: ^NS.Object) { + msgSend(nil, self, "copyIndirectCommandBuffer:sourceRange:destination:destinationIndex:", source, sourceRange, destination, destinationIndex) +} +@(objc_type=BlitCommandEncoder, objc_name="fillBuffer") +BlitCommandEncoder_fillBuffer :: proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range, value: u8) { + msgSend(nil, self, "fillBuffer:range:value:", buffer, range, value) +} +@(objc_type=BlitCommandEncoder, objc_name="generateMipmapsForTexture") +BlitCommandEncoder_generateMipmapsForTexture :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { + msgSend(nil, self, "generateMipmapsForTexture:", texture) +} +@(objc_type=BlitCommandEncoder, objc_name="getTextureAccessCounters") +BlitCommandEncoder_getTextureAccessCounters :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object, resetCounters: BOOL, countersBuffer: ^NS.Object, countersBufferOffset: ^NS.Object) { + msgSend(nil, self, "getTextureAccessCounters:region:mipLevel:slice:resetCounters:countersBuffer:countersBufferOffset:", texture, region, mipLevel, slice, resetCounters, countersBuffer, countersBufferOffset) +} +@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForCPUAccess") +BlitCommandEncoder_optimizeContentsForCPUAccess :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { + msgSend(nil, self, "optimizeContentsForCPUAccess:", texture) +} +@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForCPUAccess_slice_level_") +BlitCommandEncoder_optimizeContentsForCPUAccess_slice_level_ :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { + msgSend(nil, self, "optimizeContentsForCPUAccess:slice:level:", texture, slice, level) +} +@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForGPUAccess") +BlitCommandEncoder_optimizeContentsForGPUAccess :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { + msgSend(nil, self, "optimizeContentsForGPUAccess:", texture) +} +@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForGPUAccess_slice_level_") +BlitCommandEncoder_optimizeContentsForGPUAccess_slice_level_ :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { + msgSend(nil, self, "optimizeContentsForGPUAccess:slice:level:", texture, slice, level) +} +@(objc_type=BlitCommandEncoder, objc_name="optimizeIndirectCommandBuffer") +BlitCommandEncoder_optimizeIndirectCommandBuffer :: proc(self: ^BlitCommandEncoder, indirectCommandBuffer: ^NS.Object, range: NS.Range) { + msgSend(nil, self, "optimizeIndirectCommandBuffer:withRange:", indirectCommandBuffer, range) +} +@(objc_type=BlitCommandEncoder, objc_name="resetCommandsInBuffer") +BlitCommandEncoder_resetCommandsInBuffer :: proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range) { + msgSend(nil, self, "resetCommandsInBuffer:withRange:", buffer, range) +} +@(objc_type=BlitCommandEncoder, objc_name="resetTextureAccessCounters") +BlitCommandEncoder_resetTextureAccessCounters :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object) { + msgSend(nil, self, "resetTextureAccessCounters:region:mipLevel:slice:", texture, region, mipLevel, slice) +} +@(objc_type=BlitCommandEncoder, objc_name="resolveCounters") +BlitCommandEncoder_resolveCounters :: proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, range: NS.Range, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object) { + msgSend(nil, self, "resolveCounters:inRange:destinationBuffer:destinationOffset:", sampleBuffer, range, destinationBuffer, destinationOffset) +} +@(objc_type=BlitCommandEncoder, objc_name="sampleCountersInBuffer") +BlitCommandEncoder_sampleCountersInBuffer :: proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { + msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) +} +@(objc_type=BlitCommandEncoder, objc_name="synchronizeResource") +BlitCommandEncoder_synchronizeResource :: proc(self: ^BlitCommandEncoder, resource: ^NS.Object) { + msgSend(nil, self, "synchronizeResource:", resource) +} +@(objc_type=BlitCommandEncoder, objc_name="synchronizeTexture") +BlitCommandEncoder_synchronizeTexture :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { + msgSend(nil, self, "synchronizeTexture:slice:level:", texture, slice, level) +} +@(objc_type=BlitCommandEncoder, objc_name="updateFence") +BlitCommandEncoder_updateFence :: proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "updateFence:", fence) +} +@(objc_type=BlitCommandEncoder, objc_name="waitForFence") +BlitCommandEncoder_waitForFence :: proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "waitForFence:", fence) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Buffer +Class Methods: +Methods: + addDebugMarker + contents + didModifyRange + length + newRemoteBufferViewForDevice + newTextureWithDescriptor + remoteStorageBuffer + removeAllDebugMarkers +*/ +@(objc_class="MTLBuffer") +Buffer :: struct { using _: NS.Object } + +@(objc_type=Buffer, objc_name="addDebugMarker") +Buffer_addDebugMarker :: proc(self: ^Buffer, marker: ^NS.String, range: NS.Range) { + msgSend(nil, self, "addDebugMarker:range:", marker, range) +} +@(objc_type=Buffer, objc_name="contents") +Buffer_contents :: proc(self: ^Buffer) -> rawptr { + return msgSend(rawptr, self, "contents") +} +@(objc_type=Buffer, objc_name="didModifyRange") +Buffer_didModifyRange :: proc(self: ^Buffer, range: NS.Range) { + msgSend(nil, self, "didModifyRange:", range) +} +@(objc_type=Buffer, objc_name="length") +Buffer_length :: proc(self: ^Buffer) -> NS.Integer { + return msgSend(NS.Integer, self, "length") +} +@(objc_type=Buffer, objc_name="newRemoteBufferViewForDevice") +Buffer_newRemoteBufferViewForDevice :: proc(self: ^Buffer, device: ^NS.Object) -> ^Buffer { + return msgSend(^Buffer, self, "newRemoteBufferViewForDevice:", device) +} +@(objc_type=Buffer, objc_name="newTextureWithDescriptor") +Buffer_newTextureWithDescriptor :: proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: ^NS.Object, bytesPerRow: ^NS.Object) -> ^Buffer { + return msgSend(^Buffer, self, "newTextureWithDescriptor:offset:bytesPerRow:", descriptor, offset, bytesPerRow) +} +@(objc_type=Buffer, objc_name="remoteStorageBuffer") +Buffer_remoteStorageBuffer :: proc(self: ^Buffer) -> ^Buffer { + return msgSend(^Buffer, self, "remoteStorageBuffer") +} +@(objc_type=Buffer, objc_name="removeAllDebugMarkers") +Buffer_removeAllDebugMarkers :: proc(self: ^Buffer) { + msgSend(nil, self, "removeAllDebugMarkers") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CaptureScope +Class Methods: +Methods: + beginScope + commandQueue + device + endScope + label + setLabel +*/ +@(objc_class="MTLCaptureScope") +CaptureScope :: struct { using _: NS.Object } + +@(objc_type=CaptureScope, objc_name="beginScope") +CaptureScope_beginScope :: proc(self: ^CaptureScope) { + msgSend(nil, self, "beginScope") +} +@(objc_type=CaptureScope, objc_name="commandQueue") +CaptureScope_commandQueue :: proc(self: ^CaptureScope) -> ^CaptureScope { + return msgSend(^CaptureScope, self, "commandQueue") +} +@(objc_type=CaptureScope, objc_name="device") +CaptureScope_device :: proc(self: ^CaptureScope) -> ^CaptureScope { + return msgSend(^CaptureScope, self, "device") +} +@(objc_type=CaptureScope, objc_name="endScope") +CaptureScope_endScope :: proc(self: ^CaptureScope) { + msgSend(nil, self, "endScope") +} +@(objc_type=CaptureScope, objc_name="label") +CaptureScope_label :: proc(self: ^CaptureScope) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=CaptureScope, objc_name="setLabel") +CaptureScope_setLabel :: proc(self: ^CaptureScope, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CommandBuffer +Class Methods: +Methods: + GPUEndTime + GPUStartTime + accelerationStructureCommandEncoder + addCompletedHandler + addScheduledHandler + blitCommandEncoder + blitCommandEncoderWithDescriptor + commandQueue + commit + computeCommandEncoder + computeCommandEncoderWithDescriptor + computeCommandEncoderWithDispatchType + device + encodeSignalEvent + encodeWaitForEvent + enqueue + error + errorOptions + kernelEndTime + kernelStartTime + label + logs + parallelRenderCommandEncoderWithDescriptor + popDebugGroup + presentDrawable + presentDrawable + presentDrawable + pushDebugGroup + renderCommandEncoderWithDescriptor + resourceStateCommandEncoder + resourceStateCommandEncoderWithDescriptor + retainedReferences + setLabel + status + waitUntilCompleted + waitUntilScheduled +*/ +@(objc_class="MTLCommandBuffer") +CommandBuffer :: struct { using _: NS.Object } + +@(objc_type=CommandBuffer, objc_name="GPUEndTime") +CommandBuffer_GPUEndTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { + return msgSend(CFTimeInterval, self, "GPUEndTime") +} +@(objc_type=CommandBuffer, objc_name="GPUStartTime") +CommandBuffer_GPUStartTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { + return msgSend(CFTimeInterval, self, "GPUStartTime") +} +@(objc_type=CommandBuffer, objc_name="accelerationStructureCommandEncoder") +CommandBuffer_accelerationStructureCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "accelerationStructureCommandEncoder") +} +@(objc_type=CommandBuffer, objc_name="addCompletedHandler") +CommandBuffer_addCompletedHandler :: proc(self: ^CommandBuffer, block: CommandBufferHandler) { + msgSend(nil, self, "addCompletedHandler:", block) +} +@(objc_type=CommandBuffer, objc_name="addScheduledHandler") +CommandBuffer_addScheduledHandler :: proc(self: ^CommandBuffer, block: CommandBufferHandler) { + msgSend(nil, self, "addScheduledHandler:", block) +} +@(objc_type=CommandBuffer, objc_name="blitCommandEncoder") +CommandBuffer_blitCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "blitCommandEncoder") +} +@(objc_type=CommandBuffer, objc_name="blitCommandEncoderWithDescriptor") +CommandBuffer_blitCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, blitPassDescriptor: ^BlitPassDescriptor) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "blitCommandEncoderWithDescriptor:", blitPassDescriptor) +} +@(objc_type=CommandBuffer, objc_name="commandQueue") +CommandBuffer_commandQueue :: proc(self: ^CommandBuffer) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "commandQueue") +} +@(objc_type=CommandBuffer, objc_name="commit") +CommandBuffer_commit :: proc(self: ^CommandBuffer) { + msgSend(nil, self, "commit") +} +@(objc_type=CommandBuffer, objc_name="computeCommandEncoder") +CommandBuffer_computeCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "computeCommandEncoder") +} +@(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDescriptor") +CommandBuffer_computeCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, computePassDescriptor: ^ComputePassDescriptor) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "computeCommandEncoderWithDescriptor:", computePassDescriptor) +} +@(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDispatchType") +CommandBuffer_computeCommandEncoderWithDispatchType :: proc(self: ^CommandBuffer, dispatchType: DispatchType) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "computeCommandEncoderWithDispatchType:", dispatchType) +} +@(objc_type=CommandBuffer, objc_name="device") +CommandBuffer_device :: proc(self: ^CommandBuffer) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "device") +} +@(objc_type=CommandBuffer, objc_name="encodeSignalEvent") +CommandBuffer_encodeSignalEvent :: proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { + msgSend(nil, self, "encodeSignalEvent:value:", event, value) +} +@(objc_type=CommandBuffer, objc_name="encodeWaitForEvent") +CommandBuffer_encodeWaitForEvent :: proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { + msgSend(nil, self, "encodeWaitForEvent:value:", event, value) +} +@(objc_type=CommandBuffer, objc_name="enqueue") +CommandBuffer_enqueue :: proc(self: ^CommandBuffer) { + msgSend(nil, self, "enqueue") +} +@(objc_type=CommandBuffer, objc_name="error") +CommandBuffer_error :: proc(self: ^CommandBuffer) -> ^NS.Error { + return msgSend(^NS.Error, self, "error") +} +@(objc_type=CommandBuffer, objc_name="errorOptions") +CommandBuffer_errorOptions :: proc(self: ^CommandBuffer) -> CommandBufferErrorOption { + return msgSend(CommandBufferErrorOption, self, "errorOptions") +} +@(objc_type=CommandBuffer, objc_name="kernelEndTime") +CommandBuffer_kernelEndTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { + return msgSend(CFTimeInterval, self, "kernelEndTime") +} +@(objc_type=CommandBuffer, objc_name="kernelStartTime") +CommandBuffer_kernelStartTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { + return msgSend(CFTimeInterval, self, "kernelStartTime") +} +@(objc_type=CommandBuffer, objc_name="label") +CommandBuffer_label :: proc(self: ^CommandBuffer) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=CommandBuffer, objc_name="logs") +CommandBuffer_logs :: proc(self: ^CommandBuffer) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "logs") +} +@(objc_type=CommandBuffer, objc_name="parallelRenderCommandEncoderWithDescriptor") +CommandBuffer_parallelRenderCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "parallelRenderCommandEncoderWithDescriptor:", renderPassDescriptor) +} +@(objc_type=CommandBuffer, objc_name="popDebugGroup") +CommandBuffer_popDebugGroup :: proc(self: ^CommandBuffer) { + msgSend(nil, self, "popDebugGroup") +} +@(objc_type=CommandBuffer, objc_name="presentDrawable") +CommandBuffer_presentDrawable :: proc(self: ^CommandBuffer, drawable: ^NS.Object) { + msgSend(nil, self, "presentDrawable:", drawable) +} +@(objc_type=CommandBuffer, objc_name="presentDrawable_afterMinimumDuration_") +CommandBuffer_presentDrawable_afterMinimumDuration_ :: proc(self: ^CommandBuffer, drawable: ^NS.Object, duration: CFTimeInterval) { + msgSend(nil, self, "presentDrawable:afterMinimumDuration:", drawable, duration) +} +@(objc_type=CommandBuffer, objc_name="presentDrawable_atTime_") +CommandBuffer_presentDrawable_atTime_ :: proc(self: ^CommandBuffer, drawable: ^NS.Object, presentationTime: CFTimeInterval) { + msgSend(nil, self, "presentDrawable:atTime:", drawable, presentationTime) +} +@(objc_type=CommandBuffer, objc_name="pushDebugGroup") +CommandBuffer_pushDebugGroup :: proc(self: ^CommandBuffer, string: ^NS.String) { + msgSend(nil, self, "pushDebugGroup:", string) +} +@(objc_type=CommandBuffer, objc_name="renderCommandEncoderWithDescriptor") +CommandBuffer_renderCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "renderCommandEncoderWithDescriptor:", renderPassDescriptor) +} +@(objc_type=CommandBuffer, objc_name="resourceStateCommandEncoder") +CommandBuffer_resourceStateCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "resourceStateCommandEncoder") +} +@(objc_type=CommandBuffer, objc_name="resourceStateCommandEncoderWithDescriptor") +CommandBuffer_resourceStateCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, resourceStatePassDescriptor: ^ResourceStatePassDescriptor) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "resourceStateCommandEncoderWithDescriptor:", resourceStatePassDescriptor) +} +@(objc_type=CommandBuffer, objc_name="retainedReferences") +CommandBuffer_retainedReferences :: proc(self: ^CommandBuffer) -> BOOL { + return msgSend(BOOL, self, "retainedReferences") +} +@(objc_type=CommandBuffer, objc_name="setLabel") +CommandBuffer_setLabel :: proc(self: ^CommandBuffer, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=CommandBuffer, objc_name="status") +CommandBuffer_status :: proc(self: ^CommandBuffer) -> CommandBufferStatus { + return msgSend(CommandBufferStatus, self, "status") +} +@(objc_type=CommandBuffer, objc_name="waitUntilCompleted") +CommandBuffer_waitUntilCompleted :: proc(self: ^CommandBuffer) { + msgSend(nil, self, "waitUntilCompleted") +} +@(objc_type=CommandBuffer, objc_name="waitUntilScheduled") +CommandBuffer_waitUntilScheduled :: proc(self: ^CommandBuffer) { + msgSend(nil, self, "waitUntilScheduled") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CommandBufferEncoderInfo +Class Methods: +Methods: + debugSignposts + errorState + label +*/ +@(objc_class="MTLCommandBufferEncoderInfo") +CommandBufferEncoderInfo :: struct { using _: NS.Object } + +@(objc_type=CommandBufferEncoderInfo, objc_name="debugSignposts") +CommandBufferEncoderInfo_debugSignposts :: proc(self: ^CommandBufferEncoderInfo) -> ^NS.Array { + return msgSend(^NS.Array, self, "debugSignposts") +} +@(objc_type=CommandBufferEncoderInfo, objc_name="errorState") +CommandBufferEncoderInfo_errorState :: proc(self: ^CommandBufferEncoderInfo) -> CommandEncoderErrorState { + return msgSend(CommandEncoderErrorState, self, "errorState") +} +@(objc_type=CommandBufferEncoderInfo, objc_name="label") +CommandBufferEncoderInfo_label :: proc(self: ^CommandBufferEncoderInfo) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CommandEncoder +Class Methods: +Methods: + device + endEncoding + insertDebugSignpost + label + popDebugGroup + pushDebugGroup + setLabel +*/ +@(objc_class="MTLCommandEncoder") +CommandEncoder :: struct { using _: NS.Object } + +@(objc_type=CommandEncoder, objc_name="device") +CommandEncoder_device :: proc(self: ^CommandEncoder) -> ^CommandEncoder { + return msgSend(^CommandEncoder, self, "device") +} +@(objc_type=CommandEncoder, objc_name="endEncoding") +CommandEncoder_endEncoding :: proc(self: ^CommandEncoder) { + msgSend(nil, self, "endEncoding") +} +@(objc_type=CommandEncoder, objc_name="insertDebugSignpost") +CommandEncoder_insertDebugSignpost :: proc(self: ^CommandEncoder, string: ^NS.String) { + msgSend(nil, self, "insertDebugSignpost:", string) +} +@(objc_type=CommandEncoder, objc_name="label") +CommandEncoder_label :: proc(self: ^CommandEncoder) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=CommandEncoder, objc_name="popDebugGroup") +CommandEncoder_popDebugGroup :: proc(self: ^CommandEncoder) { + msgSend(nil, self, "popDebugGroup") +} +@(objc_type=CommandEncoder, objc_name="pushDebugGroup") +CommandEncoder_pushDebugGroup :: proc(self: ^CommandEncoder, string: ^NS.String) { + msgSend(nil, self, "pushDebugGroup:", string) +} +@(objc_type=CommandEncoder, objc_name="setLabel") +CommandEncoder_setLabel :: proc(self: ^CommandEncoder, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CommandQueue +Class Methods: +Methods: + commandBuffer + commandBufferWithDescriptor + commandBufferWithUnretainedReferences + device + insertDebugCaptureBoundary + label + setLabel +*/ +@(objc_class="MTLCommandQueue") +CommandQueue :: struct { using _: NS.Object } + +@(objc_type=CommandQueue, objc_name="commandBuffer") +CommandQueue_commandBuffer :: proc(self: ^CommandQueue) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "commandBuffer") +} +@(objc_type=CommandQueue, objc_name="commandBufferWithDescriptor") +CommandQueue_commandBufferWithDescriptor :: proc(self: ^CommandQueue, descriptor: ^CommandBufferDescriptor) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "commandBufferWithDescriptor:", descriptor) +} +@(objc_type=CommandQueue, objc_name="commandBufferWithUnretainedReferences") +CommandQueue_commandBufferWithUnretainedReferences :: proc(self: ^CommandQueue) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "commandBufferWithUnretainedReferences") +} +@(objc_type=CommandQueue, objc_name="device") +CommandQueue_device :: proc(self: ^CommandQueue) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "device") +} +@(objc_type=CommandQueue, objc_name="insertDebugCaptureBoundary") +CommandQueue_insertDebugCaptureBoundary :: proc(self: ^CommandQueue) { + msgSend(nil, self, "insertDebugCaptureBoundary") +} +@(objc_type=CommandQueue, objc_name="label") +CommandQueue_label :: proc(self: ^CommandQueue) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=CommandQueue, objc_name="setLabel") +CommandQueue_setLabel :: proc(self: ^CommandQueue, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ComputeCommandEncoder +Class Methods: +Methods: + dispatchThreadgroups + dispatchThreadgroupsWithIndirectBuffer + dispatchThreads + dispatchType + executeCommandsInBuffer + executeCommandsInBuffer + memoryBarrierWithResources + memoryBarrierWithScope + sampleCountersInBuffer + setAccelerationStructure + setBuffer + setBufferOffset + setBuffers + setBytes + setComputePipelineState + setImageblockWidth + setIntersectionFunctionTable + setIntersectionFunctionTables + setSamplerState + setSamplerState + setSamplerStates + setSamplerStates + setStageInRegion + setStageInRegionWithIndirectBuffer + setTexture + setTextures + setThreadgroupMemoryLength + setVisibleFunctionTable + setVisibleFunctionTables + updateFence + useHeap + useHeaps + useResource + useResources + waitForFence +*/ +@(objc_class="MTLComputeCommandEncoder") +ComputeCommandEncoder :: struct { using _: NS.Object } + +@(objc_type=ComputeCommandEncoder, objc_name="dispatchThreadgroups") +ComputeCommandEncoder_dispatchThreadgroups :: proc(self: ^ComputeCommandEncoder, threadgroupsPerGrid: Size, threadsPerThreadgroup: Size) { + msgSend(nil, self, "dispatchThreadgroups:threadsPerThreadgroup:", threadgroupsPerGrid, threadsPerThreadgroup) +} +@(objc_type=ComputeCommandEncoder, objc_name="dispatchThreadgroupsWithIndirectBuffer") +ComputeCommandEncoder_dispatchThreadgroupsWithIndirectBuffer :: proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object, threadsPerThreadgroup: Size) { + msgSend(nil, self, "dispatchThreadgroupsWithIndirectBuffer:indirectBufferOffset:threadsPerThreadgroup:", indirectBuffer, indirectBufferOffset, threadsPerThreadgroup) +} +@(objc_type=ComputeCommandEncoder, objc_name="dispatchThreads") +ComputeCommandEncoder_dispatchThreads :: proc(self: ^ComputeCommandEncoder, threadsPerGrid: Size, threadsPerThreadgroup: Size) { + msgSend(nil, self, "dispatchThreads:threadsPerThreadgroup:", threadsPerGrid, threadsPerThreadgroup) +} +@(objc_type=ComputeCommandEncoder, objc_name="dispatchType") +ComputeCommandEncoder_dispatchType :: proc(self: ^ComputeCommandEncoder) -> DispatchType { + return msgSend(DispatchType, self, "dispatchType") +} +@(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_") +ComputeCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: proc(self: ^ComputeCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "executeCommandsInBuffer:indirectBuffer:indirectBufferOffset:", indirectCommandbuffer, indirectRangeBuffer, indirectBufferOffset) +} +@(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBuffer_withRange_") +ComputeCommandEncoder_executeCommandsInBuffer_withRange_ :: proc(self: ^ComputeCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { + msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) +} +@(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithResources") +ComputeCommandEncoder_memoryBarrierWithResources :: proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object) { + msgSend(nil, self, "memoryBarrierWithResources:count:", resources, count) +} +@(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithScope") +ComputeCommandEncoder_memoryBarrierWithScope :: proc(self: ^ComputeCommandEncoder, scope: BarrierScope) { + msgSend(nil, self, "memoryBarrierWithScope:", scope) +} +@(objc_type=ComputeCommandEncoder, objc_name="sampleCountersInBuffer") +ComputeCommandEncoder_sampleCountersInBuffer :: proc(self: ^ComputeCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { + msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) +} +@(objc_type=ComputeCommandEncoder, objc_name="setAccelerationStructure") +ComputeCommandEncoder_setAccelerationStructure :: proc(self: ^ComputeCommandEncoder, accelerationStructure: ^NS.Object, bufferIndex: ^NS.Object) { + msgSend(nil, self, "setAccelerationStructure:atBufferIndex:", accelerationStructure, bufferIndex) +} +@(objc_type=ComputeCommandEncoder, objc_name="setBuffer") +ComputeCommandEncoder_setBuffer :: proc(self: ^ComputeCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=ComputeCommandEncoder, objc_name="setBufferOffset") +ComputeCommandEncoder_setBufferOffset :: proc(self: ^ComputeCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setBufferOffset:atIndex:", offset, index) +} +@(objc_type=ComputeCommandEncoder, objc_name="setBuffers") +ComputeCommandEncoder_setBuffers :: proc(self: ^ComputeCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { + msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) +} +@(objc_type=ComputeCommandEncoder, objc_name="setBytes") +ComputeCommandEncoder_setBytes :: proc(self: ^ComputeCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setBytes:length:atIndex:", bytes, length, index) +} +@(objc_type=ComputeCommandEncoder, objc_name="setComputePipelineState") +ComputeCommandEncoder_setComputePipelineState :: proc(self: ^ComputeCommandEncoder, pipelineState: ^NS.Object) { + msgSend(nil, self, "setComputePipelineState:", pipelineState) +} +@(objc_type=ComputeCommandEncoder, objc_name="setImageblockWidth") +ComputeCommandEncoder_setImageblockWidth :: proc(self: ^ComputeCommandEncoder, width: ^NS.Object, height: ^NS.Object) { + msgSend(nil, self, "setImageblockWidth:height:", width, height) +} +@(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTable") +ComputeCommandEncoder_setIntersectionFunctionTable :: proc(self: ^ComputeCommandEncoder, intersectionFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { + msgSend(nil, self, "setIntersectionFunctionTable:atBufferIndex:", intersectionFunctionTable, bufferIndex) +} +@(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTables") +ComputeCommandEncoder_setIntersectionFunctionTables :: proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setIntersectionFunctionTables:withBufferRange:", intersectionFunctionTables, range) +} +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_atIndex_") +ComputeCommandEncoder_setSamplerState_atIndex_ :: proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) +} +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_lodMinClamp_lodMaxClamp_atIndex_") +ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { + msgSend(nil, self, "setSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) +} +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_lodMinClamps_lodMaxClamps_withRange_") +ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { + msgSend(nil, self, "setSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +} +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_withRange_") +ComputeCommandEncoder_setSamplerStates_withRange_ :: proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) +} +@(objc_type=ComputeCommandEncoder, objc_name="setStageInRegion") +ComputeCommandEncoder_setStageInRegion :: proc(self: ^ComputeCommandEncoder, region: Region) { + msgSend(nil, self, "setStageInRegion:", region) +} +@(objc_type=ComputeCommandEncoder, objc_name="setStageInRegionWithIndirectBuffer") +ComputeCommandEncoder_setStageInRegionWithIndirectBuffer :: proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "setStageInRegionWithIndirectBuffer:indirectBufferOffset:", indirectBuffer, indirectBufferOffset) +} +@(objc_type=ComputeCommandEncoder, objc_name="setTexture") +ComputeCommandEncoder_setTexture :: proc(self: ^ComputeCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setTexture:atIndex:", texture, index) +} +@(objc_type=ComputeCommandEncoder, objc_name="setTextures") +ComputeCommandEncoder_setTextures :: proc(self: ^ComputeCommandEncoder, textures: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setTextures:withRange:", textures, range) +} +@(objc_type=ComputeCommandEncoder, objc_name="setThreadgroupMemoryLength") +ComputeCommandEncoder_setThreadgroupMemoryLength :: proc(self: ^ComputeCommandEncoder, length: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setThreadgroupMemoryLength:atIndex:", length, index) +} +@(objc_type=ComputeCommandEncoder, objc_name="setVisibleFunctionTable") +ComputeCommandEncoder_setVisibleFunctionTable :: proc(self: ^ComputeCommandEncoder, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { + msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) +} +@(objc_type=ComputeCommandEncoder, objc_name="setVisibleFunctionTables") +ComputeCommandEncoder_setVisibleFunctionTables :: proc(self: ^ComputeCommandEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) +} +@(objc_type=ComputeCommandEncoder, objc_name="updateFence") +ComputeCommandEncoder_updateFence :: proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "updateFence:", fence) +} +@(objc_type=ComputeCommandEncoder, objc_name="useHeap") +ComputeCommandEncoder_useHeap :: proc(self: ^ComputeCommandEncoder, heap: ^NS.Object) { + msgSend(nil, self, "useHeap:", heap) +} +@(objc_type=ComputeCommandEncoder, objc_name="useHeaps") +ComputeCommandEncoder_useHeaps :: proc(self: ^ComputeCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { + msgSend(nil, self, "useHeaps:count:", heaps, count) +} +@(objc_type=ComputeCommandEncoder, objc_name="useResource") +ComputeCommandEncoder_useResource :: proc(self: ^ComputeCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { + msgSend(nil, self, "useResource:usage:", resource, usage) +} +@(objc_type=ComputeCommandEncoder, objc_name="useResources") +ComputeCommandEncoder_useResources :: proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { + msgSend(nil, self, "useResources:count:usage:", resources, count, usage) +} +@(objc_type=ComputeCommandEncoder, objc_name="waitForFence") +ComputeCommandEncoder_waitForFence :: proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "waitForFence:", fence) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ComputePipelineState +Class Methods: +Methods: + device + functionHandleWithFunction + imageblockMemoryLengthForDimensions + label + maxTotalThreadsPerThreadgroup + newComputePipelineStateWithAdditionalBinaryFunctions + newIntersectionFunctionTableWithDescriptor + newVisibleFunctionTableWithDescriptor + staticThreadgroupMemoryLength + supportIndirectCommandBuffers + threadExecutionWidth +*/ +@(objc_class="MTLComputePipelineState") +ComputePipelineState :: struct { using _: NS.Object } + +@(objc_type=ComputePipelineState, objc_name="device") +ComputePipelineState_device :: proc(self: ^ComputePipelineState) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "device") +} +@(objc_type=ComputePipelineState, objc_name="functionHandleWithFunction") +ComputePipelineState_functionHandleWithFunction :: proc(self: ^ComputePipelineState, function: ^NS.Object) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "functionHandleWithFunction:", function) +} +@(objc_type=ComputePipelineState, objc_name="imageblockMemoryLengthForDimensions") +ComputePipelineState_imageblockMemoryLengthForDimensions :: proc(self: ^ComputePipelineState, imageblockDimensions: Size) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "imageblockMemoryLengthForDimensions:", imageblockDimensions) +} +@(objc_type=ComputePipelineState, objc_name="label") +ComputePipelineState_label :: proc(self: ^ComputePipelineState) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=ComputePipelineState, objc_name="maxTotalThreadsPerThreadgroup") +ComputePipelineState_maxTotalThreadsPerThreadgroup :: proc(self: ^ComputePipelineState) -> NS.Integer { + return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +} +@(objc_type=ComputePipelineState, objc_name="newComputePipelineStateWithAdditionalBinaryFunctions") +ComputePipelineState_newComputePipelineStateWithAdditionalBinaryFunctions :: proc(self: ^ComputePipelineState, functions: ^NS.Array, error: ^^NS.Error ) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "newComputePipelineStateWithAdditionalBinaryFunctions:error:", functions, error) +} +@(objc_type=ComputePipelineState, objc_name="newIntersectionFunctionTableWithDescriptor") +ComputePipelineState_newIntersectionFunctionTableWithDescriptor :: proc(self: ^ComputePipelineState, descriptor: ^IntersectionFunctionTableDescriptor) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "newIntersectionFunctionTableWithDescriptor:", descriptor) +} +@(objc_type=ComputePipelineState, objc_name="newVisibleFunctionTableWithDescriptor") +ComputePipelineState_newVisibleFunctionTableWithDescriptor :: proc(self: ^ComputePipelineState, descriptor: ^VisibleFunctionTableDescriptor) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "newVisibleFunctionTableWithDescriptor:", descriptor) +} +@(objc_type=ComputePipelineState, objc_name="staticThreadgroupMemoryLength") +ComputePipelineState_staticThreadgroupMemoryLength :: proc(self: ^ComputePipelineState) -> NS.Integer { + return msgSend(NS.Integer, self, "staticThreadgroupMemoryLength") +} +@(objc_type=ComputePipelineState, objc_name="supportIndirectCommandBuffers") +ComputePipelineState_supportIndirectCommandBuffers :: proc(self: ^ComputePipelineState) -> BOOL { + return msgSend(BOOL, self, "supportIndirectCommandBuffers") +} +@(objc_type=ComputePipelineState, objc_name="threadExecutionWidth") +ComputePipelineState_threadExecutionWidth :: proc(self: ^ComputePipelineState) -> NS.Integer { + return msgSend(NS.Integer, self, "threadExecutionWidth") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Counter +Class Methods: +Methods: + name +*/ +@(objc_class="MTLCounter") +Counter :: struct { using _: NS.Object } + +@(objc_type=Counter, objc_name="name") +Counter_name :: proc(self: ^Counter) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CounterSampleBuffer +Class Methods: +Methods: + device + label + resolveCounterRange + sampleCount +*/ +@(objc_class="MTLCounterSampleBuffer") +CounterSampleBuffer :: struct { using _: NS.Object } + +@(objc_type=CounterSampleBuffer, objc_name="device") +CounterSampleBuffer_device :: proc(self: ^CounterSampleBuffer) -> ^CounterSampleBuffer { + return msgSend(^CounterSampleBuffer, self, "device") +} +@(objc_type=CounterSampleBuffer, objc_name="label") +CounterSampleBuffer_label :: proc(self: ^CounterSampleBuffer) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=CounterSampleBuffer, objc_name="resolveCounterRange") +CounterSampleBuffer_resolveCounterRange :: proc(self: ^CounterSampleBuffer, range: NS.Range) -> ^NS.Data { + return msgSend(^NS.Data, self, "resolveCounterRange:", range) +} +@(objc_type=CounterSampleBuffer, objc_name="sampleCount") +CounterSampleBuffer_sampleCount :: proc(self: ^CounterSampleBuffer) -> NS.Integer { + return msgSend(NS.Integer, self, "sampleCount") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + CounterSet +Class Methods: +Methods: + counters + name +*/ +@(objc_class="MTLCounterSet") +CounterSet :: struct { using _: NS.Object } + +@(objc_type=CounterSet, objc_name="counters") +CounterSet_counters :: proc(self: ^CounterSet) -> ^NS.Array { + return msgSend(^NS.Array, self, "counters") +} +@(objc_type=CounterSet, objc_name="name") +CounterSet_name :: proc(self: ^CounterSet) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + DepthStencilState +Class Methods: +Methods: + device + label +*/ +@(objc_class="MTLDepthStencilState") +DepthStencilState :: struct { using _: NS.Object } + +@(objc_type=DepthStencilState, objc_name="device") +DepthStencilState_device :: proc(self: ^DepthStencilState) -> ^DepthStencilState { + return msgSend(^DepthStencilState, self, "device") +} +@(objc_type=DepthStencilState, objc_name="label") +DepthStencilState_label :: proc(self: ^DepthStencilState) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Device +Class Methods: +Methods: + accelerationStructureSizesWithDescriptor + areBarycentricCoordsSupported + areProgrammableSamplePositionsSupported + areRasterOrderGroupsSupported + argumentBuffersSupport + convertSparsePixelRegions + convertSparseTileRegions + counterSets + currentAllocatedSize + getDefaultSamplePositions + hasUnifiedMemory + heapBufferSizeAndAlignWithLength + heapTextureSizeAndAlignWithDescriptor + isDepth24Stencil8PixelFormatSupported + isHeadless + isLowPower + isRemovable + location + locationNumber + maxArgumentBufferSamplerCount + maxBufferLength + maxThreadgroupMemoryLength + maxThreadsPerThreadgroup + maxTransferRate + minimumLinearTextureAlignmentForPixelFormat + minimumTextureBufferAlignmentForPixelFormat + name + newAccelerationStructureWithDescriptor + newAccelerationStructureWithSize + newArgumentEncoderWithArguments + newBinaryArchiveWithDescriptor + newBufferWithBytes + newBufferWithBytesNoCopy + newBufferWithLength + newCommandQueue + newCommandQueueWithMaxCommandBufferCount + newComputePipelineStateWithDescriptor + newComputePipelineStateWithDescriptor + newComputePipelineStateWithFunction + newComputePipelineStateWithFunction + newComputePipelineStateWithFunction + newComputePipelineStateWithFunction + newCounterSampleBufferWithDescriptor + newDefaultLibrary + newDefaultLibraryWithBundle + newDepthStencilStateWithDescriptor + newDynamicLibrary + newDynamicLibraryWithURL + newEvent + newFence + newHeapWithDescriptor + newIndirectCommandBufferWithDescriptor + newLibraryWithData + newLibraryWithFile + newLibraryWithSource + newLibraryWithSource + newLibraryWithURL + newRasterizationRateMapWithDescriptor + newRenderPipelineStateWithDescriptor + newRenderPipelineStateWithDescriptor + newRenderPipelineStateWithDescriptor + newRenderPipelineStateWithDescriptor + newRenderPipelineStateWithTileDescriptor + newRenderPipelineStateWithTileDescriptor + newSamplerStateWithDescriptor + newSharedEvent + newSharedEventWithHandle + newSharedTextureWithDescriptor + newSharedTextureWithHandle + newTextureWithDescriptor + newTextureWithDescriptor + peerCount + peerGroupID + peerIndex + readWriteTextureSupport + recommendedMaxWorkingSetSize + registryID + sampleTimestamps + sparseTileSizeInBytes + sparseTileSizeWithTextureType + supports32BitFloatFiltering + supports32BitMSAA + supportsBCTextureCompression + supportsCounterSampling + supportsDynamicLibraries + supportsFamily + supportsFeatureSet + supportsFunctionPointers + supportsPullModelInterpolation + supportsQueryTextureLOD + supportsRasterizationRateMapWithLayerCount + supportsRaytracing + supportsShaderBarycentricCoordinates + supportsTextureSampleCount + supportsVertexAmplificationCount +*/ +@(objc_class="MTLDevice") +Device :: struct { using _: NS.Object } + +@(objc_type=Device, objc_name="accelerationStructureSizesWithDescriptor") +Device_accelerationStructureSizesWithDescriptor :: proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> AccelerationStructureSizes { + return msgSend(AccelerationStructureSizes, self, "accelerationStructureSizesWithDescriptor:", descriptor) +} +@(objc_type=Device, objc_name="areBarycentricCoordsSupported") +Device_areBarycentricCoordsSupported :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "areBarycentricCoordsSupported") +} +@(objc_type=Device, objc_name="areProgrammableSamplePositionsSupported") +Device_areProgrammableSamplePositionsSupported :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "areProgrammableSamplePositionsSupported") +} +@(objc_type=Device, objc_name="areRasterOrderGroupsSupported") +Device_areRasterOrderGroupsSupported :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "areRasterOrderGroupsSupported") +} +@(objc_type=Device, objc_name="argumentBuffersSupport") +Device_argumentBuffersSupport :: proc(self: ^Device) -> ArgumentBuffersTier { + return msgSend(ArgumentBuffersTier, self, "argumentBuffersSupport") +} +@(objc_type=Device, objc_name="convertSparsePixelRegions") +Device_convertSparsePixelRegions :: proc(self: ^Device, pixelRegions: ^Region, tileRegions: ^Region, tileSize: Size, mode: SparseTextureRegionAlignmentMode, numRegions: ^NS.Object) { + msgSend(nil, self, "convertSparsePixelRegions:toTileRegions:withTileSize:alignmentMode:numRegions:", pixelRegions, tileRegions, tileSize, mode, numRegions) +} +@(objc_type=Device, objc_name="convertSparseTileRegions") +Device_convertSparseTileRegions :: proc(self: ^Device, tileRegions: ^Region, pixelRegions: ^Region, tileSize: Size, numRegions: ^NS.Object) { + msgSend(nil, self, "convertSparseTileRegions:toPixelRegions:withTileSize:numRegions:", tileRegions, pixelRegions, tileSize, numRegions) +} +@(objc_type=Device, objc_name="counterSets") +Device_counterSets :: proc(self: ^Device) -> ^NS.Array { + return msgSend(^NS.Array, self, "counterSets") +} +@(objc_type=Device, objc_name="currentAllocatedSize") +Device_currentAllocatedSize :: proc(self: ^Device) -> NS.Integer { + return msgSend(NS.Integer, self, "currentAllocatedSize") +} +@(objc_type=Device, objc_name="getDefaultSamplePositions") +Device_getDefaultSamplePositions :: proc(self: ^Device, positions: ^SamplePosition, count: ^NS.Object) { + msgSend(nil, self, "getDefaultSamplePositions:count:", positions, count) +} +@(objc_type=Device, objc_name="hasUnifiedMemory") +Device_hasUnifiedMemory :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "hasUnifiedMemory") +} +@(objc_type=Device, objc_name="heapBufferSizeAndAlignWithLength") +Device_heapBufferSizeAndAlignWithLength :: proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> SizeAndAlign { + return msgSend(SizeAndAlign, self, "heapBufferSizeAndAlignWithLength:options:", length, options) +} +@(objc_type=Device, objc_name="heapTextureSizeAndAlignWithDescriptor") +Device_heapTextureSizeAndAlignWithDescriptor :: proc(self: ^Device, desc: ^TextureDescriptor) -> SizeAndAlign { + return msgSend(SizeAndAlign, self, "heapTextureSizeAndAlignWithDescriptor:", desc) +} +@(objc_type=Device, objc_name="isDepth24Stencil8PixelFormatSupported") +Device_isDepth24Stencil8PixelFormatSupported :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "isDepth24Stencil8PixelFormatSupported") +} +@(objc_type=Device, objc_name="isHeadless") +Device_isHeadless :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "isHeadless") +} +@(objc_type=Device, objc_name="isLowPower") +Device_isLowPower :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "isLowPower") +} +@(objc_type=Device, objc_name="isRemovable") +Device_isRemovable :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "isRemovable") +} +@(objc_type=Device, objc_name="location") +Device_location :: proc(self: ^Device) -> DeviceLocation { + return msgSend(DeviceLocation, self, "location") +} +@(objc_type=Device, objc_name="locationNumber") +Device_locationNumber :: proc(self: ^Device) -> NS.Integer { + return msgSend(NS.Integer, self, "locationNumber") +} +@(objc_type=Device, objc_name="maxArgumentBufferSamplerCount") +Device_maxArgumentBufferSamplerCount :: proc(self: ^Device) -> NS.Integer { + return msgSend(NS.Integer, self, "maxArgumentBufferSamplerCount") +} +@(objc_type=Device, objc_name="maxBufferLength") +Device_maxBufferLength :: proc(self: ^Device) -> NS.Integer { + return msgSend(NS.Integer, self, "maxBufferLength") +} +@(objc_type=Device, objc_name="maxThreadgroupMemoryLength") +Device_maxThreadgroupMemoryLength :: proc(self: ^Device) -> NS.Integer { + return msgSend(NS.Integer, self, "maxThreadgroupMemoryLength") +} +@(objc_type=Device, objc_name="maxThreadsPerThreadgroup") +Device_maxThreadsPerThreadgroup :: proc(self: ^Device) -> Size { + return msgSend(Size, self, "maxThreadsPerThreadgroup") +} +@(objc_type=Device, objc_name="maxTransferRate") +Device_maxTransferRate :: proc(self: ^Device) -> u64 { + return msgSend(u64, self, "maxTransferRate") +} +@(objc_type=Device, objc_name="minimumLinearTextureAlignmentForPixelFormat") +Device_minimumLinearTextureAlignmentForPixelFormat :: proc(self: ^Device, format: PixelFormat) -> ^Device { + return msgSend(^Device, self, "minimumLinearTextureAlignmentForPixelFormat:", format) +} +@(objc_type=Device, objc_name="minimumTextureBufferAlignmentForPixelFormat") +Device_minimumTextureBufferAlignmentForPixelFormat :: proc(self: ^Device, format: PixelFormat) -> ^Device { + return msgSend(^Device, self, "minimumTextureBufferAlignmentForPixelFormat:", format) +} +@(objc_type=Device, objc_name="name") +Device_name :: proc(self: ^Device) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} +@(objc_type=Device, objc_name="newAccelerationStructureWithDescriptor") +Device_newAccelerationStructureWithDescriptor :: proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> ^Device { + return msgSend(^Device, self, "newAccelerationStructureWithDescriptor:", descriptor) +} +@(objc_type=Device, objc_name="newAccelerationStructureWithSize") +Device_newAccelerationStructureWithSize :: proc(self: ^Device, size: ^NS.Object) -> ^Device { + return msgSend(^Device, self, "newAccelerationStructureWithSize:", size) +} +@(objc_type=Device, objc_name="newArgumentEncoderWithArguments") +Device_newArgumentEncoderWithArguments :: proc(self: ^Device, arguments: ^NS.Array) -> ^Device { + return msgSend(^Device, self, "newArgumentEncoderWithArguments:", arguments) +} +@(objc_type=Device, objc_name="newBinaryArchiveWithDescriptor") +Device_newBinaryArchiveWithDescriptor :: proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newBinaryArchiveWithDescriptor:error:", descriptor, error) +} +@(objc_type=Device, objc_name="newBufferWithBytes") +Device_newBufferWithBytes :: proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions) -> ^Device { + return msgSend(^Device, self, "newBufferWithBytes:length:options:", pointer, length, options) +} +@(objc_type=Device, objc_name="newBufferWithBytesNoCopy") +Device_newBufferWithBytesNoCopy :: proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions, deallocator: rawptr) -> ^Device { + return msgSend(^Device, self, "newBufferWithBytesNoCopy:length:options:deallocator:", pointer, length, options, deallocator) +} +@(objc_type=Device, objc_name="newBufferWithLength") +Device_newBufferWithLength :: proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> ^Device { + return msgSend(^Device, self, "newBufferWithLength:options:", length, options) +} +@(objc_type=Device, objc_name="newCommandQueue") +Device_newCommandQueue :: proc(self: ^Device) -> ^Device { + return msgSend(^Device, self, "newCommandQueue") +} +@(objc_type=Device, objc_name="newCommandQueueWithMaxCommandBufferCount") +Device_newCommandQueueWithMaxCommandBufferCount :: proc(self: ^Device, maxCommandBufferCount: ^NS.Object) -> ^Device { + return msgSend(^Device, self, "newCommandQueueWithMaxCommandBufferCount:", maxCommandBufferCount) +} +@(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_completionHandler_") +Device_newComputePipelineStateWithDescriptor_options_completionHandler_ :: proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { + msgSend(nil, self, "newComputePipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) +} +@(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_reflection_error_") +Device_newComputePipelineStateWithDescriptor_options_reflection_error_ :: proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newComputePipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, error) +} +@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_completionHandler_") +Device_newComputePipelineStateWithFunction_completionHandler_ :: proc(self: ^Device, computeFunction: ^NS.Object, completionHandler: NewComputePipelineStateCompletionHandler) { + msgSend(nil, self, "newComputePipelineStateWithFunction:completionHandler:", computeFunction, completionHandler) +} +@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_error_") +Device_newComputePipelineStateWithFunction_error_ :: proc(self: ^Device, computeFunction: ^NS.Object, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, error) +} +@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_completionHandler_") +Device_newComputePipelineStateWithFunction_options_completionHandler_ :: proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { + msgSend(nil, self, "newComputePipelineStateWithFunction:options:completionHandler:", computeFunction, options, completionHandler) +} +@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_reflection_error_") +Device_newComputePipelineStateWithFunction_options_reflection_error_ :: proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, error) +} +@(objc_type=Device, objc_name="newCounterSampleBufferWithDescriptor") +Device_newCounterSampleBufferWithDescriptor :: proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, error) +} +@(objc_type=Device, objc_name="newDefaultLibrary") +Device_newDefaultLibrary :: proc(self: ^Device) -> ^Device { + return msgSend(^Device, self, "newDefaultLibrary") +} +@(objc_type=Device, objc_name="newDefaultLibraryWithBundle") +Device_newDefaultLibraryWithBundle :: proc(self: ^Device, bundle: ^NS.Bundle, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newDefaultLibraryWithBundle:error:", bundle, error) +} +@(objc_type=Device, objc_name="newDepthStencilStateWithDescriptor") +Device_newDepthStencilStateWithDescriptor :: proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^Device { + return msgSend(^Device, self, "newDepthStencilStateWithDescriptor:", descriptor) +} +@(objc_type=Device, objc_name="newDynamicLibrary") +Device_newDynamicLibrary :: proc(self: ^Device, library: ^NS.Object, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newDynamicLibrary:error:", library, error) +} +@(objc_type=Device, objc_name="newDynamicLibraryWithURL") +Device_newDynamicLibraryWithURL :: proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newDynamicLibraryWithURL:error:", url, error) +} +@(objc_type=Device, objc_name="newEvent") +Device_newEvent :: proc(self: ^Device) -> ^Device { + return msgSend(^Device, self, "newEvent") +} +@(objc_type=Device, objc_name="newFence") +Device_newFence :: proc(self: ^Device) -> ^Device { + return msgSend(^Device, self, "newFence") +} +@(objc_type=Device, objc_name="newHeapWithDescriptor") +Device_newHeapWithDescriptor :: proc(self: ^Device, descriptor: ^HeapDescriptor) -> ^Device { + return msgSend(^Device, self, "newHeapWithDescriptor:", descriptor) +} +@(objc_type=Device, objc_name="newIndirectCommandBufferWithDescriptor") +Device_newIndirectCommandBufferWithDescriptor :: proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: ^NS.Object, options: ResourceOptions) -> ^Device { + return msgSend(^Device, self, "newIndirectCommandBufferWithDescriptor:maxCommandCount:options:", descriptor, maxCount, options) +} +@(objc_type=Device, objc_name="newLibraryWithData") +Device_newLibraryWithData :: proc(self: ^Device, data: ^NS.Object, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newLibraryWithData:error:", data, error) +} +@(objc_type=Device, objc_name="newLibraryWithFile") +Device_newLibraryWithFile :: proc(self: ^Device, filepath: ^NS.String, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newLibraryWithFile:error:", filepath, error) +} +@(objc_type=Device, objc_name="newLibraryWithSource_options_completionHandler_") +Device_newLibraryWithSource_options_completionHandler_ :: proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) { + msgSend(nil, self, "newLibraryWithSource:options:completionHandler:", source, options, completionHandler) +} +@(objc_type=Device, objc_name="newLibraryWithSource_options_error_") +Device_newLibraryWithSource_options_error_ :: proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newLibraryWithSource:options:error:", source, options, error) +} +@(objc_type=Device, objc_name="newLibraryWithURL") +Device_newLibraryWithURL :: proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newLibraryWithURL:error:", url, error) +} +@(objc_type=Device, objc_name="newRasterizationRateMapWithDescriptor") +Device_newRasterizationRateMapWithDescriptor :: proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^Device { + return msgSend(^Device, self, "newRasterizationRateMapWithDescriptor:", descriptor) +} +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_completionHandler_") +Device_newRenderPipelineStateWithDescriptor_completionHandler_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { + msgSend(nil, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) +} +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_error_") +Device_newRenderPipelineStateWithDescriptor_error_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, error) +} +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_completionHandler_") +Device_newRenderPipelineStateWithDescriptor_options_completionHandler_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { + msgSend(nil, self, "newRenderPipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) +} +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_reflection_error_") +Device_newRenderPipelineStateWithDescriptor_options_reflection_error_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, error) +} +@(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_completionHandler_") +Device_newRenderPipelineStateWithTileDescriptor_options_completionHandler_ :: proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { + msgSend(nil, self, "newRenderPipelineStateWithTileDescriptor:options:completionHandler:", descriptor, options, completionHandler) +} +@(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_reflection_error_") +Device_newRenderPipelineStateWithTileDescriptor_options_reflection_error_ :: proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { + return msgSend(^Device, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, error) +} +@(objc_type=Device, objc_name="newSamplerStateWithDescriptor") +Device_newSamplerStateWithDescriptor :: proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^Device { + return msgSend(^Device, self, "newSamplerStateWithDescriptor:", descriptor) +} +@(objc_type=Device, objc_name="newSharedEvent") +Device_newSharedEvent :: proc(self: ^Device) -> ^Device { + return msgSend(^Device, self, "newSharedEvent") +} +@(objc_type=Device, objc_name="newSharedEventWithHandle") +Device_newSharedEventWithHandle :: proc(self: ^Device, sharedEventHandle: ^SharedEventHandle) -> ^Device { + return msgSend(^Device, self, "newSharedEventWithHandle:", sharedEventHandle) +} +@(objc_type=Device, objc_name="newSharedTextureWithDescriptor") +Device_newSharedTextureWithDescriptor :: proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^Device { + return msgSend(^Device, self, "newSharedTextureWithDescriptor:", descriptor) +} +@(objc_type=Device, objc_name="newSharedTextureWithHandle") +Device_newSharedTextureWithHandle :: proc(self: ^Device, sharedHandle: ^SharedTextureHandle) -> ^Device { + return msgSend(^Device, self, "newSharedTextureWithHandle:", sharedHandle) +} +@(objc_type=Device, objc_name="newTextureWithDescriptor") +Device_newTextureWithDescriptor :: proc(self: ^Device, desc: ^TextureDescriptor) -> ^Device { + return msgSend(^Device, self, "newTextureWithDescriptor:", desc) +} +@(objc_type=Device, objc_name="newTextureWithDescriptor_iosurface_plane_") +Device_newTextureWithDescriptor_iosurface_plane_ :: proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: ^NS.Object) -> ^Device { + return msgSend(^Device, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) +} +@(objc_type=Device, objc_name="peerCount") +Device_peerCount :: proc(self: ^Device) -> u32 { + return msgSend(u32, self, "peerCount") +} +@(objc_type=Device, objc_name="peerGroupID") +Device_peerGroupID :: proc(self: ^Device) -> u64 { + return msgSend(u64, self, "peerGroupID") +} +@(objc_type=Device, objc_name="peerIndex") +Device_peerIndex :: proc(self: ^Device) -> u32 { + return msgSend(u32, self, "peerIndex") +} +@(objc_type=Device, objc_name="readWriteTextureSupport") +Device_readWriteTextureSupport :: proc(self: ^Device) -> ReadWriteTextureTier { + return msgSend(ReadWriteTextureTier, self, "readWriteTextureSupport") +} +@(objc_type=Device, objc_name="recommendedMaxWorkingSetSize") +Device_recommendedMaxWorkingSetSize :: proc(self: ^Device) -> u64 { + return msgSend(u64, self, "recommendedMaxWorkingSetSize") +} +@(objc_type=Device, objc_name="registryID") +Device_registryID :: proc(self: ^Device) -> u64 { + return msgSend(u64, self, "registryID") +} +@(objc_type=Device, objc_name="sampleTimestamps") +Device_sampleTimestamps :: proc(self: ^Device, cpuTimestamp: ^Timestamp, gpuTimestamp: ^Timestamp) { + msgSend(nil, self, "sampleTimestamps:gpuTimestamp:", cpuTimestamp, gpuTimestamp) +} +@(objc_type=Device, objc_name="sparseTileSizeInBytes") +Device_sparseTileSizeInBytes :: proc(self: ^Device) -> NS.Integer { + return msgSend(NS.Integer, self, "sparseTileSizeInBytes") +} +@(objc_type=Device, objc_name="sparseTileSizeWithTextureType") +Device_sparseTileSizeWithTextureType :: proc(self: ^Device, textureType: TextureType, pixelFormat: PixelFormat, sampleCount: ^NS.Object) -> Size { + return msgSend(Size, self, "sparseTileSizeWithTextureType:pixelFormat:sampleCount:", textureType, pixelFormat, sampleCount) +} +@(objc_type=Device, objc_name="supports32BitFloatFiltering") +Device_supports32BitFloatFiltering :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supports32BitFloatFiltering") +} +@(objc_type=Device, objc_name="supports32BitMSAA") +Device_supports32BitMSAA :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supports32BitMSAA") +} +@(objc_type=Device, objc_name="supportsBCTextureCompression") +Device_supportsBCTextureCompression :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supportsBCTextureCompression") +} +@(objc_type=Device, objc_name="supportsCounterSampling") +Device_supportsCounterSampling :: proc(self: ^Device, samplingPoint: CounterSamplingPoint) -> BOOL { + return msgSend(BOOL, self, "supportsCounterSampling:", samplingPoint) +} +@(objc_type=Device, objc_name="supportsDynamicLibraries") +Device_supportsDynamicLibraries :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supportsDynamicLibraries") +} +@(objc_type=Device, objc_name="supportsFamily") +Device_supportsFamily :: proc(self: ^Device, gpuFamily: GPUFamily) -> BOOL { + return msgSend(BOOL, self, "supportsFamily:", gpuFamily) +} +@(objc_type=Device, objc_name="supportsFeatureSet") +Device_supportsFeatureSet :: proc(self: ^Device, featureSet: FeatureSet) -> BOOL { + return msgSend(BOOL, self, "supportsFeatureSet:", featureSet) +} +@(objc_type=Device, objc_name="supportsFunctionPointers") +Device_supportsFunctionPointers :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supportsFunctionPointers") +} +@(objc_type=Device, objc_name="supportsPullModelInterpolation") +Device_supportsPullModelInterpolation :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supportsPullModelInterpolation") +} +@(objc_type=Device, objc_name="supportsQueryTextureLOD") +Device_supportsQueryTextureLOD :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supportsQueryTextureLOD") +} +@(objc_type=Device, objc_name="supportsRasterizationRateMapWithLayerCount") +Device_supportsRasterizationRateMapWithLayerCount :: proc(self: ^Device, layerCount: ^NS.Object) -> BOOL { + return msgSend(BOOL, self, "supportsRasterizationRateMapWithLayerCount:", layerCount) +} +@(objc_type=Device, objc_name="supportsRaytracing") +Device_supportsRaytracing :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supportsRaytracing") +} +@(objc_type=Device, objc_name="supportsShaderBarycentricCoordinates") +Device_supportsShaderBarycentricCoordinates :: proc(self: ^Device) -> BOOL { + return msgSend(BOOL, self, "supportsShaderBarycentricCoordinates") +} +@(objc_type=Device, objc_name="supportsTextureSampleCount") +Device_supportsTextureSampleCount :: proc(self: ^Device, sampleCount: ^NS.Object) -> BOOL { + return msgSend(BOOL, self, "supportsTextureSampleCount:", sampleCount) +} +@(objc_type=Device, objc_name="supportsVertexAmplificationCount") +Device_supportsVertexAmplificationCount :: proc(self: ^Device, count: ^NS.Object) -> BOOL { + return msgSend(BOOL, self, "supportsVertexAmplificationCount:", count) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Drawable +Class Methods: +Methods: + addPresentedHandler + drawableID + present + presentAfterMinimumDuration + presentAtTime + presentedTime +*/ +@(objc_class="MTLDrawable") +Drawable :: struct { using _: NS.Object } + +@(objc_type=Drawable, objc_name="addPresentedHandler") +Drawable_addPresentedHandler :: proc(self: ^Drawable, block: DrawablePresentedHandler) { + msgSend(nil, self, "addPresentedHandler:", block) +} +@(objc_type=Drawable, objc_name="drawableID") +Drawable_drawableID :: proc(self: ^Drawable) -> NS.Integer { + return msgSend(NS.Integer, self, "drawableID") +} +@(objc_type=Drawable, objc_name="present") +Drawable_present :: proc(self: ^Drawable) { + msgSend(nil, self, "present") +} +@(objc_type=Drawable, objc_name="presentAfterMinimumDuration") +Drawable_presentAfterMinimumDuration :: proc(self: ^Drawable, duration: CFTimeInterval) { + msgSend(nil, self, "presentAfterMinimumDuration:", duration) +} +@(objc_type=Drawable, objc_name="presentAtTime") +Drawable_presentAtTime :: proc(self: ^Drawable, presentationTime: CFTimeInterval) { + msgSend(nil, self, "presentAtTime:", presentationTime) +} +@(objc_type=Drawable, objc_name="presentedTime") +Drawable_presentedTime :: proc(self: ^Drawable) -> CFTimeInterval { + return msgSend(CFTimeInterval, self, "presentedTime") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + DynamicLibrary +Class Methods: +Methods: + device + installName + label + serializeToURL + setLabel +*/ +@(objc_class="MTLDynamicLibrary") +DynamicLibrary :: struct { using _: NS.Object } + +@(objc_type=DynamicLibrary, objc_name="device") +DynamicLibrary_device :: proc(self: ^DynamicLibrary) -> ^DynamicLibrary { + return msgSend(^DynamicLibrary, self, "device") +} +@(objc_type=DynamicLibrary, objc_name="installName") +DynamicLibrary_installName :: proc(self: ^DynamicLibrary) -> ^NS.String { + return msgSend(^NS.String, self, "installName") +} +@(objc_type=DynamicLibrary, objc_name="label") +DynamicLibrary_label :: proc(self: ^DynamicLibrary) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=DynamicLibrary, objc_name="serializeToURL") +DynamicLibrary_serializeToURL :: proc(self: ^DynamicLibrary, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { + return msgSend(BOOL, self, "serializeToURL:error:", url, error) +} +@(objc_type=DynamicLibrary, objc_name="setLabel") +DynamicLibrary_setLabel :: proc(self: ^DynamicLibrary, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Event +Class Methods: +Methods: + device + label + setLabel +*/ +@(objc_class="MTLEvent") +Event :: struct { using _: NS.Object } + +@(objc_type=Event, objc_name="device") +Event_device :: proc(self: ^Event) -> ^Event { + return msgSend(^Event, self, "device") +} +@(objc_type=Event, objc_name="label") +Event_label :: proc(self: ^Event) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=Event, objc_name="setLabel") +Event_setLabel :: proc(self: ^Event, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Fence +Class Methods: +Methods: + device + label + setLabel +*/ +@(objc_class="MTLFence") +Fence :: struct { using _: NS.Object } + +@(objc_type=Fence, objc_name="device") +Fence_device :: proc(self: ^Fence) -> ^Fence { + return msgSend(^Fence, self, "device") +} +@(objc_type=Fence, objc_name="label") +Fence_label :: proc(self: ^Fence) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=Fence, objc_name="setLabel") +Fence_setLabel :: proc(self: ^Fence, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Function +Class Methods: +Methods: + device + functionConstantsDictionary + functionType + label + name + newArgumentEncoderWithBufferIndex + newArgumentEncoderWithBufferIndex + options + patchControlPointCount + patchType + setLabel + stageInputAttributes + vertexAttributes +*/ +@(objc_class="MTLFunction") +Function :: struct { using _: NS.Object } + +@(objc_type=Function, objc_name="device") +Function_device :: proc(self: ^Function) -> ^Function { + return msgSend(^Function, self, "device") +} +@(objc_type=Function, objc_name="functionConstantsDictionary") +Function_functionConstantsDictionary :: proc(self: ^Function) -> ^NS.Dictionary { + return msgSend(^NS.Dictionary, self, "functionConstantsDictionary") +} +@(objc_type=Function, objc_name="functionType") +Function_functionType :: proc(self: ^Function) -> FunctionType { + return msgSend(FunctionType, self, "functionType") +} +@(objc_type=Function, objc_name="label") +Function_label :: proc(self: ^Function) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=Function, objc_name="name") +Function_name :: proc(self: ^Function) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} +@(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex") +Function_newArgumentEncoderWithBufferIndex :: proc(self: ^Function, bufferIndex: ^NS.Object) -> ^Function { + return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:", bufferIndex) +} +@(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex_reflection_") +Function_newArgumentEncoderWithBufferIndex_reflection_ :: proc(self: ^Function, bufferIndex: ^NS.Object, reflection: ^AutoreleasedArgument) -> ^Function { + return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:reflection:", bufferIndex, reflection) +} +@(objc_type=Function, objc_name="options") +Function_options :: proc(self: ^Function) -> FunctionOptions { + return msgSend(FunctionOptions, self, "options") +} +@(objc_type=Function, objc_name="patchControlPointCount") +Function_patchControlPointCount :: proc(self: ^Function) -> NS.Integer { + return msgSend(NS.Integer, self, "patchControlPointCount") +} +@(objc_type=Function, objc_name="patchType") +Function_patchType :: proc(self: ^Function) -> PatchType { + return msgSend(PatchType, self, "patchType") +} +@(objc_type=Function, objc_name="setLabel") +Function_setLabel :: proc(self: ^Function, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=Function, objc_name="stageInputAttributes") +Function_stageInputAttributes :: proc(self: ^Function) -> ^NS.Array { + return msgSend(^NS.Array, self, "stageInputAttributes") +} +@(objc_type=Function, objc_name="vertexAttributes") +Function_vertexAttributes :: proc(self: ^Function) -> ^NS.Array { + return msgSend(^NS.Array, self, "vertexAttributes") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + FunctionHandle +Class Methods: +Methods: + device + functionType + name +*/ +@(objc_class="MTLFunctionHandle") +FunctionHandle :: struct { using _: NS.Object } + +@(objc_type=FunctionHandle, objc_name="device") +FunctionHandle_device :: proc(self: ^FunctionHandle) -> ^FunctionHandle { + return msgSend(^FunctionHandle, self, "device") +} +@(objc_type=FunctionHandle, objc_name="functionType") +FunctionHandle_functionType :: proc(self: ^FunctionHandle) -> FunctionType { + return msgSend(FunctionType, self, "functionType") +} +@(objc_type=FunctionHandle, objc_name="name") +FunctionHandle_name :: proc(self: ^FunctionHandle) -> ^NS.String { + return msgSend(^NS.String, self, "name") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + FunctionLog +Class Methods: +Methods: + debugLocation + encoderLabel + function + type +*/ +@(objc_class="MTLFunctionLog") +FunctionLog :: struct { using _: NS.Object } + +@(objc_type=FunctionLog, objc_name="debugLocation") +FunctionLog_debugLocation :: proc(self: ^FunctionLog) -> ^FunctionLog { + return msgSend(^FunctionLog, self, "debugLocation") +} +@(objc_type=FunctionLog, objc_name="encoderLabel") +FunctionLog_encoderLabel :: proc(self: ^FunctionLog) -> ^NS.String { + return msgSend(^NS.String, self, "encoderLabel") +} +@(objc_type=FunctionLog, objc_name="function") +FunctionLog_function :: proc(self: ^FunctionLog) -> ^FunctionLog { + return msgSend(^FunctionLog, self, "function") +} +@(objc_type=FunctionLog, objc_name="type") +FunctionLog_type :: proc(self: ^FunctionLog) -> FunctionLogType { + return msgSend(FunctionLogType, self, "type") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + FunctionLogDebugLocation +Class Methods: +Methods: + URL + column + functionName + line +*/ +@(objc_class="MTLFunctionLogDebugLocation") +FunctionLogDebugLocation :: struct { using _: NS.Object } + +@(objc_type=FunctionLogDebugLocation, objc_name="URL") +FunctionLogDebugLocation_URL :: proc(self: ^FunctionLogDebugLocation) -> ^NS.URL { + return msgSend(^NS.URL, self, "URL") +} +@(objc_type=FunctionLogDebugLocation, objc_name="column") +FunctionLogDebugLocation_column :: proc(self: ^FunctionLogDebugLocation) -> NS.Integer { + return msgSend(NS.Integer, self, "column") +} +@(objc_type=FunctionLogDebugLocation, objc_name="functionName") +FunctionLogDebugLocation_functionName :: proc(self: ^FunctionLogDebugLocation) -> ^NS.String { + return msgSend(^NS.String, self, "functionName") +} +@(objc_type=FunctionLogDebugLocation, objc_name="line") +FunctionLogDebugLocation_line :: proc(self: ^FunctionLogDebugLocation) -> NS.Integer { + return msgSend(NS.Integer, self, "line") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Heap +Class Methods: +Methods: + cpuCacheMode + currentAllocatedSize + device + hazardTrackingMode + label + maxAvailableSizeWithAlignment + newBufferWithLength + newBufferWithLength + newTextureWithDescriptor + newTextureWithDescriptor + resourceOptions + setLabel + setPurgeableState + size + storageMode + type + usedSize +*/ +@(objc_class="MTLHeap") +Heap :: struct { using _: NS.Object } + +@(objc_type=Heap, objc_name="cpuCacheMode") +Heap_cpuCacheMode :: proc(self: ^Heap) -> CPUCacheMode { + return msgSend(CPUCacheMode, self, "cpuCacheMode") +} +@(objc_type=Heap, objc_name="currentAllocatedSize") +Heap_currentAllocatedSize :: proc(self: ^Heap) -> NS.Integer { + return msgSend(NS.Integer, self, "currentAllocatedSize") +} +@(objc_type=Heap, objc_name="device") +Heap_device :: proc(self: ^Heap) -> ^Heap { + return msgSend(^Heap, self, "device") +} +@(objc_type=Heap, objc_name="hazardTrackingMode") +Heap_hazardTrackingMode :: proc(self: ^Heap) -> HazardTrackingMode { + return msgSend(HazardTrackingMode, self, "hazardTrackingMode") +} +@(objc_type=Heap, objc_name="label") +Heap_label :: proc(self: ^Heap) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=Heap, objc_name="maxAvailableSizeWithAlignment") +Heap_maxAvailableSizeWithAlignment :: proc(self: ^Heap, alignment: ^NS.Object) -> ^Heap { + return msgSend(^Heap, self, "maxAvailableSizeWithAlignment:", alignment) +} +@(objc_type=Heap, objc_name="newBufferWithLength") +Heap_newBufferWithLength :: proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions) -> ^Heap { + return msgSend(^Heap, self, "newBufferWithLength:options:", length, options) +} +@(objc_type=Heap, objc_name="newBufferWithLength_options_offset_") +Heap_newBufferWithLength_options_offset_ :: proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions, offset: ^NS.Object) -> ^Heap { + return msgSend(^Heap, self, "newBufferWithLength:options:offset:", length, options, offset) +} +@(objc_type=Heap, objc_name="newTextureWithDescriptor") +Heap_newTextureWithDescriptor :: proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Heap { + return msgSend(^Heap, self, "newTextureWithDescriptor:", desc) +} +@(objc_type=Heap, objc_name="newTextureWithDescriptor_offset_") +Heap_newTextureWithDescriptor_offset_ :: proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: ^NS.Object) -> ^Heap { + return msgSend(^Heap, self, "newTextureWithDescriptor:offset:", descriptor, offset) +} +@(objc_type=Heap, objc_name="resourceOptions") +Heap_resourceOptions :: proc(self: ^Heap) -> ResourceOptions { + return msgSend(ResourceOptions, self, "resourceOptions") +} +@(objc_type=Heap, objc_name="setLabel") +Heap_setLabel :: proc(self: ^Heap, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=Heap, objc_name="setPurgeableState") +Heap_setPurgeableState :: proc(self: ^Heap, state: PurgeableState) -> PurgeableState { + return msgSend(PurgeableState, self, "setPurgeableState:", state) +} +@(objc_type=Heap, objc_name="size") +Heap_size :: proc(self: ^Heap) -> NS.Integer { + return msgSend(NS.Integer, self, "size") +} +@(objc_type=Heap, objc_name="storageMode") +Heap_storageMode :: proc(self: ^Heap) -> StorageMode { + return msgSend(StorageMode, self, "storageMode") +} +@(objc_type=Heap, objc_name="type") +Heap_type :: proc(self: ^Heap) -> FunctionLogType { + return msgSend(FunctionLogType, self, "type") +} +@(objc_type=Heap, objc_name="usedSize") +Heap_usedSize :: proc(self: ^Heap) -> NS.Integer { + return msgSend(NS.Integer, self, "usedSize") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + IndirectCommandBuffer +Class Methods: +Methods: + indirectComputeCommandAtIndex + indirectRenderCommandAtIndex + resetWithRange + size +*/ +@(objc_class="MTLIndirectCommandBuffer") +IndirectCommandBuffer :: struct { using _: NS.Object } + +@(objc_type=IndirectCommandBuffer, objc_name="indirectComputeCommandAtIndex") +IndirectCommandBuffer_indirectComputeCommandAtIndex :: proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { + return msgSend(^IndirectCommandBuffer, self, "indirectComputeCommandAtIndex:", commandIndex) +} +@(objc_type=IndirectCommandBuffer, objc_name="indirectRenderCommandAtIndex") +IndirectCommandBuffer_indirectRenderCommandAtIndex :: proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { + return msgSend(^IndirectCommandBuffer, self, "indirectRenderCommandAtIndex:", commandIndex) +} +@(objc_type=IndirectCommandBuffer, objc_name="resetWithRange") +IndirectCommandBuffer_resetWithRange :: proc(self: ^IndirectCommandBuffer, range: NS.Range) { + msgSend(nil, self, "resetWithRange:", range) +} +@(objc_type=IndirectCommandBuffer, objc_name="size") +IndirectCommandBuffer_size :: proc(self: ^IndirectCommandBuffer) -> NS.Integer { + return msgSend(NS.Integer, self, "size") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + IndirectComputeCommand +Class Methods: +Methods: + clearBarrier + concurrentDispatchThreadgroups + concurrentDispatchThreads + reset + setBarrier + setComputePipelineState + setImageblockWidth + setKernelBuffer + setStageInRegion + setThreadgroupMemoryLength +*/ +@(objc_class="MTLIndirectComputeCommand") +IndirectComputeCommand :: struct { using _: NS.Object } + +@(objc_type=IndirectComputeCommand, objc_name="clearBarrier") +IndirectComputeCommand_clearBarrier :: proc(self: ^IndirectComputeCommand) { + msgSend(nil, self, "clearBarrier") +} +@(objc_type=IndirectComputeCommand, objc_name="concurrentDispatchThreadgroups") +IndirectComputeCommand_concurrentDispatchThreadgroups :: proc(self: ^IndirectComputeCommand, threadgroupsPerGrid: Size, threadsPerThreadgroup: Size) { + msgSend(nil, self, "concurrentDispatchThreadgroups:threadsPerThreadgroup:", threadgroupsPerGrid, threadsPerThreadgroup) +} +@(objc_type=IndirectComputeCommand, objc_name="concurrentDispatchThreads") +IndirectComputeCommand_concurrentDispatchThreads :: proc(self: ^IndirectComputeCommand, threadsPerGrid: Size, threadsPerThreadgroup: Size) { + msgSend(nil, self, "concurrentDispatchThreads:threadsPerThreadgroup:", threadsPerGrid, threadsPerThreadgroup) +} +@(objc_type=IndirectComputeCommand, objc_name="reset") +IndirectComputeCommand_reset :: proc(self: ^IndirectComputeCommand) { + msgSend(nil, self, "reset") +} +@(objc_type=IndirectComputeCommand, objc_name="setBarrier") +IndirectComputeCommand_setBarrier :: proc(self: ^IndirectComputeCommand) { + msgSend(nil, self, "setBarrier") +} +@(objc_type=IndirectComputeCommand, objc_name="setComputePipelineState") +IndirectComputeCommand_setComputePipelineState :: proc(self: ^IndirectComputeCommand, pipelineState: ^NS.Object) { + msgSend(nil, self, "setComputePipelineState:", pipelineState) +} +@(objc_type=IndirectComputeCommand, objc_name="setImageblockWidth") +IndirectComputeCommand_setImageblockWidth :: proc(self: ^IndirectComputeCommand, width: ^NS.Object, height: ^NS.Object) { + msgSend(nil, self, "setImageblockWidth:height:", width, height) +} +@(objc_type=IndirectComputeCommand, objc_name="setKernelBuffer") +IndirectComputeCommand_setKernelBuffer :: proc(self: ^IndirectComputeCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setKernelBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=IndirectComputeCommand, objc_name="setStageInRegion") +IndirectComputeCommand_setStageInRegion :: proc(self: ^IndirectComputeCommand, region: Region) { + msgSend(nil, self, "setStageInRegion:", region) +} +@(objc_type=IndirectComputeCommand, objc_name="setThreadgroupMemoryLength") +IndirectComputeCommand_setThreadgroupMemoryLength :: proc(self: ^IndirectComputeCommand, length: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setThreadgroupMemoryLength:atIndex:", length, index) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + IndirectRenderCommand +Class Methods: +Methods: + drawIndexedPatches + drawIndexedPrimitives + drawPatches + drawPrimitives + reset + setFragmentBuffer + setRenderPipelineState + setVertexBuffer +*/ +@(objc_class="MTLIndirectRenderCommand") +IndirectRenderCommand :: struct { using _: NS.Object } + +@(objc_type=IndirectRenderCommand, objc_name="drawIndexedPatches") +IndirectRenderCommand_drawIndexedPatches :: proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { + msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) +} +@(objc_type=IndirectRenderCommand, objc_name="drawIndexedPrimitives") +IndirectRenderCommand_drawIndexedPrimitives :: proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { + msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) +} +@(objc_type=IndirectRenderCommand, objc_name="drawPatches") +IndirectRenderCommand_drawPatches :: proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { + msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) +} +@(objc_type=IndirectRenderCommand, objc_name="drawPrimitives") +IndirectRenderCommand_drawPrimitives :: proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { + msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) +} +@(objc_type=IndirectRenderCommand, objc_name="reset") +IndirectRenderCommand_reset :: proc(self: ^IndirectRenderCommand) { + msgSend(nil, self, "reset") +} +@(objc_type=IndirectRenderCommand, objc_name="setFragmentBuffer") +IndirectRenderCommand_setFragmentBuffer :: proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFragmentBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=IndirectRenderCommand, objc_name="setRenderPipelineState") +IndirectRenderCommand_setRenderPipelineState :: proc(self: ^IndirectRenderCommand, pipelineState: ^NS.Object) { + msgSend(nil, self, "setRenderPipelineState:", pipelineState) +} +@(objc_type=IndirectRenderCommand, objc_name="setVertexBuffer") +IndirectRenderCommand_setVertexBuffer :: proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setVertexBuffer:offset:atIndex:", buffer, offset, index) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + IntersectionFunctionTable +Class Methods: +Methods: + setBuffer + setBuffers + setFunction + setFunctions + setOpaqueTriangleIntersectionFunctionWithSignature + setOpaqueTriangleIntersectionFunctionWithSignature + setVisibleFunctionTable + setVisibleFunctionTables +*/ +@(objc_class="MTLIntersectionFunctionTable") +IntersectionFunctionTable :: struct { using _: NS.Object } + +@(objc_type=IntersectionFunctionTable, objc_name="setBuffer") +IntersectionFunctionTable_setBuffer :: proc(self: ^IntersectionFunctionTable, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=IntersectionFunctionTable, objc_name="setBuffers") +IntersectionFunctionTable_setBuffers :: proc(self: ^IntersectionFunctionTable, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { + msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) +} +@(objc_type=IntersectionFunctionTable, objc_name="setFunction") +IntersectionFunctionTable_setFunction :: proc(self: ^IntersectionFunctionTable, function: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFunction:atIndex:", function, index) +} +@(objc_type=IntersectionFunctionTable, objc_name="setFunctions") +IntersectionFunctionTable_setFunctions :: proc(self: ^IntersectionFunctionTable, functions: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setFunctions:withRange:", functions, range) +} +@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignature_atIndex_") +IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_atIndex_ :: proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: ^NS.Object) { + msgSend(nil, self, "setOpaqueTriangleIntersectionFunctionWithSignature:atIndex:", signature, index) +} +@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignature_withRange_") +IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_withRange_ :: proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, range: NS.Range) { + msgSend(nil, self, "setOpaqueTriangleIntersectionFunctionWithSignature:withRange:", signature, range) +} +@(objc_type=IntersectionFunctionTable, objc_name="setVisibleFunctionTable") +IntersectionFunctionTable_setVisibleFunctionTable :: proc(self: ^IntersectionFunctionTable, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { + msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) +} +@(objc_type=IntersectionFunctionTable, objc_name="setVisibleFunctionTables") +IntersectionFunctionTable_setVisibleFunctionTables :: proc(self: ^IntersectionFunctionTable, visibleFunctionTables: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Library +Class Methods: +Methods: + device + functionNames + installName + label + newFunctionWithDescriptor + newFunctionWithDescriptor + newFunctionWithName + newFunctionWithName + newFunctionWithName + newIntersectionFunctionWithDescriptor + newIntersectionFunctionWithDescriptor + setLabel + type +*/ +@(objc_class="MTLLibrary") +Library :: struct { using _: NS.Object } + +@(objc_type=Library, objc_name="device") +Library_device :: proc(self: ^Library) -> ^Library { + return msgSend(^Library, self, "device") +} +@(objc_type=Library, objc_name="functionNames") +Library_functionNames :: proc(self: ^Library) -> ^NS.Array { + return msgSend(^NS.Array, self, "functionNames") +} +@(objc_type=Library, objc_name="installName") +Library_installName :: proc(self: ^Library) -> ^NS.String { + return msgSend(^NS.String, self, "installName") +} +@(objc_type=Library, objc_name="label") +Library_label :: proc(self: ^Library) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=Library, objc_name="newFunctionWithDescriptor_completionHandler_") +Library_newFunctionWithDescriptor_completionHandler_ :: proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) { + msgSend(nil, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) +} +@(objc_type=Library, objc_name="newFunctionWithDescriptor_error_") +Library_newFunctionWithDescriptor_error_ :: proc(self: ^Library, descriptor: ^FunctionDescriptor, error: ^^NS.Error ) -> ^Library { + return msgSend(^Library, self, "newFunctionWithDescriptor:error:", descriptor, error) +} +@(objc_type=Library, objc_name="newFunctionWithName") +Library_newFunctionWithName :: proc(self: ^Library, functionName: ^NS.String) -> ^Library { + return msgSend(^Library, self, "newFunctionWithName:", functionName) +} +@(objc_type=Library, objc_name="newFunctionWithName_constantValues_completionHandler_") +Library_newFunctionWithName_constantValues_completionHandler_ :: proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) { + msgSend(nil, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) +} +@(objc_type=Library, objc_name="newFunctionWithName_constantValues_error_") +Library_newFunctionWithName_constantValues_error_ :: proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, error: ^^NS.Error ) -> ^Library { + return msgSend(^Library, self, "newFunctionWithName:constantValues:error:", name, constantValues, error) +} +@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_completionHandler_") +Library_newIntersectionFunctionWithDescriptor_completionHandler_ :: proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) { + msgSend(nil, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) +} +@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_error_") +Library_newIntersectionFunctionWithDescriptor_error_ :: proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, error: ^^NS.Error ) -> ^Library { + return msgSend(^Library, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, error) +} +@(objc_type=Library, objc_name="setLabel") +Library_setLabel :: proc(self: ^Library, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=Library, objc_name="type") +Library_type :: proc(self: ^Library) -> LibraryType { + return msgSend(LibraryType, self, "type") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ParallelRenderCommandEncoder +Class Methods: +Methods: + renderCommandEncoder + setColorStoreAction + setColorStoreActionOptions + setDepthStoreAction + setDepthStoreActionOptions + setStencilStoreAction + setStencilStoreActionOptions +*/ +@(objc_class="MTLParallelRenderCommandEncoder") +ParallelRenderCommandEncoder :: struct { using _: NS.Object } + +@(objc_type=ParallelRenderCommandEncoder, objc_name="renderCommandEncoder") +ParallelRenderCommandEncoder_renderCommandEncoder :: proc(self: ^ParallelRenderCommandEncoder) -> ^ParallelRenderCommandEncoder { + return msgSend(^ParallelRenderCommandEncoder, self, "renderCommandEncoder") +} +@(objc_type=ParallelRenderCommandEncoder, objc_name="setColorStoreAction") +ParallelRenderCommandEncoder_setColorStoreAction :: proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { + msgSend(nil, self, "setColorStoreAction:atIndex:", storeAction, colorAttachmentIndex) +} +@(objc_type=ParallelRenderCommandEncoder, objc_name="setColorStoreActionOptions") +ParallelRenderCommandEncoder_setColorStoreActionOptions :: proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { + msgSend(nil, self, "setColorStoreActionOptions:atIndex:", storeActionOptions, colorAttachmentIndex) +} +@(objc_type=ParallelRenderCommandEncoder, objc_name="setDepthStoreAction") +ParallelRenderCommandEncoder_setDepthStoreAction :: proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction) { + msgSend(nil, self, "setDepthStoreAction:", storeAction) +} +@(objc_type=ParallelRenderCommandEncoder, objc_name="setDepthStoreActionOptions") +ParallelRenderCommandEncoder_setDepthStoreActionOptions :: proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions) { + msgSend(nil, self, "setDepthStoreActionOptions:", storeActionOptions) +} +@(objc_type=ParallelRenderCommandEncoder, objc_name="setStencilStoreAction") +ParallelRenderCommandEncoder_setStencilStoreAction :: proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction) { + msgSend(nil, self, "setStencilStoreAction:", storeAction) +} +@(objc_type=ParallelRenderCommandEncoder, objc_name="setStencilStoreActionOptions") +ParallelRenderCommandEncoder_setStencilStoreActionOptions :: proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions) { + msgSend(nil, self, "setStencilStoreActionOptions:", storeActionOptions) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RasterizationRateMap +Class Methods: +Methods: + copyParameterDataToBuffer + device + label + layerCount + mapPhysicalToScreenCoordinates + mapScreenToPhysicalCoordinates + parameterBufferSizeAndAlign + physicalGranularity + physicalSizeForLayer + screenSize +*/ +@(objc_class="MTLRasterizationRateMap") +RasterizationRateMap :: struct { using _: NS.Object } + +@(objc_type=RasterizationRateMap, objc_name="copyParameterDataToBuffer") +RasterizationRateMap_copyParameterDataToBuffer :: proc(self: ^RasterizationRateMap, buffer: ^NS.Object, offset: ^NS.Object) { + msgSend(nil, self, "copyParameterDataToBuffer:offset:", buffer, offset) +} +@(objc_type=RasterizationRateMap, objc_name="device") +RasterizationRateMap_device :: proc(self: ^RasterizationRateMap) -> ^RasterizationRateMap { + return msgSend(^RasterizationRateMap, self, "device") +} +@(objc_type=RasterizationRateMap, objc_name="label") +RasterizationRateMap_label :: proc(self: ^RasterizationRateMap) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=RasterizationRateMap, objc_name="layerCount") +RasterizationRateMap_layerCount :: proc(self: ^RasterizationRateMap) -> NS.Integer { + return msgSend(NS.Integer, self, "layerCount") +} +@(objc_type=RasterizationRateMap, objc_name="mapPhysicalToScreenCoordinates") +RasterizationRateMap_mapPhysicalToScreenCoordinates :: proc(self: ^RasterizationRateMap, physicalCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { + return msgSend(Coordinate2D, self, "mapPhysicalToScreenCoordinates:forLayer:", physicalCoordinates, layerIndex) +} +@(objc_type=RasterizationRateMap, objc_name="mapScreenToPhysicalCoordinates") +RasterizationRateMap_mapScreenToPhysicalCoordinates :: proc(self: ^RasterizationRateMap, screenCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { + return msgSend(Coordinate2D, self, "mapScreenToPhysicalCoordinates:forLayer:", screenCoordinates, layerIndex) +} +@(objc_type=RasterizationRateMap, objc_name="parameterBufferSizeAndAlign") +RasterizationRateMap_parameterBufferSizeAndAlign :: proc(self: ^RasterizationRateMap) -> SizeAndAlign { + return msgSend(SizeAndAlign, self, "parameterBufferSizeAndAlign") +} +@(objc_type=RasterizationRateMap, objc_name="physicalGranularity") +RasterizationRateMap_physicalGranularity :: proc(self: ^RasterizationRateMap) -> Size { + return msgSend(Size, self, "physicalGranularity") +} +@(objc_type=RasterizationRateMap, objc_name="physicalSizeForLayer") +RasterizationRateMap_physicalSizeForLayer :: proc(self: ^RasterizationRateMap, layerIndex: ^NS.Object) -> Size { + return msgSend(Size, self, "physicalSizeForLayer:", layerIndex) +} +@(objc_type=RasterizationRateMap, objc_name="screenSize") +RasterizationRateMap_screenSize :: proc(self: ^RasterizationRateMap) -> Size { + return msgSend(Size, self, "screenSize") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderCommandEncoder +Class Methods: +Methods: + dispatchThreadsPerTile + drawIndexedPatches + drawIndexedPatches + drawIndexedPrimitives + drawIndexedPrimitives + drawIndexedPrimitives + drawIndexedPrimitives + drawPatches + drawPatches + drawPrimitives + drawPrimitives + drawPrimitives + drawPrimitives + executeCommandsInBuffer + executeCommandsInBuffer + memoryBarrierWithResources + memoryBarrierWithScope + sampleCountersInBuffer + setBlendColorRed + setColorStoreAction + setColorStoreActionOptions + setCullMode + setDepthBias + setDepthClipMode + setDepthStencilState + setDepthStoreAction + setDepthStoreActionOptions + setFragmentBuffer + setFragmentBufferOffset + setFragmentBuffers + setFragmentBytes + setFragmentSamplerState + setFragmentSamplerState + setFragmentSamplerStates + setFragmentSamplerStates + setFragmentTexture + setFragmentTextures + setFrontFacingWinding + setRenderPipelineState + setScissorRect + setScissorRects + setStencilFrontReferenceValue + setStencilReferenceValue + setStencilStoreAction + setStencilStoreActionOptions + setTessellationFactorBuffer + setTessellationFactorScale + setThreadgroupMemoryLength + setTileBuffer + setTileBufferOffset + setTileBuffers + setTileBytes + setTileSamplerState + setTileSamplerState + setTileSamplerStates + setTileSamplerStates + setTileTexture + setTileTextures + setTriangleFillMode + setVertexAmplificationCount + setVertexBuffer + setVertexBufferOffset + setVertexBuffers + setVertexBytes + setVertexSamplerState + setVertexSamplerState + setVertexSamplerStates + setVertexSamplerStates + setVertexTexture + setVertexTextures + setViewport + setViewports + setVisibilityResultMode + textureBarrier + tileHeight + tileWidth + updateFence + useHeap + useHeap + useHeaps + useHeaps + useResource + useResource + useResources + useResources + waitForFence +*/ +@(objc_class="MTLRenderCommandEncoder") +RenderCommandEncoder :: struct { using _: NS.Object } + +@(objc_type=RenderCommandEncoder, objc_name="dispatchThreadsPerTile") +RenderCommandEncoder_dispatchThreadsPerTile :: proc(self: ^RenderCommandEncoder, threadsPerTile: Size) { + msgSend(nil, self, "dispatchThreadsPerTile:", threadsPerTile) +} +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_") +RenderCommandEncoder_drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "drawIndexedPatches:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, indirectBuffer, indirectBufferOffset) +} +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_") +RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { + msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance) +} +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_") +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object) { + msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset) +} +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_") +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object) { + msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount) +} +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_") +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { + msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) +} +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_") +RenderCommandEncoder_drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "drawIndexedPrimitives:indexType:indexBuffer:indexBufferOffset:indirectBuffer:indirectBufferOffset:", primitiveType, indexType, indexBuffer, indexBufferOffset, indirectBuffer, indirectBufferOffset) +} +@(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_") +RenderCommandEncoder_drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "drawPatches:patchIndexBuffer:patchIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, indirectBuffer, indirectBufferOffset) +} +@(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_") +RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { + msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance) +} +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_indirectBuffer_indirectBufferOffset_") +RenderCommandEncoder_drawPrimitives_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "drawPrimitives:indirectBuffer:indirectBufferOffset:", primitiveType, indirectBuffer, indirectBufferOffset) +} +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_") +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object) { + msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:", primitiveType, vertexStart, vertexCount) +} +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_") +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object) { + msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:", primitiveType, vertexStart, vertexCount, instanceCount) +} +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_") +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { + msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) +} +@(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_") +RenderCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "executeCommandsInBuffer:indirectBuffer:indirectBufferOffset:", indirectCommandbuffer, indirectRangeBuffer, indirectBufferOffset) +} +@(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer_withRange_") +RenderCommandEncoder_executeCommandsInBuffer_withRange_ :: proc(self: ^RenderCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { + msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) +} +@(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithResources") +RenderCommandEncoder_memoryBarrierWithResources :: proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, after: RenderStages, before: RenderStages) { + msgSend(nil, self, "memoryBarrierWithResources:count:afterStages:beforeStages:", resources, count, after, before) +} +@(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithScope") +RenderCommandEncoder_memoryBarrierWithScope :: proc(self: ^RenderCommandEncoder, scope: BarrierScope, after: RenderStages, before: RenderStages) { + msgSend(nil, self, "memoryBarrierWithScope:afterStages:beforeStages:", scope, after, before) +} +@(objc_type=RenderCommandEncoder, objc_name="sampleCountersInBuffer") +RenderCommandEncoder_sampleCountersInBuffer :: proc(self: ^RenderCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { + msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) +} +@(objc_type=RenderCommandEncoder, objc_name="setBlendColorRed") +RenderCommandEncoder_setBlendColorRed :: proc(self: ^RenderCommandEncoder, red: f32, green: f32, blue: f32, alpha: f32) { + msgSend(nil, self, "setBlendColorRed:green:blue:alpha:", red, green, blue, alpha) +} +@(objc_type=RenderCommandEncoder, objc_name="setColorStoreAction") +RenderCommandEncoder_setColorStoreAction :: proc(self: ^RenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { + msgSend(nil, self, "setColorStoreAction:atIndex:", storeAction, colorAttachmentIndex) +} +@(objc_type=RenderCommandEncoder, objc_name="setColorStoreActionOptions") +RenderCommandEncoder_setColorStoreActionOptions :: proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { + msgSend(nil, self, "setColorStoreActionOptions:atIndex:", storeActionOptions, colorAttachmentIndex) +} +@(objc_type=RenderCommandEncoder, objc_name="setCullMode") +RenderCommandEncoder_setCullMode :: proc(self: ^RenderCommandEncoder, cullMode: CullMode) { + msgSend(nil, self, "setCullMode:", cullMode) +} +@(objc_type=RenderCommandEncoder, objc_name="setDepthBias") +RenderCommandEncoder_setDepthBias :: proc(self: ^RenderCommandEncoder, depthBias: f32, slopeScale: f32, clamp: f32) { + msgSend(nil, self, "setDepthBias:slopeScale:clamp:", depthBias, slopeScale, clamp) +} +@(objc_type=RenderCommandEncoder, objc_name="setDepthClipMode") +RenderCommandEncoder_setDepthClipMode :: proc(self: ^RenderCommandEncoder, depthClipMode: DepthClipMode) { + msgSend(nil, self, "setDepthClipMode:", depthClipMode) +} +@(objc_type=RenderCommandEncoder, objc_name="setDepthStencilState") +RenderCommandEncoder_setDepthStencilState :: proc(self: ^RenderCommandEncoder, depthStencilState: ^NS.Object) { + msgSend(nil, self, "setDepthStencilState:", depthStencilState) +} +@(objc_type=RenderCommandEncoder, objc_name="setDepthStoreAction") +RenderCommandEncoder_setDepthStoreAction :: proc(self: ^RenderCommandEncoder, storeAction: StoreAction) { + msgSend(nil, self, "setDepthStoreAction:", storeAction) +} +@(objc_type=RenderCommandEncoder, objc_name="setDepthStoreActionOptions") +RenderCommandEncoder_setDepthStoreActionOptions :: proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions) { + msgSend(nil, self, "setDepthStoreActionOptions:", storeActionOptions) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentBuffer") +RenderCommandEncoder_setFragmentBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFragmentBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentBufferOffset") +RenderCommandEncoder_setFragmentBufferOffset :: proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFragmentBufferOffset:atIndex:", offset, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentBuffers") +RenderCommandEncoder_setFragmentBuffers :: proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { + msgSend(nil, self, "setFragmentBuffers:offsets:withRange:", buffers, offsets, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentBytes") +RenderCommandEncoder_setFragmentBytes :: proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFragmentBytes:length:atIndex:", bytes, length, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_atIndex_") +RenderCommandEncoder_setFragmentSamplerState_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFragmentSamplerState:atIndex:", sampler, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_lodMinClamp_lodMaxClamp_atIndex_") +RenderCommandEncoder_setFragmentSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { + msgSend(nil, self, "setFragmentSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_lodMinClamps_lodMaxClamps_withRange_") +RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { + msgSend(nil, self, "setFragmentSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_withRange_") +RenderCommandEncoder_setFragmentSamplerStates_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setFragmentSamplerStates:withRange:", samplers, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentTexture") +RenderCommandEncoder_setFragmentTexture :: proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFragmentTexture:atIndex:", texture, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setFragmentTextures") +RenderCommandEncoder_setFragmentTextures :: proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setFragmentTextures:withRange:", textures, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setFrontFacingWinding") +RenderCommandEncoder_setFrontFacingWinding :: proc(self: ^RenderCommandEncoder, frontFacingWinding: Winding) { + msgSend(nil, self, "setFrontFacingWinding:", frontFacingWinding) +} +@(objc_type=RenderCommandEncoder, objc_name="setRenderPipelineState") +RenderCommandEncoder_setRenderPipelineState :: proc(self: ^RenderCommandEncoder, pipelineState: ^NS.Object) { + msgSend(nil, self, "setRenderPipelineState:", pipelineState) +} +@(objc_type=RenderCommandEncoder, objc_name="setScissorRect") +RenderCommandEncoder_setScissorRect :: proc(self: ^RenderCommandEncoder, rect: ScissorRect) { + msgSend(nil, self, "setScissorRect:", rect) +} +@(objc_type=RenderCommandEncoder, objc_name="setScissorRects") +RenderCommandEncoder_setScissorRects :: proc(self: ^RenderCommandEncoder, scissorRects: ^ScissorRect, count: ^NS.Object) { + msgSend(nil, self, "setScissorRects:count:", scissorRects, count) +} +@(objc_type=RenderCommandEncoder, objc_name="setStencilFrontReferenceValue") +RenderCommandEncoder_setStencilFrontReferenceValue :: proc(self: ^RenderCommandEncoder, frontReferenceValue: u32, backReferenceValue: u32) { + msgSend(nil, self, "setStencilFrontReferenceValue:backReferenceValue:", frontReferenceValue, backReferenceValue) +} +@(objc_type=RenderCommandEncoder, objc_name="setStencilReferenceValue") +RenderCommandEncoder_setStencilReferenceValue :: proc(self: ^RenderCommandEncoder, referenceValue: u32) { + msgSend(nil, self, "setStencilReferenceValue:", referenceValue) +} +@(objc_type=RenderCommandEncoder, objc_name="setStencilStoreAction") +RenderCommandEncoder_setStencilStoreAction :: proc(self: ^RenderCommandEncoder, storeAction: StoreAction) { + msgSend(nil, self, "setStencilStoreAction:", storeAction) +} +@(objc_type=RenderCommandEncoder, objc_name="setStencilStoreActionOptions") +RenderCommandEncoder_setStencilStoreActionOptions :: proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions) { + msgSend(nil, self, "setStencilStoreActionOptions:", storeActionOptions) +} +@(objc_type=RenderCommandEncoder, objc_name="setTessellationFactorBuffer") +RenderCommandEncoder_setTessellationFactorBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { + msgSend(nil, self, "setTessellationFactorBuffer:offset:instanceStride:", buffer, offset, instanceStride) +} +@(objc_type=RenderCommandEncoder, objc_name="setTessellationFactorScale") +RenderCommandEncoder_setTessellationFactorScale :: proc(self: ^RenderCommandEncoder, scale: f32) { + msgSend(nil, self, "setTessellationFactorScale:", scale) +} +@(objc_type=RenderCommandEncoder, objc_name="setThreadgroupMemoryLength") +RenderCommandEncoder_setThreadgroupMemoryLength :: proc(self: ^RenderCommandEncoder, length: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setThreadgroupMemoryLength:offset:atIndex:", length, offset, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileBuffer") +RenderCommandEncoder_setTileBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setTileBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileBufferOffset") +RenderCommandEncoder_setTileBufferOffset :: proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setTileBufferOffset:atIndex:", offset, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileBuffers") +RenderCommandEncoder_setTileBuffers :: proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { + msgSend(nil, self, "setTileBuffers:offsets:withRange:", buffers, offsets, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileBytes") +RenderCommandEncoder_setTileBytes :: proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setTileBytes:length:atIndex:", bytes, length, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_atIndex_") +RenderCommandEncoder_setTileSamplerState_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setTileSamplerState:atIndex:", sampler, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_lodMinClamp_lodMaxClamp_atIndex_") +RenderCommandEncoder_setTileSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { + msgSend(nil, self, "setTileSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_lodMinClamps_lodMaxClamps_withRange_") +RenderCommandEncoder_setTileSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { + msgSend(nil, self, "setTileSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_withRange_") +RenderCommandEncoder_setTileSamplerStates_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setTileSamplerStates:withRange:", samplers, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileTexture") +RenderCommandEncoder_setTileTexture :: proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setTileTexture:atIndex:", texture, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setTileTextures") +RenderCommandEncoder_setTileTextures :: proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setTileTextures:withRange:", textures, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setTriangleFillMode") +RenderCommandEncoder_setTriangleFillMode :: proc(self: ^RenderCommandEncoder, fillMode: TriangleFillMode) { + msgSend(nil, self, "setTriangleFillMode:", fillMode) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexAmplificationCount") +RenderCommandEncoder_setVertexAmplificationCount :: proc(self: ^RenderCommandEncoder, count: ^NS.Object, viewMappings: ^VertexAmplificationViewMapping) { + msgSend(nil, self, "setVertexAmplificationCount:viewMappings:", count, viewMappings) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexBuffer") +RenderCommandEncoder_setVertexBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setVertexBuffer:offset:atIndex:", buffer, offset, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexBufferOffset") +RenderCommandEncoder_setVertexBufferOffset :: proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setVertexBufferOffset:atIndex:", offset, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexBuffers") +RenderCommandEncoder_setVertexBuffers :: proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { + msgSend(nil, self, "setVertexBuffers:offsets:withRange:", buffers, offsets, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexBytes") +RenderCommandEncoder_setVertexBytes :: proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setVertexBytes:length:atIndex:", bytes, length, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_atIndex_") +RenderCommandEncoder_setVertexSamplerState_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setVertexSamplerState:atIndex:", sampler, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_lodMinClamp_lodMaxClamp_atIndex_") +RenderCommandEncoder_setVertexSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { + msgSend(nil, self, "setVertexSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange_") +RenderCommandEncoder_setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { + msgSend(nil, self, "setVertexSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_withRange_") +RenderCommandEncoder_setVertexSamplerStates_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setVertexSamplerStates:withRange:", samplers, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexTexture") +RenderCommandEncoder_setVertexTexture :: proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setVertexTexture:atIndex:", texture, index) +} +@(objc_type=RenderCommandEncoder, objc_name="setVertexTextures") +RenderCommandEncoder_setVertexTextures :: proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setVertexTextures:withRange:", textures, range) +} +@(objc_type=RenderCommandEncoder, objc_name="setViewport") +RenderCommandEncoder_setViewport :: proc(self: ^RenderCommandEncoder, viewport: Viewport) { + msgSend(nil, self, "setViewport:", viewport) +} +@(objc_type=RenderCommandEncoder, objc_name="setViewports") +RenderCommandEncoder_setViewports :: proc(self: ^RenderCommandEncoder, viewports: ^Viewport, count: ^NS.Object) { + msgSend(nil, self, "setViewports:count:", viewports, count) +} +@(objc_type=RenderCommandEncoder, objc_name="setVisibilityResultMode") +RenderCommandEncoder_setVisibilityResultMode :: proc(self: ^RenderCommandEncoder, mode: VisibilityResultMode, offset: ^NS.Object) { + msgSend(nil, self, "setVisibilityResultMode:offset:", mode, offset) +} +@(objc_type=RenderCommandEncoder, objc_name="textureBarrier") +RenderCommandEncoder_textureBarrier :: proc(self: ^RenderCommandEncoder) { + msgSend(nil, self, "textureBarrier") +} +@(objc_type=RenderCommandEncoder, objc_name="tileHeight") +RenderCommandEncoder_tileHeight :: proc(self: ^RenderCommandEncoder) -> NS.Integer { + return msgSend(NS.Integer, self, "tileHeight") +} +@(objc_type=RenderCommandEncoder, objc_name="tileWidth") +RenderCommandEncoder_tileWidth :: proc(self: ^RenderCommandEncoder) -> NS.Integer { + return msgSend(NS.Integer, self, "tileWidth") +} +@(objc_type=RenderCommandEncoder, objc_name="updateFence") +RenderCommandEncoder_updateFence :: proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { + msgSend(nil, self, "updateFence:afterStages:", fence, stages) +} +@(objc_type=RenderCommandEncoder, objc_name="useHeap") +RenderCommandEncoder_useHeap :: proc(self: ^RenderCommandEncoder, heap: ^NS.Object) { + msgSend(nil, self, "useHeap:", heap) +} +@(objc_type=RenderCommandEncoder, objc_name="useHeap_stages_") +RenderCommandEncoder_useHeap_stages_ :: proc(self: ^RenderCommandEncoder, heap: ^NS.Object, stages: RenderStages) { + msgSend(nil, self, "useHeap:stages:", heap, stages) +} +@(objc_type=RenderCommandEncoder, objc_name="useHeaps") +RenderCommandEncoder_useHeaps :: proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { + msgSend(nil, self, "useHeaps:count:", heaps, count) +} +@(objc_type=RenderCommandEncoder, objc_name="useHeaps_count_stages_") +RenderCommandEncoder_useHeaps_count_stages_ :: proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object, stages: RenderStages) { + msgSend(nil, self, "useHeaps:count:stages:", heaps, count, stages) +} +@(objc_type=RenderCommandEncoder, objc_name="useResource") +RenderCommandEncoder_useResource :: proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { + msgSend(nil, self, "useResource:usage:", resource, usage) +} +@(objc_type=RenderCommandEncoder, objc_name="useResource_usage_stages_") +RenderCommandEncoder_useResource_usage_stages_ :: proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { + msgSend(nil, self, "useResource:usage:stages:", resource, usage, stages) +} +@(objc_type=RenderCommandEncoder, objc_name="useResources") +RenderCommandEncoder_useResources :: proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { + msgSend(nil, self, "useResources:count:usage:", resources, count, usage) +} +@(objc_type=RenderCommandEncoder, objc_name="useResources_count_usage_stages_") +RenderCommandEncoder_useResources_count_usage_stages_ :: proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { + msgSend(nil, self, "useResources:count:usage:stages:", resources, count, usage, stages) +} +@(objc_type=RenderCommandEncoder, objc_name="waitForFence") +RenderCommandEncoder_waitForFence :: proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { + msgSend(nil, self, "waitForFence:beforeStages:", fence, stages) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + RenderPipelineState +Class Methods: +Methods: + device + imageblockMemoryLengthForDimensions + imageblockSampleLength + label + maxTotalThreadsPerThreadgroup + supportIndirectCommandBuffers + threadgroupSizeMatchesTileSize +*/ +@(objc_class="MTLRenderPipelineState") +RenderPipelineState :: struct { using _: NS.Object } + +@(objc_type=RenderPipelineState, objc_name="device") +RenderPipelineState_device :: proc(self: ^RenderPipelineState) -> ^RenderPipelineState { + return msgSend(^RenderPipelineState, self, "device") +} +@(objc_type=RenderPipelineState, objc_name="imageblockMemoryLengthForDimensions") +RenderPipelineState_imageblockMemoryLengthForDimensions :: proc(self: ^RenderPipelineState, imageblockDimensions: Size) -> ^RenderPipelineState { + return msgSend(^RenderPipelineState, self, "imageblockMemoryLengthForDimensions:", imageblockDimensions) +} +@(objc_type=RenderPipelineState, objc_name="imageblockSampleLength") +RenderPipelineState_imageblockSampleLength :: proc(self: ^RenderPipelineState) -> NS.Integer { + return msgSend(NS.Integer, self, "imageblockSampleLength") +} +@(objc_type=RenderPipelineState, objc_name="label") +RenderPipelineState_label :: proc(self: ^RenderPipelineState) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=RenderPipelineState, objc_name="maxTotalThreadsPerThreadgroup") +RenderPipelineState_maxTotalThreadsPerThreadgroup :: proc(self: ^RenderPipelineState) -> NS.Integer { + return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +} +@(objc_type=RenderPipelineState, objc_name="supportIndirectCommandBuffers") +RenderPipelineState_supportIndirectCommandBuffers :: proc(self: ^RenderPipelineState) -> BOOL { + return msgSend(BOOL, self, "supportIndirectCommandBuffers") +} +@(objc_type=RenderPipelineState, objc_name="threadgroupSizeMatchesTileSize") +RenderPipelineState_threadgroupSizeMatchesTileSize :: proc(self: ^RenderPipelineState) -> BOOL { + return msgSend(BOOL, self, "threadgroupSizeMatchesTileSize") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Resource +Class Methods: +Methods: + allocatedSize + cpuCacheMode + device + hazardTrackingMode + heap + heapOffset + isAliasable + label + makeAliasable + resourceOptions + setLabel + setPurgeableState + storageMode +*/ +@(objc_class="MTLResource") +Resource :: struct { using _: NS.Object } + +@(objc_type=Resource, objc_name="allocatedSize") +Resource_allocatedSize :: proc(self: ^Resource) -> NS.Integer { + return msgSend(NS.Integer, self, "allocatedSize") +} +@(objc_type=Resource, objc_name="cpuCacheMode") +Resource_cpuCacheMode :: proc(self: ^Resource) -> CPUCacheMode { + return msgSend(CPUCacheMode, self, "cpuCacheMode") +} +@(objc_type=Resource, objc_name="device") +Resource_device :: proc(self: ^Resource) -> ^Resource { + return msgSend(^Resource, self, "device") +} +@(objc_type=Resource, objc_name="hazardTrackingMode") +Resource_hazardTrackingMode :: proc(self: ^Resource) -> HazardTrackingMode { + return msgSend(HazardTrackingMode, self, "hazardTrackingMode") +} +@(objc_type=Resource, objc_name="heap") +Resource_heap :: proc(self: ^Resource) -> ^Resource { + return msgSend(^Resource, self, "heap") +} +@(objc_type=Resource, objc_name="heapOffset") +Resource_heapOffset :: proc(self: ^Resource) -> NS.Integer { + return msgSend(NS.Integer, self, "heapOffset") +} +@(objc_type=Resource, objc_name="isAliasable") +Resource_isAliasable :: proc(self: ^Resource) -> BOOL { + return msgSend(BOOL, self, "isAliasable") +} +@(objc_type=Resource, objc_name="label") +Resource_label :: proc(self: ^Resource) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} +@(objc_type=Resource, objc_name="makeAliasable") +Resource_makeAliasable :: proc(self: ^Resource) { + msgSend(nil, self, "makeAliasable") +} +@(objc_type=Resource, objc_name="resourceOptions") +Resource_resourceOptions :: proc(self: ^Resource) -> ResourceOptions { + return msgSend(ResourceOptions, self, "resourceOptions") +} +@(objc_type=Resource, objc_name="setLabel") +Resource_setLabel :: proc(self: ^Resource, label: ^NS.String) { + msgSend(nil, self, "setLabel:", label) +} +@(objc_type=Resource, objc_name="setPurgeableState") +Resource_setPurgeableState :: proc(self: ^Resource, state: PurgeableState) -> PurgeableState { + return msgSend(PurgeableState, self, "setPurgeableState:", state) +} +@(objc_type=Resource, objc_name="storageMode") +Resource_storageMode :: proc(self: ^Resource) -> StorageMode { + return msgSend(StorageMode, self, "storageMode") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + ResourceStateCommandEncoder +Class Methods: +Methods: + updateFence + updateTextureMapping + updateTextureMapping + updateTextureMappings + waitForFence +*/ +@(objc_class="MTLResourceStateCommandEncoder") +ResourceStateCommandEncoder :: struct { using _: NS.Object } + +@(objc_type=ResourceStateCommandEncoder, objc_name="updateFence") +ResourceStateCommandEncoder_updateFence :: proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "updateFence:", fence) +} +@(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_") +ResourceStateCommandEncoder_updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_ :: proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { + msgSend(nil, self, "updateTextureMapping:mode:indirectBuffer:indirectBufferOffset:", texture, mode, indirectBuffer, indirectBufferOffset) +} +@(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_region_mipLevel_slice_") +ResourceStateCommandEncoder_updateTextureMapping_mode_region_mipLevel_slice_ :: proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, region: Region, mipLevel: NS.Integer, slice: NS.Integer) { + msgSend(nil, self, "updateTextureMapping:mode:region:mipLevel:slice:", texture, mode, region, mipLevel, slice) +} +@(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMappings") +ResourceStateCommandEncoder_updateTextureMappings :: proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, regions: ^Region, mipLevels: NS.Integer, slices: NS.Integer, numRegions: ^NS.Object) { + msgSend(nil, self, "updateTextureMappings:mode:regions:mipLevels:slices:numRegions:", texture, mode, regions, mipLevels, slices, numRegions) +} +@(objc_type=ResourceStateCommandEncoder, objc_name="waitForFence") +ResourceStateCommandEncoder_waitForFence :: proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { + msgSend(nil, self, "waitForFence:", fence) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + SamplerState +Class Methods: +Methods: + device + label +*/ +@(objc_class="MTLSamplerState") +SamplerState :: struct { using _: NS.Object } + +@(objc_type=SamplerState, objc_name="device") +SamplerState_device :: proc(self: ^SamplerState) -> ^SamplerState { + return msgSend(^SamplerState, self, "device") +} +@(objc_type=SamplerState, objc_name="label") +SamplerState_label :: proc(self: ^SamplerState) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + SharedEvent +Class Methods: +Methods: + newSharedEventHandle + notifyListener + setSignaledValue + signaledValue +*/ +@(objc_class="MTLSharedEvent") +SharedEvent :: struct { using _: NS.Object } + +@(objc_type=SharedEvent, objc_name="newSharedEventHandle") +SharedEvent_newSharedEventHandle :: proc(self: ^SharedEvent) -> ^SharedEventHandle { + return msgSend(^SharedEventHandle, self, "newSharedEventHandle") +} +@(objc_type=SharedEvent, objc_name="notifyListener") +SharedEvent_notifyListener :: proc(self: ^SharedEvent, listener: ^SharedEventListener, value: u64, block: SharedEventNotificationBlock) { + msgSend(nil, self, "notifyListener:atValue:block:", listener, value, block) +} +@(objc_type=SharedEvent, objc_name="setSignaledValue") +SharedEvent_setSignaledValue :: proc(self: ^SharedEvent, signaledValue: u64) { + msgSend(nil, self, "setSignaledValue:", signaledValue) +} +@(objc_type=SharedEvent, objc_name="signaledValue") +SharedEvent_signaledValue :: proc(self: ^SharedEvent) -> u64 { + return msgSend(u64, self, "signaledValue") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + Texture +Class Methods: +Methods: + allowGPUOptimizedContents + arrayLength + buffer + bufferBytesPerRow + bufferOffset + depth + firstMipmapInTail + getBytes + getBytes + height + iosurface + iosurfacePlane + isFramebufferOnly + isShareable + isSparse + mipmapLevelCount + newRemoteTextureViewForDevice + newSharedTextureHandle + newTextureViewWithPixelFormat + newTextureViewWithPixelFormat + newTextureViewWithPixelFormat + parentRelativeLevel + parentRelativeSlice + parentTexture + pixelFormat + remoteStorageTexture + replaceRegion + replaceRegion + rootResource + sampleCount + swizzle + tailSizeInBytes + textureType + usage + width +*/ +@(objc_class="MTLTexture") +Texture :: struct { using _: NS.Object } + +@(objc_type=Texture, objc_name="allowGPUOptimizedContents") +Texture_allowGPUOptimizedContents :: proc(self: ^Texture) -> BOOL { + return msgSend(BOOL, self, "allowGPUOptimizedContents") +} +@(objc_type=Texture, objc_name="arrayLength") +Texture_arrayLength :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "arrayLength") +} +@(objc_type=Texture, objc_name="buffer") +Texture_buffer :: proc(self: ^Texture) -> ^Texture { + return msgSend(^Texture, self, "buffer") +} +@(objc_type=Texture, objc_name="bufferBytesPerRow") +Texture_bufferBytesPerRow :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "bufferBytesPerRow") +} +@(objc_type=Texture, objc_name="bufferOffset") +Texture_bufferOffset :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "bufferOffset") +} +@(objc_type=Texture, objc_name="depth") +Texture_depth :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "depth") +} +@(objc_type=Texture, objc_name="firstMipmapInTail") +Texture_firstMipmapInTail :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "firstMipmapInTail") +} +@(objc_type=Texture, objc_name="getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_") +Texture_getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_ :: proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object, region: Region, level: ^NS.Object, slice: ^NS.Object) { + msgSend(nil, self, "getBytes:bytesPerRow:bytesPerImage:fromRegion:mipmapLevel:slice:", pixelBytes, bytesPerRow, bytesPerImage, region, level, slice) +} +@(objc_type=Texture, objc_name="getBytes_bytesPerRow_fromRegion_mipmapLevel_") +Texture_getBytes_bytesPerRow_fromRegion_mipmapLevel_ :: proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, region: Region, level: ^NS.Object) { + msgSend(nil, self, "getBytes:bytesPerRow:fromRegion:mipmapLevel:", pixelBytes, bytesPerRow, region, level) +} +@(objc_type=Texture, objc_name="height") +Texture_height :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "height") +} +@(objc_type=Texture, objc_name="iosurface") +Texture_iosurface :: proc(self: ^Texture) -> IOSurfaceRef { + return msgSend(IOSurfaceRef, self, "iosurface") +} +@(objc_type=Texture, objc_name="iosurfacePlane") +Texture_iosurfacePlane :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "iosurfacePlane") +} +@(objc_type=Texture, objc_name="isFramebufferOnly") +Texture_isFramebufferOnly :: proc(self: ^Texture) -> BOOL { + return msgSend(BOOL, self, "isFramebufferOnly") +} +@(objc_type=Texture, objc_name="isShareable") +Texture_isShareable :: proc(self: ^Texture) -> BOOL { + return msgSend(BOOL, self, "isShareable") +} +@(objc_type=Texture, objc_name="isSparse") +Texture_isSparse :: proc(self: ^Texture) -> BOOL { + return msgSend(BOOL, self, "isSparse") +} +@(objc_type=Texture, objc_name="mipmapLevelCount") +Texture_mipmapLevelCount :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "mipmapLevelCount") +} +@(objc_type=Texture, objc_name="newRemoteTextureViewForDevice") +Texture_newRemoteTextureViewForDevice :: proc(self: ^Texture, device: ^NS.Object) -> ^Texture { + return msgSend(^Texture, self, "newRemoteTextureViewForDevice:", device) +} +@(objc_type=Texture, objc_name="newSharedTextureHandle") +Texture_newSharedTextureHandle :: proc(self: ^Texture) -> ^SharedTextureHandle { + return msgSend(^SharedTextureHandle, self, "newSharedTextureHandle") +} +@(objc_type=Texture, objc_name="newTextureViewWithPixelFormat") +Texture_newTextureViewWithPixelFormat :: proc(self: ^Texture, pixelFormat: PixelFormat) -> ^Texture { + return msgSend(^Texture, self, "newTextureViewWithPixelFormat:", pixelFormat) +} +@(objc_type=Texture, objc_name="newTextureViewWithPixelFormat_textureType_levels_slices_") +Texture_newTextureViewWithPixelFormat_textureType_levels_slices_ :: proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range) -> ^Texture { + return msgSend(^Texture, self, "newTextureViewWithPixelFormat:textureType:levels:slices:", pixelFormat, textureType, levelRange, sliceRange) +} +@(objc_type=Texture, objc_name="newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_") +Texture_newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_ :: proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range, swizzle: TextureSwizzleChannels) -> ^Texture { + return msgSend(^Texture, self, "newTextureViewWithPixelFormat:textureType:levels:slices:swizzle:", pixelFormat, textureType, levelRange, sliceRange, swizzle) +} +@(objc_type=Texture, objc_name="parentRelativeLevel") +Texture_parentRelativeLevel :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "parentRelativeLevel") +} +@(objc_type=Texture, objc_name="parentRelativeSlice") +Texture_parentRelativeSlice :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "parentRelativeSlice") +} +@(objc_type=Texture, objc_name="parentTexture") +Texture_parentTexture :: proc(self: ^Texture) -> ^Texture { + return msgSend(^Texture, self, "parentTexture") +} +@(objc_type=Texture, objc_name="pixelFormat") +Texture_pixelFormat :: proc(self: ^Texture) -> PixelFormat { + return msgSend(PixelFormat, self, "pixelFormat") +} +@(objc_type=Texture, objc_name="remoteStorageTexture") +Texture_remoteStorageTexture :: proc(self: ^Texture) -> ^Texture { + return msgSend(^Texture, self, "remoteStorageTexture") +} +@(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_") +Texture_replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_ :: proc(self: ^Texture, region: Region, level: ^NS.Object, slice: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object) { + msgSend(nil, self, "replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:", region, level, slice, pixelBytes, bytesPerRow, bytesPerImage) +} +@(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_withBytes_bytesPerRow_") +Texture_replaceRegion_mipmapLevel_withBytes_bytesPerRow_ :: proc(self: ^Texture, region: Region, level: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object) { + msgSend(nil, self, "replaceRegion:mipmapLevel:withBytes:bytesPerRow:", region, level, pixelBytes, bytesPerRow) +} +@(objc_type=Texture, objc_name="rootResource") +Texture_rootResource :: proc(self: ^Texture) -> ^Texture { + return msgSend(^Texture, self, "rootResource") +} +@(objc_type=Texture, objc_name="sampleCount") +Texture_sampleCount :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "sampleCount") +} +@(objc_type=Texture, objc_name="swizzle") +Texture_swizzle :: proc(self: ^Texture) -> TextureSwizzleChannels { + return msgSend(TextureSwizzleChannels, self, "swizzle") +} +@(objc_type=Texture, objc_name="tailSizeInBytes") +Texture_tailSizeInBytes :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "tailSizeInBytes") +} +@(objc_type=Texture, objc_name="textureType") +Texture_textureType :: proc(self: ^Texture) -> TextureType { + return msgSend(TextureType, self, "textureType") +} +@(objc_type=Texture, objc_name="usage") +Texture_usage :: proc(self: ^Texture) -> TextureUsage { + return msgSend(TextureUsage, self, "usage") +} +@(objc_type=Texture, objc_name="width") +Texture_width :: proc(self: ^Texture) -> NS.Integer { + return msgSend(NS.Integer, self, "width") +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + VisibleFunctionTable +Class Methods: +Methods: + setFunction + setFunctions +*/ +@(objc_class="MTLVisibleFunctionTable") +VisibleFunctionTable :: struct { using _: NS.Object } + +@(objc_type=VisibleFunctionTable, objc_name="setFunction") +VisibleFunctionTable_setFunction :: proc(self: ^VisibleFunctionTable, function: ^NS.Object, index: ^NS.Object) { + msgSend(nil, self, "setFunction:atIndex:", function, index) +} +@(objc_type=VisibleFunctionTable, objc_name="setFunctions") +VisibleFunctionTable_setFunctions :: proc(self: ^VisibleFunctionTable, functions: ^^NS.Object, range: NS.Range) { + msgSend(nil, self, "setFunctions:withRange:", functions, range) +} diff --git a/vendor/Metal/MetalEnums.odin b/vendor/Metal/MetalEnums.odin new file mode 100644 index 000000000..a0bd7b970 --- /dev/null +++ b/vendor/Metal/MetalEnums.odin @@ -0,0 +1,961 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +AccelerationStructureUsage :: distinct bit_set[AccelerationStructureUsageFlag; NS.UInteger] +AccelerationStructureUsageFlag :: enum NS.UInteger { + Refit = 0, + PreferFastBuild = 1, + ExtendedLimits = 2, +} + +AccelerationStructureInstanceOptions :: distinct bit_set[AccelerationStructureInstanceOption; u32] +AccelerationStructureInstanceOption :: enum u32 { + DisableTriangleCulling = 0, + TriangleFrontFacingWindingCounterClockwise = 1, + Opaque = 2, + NonOpaque = 3, +} + + +DataType :: enum NS.UInteger { + None = 0, + Struct = 1, + Array = 2, + Float = 3, + Float2 = 4, + Float3 = 5, + Float4 = 6, + Float2x2 = 7, + Float2x3 = 8, + Float2x4 = 9, + Float3x2 = 10, + Float3x3 = 11, + Float3x4 = 12, + Float4x2 = 13, + Float4x3 = 14, + Float4x4 = 15, + Half = 16, + Half2 = 17, + Half3 = 18, + Half4 = 19, + Half2x2 = 20, + Half2x3 = 21, + Half2x4 = 22, + Half3x2 = 23, + Half3x3 = 24, + Half3x4 = 25, + Half4x2 = 26, + Half4x3 = 27, + Half4x4 = 28, + Int = 29, + Int2 = 30, + Int3 = 31, + Int4 = 32, + UInt = 33, + UInt2 = 34, + UInt3 = 35, + UInt4 = 36, + Short = 37, + Short2 = 38, + Short3 = 39, + Short4 = 40, + UShort = 41, + UShort2 = 42, + UShort3 = 43, + UShort4 = 44, + Char = 45, + Char2 = 46, + Char3 = 47, + Char4 = 48, + UChar = 49, + UChar2 = 50, + UChar3 = 51, + UChar4 = 52, + Bool = 53, + Bool2 = 54, + Bool3 = 55, + Bool4 = 56, + Texture = 58, + Sampler = 59, + Pointer = 60, + R8Unorm = 62, + R8Snorm = 63, + R16Unorm = 64, + R16Snorm = 65, + RG8Unorm = 66, + RG8Snorm = 67, + RG16Unorm = 68, + RG16Snorm = 69, + RGBA8Unorm = 70, + RGBA8Unorm_sRGB = 71, + RGBA8Snorm = 72, + RGBA16Unorm = 73, + RGBA16Snorm = 74, + RGB10A2Unorm = 75, + RG11B10Float = 76, + RGB9E5Float = 77, + RenderPipeline = 78, + ComputePipeline = 79, + IndirectCommandBuffer = 80, + Long = 81, + Long2 = 82, + Long3 = 83, + Long4 = 84, + ULong = 85, + ULong2 = 86, + ULong3 = 87, + ULong4 = 88, + VisibleFunctionTable = 115, + IntersectionFunctionTable = 116, + PrimitiveAccelerationStructure = 117, + InstanceAccelerationStructure = 118, +} + +ArgumentType :: enum NS.UInteger { + Buffer = 0, + ThreadgroupMemory = 1, + Texture = 2, + Sampler = 3, + ImageblockData = 16, + Imageblock = 17, + VisibleFunctionTable = 24, + PrimitiveAccelerationStructure = 25, + InstanceAccelerationStructure = 26, + IntersectionFunctionTable = 27, +} + +ArgumentAccess :: enum NS.UInteger { + ReadOnly = 0, + ReadWrite = 1, + WriteOnly = 2, +} + + +BinaryArchiveError :: enum NS.UInteger { + None = 0, + InvalidFile = 1, + UnexpectedElement = 2, + CompilationFailure = 3, +} + +BlitOptionFlag :: enum NS.UInteger { + DepthFromDepthStencil = 0, + StencilFromDepthStencil = 1, + RowLinearPVRTC = 2, +} +BlitOption :: distinct bit_set[BlitOptionFlag; NS.UInteger] + +CaptureError :: enum NS.Integer { + NotSupported = 1, + AlreadyCapturing = 2, + InvalidDescriptor = 3, +} + +CaptureDestination :: enum NS.Integer { + DeveloperTools = 1, + GPUTraceDocument = 2, +} + + +CommandBufferStatus :: enum NS.UInteger { + NotEnqueued = 0, + Enqueued = 1, + Committed = 2, + Scheduled = 3, + Completed = 4, + Error = 5, +} + +CommandBufferError :: enum NS.UInteger { + None = 0, + Timeout = 2, + PageFault = 3, + AccessRevoked = 4, + Blacklisted = 4, + NotPermitted = 7, + OutOfMemory = 8, + InvalidResource = 9, + Memoryless = 10, + DeviceRemoved = 11, + StackOverflow = 12, +} + +CommandBufferErrorOptionFlag :: enum NS.UInteger { + EncoderExecutionStatus = 0, +} +CommandBufferErrorOption :: distinct bit_set[CommandBufferErrorOptionFlag; NS.UInteger] + +CommandEncoderErrorState :: enum NS.Integer { + Unknown = 0, + Completed = 1, + Affected = 2, + Pending = 3, + Faulted = 4, +} + +CommandBufferHandler :: distinct rawptr + +DispatchType :: enum NS.UInteger { + Serial = 0, + Concurrent = 1, +} + +ResourceUsageFlag :: enum NS.UInteger { + Read = 0, + Write = 1, + Sample = 2, +} +ResourceUsage :: distinct bit_set[ResourceUsageFlag; NS.UInteger] + + +BarrierScopeFlag :: enum NS.UInteger { + Buffers = 0, + Textures = 1, + RenderTargets = 2, +} +BarrierScope :: distinct bit_set[BarrierScopeFlag; NS.UInteger] + + + +CounterSampleBufferError :: enum NS.Integer { + OutOfMemory = 0, + Invalid = 1, +} + +CompareFunction :: enum NS.UInteger { + Never = 0, + Less = 1, + Equal = 2, + LessEqual = 3, + Greater = 4, + NotEqual = 5, + GreaterEqual = 6, + Always = 7, +} + +StencilOperation :: enum NS.UInteger { + Keep = 0, + Zero = 1, + Replace = 2, + IncrementClamp = 3, + DecrementClamp = 4, + Invert = 5, + IncrementWrap = 6, + DecrementWrap = 7, +} + +FeatureSet :: enum NS.UInteger { + iOS_GPUFamily1_v1 = 0, + iOS_GPUFamily2_v1 = 1, + iOS_GPUFamily1_v2 = 2, + iOS_GPUFamily2_v2 = 3, + iOS_GPUFamily3_v1 = 4, + iOS_GPUFamily1_v3 = 5, + iOS_GPUFamily2_v3 = 6, + iOS_GPUFamily3_v2 = 7, + iOS_GPUFamily1_v4 = 8, + iOS_GPUFamily2_v4 = 9, + iOS_GPUFamily3_v3 = 10, + iOS_GPUFamily4_v1 = 11, + iOS_GPUFamily1_v5 = 12, + iOS_GPUFamily2_v5 = 13, + iOS_GPUFamily3_v4 = 14, + iOS_GPUFamily4_v2 = 15, + iOS_GPUFamily5_v1 = 16, + macOS_GPUFamily1_v1 = 10000, + OSX_GPUFamily1_v1 = 10000, + macOS_GPUFamily1_v2 = 10001, + OSX_GPUFamily1_v2 = 10001, + OSX_ReadWriteTextureTier2 = 10002, + macOS_ReadWriteTextureTier2 = 10002, + macOS_GPUFamily1_v3 = 10003, + macOS_GPUFamily1_v4 = 10004, + macOS_GPUFamily2_v1 = 10005, + watchOS_GPUFamily1_v1 = 20000, + WatchOS_GPUFamily1_v1 = 20000, + watchOS_GPUFamily2_v1 = 20001, + WatchOS_GPUFamily2_v1 = 20001, + tvOS_GPUFamily1_v1 = 30000, + TVOS_GPUFamily1_v1 = 30000, + tvOS_GPUFamily1_v2 = 30001, + tvOS_GPUFamily1_v3 = 30002, + tvOS_GPUFamily2_v1 = 30003, + tvOS_GPUFamily1_v4 = 30004, + tvOS_GPUFamily2_v2 = 30005, +} + +GPUFamily :: enum NS.Integer { + Apple1 = 1001, + Apple2 = 1002, + Apple3 = 1003, + Apple4 = 1004, + Apple5 = 1005, + Apple6 = 1006, + Apple7 = 1007, + Apple8 = 1008, + Mac1 = 2001, + Mac2 = 2002, + Common1 = 3001, + Common2 = 3002, + Common3 = 3003, + MacCatalyst1 = 4001, + MacCatalyst2 = 4002, +} + +DeviceLocation :: enum NS.UInteger { + BuiltIn = 0, + Slot = 1, + External = 2, + Unspecified = NS.UIntegerMax, +} + +PipelineOptionFlag :: enum NS.UInteger { + ArgumentInfo = 0, + BufferTypeInfo = 1, + FailOnBinaryArchiveMiss = 2, +} +PipelineOption :: distinct bit_set[PipelineOptionFlag; NS.UInteger] + +ReadWriteTextureTier :: enum NS.UInteger { + TierNone = 0, + Tier1 = 1, + Tier2 = 2, +} + +ArgumentBuffersTier :: enum NS.UInteger { + Tier1 = 0, + Tier2 = 1, +} + +SparseTextureRegionAlignmentMode :: enum NS.UInteger { + Outward = 0, + Inward = 1, +} + +CounterSamplingPoint :: enum NS.UInteger { + AtStageBoundary = 0, + AtDrawBoundary = 1, + AtDispatchBoundary = 2, + AtTileDispatchBoundary = 3, + AtBlitBoundary = 4, +} + +DynamicLibraryError :: enum NS.UInteger { + None = 0, + InvalidFile = 1, + CompilationFailure = 2, + UnresolvedInstallName = 3, + DependencyLoadFailure = 4, + Unsupported = 5, +} + +FunctionOption :: enum NS.UInteger { + CompileToBinary = 0, +} +FunctionOptions :: distinct bit_set[FunctionOption; NS.UInteger] + + +FunctionLogType :: enum NS.UInteger { + Validation = 0, +} + +HeapType :: enum NS.Integer { + Automatic = 0, + Placement = 1, + Sparse = 2, +} + +IndirectCommandTypeFlag :: enum NS.UInteger { + Draw = 0, + DrawIndexed = 1, + DrawPatches = 2, + DrawIndexedPatches = 3, + ConcurrentDispatch = 5, + ConcurrentDispatchThreads = 6, +} +IndirectCommandType :: distinct bit_set[IndirectCommandTypeFlag; NS.UInteger] + +IntersectionFunctionSignatureFlag :: enum NS.UInteger { + Instancing = 0, + TriangleData = 1, + WorldSpaceData = 2, + InstanceMotion = 3, + PrimitiveMotion = 4, + ExtendedLimits = 5, +} +IntersectionFunctionSignature :: distinct bit_set[IntersectionFunctionSignatureFlag; NS.UInteger] + +PatchType :: enum NS.UInteger { + None = 0, + Triangle = 1, + Quad = 2, +} + +FunctionType :: enum NS.UInteger { + Vertex = 1, + Fragment = 2, + Kernel = 3, + Visible = 5, + Intersection = 6, +} + + +LanguageVersion :: enum NS.UInteger { + Version1_0 = 65536, + Version1_1 = 65537, + Version1_2 = 65538, + Version2_0 = 131072, + Version2_1 = 131073, + Version2_2 = 131074, + Version2_3 = 131075, + Version2_4 = 131076, +} + +LibraryType :: enum NS.Integer { + Executable = 0, + Dynamic = 1, +} + +LibraryError :: enum NS.UInteger { + Unsupported = 1, + CompileFailure = 3, + CompileWarning = 4, + FunctionNotFound = 5, + FileNotFound = 6, +} + +Mutability :: enum NS.UInteger { + Default = 0, + Mutable = 1, + Immutable = 2, +} + +PixelFormat :: enum NS.UInteger { + Invalid = 0, + A8Unorm = 1, + R8Unorm = 10, + R8Unorm_sRGB = 11, + R8Snorm = 12, + R8Uint = 13, + R8Sint = 14, + R16Unorm = 20, + R16Snorm = 22, + R16Uint = 23, + R16Sint = 24, + R16Float = 25, + RG8Unorm = 30, + RG8Unorm_sRGB = 31, + RG8Snorm = 32, + RG8Uint = 33, + RG8Sint = 34, + B5G6R5Unorm = 40, + A1BGR5Unorm = 41, + ABGR4Unorm = 42, + BGR5A1Unorm = 43, + R32Uint = 53, + R32Sint = 54, + R32Float = 55, + RG16Unorm = 60, + RG16Snorm = 62, + RG16Uint = 63, + RG16Sint = 64, + RG16Float = 65, + RGBA8Unorm = 70, + RGBA8Unorm_sRGB = 71, + RGBA8Snorm = 72, + RGBA8Uint = 73, + RGBA8Sint = 74, + BGRA8Unorm = 80, + BGRA8Unorm_sRGB = 81, + RGB10A2Unorm = 90, + RGB10A2Uint = 91, + RG11B10Float = 92, + RGB9E5Float = 93, + BGR10A2Unorm = 94, + RG32Uint = 103, + RG32Sint = 104, + RG32Float = 105, + RGBA16Unorm = 110, + RGBA16Snorm = 112, + RGBA16Uint = 113, + RGBA16Sint = 114, + RGBA16Float = 115, + RGBA32Uint = 123, + RGBA32Sint = 124, + RGBA32Float = 125, + BC1_RGBA = 130, + BC1_RGBA_sRGB = 131, + BC2_RGBA = 132, + BC2_RGBA_sRGB = 133, + BC3_RGBA = 134, + BC3_RGBA_sRGB = 135, + BC4_RUnorm = 140, + BC4_RSnorm = 141, + BC5_RGUnorm = 142, + BC5_RGSnorm = 143, + BC6H_RGBFloat = 150, + BC6H_RGBUfloat = 151, + BC7_RGBAUnorm = 152, + BC7_RGBAUnorm_sRGB = 153, + PVRTC_RGB_2BPP = 160, + PVRTC_RGB_2BPP_sRGB = 161, + PVRTC_RGB_4BPP = 162, + PVRTC_RGB_4BPP_sRGB = 163, + PVRTC_RGBA_2BPP = 164, + PVRTC_RGBA_2BPP_sRGB = 165, + PVRTC_RGBA_4BPP = 166, + PVRTC_RGBA_4BPP_sRGB = 167, + EAC_R11Unorm = 170, + EAC_R11Snorm = 172, + EAC_RG11Unorm = 174, + EAC_RG11Snorm = 176, + EAC_RGBA8 = 178, + EAC_RGBA8_sRGB = 179, + ETC2_RGB8 = 180, + ETC2_RGB8_sRGB = 181, + ETC2_RGB8A1 = 182, + ETC2_RGB8A1_sRGB = 183, + ASTC_4x4_sRGB = 186, + ASTC_5x4_sRGB = 187, + ASTC_5x5_sRGB = 188, + ASTC_6x5_sRGB = 189, + ASTC_6x6_sRGB = 190, + ASTC_8x5_sRGB = 192, + ASTC_8x6_sRGB = 193, + ASTC_8x8_sRGB = 194, + ASTC_10x5_sRGB = 195, + ASTC_10x6_sRGB = 196, + ASTC_10x8_sRGB = 197, + ASTC_10x10_sRGB = 198, + ASTC_12x10_sRGB = 199, + ASTC_12x12_sRGB = 200, + ASTC_4x4_LDR = 204, + ASTC_5x4_LDR = 205, + ASTC_5x5_LDR = 206, + ASTC_6x5_LDR = 207, + ASTC_6x6_LDR = 208, + ASTC_8x5_LDR = 210, + ASTC_8x6_LDR = 211, + ASTC_8x8_LDR = 212, + ASTC_10x5_LDR = 213, + ASTC_10x6_LDR = 214, + ASTC_10x8_LDR = 215, + ASTC_10x10_LDR = 216, + ASTC_12x10_LDR = 217, + ASTC_12x12_LDR = 218, + ASTC_4x4_HDR = 222, + ASTC_5x4_HDR = 223, + ASTC_5x5_HDR = 224, + ASTC_6x5_HDR = 225, + ASTC_6x6_HDR = 226, + ASTC_8x5_HDR = 228, + ASTC_8x6_HDR = 229, + ASTC_8x8_HDR = 230, + ASTC_10x5_HDR = 231, + ASTC_10x6_HDR = 232, + ASTC_10x8_HDR = 233, + ASTC_10x10_HDR = 234, + ASTC_12x10_HDR = 235, + ASTC_12x12_HDR = 236, + GBGR422 = 240, + BGRG422 = 241, + Depth16Unorm = 250, + Depth32Float = 252, + Stencil8 = 253, + Depth24Unorm_Stencil8 = 255, + Depth32Float_Stencil8 = 260, + X32_Stencil8 = 261, + X24_Stencil8 = 262, + BGRA10_XR = 552, + BGRA10_XR_sRGB = 553, + BGR10_XR = 554, + BGR10_XR_sRGB = 555, +} + + +PrimitiveType :: enum NS.UInteger { + Point = 0, + Line = 1, + LineStrip = 2, + Triangle = 3, + TriangleStrip = 4, +} + +VisibilityResultMode :: enum NS.UInteger { + Disabled = 0, + Boolean = 1, + Counting = 2, +} + +CullMode :: enum NS.UInteger { + None = 0, + Front = 1, + Back = 2, +} + +Winding :: enum NS.UInteger { + Clockwise = 0, + CounterClockwise = 1, +} + +DepthClipMode :: enum NS.UInteger { + Clip = 0, + Clamp = 1, +} + +TriangleFillMode :: enum NS.UInteger { + Fill = 0, + Lines = 1, +} + +RenderStage :: enum NS.UInteger { + Vertex = 0, + Fragment = 1, + Tile = 2, +} +RenderStages :: distinct bit_set[RenderStage; NS.UInteger] + + +LoadAction :: enum NS.UInteger { + DontCare = 0, + Load = 1, + Clear = 2, +} + +StoreAction :: enum NS.UInteger { + DontCare = 0, + Store = 1, + MultisampleResolve = 2, + StoreAndMultisampleResolve = 3, + Unknown = 4, + CustomSampleDepthStore = 5, +} + +StoreActionOption :: enum NS.UInteger { + CustomSamplePositions = 1, +} +StoreActionOptions :: distinct bit_set[StoreActionOption; NS.UInteger] + +MultisampleDepthResolveFilter :: enum NS.UInteger { + Sample0 = 0, + Min = 1, + Max = 2, +} + +MultisampleStencilResolveFilter :: enum NS.UInteger { + Sample0 = 0, + DepthResolvedSample = 1, +} + +BlendFactor :: enum NS.UInteger { + Zero = 0, + One = 1, + SourceColor = 2, + OneMinusSourceColor = 3, + SourceAlpha = 4, + OneMinusSourceAlpha = 5, + DestinationColor = 6, + OneMinusDestinationColor = 7, + DestinationAlpha = 8, + OneMinusDestinationAlpha = 9, + SourceAlphaSaturated = 10, + BlendColor = 11, + OneMinusBlendColor = 12, + BlendAlpha = 13, + OneMinusBlendAlpha = 14, + Source1Color = 15, + OneMinusSource1Color = 16, + Source1Alpha = 17, + OneMinusSource1Alpha = 18, +} + +BlendOperation :: enum NS.UInteger { + Add = 0, + Subtract = 1, + ReverseSubtract = 2, + Min = 3, + Max = 4, +} + +ColorWriteMaskFlag :: enum NS.UInteger { + Alpha = 0, + Blue = 1, + Green = 2, + Red = 3, +} +ColorWriteMask :: distinct bit_set[ColorWriteMaskFlag; NS.UInteger] +ColorWriteMaskAll :: ColorWriteMask{.Alpha, .Blue, .Green, .Red} + +PrimitiveTopologyClass :: enum NS.UInteger { + Unspecified = 0, + Point = 1, + Line = 2, + Triangle = 3, +} + +TessellationPartitionMode :: enum NS.UInteger { + Pow2 = 0, + Integer = 1, + FractionalOdd = 2, + FractionalEven = 3, +} + +TessellationFactorStepFunction :: enum NS.UInteger { + Constant = 0, + PerPatch = 1, + PerInstance = 2, + PerPatchAndPerInstance = 3, +} + +TessellationFactorFormat :: enum NS.UInteger { + Half = 0, +} + +TessellationControlPointIndexType :: enum NS.UInteger { + None = 0, + UInt16 = 1, + UInt32 = 2, +} + +PurgeableState :: enum NS.UInteger { + KeepCurrent = 1, + NonVolatile = 2, + Volatile = 3, + Empty = 4, +} + +CPUCacheMode :: enum NS.UInteger { + DefaultCache = 0, + WriteCombined = 1, +} + +StorageMode :: enum NS.UInteger { + Shared = 0, + Managed = 1, + Private = 2, + Memoryless = 3, +} + +HazardTrackingMode :: enum NS.UInteger { + Default = 0, + Untracked = 1, + Tracked = 2, +} + +ResourceOption :: enum NS.UInteger { + CPUCacheModeWriteCombined = 0, + StorageModeManaged = 4, + StorageModePrivate = 5, + HazardTrackingModeUntracked = 8, + HazardTrackingModeTracked = 9, +} +ResourceOptions :: distinct bit_set[ResourceOption; NS.UInteger] + +ResourceStorageModeShared :: ResourceOptions{} +ResourceHazardTrackingModeDefault :: ResourceOptions{} +ResourceCPUCacheModeDefaultCache :: ResourceOptions{} +ResourceOptionCPUCacheModeDefault :: ResourceOptions{} +ResourceStorageModeMemoryless :: ResourceOptions{.StorageModeManaged, .StorageModePrivate} + +SparseTextureMappingMode :: enum NS.UInteger { + Map = 0, + Unmap = 1, +} + +SamplerMinMagFilter :: enum NS.UInteger { + Nearest = 0, + Linear = 1, +} + +SamplerMipFilter :: enum NS.UInteger { + NotMipmapped = 0, + Nearest = 1, + Linear = 2, +} + +SamplerAddressMode :: enum NS.UInteger { + ClampToEdge = 0, + MirrorClampToEdge = 1, + Repeat = 2, + MirrorRepeat = 3, + ClampToZero = 4, + ClampToBorderColor = 5, +} + +SamplerBorderColor :: enum NS.UInteger { + TransparentBlack = 0, + OpaqueBlack = 1, + OpaqueWhite = 2, +} + + +AttributeFormat :: enum NS.UInteger { + Invalid = 0, + UChar2 = 1, + UChar3 = 2, + UChar4 = 3, + Char2 = 4, + Char3 = 5, + Char4 = 6, + UChar2Normalized = 7, + UChar3Normalized = 8, + UChar4Normalized = 9, + Char2Normalized = 10, + Char3Normalized = 11, + Char4Normalized = 12, + UShort2 = 13, + UShort3 = 14, + UShort4 = 15, + Short2 = 16, + Short3 = 17, + Short4 = 18, + UShort2Normalized = 19, + UShort3Normalized = 20, + UShort4Normalized = 21, + Short2Normalized = 22, + Short3Normalized = 23, + Short4Normalized = 24, + Half2 = 25, + Half3 = 26, + Half4 = 27, + Float = 28, + Float2 = 29, + Float3 = 30, + Float4 = 31, + Int = 32, + Int2 = 33, + Int3 = 34, + Int4 = 35, + UInt = 36, + UInt2 = 37, + UInt3 = 38, + UInt4 = 39, + Int1010102Normalized = 40, + UInt1010102Normalized = 41, + UChar4Normalized_BGRA = 42, + UChar = 45, + Char = 46, + UCharNormalized = 47, + CharNormalized = 48, + UShort = 49, + Short = 50, + UShortNormalized = 51, + ShortNormalized = 52, + Half = 53, +} + +IndexType :: enum NS.UInteger { + UInt16 = 0, + UInt32 = 1, +} + +StepFunction :: enum NS.UInteger { + Constant = 0, + PerVertex = 1, + PerInstance = 2, + PerPatch = 3, + PerPatchControlPoint = 4, + ThreadPositionInGridX = 5, + ThreadPositionInGridY = 6, + ThreadPositionInGridXIndexed = 7, + ThreadPositionInGridYIndexed = 8, +} + +TextureType :: enum NS.UInteger { + Type1D = 0, + Type1DArray = 1, + Type2D = 2, + Type2DArray = 3, + Type2DMultisample = 4, + TypeCube = 5, + TypeCubeArray = 6, + Type3D = 7, + Type2DMultisampleArray = 8, + TypeTextureBuffer = 9, +} + +TextureSwizzle :: enum u8 { + Zero = 0, + One = 1, + Red = 2, + Green = 3, + Blue = 4, + Alpha = 5, +} + +TextureUsageFlag :: enum NS.UInteger { + ShaderRead = 0, + ShaderWrite = 1, + RenderTarget = 2, + PixelFormatView = 4, +} +TextureUsage :: distinct bit_set[TextureUsageFlag; NS.UInteger] + +TextureCompressionType :: enum NS.Integer { + Lossless = 0, + Lossy = 1, +} + +VertexFormat :: enum NS.UInteger { + Invalid = 0, + UChar2 = 1, + UChar3 = 2, + UChar4 = 3, + Char2 = 4, + Char3 = 5, + Char4 = 6, + UChar2Normalized = 7, + UChar3Normalized = 8, + UChar4Normalized = 9, + Char2Normalized = 10, + Char3Normalized = 11, + Char4Normalized = 12, + UShort2 = 13, + UShort3 = 14, + UShort4 = 15, + Short2 = 16, + Short3 = 17, + Short4 = 18, + UShort2Normalized = 19, + UShort3Normalized = 20, + UShort4Normalized = 21, + Short2Normalized = 22, + Short3Normalized = 23, + Short4Normalized = 24, + Half2 = 25, + Half3 = 26, + Half4 = 27, + Float = 28, + Float2 = 29, + Float3 = 30, + Float4 = 31, + Int = 32, + Int2 = 33, + Int3 = 34, + Int4 = 35, + UInt = 36, + UInt2 = 37, + UInt3 = 38, + UInt4 = 39, + Int1010102Normalized = 40, + UInt1010102Normalized = 41, + UChar4Normalized_BGRA = 42, + UChar = 45, + Char = 46, + UCharNormalized = 47, + CharNormalized = 48, + UShort = 49, + Short = 50, + UShortNormalized = 51, + ShortNormalized = 52, + Half = 53, +} + +VertexStepFunction :: enum NS.UInteger { + Constant = 0, + PerVertex = 1, + PerInstance = 2, + PerPatch = 3, + PerPatchControlPoint = 4, +} diff --git a/vendor/Metal/MetalErrors.odin b/vendor/Metal/MetalErrors.odin new file mode 100644 index 000000000..5909b35e4 --- /dev/null +++ b/vendor/Metal/MetalErrors.odin @@ -0,0 +1,39 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +foreign import "system:Metal.framework" + +CommonCounter :: ^NS.String +CommonCounterSet :: ^NS.String +DeviceNotificationName :: ^NS.String + +foreign Metal { + @(linkage="weak") CommonCounterTimestamp: CommonCounter + @(linkage="weak") CommonCounterTessellationInputPatches: CommonCounter + @(linkage="weak") CommonCounterVertexInvocations: CommonCounter + @(linkage="weak") CommonCounterPostTessellationVertexInvocations: CommonCounter + @(linkage="weak") CommonCounterClipperInvocations: CommonCounter + @(linkage="weak") CommonCounterClipperPrimitivesOut: CommonCounter + @(linkage="weak") CommonCounterFragmentInvocations: CommonCounter + @(linkage="weak") CommonCounterFragmentsPassed: CommonCounter + @(linkage="weak") CommonCounterComputeKernelInvocations: CommonCounter + @(linkage="weak") CommonCounterTotalCycles: CommonCounter + @(linkage="weak") CommonCounterVertexCycles: CommonCounter + @(linkage="weak") CommonCounterTessellationCycles: CommonCounter + @(linkage="weak") CommonCounterPostTessellationVertexCycles: CommonCounter + @(linkage="weak") CommonCounterFragmentCycles: CommonCounter + @(linkage="weak") CommonCounterRenderTargetWriteCycles: CommonCounter +} + +foreign Metal { + @(linkage="weak") CommonCounterSetTimestamp: CommonCounterSet + @(linkage="weak") CommonCounterSetStageUtilization: CommonCounterSet + @(linkage="weak") CommonCounterSetStatistic: CommonCounterSet +} + +foreign Metal { + @(linkage="weak") DeviceWasAddedNotification: DeviceNotificationName + @(linkage="weak") DeviceRemovalRequestedNotification: DeviceNotificationName + @(linkage="weak") DeviceWasRemovedNotification: DeviceNotificationName +} \ No newline at end of file diff --git a/vendor/Metal/MetalTypes.odin b/vendor/Metal/MetalTypes.odin new file mode 100644 index 000000000..c8c02e5f2 --- /dev/null +++ b/vendor/Metal/MetalTypes.odin @@ -0,0 +1,198 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" +import "core:intrinsics" + +BOOL :: NS.BOOL + +CFTimeInterval :: NS.TimeInterval + +IOSurfaceRef :: distinct rawptr + +@(private) +msgSend :: intrinsics.objc_send + +AccelerationStructureInstanceDescriptor :: struct { + transformationMatrix: PackedFloat4x3, + options: AccelerationStructureInstanceOptions, + mask: u32, + intersectionFunctionTableOffset: u32, + accelerationStructureIndex: u32, +} + +AccelerationStructureSizes :: struct { + accelerationStructureSize: NS.Integer, + buildScratchBufferSize: NS.Integer, + refitScratchBufferSize: NS.Integer, +} + +AxisAlignedBoundingBox :: struct { + min: PackedFloat3, + max: PackedFloat3, +} + +ClearColor :: struct { + red: f64, + green: f64, + blue: f64, + alpha: f64, +} + +Coordinate2D :: struct { + x: f32, + y: f32, +} + +CounterResultStageUtilization :: struct { + totalCycles: u64, + vertexCycles: u64, + tessellationCycles: u64, + postTessellationVertexCycles: u64, + fragmentCycles: u64, + renderTargetCycles: u64, +} + +CounterResultStatistic :: struct { + tessellationInputPatches: u64, + vertexInvocations: u64, + postTessellationVertexInvocations: u64, + clipperInvocations: u64, + clipperPrimitivesOut: u64, + fragmentInvocations: u64, + fragmentsPassed: u64, + computeKernelInvocations: u64, +} + +CounterResultTimestamp :: struct { + timestamp: u64, +} + +DispatchThreadgroupsIndirectArguments :: struct { + threadgroupsPerGrid: [3]u32, +} + +DrawIndexedPrimitivesIndirectArguments :: struct { + indexCount: u32, + instanceCount: u32, + indexStart: u32, + baseVertex: i32, + baseInstance: u32, +} + +DrawPatchIndirectArguments :: struct { + patchCount: u32, + instanceCount: u32, + patchStart: u32, + baseInstance: u32, +} + +DrawPrimitivesIndirectArguments :: struct { + vertexCount: u32, + instanceCount: u32, + vertexStart: u32, + baseInstance: u32, +} + +IndirectCommandBufferExecutionRange :: struct { + location: u32, + length: u32, +} + +MapIndirectArguments :: struct { + regionOriginX: u32, + regionOriginY: u32, + regionOriginZ: u32, + regionSizeWidth: u32, + regionSizeHeight: u32, + regionSizeDepth: u32, + mipMapLevel: u32, + sliceId: u32, +} + +Origin :: distinct [3]NS.Integer + +PackedFloat3 :: distinct [3]f32 + +PackedFloat4x3 :: struct { + columns: [4]PackedFloat3, +} + +QuadTessellationFactorsHalf :: struct { + edgeTessellationFactor: [4]u16, + insideTessellationFactor: [2]u16, +} + +Region :: struct { + origin: Origin, + size: Size, +} + +SamplePosition :: struct { + x: f32, + y: f32, +} + +ScissorRect :: struct { + x: NS.Integer, + y: NS.Integer, + width: NS.Integer, + height: NS.Integer, +} + +Size :: struct { + width: NS.Integer, + height: NS.Integer, + depth: NS.Integer, +} + +SizeAndAlign :: struct { + size: NS.Integer, + align: NS.Integer, +} + +StageInRegionIndirectArguments :: struct { + stageInOrigin: [3]u32, + stageInSize: [3]u32, +} + +TextureSwizzleChannels :: struct { + red: TextureSwizzle, + green: TextureSwizzle, + blue: TextureSwizzle, + alpha: TextureSwizzle, +} + +TriangleTessellationFactorsHalf :: struct { + edgeTessellationFactor: [3]u16, + insideTessellationFactor: u16, +} + +VertexAmplificationViewMapping :: struct { + viewportArrayIndexOffset: u32, + renderTargetArrayIndexOffset: u32, +} + +Viewport :: struct { + originX: f64, + originY: f64, + width: f64, + height: f64, + znear: f64, + zfar: f64, +} + +Timestamp :: distinct u64 + +DeviceNotificationHandler :: distinct rawptr +AutoreleasedComputePipelineReflection :: ^ComputePipelineReflection +AutoreleasedRenderPipelineReflection :: ^RenderPipelineReflection +NewLibraryCompletionHandler :: distinct rawptr +NewRenderPipelineStateCompletionHandler :: distinct rawptr +NewRenderPipelineStateWithReflectionCompletionHandler :: distinct rawptr +NewComputePipelineStateCompletionHandler :: distinct rawptr +NewComputePipelineStateWithReflectionCompletionHandler :: distinct rawptr +SharedEventNotificationBlock :: distinct rawptr + +DrawablePresentedHandler :: distinct rawptr + +AutoreleasedArgument :: ^Argument \ No newline at end of file diff --git a/vendor/Metal/NSBuffer.odin b/vendor/Metal/NSBuffer.odin deleted file mode 100644 index 9f7a83c1a..000000000 --- a/vendor/Metal/NSBuffer.odin +++ /dev/null @@ -1,5 +0,0 @@ -package objc_Metal - -import NS "core:sys/darwin/Foundation" - -Buffer :: struct { using _: Resource } \ No newline at end of file diff --git a/vendor/Metal/NSResource.odin b/vendor/Metal/NSResource.odin deleted file mode 100644 index 34bc0267c..000000000 --- a/vendor/Metal/NSResource.odin +++ /dev/null @@ -1,5 +0,0 @@ -package objc_Metal - -import NS "core:sys/darwin/Foundation" - -Resource :: struct { using _: NS.Object } \ No newline at end of file From ae3b95b194bffc9e9f77e70d4e2b6f33373e39aa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 17:46:19 +0000 Subject: [PATCH 0136/1052] `#force_inline` procedures and move foreign procedures to a separate file --- vendor/Metal/MetalClasses.odin | 2652 ++++++++++++++--------------- vendor/Metal/MetalProcedures.odin | 14 + 2 files changed, 1333 insertions(+), 1333 deletions(-) create mode 100644 vendor/Metal/MetalProcedures.odin diff --git a/vendor/Metal/MetalClasses.odin b/vendor/Metal/MetalClasses.odin index 138677d0d..4f788cb55 100644 --- a/vendor/Metal/MetalClasses.odin +++ b/vendor/Metal/MetalClasses.odin @@ -2,20 +2,6 @@ package objc_Metal import NS "core:sys/darwin/Foundation" -foreign import "system:Metal.framework" - -@(default_calling_convention="c", link_prefix="MTL") -foreign Metal { - CopyAllDevices :: proc() -> ^NS.Array --- - CopyAllDevicesWithObserver :: proc(observer: ^^NS.Object, handler: DeviceNotificationHandler) -> ^NS.Array --- - CreateSystemDefaultDevice :: proc() -> ^NS.Object --- - RemoveDeviceObserver :: proc(observer: ^NS.Object) --- -} - - - - - //////////////////////////////////////////////////////////////////////////////// /* @@ -39,47 +25,47 @@ Methods: AccelerationStructureBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureBoundingBoxGeometryDescriptor) } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="alloc") -AccelerationStructureBoundingBoxGeometryDescriptor_alloc :: proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { +AccelerationStructureBoundingBoxGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, AccelerationStructureBoundingBoxGeometryDescriptor, "alloc") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="init") -AccelerationStructureBoundingBoxGeometryDescriptor_init :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^AccelerationStructureBoundingBoxGeometryDescriptor { +AccelerationStructureBoundingBoxGeometryDescriptor_init :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^AccelerationStructureBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, self, "init") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxBuffer") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^AccelerationStructureBoundingBoxGeometryDescriptor { +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^AccelerationStructureBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, self, "boundingBoxBuffer") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxBufferOffset") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "boundingBoxBufferOffset") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxCount") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "boundingBoxCount") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxStride") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "boundingBoxStride") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="descriptor") -AccelerationStructureBoundingBoxGeometryDescriptor_descriptor :: proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { +AccelerationStructureBoundingBoxGeometryDescriptor_descriptor :: #force_inline proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, AccelerationStructureBoundingBoxGeometryDescriptor, "descriptor") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxBuffer") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBuffer :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBuffer: ^NS.Object) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBuffer :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBuffer: ^NS.Object) { msgSend(nil, self, "setBoundingBoxBuffer:", boundingBoxBuffer) } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxBufferOffset") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBufferOffset :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBufferOffset: NS.Integer) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBufferOffset :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBufferOffset: NS.Integer) { msgSend(nil, self, "setBoundingBoxBufferOffset:", boundingBoxBufferOffset) } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxCount") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxCount :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxCount: NS.Integer) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxCount :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxCount: NS.Integer) { msgSend(nil, self, "setBoundingBoxCount:", boundingBoxCount) } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxStride") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxStride :: proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxStride: NS.Integer) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxStride :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxStride: NS.Integer) { msgSend(nil, self, "setBoundingBoxStride:", boundingBoxStride) } @@ -99,19 +85,19 @@ Methods: AccelerationStructureDescriptor :: struct { using _: NS.Copying(AccelerationStructureDescriptor) } @(objc_type=AccelerationStructureDescriptor, objc_class_name="alloc") -AccelerationStructureDescriptor_alloc :: proc() -> ^AccelerationStructureDescriptor { +AccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureDescriptor { return msgSend(^AccelerationStructureDescriptor, AccelerationStructureDescriptor, "alloc") } @(objc_type=AccelerationStructureDescriptor, objc_name="init") -AccelerationStructureDescriptor_init :: proc(self: ^AccelerationStructureDescriptor) -> ^AccelerationStructureDescriptor { +AccelerationStructureDescriptor_init :: #force_inline proc(self: ^AccelerationStructureDescriptor) -> ^AccelerationStructureDescriptor { return msgSend(^AccelerationStructureDescriptor, self, "init") } @(objc_type=AccelerationStructureDescriptor, objc_name="setUsage") -AccelerationStructureDescriptor_setUsage :: proc(self: ^AccelerationStructureDescriptor, usage: AccelerationStructureUsage) { +AccelerationStructureDescriptor_setUsage :: #force_inline proc(self: ^AccelerationStructureDescriptor, usage: AccelerationStructureUsage) { msgSend(nil, self, "setUsage:", usage) } @(objc_type=AccelerationStructureDescriptor, objc_name="usage") -AccelerationStructureDescriptor_usage :: proc(self: ^AccelerationStructureDescriptor) -> AccelerationStructureUsage { +AccelerationStructureDescriptor_usage :: #force_inline proc(self: ^AccelerationStructureDescriptor) -> AccelerationStructureUsage { return msgSend(AccelerationStructureUsage, self, "usage") } @@ -135,35 +121,35 @@ Methods: AccelerationStructureGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureGeometryDescriptor) } @(objc_type=AccelerationStructureGeometryDescriptor, objc_class_name="alloc") -AccelerationStructureGeometryDescriptor_alloc :: proc() -> ^AccelerationStructureGeometryDescriptor { +AccelerationStructureGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureGeometryDescriptor { return msgSend(^AccelerationStructureGeometryDescriptor, AccelerationStructureGeometryDescriptor, "alloc") } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="init") -AccelerationStructureGeometryDescriptor_init :: proc(self: ^AccelerationStructureGeometryDescriptor) -> ^AccelerationStructureGeometryDescriptor { +AccelerationStructureGeometryDescriptor_init :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor) -> ^AccelerationStructureGeometryDescriptor { return msgSend(^AccelerationStructureGeometryDescriptor, self, "init") } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="allowDuplicateIntersectionFunctionInvocation") -AccelerationStructureGeometryDescriptor_allowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { +AccelerationStructureGeometryDescriptor_allowDuplicateIntersectionFunctionInvocation :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { return msgSend(BOOL, self, "allowDuplicateIntersectionFunctionInvocation") } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="intersectionFunctionTableOffset") -AccelerationStructureGeometryDescriptor_intersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor) -> NS.Integer { +AccelerationStructureGeometryDescriptor_intersectionFunctionTableOffset :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "intersectionFunctionTableOffset") } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="opaque") -AccelerationStructureGeometryDescriptor_opaque :: proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { +AccelerationStructureGeometryDescriptor_opaque :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { return msgSend(BOOL, self, "opaque") } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setAllowDuplicateIntersectionFunctionInvocation") -AccelerationStructureGeometryDescriptor_setAllowDuplicateIntersectionFunctionInvocation :: proc(self: ^AccelerationStructureGeometryDescriptor, allowDuplicateIntersectionFunctionInvocation: BOOL) { +AccelerationStructureGeometryDescriptor_setAllowDuplicateIntersectionFunctionInvocation :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor, allowDuplicateIntersectionFunctionInvocation: BOOL) { msgSend(nil, self, "setAllowDuplicateIntersectionFunctionInvocation:", allowDuplicateIntersectionFunctionInvocation) } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setIntersectionFunctionTableOffset") -AccelerationStructureGeometryDescriptor_setIntersectionFunctionTableOffset :: proc(self: ^AccelerationStructureGeometryDescriptor, intersectionFunctionTableOffset: NS.Integer) { +AccelerationStructureGeometryDescriptor_setIntersectionFunctionTableOffset :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor, intersectionFunctionTableOffset: NS.Integer) { msgSend(nil, self, "setIntersectionFunctionTableOffset:", intersectionFunctionTableOffset) } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setOpaque") -AccelerationStructureGeometryDescriptor_setOpaque :: proc(self: ^AccelerationStructureGeometryDescriptor, opaque: BOOL) { +AccelerationStructureGeometryDescriptor_setOpaque :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor, opaque: BOOL) { msgSend(nil, self, "setOpaque:", opaque) } @@ -196,71 +182,71 @@ Methods: AccelerationStructureTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureTriangleGeometryDescriptor) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_class_name="alloc") -AccelerationStructureTriangleGeometryDescriptor_alloc :: proc() -> ^AccelerationStructureTriangleGeometryDescriptor { +AccelerationStructureTriangleGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "alloc") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="init") -AccelerationStructureTriangleGeometryDescriptor_init :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { +AccelerationStructureTriangleGeometryDescriptor_init :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "init") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_class_name="descriptor") -AccelerationStructureTriangleGeometryDescriptor_descriptor :: proc() -> ^AccelerationStructureTriangleGeometryDescriptor { +AccelerationStructureTriangleGeometryDescriptor_descriptor :: #force_inline proc() -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "descriptor") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexBuffer") -AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { +AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "indexBuffer") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { +AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "indexBufferOffset") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexType") -AccelerationStructureTriangleGeometryDescriptor_indexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> IndexType { +AccelerationStructureTriangleGeometryDescriptor_indexType :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> IndexType { return msgSend(IndexType, self, "indexType") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexBuffer") -AccelerationStructureTriangleGeometryDescriptor_setIndexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBuffer: ^NS.Object) { +AccelerationStructureTriangleGeometryDescriptor_setIndexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBuffer: ^NS.Object) { msgSend(nil, self, "setIndexBuffer:", indexBuffer) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_setIndexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBufferOffset: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setIndexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBufferOffset: NS.Integer) { msgSend(nil, self, "setIndexBufferOffset:", indexBufferOffset) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexType") -AccelerationStructureTriangleGeometryDescriptor_setIndexType :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexType: IndexType) { +AccelerationStructureTriangleGeometryDescriptor_setIndexType :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexType: IndexType) { msgSend(nil, self, "setIndexType:", indexType) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setTriangleCount") -AccelerationStructureTriangleGeometryDescriptor_setTriangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, triangleCount: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setTriangleCount :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, triangleCount: NS.Integer) { msgSend(nil, self, "setTriangleCount:", triangleCount) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexBuffer") -AccelerationStructureTriangleGeometryDescriptor_setVertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBuffer: ^NS.Object) { +AccelerationStructureTriangleGeometryDescriptor_setVertexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBuffer: ^NS.Object) { msgSend(nil, self, "setVertexBuffer:", vertexBuffer) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_setVertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBufferOffset: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setVertexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBufferOffset: NS.Integer) { msgSend(nil, self, "setVertexBufferOffset:", vertexBufferOffset) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexStride") -AccelerationStructureTriangleGeometryDescriptor_setVertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexStride: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setVertexStride :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexStride: NS.Integer) { msgSend(nil, self, "setVertexStride:", vertexStride) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="triangleCount") -AccelerationStructureTriangleGeometryDescriptor_triangleCount :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { +AccelerationStructureTriangleGeometryDescriptor_triangleCount :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "triangleCount") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBuffer") -AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { +AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "vertexBuffer") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { +AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "vertexBufferOffset") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexStride") -AccelerationStructureTriangleGeometryDescriptor_vertexStride :: proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { +AccelerationStructureTriangleGeometryDescriptor_vertexStride :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "vertexStride") } @@ -294,75 +280,75 @@ Methods: Argument :: struct { using _: NS.Object } @(objc_type=Argument, objc_class_name="alloc") -Argument_alloc :: proc() -> ^Argument { +Argument_alloc :: #force_inline proc() -> ^Argument { return msgSend(^Argument, Argument, "alloc") } @(objc_type=Argument, objc_name="init") -Argument_init :: proc(self: ^Argument) -> ^Argument { +Argument_init :: #force_inline proc(self: ^Argument) -> ^Argument { return msgSend(^Argument, self, "init") } @(objc_type=Argument, objc_name="access") -Argument_access :: proc(self: ^Argument) -> ArgumentAccess { +Argument_access :: #force_inline proc(self: ^Argument) -> ArgumentAccess { return msgSend(ArgumentAccess, self, "access") } @(objc_type=Argument, objc_name="arrayLength") -Argument_arrayLength :: proc(self: ^Argument) -> NS.Integer { +Argument_arrayLength :: #force_inline proc(self: ^Argument) -> NS.Integer { return msgSend(NS.Integer, self, "arrayLength") } @(objc_type=Argument, objc_name="bufferAlignment") -Argument_bufferAlignment :: proc(self: ^Argument) -> NS.Integer { +Argument_bufferAlignment :: #force_inline proc(self: ^Argument) -> NS.Integer { return msgSend(NS.Integer, self, "bufferAlignment") } @(objc_type=Argument, objc_name="bufferDataSize") -Argument_bufferDataSize :: proc(self: ^Argument) -> NS.Integer { +Argument_bufferDataSize :: #force_inline proc(self: ^Argument) -> NS.Integer { return msgSend(NS.Integer, self, "bufferDataSize") } @(objc_type=Argument, objc_name="bufferDataType") -Argument_bufferDataType :: proc(self: ^Argument) -> DataType { +Argument_bufferDataType :: #force_inline proc(self: ^Argument) -> DataType { return msgSend(DataType, self, "bufferDataType") } @(objc_type=Argument, objc_name="bufferPointerType") -Argument_bufferPointerType :: proc(self: ^Argument) -> ^PointerType { +Argument_bufferPointerType :: #force_inline proc(self: ^Argument) -> ^PointerType { return msgSend(^PointerType, self, "bufferPointerType") } @(objc_type=Argument, objc_name="bufferStructType") -Argument_bufferStructType :: proc(self: ^Argument) -> ^StructType { +Argument_bufferStructType :: #force_inline proc(self: ^Argument) -> ^StructType { return msgSend(^StructType, self, "bufferStructType") } @(objc_type=Argument, objc_name="index") -Argument_index :: proc(self: ^Argument) -> NS.Integer { +Argument_index :: #force_inline proc(self: ^Argument) -> NS.Integer { return msgSend(NS.Integer, self, "index") } @(objc_type=Argument, objc_name="isActive") -Argument_isActive :: proc(self: ^Argument) -> BOOL { +Argument_isActive :: #force_inline proc(self: ^Argument) -> BOOL { return msgSend(BOOL, self, "isActive") } @(objc_type=Argument, objc_name="isDepthTexture") -Argument_isDepthTexture :: proc(self: ^Argument) -> BOOL { +Argument_isDepthTexture :: #force_inline proc(self: ^Argument) -> BOOL { return msgSend(BOOL, self, "isDepthTexture") } @(objc_type=Argument, objc_name="name") -Argument_name :: proc(self: ^Argument) -> ^NS.String { +Argument_name :: #force_inline proc(self: ^Argument) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=Argument, objc_name="textureDataType") -Argument_textureDataType :: proc(self: ^Argument) -> DataType { +Argument_textureDataType :: #force_inline proc(self: ^Argument) -> DataType { return msgSend(DataType, self, "textureDataType") } @(objc_type=Argument, objc_name="textureType") -Argument_textureType :: proc(self: ^Argument) -> TextureType { +Argument_textureType :: #force_inline proc(self: ^Argument) -> TextureType { return msgSend(TextureType, self, "textureType") } @(objc_type=Argument, objc_name="threadgroupMemoryAlignment") -Argument_threadgroupMemoryAlignment :: proc(self: ^Argument) -> NS.Integer { +Argument_threadgroupMemoryAlignment :: #force_inline proc(self: ^Argument) -> NS.Integer { return msgSend(NS.Integer, self, "threadgroupMemoryAlignment") } @(objc_type=Argument, objc_name="threadgroupMemoryDataSize") -Argument_threadgroupMemoryDataSize :: proc(self: ^Argument) -> NS.Integer { +Argument_threadgroupMemoryDataSize :: #force_inline proc(self: ^Argument) -> NS.Integer { return msgSend(NS.Integer, self, "threadgroupMemoryDataSize") } @(objc_type=Argument, objc_name="type") -Argument_type :: proc(self: ^Argument) -> ArgumentType { +Argument_type :: #force_inline proc(self: ^Argument) -> ArgumentType { return msgSend(ArgumentType, self, "type") } @@ -393,63 +379,63 @@ Methods: ArgumentDescriptor :: struct { using _: NS.Copying(ArgumentDescriptor) } @(objc_type=ArgumentDescriptor, objc_class_name="alloc") -ArgumentDescriptor_alloc :: proc() -> ^ArgumentDescriptor { +ArgumentDescriptor_alloc :: #force_inline proc() -> ^ArgumentDescriptor { return msgSend(^ArgumentDescriptor, ArgumentDescriptor, "alloc") } @(objc_type=ArgumentDescriptor, objc_name="init") -ArgumentDescriptor_init :: proc(self: ^ArgumentDescriptor) -> ^ArgumentDescriptor { +ArgumentDescriptor_init :: #force_inline proc(self: ^ArgumentDescriptor) -> ^ArgumentDescriptor { return msgSend(^ArgumentDescriptor, self, "init") } @(objc_type=ArgumentDescriptor, objc_name="access") -ArgumentDescriptor_access :: proc(self: ^ArgumentDescriptor) -> ArgumentAccess { +ArgumentDescriptor_access :: #force_inline proc(self: ^ArgumentDescriptor) -> ArgumentAccess { return msgSend(ArgumentAccess, self, "access") } @(objc_type=ArgumentDescriptor, objc_class_name="argumentDescriptor") -ArgumentDescriptor_argumentDescriptor :: proc() -> ^ArgumentDescriptor { +ArgumentDescriptor_argumentDescriptor :: #force_inline proc() -> ^ArgumentDescriptor { return msgSend(^ArgumentDescriptor, ArgumentDescriptor, "argumentDescriptor") } @(objc_type=ArgumentDescriptor, objc_name="arrayLength") -ArgumentDescriptor_arrayLength :: proc(self: ^ArgumentDescriptor) -> NS.Integer { +ArgumentDescriptor_arrayLength :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "arrayLength") } @(objc_type=ArgumentDescriptor, objc_name="constantBlockAlignment") -ArgumentDescriptor_constantBlockAlignment :: proc(self: ^ArgumentDescriptor) -> NS.Integer { +ArgumentDescriptor_constantBlockAlignment :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "constantBlockAlignment") } @(objc_type=ArgumentDescriptor, objc_name="dataType") -ArgumentDescriptor_dataType :: proc(self: ^ArgumentDescriptor) -> DataType { +ArgumentDescriptor_dataType :: #force_inline proc(self: ^ArgumentDescriptor) -> DataType { return msgSend(DataType, self, "dataType") } @(objc_type=ArgumentDescriptor, objc_name="index") -ArgumentDescriptor_index :: proc(self: ^ArgumentDescriptor) -> NS.Integer { +ArgumentDescriptor_index :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "index") } @(objc_type=ArgumentDescriptor, objc_name="setAccess") -ArgumentDescriptor_setAccess :: proc(self: ^ArgumentDescriptor, access: ArgumentAccess) { +ArgumentDescriptor_setAccess :: #force_inline proc(self: ^ArgumentDescriptor, access: ArgumentAccess) { msgSend(nil, self, "setAccess:", access) } @(objc_type=ArgumentDescriptor, objc_name="setArrayLength") -ArgumentDescriptor_setArrayLength :: proc(self: ^ArgumentDescriptor, arrayLength: NS.Integer) { +ArgumentDescriptor_setArrayLength :: #force_inline proc(self: ^ArgumentDescriptor, arrayLength: NS.Integer) { msgSend(nil, self, "setArrayLength:", arrayLength) } @(objc_type=ArgumentDescriptor, objc_name="setConstantBlockAlignment") -ArgumentDescriptor_setConstantBlockAlignment :: proc(self: ^ArgumentDescriptor, constantBlockAlignment: NS.Integer) { +ArgumentDescriptor_setConstantBlockAlignment :: #force_inline proc(self: ^ArgumentDescriptor, constantBlockAlignment: NS.Integer) { msgSend(nil, self, "setConstantBlockAlignment:", constantBlockAlignment) } @(objc_type=ArgumentDescriptor, objc_name="setDataType") -ArgumentDescriptor_setDataType :: proc(self: ^ArgumentDescriptor, dataType: DataType) { +ArgumentDescriptor_setDataType :: #force_inline proc(self: ^ArgumentDescriptor, dataType: DataType) { msgSend(nil, self, "setDataType:", dataType) } @(objc_type=ArgumentDescriptor, objc_name="setIndex") -ArgumentDescriptor_setIndex :: proc(self: ^ArgumentDescriptor, index: NS.Integer) { +ArgumentDescriptor_setIndex :: #force_inline proc(self: ^ArgumentDescriptor, index: NS.Integer) { msgSend(nil, self, "setIndex:", index) } @(objc_type=ArgumentDescriptor, objc_name="setTextureType") -ArgumentDescriptor_setTextureType :: proc(self: ^ArgumentDescriptor, textureType: TextureType) { +ArgumentDescriptor_setTextureType :: #force_inline proc(self: ^ArgumentDescriptor, textureType: TextureType) { msgSend(nil, self, "setTextureType:", textureType) } @(objc_type=ArgumentDescriptor, objc_name="textureType") -ArgumentDescriptor_textureType :: proc(self: ^ArgumentDescriptor) -> TextureType { +ArgumentDescriptor_textureType :: #force_inline proc(self: ^ArgumentDescriptor) -> TextureType { return msgSend(TextureType, self, "textureType") } @@ -475,43 +461,43 @@ Methods: ArrayType :: struct { using _: NS.Object } @(objc_type=ArrayType, objc_class_name="alloc") -ArrayType_alloc :: proc() -> ^ArrayType { +ArrayType_alloc :: #force_inline proc() -> ^ArrayType { return msgSend(^ArrayType, ArrayType, "alloc") } @(objc_type=ArrayType, objc_name="init") -ArrayType_init :: proc(self: ^ArrayType) -> ^ArrayType { +ArrayType_init :: #force_inline proc(self: ^ArrayType) -> ^ArrayType { return msgSend(^ArrayType, self, "init") } @(objc_type=ArrayType, objc_name="argumentIndexStride") -ArrayType_argumentIndexStride :: proc(self: ^ArrayType) -> NS.Integer { +ArrayType_argumentIndexStride :: #force_inline proc(self: ^ArrayType) -> NS.Integer { return msgSend(NS.Integer, self, "argumentIndexStride") } @(objc_type=ArrayType, objc_name="arrayLength") -ArrayType_arrayLength :: proc(self: ^ArrayType) -> NS.Integer { +ArrayType_arrayLength :: #force_inline proc(self: ^ArrayType) -> NS.Integer { return msgSend(NS.Integer, self, "arrayLength") } @(objc_type=ArrayType, objc_name="elementArrayType") -ArrayType_elementArrayType :: proc(self: ^ArrayType) -> ^ArrayType { +ArrayType_elementArrayType :: #force_inline proc(self: ^ArrayType) -> ^ArrayType { return msgSend(^ArrayType, self, "elementArrayType") } @(objc_type=ArrayType, objc_name="elementPointerType") -ArrayType_elementPointerType :: proc(self: ^ArrayType) -> ^PointerType { +ArrayType_elementPointerType :: #force_inline proc(self: ^ArrayType) -> ^PointerType { return msgSend(^PointerType, self, "elementPointerType") } @(objc_type=ArrayType, objc_name="elementStructType") -ArrayType_elementStructType :: proc(self: ^ArrayType) -> ^StructType { +ArrayType_elementStructType :: #force_inline proc(self: ^ArrayType) -> ^StructType { return msgSend(^StructType, self, "elementStructType") } @(objc_type=ArrayType, objc_name="elementTextureReferenceType") -ArrayType_elementTextureReferenceType :: proc(self: ^ArrayType) -> ^TextureReferenceType { +ArrayType_elementTextureReferenceType :: #force_inline proc(self: ^ArrayType) -> ^TextureReferenceType { return msgSend(^TextureReferenceType, self, "elementTextureReferenceType") } @(objc_type=ArrayType, objc_name="elementType") -ArrayType_elementType :: proc(self: ^ArrayType) -> DataType { +ArrayType_elementType :: #force_inline proc(self: ^ArrayType) -> DataType { return msgSend(DataType, self, "elementType") } @(objc_type=ArrayType, objc_name="stride") -ArrayType_stride :: proc(self: ^ArrayType) -> NS.Integer { +ArrayType_stride :: #force_inline proc(self: ^ArrayType) -> NS.Integer { return msgSend(NS.Integer, self, "stride") } @@ -535,35 +521,35 @@ Methods: Attribute :: struct { using _: NS.Object } @(objc_type=Attribute, objc_class_name="alloc") -Attribute_alloc :: proc() -> ^Attribute { +Attribute_alloc :: #force_inline proc() -> ^Attribute { return msgSend(^Attribute, Attribute, "alloc") } @(objc_type=Attribute, objc_name="init") -Attribute_init :: proc(self: ^Attribute) -> ^Attribute { +Attribute_init :: #force_inline proc(self: ^Attribute) -> ^Attribute { return msgSend(^Attribute, self, "init") } @(objc_type=Attribute, objc_name="attributeIndex") -Attribute_attributeIndex :: proc(self: ^Attribute) -> NS.Integer { +Attribute_attributeIndex :: #force_inline proc(self: ^Attribute) -> NS.Integer { return msgSend(NS.Integer, self, "attributeIndex") } @(objc_type=Attribute, objc_name="attributeType") -Attribute_attributeType :: proc(self: ^Attribute) -> DataType { +Attribute_attributeType :: #force_inline proc(self: ^Attribute) -> DataType { return msgSend(DataType, self, "attributeType") } @(objc_type=Attribute, objc_name="isActive") -Attribute_isActive :: proc(self: ^Attribute) -> BOOL { +Attribute_isActive :: #force_inline proc(self: ^Attribute) -> BOOL { return msgSend(BOOL, self, "isActive") } @(objc_type=Attribute, objc_name="isPatchControlPointData") -Attribute_isPatchControlPointData :: proc(self: ^Attribute) -> BOOL { +Attribute_isPatchControlPointData :: #force_inline proc(self: ^Attribute) -> BOOL { return msgSend(BOOL, self, "isPatchControlPointData") } @(objc_type=Attribute, objc_name="isPatchData") -Attribute_isPatchData :: proc(self: ^Attribute) -> BOOL { +Attribute_isPatchData :: #force_inline proc(self: ^Attribute) -> BOOL { return msgSend(BOOL, self, "isPatchData") } @(objc_type=Attribute, objc_name="name") -Attribute_name :: proc(self: ^Attribute) -> ^NS.String { +Attribute_name :: #force_inline proc(self: ^Attribute) -> ^NS.String { return msgSend(^NS.String, self, "name") } @@ -587,35 +573,35 @@ Methods: AttributeDescriptor :: struct { using _: NS.Copying(AttributeDescriptor) } @(objc_type=AttributeDescriptor, objc_class_name="alloc") -AttributeDescriptor_alloc :: proc() -> ^AttributeDescriptor { +AttributeDescriptor_alloc :: #force_inline proc() -> ^AttributeDescriptor { return msgSend(^AttributeDescriptor, AttributeDescriptor, "alloc") } @(objc_type=AttributeDescriptor, objc_name="init") -AttributeDescriptor_init :: proc(self: ^AttributeDescriptor) -> ^AttributeDescriptor { +AttributeDescriptor_init :: #force_inline proc(self: ^AttributeDescriptor) -> ^AttributeDescriptor { return msgSend(^AttributeDescriptor, self, "init") } @(objc_type=AttributeDescriptor, objc_name="bufferIndex") -AttributeDescriptor_bufferIndex :: proc(self: ^AttributeDescriptor) -> NS.Integer { +AttributeDescriptor_bufferIndex :: #force_inline proc(self: ^AttributeDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "bufferIndex") } @(objc_type=AttributeDescriptor, objc_name="format") -AttributeDescriptor_format :: proc(self: ^AttributeDescriptor) -> AttributeFormat { +AttributeDescriptor_format :: #force_inline proc(self: ^AttributeDescriptor) -> AttributeFormat { return msgSend(AttributeFormat, self, "format") } @(objc_type=AttributeDescriptor, objc_name="offset") -AttributeDescriptor_offset :: proc(self: ^AttributeDescriptor) -> NS.Integer { +AttributeDescriptor_offset :: #force_inline proc(self: ^AttributeDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "offset") } @(objc_type=AttributeDescriptor, objc_name="setBufferIndex") -AttributeDescriptor_setBufferIndex :: proc(self: ^AttributeDescriptor, bufferIndex: NS.Integer) { +AttributeDescriptor_setBufferIndex :: #force_inline proc(self: ^AttributeDescriptor, bufferIndex: NS.Integer) { msgSend(nil, self, "setBufferIndex:", bufferIndex) } @(objc_type=AttributeDescriptor, objc_name="setFormat") -AttributeDescriptor_setFormat :: proc(self: ^AttributeDescriptor, format: AttributeFormat) { +AttributeDescriptor_setFormat :: #force_inline proc(self: ^AttributeDescriptor, format: AttributeFormat) { msgSend(nil, self, "setFormat:", format) } @(objc_type=AttributeDescriptor, objc_name="setOffset") -AttributeDescriptor_setOffset :: proc(self: ^AttributeDescriptor, offset: NS.Integer) { +AttributeDescriptor_setOffset :: #force_inline proc(self: ^AttributeDescriptor, offset: NS.Integer) { msgSend(nil, self, "setOffset:", offset) } @@ -635,19 +621,19 @@ Methods: AttributeDescriptorArray :: struct { using _: NS.Object } @(objc_type=AttributeDescriptorArray, objc_class_name="alloc") -AttributeDescriptorArray_alloc :: proc() -> ^AttributeDescriptorArray { +AttributeDescriptorArray_alloc :: #force_inline proc() -> ^AttributeDescriptorArray { return msgSend(^AttributeDescriptorArray, AttributeDescriptorArray, "alloc") } @(objc_type=AttributeDescriptorArray, objc_name="init") -AttributeDescriptorArray_init :: proc(self: ^AttributeDescriptorArray) -> ^AttributeDescriptorArray { +AttributeDescriptorArray_init :: #force_inline proc(self: ^AttributeDescriptorArray) -> ^AttributeDescriptorArray { return msgSend(^AttributeDescriptorArray, self, "init") } @(objc_type=AttributeDescriptorArray, objc_name="objectAtIndexedSubscript") -AttributeDescriptorArray_objectAtIndexedSubscript :: proc(self: ^AttributeDescriptorArray, index: ^NS.Object) -> ^AttributeDescriptor { +AttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^AttributeDescriptorArray, index: ^NS.Object) -> ^AttributeDescriptor { return msgSend(^AttributeDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=AttributeDescriptorArray, objc_name="setObject") -AttributeDescriptorArray_setObject :: proc(self: ^AttributeDescriptorArray, attributeDesc: ^AttributeDescriptor, index: ^NS.Object) { +AttributeDescriptorArray_setObject :: #force_inline proc(self: ^AttributeDescriptorArray, attributeDesc: ^AttributeDescriptor, index: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attributeDesc, index) } @@ -667,19 +653,19 @@ Methods: BinaryArchiveDescriptor :: struct { using _: NS.Copying(BinaryArchiveDescriptor) } @(objc_type=BinaryArchiveDescriptor, objc_class_name="alloc") -BinaryArchiveDescriptor_alloc :: proc() -> ^BinaryArchiveDescriptor { +BinaryArchiveDescriptor_alloc :: #force_inline proc() -> ^BinaryArchiveDescriptor { return msgSend(^BinaryArchiveDescriptor, BinaryArchiveDescriptor, "alloc") } @(objc_type=BinaryArchiveDescriptor, objc_name="init") -BinaryArchiveDescriptor_init :: proc(self: ^BinaryArchiveDescriptor) -> ^BinaryArchiveDescriptor { +BinaryArchiveDescriptor_init :: #force_inline proc(self: ^BinaryArchiveDescriptor) -> ^BinaryArchiveDescriptor { return msgSend(^BinaryArchiveDescriptor, self, "init") } @(objc_type=BinaryArchiveDescriptor, objc_name="setUrl") -BinaryArchiveDescriptor_setUrl :: proc(self: ^BinaryArchiveDescriptor, url: ^NS.URL) { +BinaryArchiveDescriptor_setUrl :: #force_inline proc(self: ^BinaryArchiveDescriptor, url: ^NS.URL) { msgSend(nil, self, "setUrl:", url) } @(objc_type=BinaryArchiveDescriptor, objc_name="url") -BinaryArchiveDescriptor_url :: proc(self: ^BinaryArchiveDescriptor) -> ^NS.URL { +BinaryArchiveDescriptor_url :: #force_inline proc(self: ^BinaryArchiveDescriptor) -> ^NS.URL { return msgSend(^NS.URL, self, "url") } @@ -699,19 +685,19 @@ Methods: BlitPassDescriptor :: struct { using _: NS.Copying(BlitPassDescriptor) } @(objc_type=BlitPassDescriptor, objc_class_name="alloc") -BlitPassDescriptor_alloc :: proc() -> ^BlitPassDescriptor { +BlitPassDescriptor_alloc :: #force_inline proc() -> ^BlitPassDescriptor { return msgSend(^BlitPassDescriptor, BlitPassDescriptor, "alloc") } @(objc_type=BlitPassDescriptor, objc_name="init") -BlitPassDescriptor_init :: proc(self: ^BlitPassDescriptor) -> ^BlitPassDescriptor { +BlitPassDescriptor_init :: #force_inline proc(self: ^BlitPassDescriptor) -> ^BlitPassDescriptor { return msgSend(^BlitPassDescriptor, self, "init") } @(objc_type=BlitPassDescriptor, objc_class_name="blitPassDescriptor") -BlitPassDescriptor_blitPassDescriptor :: proc() -> ^BlitPassDescriptor { +BlitPassDescriptor_blitPassDescriptor :: #force_inline proc() -> ^BlitPassDescriptor { return msgSend(^BlitPassDescriptor, BlitPassDescriptor, "blitPassDescriptor") } @(objc_type=BlitPassDescriptor, objc_name="sampleBufferAttachments") -BlitPassDescriptor_sampleBufferAttachments :: proc(self: ^BlitPassDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptorArray { +BlitPassDescriptor_sampleBufferAttachments :: #force_inline proc(self: ^BlitPassDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptorArray { return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") } @@ -735,35 +721,35 @@ Methods: BlitPassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(BlitPassSampleBufferAttachmentDescriptor) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_class_name="alloc") -BlitPassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^BlitPassSampleBufferAttachmentDescriptor { +BlitPassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, BlitPassSampleBufferAttachmentDescriptor, "alloc") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="init") -BlitPassSampleBufferAttachmentDescriptor_init :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { +BlitPassSampleBufferAttachmentDescriptor_init :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { +BlitPassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { +BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { +BlitPassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -BlitPassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +BlitPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { +BlitPassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { +BlitPassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") } @@ -783,19 +769,19 @@ Methods: BlitPassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } @(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") -BlitPassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^BlitPassSampleBufferAttachmentDescriptorArray { +BlitPassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^BlitPassSampleBufferAttachmentDescriptorArray { return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, BlitPassSampleBufferAttachmentDescriptorArray, "alloc") } @(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="init") -BlitPassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray) -> ^BlitPassSampleBufferAttachmentDescriptorArray { +BlitPassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray) -> ^BlitPassSampleBufferAttachmentDescriptorArray { return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -BlitPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^BlitPassSampleBufferAttachmentDescriptor { +BlitPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -BlitPassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachment: ^BlitPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +BlitPassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachment: ^BlitPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -819,35 +805,35 @@ Methods: BufferLayoutDescriptor :: struct { using _: NS.Copying(BufferLayoutDescriptor) } @(objc_type=BufferLayoutDescriptor, objc_class_name="alloc") -BufferLayoutDescriptor_alloc :: proc() -> ^BufferLayoutDescriptor { +BufferLayoutDescriptor_alloc :: #force_inline proc() -> ^BufferLayoutDescriptor { return msgSend(^BufferLayoutDescriptor, BufferLayoutDescriptor, "alloc") } @(objc_type=BufferLayoutDescriptor, objc_name="init") -BufferLayoutDescriptor_init :: proc(self: ^BufferLayoutDescriptor) -> ^BufferLayoutDescriptor { +BufferLayoutDescriptor_init :: #force_inline proc(self: ^BufferLayoutDescriptor) -> ^BufferLayoutDescriptor { return msgSend(^BufferLayoutDescriptor, self, "init") } @(objc_type=BufferLayoutDescriptor, objc_name="setStepFunction") -BufferLayoutDescriptor_setStepFunction :: proc(self: ^BufferLayoutDescriptor, stepFunction: StepFunction) { +BufferLayoutDescriptor_setStepFunction :: #force_inline proc(self: ^BufferLayoutDescriptor, stepFunction: StepFunction) { msgSend(nil, self, "setStepFunction:", stepFunction) } @(objc_type=BufferLayoutDescriptor, objc_name="setStepRate") -BufferLayoutDescriptor_setStepRate :: proc(self: ^BufferLayoutDescriptor, stepRate: NS.Integer) { +BufferLayoutDescriptor_setStepRate :: #force_inline proc(self: ^BufferLayoutDescriptor, stepRate: NS.Integer) { msgSend(nil, self, "setStepRate:", stepRate) } @(objc_type=BufferLayoutDescriptor, objc_name="setStride") -BufferLayoutDescriptor_setStride :: proc(self: ^BufferLayoutDescriptor, stride: NS.Integer) { +BufferLayoutDescriptor_setStride :: #force_inline proc(self: ^BufferLayoutDescriptor, stride: NS.Integer) { msgSend(nil, self, "setStride:", stride) } @(objc_type=BufferLayoutDescriptor, objc_name="stepFunction") -BufferLayoutDescriptor_stepFunction :: proc(self: ^BufferLayoutDescriptor) -> StepFunction { +BufferLayoutDescriptor_stepFunction :: #force_inline proc(self: ^BufferLayoutDescriptor) -> StepFunction { return msgSend(StepFunction, self, "stepFunction") } @(objc_type=BufferLayoutDescriptor, objc_name="stepRate") -BufferLayoutDescriptor_stepRate :: proc(self: ^BufferLayoutDescriptor) -> NS.Integer { +BufferLayoutDescriptor_stepRate :: #force_inline proc(self: ^BufferLayoutDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "stepRate") } @(objc_type=BufferLayoutDescriptor, objc_name="stride") -BufferLayoutDescriptor_stride :: proc(self: ^BufferLayoutDescriptor) -> NS.Integer { +BufferLayoutDescriptor_stride :: #force_inline proc(self: ^BufferLayoutDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "stride") } @@ -867,19 +853,19 @@ Methods: BufferLayoutDescriptorArray :: struct { using _: NS.Object } @(objc_type=BufferLayoutDescriptorArray, objc_class_name="alloc") -BufferLayoutDescriptorArray_alloc :: proc() -> ^BufferLayoutDescriptorArray { +BufferLayoutDescriptorArray_alloc :: #force_inline proc() -> ^BufferLayoutDescriptorArray { return msgSend(^BufferLayoutDescriptorArray, BufferLayoutDescriptorArray, "alloc") } @(objc_type=BufferLayoutDescriptorArray, objc_name="init") -BufferLayoutDescriptorArray_init :: proc(self: ^BufferLayoutDescriptorArray) -> ^BufferLayoutDescriptorArray { +BufferLayoutDescriptorArray_init :: #force_inline proc(self: ^BufferLayoutDescriptorArray) -> ^BufferLayoutDescriptorArray { return msgSend(^BufferLayoutDescriptorArray, self, "init") } @(objc_type=BufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") -BufferLayoutDescriptorArray_objectAtIndexedSubscript :: proc(self: ^BufferLayoutDescriptorArray, index: ^NS.Object) -> ^BufferLayoutDescriptor { +BufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BufferLayoutDescriptorArray, index: ^NS.Object) -> ^BufferLayoutDescriptor { return msgSend(^BufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=BufferLayoutDescriptorArray, objc_name="setObject") -BufferLayoutDescriptorArray_setObject :: proc(self: ^BufferLayoutDescriptorArray, bufferDesc: ^BufferLayoutDescriptor, index: ^NS.Object) { +BufferLayoutDescriptorArray_setObject :: #force_inline proc(self: ^BufferLayoutDescriptorArray, bufferDesc: ^BufferLayoutDescriptor, index: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", bufferDesc, index) } @@ -903,35 +889,35 @@ Methods: CaptureDescriptor :: struct { using _: NS.Copying(CaptureDescriptor) } @(objc_type=CaptureDescriptor, objc_class_name="alloc") -CaptureDescriptor_alloc :: proc() -> ^CaptureDescriptor { +CaptureDescriptor_alloc :: #force_inline proc() -> ^CaptureDescriptor { return msgSend(^CaptureDescriptor, CaptureDescriptor, "alloc") } @(objc_type=CaptureDescriptor, objc_name="init") -CaptureDescriptor_init :: proc(self: ^CaptureDescriptor) -> ^CaptureDescriptor { +CaptureDescriptor_init :: #force_inline proc(self: ^CaptureDescriptor) -> ^CaptureDescriptor { return msgSend(^CaptureDescriptor, self, "init") } @(objc_type=CaptureDescriptor, objc_name="captureObject") -CaptureDescriptor_captureObject :: proc(self: ^CaptureDescriptor) -> ^CaptureDescriptor { +CaptureDescriptor_captureObject :: #force_inline proc(self: ^CaptureDescriptor) -> ^CaptureDescriptor { return msgSend(^CaptureDescriptor, self, "captureObject") } @(objc_type=CaptureDescriptor, objc_name="destination") -CaptureDescriptor_destination :: proc(self: ^CaptureDescriptor) -> CaptureDestination { +CaptureDescriptor_destination :: #force_inline proc(self: ^CaptureDescriptor) -> CaptureDestination { return msgSend(CaptureDestination, self, "destination") } @(objc_type=CaptureDescriptor, objc_name="outputURL") -CaptureDescriptor_outputURL :: proc(self: ^CaptureDescriptor) -> ^NS.URL { +CaptureDescriptor_outputURL :: #force_inline proc(self: ^CaptureDescriptor) -> ^NS.URL { return msgSend(^NS.URL, self, "outputURL") } @(objc_type=CaptureDescriptor, objc_name="setCaptureObject") -CaptureDescriptor_setCaptureObject :: proc(self: ^CaptureDescriptor, captureObject: ^NS.Object) { +CaptureDescriptor_setCaptureObject :: #force_inline proc(self: ^CaptureDescriptor, captureObject: ^NS.Object) { msgSend(nil, self, "setCaptureObject:", captureObject) } @(objc_type=CaptureDescriptor, objc_name="setDestination") -CaptureDescriptor_setDestination :: proc(self: ^CaptureDescriptor, destination: CaptureDestination) { +CaptureDescriptor_setDestination :: #force_inline proc(self: ^CaptureDescriptor, destination: CaptureDestination) { msgSend(nil, self, "setDestination:", destination) } @(objc_type=CaptureDescriptor, objc_name="setOutputURL") -CaptureDescriptor_setOutputURL :: proc(self: ^CaptureDescriptor, outputURL: ^NS.URL) { +CaptureDescriptor_setOutputURL :: #force_inline proc(self: ^CaptureDescriptor, outputURL: ^NS.URL) { msgSend(nil, self, "setOutputURL:", outputURL) } @@ -961,59 +947,59 @@ Methods: CaptureManager :: struct { using _: NS.Object } @(objc_type=CaptureManager, objc_class_name="alloc") -CaptureManager_alloc :: proc() -> ^CaptureManager { +CaptureManager_alloc :: #force_inline proc() -> ^CaptureManager { return msgSend(^CaptureManager, CaptureManager, "alloc") } @(objc_type=CaptureManager, objc_name="defaultCaptureScope") -CaptureManager_defaultCaptureScope :: proc(self: ^CaptureManager) -> ^CaptureManager { +CaptureManager_defaultCaptureScope :: #force_inline proc(self: ^CaptureManager) -> ^CaptureManager { return msgSend(^CaptureManager, self, "defaultCaptureScope") } @(objc_type=CaptureManager, objc_name="init") -CaptureManager_init :: proc(self: ^CaptureManager) -> ^CaptureManager { +CaptureManager_init :: #force_inline proc(self: ^CaptureManager) -> ^CaptureManager { return msgSend(^CaptureManager, self, "init") } @(objc_type=CaptureManager, objc_name="isCapturing") -CaptureManager_isCapturing :: proc(self: ^CaptureManager) -> BOOL { +CaptureManager_isCapturing :: #force_inline proc(self: ^CaptureManager) -> BOOL { return msgSend(BOOL, self, "isCapturing") } @(objc_type=CaptureManager, objc_name="newCaptureScopeWithCommandQueue") -CaptureManager_newCaptureScopeWithCommandQueue :: proc(self: ^CaptureManager, commandQueue: ^NS.Object) -> ^CaptureManager { +CaptureManager_newCaptureScopeWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^NS.Object) -> ^CaptureManager { return msgSend(^CaptureManager, self, "newCaptureScopeWithCommandQueue:", commandQueue) } @(objc_type=CaptureManager, objc_name="newCaptureScopeWithDevice") -CaptureManager_newCaptureScopeWithDevice :: proc(self: ^CaptureManager, device: ^NS.Object) -> ^CaptureManager { +CaptureManager_newCaptureScopeWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^NS.Object) -> ^CaptureManager { return msgSend(^CaptureManager, self, "newCaptureScopeWithDevice:", device) } @(objc_type=CaptureManager, objc_name="setDefaultCaptureScope") -CaptureManager_setDefaultCaptureScope :: proc(self: ^CaptureManager, defaultCaptureScope: ^NS.Object) { +CaptureManager_setDefaultCaptureScope :: #force_inline proc(self: ^CaptureManager, defaultCaptureScope: ^NS.Object) { msgSend(nil, self, "setDefaultCaptureScope:", defaultCaptureScope) } @(objc_type=CaptureManager, objc_class_name="sharedCaptureManager") -CaptureManager_sharedCaptureManager :: proc() -> ^CaptureManager { +CaptureManager_sharedCaptureManager :: #force_inline proc() -> ^CaptureManager { return msgSend(^CaptureManager, CaptureManager, "sharedCaptureManager") } @(objc_type=CaptureManager, objc_name="startCaptureWithCommandQueue") -CaptureManager_startCaptureWithCommandQueue :: proc(self: ^CaptureManager, commandQueue: ^NS.Object) { +CaptureManager_startCaptureWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^NS.Object) { msgSend(nil, self, "startCaptureWithCommandQueue:", commandQueue) } @(objc_type=CaptureManager, objc_name="startCaptureWithDescriptor") -CaptureManager_startCaptureWithDescriptor :: proc(self: ^CaptureManager, descriptor: ^CaptureDescriptor, error: ^^NS.Error ) -> BOOL { +CaptureManager_startCaptureWithDescriptor :: #force_inline proc(self: ^CaptureManager, descriptor: ^CaptureDescriptor, error: ^^NS.Error ) -> BOOL { return msgSend(BOOL, self, "startCaptureWithDescriptor:error:", descriptor, error) } @(objc_type=CaptureManager, objc_name="startCaptureWithDevice") -CaptureManager_startCaptureWithDevice :: proc(self: ^CaptureManager, device: ^NS.Object) { +CaptureManager_startCaptureWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^NS.Object) { msgSend(nil, self, "startCaptureWithDevice:", device) } @(objc_type=CaptureManager, objc_name="startCaptureWithScope") -CaptureManager_startCaptureWithScope :: proc(self: ^CaptureManager, captureScope: ^NS.Object) { +CaptureManager_startCaptureWithScope :: #force_inline proc(self: ^CaptureManager, captureScope: ^NS.Object) { msgSend(nil, self, "startCaptureWithScope:", captureScope) } @(objc_type=CaptureManager, objc_name="stopCapture") -CaptureManager_stopCapture :: proc(self: ^CaptureManager) { +CaptureManager_stopCapture :: #force_inline proc(self: ^CaptureManager) { msgSend(nil, self, "stopCapture") } @(objc_type=CaptureManager, objc_name="supportsDestination") -CaptureManager_supportsDestination :: proc(self: ^CaptureManager, destination: CaptureDestination) -> BOOL { +CaptureManager_supportsDestination :: #force_inline proc(self: ^CaptureManager, destination: CaptureDestination) -> BOOL { return msgSend(BOOL, self, "supportsDestination:", destination) } @@ -1035,27 +1021,27 @@ Methods: CommandBufferDescriptor :: struct { using _: NS.Copying(CommandBufferDescriptor) } @(objc_type=CommandBufferDescriptor, objc_class_name="alloc") -CommandBufferDescriptor_alloc :: proc() -> ^CommandBufferDescriptor { +CommandBufferDescriptor_alloc :: #force_inline proc() -> ^CommandBufferDescriptor { return msgSend(^CommandBufferDescriptor, CommandBufferDescriptor, "alloc") } @(objc_type=CommandBufferDescriptor, objc_name="init") -CommandBufferDescriptor_init :: proc(self: ^CommandBufferDescriptor) -> ^CommandBufferDescriptor { +CommandBufferDescriptor_init :: #force_inline proc(self: ^CommandBufferDescriptor) -> ^CommandBufferDescriptor { return msgSend(^CommandBufferDescriptor, self, "init") } @(objc_type=CommandBufferDescriptor, objc_name="errorOptions") -CommandBufferDescriptor_errorOptions :: proc(self: ^CommandBufferDescriptor) -> CommandBufferErrorOption { +CommandBufferDescriptor_errorOptions :: #force_inline proc(self: ^CommandBufferDescriptor) -> CommandBufferErrorOption { return msgSend(CommandBufferErrorOption, self, "errorOptions") } @(objc_type=CommandBufferDescriptor, objc_name="retainedReferences") -CommandBufferDescriptor_retainedReferences :: proc(self: ^CommandBufferDescriptor) -> BOOL { +CommandBufferDescriptor_retainedReferences :: #force_inline proc(self: ^CommandBufferDescriptor) -> BOOL { return msgSend(BOOL, self, "retainedReferences") } @(objc_type=CommandBufferDescriptor, objc_name="setErrorOptions") -CommandBufferDescriptor_setErrorOptions :: proc(self: ^CommandBufferDescriptor, errorOptions: CommandBufferErrorOption) { +CommandBufferDescriptor_setErrorOptions :: #force_inline proc(self: ^CommandBufferDescriptor, errorOptions: CommandBufferErrorOption) { msgSend(nil, self, "setErrorOptions:", errorOptions) } @(objc_type=CommandBufferDescriptor, objc_name="setRetainedReferences") -CommandBufferDescriptor_setRetainedReferences :: proc(self: ^CommandBufferDescriptor, retainedReferences: BOOL) { +CommandBufferDescriptor_setRetainedReferences :: #force_inline proc(self: ^CommandBufferDescriptor, retainedReferences: BOOL) { msgSend(nil, self, "setRetainedReferences:", retainedReferences) } @@ -1087,67 +1073,67 @@ Methods: CompileOptions :: struct { using _: NS.Copying(CompileOptions) } @(objc_type=CompileOptions, objc_class_name="alloc") -CompileOptions_alloc :: proc() -> ^CompileOptions { +CompileOptions_alloc :: #force_inline proc() -> ^CompileOptions { return msgSend(^CompileOptions, CompileOptions, "alloc") } @(objc_type=CompileOptions, objc_name="init") -CompileOptions_init :: proc(self: ^CompileOptions) -> ^CompileOptions { +CompileOptions_init :: #force_inline proc(self: ^CompileOptions) -> ^CompileOptions { return msgSend(^CompileOptions, self, "init") } @(objc_type=CompileOptions, objc_name="fastMathEnabled") -CompileOptions_fastMathEnabled :: proc(self: ^CompileOptions) -> BOOL { +CompileOptions_fastMathEnabled :: #force_inline proc(self: ^CompileOptions) -> BOOL { return msgSend(BOOL, self, "fastMathEnabled") } @(objc_type=CompileOptions, objc_name="installName") -CompileOptions_installName :: proc(self: ^CompileOptions) -> ^NS.String { +CompileOptions_installName :: #force_inline proc(self: ^CompileOptions) -> ^NS.String { return msgSend(^NS.String, self, "installName") } @(objc_type=CompileOptions, objc_name="languageVersion") -CompileOptions_languageVersion :: proc(self: ^CompileOptions) -> LanguageVersion { +CompileOptions_languageVersion :: #force_inline proc(self: ^CompileOptions) -> LanguageVersion { return msgSend(LanguageVersion, self, "languageVersion") } @(objc_type=CompileOptions, objc_name="libraries") -CompileOptions_libraries :: proc(self: ^CompileOptions) -> ^NS.Array { +CompileOptions_libraries :: #force_inline proc(self: ^CompileOptions) -> ^NS.Array { return msgSend(^NS.Array, self, "libraries") } @(objc_type=CompileOptions, objc_name="libraryType") -CompileOptions_libraryType :: proc(self: ^CompileOptions) -> LibraryType { +CompileOptions_libraryType :: #force_inline proc(self: ^CompileOptions) -> LibraryType { return msgSend(LibraryType, self, "libraryType") } @(objc_type=CompileOptions, objc_name="preprocessorMacros") -CompileOptions_preprocessorMacros :: proc(self: ^CompileOptions) -> ^NS.Dictionary { +CompileOptions_preprocessorMacros :: #force_inline proc(self: ^CompileOptions) -> ^NS.Dictionary { return msgSend(^NS.Dictionary, self, "preprocessorMacros") } @(objc_type=CompileOptions, objc_name="preserveInvariance") -CompileOptions_preserveInvariance :: proc(self: ^CompileOptions) -> BOOL { +CompileOptions_preserveInvariance :: #force_inline proc(self: ^CompileOptions) -> BOOL { return msgSend(BOOL, self, "preserveInvariance") } @(objc_type=CompileOptions, objc_name="setFastMathEnabled") -CompileOptions_setFastMathEnabled :: proc(self: ^CompileOptions, fastMathEnabled: BOOL) { +CompileOptions_setFastMathEnabled :: #force_inline proc(self: ^CompileOptions, fastMathEnabled: BOOL) { msgSend(nil, self, "setFastMathEnabled:", fastMathEnabled) } @(objc_type=CompileOptions, objc_name="setInstallName") -CompileOptions_setInstallName :: proc(self: ^CompileOptions, installName: ^NS.String) { +CompileOptions_setInstallName :: #force_inline proc(self: ^CompileOptions, installName: ^NS.String) { msgSend(nil, self, "setInstallName:", installName) } @(objc_type=CompileOptions, objc_name="setLanguageVersion") -CompileOptions_setLanguageVersion :: proc(self: ^CompileOptions, languageVersion: LanguageVersion) { +CompileOptions_setLanguageVersion :: #force_inline proc(self: ^CompileOptions, languageVersion: LanguageVersion) { msgSend(nil, self, "setLanguageVersion:", languageVersion) } @(objc_type=CompileOptions, objc_name="setLibraries") -CompileOptions_setLibraries :: proc(self: ^CompileOptions, libraries: ^NS.Array) { +CompileOptions_setLibraries :: #force_inline proc(self: ^CompileOptions, libraries: ^NS.Array) { msgSend(nil, self, "setLibraries:", libraries) } @(objc_type=CompileOptions, objc_name="setLibraryType") -CompileOptions_setLibraryType :: proc(self: ^CompileOptions, libraryType: LibraryType) { +CompileOptions_setLibraryType :: #force_inline proc(self: ^CompileOptions, libraryType: LibraryType) { msgSend(nil, self, "setLibraryType:", libraryType) } @(objc_type=CompileOptions, objc_name="setPreprocessorMacros") -CompileOptions_setPreprocessorMacros :: proc(self: ^CompileOptions, preprocessorMacros: ^NS.Dictionary) { +CompileOptions_setPreprocessorMacros :: #force_inline proc(self: ^CompileOptions, preprocessorMacros: ^NS.Dictionary) { msgSend(nil, self, "setPreprocessorMacros:", preprocessorMacros) } @(objc_type=CompileOptions, objc_name="setPreserveInvariance") -CompileOptions_setPreserveInvariance :: proc(self: ^CompileOptions, preserveInvariance: BOOL) { +CompileOptions_setPreserveInvariance :: #force_inline proc(self: ^CompileOptions, preserveInvariance: BOOL) { msgSend(nil, self, "setPreserveInvariance:", preserveInvariance) } @@ -1169,27 +1155,27 @@ Methods: ComputePassDescriptor :: struct { using _: NS.Copying(ComputePassDescriptor) } @(objc_type=ComputePassDescriptor, objc_class_name="alloc") -ComputePassDescriptor_alloc :: proc() -> ^ComputePassDescriptor { +ComputePassDescriptor_alloc :: #force_inline proc() -> ^ComputePassDescriptor { return msgSend(^ComputePassDescriptor, ComputePassDescriptor, "alloc") } @(objc_type=ComputePassDescriptor, objc_name="init") -ComputePassDescriptor_init :: proc(self: ^ComputePassDescriptor) -> ^ComputePassDescriptor { +ComputePassDescriptor_init :: #force_inline proc(self: ^ComputePassDescriptor) -> ^ComputePassDescriptor { return msgSend(^ComputePassDescriptor, self, "init") } @(objc_type=ComputePassDescriptor, objc_class_name="computePassDescriptor") -ComputePassDescriptor_computePassDescriptor :: proc() -> ^ComputePassDescriptor { +ComputePassDescriptor_computePassDescriptor :: #force_inline proc() -> ^ComputePassDescriptor { return msgSend(^ComputePassDescriptor, ComputePassDescriptor, "computePassDescriptor") } @(objc_type=ComputePassDescriptor, objc_name="dispatchType") -ComputePassDescriptor_dispatchType :: proc(self: ^ComputePassDescriptor) -> DispatchType { +ComputePassDescriptor_dispatchType :: #force_inline proc(self: ^ComputePassDescriptor) -> DispatchType { return msgSend(DispatchType, self, "dispatchType") } @(objc_type=ComputePassDescriptor, objc_name="sampleBufferAttachments") -ComputePassDescriptor_sampleBufferAttachments :: proc(self: ^ComputePassDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptorArray { +ComputePassDescriptor_sampleBufferAttachments :: #force_inline proc(self: ^ComputePassDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptorArray { return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") } @(objc_type=ComputePassDescriptor, objc_name="setDispatchType") -ComputePassDescriptor_setDispatchType :: proc(self: ^ComputePassDescriptor, dispatchType: DispatchType) { +ComputePassDescriptor_setDispatchType :: #force_inline proc(self: ^ComputePassDescriptor, dispatchType: DispatchType) { msgSend(nil, self, "setDispatchType:", dispatchType) } @@ -1213,35 +1199,35 @@ Methods: ComputePassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(ComputePassSampleBufferAttachmentDescriptor) } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_class_name="alloc") -ComputePassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^ComputePassSampleBufferAttachmentDescriptor { +ComputePassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, ComputePassSampleBufferAttachmentDescriptor, "alloc") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="init") -ComputePassSampleBufferAttachmentDescriptor_init :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { +ComputePassSampleBufferAttachmentDescriptor_init :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { +ComputePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { +ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { +ComputePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -ComputePassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +ComputePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { +ComputePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { +ComputePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") } @@ -1261,19 +1247,19 @@ Methods: ComputePassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } @(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") -ComputePassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^ComputePassSampleBufferAttachmentDescriptorArray { +ComputePassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^ComputePassSampleBufferAttachmentDescriptorArray { return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, ComputePassSampleBufferAttachmentDescriptorArray, "alloc") } @(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="init") -ComputePassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray) -> ^ComputePassSampleBufferAttachmentDescriptorArray { +ComputePassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray) -> ^ComputePassSampleBufferAttachmentDescriptorArray { return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -ComputePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ComputePassSampleBufferAttachmentDescriptor { +ComputePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -ComputePassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachment: ^ComputePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +ComputePassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachment: ^ComputePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -1315,107 +1301,107 @@ Methods: ComputePipelineDescriptor :: struct { using _: NS.Copying(ComputePipelineDescriptor) } @(objc_type=ComputePipelineDescriptor, objc_class_name="alloc") -ComputePipelineDescriptor_alloc :: proc() -> ^ComputePipelineDescriptor { +ComputePipelineDescriptor_alloc :: #force_inline proc() -> ^ComputePipelineDescriptor { return msgSend(^ComputePipelineDescriptor, ComputePipelineDescriptor, "alloc") } @(objc_type=ComputePipelineDescriptor, objc_name="init") -ComputePipelineDescriptor_init :: proc(self: ^ComputePipelineDescriptor) -> ^ComputePipelineDescriptor { +ComputePipelineDescriptor_init :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^ComputePipelineDescriptor { return msgSend(^ComputePipelineDescriptor, self, "init") } @(objc_type=ComputePipelineDescriptor, objc_name="binaryArchives") -ComputePipelineDescriptor_binaryArchives :: proc(self: ^ComputePipelineDescriptor) -> ^NS.Array { +ComputePipelineDescriptor_binaryArchives :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^NS.Array { return msgSend(^NS.Array, self, "binaryArchives") } @(objc_type=ComputePipelineDescriptor, objc_name="buffers") -ComputePipelineDescriptor_buffers :: proc(self: ^ComputePipelineDescriptor) -> ^PipelineBufferDescriptorArray { +ComputePipelineDescriptor_buffers :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, self, "buffers") } @(objc_type=ComputePipelineDescriptor, objc_name="computeFunction") -ComputePipelineDescriptor_computeFunction :: proc(self: ^ComputePipelineDescriptor) -> ^ComputePipelineDescriptor { +ComputePipelineDescriptor_computeFunction :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^ComputePipelineDescriptor { return msgSend(^ComputePipelineDescriptor, self, "computeFunction") } @(objc_type=ComputePipelineDescriptor, objc_name="insertLibraries") -ComputePipelineDescriptor_insertLibraries :: proc(self: ^ComputePipelineDescriptor) -> ^NS.Array { +ComputePipelineDescriptor_insertLibraries :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^NS.Array { return msgSend(^NS.Array, self, "insertLibraries") } @(objc_type=ComputePipelineDescriptor, objc_name="label") -ComputePipelineDescriptor_label :: proc(self: ^ComputePipelineDescriptor) -> ^NS.String { +ComputePipelineDescriptor_label :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=ComputePipelineDescriptor, objc_name="linkedFunctions") -ComputePipelineDescriptor_linkedFunctions :: proc(self: ^ComputePipelineDescriptor) -> ^LinkedFunctions { +ComputePipelineDescriptor_linkedFunctions :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^LinkedFunctions { return msgSend(^LinkedFunctions, self, "linkedFunctions") } @(objc_type=ComputePipelineDescriptor, objc_name="maxCallStackDepth") -ComputePipelineDescriptor_maxCallStackDepth :: proc(self: ^ComputePipelineDescriptor) -> NS.Integer { +ComputePipelineDescriptor_maxCallStackDepth :: #force_inline proc(self: ^ComputePipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxCallStackDepth") } @(objc_type=ComputePipelineDescriptor, objc_name="maxTotalThreadsPerThreadgroup") -ComputePipelineDescriptor_maxTotalThreadsPerThreadgroup :: proc(self: ^ComputePipelineDescriptor) -> NS.Integer { +ComputePipelineDescriptor_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=ComputePipelineDescriptor, objc_name="reset") -ComputePipelineDescriptor_reset :: proc(self: ^ComputePipelineDescriptor) { +ComputePipelineDescriptor_reset :: #force_inline proc(self: ^ComputePipelineDescriptor) { msgSend(nil, self, "reset") } @(objc_type=ComputePipelineDescriptor, objc_name="setBinaryArchives") -ComputePipelineDescriptor_setBinaryArchives :: proc(self: ^ComputePipelineDescriptor, binaryArchives: ^NS.Array) { +ComputePipelineDescriptor_setBinaryArchives :: #force_inline proc(self: ^ComputePipelineDescriptor, binaryArchives: ^NS.Array) { msgSend(nil, self, "setBinaryArchives:", binaryArchives) } @(objc_type=ComputePipelineDescriptor, objc_name="setComputeFunction") -ComputePipelineDescriptor_setComputeFunction :: proc(self: ^ComputePipelineDescriptor, computeFunction: ^NS.Object) { +ComputePipelineDescriptor_setComputeFunction :: #force_inline proc(self: ^ComputePipelineDescriptor, computeFunction: ^NS.Object) { msgSend(nil, self, "setComputeFunction:", computeFunction) } @(objc_type=ComputePipelineDescriptor, objc_name="setInsertLibraries") -ComputePipelineDescriptor_setInsertLibraries :: proc(self: ^ComputePipelineDescriptor, insertLibraries: ^NS.Array) { +ComputePipelineDescriptor_setInsertLibraries :: #force_inline proc(self: ^ComputePipelineDescriptor, insertLibraries: ^NS.Array) { msgSend(nil, self, "setInsertLibraries:", insertLibraries) } @(objc_type=ComputePipelineDescriptor, objc_name="setLabel") -ComputePipelineDescriptor_setLabel :: proc(self: ^ComputePipelineDescriptor, label: ^NS.String) { +ComputePipelineDescriptor_setLabel :: #force_inline proc(self: ^ComputePipelineDescriptor, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=ComputePipelineDescriptor, objc_name="setLinkedFunctions") -ComputePipelineDescriptor_setLinkedFunctions :: proc(self: ^ComputePipelineDescriptor, linkedFunctions: ^LinkedFunctions) { +ComputePipelineDescriptor_setLinkedFunctions :: #force_inline proc(self: ^ComputePipelineDescriptor, linkedFunctions: ^LinkedFunctions) { msgSend(nil, self, "setLinkedFunctions:", linkedFunctions) } @(objc_type=ComputePipelineDescriptor, objc_name="setMaxCallStackDepth") -ComputePipelineDescriptor_setMaxCallStackDepth :: proc(self: ^ComputePipelineDescriptor, maxCallStackDepth: NS.Integer) { +ComputePipelineDescriptor_setMaxCallStackDepth :: #force_inline proc(self: ^ComputePipelineDescriptor, maxCallStackDepth: NS.Integer) { msgSend(nil, self, "setMaxCallStackDepth:", maxCallStackDepth) } @(objc_type=ComputePipelineDescriptor, objc_name="setMaxTotalThreadsPerThreadgroup") -ComputePipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: proc(self: ^ComputePipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { +ComputePipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { msgSend(nil, self, "setMaxTotalThreadsPerThreadgroup:", maxTotalThreadsPerThreadgroup) } @(objc_type=ComputePipelineDescriptor, objc_name="setStageInputDescriptor") -ComputePipelineDescriptor_setStageInputDescriptor :: proc(self: ^ComputePipelineDescriptor, stageInputDescriptor: ^StageInputOutputDescriptor) { +ComputePipelineDescriptor_setStageInputDescriptor :: #force_inline proc(self: ^ComputePipelineDescriptor, stageInputDescriptor: ^StageInputOutputDescriptor) { msgSend(nil, self, "setStageInputDescriptor:", stageInputDescriptor) } @(objc_type=ComputePipelineDescriptor, objc_name="setSupportAddingBinaryFunctions") -ComputePipelineDescriptor_setSupportAddingBinaryFunctions :: proc(self: ^ComputePipelineDescriptor, supportAddingBinaryFunctions: BOOL) { +ComputePipelineDescriptor_setSupportAddingBinaryFunctions :: #force_inline proc(self: ^ComputePipelineDescriptor, supportAddingBinaryFunctions: BOOL) { msgSend(nil, self, "setSupportAddingBinaryFunctions:", supportAddingBinaryFunctions) } @(objc_type=ComputePipelineDescriptor, objc_name="setSupportIndirectCommandBuffers") -ComputePipelineDescriptor_setSupportIndirectCommandBuffers :: proc(self: ^ComputePipelineDescriptor, supportIndirectCommandBuffers: BOOL) { +ComputePipelineDescriptor_setSupportIndirectCommandBuffers :: #force_inline proc(self: ^ComputePipelineDescriptor, supportIndirectCommandBuffers: BOOL) { msgSend(nil, self, "setSupportIndirectCommandBuffers:", supportIndirectCommandBuffers) } @(objc_type=ComputePipelineDescriptor, objc_name="setThreadGroupSizeIsMultipleOfThreadExecutionWidth") -ComputePipelineDescriptor_setThreadGroupSizeIsMultipleOfThreadExecutionWidth :: proc(self: ^ComputePipelineDescriptor, threadGroupSizeIsMultipleOfThreadExecutionWidth: BOOL) { +ComputePipelineDescriptor_setThreadGroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc(self: ^ComputePipelineDescriptor, threadGroupSizeIsMultipleOfThreadExecutionWidth: BOOL) { msgSend(nil, self, "setThreadGroupSizeIsMultipleOfThreadExecutionWidth:", threadGroupSizeIsMultipleOfThreadExecutionWidth) } @(objc_type=ComputePipelineDescriptor, objc_name="stageInputDescriptor") -ComputePipelineDescriptor_stageInputDescriptor :: proc(self: ^ComputePipelineDescriptor) -> ^StageInputOutputDescriptor { +ComputePipelineDescriptor_stageInputDescriptor :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^StageInputOutputDescriptor { return msgSend(^StageInputOutputDescriptor, self, "stageInputDescriptor") } @(objc_type=ComputePipelineDescriptor, objc_name="supportAddingBinaryFunctions") -ComputePipelineDescriptor_supportAddingBinaryFunctions :: proc(self: ^ComputePipelineDescriptor) -> BOOL { +ComputePipelineDescriptor_supportAddingBinaryFunctions :: #force_inline proc(self: ^ComputePipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "supportAddingBinaryFunctions") } @(objc_type=ComputePipelineDescriptor, objc_name="supportIndirectCommandBuffers") -ComputePipelineDescriptor_supportIndirectCommandBuffers :: proc(self: ^ComputePipelineDescriptor) -> BOOL { +ComputePipelineDescriptor_supportIndirectCommandBuffers :: #force_inline proc(self: ^ComputePipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "supportIndirectCommandBuffers") } @(objc_type=ComputePipelineDescriptor, objc_name="threadGroupSizeIsMultipleOfThreadExecutionWidth") -ComputePipelineDescriptor_threadGroupSizeIsMultipleOfThreadExecutionWidth :: proc(self: ^ComputePipelineDescriptor) -> BOOL { +ComputePipelineDescriptor_threadGroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc(self: ^ComputePipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "threadGroupSizeIsMultipleOfThreadExecutionWidth") } @@ -1434,15 +1420,15 @@ Methods: ComputePipelineReflection :: struct { using _: NS.Object } @(objc_type=ComputePipelineReflection, objc_class_name="alloc") -ComputePipelineReflection_alloc :: proc() -> ^ComputePipelineReflection { +ComputePipelineReflection_alloc :: #force_inline proc() -> ^ComputePipelineReflection { return msgSend(^ComputePipelineReflection, ComputePipelineReflection, "alloc") } @(objc_type=ComputePipelineReflection, objc_name="init") -ComputePipelineReflection_init :: proc(self: ^ComputePipelineReflection) -> ^ComputePipelineReflection { +ComputePipelineReflection_init :: #force_inline proc(self: ^ComputePipelineReflection) -> ^ComputePipelineReflection { return msgSend(^ComputePipelineReflection, self, "init") } @(objc_type=ComputePipelineReflection, objc_name="arguments") -ComputePipelineReflection_arguments :: proc(self: ^ComputePipelineReflection) -> ^NS.Array { +ComputePipelineReflection_arguments :: #force_inline proc(self: ^ComputePipelineReflection) -> ^NS.Array { return msgSend(^NS.Array, self, "arguments") } @@ -1468,43 +1454,43 @@ Methods: CounterSampleBufferDescriptor :: struct { using _: NS.Copying(CounterSampleBufferDescriptor) } @(objc_type=CounterSampleBufferDescriptor, objc_class_name="alloc") -CounterSampleBufferDescriptor_alloc :: proc() -> ^CounterSampleBufferDescriptor { +CounterSampleBufferDescriptor_alloc :: #force_inline proc() -> ^CounterSampleBufferDescriptor { return msgSend(^CounterSampleBufferDescriptor, CounterSampleBufferDescriptor, "alloc") } @(objc_type=CounterSampleBufferDescriptor, objc_name="init") -CounterSampleBufferDescriptor_init :: proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSampleBufferDescriptor { +CounterSampleBufferDescriptor_init :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSampleBufferDescriptor { return msgSend(^CounterSampleBufferDescriptor, self, "init") } @(objc_type=CounterSampleBufferDescriptor, objc_name="counterSet") -CounterSampleBufferDescriptor_counterSet :: proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSampleBufferDescriptor { +CounterSampleBufferDescriptor_counterSet :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSampleBufferDescriptor { return msgSend(^CounterSampleBufferDescriptor, self, "counterSet") } @(objc_type=CounterSampleBufferDescriptor, objc_name="label") -CounterSampleBufferDescriptor_label :: proc(self: ^CounterSampleBufferDescriptor) -> ^NS.String { +CounterSampleBufferDescriptor_label :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CounterSampleBufferDescriptor, objc_name="sampleCount") -CounterSampleBufferDescriptor_sampleCount :: proc(self: ^CounterSampleBufferDescriptor) -> NS.Integer { +CounterSampleBufferDescriptor_sampleCount :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "sampleCount") } @(objc_type=CounterSampleBufferDescriptor, objc_name="setCounterSet") -CounterSampleBufferDescriptor_setCounterSet :: proc(self: ^CounterSampleBufferDescriptor, counterSet: ^NS.Object) { +CounterSampleBufferDescriptor_setCounterSet :: #force_inline proc(self: ^CounterSampleBufferDescriptor, counterSet: ^NS.Object) { msgSend(nil, self, "setCounterSet:", counterSet) } @(objc_type=CounterSampleBufferDescriptor, objc_name="setLabel") -CounterSampleBufferDescriptor_setLabel :: proc(self: ^CounterSampleBufferDescriptor, label: ^NS.String) { +CounterSampleBufferDescriptor_setLabel :: #force_inline proc(self: ^CounterSampleBufferDescriptor, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=CounterSampleBufferDescriptor, objc_name="setSampleCount") -CounterSampleBufferDescriptor_setSampleCount :: proc(self: ^CounterSampleBufferDescriptor, sampleCount: NS.Integer) { +CounterSampleBufferDescriptor_setSampleCount :: #force_inline proc(self: ^CounterSampleBufferDescriptor, sampleCount: NS.Integer) { msgSend(nil, self, "setSampleCount:", sampleCount) } @(objc_type=CounterSampleBufferDescriptor, objc_name="setStorageMode") -CounterSampleBufferDescriptor_setStorageMode :: proc(self: ^CounterSampleBufferDescriptor, storageMode: StorageMode) { +CounterSampleBufferDescriptor_setStorageMode :: #force_inline proc(self: ^CounterSampleBufferDescriptor, storageMode: StorageMode) { msgSend(nil, self, "setStorageMode:", storageMode) } @(objc_type=CounterSampleBufferDescriptor, objc_name="storageMode") -CounterSampleBufferDescriptor_storageMode :: proc(self: ^CounterSampleBufferDescriptor) -> StorageMode { +CounterSampleBufferDescriptor_storageMode :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> StorageMode { return msgSend(StorageMode, self, "storageMode") } @@ -1532,51 +1518,51 @@ Methods: DepthStencilDescriptor :: struct { using _: NS.Copying(DepthStencilDescriptor) } @(objc_type=DepthStencilDescriptor, objc_class_name="alloc") -DepthStencilDescriptor_alloc :: proc() -> ^DepthStencilDescriptor { +DepthStencilDescriptor_alloc :: #force_inline proc() -> ^DepthStencilDescriptor { return msgSend(^DepthStencilDescriptor, DepthStencilDescriptor, "alloc") } @(objc_type=DepthStencilDescriptor, objc_name="init") -DepthStencilDescriptor_init :: proc(self: ^DepthStencilDescriptor) -> ^DepthStencilDescriptor { +DepthStencilDescriptor_init :: #force_inline proc(self: ^DepthStencilDescriptor) -> ^DepthStencilDescriptor { return msgSend(^DepthStencilDescriptor, self, "init") } @(objc_type=DepthStencilDescriptor, objc_name="backFaceStencil") -DepthStencilDescriptor_backFaceStencil :: proc(self: ^DepthStencilDescriptor) -> ^StencilDescriptor { +DepthStencilDescriptor_backFaceStencil :: #force_inline proc(self: ^DepthStencilDescriptor) -> ^StencilDescriptor { return msgSend(^StencilDescriptor, self, "backFaceStencil") } @(objc_type=DepthStencilDescriptor, objc_name="depthCompareFunction") -DepthStencilDescriptor_depthCompareFunction :: proc(self: ^DepthStencilDescriptor) -> CompareFunction { +DepthStencilDescriptor_depthCompareFunction :: #force_inline proc(self: ^DepthStencilDescriptor) -> CompareFunction { return msgSend(CompareFunction, self, "depthCompareFunction") } @(objc_type=DepthStencilDescriptor, objc_name="frontFaceStencil") -DepthStencilDescriptor_frontFaceStencil :: proc(self: ^DepthStencilDescriptor) -> ^StencilDescriptor { +DepthStencilDescriptor_frontFaceStencil :: #force_inline proc(self: ^DepthStencilDescriptor) -> ^StencilDescriptor { return msgSend(^StencilDescriptor, self, "frontFaceStencil") } @(objc_type=DepthStencilDescriptor, objc_name="isDepthWriteEnabled") -DepthStencilDescriptor_isDepthWriteEnabled :: proc(self: ^DepthStencilDescriptor) -> BOOL { +DepthStencilDescriptor_isDepthWriteEnabled :: #force_inline proc(self: ^DepthStencilDescriptor) -> BOOL { return msgSend(BOOL, self, "isDepthWriteEnabled") } @(objc_type=DepthStencilDescriptor, objc_name="label") -DepthStencilDescriptor_label :: proc(self: ^DepthStencilDescriptor) -> ^NS.String { +DepthStencilDescriptor_label :: #force_inline proc(self: ^DepthStencilDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=DepthStencilDescriptor, objc_name="setBackFaceStencil") -DepthStencilDescriptor_setBackFaceStencil :: proc(self: ^DepthStencilDescriptor, backFaceStencil: ^StencilDescriptor) { +DepthStencilDescriptor_setBackFaceStencil :: #force_inline proc(self: ^DepthStencilDescriptor, backFaceStencil: ^StencilDescriptor) { msgSend(nil, self, "setBackFaceStencil:", backFaceStencil) } @(objc_type=DepthStencilDescriptor, objc_name="setDepthCompareFunction") -DepthStencilDescriptor_setDepthCompareFunction :: proc(self: ^DepthStencilDescriptor, depthCompareFunction: CompareFunction) { +DepthStencilDescriptor_setDepthCompareFunction :: #force_inline proc(self: ^DepthStencilDescriptor, depthCompareFunction: CompareFunction) { msgSend(nil, self, "setDepthCompareFunction:", depthCompareFunction) } @(objc_type=DepthStencilDescriptor, objc_name="setDepthWriteEnabled") -DepthStencilDescriptor_setDepthWriteEnabled :: proc(self: ^DepthStencilDescriptor, depthWriteEnabled: BOOL) { +DepthStencilDescriptor_setDepthWriteEnabled :: #force_inline proc(self: ^DepthStencilDescriptor, depthWriteEnabled: BOOL) { msgSend(nil, self, "setDepthWriteEnabled:", depthWriteEnabled) } @(objc_type=DepthStencilDescriptor, objc_name="setFrontFaceStencil") -DepthStencilDescriptor_setFrontFaceStencil :: proc(self: ^DepthStencilDescriptor, frontFaceStencil: ^StencilDescriptor) { +DepthStencilDescriptor_setFrontFaceStencil :: #force_inline proc(self: ^DepthStencilDescriptor, frontFaceStencil: ^StencilDescriptor) { msgSend(nil, self, "setFrontFaceStencil:", frontFaceStencil) } @(objc_type=DepthStencilDescriptor, objc_name="setLabel") -DepthStencilDescriptor_setLabel :: proc(self: ^DepthStencilDescriptor, label: ^NS.String) { +DepthStencilDescriptor_setLabel :: #force_inline proc(self: ^DepthStencilDescriptor, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -1598,27 +1584,27 @@ Methods: FunctionConstant :: struct { using _: NS.Copying(FunctionConstant) } @(objc_type=FunctionConstant, objc_class_name="alloc") -FunctionConstant_alloc :: proc() -> ^FunctionConstant { +FunctionConstant_alloc :: #force_inline proc() -> ^FunctionConstant { return msgSend(^FunctionConstant, FunctionConstant, "alloc") } @(objc_type=FunctionConstant, objc_name="init") -FunctionConstant_init :: proc(self: ^FunctionConstant) -> ^FunctionConstant { +FunctionConstant_init :: #force_inline proc(self: ^FunctionConstant) -> ^FunctionConstant { return msgSend(^FunctionConstant, self, "init") } @(objc_type=FunctionConstant, objc_name="index") -FunctionConstant_index :: proc(self: ^FunctionConstant) -> NS.Integer { +FunctionConstant_index :: #force_inline proc(self: ^FunctionConstant) -> NS.Integer { return msgSend(NS.Integer, self, "index") } @(objc_type=FunctionConstant, objc_name="name") -FunctionConstant_name :: proc(self: ^FunctionConstant) -> ^NS.String { +FunctionConstant_name :: #force_inline proc(self: ^FunctionConstant) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=FunctionConstant, objc_name="required") -FunctionConstant_required :: proc(self: ^FunctionConstant) -> BOOL { +FunctionConstant_required :: #force_inline proc(self: ^FunctionConstant) -> BOOL { return msgSend(BOOL, self, "required") } @(objc_type=FunctionConstant, objc_name="type") -FunctionConstant_type :: proc(self: ^FunctionConstant) -> DataType { +FunctionConstant_type :: #force_inline proc(self: ^FunctionConstant) -> DataType { return msgSend(DataType, self, "type") } @@ -1640,27 +1626,27 @@ Methods: FunctionConstantValues :: struct { using _: NS.Copying(FunctionConstantValues) } @(objc_type=FunctionConstantValues, objc_class_name="alloc") -FunctionConstantValues_alloc :: proc() -> ^FunctionConstantValues { +FunctionConstantValues_alloc :: #force_inline proc() -> ^FunctionConstantValues { return msgSend(^FunctionConstantValues, FunctionConstantValues, "alloc") } @(objc_type=FunctionConstantValues, objc_name="init") -FunctionConstantValues_init :: proc(self: ^FunctionConstantValues) -> ^FunctionConstantValues { +FunctionConstantValues_init :: #force_inline proc(self: ^FunctionConstantValues) -> ^FunctionConstantValues { return msgSend(^FunctionConstantValues, self, "init") } @(objc_type=FunctionConstantValues, objc_name="reset") -FunctionConstantValues_reset :: proc(self: ^FunctionConstantValues) { +FunctionConstantValues_reset :: #force_inline proc(self: ^FunctionConstantValues) { msgSend(nil, self, "reset") } @(objc_type=FunctionConstantValues, objc_name="setConstantValue_type_atIndex_") -FunctionConstantValues_setConstantValue_type_atIndex_ :: proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, index: ^NS.Object) { +FunctionConstantValues_setConstantValue_type_atIndex_ :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, index: ^NS.Object) { msgSend(nil, self, "setConstantValue:type:atIndex:", value, type, index) } @(objc_type=FunctionConstantValues, objc_name="setConstantValue_type_withName_") -FunctionConstantValues_setConstantValue_type_withName_ :: proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, name: ^NS.String) { +FunctionConstantValues_setConstantValue_type_withName_ :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, name: ^NS.String) { msgSend(nil, self, "setConstantValue:type:withName:", value, type, name) } @(objc_type=FunctionConstantValues, objc_name="setConstantValues") -FunctionConstantValues_setConstantValues :: proc(self: ^FunctionConstantValues, values: rawptr, type: DataType, range: NS.Range) { +FunctionConstantValues_setConstantValues :: #force_inline proc(self: ^FunctionConstantValues, values: rawptr, type: DataType, range: NS.Range) { msgSend(nil, self, "setConstantValues:type:withRange:", values, type, range) } @@ -1687,47 +1673,47 @@ Methods: FunctionDescriptor :: struct { using _: NS.Copying(FunctionDescriptor) } @(objc_type=FunctionDescriptor, objc_class_name="alloc") -FunctionDescriptor_alloc :: proc() -> ^FunctionDescriptor { +FunctionDescriptor_alloc :: #force_inline proc() -> ^FunctionDescriptor { return msgSend(^FunctionDescriptor, FunctionDescriptor, "alloc") } @(objc_type=FunctionDescriptor, objc_name="init") -FunctionDescriptor_init :: proc(self: ^FunctionDescriptor) -> ^FunctionDescriptor { +FunctionDescriptor_init :: #force_inline proc(self: ^FunctionDescriptor) -> ^FunctionDescriptor { return msgSend(^FunctionDescriptor, self, "init") } @(objc_type=FunctionDescriptor, objc_name="constantValues") -FunctionDescriptor_constantValues :: proc(self: ^FunctionDescriptor) -> ^FunctionConstantValues { +FunctionDescriptor_constantValues :: #force_inline proc(self: ^FunctionDescriptor) -> ^FunctionConstantValues { return msgSend(^FunctionConstantValues, self, "constantValues") } @(objc_type=FunctionDescriptor, objc_class_name="functionDescriptor") -FunctionDescriptor_functionDescriptor :: proc() -> ^FunctionDescriptor { +FunctionDescriptor_functionDescriptor :: #force_inline proc() -> ^FunctionDescriptor { return msgSend(^FunctionDescriptor, FunctionDescriptor, "functionDescriptor") } @(objc_type=FunctionDescriptor, objc_name="name") -FunctionDescriptor_name :: proc(self: ^FunctionDescriptor) -> ^NS.String { +FunctionDescriptor_name :: #force_inline proc(self: ^FunctionDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=FunctionDescriptor, objc_name="options") -FunctionDescriptor_options :: proc(self: ^FunctionDescriptor) -> FunctionOptions { +FunctionDescriptor_options :: #force_inline proc(self: ^FunctionDescriptor) -> FunctionOptions { return msgSend(FunctionOptions, self, "options") } @(objc_type=FunctionDescriptor, objc_name="setConstantValues") -FunctionDescriptor_setConstantValues :: proc(self: ^FunctionDescriptor, constantValues: ^FunctionConstantValues) { +FunctionDescriptor_setConstantValues :: #force_inline proc(self: ^FunctionDescriptor, constantValues: ^FunctionConstantValues) { msgSend(nil, self, "setConstantValues:", constantValues) } @(objc_type=FunctionDescriptor, objc_name="setName") -FunctionDescriptor_setName :: proc(self: ^FunctionDescriptor, name: ^NS.String) { +FunctionDescriptor_setName :: #force_inline proc(self: ^FunctionDescriptor, name: ^NS.String) { msgSend(nil, self, "setName:", name) } @(objc_type=FunctionDescriptor, objc_name="setOptions") -FunctionDescriptor_setOptions :: proc(self: ^FunctionDescriptor, options: FunctionOptions) { +FunctionDescriptor_setOptions :: #force_inline proc(self: ^FunctionDescriptor, options: FunctionOptions) { msgSend(nil, self, "setOptions:", options) } @(objc_type=FunctionDescriptor, objc_name="setSpecializedName") -FunctionDescriptor_setSpecializedName :: proc(self: ^FunctionDescriptor, specializedName: ^NS.String) { +FunctionDescriptor_setSpecializedName :: #force_inline proc(self: ^FunctionDescriptor, specializedName: ^NS.String) { msgSend(nil, self, "setSpecializedName:", specializedName) } @(objc_type=FunctionDescriptor, objc_name="specializedName") -FunctionDescriptor_specializedName :: proc(self: ^FunctionDescriptor) -> ^NS.String { +FunctionDescriptor_specializedName :: #force_inline proc(self: ^FunctionDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "specializedName") } @@ -1745,11 +1731,11 @@ Methods: IntersectionFunctionDescriptor :: struct { using _: NS.Copying(IntersectionFunctionDescriptor) } @(objc_type=IntersectionFunctionDescriptor, objc_class_name="alloc") -IntersectionFunctionDescriptor_alloc :: proc() -> ^IntersectionFunctionDescriptor { +IntersectionFunctionDescriptor_alloc :: #force_inline proc() -> ^IntersectionFunctionDescriptor { return msgSend(^IntersectionFunctionDescriptor, IntersectionFunctionDescriptor, "alloc") } @(objc_type=IntersectionFunctionDescriptor, objc_name="init") -IntersectionFunctionDescriptor_init :: proc(self: ^IntersectionFunctionDescriptor) -> ^IntersectionFunctionDescriptor { +IntersectionFunctionDescriptor_init :: #force_inline proc(self: ^IntersectionFunctionDescriptor) -> ^IntersectionFunctionDescriptor { return msgSend(^IntersectionFunctionDescriptor, self, "init") } @@ -1779,59 +1765,59 @@ Methods: HeapDescriptor :: struct { using _: NS.Copying(HeapDescriptor) } @(objc_type=HeapDescriptor, objc_class_name="alloc") -HeapDescriptor_alloc :: proc() -> ^HeapDescriptor { +HeapDescriptor_alloc :: #force_inline proc() -> ^HeapDescriptor { return msgSend(^HeapDescriptor, HeapDescriptor, "alloc") } @(objc_type=HeapDescriptor, objc_name="init") -HeapDescriptor_init :: proc(self: ^HeapDescriptor) -> ^HeapDescriptor { +HeapDescriptor_init :: #force_inline proc(self: ^HeapDescriptor) -> ^HeapDescriptor { return msgSend(^HeapDescriptor, self, "init") } @(objc_type=HeapDescriptor, objc_name="cpuCacheMode") -HeapDescriptor_cpuCacheMode :: proc(self: ^HeapDescriptor) -> CPUCacheMode { +HeapDescriptor_cpuCacheMode :: #force_inline proc(self: ^HeapDescriptor) -> CPUCacheMode { return msgSend(CPUCacheMode, self, "cpuCacheMode") } @(objc_type=HeapDescriptor, objc_name="hazardTrackingMode") -HeapDescriptor_hazardTrackingMode :: proc(self: ^HeapDescriptor) -> HazardTrackingMode { +HeapDescriptor_hazardTrackingMode :: #force_inline proc(self: ^HeapDescriptor) -> HazardTrackingMode { return msgSend(HazardTrackingMode, self, "hazardTrackingMode") } @(objc_type=HeapDescriptor, objc_name="resourceOptions") -HeapDescriptor_resourceOptions :: proc(self: ^HeapDescriptor) -> ResourceOptions { +HeapDescriptor_resourceOptions :: #force_inline proc(self: ^HeapDescriptor) -> ResourceOptions { return msgSend(ResourceOptions, self, "resourceOptions") } @(objc_type=HeapDescriptor, objc_name="setCpuCacheMode") -HeapDescriptor_setCpuCacheMode :: proc(self: ^HeapDescriptor, cpuCacheMode: CPUCacheMode) { +HeapDescriptor_setCpuCacheMode :: #force_inline proc(self: ^HeapDescriptor, cpuCacheMode: CPUCacheMode) { msgSend(nil, self, "setCpuCacheMode:", cpuCacheMode) } @(objc_type=HeapDescriptor, objc_name="setHazardTrackingMode") -HeapDescriptor_setHazardTrackingMode :: proc(self: ^HeapDescriptor, hazardTrackingMode: HazardTrackingMode) { +HeapDescriptor_setHazardTrackingMode :: #force_inline proc(self: ^HeapDescriptor, hazardTrackingMode: HazardTrackingMode) { msgSend(nil, self, "setHazardTrackingMode:", hazardTrackingMode) } @(objc_type=HeapDescriptor, objc_name="setResourceOptions") -HeapDescriptor_setResourceOptions :: proc(self: ^HeapDescriptor, resourceOptions: ResourceOptions) { +HeapDescriptor_setResourceOptions :: #force_inline proc(self: ^HeapDescriptor, resourceOptions: ResourceOptions) { msgSend(nil, self, "setResourceOptions:", resourceOptions) } @(objc_type=HeapDescriptor, objc_name="setSize") -HeapDescriptor_setSize :: proc(self: ^HeapDescriptor, size: NS.Integer) { +HeapDescriptor_setSize :: #force_inline proc(self: ^HeapDescriptor, size: NS.Integer) { msgSend(nil, self, "setSize:", size) } @(objc_type=HeapDescriptor, objc_name="setStorageMode") -HeapDescriptor_setStorageMode :: proc(self: ^HeapDescriptor, storageMode: StorageMode) { +HeapDescriptor_setStorageMode :: #force_inline proc(self: ^HeapDescriptor, storageMode: StorageMode) { msgSend(nil, self, "setStorageMode:", storageMode) } @(objc_type=HeapDescriptor, objc_name="setType") -HeapDescriptor_setType :: proc(self: ^HeapDescriptor, type: HeapType) { +HeapDescriptor_setType :: #force_inline proc(self: ^HeapDescriptor, type: HeapType) { msgSend(nil, self, "setType:", type) } @(objc_type=HeapDescriptor, objc_name="size") -HeapDescriptor_size :: proc(self: ^HeapDescriptor) -> NS.Integer { +HeapDescriptor_size :: #force_inline proc(self: ^HeapDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "size") } @(objc_type=HeapDescriptor, objc_name="storageMode") -HeapDescriptor_storageMode :: proc(self: ^HeapDescriptor) -> StorageMode { +HeapDescriptor_storageMode :: #force_inline proc(self: ^HeapDescriptor) -> StorageMode { return msgSend(StorageMode, self, "storageMode") } @(objc_type=HeapDescriptor, objc_name="type") -HeapDescriptor_type :: proc(self: ^HeapDescriptor) -> HeapType { +HeapDescriptor_type :: #force_inline proc(self: ^HeapDescriptor) -> HeapType { return msgSend(HeapType, self, "type") } @@ -1861,59 +1847,59 @@ Methods: IndirectCommandBufferDescriptor :: struct { using _: NS.Copying(IndirectCommandBufferDescriptor) } @(objc_type=IndirectCommandBufferDescriptor, objc_class_name="alloc") -IndirectCommandBufferDescriptor_alloc :: proc() -> ^IndirectCommandBufferDescriptor { +IndirectCommandBufferDescriptor_alloc :: #force_inline proc() -> ^IndirectCommandBufferDescriptor { return msgSend(^IndirectCommandBufferDescriptor, IndirectCommandBufferDescriptor, "alloc") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="init") -IndirectCommandBufferDescriptor_init :: proc(self: ^IndirectCommandBufferDescriptor) -> ^IndirectCommandBufferDescriptor { +IndirectCommandBufferDescriptor_init :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> ^IndirectCommandBufferDescriptor { return msgSend(^IndirectCommandBufferDescriptor, self, "init") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="commandTypes") -IndirectCommandBufferDescriptor_commandTypes :: proc(self: ^IndirectCommandBufferDescriptor) -> IndirectCommandType { +IndirectCommandBufferDescriptor_commandTypes :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> IndirectCommandType { return msgSend(IndirectCommandType, self, "commandTypes") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="inheritBuffers") -IndirectCommandBufferDescriptor_inheritBuffers :: proc(self: ^IndirectCommandBufferDescriptor) -> BOOL { +IndirectCommandBufferDescriptor_inheritBuffers :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> BOOL { return msgSend(BOOL, self, "inheritBuffers") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="inheritPipelineState") -IndirectCommandBufferDescriptor_inheritPipelineState :: proc(self: ^IndirectCommandBufferDescriptor) -> BOOL { +IndirectCommandBufferDescriptor_inheritPipelineState :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> BOOL { return msgSend(BOOL, self, "inheritPipelineState") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="maxFragmentBufferBindCount") -IndirectCommandBufferDescriptor_maxFragmentBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { +IndirectCommandBufferDescriptor_maxFragmentBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxFragmentBufferBindCount") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="maxKernelBufferBindCount") -IndirectCommandBufferDescriptor_maxKernelBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { +IndirectCommandBufferDescriptor_maxKernelBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxKernelBufferBindCount") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="maxVertexBufferBindCount") -IndirectCommandBufferDescriptor_maxVertexBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { +IndirectCommandBufferDescriptor_maxVertexBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxVertexBufferBindCount") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setCommandTypes") -IndirectCommandBufferDescriptor_setCommandTypes :: proc(self: ^IndirectCommandBufferDescriptor, commandTypes: IndirectCommandType) { +IndirectCommandBufferDescriptor_setCommandTypes :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, commandTypes: IndirectCommandType) { msgSend(nil, self, "setCommandTypes:", commandTypes) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setInheritBuffers") -IndirectCommandBufferDescriptor_setInheritBuffers :: proc(self: ^IndirectCommandBufferDescriptor, inheritBuffers: BOOL) { +IndirectCommandBufferDescriptor_setInheritBuffers :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, inheritBuffers: BOOL) { msgSend(nil, self, "setInheritBuffers:", inheritBuffers) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setInheritPipelineState") -IndirectCommandBufferDescriptor_setInheritPipelineState :: proc(self: ^IndirectCommandBufferDescriptor, inheritPipelineState: BOOL) { +IndirectCommandBufferDescriptor_setInheritPipelineState :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, inheritPipelineState: BOOL) { msgSend(nil, self, "setInheritPipelineState:", inheritPipelineState) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxFragmentBufferBindCount") -IndirectCommandBufferDescriptor_setMaxFragmentBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor, maxFragmentBufferBindCount: NS.Integer) { +IndirectCommandBufferDescriptor_setMaxFragmentBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxFragmentBufferBindCount: NS.Integer) { msgSend(nil, self, "setMaxFragmentBufferBindCount:", maxFragmentBufferBindCount) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxKernelBufferBindCount") -IndirectCommandBufferDescriptor_setMaxKernelBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor, maxKernelBufferBindCount: NS.Integer) { +IndirectCommandBufferDescriptor_setMaxKernelBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxKernelBufferBindCount: NS.Integer) { msgSend(nil, self, "setMaxKernelBufferBindCount:", maxKernelBufferBindCount) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxVertexBufferBindCount") -IndirectCommandBufferDescriptor_setMaxVertexBufferBindCount :: proc(self: ^IndirectCommandBufferDescriptor, maxVertexBufferBindCount: NS.Integer) { +IndirectCommandBufferDescriptor_setMaxVertexBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxVertexBufferBindCount: NS.Integer) { msgSend(nil, self, "setMaxVertexBufferBindCount:", maxVertexBufferBindCount) } @@ -1942,55 +1928,55 @@ Methods: InstanceAccelerationStructureDescriptor :: struct { using _: NS.Copying(InstanceAccelerationStructureDescriptor) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_class_name="alloc") -InstanceAccelerationStructureDescriptor_alloc :: proc() -> ^InstanceAccelerationStructureDescriptor { +InstanceAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, InstanceAccelerationStructureDescriptor, "alloc") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="init") -InstanceAccelerationStructureDescriptor_init :: proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { +InstanceAccelerationStructureDescriptor_init :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, self, "init") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_class_name="descriptor") -InstanceAccelerationStructureDescriptor_descriptor :: proc() -> ^InstanceAccelerationStructureDescriptor { +InstanceAccelerationStructureDescriptor_descriptor :: #force_inline proc() -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, InstanceAccelerationStructureDescriptor, "descriptor") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceCount") -InstanceAccelerationStructureDescriptor_instanceCount :: proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { +InstanceAccelerationStructureDescriptor_instanceCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "instanceCount") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBuffer") -InstanceAccelerationStructureDescriptor_instanceDescriptorBuffer :: proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { +InstanceAccelerationStructureDescriptor_instanceDescriptorBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, self, "instanceDescriptorBuffer") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBufferOffset") -InstanceAccelerationStructureDescriptor_instanceDescriptorBufferOffset :: proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { +InstanceAccelerationStructureDescriptor_instanceDescriptorBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "instanceDescriptorBufferOffset") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorStride") -InstanceAccelerationStructureDescriptor_instanceDescriptorStride :: proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { +InstanceAccelerationStructureDescriptor_instanceDescriptorStride :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "instanceDescriptorStride") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instancedAccelerationStructures") -InstanceAccelerationStructureDescriptor_instancedAccelerationStructures :: proc(self: ^InstanceAccelerationStructureDescriptor) -> ^NS.Array { +InstanceAccelerationStructureDescriptor_instancedAccelerationStructures :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^NS.Array { return msgSend(^NS.Array, self, "instancedAccelerationStructures") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceCount") -InstanceAccelerationStructureDescriptor_setInstanceCount :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceCount: NS.Integer) { +InstanceAccelerationStructureDescriptor_setInstanceCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceCount: NS.Integer) { msgSend(nil, self, "setInstanceCount:", instanceCount) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorBuffer") -InstanceAccelerationStructureDescriptor_setInstanceDescriptorBuffer :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBuffer: ^NS.Object) { +InstanceAccelerationStructureDescriptor_setInstanceDescriptorBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBuffer: ^NS.Object) { msgSend(nil, self, "setInstanceDescriptorBuffer:", instanceDescriptorBuffer) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorBufferOffset") -InstanceAccelerationStructureDescriptor_setInstanceDescriptorBufferOffset :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBufferOffset: NS.Integer) { +InstanceAccelerationStructureDescriptor_setInstanceDescriptorBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBufferOffset: NS.Integer) { msgSend(nil, self, "setInstanceDescriptorBufferOffset:", instanceDescriptorBufferOffset) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorStride") -InstanceAccelerationStructureDescriptor_setInstanceDescriptorStride :: proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorStride: NS.Integer) { +InstanceAccelerationStructureDescriptor_setInstanceDescriptorStride :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorStride: NS.Integer) { msgSend(nil, self, "setInstanceDescriptorStride:", instanceDescriptorStride) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstancedAccelerationStructures") -InstanceAccelerationStructureDescriptor_setInstancedAccelerationStructures :: proc(self: ^InstanceAccelerationStructureDescriptor, instancedAccelerationStructures: ^NS.Array) { +InstanceAccelerationStructureDescriptor_setInstancedAccelerationStructures :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instancedAccelerationStructures: ^NS.Array) { msgSend(nil, self, "setInstancedAccelerationStructures:", instancedAccelerationStructures) } @@ -2011,23 +1997,23 @@ Methods: IntersectionFunctionTableDescriptor :: struct { using _: NS.Copying(IntersectionFunctionTableDescriptor) } @(objc_type=IntersectionFunctionTableDescriptor, objc_class_name="alloc") -IntersectionFunctionTableDescriptor_alloc :: proc() -> ^IntersectionFunctionTableDescriptor { +IntersectionFunctionTableDescriptor_alloc :: #force_inline proc() -> ^IntersectionFunctionTableDescriptor { return msgSend(^IntersectionFunctionTableDescriptor, IntersectionFunctionTableDescriptor, "alloc") } @(objc_type=IntersectionFunctionTableDescriptor, objc_name="init") -IntersectionFunctionTableDescriptor_init :: proc(self: ^IntersectionFunctionTableDescriptor) -> ^IntersectionFunctionTableDescriptor { +IntersectionFunctionTableDescriptor_init :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor) -> ^IntersectionFunctionTableDescriptor { return msgSend(^IntersectionFunctionTableDescriptor, self, "init") } @(objc_type=IntersectionFunctionTableDescriptor, objc_name="functionCount") -IntersectionFunctionTableDescriptor_functionCount :: proc(self: ^IntersectionFunctionTableDescriptor) -> NS.Integer { +IntersectionFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "functionCount") } @(objc_type=IntersectionFunctionTableDescriptor, objc_class_name="intersectionFunctionTableDescriptor") -IntersectionFunctionTableDescriptor_intersectionFunctionTableDescriptor :: proc() -> ^IntersectionFunctionTableDescriptor { +IntersectionFunctionTableDescriptor_intersectionFunctionTableDescriptor :: #force_inline proc() -> ^IntersectionFunctionTableDescriptor { return msgSend(^IntersectionFunctionTableDescriptor, IntersectionFunctionTableDescriptor, "intersectionFunctionTableDescriptor") } @(objc_type=IntersectionFunctionTableDescriptor, objc_name="setFunctionCount") -IntersectionFunctionTableDescriptor_setFunctionCount :: proc(self: ^IntersectionFunctionTableDescriptor, functionCount: NS.Integer) { +IntersectionFunctionTableDescriptor_setFunctionCount :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor, functionCount: NS.Integer) { msgSend(nil, self, "setFunctionCount:", functionCount) } @@ -2052,39 +2038,39 @@ Methods: LinkedFunctions :: struct { using _: NS.Copying(LinkedFunctions) } @(objc_type=LinkedFunctions, objc_class_name="alloc") -LinkedFunctions_alloc :: proc() -> ^LinkedFunctions { +LinkedFunctions_alloc :: #force_inline proc() -> ^LinkedFunctions { return msgSend(^LinkedFunctions, LinkedFunctions, "alloc") } @(objc_type=LinkedFunctions, objc_name="init") -LinkedFunctions_init :: proc(self: ^LinkedFunctions) -> ^LinkedFunctions { +LinkedFunctions_init :: #force_inline proc(self: ^LinkedFunctions) -> ^LinkedFunctions { return msgSend(^LinkedFunctions, self, "init") } @(objc_type=LinkedFunctions, objc_name="binaryFunctions") -LinkedFunctions_binaryFunctions :: proc(self: ^LinkedFunctions) -> ^NS.Array { +LinkedFunctions_binaryFunctions :: #force_inline proc(self: ^LinkedFunctions) -> ^NS.Array { return msgSend(^NS.Array, self, "binaryFunctions") } @(objc_type=LinkedFunctions, objc_name="functions") -LinkedFunctions_functions :: proc(self: ^LinkedFunctions) -> ^NS.Array { +LinkedFunctions_functions :: #force_inline proc(self: ^LinkedFunctions) -> ^NS.Array { return msgSend(^NS.Array, self, "functions") } @(objc_type=LinkedFunctions, objc_name="groups") -LinkedFunctions_groups :: proc(self: ^LinkedFunctions) -> ^NS.Dictionary { +LinkedFunctions_groups :: #force_inline proc(self: ^LinkedFunctions) -> ^NS.Dictionary { return msgSend(^NS.Dictionary, self, "groups") } @(objc_type=LinkedFunctions, objc_class_name="linkedFunctions") -LinkedFunctions_linkedFunctions :: proc() -> ^LinkedFunctions { +LinkedFunctions_linkedFunctions :: #force_inline proc() -> ^LinkedFunctions { return msgSend(^LinkedFunctions, LinkedFunctions, "linkedFunctions") } @(objc_type=LinkedFunctions, objc_name="setBinaryFunctions") -LinkedFunctions_setBinaryFunctions :: proc(self: ^LinkedFunctions, binaryFunctions: ^NS.Array) { +LinkedFunctions_setBinaryFunctions :: #force_inline proc(self: ^LinkedFunctions, binaryFunctions: ^NS.Array) { msgSend(nil, self, "setBinaryFunctions:", binaryFunctions) } @(objc_type=LinkedFunctions, objc_name="setFunctions") -LinkedFunctions_setFunctions :: proc(self: ^LinkedFunctions, functions: ^NS.Array) { +LinkedFunctions_setFunctions :: #force_inline proc(self: ^LinkedFunctions, functions: ^NS.Array) { msgSend(nil, self, "setFunctions:", functions) } @(objc_type=LinkedFunctions, objc_name="setGroups") -LinkedFunctions_setGroups :: proc(self: ^LinkedFunctions, groups: ^NS.Dictionary) { +LinkedFunctions_setGroups :: #force_inline proc(self: ^LinkedFunctions, groups: ^NS.Dictionary) { msgSend(nil, self, "setGroups:", groups) } @@ -2104,19 +2090,19 @@ Methods: PipelineBufferDescriptor :: struct { using _: NS.Copying(PipelineBufferDescriptor) } @(objc_type=PipelineBufferDescriptor, objc_class_name="alloc") -PipelineBufferDescriptor_alloc :: proc() -> ^PipelineBufferDescriptor { +PipelineBufferDescriptor_alloc :: #force_inline proc() -> ^PipelineBufferDescriptor { return msgSend(^PipelineBufferDescriptor, PipelineBufferDescriptor, "alloc") } @(objc_type=PipelineBufferDescriptor, objc_name="init") -PipelineBufferDescriptor_init :: proc(self: ^PipelineBufferDescriptor) -> ^PipelineBufferDescriptor { +PipelineBufferDescriptor_init :: #force_inline proc(self: ^PipelineBufferDescriptor) -> ^PipelineBufferDescriptor { return msgSend(^PipelineBufferDescriptor, self, "init") } @(objc_type=PipelineBufferDescriptor, objc_name="mutability") -PipelineBufferDescriptor_mutability :: proc(self: ^PipelineBufferDescriptor) -> Mutability { +PipelineBufferDescriptor_mutability :: #force_inline proc(self: ^PipelineBufferDescriptor) -> Mutability { return msgSend(Mutability, self, "mutability") } @(objc_type=PipelineBufferDescriptor, objc_name="setMutability") -PipelineBufferDescriptor_setMutability :: proc(self: ^PipelineBufferDescriptor, mutability: Mutability) { +PipelineBufferDescriptor_setMutability :: #force_inline proc(self: ^PipelineBufferDescriptor, mutability: Mutability) { msgSend(nil, self, "setMutability:", mutability) } @@ -2136,19 +2122,19 @@ Methods: PipelineBufferDescriptorArray :: struct { using _: NS.Object } @(objc_type=PipelineBufferDescriptorArray, objc_class_name="alloc") -PipelineBufferDescriptorArray_alloc :: proc() -> ^PipelineBufferDescriptorArray { +PipelineBufferDescriptorArray_alloc :: #force_inline proc() -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, PipelineBufferDescriptorArray, "alloc") } @(objc_type=PipelineBufferDescriptorArray, objc_name="init") -PipelineBufferDescriptorArray_init :: proc(self: ^PipelineBufferDescriptorArray) -> ^PipelineBufferDescriptorArray { +PipelineBufferDescriptorArray_init :: #force_inline proc(self: ^PipelineBufferDescriptorArray) -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, self, "init") } @(objc_type=PipelineBufferDescriptorArray, objc_name="objectAtIndexedSubscript") -PipelineBufferDescriptorArray_objectAtIndexedSubscript :: proc(self: ^PipelineBufferDescriptorArray, bufferIndex: ^NS.Object) -> ^PipelineBufferDescriptor { +PipelineBufferDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^PipelineBufferDescriptorArray, bufferIndex: ^NS.Object) -> ^PipelineBufferDescriptor { return msgSend(^PipelineBufferDescriptor, self, "objectAtIndexedSubscript:", bufferIndex) } @(objc_type=PipelineBufferDescriptorArray, objc_name="setObject") -PipelineBufferDescriptorArray_setObject :: proc(self: ^PipelineBufferDescriptorArray, buffer: ^PipelineBufferDescriptor, bufferIndex: ^NS.Object) { +PipelineBufferDescriptorArray_setObject :: #force_inline proc(self: ^PipelineBufferDescriptorArray, buffer: ^PipelineBufferDescriptor, bufferIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", buffer, bufferIndex) } @@ -2173,39 +2159,39 @@ Methods: PointerType :: struct { using _: NS.Object } @(objc_type=PointerType, objc_class_name="alloc") -PointerType_alloc :: proc() -> ^PointerType { +PointerType_alloc :: #force_inline proc() -> ^PointerType { return msgSend(^PointerType, PointerType, "alloc") } @(objc_type=PointerType, objc_name="init") -PointerType_init :: proc(self: ^PointerType) -> ^PointerType { +PointerType_init :: #force_inline proc(self: ^PointerType) -> ^PointerType { return msgSend(^PointerType, self, "init") } @(objc_type=PointerType, objc_name="access") -PointerType_access :: proc(self: ^PointerType) -> ArgumentAccess { +PointerType_access :: #force_inline proc(self: ^PointerType) -> ArgumentAccess { return msgSend(ArgumentAccess, self, "access") } @(objc_type=PointerType, objc_name="alignment") -PointerType_alignment :: proc(self: ^PointerType) -> NS.Integer { +PointerType_alignment :: #force_inline proc(self: ^PointerType) -> NS.Integer { return msgSend(NS.Integer, self, "alignment") } @(objc_type=PointerType, objc_name="dataSize") -PointerType_dataSize :: proc(self: ^PointerType) -> NS.Integer { +PointerType_dataSize :: #force_inline proc(self: ^PointerType) -> NS.Integer { return msgSend(NS.Integer, self, "dataSize") } @(objc_type=PointerType, objc_name="elementArrayType") -PointerType_elementArrayType :: proc(self: ^PointerType) -> ^ArrayType { +PointerType_elementArrayType :: #force_inline proc(self: ^PointerType) -> ^ArrayType { return msgSend(^ArrayType, self, "elementArrayType") } @(objc_type=PointerType, objc_name="elementIsArgumentBuffer") -PointerType_elementIsArgumentBuffer :: proc(self: ^PointerType) -> BOOL { +PointerType_elementIsArgumentBuffer :: #force_inline proc(self: ^PointerType) -> BOOL { return msgSend(BOOL, self, "elementIsArgumentBuffer") } @(objc_type=PointerType, objc_name="elementStructType") -PointerType_elementStructType :: proc(self: ^PointerType) -> ^StructType { +PointerType_elementStructType :: #force_inline proc(self: ^PointerType) -> ^StructType { return msgSend(^StructType, self, "elementStructType") } @(objc_type=PointerType, objc_name="elementType") -PointerType_elementType :: proc(self: ^PointerType) -> DataType { +PointerType_elementType :: #force_inline proc(self: ^PointerType) -> DataType { return msgSend(DataType, self, "elementType") } @@ -2226,23 +2212,23 @@ Methods: PrimitiveAccelerationStructureDescriptor :: struct { using _: NS.Copying(PrimitiveAccelerationStructureDescriptor) } @(objc_type=PrimitiveAccelerationStructureDescriptor, objc_class_name="alloc") -PrimitiveAccelerationStructureDescriptor_alloc :: proc() -> ^PrimitiveAccelerationStructureDescriptor { +PrimitiveAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^PrimitiveAccelerationStructureDescriptor { return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "alloc") } @(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="init") -PrimitiveAccelerationStructureDescriptor_init :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> ^PrimitiveAccelerationStructureDescriptor { +PrimitiveAccelerationStructureDescriptor_init :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> ^PrimitiveAccelerationStructureDescriptor { return msgSend(^PrimitiveAccelerationStructureDescriptor, self, "init") } @(objc_type=PrimitiveAccelerationStructureDescriptor, objc_class_name="descriptor") -PrimitiveAccelerationStructureDescriptor_descriptor :: proc() -> ^PrimitiveAccelerationStructureDescriptor { +PrimitiveAccelerationStructureDescriptor_descriptor :: #force_inline proc() -> ^PrimitiveAccelerationStructureDescriptor { return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "descriptor") } @(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="geometryDescriptors") -PrimitiveAccelerationStructureDescriptor_geometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor) -> ^NS.Array { +PrimitiveAccelerationStructureDescriptor_geometryDescriptors :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> ^NS.Array { return msgSend(^NS.Array, self, "geometryDescriptors") } @(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="setGeometryDescriptors") -PrimitiveAccelerationStructureDescriptor_setGeometryDescriptors :: proc(self: ^PrimitiveAccelerationStructureDescriptor, geometryDescriptors: ^NS.Array) { +PrimitiveAccelerationStructureDescriptor_setGeometryDescriptors :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor, geometryDescriptors: ^NS.Array) { msgSend(nil, self, "setGeometryDescriptors:", geometryDescriptors) } @@ -2262,19 +2248,19 @@ Methods: RasterizationRateLayerArray :: struct { using _: NS.Object } @(objc_type=RasterizationRateLayerArray, objc_class_name="alloc") -RasterizationRateLayerArray_alloc :: proc() -> ^RasterizationRateLayerArray { +RasterizationRateLayerArray_alloc :: #force_inline proc() -> ^RasterizationRateLayerArray { return msgSend(^RasterizationRateLayerArray, RasterizationRateLayerArray, "alloc") } @(objc_type=RasterizationRateLayerArray, objc_name="init") -RasterizationRateLayerArray_init :: proc(self: ^RasterizationRateLayerArray) -> ^RasterizationRateLayerArray { +RasterizationRateLayerArray_init :: #force_inline proc(self: ^RasterizationRateLayerArray) -> ^RasterizationRateLayerArray { return msgSend(^RasterizationRateLayerArray, self, "init") } @(objc_type=RasterizationRateLayerArray, objc_name="objectAtIndexedSubscript") -RasterizationRateLayerArray_objectAtIndexedSubscript :: proc(self: ^RasterizationRateLayerArray, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { +RasterizationRateLayerArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateLayerArray, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "objectAtIndexedSubscript:", layerIndex) } @(objc_type=RasterizationRateLayerArray, objc_name="setObject") -RasterizationRateLayerArray_setObject :: proc(self: ^RasterizationRateLayerArray, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { +RasterizationRateLayerArray_setObject :: #force_inline proc(self: ^RasterizationRateLayerArray, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", layer, layerIndex) } @@ -2299,39 +2285,39 @@ Methods: RasterizationRateLayerDescriptor :: struct { using _: NS.Copying(RasterizationRateLayerDescriptor) } @(objc_type=RasterizationRateLayerDescriptor, objc_class_name="alloc") -RasterizationRateLayerDescriptor_alloc :: proc() -> ^RasterizationRateLayerDescriptor { +RasterizationRateLayerDescriptor_alloc :: #force_inline proc() -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, RasterizationRateLayerDescriptor, "alloc") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="horizontal") -RasterizationRateLayerDescriptor_horizontal :: proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateSampleArray { +RasterizationRateLayerDescriptor_horizontal :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateSampleArray { return msgSend(^RasterizationRateSampleArray, self, "horizontal") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="horizontalSampleStorage") -RasterizationRateLayerDescriptor_horizontalSampleStorage :: proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { +RasterizationRateLayerDescriptor_horizontalSampleStorage :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { return msgSend(^f32, self, "horizontalSampleStorage") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="init") -RasterizationRateLayerDescriptor_init :: proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateLayerDescriptor { +RasterizationRateLayerDescriptor_init :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "init") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="initWithSampleCount") -RasterizationRateLayerDescriptor_initWithSampleCount :: proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size) -> ^RasterizationRateLayerDescriptor { +RasterizationRateLayerDescriptor_initWithSampleCount :: #force_inline proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "initWithSampleCount:", sampleCount) } @(objc_type=RasterizationRateLayerDescriptor, objc_name="initWithSampleCountWithDimensions") -RasterizationRateLayerDescriptor_initWithSampleCountWithDimensions :: proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size, horizontal: ^f32, vertical: ^f32) -> ^RasterizationRateLayerDescriptor { +RasterizationRateLayerDescriptor_initWithSampleCountWithDimensions :: #force_inline proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size, horizontal: ^f32, vertical: ^f32) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "initWithSampleCount:horizontal:vertical:", sampleCount, horizontal, vertical) } @(objc_type=RasterizationRateLayerDescriptor, objc_name="sampleCount") -RasterizationRateLayerDescriptor_sampleCount :: proc(self: ^RasterizationRateLayerDescriptor) -> Size { +RasterizationRateLayerDescriptor_sampleCount :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> Size { return msgSend(Size, self, "sampleCount") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="vertical") -RasterizationRateLayerDescriptor_vertical :: proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateSampleArray { +RasterizationRateLayerDescriptor_vertical :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateSampleArray { return msgSend(^RasterizationRateSampleArray, self, "vertical") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="verticalSampleStorage") -RasterizationRateLayerDescriptor_verticalSampleStorage :: proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { +RasterizationRateLayerDescriptor_verticalSampleStorage :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { return msgSend(^f32, self, "verticalSampleStorage") } @@ -2360,55 +2346,55 @@ Methods: RasterizationRateMapDescriptor :: struct { using _: NS.Copying(RasterizationRateMapDescriptor) } @(objc_type=RasterizationRateMapDescriptor, objc_class_name="alloc") -RasterizationRateMapDescriptor_alloc :: proc() -> ^RasterizationRateMapDescriptor { +RasterizationRateMapDescriptor_alloc :: #force_inline proc() -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "alloc") } @(objc_type=RasterizationRateMapDescriptor, objc_name="init") -RasterizationRateMapDescriptor_init :: proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMapDescriptor { +RasterizationRateMapDescriptor_init :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, self, "init") } @(objc_type=RasterizationRateMapDescriptor, objc_name="label") -RasterizationRateMapDescriptor_label :: proc(self: ^RasterizationRateMapDescriptor) -> ^NS.String { +RasterizationRateMapDescriptor_label :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=RasterizationRateMapDescriptor, objc_name="layerAtIndex") -RasterizationRateMapDescriptor_layerAtIndex :: proc(self: ^RasterizationRateMapDescriptor, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { +RasterizationRateMapDescriptor_layerAtIndex :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "layerAtIndex:", layerIndex) } @(objc_type=RasterizationRateMapDescriptor, objc_name="layerCount") -RasterizationRateMapDescriptor_layerCount :: proc(self: ^RasterizationRateMapDescriptor) -> NS.Integer { +RasterizationRateMapDescriptor_layerCount :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "layerCount") } @(objc_type=RasterizationRateMapDescriptor, objc_name="layers") -RasterizationRateMapDescriptor_layers :: proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateLayerArray { +RasterizationRateMapDescriptor_layers :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateLayerArray { return msgSend(^RasterizationRateLayerArray, self, "layers") } @(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize") -RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize :: proc(screenSize: Size) -> ^RasterizationRateMapDescriptor { +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize :: #force_inline proc(screenSize: Size) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:", screenSize) } @(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize_layer_") -RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layer_ :: proc(screenSize: Size, layer: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layer_ :: #force_inline proc(screenSize: Size, layer: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layer:", screenSize, layer) } @(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize_layerCount_layers_") -RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layerCount_layers_ :: proc(screenSize: Size, layerCount: ^NS.Object, layers: ^^RasterizationRateLayerDescriptor ) -> ^RasterizationRateMapDescriptor { +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layerCount_layers_ :: #force_inline proc(screenSize: Size, layerCount: ^NS.Object, layers: ^^RasterizationRateLayerDescriptor ) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layerCount:layers:", screenSize, layerCount, layers) } @(objc_type=RasterizationRateMapDescriptor, objc_name="screenSize") -RasterizationRateMapDescriptor_screenSize :: proc(self: ^RasterizationRateMapDescriptor) -> Size { +RasterizationRateMapDescriptor_screenSize :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> Size { return msgSend(Size, self, "screenSize") } @(objc_type=RasterizationRateMapDescriptor, objc_name="setLabel") -RasterizationRateMapDescriptor_setLabel :: proc(self: ^RasterizationRateMapDescriptor, label: ^NS.String) { +RasterizationRateMapDescriptor_setLabel :: #force_inline proc(self: ^RasterizationRateMapDescriptor, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=RasterizationRateMapDescriptor, objc_name="setLayer") -RasterizationRateMapDescriptor_setLayer :: proc(self: ^RasterizationRateMapDescriptor, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { +RasterizationRateMapDescriptor_setLayer :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { msgSend(nil, self, "setLayer:atIndex:", layer, layerIndex) } @(objc_type=RasterizationRateMapDescriptor, objc_name="setScreenSize") -RasterizationRateMapDescriptor_setScreenSize :: proc(self: ^RasterizationRateMapDescriptor, screenSize: Size) { +RasterizationRateMapDescriptor_setScreenSize :: #force_inline proc(self: ^RasterizationRateMapDescriptor, screenSize: Size) { msgSend(nil, self, "setScreenSize:", screenSize) } @@ -2428,19 +2414,19 @@ Methods: RasterizationRateSampleArray :: struct { using _: NS.Object } @(objc_type=RasterizationRateSampleArray, objc_class_name="alloc") -RasterizationRateSampleArray_alloc :: proc() -> ^RasterizationRateSampleArray { +RasterizationRateSampleArray_alloc :: #force_inline proc() -> ^RasterizationRateSampleArray { return msgSend(^RasterizationRateSampleArray, RasterizationRateSampleArray, "alloc") } @(objc_type=RasterizationRateSampleArray, objc_name="init") -RasterizationRateSampleArray_init :: proc(self: ^RasterizationRateSampleArray) -> ^RasterizationRateSampleArray { +RasterizationRateSampleArray_init :: #force_inline proc(self: ^RasterizationRateSampleArray) -> ^RasterizationRateSampleArray { return msgSend(^RasterizationRateSampleArray, self, "init") } @(objc_type=RasterizationRateSampleArray, objc_name="objectAtIndexedSubscript") -RasterizationRateSampleArray_objectAtIndexedSubscript :: proc(self: ^RasterizationRateSampleArray, index: ^NS.Object) -> ^NS.Number { +RasterizationRateSampleArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateSampleArray, index: ^NS.Object) -> ^NS.Number { return msgSend(^NS.Number, self, "objectAtIndexedSubscript:", index) } @(objc_type=RasterizationRateSampleArray, objc_name="setObject") -RasterizationRateSampleArray_setObject :: proc(self: ^RasterizationRateSampleArray, value: ^NS.Number, index: ^NS.Object) { +RasterizationRateSampleArray_setObject :: #force_inline proc(self: ^RasterizationRateSampleArray, value: ^NS.Number, index: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", value, index) } @@ -2480,99 +2466,99 @@ Methods: RenderPassAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassAttachmentDescriptor) } @(objc_type=RenderPassAttachmentDescriptor, objc_class_name="alloc") -RenderPassAttachmentDescriptor_alloc :: proc() -> ^RenderPassAttachmentDescriptor { +RenderPassAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassAttachmentDescriptor { return msgSend(^RenderPassAttachmentDescriptor, RenderPassAttachmentDescriptor, "alloc") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="init") -RenderPassAttachmentDescriptor_init :: proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { +RenderPassAttachmentDescriptor_init :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { return msgSend(^RenderPassAttachmentDescriptor, self, "init") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="depthPlane") -RenderPassAttachmentDescriptor_depthPlane :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { +RenderPassAttachmentDescriptor_depthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "depthPlane") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="level") -RenderPassAttachmentDescriptor_level :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { +RenderPassAttachmentDescriptor_level :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "level") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="loadAction") -RenderPassAttachmentDescriptor_loadAction :: proc(self: ^RenderPassAttachmentDescriptor) -> LoadAction { +RenderPassAttachmentDescriptor_loadAction :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> LoadAction { return msgSend(LoadAction, self, "loadAction") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveDepthPlane") -RenderPassAttachmentDescriptor_resolveDepthPlane :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { +RenderPassAttachmentDescriptor_resolveDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "resolveDepthPlane") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveLevel") -RenderPassAttachmentDescriptor_resolveLevel :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { +RenderPassAttachmentDescriptor_resolveLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "resolveLevel") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveSlice") -RenderPassAttachmentDescriptor_resolveSlice :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { +RenderPassAttachmentDescriptor_resolveSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "resolveSlice") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveTexture") -RenderPassAttachmentDescriptor_resolveTexture :: proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { +RenderPassAttachmentDescriptor_resolveTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { return msgSend(^RenderPassAttachmentDescriptor, self, "resolveTexture") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setDepthPlane") -RenderPassAttachmentDescriptor_setDepthPlane :: proc(self: ^RenderPassAttachmentDescriptor, depthPlane: NS.Integer) { +RenderPassAttachmentDescriptor_setDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, depthPlane: NS.Integer) { msgSend(nil, self, "setDepthPlane:", depthPlane) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setLevel") -RenderPassAttachmentDescriptor_setLevel :: proc(self: ^RenderPassAttachmentDescriptor, level: NS.Integer) { +RenderPassAttachmentDescriptor_setLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, level: NS.Integer) { msgSend(nil, self, "setLevel:", level) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setLoadAction") -RenderPassAttachmentDescriptor_setLoadAction :: proc(self: ^RenderPassAttachmentDescriptor, loadAction: LoadAction) { +RenderPassAttachmentDescriptor_setLoadAction :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, loadAction: LoadAction) { msgSend(nil, self, "setLoadAction:", loadAction) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveDepthPlane") -RenderPassAttachmentDescriptor_setResolveDepthPlane :: proc(self: ^RenderPassAttachmentDescriptor, resolveDepthPlane: NS.Integer) { +RenderPassAttachmentDescriptor_setResolveDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveDepthPlane: NS.Integer) { msgSend(nil, self, "setResolveDepthPlane:", resolveDepthPlane) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveLevel") -RenderPassAttachmentDescriptor_setResolveLevel :: proc(self: ^RenderPassAttachmentDescriptor, resolveLevel: NS.Integer) { +RenderPassAttachmentDescriptor_setResolveLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveLevel: NS.Integer) { msgSend(nil, self, "setResolveLevel:", resolveLevel) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveSlice") -RenderPassAttachmentDescriptor_setResolveSlice :: proc(self: ^RenderPassAttachmentDescriptor, resolveSlice: NS.Integer) { +RenderPassAttachmentDescriptor_setResolveSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveSlice: NS.Integer) { msgSend(nil, self, "setResolveSlice:", resolveSlice) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveTexture") -RenderPassAttachmentDescriptor_setResolveTexture :: proc(self: ^RenderPassAttachmentDescriptor, resolveTexture: ^NS.Object) { +RenderPassAttachmentDescriptor_setResolveTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveTexture: ^NS.Object) { msgSend(nil, self, "setResolveTexture:", resolveTexture) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setSlice") -RenderPassAttachmentDescriptor_setSlice :: proc(self: ^RenderPassAttachmentDescriptor, slice: NS.Integer) { +RenderPassAttachmentDescriptor_setSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, slice: NS.Integer) { msgSend(nil, self, "setSlice:", slice) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setStoreAction") -RenderPassAttachmentDescriptor_setStoreAction :: proc(self: ^RenderPassAttachmentDescriptor, storeAction: StoreAction) { +RenderPassAttachmentDescriptor_setStoreAction :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, storeAction: StoreAction) { msgSend(nil, self, "setStoreAction:", storeAction) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setStoreActionOptions") -RenderPassAttachmentDescriptor_setStoreActionOptions :: proc(self: ^RenderPassAttachmentDescriptor, storeActionOptions: StoreActionOptions) { +RenderPassAttachmentDescriptor_setStoreActionOptions :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, storeActionOptions: StoreActionOptions) { msgSend(nil, self, "setStoreActionOptions:", storeActionOptions) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setTexture") -RenderPassAttachmentDescriptor_setTexture :: proc(self: ^RenderPassAttachmentDescriptor, texture: ^NS.Object) { +RenderPassAttachmentDescriptor_setTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, texture: ^NS.Object) { msgSend(nil, self, "setTexture:", texture) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="slice") -RenderPassAttachmentDescriptor_slice :: proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { +RenderPassAttachmentDescriptor_slice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "slice") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="storeAction") -RenderPassAttachmentDescriptor_storeAction :: proc(self: ^RenderPassAttachmentDescriptor) -> StoreAction { +RenderPassAttachmentDescriptor_storeAction :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> StoreAction { return msgSend(StoreAction, self, "storeAction") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="storeActionOptions") -RenderPassAttachmentDescriptor_storeActionOptions :: proc(self: ^RenderPassAttachmentDescriptor) -> StoreActionOptions { +RenderPassAttachmentDescriptor_storeActionOptions :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> StoreActionOptions { return msgSend(StoreActionOptions, self, "storeActionOptions") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="texture") -RenderPassAttachmentDescriptor_texture :: proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { +RenderPassAttachmentDescriptor_texture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { return msgSend(^RenderPassAttachmentDescriptor, self, "texture") } @@ -2592,19 +2578,19 @@ Methods: RenderPassColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassColorAttachmentDescriptor) } @(objc_type=RenderPassColorAttachmentDescriptor, objc_class_name="alloc") -RenderPassColorAttachmentDescriptor_alloc :: proc() -> ^RenderPassColorAttachmentDescriptor { +RenderPassColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassColorAttachmentDescriptor { return msgSend(^RenderPassColorAttachmentDescriptor, RenderPassColorAttachmentDescriptor, "alloc") } @(objc_type=RenderPassColorAttachmentDescriptor, objc_name="init") -RenderPassColorAttachmentDescriptor_init :: proc(self: ^RenderPassColorAttachmentDescriptor) -> ^RenderPassColorAttachmentDescriptor { +RenderPassColorAttachmentDescriptor_init :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptor) -> ^RenderPassColorAttachmentDescriptor { return msgSend(^RenderPassColorAttachmentDescriptor, self, "init") } @(objc_type=RenderPassColorAttachmentDescriptor, objc_name="clearColor") -RenderPassColorAttachmentDescriptor_clearColor :: proc(self: ^RenderPassColorAttachmentDescriptor) -> ClearColor { +RenderPassColorAttachmentDescriptor_clearColor :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptor) -> ClearColor { return msgSend(ClearColor, self, "clearColor") } @(objc_type=RenderPassColorAttachmentDescriptor, objc_name="setClearColor") -RenderPassColorAttachmentDescriptor_setClearColor :: proc(self: ^RenderPassColorAttachmentDescriptor, clearColor: ClearColor) { +RenderPassColorAttachmentDescriptor_setClearColor :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptor, clearColor: ClearColor) { msgSend(nil, self, "setClearColor:", clearColor) } @@ -2624,19 +2610,19 @@ Methods: RenderPassColorAttachmentDescriptorArray :: struct { using _: NS.Object } @(objc_type=RenderPassColorAttachmentDescriptorArray, objc_class_name="alloc") -RenderPassColorAttachmentDescriptorArray_alloc :: proc() -> ^RenderPassColorAttachmentDescriptorArray { +RenderPassColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^RenderPassColorAttachmentDescriptorArray { return msgSend(^RenderPassColorAttachmentDescriptorArray, RenderPassColorAttachmentDescriptorArray, "alloc") } @(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="init") -RenderPassColorAttachmentDescriptorArray_init :: proc(self: ^RenderPassColorAttachmentDescriptorArray) -> ^RenderPassColorAttachmentDescriptorArray { +RenderPassColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray) -> ^RenderPassColorAttachmentDescriptorArray { return msgSend(^RenderPassColorAttachmentDescriptorArray, self, "init") } @(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPassColorAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^RenderPassColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassColorAttachmentDescriptor { +RenderPassColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassColorAttachmentDescriptor { return msgSend(^RenderPassColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="setObject") -RenderPassColorAttachmentDescriptorArray_setObject :: proc(self: ^RenderPassColorAttachmentDescriptorArray, attachment: ^RenderPassColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { +RenderPassColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachment: ^RenderPassColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -2658,27 +2644,27 @@ Methods: RenderPassDepthAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassDepthAttachmentDescriptor) } @(objc_type=RenderPassDepthAttachmentDescriptor, objc_class_name="alloc") -RenderPassDepthAttachmentDescriptor_alloc :: proc() -> ^RenderPassDepthAttachmentDescriptor { +RenderPassDepthAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassDepthAttachmentDescriptor { return msgSend(^RenderPassDepthAttachmentDescriptor, RenderPassDepthAttachmentDescriptor, "alloc") } @(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="init") -RenderPassDepthAttachmentDescriptor_init :: proc(self: ^RenderPassDepthAttachmentDescriptor) -> ^RenderPassDepthAttachmentDescriptor { +RenderPassDepthAttachmentDescriptor_init :: #force_inline proc(self: ^RenderPassDepthAttachmentDescriptor) -> ^RenderPassDepthAttachmentDescriptor { return msgSend(^RenderPassDepthAttachmentDescriptor, self, "init") } @(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="clearDepth") -RenderPassDepthAttachmentDescriptor_clearDepth :: proc(self: ^RenderPassDepthAttachmentDescriptor) -> f64 { +RenderPassDepthAttachmentDescriptor_clearDepth :: #force_inline proc(self: ^RenderPassDepthAttachmentDescriptor) -> f64 { return msgSend(f64, self, "clearDepth") } @(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="depthResolveFilter") -RenderPassDepthAttachmentDescriptor_depthResolveFilter :: proc(self: ^RenderPassDepthAttachmentDescriptor) -> MultisampleDepthResolveFilter { +RenderPassDepthAttachmentDescriptor_depthResolveFilter :: #force_inline proc(self: ^RenderPassDepthAttachmentDescriptor) -> MultisampleDepthResolveFilter { return msgSend(MultisampleDepthResolveFilter, self, "depthResolveFilter") } @(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="setClearDepth") -RenderPassDepthAttachmentDescriptor_setClearDepth :: proc(self: ^RenderPassDepthAttachmentDescriptor, clearDepth: f64) { +RenderPassDepthAttachmentDescriptor_setClearDepth :: #force_inline proc(self: ^RenderPassDepthAttachmentDescriptor, clearDepth: f64) { msgSend(nil, self, "setClearDepth:", clearDepth) } @(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="setDepthResolveFilter") -RenderPassDepthAttachmentDescriptor_setDepthResolveFilter :: proc(self: ^RenderPassDepthAttachmentDescriptor, depthResolveFilter: MultisampleDepthResolveFilter) { +RenderPassDepthAttachmentDescriptor_setDepthResolveFilter :: #force_inline proc(self: ^RenderPassDepthAttachmentDescriptor, depthResolveFilter: MultisampleDepthResolveFilter) { msgSend(nil, self, "setDepthResolveFilter:", depthResolveFilter) } @@ -2725,127 +2711,127 @@ Methods: RenderPassDescriptor :: struct { using _: NS.Copying(RenderPassDescriptor) } @(objc_type=RenderPassDescriptor, objc_class_name="alloc") -RenderPassDescriptor_alloc :: proc() -> ^RenderPassDescriptor { +RenderPassDescriptor_alloc :: #force_inline proc() -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, RenderPassDescriptor, "alloc") } @(objc_type=RenderPassDescriptor, objc_name="init") -RenderPassDescriptor_init :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { +RenderPassDescriptor_init :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, self, "init") } @(objc_type=RenderPassDescriptor, objc_name="colorAttachments") -RenderPassDescriptor_colorAttachments :: proc(self: ^RenderPassDescriptor) -> ^RenderPassColorAttachmentDescriptorArray { +RenderPassDescriptor_colorAttachments :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassColorAttachmentDescriptorArray { return msgSend(^RenderPassColorAttachmentDescriptorArray, self, "colorAttachments") } @(objc_type=RenderPassDescriptor, objc_name="defaultRasterSampleCount") -RenderPassDescriptor_defaultRasterSampleCount :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_defaultRasterSampleCount :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "defaultRasterSampleCount") } @(objc_type=RenderPassDescriptor, objc_name="depthAttachment") -RenderPassDescriptor_depthAttachment :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDepthAttachmentDescriptor { +RenderPassDescriptor_depthAttachment :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDepthAttachmentDescriptor { return msgSend(^RenderPassDepthAttachmentDescriptor, self, "depthAttachment") } @(objc_type=RenderPassDescriptor, objc_name="getSamplePositions") -RenderPassDescriptor_getSamplePositions :: proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) -> ^RenderPassDescriptor { +RenderPassDescriptor_getSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, self, "getSamplePositions:count:", positions, count) } @(objc_type=RenderPassDescriptor, objc_name="imageblockSampleLength") -RenderPassDescriptor_imageblockSampleLength :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_imageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "imageblockSampleLength") } @(objc_type=RenderPassDescriptor, objc_name="rasterizationRateMap") -RenderPassDescriptor_rasterizationRateMap :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { +RenderPassDescriptor_rasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, self, "rasterizationRateMap") } @(objc_type=RenderPassDescriptor, objc_class_name="renderPassDescriptor") -RenderPassDescriptor_renderPassDescriptor :: proc() -> ^RenderPassDescriptor { +RenderPassDescriptor_renderPassDescriptor :: #force_inline proc() -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, RenderPassDescriptor, "renderPassDescriptor") } @(objc_type=RenderPassDescriptor, objc_name="renderTargetArrayLength") -RenderPassDescriptor_renderTargetArrayLength :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_renderTargetArrayLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "renderTargetArrayLength") } @(objc_type=RenderPassDescriptor, objc_name="renderTargetHeight") -RenderPassDescriptor_renderTargetHeight :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_renderTargetHeight :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "renderTargetHeight") } @(objc_type=RenderPassDescriptor, objc_name="renderTargetWidth") -RenderPassDescriptor_renderTargetWidth :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_renderTargetWidth :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "renderTargetWidth") } @(objc_type=RenderPassDescriptor, objc_name="sampleBufferAttachments") -RenderPassDescriptor_sampleBufferAttachments :: proc(self: ^RenderPassDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptorArray { +RenderPassDescriptor_sampleBufferAttachments :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptorArray { return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") } @(objc_type=RenderPassDescriptor, objc_name="setDefaultRasterSampleCount") -RenderPassDescriptor_setDefaultRasterSampleCount :: proc(self: ^RenderPassDescriptor, defaultRasterSampleCount: NS.Integer) { +RenderPassDescriptor_setDefaultRasterSampleCount :: #force_inline proc(self: ^RenderPassDescriptor, defaultRasterSampleCount: NS.Integer) { msgSend(nil, self, "setDefaultRasterSampleCount:", defaultRasterSampleCount) } @(objc_type=RenderPassDescriptor, objc_name="setDepthAttachment") -RenderPassDescriptor_setDepthAttachment :: proc(self: ^RenderPassDescriptor, depthAttachment: ^RenderPassDepthAttachmentDescriptor) { +RenderPassDescriptor_setDepthAttachment :: #force_inline proc(self: ^RenderPassDescriptor, depthAttachment: ^RenderPassDepthAttachmentDescriptor) { msgSend(nil, self, "setDepthAttachment:", depthAttachment) } @(objc_type=RenderPassDescriptor, objc_name="setImageblockSampleLength") -RenderPassDescriptor_setImageblockSampleLength :: proc(self: ^RenderPassDescriptor, imageblockSampleLength: NS.Integer) { +RenderPassDescriptor_setImageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor, imageblockSampleLength: NS.Integer) { msgSend(nil, self, "setImageblockSampleLength:", imageblockSampleLength) } @(objc_type=RenderPassDescriptor, objc_name="setRasterizationRateMap") -RenderPassDescriptor_setRasterizationRateMap :: proc(self: ^RenderPassDescriptor, rasterizationRateMap: ^NS.Object) { +RenderPassDescriptor_setRasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor, rasterizationRateMap: ^NS.Object) { msgSend(nil, self, "setRasterizationRateMap:", rasterizationRateMap) } @(objc_type=RenderPassDescriptor, objc_name="setRenderTargetArrayLength") -RenderPassDescriptor_setRenderTargetArrayLength :: proc(self: ^RenderPassDescriptor, renderTargetArrayLength: NS.Integer) { +RenderPassDescriptor_setRenderTargetArrayLength :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetArrayLength: NS.Integer) { msgSend(nil, self, "setRenderTargetArrayLength:", renderTargetArrayLength) } @(objc_type=RenderPassDescriptor, objc_name="setRenderTargetHeight") -RenderPassDescriptor_setRenderTargetHeight :: proc(self: ^RenderPassDescriptor, renderTargetHeight: NS.Integer) { +RenderPassDescriptor_setRenderTargetHeight :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetHeight: NS.Integer) { msgSend(nil, self, "setRenderTargetHeight:", renderTargetHeight) } @(objc_type=RenderPassDescriptor, objc_name="setRenderTargetWidth") -RenderPassDescriptor_setRenderTargetWidth :: proc(self: ^RenderPassDescriptor, renderTargetWidth: NS.Integer) { +RenderPassDescriptor_setRenderTargetWidth :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetWidth: NS.Integer) { msgSend(nil, self, "setRenderTargetWidth:", renderTargetWidth) } @(objc_type=RenderPassDescriptor, objc_name="setSamplePositions") -RenderPassDescriptor_setSamplePositions :: proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) { +RenderPassDescriptor_setSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) { msgSend(nil, self, "setSamplePositions:count:", positions, count) } @(objc_type=RenderPassDescriptor, objc_name="setStencilAttachment") -RenderPassDescriptor_setStencilAttachment :: proc(self: ^RenderPassDescriptor, stencilAttachment: ^RenderPassStencilAttachmentDescriptor) { +RenderPassDescriptor_setStencilAttachment :: #force_inline proc(self: ^RenderPassDescriptor, stencilAttachment: ^RenderPassStencilAttachmentDescriptor) { msgSend(nil, self, "setStencilAttachment:", stencilAttachment) } @(objc_type=RenderPassDescriptor, objc_name="setThreadgroupMemoryLength") -RenderPassDescriptor_setThreadgroupMemoryLength :: proc(self: ^RenderPassDescriptor, threadgroupMemoryLength: NS.Integer) { +RenderPassDescriptor_setThreadgroupMemoryLength :: #force_inline proc(self: ^RenderPassDescriptor, threadgroupMemoryLength: NS.Integer) { msgSend(nil, self, "setThreadgroupMemoryLength:", threadgroupMemoryLength) } @(objc_type=RenderPassDescriptor, objc_name="setTileHeight") -RenderPassDescriptor_setTileHeight :: proc(self: ^RenderPassDescriptor, tileHeight: NS.Integer) { +RenderPassDescriptor_setTileHeight :: #force_inline proc(self: ^RenderPassDescriptor, tileHeight: NS.Integer) { msgSend(nil, self, "setTileHeight:", tileHeight) } @(objc_type=RenderPassDescriptor, objc_name="setTileWidth") -RenderPassDescriptor_setTileWidth :: proc(self: ^RenderPassDescriptor, tileWidth: NS.Integer) { +RenderPassDescriptor_setTileWidth :: #force_inline proc(self: ^RenderPassDescriptor, tileWidth: NS.Integer) { msgSend(nil, self, "setTileWidth:", tileWidth) } @(objc_type=RenderPassDescriptor, objc_name="setVisibilityResultBuffer") -RenderPassDescriptor_setVisibilityResultBuffer :: proc(self: ^RenderPassDescriptor, visibilityResultBuffer: ^NS.Object) { +RenderPassDescriptor_setVisibilityResultBuffer :: #force_inline proc(self: ^RenderPassDescriptor, visibilityResultBuffer: ^NS.Object) { msgSend(nil, self, "setVisibilityResultBuffer:", visibilityResultBuffer) } @(objc_type=RenderPassDescriptor, objc_name="stencilAttachment") -RenderPassDescriptor_stencilAttachment :: proc(self: ^RenderPassDescriptor) -> ^RenderPassStencilAttachmentDescriptor { +RenderPassDescriptor_stencilAttachment :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassStencilAttachmentDescriptor { return msgSend(^RenderPassStencilAttachmentDescriptor, self, "stencilAttachment") } @(objc_type=RenderPassDescriptor, objc_name="threadgroupMemoryLength") -RenderPassDescriptor_threadgroupMemoryLength :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_threadgroupMemoryLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "threadgroupMemoryLength") } @(objc_type=RenderPassDescriptor, objc_name="tileHeight") -RenderPassDescriptor_tileHeight :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_tileHeight :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "tileHeight") } @(objc_type=RenderPassDescriptor, objc_name="tileWidth") -RenderPassDescriptor_tileWidth :: proc(self: ^RenderPassDescriptor) -> NS.Integer { +RenderPassDescriptor_tileWidth :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "tileWidth") } @(objc_type=RenderPassDescriptor, objc_name="visibilityResultBuffer") -RenderPassDescriptor_visibilityResultBuffer :: proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { +RenderPassDescriptor_visibilityResultBuffer :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, self, "visibilityResultBuffer") } @@ -2873,51 +2859,51 @@ Methods: RenderPassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassSampleBufferAttachmentDescriptor) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_class_name="alloc") -RenderPassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^RenderPassSampleBufferAttachmentDescriptor { +RenderPassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, RenderPassSampleBufferAttachmentDescriptor, "alloc") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="init") -RenderPassSampleBufferAttachmentDescriptor_init :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { +RenderPassSampleBufferAttachmentDescriptor_init :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="endOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_endOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { +RenderPassSampleBufferAttachmentDescriptor_endOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "endOfFragmentSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="endOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_endOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { +RenderPassSampleBufferAttachmentDescriptor_endOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "endOfVertexSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { +RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setEndOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfFragmentSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setEndOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfFragmentSampleIndex: NS.Integer) { msgSend(nil, self, "setEndOfFragmentSampleIndex:", endOfFragmentSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setEndOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfVertexSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setEndOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfVertexSampleIndex: NS.Integer) { msgSend(nil, self, "setEndOfVertexSampleIndex:", endOfVertexSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -RenderPassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +RenderPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setStartOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setStartOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfFragmentSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setStartOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfFragmentSampleIndex: NS.Integer) { msgSend(nil, self, "setStartOfFragmentSampleIndex:", startOfFragmentSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setStartOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setStartOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfVertexSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setStartOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfVertexSampleIndex: NS.Integer) { msgSend(nil, self, "setStartOfVertexSampleIndex:", startOfVertexSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="startOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_startOfFragmentSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { +RenderPassSampleBufferAttachmentDescriptor_startOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "startOfFragmentSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="startOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_startOfVertexSampleIndex :: proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { +RenderPassSampleBufferAttachmentDescriptor_startOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "startOfVertexSampleIndex") } @@ -2937,19 +2923,19 @@ Methods: RenderPassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } @(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") -RenderPassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^RenderPassSampleBufferAttachmentDescriptorArray { +RenderPassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^RenderPassSampleBufferAttachmentDescriptorArray { return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, RenderPassSampleBufferAttachmentDescriptorArray, "alloc") } @(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="init") -RenderPassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray) -> ^RenderPassSampleBufferAttachmentDescriptorArray { +RenderPassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray) -> ^RenderPassSampleBufferAttachmentDescriptorArray { return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassSampleBufferAttachmentDescriptor { +RenderPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -RenderPassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachment: ^RenderPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +RenderPassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachment: ^RenderPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -2971,27 +2957,27 @@ Methods: RenderPassStencilAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassStencilAttachmentDescriptor) } @(objc_type=RenderPassStencilAttachmentDescriptor, objc_class_name="alloc") -RenderPassStencilAttachmentDescriptor_alloc :: proc() -> ^RenderPassStencilAttachmentDescriptor { +RenderPassStencilAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassStencilAttachmentDescriptor { return msgSend(^RenderPassStencilAttachmentDescriptor, RenderPassStencilAttachmentDescriptor, "alloc") } @(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="init") -RenderPassStencilAttachmentDescriptor_init :: proc(self: ^RenderPassStencilAttachmentDescriptor) -> ^RenderPassStencilAttachmentDescriptor { +RenderPassStencilAttachmentDescriptor_init :: #force_inline proc(self: ^RenderPassStencilAttachmentDescriptor) -> ^RenderPassStencilAttachmentDescriptor { return msgSend(^RenderPassStencilAttachmentDescriptor, self, "init") } @(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="clearStencil") -RenderPassStencilAttachmentDescriptor_clearStencil :: proc(self: ^RenderPassStencilAttachmentDescriptor) -> u32 { +RenderPassStencilAttachmentDescriptor_clearStencil :: #force_inline proc(self: ^RenderPassStencilAttachmentDescriptor) -> u32 { return msgSend(u32, self, "clearStencil") } @(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="setClearStencil") -RenderPassStencilAttachmentDescriptor_setClearStencil :: proc(self: ^RenderPassStencilAttachmentDescriptor, clearStencil: u32) { +RenderPassStencilAttachmentDescriptor_setClearStencil :: #force_inline proc(self: ^RenderPassStencilAttachmentDescriptor, clearStencil: u32) { msgSend(nil, self, "setClearStencil:", clearStencil) } @(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="setStencilResolveFilter") -RenderPassStencilAttachmentDescriptor_setStencilResolveFilter :: proc(self: ^RenderPassStencilAttachmentDescriptor, stencilResolveFilter: MultisampleStencilResolveFilter) { +RenderPassStencilAttachmentDescriptor_setStencilResolveFilter :: #force_inline proc(self: ^RenderPassStencilAttachmentDescriptor, stencilResolveFilter: MultisampleStencilResolveFilter) { msgSend(nil, self, "setStencilResolveFilter:", stencilResolveFilter) } @(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="stencilResolveFilter") -RenderPassStencilAttachmentDescriptor_stencilResolveFilter :: proc(self: ^RenderPassStencilAttachmentDescriptor) -> MultisampleStencilResolveFilter { +RenderPassStencilAttachmentDescriptor_stencilResolveFilter :: #force_inline proc(self: ^RenderPassStencilAttachmentDescriptor) -> MultisampleStencilResolveFilter { return msgSend(MultisampleStencilResolveFilter, self, "stencilResolveFilter") } @@ -3027,83 +3013,83 @@ Methods: RenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPipelineColorAttachmentDescriptor) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_class_name="alloc") -RenderPipelineColorAttachmentDescriptor_alloc :: proc() -> ^RenderPipelineColorAttachmentDescriptor { +RenderPipelineColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPipelineColorAttachmentDescriptor { return msgSend(^RenderPipelineColorAttachmentDescriptor, RenderPipelineColorAttachmentDescriptor, "alloc") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="init") -RenderPipelineColorAttachmentDescriptor_init :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> ^RenderPipelineColorAttachmentDescriptor { +RenderPipelineColorAttachmentDescriptor_init :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> ^RenderPipelineColorAttachmentDescriptor { return msgSend(^RenderPipelineColorAttachmentDescriptor, self, "init") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="alphaBlendOperation") -RenderPipelineColorAttachmentDescriptor_alphaBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendOperation { +RenderPipelineColorAttachmentDescriptor_alphaBlendOperation :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendOperation { return msgSend(BlendOperation, self, "alphaBlendOperation") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="destinationAlphaBlendFactor") -RenderPipelineColorAttachmentDescriptor_destinationAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { +RenderPipelineColorAttachmentDescriptor_destinationAlphaBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { return msgSend(BlendFactor, self, "destinationAlphaBlendFactor") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="destinationRGBBlendFactor") -RenderPipelineColorAttachmentDescriptor_destinationRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { +RenderPipelineColorAttachmentDescriptor_destinationRGBBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { return msgSend(BlendFactor, self, "destinationRGBBlendFactor") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="isBlendingEnabled") -RenderPipelineColorAttachmentDescriptor_isBlendingEnabled :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BOOL { +RenderPipelineColorAttachmentDescriptor_isBlendingEnabled :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BOOL { return msgSend(BOOL, self, "isBlendingEnabled") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="pixelFormat") -RenderPipelineColorAttachmentDescriptor_pixelFormat :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> PixelFormat { +RenderPipelineColorAttachmentDescriptor_pixelFormat :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> PixelFormat { return msgSend(PixelFormat, self, "pixelFormat") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="rgbBlendOperation") -RenderPipelineColorAttachmentDescriptor_rgbBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendOperation { +RenderPipelineColorAttachmentDescriptor_rgbBlendOperation :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendOperation { return msgSend(BlendOperation, self, "rgbBlendOperation") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setAlphaBlendOperation") -RenderPipelineColorAttachmentDescriptor_setAlphaBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor, alphaBlendOperation: BlendOperation) { +RenderPipelineColorAttachmentDescriptor_setAlphaBlendOperation :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, alphaBlendOperation: BlendOperation) { msgSend(nil, self, "setAlphaBlendOperation:", alphaBlendOperation) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setBlendingEnabled") -RenderPipelineColorAttachmentDescriptor_setBlendingEnabled :: proc(self: ^RenderPipelineColorAttachmentDescriptor, blendingEnabled: BOOL) { +RenderPipelineColorAttachmentDescriptor_setBlendingEnabled :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, blendingEnabled: BOOL) { msgSend(nil, self, "setBlendingEnabled:", blendingEnabled) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setDestinationAlphaBlendFactor") -RenderPipelineColorAttachmentDescriptor_setDestinationAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, destinationAlphaBlendFactor: BlendFactor) { +RenderPipelineColorAttachmentDescriptor_setDestinationAlphaBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, destinationAlphaBlendFactor: BlendFactor) { msgSend(nil, self, "setDestinationAlphaBlendFactor:", destinationAlphaBlendFactor) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setDestinationRGBBlendFactor") -RenderPipelineColorAttachmentDescriptor_setDestinationRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, destinationRGBBlendFactor: BlendFactor) { +RenderPipelineColorAttachmentDescriptor_setDestinationRGBBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, destinationRGBBlendFactor: BlendFactor) { msgSend(nil, self, "setDestinationRGBBlendFactor:", destinationRGBBlendFactor) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setPixelFormat") -RenderPipelineColorAttachmentDescriptor_setPixelFormat :: proc(self: ^RenderPipelineColorAttachmentDescriptor, pixelFormat: PixelFormat) { +RenderPipelineColorAttachmentDescriptor_setPixelFormat :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, pixelFormat: PixelFormat) { msgSend(nil, self, "setPixelFormat:", pixelFormat) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setRgbBlendOperation") -RenderPipelineColorAttachmentDescriptor_setRgbBlendOperation :: proc(self: ^RenderPipelineColorAttachmentDescriptor, rgbBlendOperation: BlendOperation) { +RenderPipelineColorAttachmentDescriptor_setRgbBlendOperation :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, rgbBlendOperation: BlendOperation) { msgSend(nil, self, "setRgbBlendOperation:", rgbBlendOperation) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setSourceAlphaBlendFactor") -RenderPipelineColorAttachmentDescriptor_setSourceAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, sourceAlphaBlendFactor: BlendFactor) { +RenderPipelineColorAttachmentDescriptor_setSourceAlphaBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, sourceAlphaBlendFactor: BlendFactor) { msgSend(nil, self, "setSourceAlphaBlendFactor:", sourceAlphaBlendFactor) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setSourceRGBBlendFactor") -RenderPipelineColorAttachmentDescriptor_setSourceRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor, sourceRGBBlendFactor: BlendFactor) { +RenderPipelineColorAttachmentDescriptor_setSourceRGBBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, sourceRGBBlendFactor: BlendFactor) { msgSend(nil, self, "setSourceRGBBlendFactor:", sourceRGBBlendFactor) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="setWriteMask") -RenderPipelineColorAttachmentDescriptor_setWriteMask :: proc(self: ^RenderPipelineColorAttachmentDescriptor, writeMask: ColorWriteMask) { +RenderPipelineColorAttachmentDescriptor_setWriteMask :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor, writeMask: ColorWriteMask) { msgSend(nil, self, "setWriteMask:", writeMask) } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="sourceAlphaBlendFactor") -RenderPipelineColorAttachmentDescriptor_sourceAlphaBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { +RenderPipelineColorAttachmentDescriptor_sourceAlphaBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { return msgSend(BlendFactor, self, "sourceAlphaBlendFactor") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="sourceRGBBlendFactor") -RenderPipelineColorAttachmentDescriptor_sourceRGBBlendFactor :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { +RenderPipelineColorAttachmentDescriptor_sourceRGBBlendFactor :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> BlendFactor { return msgSend(BlendFactor, self, "sourceRGBBlendFactor") } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="writeMask") -RenderPipelineColorAttachmentDescriptor_writeMask :: proc(self: ^RenderPipelineColorAttachmentDescriptor) -> ColorWriteMask { +RenderPipelineColorAttachmentDescriptor_writeMask :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptor) -> ColorWriteMask { return msgSend(ColorWriteMask, self, "writeMask") } @@ -3123,19 +3109,19 @@ Methods: RenderPipelineColorAttachmentDescriptorArray :: struct { using _: NS.Object } @(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_class_name="alloc") -RenderPipelineColorAttachmentDescriptorArray_alloc :: proc() -> ^RenderPipelineColorAttachmentDescriptorArray { +RenderPipelineColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^RenderPipelineColorAttachmentDescriptorArray { return msgSend(^RenderPipelineColorAttachmentDescriptorArray, RenderPipelineColorAttachmentDescriptorArray, "alloc") } @(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="init") -RenderPipelineColorAttachmentDescriptorArray_init :: proc(self: ^RenderPipelineColorAttachmentDescriptorArray) -> ^RenderPipelineColorAttachmentDescriptorArray { +RenderPipelineColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray) -> ^RenderPipelineColorAttachmentDescriptorArray { return msgSend(^RenderPipelineColorAttachmentDescriptorArray, self, "init") } @(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPipelineColorAttachmentDescriptor { +RenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPipelineColorAttachmentDescriptor { return msgSend(^RenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") -RenderPipelineColorAttachmentDescriptorArray_setObject :: proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachment: ^RenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { +RenderPipelineColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachment: ^RenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -3201,203 +3187,203 @@ Methods: RenderPipelineDescriptor :: struct { using _: NS.Copying(RenderPipelineDescriptor) } @(objc_type=RenderPipelineDescriptor, objc_class_name="alloc") -RenderPipelineDescriptor_alloc :: proc() -> ^RenderPipelineDescriptor { +RenderPipelineDescriptor_alloc :: #force_inline proc() -> ^RenderPipelineDescriptor { return msgSend(^RenderPipelineDescriptor, RenderPipelineDescriptor, "alloc") } @(objc_type=RenderPipelineDescriptor, objc_name="init") -RenderPipelineDescriptor_init :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { +RenderPipelineDescriptor_init :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { return msgSend(^RenderPipelineDescriptor, self, "init") } @(objc_type=RenderPipelineDescriptor, objc_name="binaryArchives") -RenderPipelineDescriptor_binaryArchives :: proc(self: ^RenderPipelineDescriptor) -> ^NS.Array { +RenderPipelineDescriptor_binaryArchives :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^NS.Array { return msgSend(^NS.Array, self, "binaryArchives") } @(objc_type=RenderPipelineDescriptor, objc_name="colorAttachments") -RenderPipelineDescriptor_colorAttachments :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineColorAttachmentDescriptorArray { +RenderPipelineDescriptor_colorAttachments :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineColorAttachmentDescriptorArray { return msgSend(^RenderPipelineColorAttachmentDescriptorArray, self, "colorAttachments") } @(objc_type=RenderPipelineDescriptor, objc_name="depthAttachmentPixelFormat") -RenderPipelineDescriptor_depthAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor) -> PixelFormat { +RenderPipelineDescriptor_depthAttachmentPixelFormat :: #force_inline proc(self: ^RenderPipelineDescriptor) -> PixelFormat { return msgSend(PixelFormat, self, "depthAttachmentPixelFormat") } @(objc_type=RenderPipelineDescriptor, objc_name="fragmentBuffers") -RenderPipelineDescriptor_fragmentBuffers :: proc(self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { +RenderPipelineDescriptor_fragmentBuffers :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, self, "fragmentBuffers") } @(objc_type=RenderPipelineDescriptor, objc_name="fragmentFunction") -RenderPipelineDescriptor_fragmentFunction :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { +RenderPipelineDescriptor_fragmentFunction :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { return msgSend(^RenderPipelineDescriptor, self, "fragmentFunction") } @(objc_type=RenderPipelineDescriptor, objc_name="inputPrimitiveTopology") -RenderPipelineDescriptor_inputPrimitiveTopology :: proc(self: ^RenderPipelineDescriptor) -> PrimitiveTopologyClass { +RenderPipelineDescriptor_inputPrimitiveTopology :: #force_inline proc(self: ^RenderPipelineDescriptor) -> PrimitiveTopologyClass { return msgSend(PrimitiveTopologyClass, self, "inputPrimitiveTopology") } @(objc_type=RenderPipelineDescriptor, objc_name="isAlphaToCoverageEnabled") -RenderPipelineDescriptor_isAlphaToCoverageEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { +RenderPipelineDescriptor_isAlphaToCoverageEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "isAlphaToCoverageEnabled") } @(objc_type=RenderPipelineDescriptor, objc_name="isAlphaToOneEnabled") -RenderPipelineDescriptor_isAlphaToOneEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { +RenderPipelineDescriptor_isAlphaToOneEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "isAlphaToOneEnabled") } @(objc_type=RenderPipelineDescriptor, objc_name="isRasterizationEnabled") -RenderPipelineDescriptor_isRasterizationEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { +RenderPipelineDescriptor_isRasterizationEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "isRasterizationEnabled") } @(objc_type=RenderPipelineDescriptor, objc_name="isTessellationFactorScaleEnabled") -RenderPipelineDescriptor_isTessellationFactorScaleEnabled :: proc(self: ^RenderPipelineDescriptor) -> BOOL { +RenderPipelineDescriptor_isTessellationFactorScaleEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "isTessellationFactorScaleEnabled") } @(objc_type=RenderPipelineDescriptor, objc_name="label") -RenderPipelineDescriptor_label :: proc(self: ^RenderPipelineDescriptor) -> ^NS.String { +RenderPipelineDescriptor_label :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=RenderPipelineDescriptor, objc_name="maxTessellationFactor") -RenderPipelineDescriptor_maxTessellationFactor :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { +RenderPipelineDescriptor_maxTessellationFactor :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxTessellationFactor") } @(objc_type=RenderPipelineDescriptor, objc_name="maxVertexAmplificationCount") -RenderPipelineDescriptor_maxVertexAmplificationCount :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { +RenderPipelineDescriptor_maxVertexAmplificationCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxVertexAmplificationCount") } @(objc_type=RenderPipelineDescriptor, objc_name="rasterSampleCount") -RenderPipelineDescriptor_rasterSampleCount :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { +RenderPipelineDescriptor_rasterSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "rasterSampleCount") } @(objc_type=RenderPipelineDescriptor, objc_name="reset") -RenderPipelineDescriptor_reset :: proc(self: ^RenderPipelineDescriptor) { +RenderPipelineDescriptor_reset :: #force_inline proc(self: ^RenderPipelineDescriptor) { msgSend(nil, self, "reset") } @(objc_type=RenderPipelineDescriptor, objc_name="sampleCount") -RenderPipelineDescriptor_sampleCount :: proc(self: ^RenderPipelineDescriptor) -> NS.Integer { +RenderPipelineDescriptor_sampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "sampleCount") } @(objc_type=RenderPipelineDescriptor, objc_name="setAlphaToCoverageEnabled") -RenderPipelineDescriptor_setAlphaToCoverageEnabled :: proc(self: ^RenderPipelineDescriptor, alphaToCoverageEnabled: BOOL) { +RenderPipelineDescriptor_setAlphaToCoverageEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor, alphaToCoverageEnabled: BOOL) { msgSend(nil, self, "setAlphaToCoverageEnabled:", alphaToCoverageEnabled) } @(objc_type=RenderPipelineDescriptor, objc_name="setAlphaToOneEnabled") -RenderPipelineDescriptor_setAlphaToOneEnabled :: proc(self: ^RenderPipelineDescriptor, alphaToOneEnabled: BOOL) { +RenderPipelineDescriptor_setAlphaToOneEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor, alphaToOneEnabled: BOOL) { msgSend(nil, self, "setAlphaToOneEnabled:", alphaToOneEnabled) } @(objc_type=RenderPipelineDescriptor, objc_name="setBinaryArchives") -RenderPipelineDescriptor_setBinaryArchives :: proc(self: ^RenderPipelineDescriptor, binaryArchives: ^NS.Array) { +RenderPipelineDescriptor_setBinaryArchives :: #force_inline proc(self: ^RenderPipelineDescriptor, binaryArchives: ^NS.Array) { msgSend(nil, self, "setBinaryArchives:", binaryArchives) } @(objc_type=RenderPipelineDescriptor, objc_name="setDepthAttachmentPixelFormat") -RenderPipelineDescriptor_setDepthAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor, depthAttachmentPixelFormat: PixelFormat) { +RenderPipelineDescriptor_setDepthAttachmentPixelFormat :: #force_inline proc(self: ^RenderPipelineDescriptor, depthAttachmentPixelFormat: PixelFormat) { msgSend(nil, self, "setDepthAttachmentPixelFormat:", depthAttachmentPixelFormat) } @(objc_type=RenderPipelineDescriptor, objc_name="setFragmentFunction") -RenderPipelineDescriptor_setFragmentFunction :: proc(self: ^RenderPipelineDescriptor, fragmentFunction: ^NS.Object) { +RenderPipelineDescriptor_setFragmentFunction :: #force_inline proc(self: ^RenderPipelineDescriptor, fragmentFunction: ^NS.Object) { msgSend(nil, self, "setFragmentFunction:", fragmentFunction) } @(objc_type=RenderPipelineDescriptor, objc_name="setInputPrimitiveTopology") -RenderPipelineDescriptor_setInputPrimitiveTopology :: proc(self: ^RenderPipelineDescriptor, inputPrimitiveTopology: PrimitiveTopologyClass) { +RenderPipelineDescriptor_setInputPrimitiveTopology :: #force_inline proc(self: ^RenderPipelineDescriptor, inputPrimitiveTopology: PrimitiveTopologyClass) { msgSend(nil, self, "setInputPrimitiveTopology:", inputPrimitiveTopology) } @(objc_type=RenderPipelineDescriptor, objc_name="setLabel") -RenderPipelineDescriptor_setLabel :: proc(self: ^RenderPipelineDescriptor, label: ^NS.String) { +RenderPipelineDescriptor_setLabel :: #force_inline proc(self: ^RenderPipelineDescriptor, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=RenderPipelineDescriptor, objc_name="setMaxTessellationFactor") -RenderPipelineDescriptor_setMaxTessellationFactor :: proc(self: ^RenderPipelineDescriptor, maxTessellationFactor: NS.Integer) { +RenderPipelineDescriptor_setMaxTessellationFactor :: #force_inline proc(self: ^RenderPipelineDescriptor, maxTessellationFactor: NS.Integer) { msgSend(nil, self, "setMaxTessellationFactor:", maxTessellationFactor) } @(objc_type=RenderPipelineDescriptor, objc_name="setMaxVertexAmplificationCount") -RenderPipelineDescriptor_setMaxVertexAmplificationCount :: proc(self: ^RenderPipelineDescriptor, maxVertexAmplificationCount: NS.Integer) { +RenderPipelineDescriptor_setMaxVertexAmplificationCount :: #force_inline proc(self: ^RenderPipelineDescriptor, maxVertexAmplificationCount: NS.Integer) { msgSend(nil, self, "setMaxVertexAmplificationCount:", maxVertexAmplificationCount) } @(objc_type=RenderPipelineDescriptor, objc_name="setRasterSampleCount") -RenderPipelineDescriptor_setRasterSampleCount :: proc(self: ^RenderPipelineDescriptor, rasterSampleCount: NS.Integer) { +RenderPipelineDescriptor_setRasterSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor, rasterSampleCount: NS.Integer) { msgSend(nil, self, "setRasterSampleCount:", rasterSampleCount) } @(objc_type=RenderPipelineDescriptor, objc_name="setRasterizationEnabled") -RenderPipelineDescriptor_setRasterizationEnabled :: proc(self: ^RenderPipelineDescriptor, rasterizationEnabled: BOOL) { +RenderPipelineDescriptor_setRasterizationEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor, rasterizationEnabled: BOOL) { msgSend(nil, self, "setRasterizationEnabled:", rasterizationEnabled) } @(objc_type=RenderPipelineDescriptor, objc_name="setSampleCount") -RenderPipelineDescriptor_setSampleCount :: proc(self: ^RenderPipelineDescriptor, sampleCount: NS.Integer) { +RenderPipelineDescriptor_setSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor, sampleCount: NS.Integer) { msgSend(nil, self, "setSampleCount:", sampleCount) } @(objc_type=RenderPipelineDescriptor, objc_name="setStencilAttachmentPixelFormat") -RenderPipelineDescriptor_setStencilAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor, stencilAttachmentPixelFormat: PixelFormat) { +RenderPipelineDescriptor_setStencilAttachmentPixelFormat :: #force_inline proc(self: ^RenderPipelineDescriptor, stencilAttachmentPixelFormat: PixelFormat) { msgSend(nil, self, "setStencilAttachmentPixelFormat:", stencilAttachmentPixelFormat) } @(objc_type=RenderPipelineDescriptor, objc_name="setSupportIndirectCommandBuffers") -RenderPipelineDescriptor_setSupportIndirectCommandBuffers :: proc(self: ^RenderPipelineDescriptor, supportIndirectCommandBuffers: BOOL) { +RenderPipelineDescriptor_setSupportIndirectCommandBuffers :: #force_inline proc(self: ^RenderPipelineDescriptor, supportIndirectCommandBuffers: BOOL) { msgSend(nil, self, "setSupportIndirectCommandBuffers:", supportIndirectCommandBuffers) } @(objc_type=RenderPipelineDescriptor, objc_name="setTessellationControlPointIndexType") -RenderPipelineDescriptor_setTessellationControlPointIndexType :: proc(self: ^RenderPipelineDescriptor, tessellationControlPointIndexType: TessellationControlPointIndexType) { +RenderPipelineDescriptor_setTessellationControlPointIndexType :: #force_inline proc(self: ^RenderPipelineDescriptor, tessellationControlPointIndexType: TessellationControlPointIndexType) { msgSend(nil, self, "setTessellationControlPointIndexType:", tessellationControlPointIndexType) } @(objc_type=RenderPipelineDescriptor, objc_name="setTessellationFactorFormat") -RenderPipelineDescriptor_setTessellationFactorFormat :: proc(self: ^RenderPipelineDescriptor, tessellationFactorFormat: TessellationFactorFormat) { +RenderPipelineDescriptor_setTessellationFactorFormat :: #force_inline proc(self: ^RenderPipelineDescriptor, tessellationFactorFormat: TessellationFactorFormat) { msgSend(nil, self, "setTessellationFactorFormat:", tessellationFactorFormat) } @(objc_type=RenderPipelineDescriptor, objc_name="setTessellationFactorScaleEnabled") -RenderPipelineDescriptor_setTessellationFactorScaleEnabled :: proc(self: ^RenderPipelineDescriptor, tessellationFactorScaleEnabled: BOOL) { +RenderPipelineDescriptor_setTessellationFactorScaleEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor, tessellationFactorScaleEnabled: BOOL) { msgSend(nil, self, "setTessellationFactorScaleEnabled:", tessellationFactorScaleEnabled) } @(objc_type=RenderPipelineDescriptor, objc_name="setTessellationFactorStepFunction") -RenderPipelineDescriptor_setTessellationFactorStepFunction :: proc(self: ^RenderPipelineDescriptor, tessellationFactorStepFunction: TessellationFactorStepFunction) { +RenderPipelineDescriptor_setTessellationFactorStepFunction :: #force_inline proc(self: ^RenderPipelineDescriptor, tessellationFactorStepFunction: TessellationFactorStepFunction) { msgSend(nil, self, "setTessellationFactorStepFunction:", tessellationFactorStepFunction) } @(objc_type=RenderPipelineDescriptor, objc_name="setTessellationOutputWindingOrder") -RenderPipelineDescriptor_setTessellationOutputWindingOrder :: proc(self: ^RenderPipelineDescriptor, tessellationOutputWindingOrder: Winding) { +RenderPipelineDescriptor_setTessellationOutputWindingOrder :: #force_inline proc(self: ^RenderPipelineDescriptor, tessellationOutputWindingOrder: Winding) { msgSend(nil, self, "setTessellationOutputWindingOrder:", tessellationOutputWindingOrder) } @(objc_type=RenderPipelineDescriptor, objc_name="setTessellationPartitionMode") -RenderPipelineDescriptor_setTessellationPartitionMode :: proc(self: ^RenderPipelineDescriptor, tessellationPartitionMode: TessellationPartitionMode) { +RenderPipelineDescriptor_setTessellationPartitionMode :: #force_inline proc(self: ^RenderPipelineDescriptor, tessellationPartitionMode: TessellationPartitionMode) { msgSend(nil, self, "setTessellationPartitionMode:", tessellationPartitionMode) } @(objc_type=RenderPipelineDescriptor, objc_name="setVertexDescriptor") -RenderPipelineDescriptor_setVertexDescriptor :: proc(self: ^RenderPipelineDescriptor, vertexDescriptor: ^VertexDescriptor) { +RenderPipelineDescriptor_setVertexDescriptor :: #force_inline proc(self: ^RenderPipelineDescriptor, vertexDescriptor: ^VertexDescriptor) { msgSend(nil, self, "setVertexDescriptor:", vertexDescriptor) } @(objc_type=RenderPipelineDescriptor, objc_name="setVertexFunction") -RenderPipelineDescriptor_setVertexFunction :: proc(self: ^RenderPipelineDescriptor, vertexFunction: ^NS.Object) { +RenderPipelineDescriptor_setVertexFunction :: #force_inline proc(self: ^RenderPipelineDescriptor, vertexFunction: ^NS.Object) { msgSend(nil, self, "setVertexFunction:", vertexFunction) } @(objc_type=RenderPipelineDescriptor, objc_name="stencilAttachmentPixelFormat") -RenderPipelineDescriptor_stencilAttachmentPixelFormat :: proc(self: ^RenderPipelineDescriptor) -> PixelFormat { +RenderPipelineDescriptor_stencilAttachmentPixelFormat :: #force_inline proc(self: ^RenderPipelineDescriptor) -> PixelFormat { return msgSend(PixelFormat, self, "stencilAttachmentPixelFormat") } @(objc_type=RenderPipelineDescriptor, objc_name="supportIndirectCommandBuffers") -RenderPipelineDescriptor_supportIndirectCommandBuffers :: proc(self: ^RenderPipelineDescriptor) -> BOOL { +RenderPipelineDescriptor_supportIndirectCommandBuffers :: #force_inline proc(self: ^RenderPipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "supportIndirectCommandBuffers") } @(objc_type=RenderPipelineDescriptor, objc_name="tessellationControlPointIndexType") -RenderPipelineDescriptor_tessellationControlPointIndexType :: proc(self: ^RenderPipelineDescriptor) -> TessellationControlPointIndexType { +RenderPipelineDescriptor_tessellationControlPointIndexType :: #force_inline proc(self: ^RenderPipelineDescriptor) -> TessellationControlPointIndexType { return msgSend(TessellationControlPointIndexType, self, "tessellationControlPointIndexType") } @(objc_type=RenderPipelineDescriptor, objc_name="tessellationFactorFormat") -RenderPipelineDescriptor_tessellationFactorFormat :: proc(self: ^RenderPipelineDescriptor) -> TessellationFactorFormat { +RenderPipelineDescriptor_tessellationFactorFormat :: #force_inline proc(self: ^RenderPipelineDescriptor) -> TessellationFactorFormat { return msgSend(TessellationFactorFormat, self, "tessellationFactorFormat") } @(objc_type=RenderPipelineDescriptor, objc_name="tessellationFactorStepFunction") -RenderPipelineDescriptor_tessellationFactorStepFunction :: proc(self: ^RenderPipelineDescriptor) -> TessellationFactorStepFunction { +RenderPipelineDescriptor_tessellationFactorStepFunction :: #force_inline proc(self: ^RenderPipelineDescriptor) -> TessellationFactorStepFunction { return msgSend(TessellationFactorStepFunction, self, "tessellationFactorStepFunction") } @(objc_type=RenderPipelineDescriptor, objc_name="tessellationOutputWindingOrder") -RenderPipelineDescriptor_tessellationOutputWindingOrder :: proc(self: ^RenderPipelineDescriptor) -> Winding { +RenderPipelineDescriptor_tessellationOutputWindingOrder :: #force_inline proc(self: ^RenderPipelineDescriptor) -> Winding { return msgSend(Winding, self, "tessellationOutputWindingOrder") } @(objc_type=RenderPipelineDescriptor, objc_name="tessellationPartitionMode") -RenderPipelineDescriptor_tessellationPartitionMode :: proc(self: ^RenderPipelineDescriptor) -> TessellationPartitionMode { +RenderPipelineDescriptor_tessellationPartitionMode :: #force_inline proc(self: ^RenderPipelineDescriptor) -> TessellationPartitionMode { return msgSend(TessellationPartitionMode, self, "tessellationPartitionMode") } @(objc_type=RenderPipelineDescriptor, objc_name="vertexBuffers") -RenderPipelineDescriptor_vertexBuffers :: proc(self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { +RenderPipelineDescriptor_vertexBuffers :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, self, "vertexBuffers") } @(objc_type=RenderPipelineDescriptor, objc_name="vertexDescriptor") -RenderPipelineDescriptor_vertexDescriptor :: proc(self: ^RenderPipelineDescriptor) -> ^VertexDescriptor { +RenderPipelineDescriptor_vertexDescriptor :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^VertexDescriptor { return msgSend(^VertexDescriptor, self, "vertexDescriptor") } @(objc_type=RenderPipelineDescriptor, objc_name="vertexFunction") -RenderPipelineDescriptor_vertexFunction :: proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { +RenderPipelineDescriptor_vertexFunction :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { return msgSend(^RenderPipelineDescriptor, self, "vertexFunction") } @@ -3418,23 +3404,23 @@ Methods: RenderPipelineReflection :: struct { using _: NS.Object } @(objc_type=RenderPipelineReflection, objc_class_name="alloc") -RenderPipelineReflection_alloc :: proc() -> ^RenderPipelineReflection { +RenderPipelineReflection_alloc :: #force_inline proc() -> ^RenderPipelineReflection { return msgSend(^RenderPipelineReflection, RenderPipelineReflection, "alloc") } @(objc_type=RenderPipelineReflection, objc_name="init") -RenderPipelineReflection_init :: proc(self: ^RenderPipelineReflection) -> ^RenderPipelineReflection { +RenderPipelineReflection_init :: #force_inline proc(self: ^RenderPipelineReflection) -> ^RenderPipelineReflection { return msgSend(^RenderPipelineReflection, self, "init") } @(objc_type=RenderPipelineReflection, objc_name="fragmentArguments") -RenderPipelineReflection_fragmentArguments :: proc(self: ^RenderPipelineReflection) -> ^NS.Array { +RenderPipelineReflection_fragmentArguments :: #force_inline proc(self: ^RenderPipelineReflection) -> ^NS.Array { return msgSend(^NS.Array, self, "fragmentArguments") } @(objc_type=RenderPipelineReflection, objc_name="tileArguments") -RenderPipelineReflection_tileArguments :: proc(self: ^RenderPipelineReflection) -> ^NS.Array { +RenderPipelineReflection_tileArguments :: #force_inline proc(self: ^RenderPipelineReflection) -> ^NS.Array { return msgSend(^NS.Array, self, "tileArguments") } @(objc_type=RenderPipelineReflection, objc_name="vertexArguments") -RenderPipelineReflection_vertexArguments :: proc(self: ^RenderPipelineReflection) -> ^NS.Array { +RenderPipelineReflection_vertexArguments :: #force_inline proc(self: ^RenderPipelineReflection) -> ^NS.Array { return msgSend(^NS.Array, self, "vertexArguments") } @@ -3454,19 +3440,19 @@ Methods: ResourceStatePassDescriptor :: struct { using _: NS.Copying(ResourceStatePassDescriptor) } @(objc_type=ResourceStatePassDescriptor, objc_class_name="alloc") -ResourceStatePassDescriptor_alloc :: proc() -> ^ResourceStatePassDescriptor { +ResourceStatePassDescriptor_alloc :: #force_inline proc() -> ^ResourceStatePassDescriptor { return msgSend(^ResourceStatePassDescriptor, ResourceStatePassDescriptor, "alloc") } @(objc_type=ResourceStatePassDescriptor, objc_name="init") -ResourceStatePassDescriptor_init :: proc(self: ^ResourceStatePassDescriptor) -> ^ResourceStatePassDescriptor { +ResourceStatePassDescriptor_init :: #force_inline proc(self: ^ResourceStatePassDescriptor) -> ^ResourceStatePassDescriptor { return msgSend(^ResourceStatePassDescriptor, self, "init") } @(objc_type=ResourceStatePassDescriptor, objc_class_name="resourceStatePassDescriptor") -ResourceStatePassDescriptor_resourceStatePassDescriptor :: proc() -> ^ResourceStatePassDescriptor { +ResourceStatePassDescriptor_resourceStatePassDescriptor :: #force_inline proc() -> ^ResourceStatePassDescriptor { return msgSend(^ResourceStatePassDescriptor, ResourceStatePassDescriptor, "resourceStatePassDescriptor") } @(objc_type=ResourceStatePassDescriptor, objc_name="sampleBufferAttachments") -ResourceStatePassDescriptor_sampleBufferAttachments :: proc(self: ^ResourceStatePassDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { +ResourceStatePassDescriptor_sampleBufferAttachments :: #force_inline proc(self: ^ResourceStatePassDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") } @@ -3490,35 +3476,35 @@ Methods: ResourceStatePassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(ResourceStatePassSampleBufferAttachmentDescriptor) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_class_name="alloc") -ResourceStatePassSampleBufferAttachmentDescriptor_alloc :: proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptor { +ResourceStatePassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, ResourceStatePassSampleBufferAttachmentDescriptor, "alloc") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="init") -ResourceStatePassSampleBufferAttachmentDescriptor_init :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { +ResourceStatePassSampleBufferAttachmentDescriptor_init :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { +ResourceStatePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { +ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { +ResourceStatePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -ResourceStatePassSampleBufferAttachmentDescriptor_setSampleBuffer :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +ResourceStatePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { +ResourceStatePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { +ResourceStatePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") } @@ -3538,19 +3524,19 @@ Methods: ResourceStatePassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") -ResourceStatePassSampleBufferAttachmentDescriptorArray_alloc :: proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { +ResourceStatePassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, ResourceStatePassSampleBufferAttachmentDescriptorArray, "alloc") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="init") -ResourceStatePassSampleBufferAttachmentDescriptorArray_init :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray) -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { +ResourceStatePassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray) -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -ResourceStatePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { +ResourceStatePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -ResourceStatePassSampleBufferAttachmentDescriptorArray_setObject :: proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachment: ^ResourceStatePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +ResourceStatePassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachment: ^ResourceStatePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -3598,131 +3584,131 @@ Methods: SamplerDescriptor :: struct { using _: NS.Copying(SamplerDescriptor) } @(objc_type=SamplerDescriptor, objc_class_name="alloc") -SamplerDescriptor_alloc :: proc() -> ^SamplerDescriptor { +SamplerDescriptor_alloc :: #force_inline proc() -> ^SamplerDescriptor { return msgSend(^SamplerDescriptor, SamplerDescriptor, "alloc") } @(objc_type=SamplerDescriptor, objc_name="init") -SamplerDescriptor_init :: proc(self: ^SamplerDescriptor) -> ^SamplerDescriptor { +SamplerDescriptor_init :: #force_inline proc(self: ^SamplerDescriptor) -> ^SamplerDescriptor { return msgSend(^SamplerDescriptor, self, "init") } @(objc_type=SamplerDescriptor, objc_name="borderColor") -SamplerDescriptor_borderColor :: proc(self: ^SamplerDescriptor) -> SamplerBorderColor { +SamplerDescriptor_borderColor :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerBorderColor { return msgSend(SamplerBorderColor, self, "borderColor") } @(objc_type=SamplerDescriptor, objc_name="compareFunction") -SamplerDescriptor_compareFunction :: proc(self: ^SamplerDescriptor) -> CompareFunction { +SamplerDescriptor_compareFunction :: #force_inline proc(self: ^SamplerDescriptor) -> CompareFunction { return msgSend(CompareFunction, self, "compareFunction") } @(objc_type=SamplerDescriptor, objc_name="label") -SamplerDescriptor_label :: proc(self: ^SamplerDescriptor) -> ^NS.String { +SamplerDescriptor_label :: #force_inline proc(self: ^SamplerDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=SamplerDescriptor, objc_name="lodAverage") -SamplerDescriptor_lodAverage :: proc(self: ^SamplerDescriptor) -> BOOL { +SamplerDescriptor_lodAverage :: #force_inline proc(self: ^SamplerDescriptor) -> BOOL { return msgSend(BOOL, self, "lodAverage") } @(objc_type=SamplerDescriptor, objc_name="lodMaxClamp") -SamplerDescriptor_lodMaxClamp :: proc(self: ^SamplerDescriptor) -> f32 { +SamplerDescriptor_lodMaxClamp :: #force_inline proc(self: ^SamplerDescriptor) -> f32 { return msgSend(f32, self, "lodMaxClamp") } @(objc_type=SamplerDescriptor, objc_name="lodMinClamp") -SamplerDescriptor_lodMinClamp :: proc(self: ^SamplerDescriptor) -> f32 { +SamplerDescriptor_lodMinClamp :: #force_inline proc(self: ^SamplerDescriptor) -> f32 { return msgSend(f32, self, "lodMinClamp") } @(objc_type=SamplerDescriptor, objc_name="magFilter") -SamplerDescriptor_magFilter :: proc(self: ^SamplerDescriptor) -> SamplerMinMagFilter { +SamplerDescriptor_magFilter :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerMinMagFilter { return msgSend(SamplerMinMagFilter, self, "magFilter") } @(objc_type=SamplerDescriptor, objc_name="maxAnisotropy") -SamplerDescriptor_maxAnisotropy :: proc(self: ^SamplerDescriptor) -> NS.Integer { +SamplerDescriptor_maxAnisotropy :: #force_inline proc(self: ^SamplerDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxAnisotropy") } @(objc_type=SamplerDescriptor, objc_name="minFilter") -SamplerDescriptor_minFilter :: proc(self: ^SamplerDescriptor) -> SamplerMinMagFilter { +SamplerDescriptor_minFilter :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerMinMagFilter { return msgSend(SamplerMinMagFilter, self, "minFilter") } @(objc_type=SamplerDescriptor, objc_name="mipFilter") -SamplerDescriptor_mipFilter :: proc(self: ^SamplerDescriptor) -> SamplerMipFilter { +SamplerDescriptor_mipFilter :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerMipFilter { return msgSend(SamplerMipFilter, self, "mipFilter") } @(objc_type=SamplerDescriptor, objc_name="normalizedCoordinates") -SamplerDescriptor_normalizedCoordinates :: proc(self: ^SamplerDescriptor) -> BOOL { +SamplerDescriptor_normalizedCoordinates :: #force_inline proc(self: ^SamplerDescriptor) -> BOOL { return msgSend(BOOL, self, "normalizedCoordinates") } @(objc_type=SamplerDescriptor, objc_name="rAddressMode") -SamplerDescriptor_rAddressMode :: proc(self: ^SamplerDescriptor) -> SamplerAddressMode { +SamplerDescriptor_rAddressMode :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerAddressMode { return msgSend(SamplerAddressMode, self, "rAddressMode") } @(objc_type=SamplerDescriptor, objc_name="sAddressMode") -SamplerDescriptor_sAddressMode :: proc(self: ^SamplerDescriptor) -> SamplerAddressMode { +SamplerDescriptor_sAddressMode :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerAddressMode { return msgSend(SamplerAddressMode, self, "sAddressMode") } @(objc_type=SamplerDescriptor, objc_name="setBorderColor") -SamplerDescriptor_setBorderColor :: proc(self: ^SamplerDescriptor, borderColor: SamplerBorderColor) { +SamplerDescriptor_setBorderColor :: #force_inline proc(self: ^SamplerDescriptor, borderColor: SamplerBorderColor) { msgSend(nil, self, "setBorderColor:", borderColor) } @(objc_type=SamplerDescriptor, objc_name="setCompareFunction") -SamplerDescriptor_setCompareFunction :: proc(self: ^SamplerDescriptor, compareFunction: CompareFunction) { +SamplerDescriptor_setCompareFunction :: #force_inline proc(self: ^SamplerDescriptor, compareFunction: CompareFunction) { msgSend(nil, self, "setCompareFunction:", compareFunction) } @(objc_type=SamplerDescriptor, objc_name="setLabel") -SamplerDescriptor_setLabel :: proc(self: ^SamplerDescriptor, label: ^NS.String) { +SamplerDescriptor_setLabel :: #force_inline proc(self: ^SamplerDescriptor, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=SamplerDescriptor, objc_name="setLodAverage") -SamplerDescriptor_setLodAverage :: proc(self: ^SamplerDescriptor, lodAverage: BOOL) { +SamplerDescriptor_setLodAverage :: #force_inline proc(self: ^SamplerDescriptor, lodAverage: BOOL) { msgSend(nil, self, "setLodAverage:", lodAverage) } @(objc_type=SamplerDescriptor, objc_name="setLodMaxClamp") -SamplerDescriptor_setLodMaxClamp :: proc(self: ^SamplerDescriptor, lodMaxClamp: f32) { +SamplerDescriptor_setLodMaxClamp :: #force_inline proc(self: ^SamplerDescriptor, lodMaxClamp: f32) { msgSend(nil, self, "setLodMaxClamp:", lodMaxClamp) } @(objc_type=SamplerDescriptor, objc_name="setLodMinClamp") -SamplerDescriptor_setLodMinClamp :: proc(self: ^SamplerDescriptor, lodMinClamp: f32) { +SamplerDescriptor_setLodMinClamp :: #force_inline proc(self: ^SamplerDescriptor, lodMinClamp: f32) { msgSend(nil, self, "setLodMinClamp:", lodMinClamp) } @(objc_type=SamplerDescriptor, objc_name="setMagFilter") -SamplerDescriptor_setMagFilter :: proc(self: ^SamplerDescriptor, magFilter: SamplerMinMagFilter) { +SamplerDescriptor_setMagFilter :: #force_inline proc(self: ^SamplerDescriptor, magFilter: SamplerMinMagFilter) { msgSend(nil, self, "setMagFilter:", magFilter) } @(objc_type=SamplerDescriptor, objc_name="setMaxAnisotropy") -SamplerDescriptor_setMaxAnisotropy :: proc(self: ^SamplerDescriptor, maxAnisotropy: NS.Integer) { +SamplerDescriptor_setMaxAnisotropy :: #force_inline proc(self: ^SamplerDescriptor, maxAnisotropy: NS.Integer) { msgSend(nil, self, "setMaxAnisotropy:", maxAnisotropy) } @(objc_type=SamplerDescriptor, objc_name="setMinFilter") -SamplerDescriptor_setMinFilter :: proc(self: ^SamplerDescriptor, minFilter: SamplerMinMagFilter) { +SamplerDescriptor_setMinFilter :: #force_inline proc(self: ^SamplerDescriptor, minFilter: SamplerMinMagFilter) { msgSend(nil, self, "setMinFilter:", minFilter) } @(objc_type=SamplerDescriptor, objc_name="setMipFilter") -SamplerDescriptor_setMipFilter :: proc(self: ^SamplerDescriptor, mipFilter: SamplerMipFilter) { +SamplerDescriptor_setMipFilter :: #force_inline proc(self: ^SamplerDescriptor, mipFilter: SamplerMipFilter) { msgSend(nil, self, "setMipFilter:", mipFilter) } @(objc_type=SamplerDescriptor, objc_name="setNormalizedCoordinates") -SamplerDescriptor_setNormalizedCoordinates :: proc(self: ^SamplerDescriptor, normalizedCoordinates: BOOL) { +SamplerDescriptor_setNormalizedCoordinates :: #force_inline proc(self: ^SamplerDescriptor, normalizedCoordinates: BOOL) { msgSend(nil, self, "setNormalizedCoordinates:", normalizedCoordinates) } @(objc_type=SamplerDescriptor, objc_name="setRAddressMode") -SamplerDescriptor_setRAddressMode :: proc(self: ^SamplerDescriptor, rAddressMode: SamplerAddressMode) { +SamplerDescriptor_setRAddressMode :: #force_inline proc(self: ^SamplerDescriptor, rAddressMode: SamplerAddressMode) { msgSend(nil, self, "setRAddressMode:", rAddressMode) } @(objc_type=SamplerDescriptor, objc_name="setSAddressMode") -SamplerDescriptor_setSAddressMode :: proc(self: ^SamplerDescriptor, sAddressMode: SamplerAddressMode) { +SamplerDescriptor_setSAddressMode :: #force_inline proc(self: ^SamplerDescriptor, sAddressMode: SamplerAddressMode) { msgSend(nil, self, "setSAddressMode:", sAddressMode) } @(objc_type=SamplerDescriptor, objc_name="setSupportArgumentBuffers") -SamplerDescriptor_setSupportArgumentBuffers :: proc(self: ^SamplerDescriptor, supportArgumentBuffers: BOOL) { +SamplerDescriptor_setSupportArgumentBuffers :: #force_inline proc(self: ^SamplerDescriptor, supportArgumentBuffers: BOOL) { msgSend(nil, self, "setSupportArgumentBuffers:", supportArgumentBuffers) } @(objc_type=SamplerDescriptor, objc_name="setTAddressMode") -SamplerDescriptor_setTAddressMode :: proc(self: ^SamplerDescriptor, tAddressMode: SamplerAddressMode) { +SamplerDescriptor_setTAddressMode :: #force_inline proc(self: ^SamplerDescriptor, tAddressMode: SamplerAddressMode) { msgSend(nil, self, "setTAddressMode:", tAddressMode) } @(objc_type=SamplerDescriptor, objc_name="supportArgumentBuffers") -SamplerDescriptor_supportArgumentBuffers :: proc(self: ^SamplerDescriptor) -> BOOL { +SamplerDescriptor_supportArgumentBuffers :: #force_inline proc(self: ^SamplerDescriptor) -> BOOL { return msgSend(BOOL, self, "supportArgumentBuffers") } @(objc_type=SamplerDescriptor, objc_name="tAddressMode") -SamplerDescriptor_tAddressMode :: proc(self: ^SamplerDescriptor) -> SamplerAddressMode { +SamplerDescriptor_tAddressMode :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerAddressMode { return msgSend(SamplerAddressMode, self, "tAddressMode") } @@ -3741,15 +3727,15 @@ Methods: SharedEventHandle :: struct { using _: NS.Object } @(objc_type=SharedEventHandle, objc_class_name="alloc") -SharedEventHandle_alloc :: proc() -> ^SharedEventHandle { +SharedEventHandle_alloc :: #force_inline proc() -> ^SharedEventHandle { return msgSend(^SharedEventHandle, SharedEventHandle, "alloc") } @(objc_type=SharedEventHandle, objc_name="init") -SharedEventHandle_init :: proc(self: ^SharedEventHandle) -> ^SharedEventHandle { +SharedEventHandle_init :: #force_inline proc(self: ^SharedEventHandle) -> ^SharedEventHandle { return msgSend(^SharedEventHandle, self, "init") } @(objc_type=SharedEventHandle, objc_name="label") -SharedEventHandle_label :: proc(self: ^SharedEventHandle) -> ^NS.String { +SharedEventHandle_label :: #force_inline proc(self: ^SharedEventHandle) -> ^NS.String { return msgSend(^NS.String, self, "label") } @@ -3769,19 +3755,19 @@ Methods: SharedEventListener :: struct { using _: NS.Object } @(objc_type=SharedEventListener, objc_class_name="alloc") -SharedEventListener_alloc :: proc() -> ^SharedEventListener { +SharedEventListener_alloc :: #force_inline proc() -> ^SharedEventListener { return msgSend(^SharedEventListener, SharedEventListener, "alloc") } @(objc_type=SharedEventListener, objc_name="dispatchQueue") -SharedEventListener_dispatchQueue :: proc(self: ^SharedEventListener) -> NS.Integer { +SharedEventListener_dispatchQueue :: #force_inline proc(self: ^SharedEventListener) -> NS.Integer { return msgSend(NS.Integer, self, "dispatchQueue") } @(objc_type=SharedEventListener, objc_name="init") -SharedEventListener_init :: proc(self: ^SharedEventListener) -> ^SharedEventListener { +SharedEventListener_init :: #force_inline proc(self: ^SharedEventListener) -> ^SharedEventListener { return msgSend(^SharedEventListener, self, "init") } @(objc_type=SharedEventListener, objc_name="initWithDispatchQueue") -SharedEventListener_initWithDispatchQueue :: proc(self: ^SharedEventListener, dispatchQueue: ^NS.Object) -> ^SharedEventListener { +SharedEventListener_initWithDispatchQueue :: #force_inline proc(self: ^SharedEventListener, dispatchQueue: ^NS.Object) -> ^SharedEventListener { return msgSend(^SharedEventListener, self, "initWithDispatchQueue:", dispatchQueue) } @@ -3801,19 +3787,19 @@ Methods: SharedTextureHandle :: struct { using _: NS.Object } @(objc_type=SharedTextureHandle, objc_class_name="alloc") -SharedTextureHandle_alloc :: proc() -> ^SharedTextureHandle { +SharedTextureHandle_alloc :: #force_inline proc() -> ^SharedTextureHandle { return msgSend(^SharedTextureHandle, SharedTextureHandle, "alloc") } @(objc_type=SharedTextureHandle, objc_name="init") -SharedTextureHandle_init :: proc(self: ^SharedTextureHandle) -> ^SharedTextureHandle { +SharedTextureHandle_init :: #force_inline proc(self: ^SharedTextureHandle) -> ^SharedTextureHandle { return msgSend(^SharedTextureHandle, self, "init") } @(objc_type=SharedTextureHandle, objc_name="device") -SharedTextureHandle_device :: proc(self: ^SharedTextureHandle) -> ^SharedTextureHandle { +SharedTextureHandle_device :: #force_inline proc(self: ^SharedTextureHandle) -> ^SharedTextureHandle { return msgSend(^SharedTextureHandle, self, "device") } @(objc_type=SharedTextureHandle, objc_name="label") -SharedTextureHandle_label :: proc(self: ^SharedTextureHandle) -> ^NS.String { +SharedTextureHandle_label :: #force_inline proc(self: ^SharedTextureHandle) -> ^NS.String { return msgSend(^NS.String, self, "label") } @@ -3839,43 +3825,43 @@ Methods: StageInputOutputDescriptor :: struct { using _: NS.Copying(StageInputOutputDescriptor) } @(objc_type=StageInputOutputDescriptor, objc_class_name="alloc") -StageInputOutputDescriptor_alloc :: proc() -> ^StageInputOutputDescriptor { +StageInputOutputDescriptor_alloc :: #force_inline proc() -> ^StageInputOutputDescriptor { return msgSend(^StageInputOutputDescriptor, StageInputOutputDescriptor, "alloc") } @(objc_type=StageInputOutputDescriptor, objc_name="init") -StageInputOutputDescriptor_init :: proc(self: ^StageInputOutputDescriptor) -> ^StageInputOutputDescriptor { +StageInputOutputDescriptor_init :: #force_inline proc(self: ^StageInputOutputDescriptor) -> ^StageInputOutputDescriptor { return msgSend(^StageInputOutputDescriptor, self, "init") } @(objc_type=StageInputOutputDescriptor, objc_name="attributes") -StageInputOutputDescriptor_attributes :: proc(self: ^StageInputOutputDescriptor) -> ^AttributeDescriptorArray { +StageInputOutputDescriptor_attributes :: #force_inline proc(self: ^StageInputOutputDescriptor) -> ^AttributeDescriptorArray { return msgSend(^AttributeDescriptorArray, self, "attributes") } @(objc_type=StageInputOutputDescriptor, objc_name="indexBufferIndex") -StageInputOutputDescriptor_indexBufferIndex :: proc(self: ^StageInputOutputDescriptor) -> NS.Integer { +StageInputOutputDescriptor_indexBufferIndex :: #force_inline proc(self: ^StageInputOutputDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "indexBufferIndex") } @(objc_type=StageInputOutputDescriptor, objc_name="indexType") -StageInputOutputDescriptor_indexType :: proc(self: ^StageInputOutputDescriptor) -> IndexType { +StageInputOutputDescriptor_indexType :: #force_inline proc(self: ^StageInputOutputDescriptor) -> IndexType { return msgSend(IndexType, self, "indexType") } @(objc_type=StageInputOutputDescriptor, objc_name="layouts") -StageInputOutputDescriptor_layouts :: proc(self: ^StageInputOutputDescriptor) -> ^BufferLayoutDescriptorArray { +StageInputOutputDescriptor_layouts :: #force_inline proc(self: ^StageInputOutputDescriptor) -> ^BufferLayoutDescriptorArray { return msgSend(^BufferLayoutDescriptorArray, self, "layouts") } @(objc_type=StageInputOutputDescriptor, objc_name="reset") -StageInputOutputDescriptor_reset :: proc(self: ^StageInputOutputDescriptor) { +StageInputOutputDescriptor_reset :: #force_inline proc(self: ^StageInputOutputDescriptor) { msgSend(nil, self, "reset") } @(objc_type=StageInputOutputDescriptor, objc_name="setIndexBufferIndex") -StageInputOutputDescriptor_setIndexBufferIndex :: proc(self: ^StageInputOutputDescriptor, indexBufferIndex: NS.Integer) { +StageInputOutputDescriptor_setIndexBufferIndex :: #force_inline proc(self: ^StageInputOutputDescriptor, indexBufferIndex: NS.Integer) { msgSend(nil, self, "setIndexBufferIndex:", indexBufferIndex) } @(objc_type=StageInputOutputDescriptor, objc_name="setIndexType") -StageInputOutputDescriptor_setIndexType :: proc(self: ^StageInputOutputDescriptor, indexType: IndexType) { +StageInputOutputDescriptor_setIndexType :: #force_inline proc(self: ^StageInputOutputDescriptor, indexType: IndexType) { msgSend(nil, self, "setIndexType:", indexType) } @(objc_type=StageInputOutputDescriptor, objc_class_name="stageInputOutputDescriptor") -StageInputOutputDescriptor_stageInputOutputDescriptor :: proc() -> ^StageInputOutputDescriptor { +StageInputOutputDescriptor_stageInputOutputDescriptor :: #force_inline proc() -> ^StageInputOutputDescriptor { return msgSend(^StageInputOutputDescriptor, StageInputOutputDescriptor, "stageInputOutputDescriptor") } @@ -3905,59 +3891,59 @@ Methods: StencilDescriptor :: struct { using _: NS.Copying(StencilDescriptor) } @(objc_type=StencilDescriptor, objc_class_name="alloc") -StencilDescriptor_alloc :: proc() -> ^StencilDescriptor { +StencilDescriptor_alloc :: #force_inline proc() -> ^StencilDescriptor { return msgSend(^StencilDescriptor, StencilDescriptor, "alloc") } @(objc_type=StencilDescriptor, objc_name="init") -StencilDescriptor_init :: proc(self: ^StencilDescriptor) -> ^StencilDescriptor { +StencilDescriptor_init :: #force_inline proc(self: ^StencilDescriptor) -> ^StencilDescriptor { return msgSend(^StencilDescriptor, self, "init") } @(objc_type=StencilDescriptor, objc_name="depthFailureOperation") -StencilDescriptor_depthFailureOperation :: proc(self: ^StencilDescriptor) -> StencilOperation { +StencilDescriptor_depthFailureOperation :: #force_inline proc(self: ^StencilDescriptor) -> StencilOperation { return msgSend(StencilOperation, self, "depthFailureOperation") } @(objc_type=StencilDescriptor, objc_name="depthStencilPassOperation") -StencilDescriptor_depthStencilPassOperation :: proc(self: ^StencilDescriptor) -> StencilOperation { +StencilDescriptor_depthStencilPassOperation :: #force_inline proc(self: ^StencilDescriptor) -> StencilOperation { return msgSend(StencilOperation, self, "depthStencilPassOperation") } @(objc_type=StencilDescriptor, objc_name="readMask") -StencilDescriptor_readMask :: proc(self: ^StencilDescriptor) -> u32 { +StencilDescriptor_readMask :: #force_inline proc(self: ^StencilDescriptor) -> u32 { return msgSend(u32, self, "readMask") } @(objc_type=StencilDescriptor, objc_name="setDepthFailureOperation") -StencilDescriptor_setDepthFailureOperation :: proc(self: ^StencilDescriptor, depthFailureOperation: StencilOperation) { +StencilDescriptor_setDepthFailureOperation :: #force_inline proc(self: ^StencilDescriptor, depthFailureOperation: StencilOperation) { msgSend(nil, self, "setDepthFailureOperation:", depthFailureOperation) } @(objc_type=StencilDescriptor, objc_name="setDepthStencilPassOperation") -StencilDescriptor_setDepthStencilPassOperation :: proc(self: ^StencilDescriptor, depthStencilPassOperation: StencilOperation) { +StencilDescriptor_setDepthStencilPassOperation :: #force_inline proc(self: ^StencilDescriptor, depthStencilPassOperation: StencilOperation) { msgSend(nil, self, "setDepthStencilPassOperation:", depthStencilPassOperation) } @(objc_type=StencilDescriptor, objc_name="setReadMask") -StencilDescriptor_setReadMask :: proc(self: ^StencilDescriptor, readMask: u32) { +StencilDescriptor_setReadMask :: #force_inline proc(self: ^StencilDescriptor, readMask: u32) { msgSend(nil, self, "setReadMask:", readMask) } @(objc_type=StencilDescriptor, objc_name="setStencilCompareFunction") -StencilDescriptor_setStencilCompareFunction :: proc(self: ^StencilDescriptor, stencilCompareFunction: CompareFunction) { +StencilDescriptor_setStencilCompareFunction :: #force_inline proc(self: ^StencilDescriptor, stencilCompareFunction: CompareFunction) { msgSend(nil, self, "setStencilCompareFunction:", stencilCompareFunction) } @(objc_type=StencilDescriptor, objc_name="setStencilFailureOperation") -StencilDescriptor_setStencilFailureOperation :: proc(self: ^StencilDescriptor, stencilFailureOperation: StencilOperation) { +StencilDescriptor_setStencilFailureOperation :: #force_inline proc(self: ^StencilDescriptor, stencilFailureOperation: StencilOperation) { msgSend(nil, self, "setStencilFailureOperation:", stencilFailureOperation) } @(objc_type=StencilDescriptor, objc_name="setWriteMask") -StencilDescriptor_setWriteMask :: proc(self: ^StencilDescriptor, writeMask: u32) { +StencilDescriptor_setWriteMask :: #force_inline proc(self: ^StencilDescriptor, writeMask: u32) { msgSend(nil, self, "setWriteMask:", writeMask) } @(objc_type=StencilDescriptor, objc_name="stencilCompareFunction") -StencilDescriptor_stencilCompareFunction :: proc(self: ^StencilDescriptor) -> CompareFunction { +StencilDescriptor_stencilCompareFunction :: #force_inline proc(self: ^StencilDescriptor) -> CompareFunction { return msgSend(CompareFunction, self, "stencilCompareFunction") } @(objc_type=StencilDescriptor, objc_name="stencilFailureOperation") -StencilDescriptor_stencilFailureOperation :: proc(self: ^StencilDescriptor) -> StencilOperation { +StencilDescriptor_stencilFailureOperation :: #force_inline proc(self: ^StencilDescriptor) -> StencilOperation { return msgSend(StencilOperation, self, "stencilFailureOperation") } @(objc_type=StencilDescriptor, objc_name="writeMask") -StencilDescriptor_writeMask :: proc(self: ^StencilDescriptor) -> u32 { +StencilDescriptor_writeMask :: #force_inline proc(self: ^StencilDescriptor) -> u32 { return msgSend(u32, self, "writeMask") } @@ -3983,43 +3969,43 @@ Methods: StructMember :: struct { using _: NS.Object } @(objc_type=StructMember, objc_class_name="alloc") -StructMember_alloc :: proc() -> ^StructMember { +StructMember_alloc :: #force_inline proc() -> ^StructMember { return msgSend(^StructMember, StructMember, "alloc") } @(objc_type=StructMember, objc_name="init") -StructMember_init :: proc(self: ^StructMember) -> ^StructMember { +StructMember_init :: #force_inline proc(self: ^StructMember) -> ^StructMember { return msgSend(^StructMember, self, "init") } @(objc_type=StructMember, objc_name="argumentIndex") -StructMember_argumentIndex :: proc(self: ^StructMember) -> NS.Integer { +StructMember_argumentIndex :: #force_inline proc(self: ^StructMember) -> NS.Integer { return msgSend(NS.Integer, self, "argumentIndex") } @(objc_type=StructMember, objc_name="arrayType") -StructMember_arrayType :: proc(self: ^StructMember) -> ^ArrayType { +StructMember_arrayType :: #force_inline proc(self: ^StructMember) -> ^ArrayType { return msgSend(^ArrayType, self, "arrayType") } @(objc_type=StructMember, objc_name="dataType") -StructMember_dataType :: proc(self: ^StructMember) -> DataType { +StructMember_dataType :: #force_inline proc(self: ^StructMember) -> DataType { return msgSend(DataType, self, "dataType") } @(objc_type=StructMember, objc_name="name") -StructMember_name :: proc(self: ^StructMember) -> ^NS.String { +StructMember_name :: #force_inline proc(self: ^StructMember) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=StructMember, objc_name="offset") -StructMember_offset :: proc(self: ^StructMember) -> NS.Integer { +StructMember_offset :: #force_inline proc(self: ^StructMember) -> NS.Integer { return msgSend(NS.Integer, self, "offset") } @(objc_type=StructMember, objc_name="pointerType") -StructMember_pointerType :: proc(self: ^StructMember) -> ^PointerType { +StructMember_pointerType :: #force_inline proc(self: ^StructMember) -> ^PointerType { return msgSend(^PointerType, self, "pointerType") } @(objc_type=StructMember, objc_name="structType") -StructMember_structType :: proc(self: ^StructMember) -> ^StructType { +StructMember_structType :: #force_inline proc(self: ^StructMember) -> ^StructType { return msgSend(^StructType, self, "structType") } @(objc_type=StructMember, objc_name="textureReferenceType") -StructMember_textureReferenceType :: proc(self: ^StructMember) -> ^TextureReferenceType { +StructMember_textureReferenceType :: #force_inline proc(self: ^StructMember) -> ^TextureReferenceType { return msgSend(^TextureReferenceType, self, "textureReferenceType") } @@ -4039,19 +4025,19 @@ Methods: StructType :: struct { using _: NS.Object } @(objc_type=StructType, objc_class_name="alloc") -StructType_alloc :: proc() -> ^StructType { +StructType_alloc :: #force_inline proc() -> ^StructType { return msgSend(^StructType, StructType, "alloc") } @(objc_type=StructType, objc_name="init") -StructType_init :: proc(self: ^StructType) -> ^StructType { +StructType_init :: #force_inline proc(self: ^StructType) -> ^StructType { return msgSend(^StructType, self, "init") } @(objc_type=StructType, objc_name="memberByName") -StructType_memberByName :: proc(self: ^StructType, name: ^NS.String) -> ^StructMember { +StructType_memberByName :: #force_inline proc(self: ^StructType, name: ^NS.String) -> ^StructMember { return msgSend(^StructMember, self, "memberByName:", name) } @(objc_type=StructType, objc_name="members") -StructType_members :: proc(self: ^StructType) -> ^NS.Array { +StructType_members :: #force_inline proc(self: ^StructType) -> ^NS.Array { return msgSend(^NS.Array, self, "members") } @@ -4102,143 +4088,143 @@ Methods: TextureDescriptor :: struct { using _: NS.Copying(TextureDescriptor) } @(objc_type=TextureDescriptor, objc_class_name="alloc") -TextureDescriptor_alloc :: proc() -> ^TextureDescriptor { +TextureDescriptor_alloc :: #force_inline proc() -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "alloc") } @(objc_type=TextureDescriptor, objc_name="init") -TextureDescriptor_init :: proc(self: ^TextureDescriptor) -> ^TextureDescriptor { +TextureDescriptor_init :: #force_inline proc(self: ^TextureDescriptor) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, self, "init") } @(objc_type=TextureDescriptor, objc_name="allowGPUOptimizedContents") -TextureDescriptor_allowGPUOptimizedContents :: proc(self: ^TextureDescriptor) -> BOOL { +TextureDescriptor_allowGPUOptimizedContents :: #force_inline proc(self: ^TextureDescriptor) -> BOOL { return msgSend(BOOL, self, "allowGPUOptimizedContents") } @(objc_type=TextureDescriptor, objc_name="arrayLength") -TextureDescriptor_arrayLength :: proc(self: ^TextureDescriptor) -> NS.Integer { +TextureDescriptor_arrayLength :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "arrayLength") } @(objc_type=TextureDescriptor, objc_name="cpuCacheMode") -TextureDescriptor_cpuCacheMode :: proc(self: ^TextureDescriptor) -> CPUCacheMode { +TextureDescriptor_cpuCacheMode :: #force_inline proc(self: ^TextureDescriptor) -> CPUCacheMode { return msgSend(CPUCacheMode, self, "cpuCacheMode") } @(objc_type=TextureDescriptor, objc_name="depth") -TextureDescriptor_depth :: proc(self: ^TextureDescriptor) -> NS.Integer { +TextureDescriptor_depth :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "depth") } @(objc_type=TextureDescriptor, objc_name="hazardTrackingMode") -TextureDescriptor_hazardTrackingMode :: proc(self: ^TextureDescriptor) -> HazardTrackingMode { +TextureDescriptor_hazardTrackingMode :: #force_inline proc(self: ^TextureDescriptor) -> HazardTrackingMode { return msgSend(HazardTrackingMode, self, "hazardTrackingMode") } @(objc_type=TextureDescriptor, objc_name="height") -TextureDescriptor_height :: proc(self: ^TextureDescriptor) -> NS.Integer { +TextureDescriptor_height :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "height") } @(objc_type=TextureDescriptor, objc_name="mipmapLevelCount") -TextureDescriptor_mipmapLevelCount :: proc(self: ^TextureDescriptor) -> NS.Integer { +TextureDescriptor_mipmapLevelCount :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "mipmapLevelCount") } @(objc_type=TextureDescriptor, objc_name="pixelFormat") -TextureDescriptor_pixelFormat :: proc(self: ^TextureDescriptor) -> PixelFormat { +TextureDescriptor_pixelFormat :: #force_inline proc(self: ^TextureDescriptor) -> PixelFormat { return msgSend(PixelFormat, self, "pixelFormat") } @(objc_type=TextureDescriptor, objc_name="resourceOptions") -TextureDescriptor_resourceOptions :: proc(self: ^TextureDescriptor) -> ResourceOptions { +TextureDescriptor_resourceOptions :: #force_inline proc(self: ^TextureDescriptor) -> ResourceOptions { return msgSend(ResourceOptions, self, "resourceOptions") } @(objc_type=TextureDescriptor, objc_name="sampleCount") -TextureDescriptor_sampleCount :: proc(self: ^TextureDescriptor) -> NS.Integer { +TextureDescriptor_sampleCount :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "sampleCount") } @(objc_type=TextureDescriptor, objc_name="setAllowGPUOptimizedContents") -TextureDescriptor_setAllowGPUOptimizedContents :: proc(self: ^TextureDescriptor, allowGPUOptimizedContents: BOOL) { +TextureDescriptor_setAllowGPUOptimizedContents :: #force_inline proc(self: ^TextureDescriptor, allowGPUOptimizedContents: BOOL) { msgSend(nil, self, "setAllowGPUOptimizedContents:", allowGPUOptimizedContents) } @(objc_type=TextureDescriptor, objc_name="setArrayLength") -TextureDescriptor_setArrayLength :: proc(self: ^TextureDescriptor, arrayLength: NS.Integer) { +TextureDescriptor_setArrayLength :: #force_inline proc(self: ^TextureDescriptor, arrayLength: NS.Integer) { msgSend(nil, self, "setArrayLength:", arrayLength) } @(objc_type=TextureDescriptor, objc_name="setCpuCacheMode") -TextureDescriptor_setCpuCacheMode :: proc(self: ^TextureDescriptor, cpuCacheMode: CPUCacheMode) { +TextureDescriptor_setCpuCacheMode :: #force_inline proc(self: ^TextureDescriptor, cpuCacheMode: CPUCacheMode) { msgSend(nil, self, "setCpuCacheMode:", cpuCacheMode) } @(objc_type=TextureDescriptor, objc_name="setDepth") -TextureDescriptor_setDepth :: proc(self: ^TextureDescriptor, depth: NS.Integer) { +TextureDescriptor_setDepth :: #force_inline proc(self: ^TextureDescriptor, depth: NS.Integer) { msgSend(nil, self, "setDepth:", depth) } @(objc_type=TextureDescriptor, objc_name="setHazardTrackingMode") -TextureDescriptor_setHazardTrackingMode :: proc(self: ^TextureDescriptor, hazardTrackingMode: HazardTrackingMode) { +TextureDescriptor_setHazardTrackingMode :: #force_inline proc(self: ^TextureDescriptor, hazardTrackingMode: HazardTrackingMode) { msgSend(nil, self, "setHazardTrackingMode:", hazardTrackingMode) } @(objc_type=TextureDescriptor, objc_name="setHeight") -TextureDescriptor_setHeight :: proc(self: ^TextureDescriptor, height: NS.Integer) { +TextureDescriptor_setHeight :: #force_inline proc(self: ^TextureDescriptor, height: NS.Integer) { msgSend(nil, self, "setHeight:", height) } @(objc_type=TextureDescriptor, objc_name="setMipmapLevelCount") -TextureDescriptor_setMipmapLevelCount :: proc(self: ^TextureDescriptor, mipmapLevelCount: NS.Integer) { +TextureDescriptor_setMipmapLevelCount :: #force_inline proc(self: ^TextureDescriptor, mipmapLevelCount: NS.Integer) { msgSend(nil, self, "setMipmapLevelCount:", mipmapLevelCount) } @(objc_type=TextureDescriptor, objc_name="setPixelFormat") -TextureDescriptor_setPixelFormat :: proc(self: ^TextureDescriptor, pixelFormat: PixelFormat) { +TextureDescriptor_setPixelFormat :: #force_inline proc(self: ^TextureDescriptor, pixelFormat: PixelFormat) { msgSend(nil, self, "setPixelFormat:", pixelFormat) } @(objc_type=TextureDescriptor, objc_name="setResourceOptions") -TextureDescriptor_setResourceOptions :: proc(self: ^TextureDescriptor, resourceOptions: ResourceOptions) { +TextureDescriptor_setResourceOptions :: #force_inline proc(self: ^TextureDescriptor, resourceOptions: ResourceOptions) { msgSend(nil, self, "setResourceOptions:", resourceOptions) } @(objc_type=TextureDescriptor, objc_name="setSampleCount") -TextureDescriptor_setSampleCount :: proc(self: ^TextureDescriptor, sampleCount: NS.Integer) { +TextureDescriptor_setSampleCount :: #force_inline proc(self: ^TextureDescriptor, sampleCount: NS.Integer) { msgSend(nil, self, "setSampleCount:", sampleCount) } @(objc_type=TextureDescriptor, objc_name="setStorageMode") -TextureDescriptor_setStorageMode :: proc(self: ^TextureDescriptor, storageMode: StorageMode) { +TextureDescriptor_setStorageMode :: #force_inline proc(self: ^TextureDescriptor, storageMode: StorageMode) { msgSend(nil, self, "setStorageMode:", storageMode) } @(objc_type=TextureDescriptor, objc_name="setSwizzle") -TextureDescriptor_setSwizzle :: proc(self: ^TextureDescriptor, swizzle: TextureSwizzleChannels) { +TextureDescriptor_setSwizzle :: #force_inline proc(self: ^TextureDescriptor, swizzle: TextureSwizzleChannels) { msgSend(nil, self, "setSwizzle:", swizzle) } @(objc_type=TextureDescriptor, objc_name="setTextureType") -TextureDescriptor_setTextureType :: proc(self: ^TextureDescriptor, textureType: TextureType) { +TextureDescriptor_setTextureType :: #force_inline proc(self: ^TextureDescriptor, textureType: TextureType) { msgSend(nil, self, "setTextureType:", textureType) } @(objc_type=TextureDescriptor, objc_name="setUsage") -TextureDescriptor_setUsage :: proc(self: ^TextureDescriptor, usage: TextureUsage) { +TextureDescriptor_setUsage :: #force_inline proc(self: ^TextureDescriptor, usage: TextureUsage) { msgSend(nil, self, "setUsage:", usage) } @(objc_type=TextureDescriptor, objc_name="setWidth") -TextureDescriptor_setWidth :: proc(self: ^TextureDescriptor, width: NS.Integer) { +TextureDescriptor_setWidth :: #force_inline proc(self: ^TextureDescriptor, width: NS.Integer) { msgSend(nil, self, "setWidth:", width) } @(objc_type=TextureDescriptor, objc_name="storageMode") -TextureDescriptor_storageMode :: proc(self: ^TextureDescriptor) -> StorageMode { +TextureDescriptor_storageMode :: #force_inline proc(self: ^TextureDescriptor) -> StorageMode { return msgSend(StorageMode, self, "storageMode") } @(objc_type=TextureDescriptor, objc_name="swizzle") -TextureDescriptor_swizzle :: proc(self: ^TextureDescriptor) -> TextureSwizzleChannels { +TextureDescriptor_swizzle :: #force_inline proc(self: ^TextureDescriptor) -> TextureSwizzleChannels { return msgSend(TextureSwizzleChannels, self, "swizzle") } @(objc_type=TextureDescriptor, objc_class_name="texture2DDescriptorWithPixelFormat") -TextureDescriptor_texture2DDescriptorWithPixelFormat :: proc(pixelFormat: PixelFormat, width: ^NS.Object, height: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { +TextureDescriptor_texture2DDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: ^NS.Object, height: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "texture2DDescriptorWithPixelFormat:width:height:mipmapped:", pixelFormat, width, height, mipmapped) } @(objc_type=TextureDescriptor, objc_class_name="textureBufferDescriptorWithPixelFormat") -TextureDescriptor_textureBufferDescriptorWithPixelFormat :: proc(pixelFormat: PixelFormat, width: ^NS.Object, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { +TextureDescriptor_textureBufferDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: ^NS.Object, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureBufferDescriptorWithPixelFormat:width:resourceOptions:usage:", pixelFormat, width, resourceOptions, usage) } @(objc_type=TextureDescriptor, objc_class_name="textureCubeDescriptorWithPixelFormat") -TextureDescriptor_textureCubeDescriptorWithPixelFormat :: proc(pixelFormat: PixelFormat, size: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { +TextureDescriptor_textureCubeDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, size: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureCubeDescriptorWithPixelFormat:size:mipmapped:", pixelFormat, size, mipmapped) } @(objc_type=TextureDescriptor, objc_name="textureType") -TextureDescriptor_textureType :: proc(self: ^TextureDescriptor) -> TextureType { +TextureDescriptor_textureType :: #force_inline proc(self: ^TextureDescriptor) -> TextureType { return msgSend(TextureType, self, "textureType") } @(objc_type=TextureDescriptor, objc_name="usage") -TextureDescriptor_usage :: proc(self: ^TextureDescriptor) -> TextureUsage { +TextureDescriptor_usage :: #force_inline proc(self: ^TextureDescriptor) -> TextureUsage { return msgSend(TextureUsage, self, "usage") } @(objc_type=TextureDescriptor, objc_name="width") -TextureDescriptor_width :: proc(self: ^TextureDescriptor) -> NS.Integer { +TextureDescriptor_width :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "width") } @@ -4260,27 +4246,27 @@ Methods: TextureReferenceType :: struct { using _: NS.Object } @(objc_type=TextureReferenceType, objc_class_name="alloc") -TextureReferenceType_alloc :: proc() -> ^TextureReferenceType { +TextureReferenceType_alloc :: #force_inline proc() -> ^TextureReferenceType { return msgSend(^TextureReferenceType, TextureReferenceType, "alloc") } @(objc_type=TextureReferenceType, objc_name="init") -TextureReferenceType_init :: proc(self: ^TextureReferenceType) -> ^TextureReferenceType { +TextureReferenceType_init :: #force_inline proc(self: ^TextureReferenceType) -> ^TextureReferenceType { return msgSend(^TextureReferenceType, self, "init") } @(objc_type=TextureReferenceType, objc_name="access") -TextureReferenceType_access :: proc(self: ^TextureReferenceType) -> ArgumentAccess { +TextureReferenceType_access :: #force_inline proc(self: ^TextureReferenceType) -> ArgumentAccess { return msgSend(ArgumentAccess, self, "access") } @(objc_type=TextureReferenceType, objc_name="isDepthTexture") -TextureReferenceType_isDepthTexture :: proc(self: ^TextureReferenceType) -> BOOL { +TextureReferenceType_isDepthTexture :: #force_inline proc(self: ^TextureReferenceType) -> BOOL { return msgSend(BOOL, self, "isDepthTexture") } @(objc_type=TextureReferenceType, objc_name="textureDataType") -TextureReferenceType_textureDataType :: proc(self: ^TextureReferenceType) -> DataType { +TextureReferenceType_textureDataType :: #force_inline proc(self: ^TextureReferenceType) -> DataType { return msgSend(DataType, self, "textureDataType") } @(objc_type=TextureReferenceType, objc_name="textureType") -TextureReferenceType_textureType :: proc(self: ^TextureReferenceType) -> TextureType { +TextureReferenceType_textureType :: #force_inline proc(self: ^TextureReferenceType) -> TextureType { return msgSend(TextureType, self, "textureType") } @@ -4300,19 +4286,19 @@ Methods: TileRenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(TileRenderPipelineColorAttachmentDescriptor) } @(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_class_name="alloc") -TileRenderPipelineColorAttachmentDescriptor_alloc :: proc() -> ^TileRenderPipelineColorAttachmentDescriptor { +TileRenderPipelineColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^TileRenderPipelineColorAttachmentDescriptor { return msgSend(^TileRenderPipelineColorAttachmentDescriptor, TileRenderPipelineColorAttachmentDescriptor, "alloc") } @(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_name="init") -TileRenderPipelineColorAttachmentDescriptor_init :: proc(self: ^TileRenderPipelineColorAttachmentDescriptor) -> ^TileRenderPipelineColorAttachmentDescriptor { +TileRenderPipelineColorAttachmentDescriptor_init :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptor) -> ^TileRenderPipelineColorAttachmentDescriptor { return msgSend(^TileRenderPipelineColorAttachmentDescriptor, self, "init") } @(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_name="pixelFormat") -TileRenderPipelineColorAttachmentDescriptor_pixelFormat :: proc(self: ^TileRenderPipelineColorAttachmentDescriptor) -> PixelFormat { +TileRenderPipelineColorAttachmentDescriptor_pixelFormat :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptor) -> PixelFormat { return msgSend(PixelFormat, self, "pixelFormat") } @(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_name="setPixelFormat") -TileRenderPipelineColorAttachmentDescriptor_setPixelFormat :: proc(self: ^TileRenderPipelineColorAttachmentDescriptor, pixelFormat: PixelFormat) { +TileRenderPipelineColorAttachmentDescriptor_setPixelFormat :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptor, pixelFormat: PixelFormat) { msgSend(nil, self, "setPixelFormat:", pixelFormat) } @@ -4332,19 +4318,19 @@ Methods: TileRenderPipelineColorAttachmentDescriptorArray :: struct { using _: NS.Object } @(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_class_name="alloc") -TileRenderPipelineColorAttachmentDescriptorArray_alloc :: proc() -> ^TileRenderPipelineColorAttachmentDescriptorArray { +TileRenderPipelineColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^TileRenderPipelineColorAttachmentDescriptorArray { return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, TileRenderPipelineColorAttachmentDescriptorArray, "alloc") } @(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="init") -TileRenderPipelineColorAttachmentDescriptorArray_init :: proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray) -> ^TileRenderPipelineColorAttachmentDescriptorArray { +TileRenderPipelineColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray) -> ^TileRenderPipelineColorAttachmentDescriptorArray { return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, self, "init") } @(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -TileRenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^TileRenderPipelineColorAttachmentDescriptor { +TileRenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^TileRenderPipelineColorAttachmentDescriptor { return msgSend(^TileRenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") -TileRenderPipelineColorAttachmentDescriptorArray_setObject :: proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachment: ^TileRenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { +TileRenderPipelineColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachment: ^TileRenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -4377,71 +4363,71 @@ Methods: TileRenderPipelineDescriptor :: struct { using _: NS.Copying(TileRenderPipelineDescriptor) } @(objc_type=TileRenderPipelineDescriptor, objc_class_name="alloc") -TileRenderPipelineDescriptor_alloc :: proc() -> ^TileRenderPipelineDescriptor { +TileRenderPipelineDescriptor_alloc :: #force_inline proc() -> ^TileRenderPipelineDescriptor { return msgSend(^TileRenderPipelineDescriptor, TileRenderPipelineDescriptor, "alloc") } @(objc_type=TileRenderPipelineDescriptor, objc_name="init") -TileRenderPipelineDescriptor_init :: proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineDescriptor { +TileRenderPipelineDescriptor_init :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineDescriptor { return msgSend(^TileRenderPipelineDescriptor, self, "init") } @(objc_type=TileRenderPipelineDescriptor, objc_name="binaryArchives") -TileRenderPipelineDescriptor_binaryArchives :: proc(self: ^TileRenderPipelineDescriptor) -> ^NS.Array { +TileRenderPipelineDescriptor_binaryArchives :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^NS.Array { return msgSend(^NS.Array, self, "binaryArchives") } @(objc_type=TileRenderPipelineDescriptor, objc_name="colorAttachments") -TileRenderPipelineDescriptor_colorAttachments :: proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineColorAttachmentDescriptorArray { +TileRenderPipelineDescriptor_colorAttachments :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineColorAttachmentDescriptorArray { return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, self, "colorAttachments") } @(objc_type=TileRenderPipelineDescriptor, objc_name="label") -TileRenderPipelineDescriptor_label :: proc(self: ^TileRenderPipelineDescriptor) -> ^NS.String { +TileRenderPipelineDescriptor_label :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=TileRenderPipelineDescriptor, objc_name="maxTotalThreadsPerThreadgroup") -TileRenderPipelineDescriptor_maxTotalThreadsPerThreadgroup :: proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { +TileRenderPipelineDescriptor_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=TileRenderPipelineDescriptor, objc_name="rasterSampleCount") -TileRenderPipelineDescriptor_rasterSampleCount :: proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { +TileRenderPipelineDescriptor_rasterSampleCount :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "rasterSampleCount") } @(objc_type=TileRenderPipelineDescriptor, objc_name="reset") -TileRenderPipelineDescriptor_reset :: proc(self: ^TileRenderPipelineDescriptor) { +TileRenderPipelineDescriptor_reset :: #force_inline proc(self: ^TileRenderPipelineDescriptor) { msgSend(nil, self, "reset") } @(objc_type=TileRenderPipelineDescriptor, objc_name="setBinaryArchives") -TileRenderPipelineDescriptor_setBinaryArchives :: proc(self: ^TileRenderPipelineDescriptor, binaryArchives: ^NS.Array) { +TileRenderPipelineDescriptor_setBinaryArchives :: #force_inline proc(self: ^TileRenderPipelineDescriptor, binaryArchives: ^NS.Array) { msgSend(nil, self, "setBinaryArchives:", binaryArchives) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setLabel") -TileRenderPipelineDescriptor_setLabel :: proc(self: ^TileRenderPipelineDescriptor, label: ^NS.String) { +TileRenderPipelineDescriptor_setLabel :: #force_inline proc(self: ^TileRenderPipelineDescriptor, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setMaxTotalThreadsPerThreadgroup") -TileRenderPipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: proc(self: ^TileRenderPipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { +TileRenderPipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^TileRenderPipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { msgSend(nil, self, "setMaxTotalThreadsPerThreadgroup:", maxTotalThreadsPerThreadgroup) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setRasterSampleCount") -TileRenderPipelineDescriptor_setRasterSampleCount :: proc(self: ^TileRenderPipelineDescriptor, rasterSampleCount: NS.Integer) { +TileRenderPipelineDescriptor_setRasterSampleCount :: #force_inline proc(self: ^TileRenderPipelineDescriptor, rasterSampleCount: NS.Integer) { msgSend(nil, self, "setRasterSampleCount:", rasterSampleCount) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setThreadgroupSizeMatchesTileSize") -TileRenderPipelineDescriptor_setThreadgroupSizeMatchesTileSize :: proc(self: ^TileRenderPipelineDescriptor, threadgroupSizeMatchesTileSize: BOOL) { +TileRenderPipelineDescriptor_setThreadgroupSizeMatchesTileSize :: #force_inline proc(self: ^TileRenderPipelineDescriptor, threadgroupSizeMatchesTileSize: BOOL) { msgSend(nil, self, "setThreadgroupSizeMatchesTileSize:", threadgroupSizeMatchesTileSize) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setTileFunction") -TileRenderPipelineDescriptor_setTileFunction :: proc(self: ^TileRenderPipelineDescriptor, tileFunction: ^NS.Object) { +TileRenderPipelineDescriptor_setTileFunction :: #force_inline proc(self: ^TileRenderPipelineDescriptor, tileFunction: ^NS.Object) { msgSend(nil, self, "setTileFunction:", tileFunction) } @(objc_type=TileRenderPipelineDescriptor, objc_name="threadgroupSizeMatchesTileSize") -TileRenderPipelineDescriptor_threadgroupSizeMatchesTileSize :: proc(self: ^TileRenderPipelineDescriptor) -> BOOL { +TileRenderPipelineDescriptor_threadgroupSizeMatchesTileSize :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "threadgroupSizeMatchesTileSize") } @(objc_type=TileRenderPipelineDescriptor, objc_name="tileBuffers") -TileRenderPipelineDescriptor_tileBuffers :: proc(self: ^TileRenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { +TileRenderPipelineDescriptor_tileBuffers :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, self, "tileBuffers") } @(objc_type=TileRenderPipelineDescriptor, objc_name="tileFunction") -TileRenderPipelineDescriptor_tileFunction :: proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineDescriptor { +TileRenderPipelineDescriptor_tileFunction :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineDescriptor { return msgSend(^TileRenderPipelineDescriptor, self, "tileFunction") } @@ -4460,15 +4446,15 @@ Methods: Type :: struct { using _: NS.Object } @(objc_type=Type, objc_class_name="alloc") -Type_alloc :: proc() -> ^Type { +Type_alloc :: #force_inline proc() -> ^Type { return msgSend(^Type, Type, "alloc") } @(objc_type=Type, objc_name="init") -Type_init :: proc(self: ^Type) -> ^Type { +Type_init :: #force_inline proc(self: ^Type) -> ^Type { return msgSend(^Type, self, "init") } @(objc_type=Type, objc_name="dataType") -Type_dataType :: proc(self: ^Type) -> DataType { +Type_dataType :: #force_inline proc(self: ^Type) -> DataType { return msgSend(DataType, self, "dataType") } @@ -4492,35 +4478,35 @@ Methods: VertexAttribute :: struct { using _: NS.Object } @(objc_type=VertexAttribute, objc_class_name="alloc") -VertexAttribute_alloc :: proc() -> ^VertexAttribute { +VertexAttribute_alloc :: #force_inline proc() -> ^VertexAttribute { return msgSend(^VertexAttribute, VertexAttribute, "alloc") } @(objc_type=VertexAttribute, objc_name="init") -VertexAttribute_init :: proc(self: ^VertexAttribute) -> ^VertexAttribute { +VertexAttribute_init :: #force_inline proc(self: ^VertexAttribute) -> ^VertexAttribute { return msgSend(^VertexAttribute, self, "init") } @(objc_type=VertexAttribute, objc_name="attributeIndex") -VertexAttribute_attributeIndex :: proc(self: ^VertexAttribute) -> NS.Integer { +VertexAttribute_attributeIndex :: #force_inline proc(self: ^VertexAttribute) -> NS.Integer { return msgSend(NS.Integer, self, "attributeIndex") } @(objc_type=VertexAttribute, objc_name="attributeType") -VertexAttribute_attributeType :: proc(self: ^VertexAttribute) -> DataType { +VertexAttribute_attributeType :: #force_inline proc(self: ^VertexAttribute) -> DataType { return msgSend(DataType, self, "attributeType") } @(objc_type=VertexAttribute, objc_name="isActive") -VertexAttribute_isActive :: proc(self: ^VertexAttribute) -> BOOL { +VertexAttribute_isActive :: #force_inline proc(self: ^VertexAttribute) -> BOOL { return msgSend(BOOL, self, "isActive") } @(objc_type=VertexAttribute, objc_name="isPatchControlPointData") -VertexAttribute_isPatchControlPointData :: proc(self: ^VertexAttribute) -> BOOL { +VertexAttribute_isPatchControlPointData :: #force_inline proc(self: ^VertexAttribute) -> BOOL { return msgSend(BOOL, self, "isPatchControlPointData") } @(objc_type=VertexAttribute, objc_name="isPatchData") -VertexAttribute_isPatchData :: proc(self: ^VertexAttribute) -> BOOL { +VertexAttribute_isPatchData :: #force_inline proc(self: ^VertexAttribute) -> BOOL { return msgSend(BOOL, self, "isPatchData") } @(objc_type=VertexAttribute, objc_name="name") -VertexAttribute_name :: proc(self: ^VertexAttribute) -> ^NS.String { +VertexAttribute_name :: #force_inline proc(self: ^VertexAttribute) -> ^NS.String { return msgSend(^NS.String, self, "name") } @@ -4544,35 +4530,35 @@ Methods: VertexAttributeDescriptor :: struct { using _: NS.Copying(VertexAttributeDescriptor) } @(objc_type=VertexAttributeDescriptor, objc_class_name="alloc") -VertexAttributeDescriptor_alloc :: proc() -> ^VertexAttributeDescriptor { +VertexAttributeDescriptor_alloc :: #force_inline proc() -> ^VertexAttributeDescriptor { return msgSend(^VertexAttributeDescriptor, VertexAttributeDescriptor, "alloc") } @(objc_type=VertexAttributeDescriptor, objc_name="init") -VertexAttributeDescriptor_init :: proc(self: ^VertexAttributeDescriptor) -> ^VertexAttributeDescriptor { +VertexAttributeDescriptor_init :: #force_inline proc(self: ^VertexAttributeDescriptor) -> ^VertexAttributeDescriptor { return msgSend(^VertexAttributeDescriptor, self, "init") } @(objc_type=VertexAttributeDescriptor, objc_name="bufferIndex") -VertexAttributeDescriptor_bufferIndex :: proc(self: ^VertexAttributeDescriptor) -> NS.Integer { +VertexAttributeDescriptor_bufferIndex :: #force_inline proc(self: ^VertexAttributeDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "bufferIndex") } @(objc_type=VertexAttributeDescriptor, objc_name="format") -VertexAttributeDescriptor_format :: proc(self: ^VertexAttributeDescriptor) -> VertexFormat { +VertexAttributeDescriptor_format :: #force_inline proc(self: ^VertexAttributeDescriptor) -> VertexFormat { return msgSend(VertexFormat, self, "format") } @(objc_type=VertexAttributeDescriptor, objc_name="offset") -VertexAttributeDescriptor_offset :: proc(self: ^VertexAttributeDescriptor) -> NS.Integer { +VertexAttributeDescriptor_offset :: #force_inline proc(self: ^VertexAttributeDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "offset") } @(objc_type=VertexAttributeDescriptor, objc_name="setBufferIndex") -VertexAttributeDescriptor_setBufferIndex :: proc(self: ^VertexAttributeDescriptor, bufferIndex: NS.Integer) { +VertexAttributeDescriptor_setBufferIndex :: #force_inline proc(self: ^VertexAttributeDescriptor, bufferIndex: NS.Integer) { msgSend(nil, self, "setBufferIndex:", bufferIndex) } @(objc_type=VertexAttributeDescriptor, objc_name="setFormat") -VertexAttributeDescriptor_setFormat :: proc(self: ^VertexAttributeDescriptor, format: VertexFormat) { +VertexAttributeDescriptor_setFormat :: #force_inline proc(self: ^VertexAttributeDescriptor, format: VertexFormat) { msgSend(nil, self, "setFormat:", format) } @(objc_type=VertexAttributeDescriptor, objc_name="setOffset") -VertexAttributeDescriptor_setOffset :: proc(self: ^VertexAttributeDescriptor, offset: NS.Integer) { +VertexAttributeDescriptor_setOffset :: #force_inline proc(self: ^VertexAttributeDescriptor, offset: NS.Integer) { msgSend(nil, self, "setOffset:", offset) } @@ -4592,19 +4578,19 @@ Methods: VertexAttributeDescriptorArray :: struct { using _: NS.Object } @(objc_type=VertexAttributeDescriptorArray, objc_class_name="alloc") -VertexAttributeDescriptorArray_alloc :: proc() -> ^VertexAttributeDescriptorArray { +VertexAttributeDescriptorArray_alloc :: #force_inline proc() -> ^VertexAttributeDescriptorArray { return msgSend(^VertexAttributeDescriptorArray, VertexAttributeDescriptorArray, "alloc") } @(objc_type=VertexAttributeDescriptorArray, objc_name="init") -VertexAttributeDescriptorArray_init :: proc(self: ^VertexAttributeDescriptorArray) -> ^VertexAttributeDescriptorArray { +VertexAttributeDescriptorArray_init :: #force_inline proc(self: ^VertexAttributeDescriptorArray) -> ^VertexAttributeDescriptorArray { return msgSend(^VertexAttributeDescriptorArray, self, "init") } @(objc_type=VertexAttributeDescriptorArray, objc_name="objectAtIndexedSubscript") -VertexAttributeDescriptorArray_objectAtIndexedSubscript :: proc(self: ^VertexAttributeDescriptorArray, index: ^NS.Object) -> ^VertexAttributeDescriptor { +VertexAttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexAttributeDescriptorArray, index: ^NS.Object) -> ^VertexAttributeDescriptor { return msgSend(^VertexAttributeDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=VertexAttributeDescriptorArray, objc_name="setObject") -VertexAttributeDescriptorArray_setObject :: proc(self: ^VertexAttributeDescriptorArray, attributeDesc: ^VertexAttributeDescriptor, index: ^NS.Object) { +VertexAttributeDescriptorArray_setObject :: #force_inline proc(self: ^VertexAttributeDescriptorArray, attributeDesc: ^VertexAttributeDescriptor, index: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", attributeDesc, index) } @@ -4628,35 +4614,35 @@ Methods: VertexBufferLayoutDescriptor :: struct { using _: NS.Copying(VertexBufferLayoutDescriptor) } @(objc_type=VertexBufferLayoutDescriptor, objc_class_name="alloc") -VertexBufferLayoutDescriptor_alloc :: proc() -> ^VertexBufferLayoutDescriptor { +VertexBufferLayoutDescriptor_alloc :: #force_inline proc() -> ^VertexBufferLayoutDescriptor { return msgSend(^VertexBufferLayoutDescriptor, VertexBufferLayoutDescriptor, "alloc") } @(objc_type=VertexBufferLayoutDescriptor, objc_name="init") -VertexBufferLayoutDescriptor_init :: proc(self: ^VertexBufferLayoutDescriptor) -> ^VertexBufferLayoutDescriptor { +VertexBufferLayoutDescriptor_init :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> ^VertexBufferLayoutDescriptor { return msgSend(^VertexBufferLayoutDescriptor, self, "init") } @(objc_type=VertexBufferLayoutDescriptor, objc_name="setStepFunction") -VertexBufferLayoutDescriptor_setStepFunction :: proc(self: ^VertexBufferLayoutDescriptor, stepFunction: VertexStepFunction) { +VertexBufferLayoutDescriptor_setStepFunction :: #force_inline proc(self: ^VertexBufferLayoutDescriptor, stepFunction: VertexStepFunction) { msgSend(nil, self, "setStepFunction:", stepFunction) } @(objc_type=VertexBufferLayoutDescriptor, objc_name="setStepRate") -VertexBufferLayoutDescriptor_setStepRate :: proc(self: ^VertexBufferLayoutDescriptor, stepRate: NS.Integer) { +VertexBufferLayoutDescriptor_setStepRate :: #force_inline proc(self: ^VertexBufferLayoutDescriptor, stepRate: NS.Integer) { msgSend(nil, self, "setStepRate:", stepRate) } @(objc_type=VertexBufferLayoutDescriptor, objc_name="setStride") -VertexBufferLayoutDescriptor_setStride :: proc(self: ^VertexBufferLayoutDescriptor, stride: NS.Integer) { +VertexBufferLayoutDescriptor_setStride :: #force_inline proc(self: ^VertexBufferLayoutDescriptor, stride: NS.Integer) { msgSend(nil, self, "setStride:", stride) } @(objc_type=VertexBufferLayoutDescriptor, objc_name="stepFunction") -VertexBufferLayoutDescriptor_stepFunction :: proc(self: ^VertexBufferLayoutDescriptor) -> VertexStepFunction { +VertexBufferLayoutDescriptor_stepFunction :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> VertexStepFunction { return msgSend(VertexStepFunction, self, "stepFunction") } @(objc_type=VertexBufferLayoutDescriptor, objc_name="stepRate") -VertexBufferLayoutDescriptor_stepRate :: proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { +VertexBufferLayoutDescriptor_stepRate :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "stepRate") } @(objc_type=VertexBufferLayoutDescriptor, objc_name="stride") -VertexBufferLayoutDescriptor_stride :: proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { +VertexBufferLayoutDescriptor_stride :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "stride") } @@ -4676,19 +4662,19 @@ Methods: VertexBufferLayoutDescriptorArray :: struct { using _: NS.Object } @(objc_type=VertexBufferLayoutDescriptorArray, objc_class_name="alloc") -VertexBufferLayoutDescriptorArray_alloc :: proc() -> ^VertexBufferLayoutDescriptorArray { +VertexBufferLayoutDescriptorArray_alloc :: #force_inline proc() -> ^VertexBufferLayoutDescriptorArray { return msgSend(^VertexBufferLayoutDescriptorArray, VertexBufferLayoutDescriptorArray, "alloc") } @(objc_type=VertexBufferLayoutDescriptorArray, objc_name="init") -VertexBufferLayoutDescriptorArray_init :: proc(self: ^VertexBufferLayoutDescriptorArray) -> ^VertexBufferLayoutDescriptorArray { +VertexBufferLayoutDescriptorArray_init :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray) -> ^VertexBufferLayoutDescriptorArray { return msgSend(^VertexBufferLayoutDescriptorArray, self, "init") } @(objc_type=VertexBufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") -VertexBufferLayoutDescriptorArray_objectAtIndexedSubscript :: proc(self: ^VertexBufferLayoutDescriptorArray, index: ^NS.Object) -> ^VertexBufferLayoutDescriptor { +VertexBufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, index: ^NS.Object) -> ^VertexBufferLayoutDescriptor { return msgSend(^VertexBufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=VertexBufferLayoutDescriptorArray, objc_name="setObject") -VertexBufferLayoutDescriptorArray_setObject :: proc(self: ^VertexBufferLayoutDescriptorArray, bufferDesc: ^VertexBufferLayoutDescriptor, index: ^NS.Object) { +VertexBufferLayoutDescriptorArray_setObject :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, bufferDesc: ^VertexBufferLayoutDescriptor, index: ^NS.Object) { msgSend(nil, self, "setObject:atIndexedSubscript:", bufferDesc, index) } @@ -4710,27 +4696,27 @@ Methods: VertexDescriptor :: struct { using _: NS.Copying(VertexDescriptor) } @(objc_type=VertexDescriptor, objc_class_name="alloc") -VertexDescriptor_alloc :: proc() -> ^VertexDescriptor { +VertexDescriptor_alloc :: #force_inline proc() -> ^VertexDescriptor { return msgSend(^VertexDescriptor, VertexDescriptor, "alloc") } @(objc_type=VertexDescriptor, objc_name="init") -VertexDescriptor_init :: proc(self: ^VertexDescriptor) -> ^VertexDescriptor { +VertexDescriptor_init :: #force_inline proc(self: ^VertexDescriptor) -> ^VertexDescriptor { return msgSend(^VertexDescriptor, self, "init") } @(objc_type=VertexDescriptor, objc_name="attributes") -VertexDescriptor_attributes :: proc(self: ^VertexDescriptor) -> ^VertexAttributeDescriptorArray { +VertexDescriptor_attributes :: #force_inline proc(self: ^VertexDescriptor) -> ^VertexAttributeDescriptorArray { return msgSend(^VertexAttributeDescriptorArray, self, "attributes") } @(objc_type=VertexDescriptor, objc_name="layouts") -VertexDescriptor_layouts :: proc(self: ^VertexDescriptor) -> ^VertexBufferLayoutDescriptorArray { +VertexDescriptor_layouts :: #force_inline proc(self: ^VertexDescriptor) -> ^VertexBufferLayoutDescriptorArray { return msgSend(^VertexBufferLayoutDescriptorArray, self, "layouts") } @(objc_type=VertexDescriptor, objc_name="reset") -VertexDescriptor_reset :: proc(self: ^VertexDescriptor) { +VertexDescriptor_reset :: #force_inline proc(self: ^VertexDescriptor) { msgSend(nil, self, "reset") } @(objc_type=VertexDescriptor, objc_class_name="vertexDescriptor") -VertexDescriptor_vertexDescriptor :: proc() -> ^VertexDescriptor { +VertexDescriptor_vertexDescriptor :: #force_inline proc() -> ^VertexDescriptor { return msgSend(^VertexDescriptor, VertexDescriptor, "vertexDescriptor") } @@ -4751,23 +4737,23 @@ Methods: VisibleFunctionTableDescriptor :: struct { using _: NS.Copying(VisibleFunctionTableDescriptor) } @(objc_type=VisibleFunctionTableDescriptor, objc_class_name="alloc") -VisibleFunctionTableDescriptor_alloc :: proc() -> ^VisibleFunctionTableDescriptor { +VisibleFunctionTableDescriptor_alloc :: #force_inline proc() -> ^VisibleFunctionTableDescriptor { return msgSend(^VisibleFunctionTableDescriptor, VisibleFunctionTableDescriptor, "alloc") } @(objc_type=VisibleFunctionTableDescriptor, objc_name="init") -VisibleFunctionTableDescriptor_init :: proc(self: ^VisibleFunctionTableDescriptor) -> ^VisibleFunctionTableDescriptor { +VisibleFunctionTableDescriptor_init :: #force_inline proc(self: ^VisibleFunctionTableDescriptor) -> ^VisibleFunctionTableDescriptor { return msgSend(^VisibleFunctionTableDescriptor, self, "init") } @(objc_type=VisibleFunctionTableDescriptor, objc_name="functionCount") -VisibleFunctionTableDescriptor_functionCount :: proc(self: ^VisibleFunctionTableDescriptor) -> NS.Integer { +VisibleFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^VisibleFunctionTableDescriptor) -> NS.Integer { return msgSend(NS.Integer, self, "functionCount") } @(objc_type=VisibleFunctionTableDescriptor, objc_name="setFunctionCount") -VisibleFunctionTableDescriptor_setFunctionCount :: proc(self: ^VisibleFunctionTableDescriptor, functionCount: NS.Integer) { +VisibleFunctionTableDescriptor_setFunctionCount :: #force_inline proc(self: ^VisibleFunctionTableDescriptor, functionCount: NS.Integer) { msgSend(nil, self, "setFunctionCount:", functionCount) } @(objc_type=VisibleFunctionTableDescriptor, objc_class_name="visibleFunctionTableDescriptor") -VisibleFunctionTableDescriptor_visibleFunctionTableDescriptor :: proc() -> ^VisibleFunctionTableDescriptor { +VisibleFunctionTableDescriptor_visibleFunctionTableDescriptor :: #force_inline proc() -> ^VisibleFunctionTableDescriptor { return msgSend(^VisibleFunctionTableDescriptor, VisibleFunctionTableDescriptor, "visibleFunctionTableDescriptor") } @@ -4784,7 +4770,7 @@ Methods: AccelerationStructure :: struct { using _: NS.Object } @(objc_type=AccelerationStructure, objc_name="size") -AccelerationStructure_size :: proc(self: ^AccelerationStructure) -> NS.Integer { +AccelerationStructure_size :: #force_inline proc(self: ^AccelerationStructure) -> NS.Integer { return msgSend(NS.Integer, self, "size") } @@ -4812,51 +4798,51 @@ Methods: AccelerationStructureCommandEncoder :: struct { using _: NS.Object } @(objc_type=AccelerationStructureCommandEncoder, objc_name="buildAccelerationStructure") -AccelerationStructureCommandEncoder_buildAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { +AccelerationStructureCommandEncoder_buildAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { msgSend(nil, self, "buildAccelerationStructure:descriptor:scratchBuffer:scratchBufferOffset:", accelerationStructure, descriptor, scratchBuffer, scratchBufferOffset) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAccelerationStructure") -AccelerationStructureCommandEncoder_copyAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { +AccelerationStructureCommandEncoder_copyAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { msgSend(nil, self, "copyAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAndCompactAccelerationStructure") -AccelerationStructureCommandEncoder_copyAndCompactAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { +AccelerationStructureCommandEncoder_copyAndCompactAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { msgSend(nil, self, "copyAndCompactAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="refitAccelerationStructure") -AccelerationStructureCommandEncoder_refitAccelerationStructure :: proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, destinationAccelerationStructure: ^NS.Object, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { +AccelerationStructureCommandEncoder_refitAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, destinationAccelerationStructure: ^NS.Object, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { msgSend(nil, self, "refitAccelerationStructure:descriptor:destination:scratchBuffer:scratchBufferOffset:", sourceAccelerationStructure, descriptor, destinationAccelerationStructure, scratchBuffer, scratchBufferOffset) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="sampleCountersInBuffer") -AccelerationStructureCommandEncoder_sampleCountersInBuffer :: proc(self: ^AccelerationStructureCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +AccelerationStructureCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="updateFence") -AccelerationStructureCommandEncoder_updateFence :: proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { +AccelerationStructureCommandEncoder_updateFence :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useHeap") -AccelerationStructureCommandEncoder_useHeap :: proc(self: ^AccelerationStructureCommandEncoder, heap: ^NS.Object) { +AccelerationStructureCommandEncoder_useHeap :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heap: ^NS.Object) { msgSend(nil, self, "useHeap:", heap) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useHeaps") -AccelerationStructureCommandEncoder_useHeaps :: proc(self: ^AccelerationStructureCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { +AccelerationStructureCommandEncoder_useHeaps :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { msgSend(nil, self, "useHeaps:count:", heaps, count) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useResource") -AccelerationStructureCommandEncoder_useResource :: proc(self: ^AccelerationStructureCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { +AccelerationStructureCommandEncoder_useResource :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useResources") -AccelerationStructureCommandEncoder_useResources :: proc(self: ^AccelerationStructureCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { +AccelerationStructureCommandEncoder_useResources :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { msgSend(nil, self, "useResources:count:usage:", resources, count, usage) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="waitForFence") -AccelerationStructureCommandEncoder_waitForFence :: proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { +AccelerationStructureCommandEncoder_waitForFence :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "waitForFence:", fence) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="writeCompactedAccelerationStructureSize") -AccelerationStructureCommandEncoder_writeCompactedAccelerationStructureSize :: proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object) { +AccelerationStructureCommandEncoder_writeCompactedAccelerationStructureSize :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object) { msgSend(nil, self, "writeCompactedAccelerationStructureSize:toBuffer:offset:", accelerationStructure, buffer, offset) } @@ -4898,107 +4884,107 @@ Methods: ArgumentEncoder :: struct { using _: NS.Object } @(objc_type=ArgumentEncoder, objc_name="alignment") -ArgumentEncoder_alignment :: proc(self: ^ArgumentEncoder) -> NS.Integer { +ArgumentEncoder_alignment :: #force_inline proc(self: ^ArgumentEncoder) -> NS.Integer { return msgSend(NS.Integer, self, "alignment") } @(objc_type=ArgumentEncoder, objc_name="constantDataAtIndex") -ArgumentEncoder_constantDataAtIndex :: proc(self: ^ArgumentEncoder, index: ^NS.Object) -> rawptr { +ArgumentEncoder_constantDataAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: ^NS.Object) -> rawptr { return msgSend(rawptr, self, "constantDataAtIndex:", index) } @(objc_type=ArgumentEncoder, objc_name="device") -ArgumentEncoder_device :: proc(self: ^ArgumentEncoder) -> ^ArgumentEncoder { +ArgumentEncoder_device :: #force_inline proc(self: ^ArgumentEncoder) -> ^ArgumentEncoder { return msgSend(^ArgumentEncoder, self, "device") } @(objc_type=ArgumentEncoder, objc_name="encodedLength") -ArgumentEncoder_encodedLength :: proc(self: ^ArgumentEncoder) -> NS.Integer { +ArgumentEncoder_encodedLength :: #force_inline proc(self: ^ArgumentEncoder) -> NS.Integer { return msgSend(NS.Integer, self, "encodedLength") } @(objc_type=ArgumentEncoder, objc_name="label") -ArgumentEncoder_label :: proc(self: ^ArgumentEncoder) -> ^NS.String { +ArgumentEncoder_label :: #force_inline proc(self: ^ArgumentEncoder) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=ArgumentEncoder, objc_name="newArgumentEncoderForBufferAtIndex") -ArgumentEncoder_newArgumentEncoderForBufferAtIndex :: proc(self: ^ArgumentEncoder, index: ^NS.Object) -> ^ArgumentEncoder { +ArgumentEncoder_newArgumentEncoderForBufferAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: ^NS.Object) -> ^ArgumentEncoder { return msgSend(^ArgumentEncoder, self, "newArgumentEncoderForBufferAtIndex:", index) } @(objc_type=ArgumentEncoder, objc_name="setAccelerationStructure") -ArgumentEncoder_setAccelerationStructure :: proc(self: ^ArgumentEncoder, accelerationStructure: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setAccelerationStructure :: #force_inline proc(self: ^ArgumentEncoder, accelerationStructure: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setAccelerationStructure:atIndex:", accelerationStructure, index) } @(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_offset_") -ArgumentEncoder_setArgumentBuffer_offset_ :: proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, offset: ^NS.Object) { +ArgumentEncoder_setArgumentBuffer_offset_ :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, offset: ^NS.Object) { msgSend(nil, self, "setArgumentBuffer:offset:", argumentBuffer, offset) } @(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_startOffset_arrayElement_") -ArgumentEncoder_setArgumentBuffer_startOffset_arrayElement_ :: proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, startOffset: ^NS.Object, arrayElement: ^NS.Object) { +ArgumentEncoder_setArgumentBuffer_startOffset_arrayElement_ :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, startOffset: ^NS.Object, arrayElement: ^NS.Object) { msgSend(nil, self, "setArgumentBuffer:startOffset:arrayElement:", argumentBuffer, startOffset, arrayElement) } @(objc_type=ArgumentEncoder, objc_name="setBuffer") -ArgumentEncoder_setBuffer :: proc(self: ^ArgumentEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setBuffer :: #force_inline proc(self: ^ArgumentEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=ArgumentEncoder, objc_name="setBuffers") -ArgumentEncoder_setBuffers :: proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +ArgumentEncoder_setBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineState") -ArgumentEncoder_setComputePipelineState :: proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setComputePipelineState :: #force_inline proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setComputePipelineState:atIndex:", pipeline, index) } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineStates") -ArgumentEncoder_setComputePipelineStates :: proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setComputePipelineStates:withRange:", pipelines, range) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffer") -ArgumentEncoder_setIndirectCommandBuffer :: proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setIndirectCommandBuffer:atIndex:", indirectCommandBuffer, index) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffers") -ArgumentEncoder_setIndirectCommandBuffers :: proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setIndirectCommandBuffers:withRange:", buffers, range) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTable") -ArgumentEncoder_setIntersectionFunctionTable :: proc(self: ^ArgumentEncoder, intersectionFunctionTable: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTable: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setIntersectionFunctionTable:atIndex:", intersectionFunctionTable, index) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTables") -ArgumentEncoder_setIntersectionFunctionTables :: proc(self: ^ArgumentEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setIntersectionFunctionTables:withRange:", intersectionFunctionTables, range) } @(objc_type=ArgumentEncoder, objc_name="setLabel") -ArgumentEncoder_setLabel :: proc(self: ^ArgumentEncoder, label: ^NS.String) { +ArgumentEncoder_setLabel :: #force_inline proc(self: ^ArgumentEncoder, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=ArgumentEncoder, objc_name="setRenderPipelineState") -ArgumentEncoder_setRenderPipelineState :: proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setRenderPipelineState :: #force_inline proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setRenderPipelineState:atIndex:", pipeline, index) } @(objc_type=ArgumentEncoder, objc_name="setRenderPipelineStates") -ArgumentEncoder_setRenderPipelineStates :: proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setRenderPipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setRenderPipelineStates:withRange:", pipelines, range) } @(objc_type=ArgumentEncoder, objc_name="setSamplerState") -ArgumentEncoder_setSamplerState :: proc(self: ^ArgumentEncoder, sampler: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setSamplerState :: #force_inline proc(self: ^ArgumentEncoder, sampler: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) } @(objc_type=ArgumentEncoder, objc_name="setSamplerStates") -ArgumentEncoder_setSamplerStates :: proc(self: ^ArgumentEncoder, samplers: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setSamplerStates :: #force_inline proc(self: ^ArgumentEncoder, samplers: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) } @(objc_type=ArgumentEncoder, objc_name="setTexture") -ArgumentEncoder_setTexture :: proc(self: ^ArgumentEncoder, texture: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setTexture :: #force_inline proc(self: ^ArgumentEncoder, texture: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setTexture:atIndex:", texture, index) } @(objc_type=ArgumentEncoder, objc_name="setTextures") -ArgumentEncoder_setTextures :: proc(self: ^ArgumentEncoder, textures: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setTextures :: #force_inline proc(self: ^ArgumentEncoder, textures: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setTextures:withRange:", textures, range) } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTable") -ArgumentEncoder_setVisibleFunctionTable :: proc(self: ^ArgumentEncoder, visibleFunctionTable: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTable: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setVisibleFunctionTable:atIndex:", visibleFunctionTable, index) } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTables") -ArgumentEncoder_setVisibleFunctionTables :: proc(self: ^ArgumentEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setVisibleFunctionTables:withRange:", visibleFunctionTables, range) } @@ -5021,31 +5007,31 @@ Methods: BinaryArchive :: struct { using _: NS.Copying(BinaryArchive) } @(objc_type=BinaryArchive, objc_name="addComputePipelineFunctionsWithDescriptor") -BinaryArchive_addComputePipelineFunctionsWithDescriptor :: proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor, error: ^^NS.Error ) -> BOOL { +BinaryArchive_addComputePipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor, error: ^^NS.Error ) -> BOOL { return msgSend(BOOL, self, "addComputePipelineFunctionsWithDescriptor:error:", descriptor, error) } @(objc_type=BinaryArchive, objc_name="addRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { +BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { return msgSend(BOOL, self, "addRenderPipelineFunctionsWithDescriptor:error:", descriptor, error) } @(objc_type=BinaryArchive, objc_name="addTileRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { +BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { return msgSend(BOOL, self, "addTileRenderPipelineFunctionsWithDescriptor:error:", descriptor, error) } @(objc_type=BinaryArchive, objc_name="device") -BinaryArchive_device :: proc(self: ^BinaryArchive) -> ^BinaryArchive { +BinaryArchive_device :: #force_inline proc(self: ^BinaryArchive) -> ^BinaryArchive { return msgSend(^BinaryArchive, self, "device") } @(objc_type=BinaryArchive, objc_name="label") -BinaryArchive_label :: proc(self: ^BinaryArchive) -> ^NS.String { +BinaryArchive_label :: #force_inline proc(self: ^BinaryArchive) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=BinaryArchive, objc_name="serializeToURL") -BinaryArchive_serializeToURL :: proc(self: ^BinaryArchive, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { +BinaryArchive_serializeToURL :: #force_inline proc(self: ^BinaryArchive, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { return msgSend(BOOL, self, "serializeToURL:error:", url, error) } @(objc_type=BinaryArchive, objc_name="setLabel") -BinaryArchive_setLabel :: proc(self: ^BinaryArchive, label: ^NS.String) { +BinaryArchive_setLabel :: #force_inline proc(self: ^BinaryArchive, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -5086,103 +5072,103 @@ Methods: BlitCommandEncoder :: struct { using _: NS.Object } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { +BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_ :: proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin, options: BlitOption) { +BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin, options: BlitOption) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:options:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin, options) } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_ :: proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, size: ^NS.Object) { +BlitCommandEncoder_copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, size: ^NS.Object) { msgSend(nil, self, "copyFromBuffer:sourceOffset:toBuffer:destinationOffset:size:", sourceBuffer, sourceOffset, destinationBuffer, destinationOffset, size) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object, options: BlitOption) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object, options: BlitOption) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:options:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage, options) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, sliceCount: ^NS.Object, levelCount: ^NS.Object) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, sliceCount: ^NS.Object, levelCount: ^NS.Object) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:toTexture:destinationSlice:destinationLevel:sliceCount:levelCount:", sourceTexture, sourceSlice, sourceLevel, destinationTexture, destinationSlice, destinationLevel, sliceCount, levelCount) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_toTexture_") -BlitCommandEncoder_copyFromTexture_toTexture_ :: proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, destinationTexture: ^NS.Object) { +BlitCommandEncoder_copyFromTexture_toTexture_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, destinationTexture: ^NS.Object) { msgSend(nil, self, "copyFromTexture:toTexture:", sourceTexture, destinationTexture) } @(objc_type=BlitCommandEncoder, objc_name="copyIndirectCommandBuffer") -BlitCommandEncoder_copyIndirectCommandBuffer :: proc(self: ^BlitCommandEncoder, source: ^NS.Object, sourceRange: NS.Range, destination: ^NS.Object, destinationIndex: ^NS.Object) { +BlitCommandEncoder_copyIndirectCommandBuffer :: #force_inline proc(self: ^BlitCommandEncoder, source: ^NS.Object, sourceRange: NS.Range, destination: ^NS.Object, destinationIndex: ^NS.Object) { msgSend(nil, self, "copyIndirectCommandBuffer:sourceRange:destination:destinationIndex:", source, sourceRange, destination, destinationIndex) } @(objc_type=BlitCommandEncoder, objc_name="fillBuffer") -BlitCommandEncoder_fillBuffer :: proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range, value: u8) { +BlitCommandEncoder_fillBuffer :: #force_inline proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range, value: u8) { msgSend(nil, self, "fillBuffer:range:value:", buffer, range, value) } @(objc_type=BlitCommandEncoder, objc_name="generateMipmapsForTexture") -BlitCommandEncoder_generateMipmapsForTexture :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { +BlitCommandEncoder_generateMipmapsForTexture :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { msgSend(nil, self, "generateMipmapsForTexture:", texture) } @(objc_type=BlitCommandEncoder, objc_name="getTextureAccessCounters") -BlitCommandEncoder_getTextureAccessCounters :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object, resetCounters: BOOL, countersBuffer: ^NS.Object, countersBufferOffset: ^NS.Object) { +BlitCommandEncoder_getTextureAccessCounters :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object, resetCounters: BOOL, countersBuffer: ^NS.Object, countersBufferOffset: ^NS.Object) { msgSend(nil, self, "getTextureAccessCounters:region:mipLevel:slice:resetCounters:countersBuffer:countersBufferOffset:", texture, region, mipLevel, slice, resetCounters, countersBuffer, countersBufferOffset) } @(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForCPUAccess") -BlitCommandEncoder_optimizeContentsForCPUAccess :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { +BlitCommandEncoder_optimizeContentsForCPUAccess :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { msgSend(nil, self, "optimizeContentsForCPUAccess:", texture) } @(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForCPUAccess_slice_level_") -BlitCommandEncoder_optimizeContentsForCPUAccess_slice_level_ :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { +BlitCommandEncoder_optimizeContentsForCPUAccess_slice_level_ :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { msgSend(nil, self, "optimizeContentsForCPUAccess:slice:level:", texture, slice, level) } @(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForGPUAccess") -BlitCommandEncoder_optimizeContentsForGPUAccess :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { +BlitCommandEncoder_optimizeContentsForGPUAccess :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { msgSend(nil, self, "optimizeContentsForGPUAccess:", texture) } @(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForGPUAccess_slice_level_") -BlitCommandEncoder_optimizeContentsForGPUAccess_slice_level_ :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { +BlitCommandEncoder_optimizeContentsForGPUAccess_slice_level_ :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { msgSend(nil, self, "optimizeContentsForGPUAccess:slice:level:", texture, slice, level) } @(objc_type=BlitCommandEncoder, objc_name="optimizeIndirectCommandBuffer") -BlitCommandEncoder_optimizeIndirectCommandBuffer :: proc(self: ^BlitCommandEncoder, indirectCommandBuffer: ^NS.Object, range: NS.Range) { +BlitCommandEncoder_optimizeIndirectCommandBuffer :: #force_inline proc(self: ^BlitCommandEncoder, indirectCommandBuffer: ^NS.Object, range: NS.Range) { msgSend(nil, self, "optimizeIndirectCommandBuffer:withRange:", indirectCommandBuffer, range) } @(objc_type=BlitCommandEncoder, objc_name="resetCommandsInBuffer") -BlitCommandEncoder_resetCommandsInBuffer :: proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range) { +BlitCommandEncoder_resetCommandsInBuffer :: #force_inline proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range) { msgSend(nil, self, "resetCommandsInBuffer:withRange:", buffer, range) } @(objc_type=BlitCommandEncoder, objc_name="resetTextureAccessCounters") -BlitCommandEncoder_resetTextureAccessCounters :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object) { +BlitCommandEncoder_resetTextureAccessCounters :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object) { msgSend(nil, self, "resetTextureAccessCounters:region:mipLevel:slice:", texture, region, mipLevel, slice) } @(objc_type=BlitCommandEncoder, objc_name="resolveCounters") -BlitCommandEncoder_resolveCounters :: proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, range: NS.Range, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object) { +BlitCommandEncoder_resolveCounters :: #force_inline proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, range: NS.Range, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object) { msgSend(nil, self, "resolveCounters:inRange:destinationBuffer:destinationOffset:", sampleBuffer, range, destinationBuffer, destinationOffset) } @(objc_type=BlitCommandEncoder, objc_name="sampleCountersInBuffer") -BlitCommandEncoder_sampleCountersInBuffer :: proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +BlitCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=BlitCommandEncoder, objc_name="synchronizeResource") -BlitCommandEncoder_synchronizeResource :: proc(self: ^BlitCommandEncoder, resource: ^NS.Object) { +BlitCommandEncoder_synchronizeResource :: #force_inline proc(self: ^BlitCommandEncoder, resource: ^NS.Object) { msgSend(nil, self, "synchronizeResource:", resource) } @(objc_type=BlitCommandEncoder, objc_name="synchronizeTexture") -BlitCommandEncoder_synchronizeTexture :: proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { +BlitCommandEncoder_synchronizeTexture :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { msgSend(nil, self, "synchronizeTexture:slice:level:", texture, slice, level) } @(objc_type=BlitCommandEncoder, objc_name="updateFence") -BlitCommandEncoder_updateFence :: proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { +BlitCommandEncoder_updateFence :: #force_inline proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=BlitCommandEncoder, objc_name="waitForFence") -BlitCommandEncoder_waitForFence :: proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { +BlitCommandEncoder_waitForFence :: #force_inline proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "waitForFence:", fence) } @@ -5206,35 +5192,35 @@ Methods: Buffer :: struct { using _: NS.Object } @(objc_type=Buffer, objc_name="addDebugMarker") -Buffer_addDebugMarker :: proc(self: ^Buffer, marker: ^NS.String, range: NS.Range) { +Buffer_addDebugMarker :: #force_inline proc(self: ^Buffer, marker: ^NS.String, range: NS.Range) { msgSend(nil, self, "addDebugMarker:range:", marker, range) } @(objc_type=Buffer, objc_name="contents") -Buffer_contents :: proc(self: ^Buffer) -> rawptr { +Buffer_contents :: #force_inline proc(self: ^Buffer) -> rawptr { return msgSend(rawptr, self, "contents") } @(objc_type=Buffer, objc_name="didModifyRange") -Buffer_didModifyRange :: proc(self: ^Buffer, range: NS.Range) { +Buffer_didModifyRange :: #force_inline proc(self: ^Buffer, range: NS.Range) { msgSend(nil, self, "didModifyRange:", range) } @(objc_type=Buffer, objc_name="length") -Buffer_length :: proc(self: ^Buffer) -> NS.Integer { +Buffer_length :: #force_inline proc(self: ^Buffer) -> NS.Integer { return msgSend(NS.Integer, self, "length") } @(objc_type=Buffer, objc_name="newRemoteBufferViewForDevice") -Buffer_newRemoteBufferViewForDevice :: proc(self: ^Buffer, device: ^NS.Object) -> ^Buffer { +Buffer_newRemoteBufferViewForDevice :: #force_inline proc(self: ^Buffer, device: ^NS.Object) -> ^Buffer { return msgSend(^Buffer, self, "newRemoteBufferViewForDevice:", device) } @(objc_type=Buffer, objc_name="newTextureWithDescriptor") -Buffer_newTextureWithDescriptor :: proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: ^NS.Object, bytesPerRow: ^NS.Object) -> ^Buffer { +Buffer_newTextureWithDescriptor :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: ^NS.Object, bytesPerRow: ^NS.Object) -> ^Buffer { return msgSend(^Buffer, self, "newTextureWithDescriptor:offset:bytesPerRow:", descriptor, offset, bytesPerRow) } @(objc_type=Buffer, objc_name="remoteStorageBuffer") -Buffer_remoteStorageBuffer :: proc(self: ^Buffer) -> ^Buffer { +Buffer_remoteStorageBuffer :: #force_inline proc(self: ^Buffer) -> ^Buffer { return msgSend(^Buffer, self, "remoteStorageBuffer") } @(objc_type=Buffer, objc_name="removeAllDebugMarkers") -Buffer_removeAllDebugMarkers :: proc(self: ^Buffer) { +Buffer_removeAllDebugMarkers :: #force_inline proc(self: ^Buffer) { msgSend(nil, self, "removeAllDebugMarkers") } @@ -5256,27 +5242,27 @@ Methods: CaptureScope :: struct { using _: NS.Object } @(objc_type=CaptureScope, objc_name="beginScope") -CaptureScope_beginScope :: proc(self: ^CaptureScope) { +CaptureScope_beginScope :: #force_inline proc(self: ^CaptureScope) { msgSend(nil, self, "beginScope") } @(objc_type=CaptureScope, objc_name="commandQueue") -CaptureScope_commandQueue :: proc(self: ^CaptureScope) -> ^CaptureScope { +CaptureScope_commandQueue :: #force_inline proc(self: ^CaptureScope) -> ^CaptureScope { return msgSend(^CaptureScope, self, "commandQueue") } @(objc_type=CaptureScope, objc_name="device") -CaptureScope_device :: proc(self: ^CaptureScope) -> ^CaptureScope { +CaptureScope_device :: #force_inline proc(self: ^CaptureScope) -> ^CaptureScope { return msgSend(^CaptureScope, self, "device") } @(objc_type=CaptureScope, objc_name="endScope") -CaptureScope_endScope :: proc(self: ^CaptureScope) { +CaptureScope_endScope :: #force_inline proc(self: ^CaptureScope) { msgSend(nil, self, "endScope") } @(objc_type=CaptureScope, objc_name="label") -CaptureScope_label :: proc(self: ^CaptureScope) -> ^NS.String { +CaptureScope_label :: #force_inline proc(self: ^CaptureScope) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CaptureScope, objc_name="setLabel") -CaptureScope_setLabel :: proc(self: ^CaptureScope, label: ^NS.String) { +CaptureScope_setLabel :: #force_inline proc(self: ^CaptureScope, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -5328,147 +5314,147 @@ Methods: CommandBuffer :: struct { using _: NS.Object } @(objc_type=CommandBuffer, objc_name="GPUEndTime") -CommandBuffer_GPUEndTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { +CommandBuffer_GPUEndTime :: #force_inline proc(self: ^CommandBuffer) -> CFTimeInterval { return msgSend(CFTimeInterval, self, "GPUEndTime") } @(objc_type=CommandBuffer, objc_name="GPUStartTime") -CommandBuffer_GPUStartTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { +CommandBuffer_GPUStartTime :: #force_inline proc(self: ^CommandBuffer) -> CFTimeInterval { return msgSend(CFTimeInterval, self, "GPUStartTime") } @(objc_type=CommandBuffer, objc_name="accelerationStructureCommandEncoder") -CommandBuffer_accelerationStructureCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { +CommandBuffer_accelerationStructureCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "accelerationStructureCommandEncoder") } @(objc_type=CommandBuffer, objc_name="addCompletedHandler") -CommandBuffer_addCompletedHandler :: proc(self: ^CommandBuffer, block: CommandBufferHandler) { +CommandBuffer_addCompletedHandler :: #force_inline proc(self: ^CommandBuffer, block: CommandBufferHandler) { msgSend(nil, self, "addCompletedHandler:", block) } @(objc_type=CommandBuffer, objc_name="addScheduledHandler") -CommandBuffer_addScheduledHandler :: proc(self: ^CommandBuffer, block: CommandBufferHandler) { +CommandBuffer_addScheduledHandler :: #force_inline proc(self: ^CommandBuffer, block: CommandBufferHandler) { msgSend(nil, self, "addScheduledHandler:", block) } @(objc_type=CommandBuffer, objc_name="blitCommandEncoder") -CommandBuffer_blitCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { +CommandBuffer_blitCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "blitCommandEncoder") } @(objc_type=CommandBuffer, objc_name="blitCommandEncoderWithDescriptor") -CommandBuffer_blitCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, blitPassDescriptor: ^BlitPassDescriptor) -> ^CommandBuffer { +CommandBuffer_blitCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, blitPassDescriptor: ^BlitPassDescriptor) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "blitCommandEncoderWithDescriptor:", blitPassDescriptor) } @(objc_type=CommandBuffer, objc_name="commandQueue") -CommandBuffer_commandQueue :: proc(self: ^CommandBuffer) -> ^CommandBuffer { +CommandBuffer_commandQueue :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "commandQueue") } @(objc_type=CommandBuffer, objc_name="commit") -CommandBuffer_commit :: proc(self: ^CommandBuffer) { +CommandBuffer_commit :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "commit") } @(objc_type=CommandBuffer, objc_name="computeCommandEncoder") -CommandBuffer_computeCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { +CommandBuffer_computeCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "computeCommandEncoder") } @(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDescriptor") -CommandBuffer_computeCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, computePassDescriptor: ^ComputePassDescriptor) -> ^CommandBuffer { +CommandBuffer_computeCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, computePassDescriptor: ^ComputePassDescriptor) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "computeCommandEncoderWithDescriptor:", computePassDescriptor) } @(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDispatchType") -CommandBuffer_computeCommandEncoderWithDispatchType :: proc(self: ^CommandBuffer, dispatchType: DispatchType) -> ^CommandBuffer { +CommandBuffer_computeCommandEncoderWithDispatchType :: #force_inline proc(self: ^CommandBuffer, dispatchType: DispatchType) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "computeCommandEncoderWithDispatchType:", dispatchType) } @(objc_type=CommandBuffer, objc_name="device") -CommandBuffer_device :: proc(self: ^CommandBuffer) -> ^CommandBuffer { +CommandBuffer_device :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "device") } @(objc_type=CommandBuffer, objc_name="encodeSignalEvent") -CommandBuffer_encodeSignalEvent :: proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { +CommandBuffer_encodeSignalEvent :: #force_inline proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { msgSend(nil, self, "encodeSignalEvent:value:", event, value) } @(objc_type=CommandBuffer, objc_name="encodeWaitForEvent") -CommandBuffer_encodeWaitForEvent :: proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { +CommandBuffer_encodeWaitForEvent :: #force_inline proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { msgSend(nil, self, "encodeWaitForEvent:value:", event, value) } @(objc_type=CommandBuffer, objc_name="enqueue") -CommandBuffer_enqueue :: proc(self: ^CommandBuffer) { +CommandBuffer_enqueue :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "enqueue") } @(objc_type=CommandBuffer, objc_name="error") -CommandBuffer_error :: proc(self: ^CommandBuffer) -> ^NS.Error { +CommandBuffer_error :: #force_inline proc(self: ^CommandBuffer) -> ^NS.Error { return msgSend(^NS.Error, self, "error") } @(objc_type=CommandBuffer, objc_name="errorOptions") -CommandBuffer_errorOptions :: proc(self: ^CommandBuffer) -> CommandBufferErrorOption { +CommandBuffer_errorOptions :: #force_inline proc(self: ^CommandBuffer) -> CommandBufferErrorOption { return msgSend(CommandBufferErrorOption, self, "errorOptions") } @(objc_type=CommandBuffer, objc_name="kernelEndTime") -CommandBuffer_kernelEndTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { +CommandBuffer_kernelEndTime :: #force_inline proc(self: ^CommandBuffer) -> CFTimeInterval { return msgSend(CFTimeInterval, self, "kernelEndTime") } @(objc_type=CommandBuffer, objc_name="kernelStartTime") -CommandBuffer_kernelStartTime :: proc(self: ^CommandBuffer) -> CFTimeInterval { +CommandBuffer_kernelStartTime :: #force_inline proc(self: ^CommandBuffer) -> CFTimeInterval { return msgSend(CFTimeInterval, self, "kernelStartTime") } @(objc_type=CommandBuffer, objc_name="label") -CommandBuffer_label :: proc(self: ^CommandBuffer) -> ^NS.String { +CommandBuffer_label :: #force_inline proc(self: ^CommandBuffer) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CommandBuffer, objc_name="logs") -CommandBuffer_logs :: proc(self: ^CommandBuffer) -> ^CommandBuffer { +CommandBuffer_logs :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "logs") } @(objc_type=CommandBuffer, objc_name="parallelRenderCommandEncoderWithDescriptor") -CommandBuffer_parallelRenderCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { +CommandBuffer_parallelRenderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "parallelRenderCommandEncoderWithDescriptor:", renderPassDescriptor) } @(objc_type=CommandBuffer, objc_name="popDebugGroup") -CommandBuffer_popDebugGroup :: proc(self: ^CommandBuffer) { +CommandBuffer_popDebugGroup :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "popDebugGroup") } @(objc_type=CommandBuffer, objc_name="presentDrawable") -CommandBuffer_presentDrawable :: proc(self: ^CommandBuffer, drawable: ^NS.Object) { +CommandBuffer_presentDrawable :: #force_inline proc(self: ^CommandBuffer, drawable: ^NS.Object) { msgSend(nil, self, "presentDrawable:", drawable) } @(objc_type=CommandBuffer, objc_name="presentDrawable_afterMinimumDuration_") -CommandBuffer_presentDrawable_afterMinimumDuration_ :: proc(self: ^CommandBuffer, drawable: ^NS.Object, duration: CFTimeInterval) { +CommandBuffer_presentDrawable_afterMinimumDuration_ :: #force_inline proc(self: ^CommandBuffer, drawable: ^NS.Object, duration: CFTimeInterval) { msgSend(nil, self, "presentDrawable:afterMinimumDuration:", drawable, duration) } @(objc_type=CommandBuffer, objc_name="presentDrawable_atTime_") -CommandBuffer_presentDrawable_atTime_ :: proc(self: ^CommandBuffer, drawable: ^NS.Object, presentationTime: CFTimeInterval) { +CommandBuffer_presentDrawable_atTime_ :: #force_inline proc(self: ^CommandBuffer, drawable: ^NS.Object, presentationTime: CFTimeInterval) { msgSend(nil, self, "presentDrawable:atTime:", drawable, presentationTime) } @(objc_type=CommandBuffer, objc_name="pushDebugGroup") -CommandBuffer_pushDebugGroup :: proc(self: ^CommandBuffer, string: ^NS.String) { +CommandBuffer_pushDebugGroup :: #force_inline proc(self: ^CommandBuffer, string: ^NS.String) { msgSend(nil, self, "pushDebugGroup:", string) } @(objc_type=CommandBuffer, objc_name="renderCommandEncoderWithDescriptor") -CommandBuffer_renderCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { +CommandBuffer_renderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "renderCommandEncoderWithDescriptor:", renderPassDescriptor) } @(objc_type=CommandBuffer, objc_name="resourceStateCommandEncoder") -CommandBuffer_resourceStateCommandEncoder :: proc(self: ^CommandBuffer) -> ^CommandBuffer { +CommandBuffer_resourceStateCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "resourceStateCommandEncoder") } @(objc_type=CommandBuffer, objc_name="resourceStateCommandEncoderWithDescriptor") -CommandBuffer_resourceStateCommandEncoderWithDescriptor :: proc(self: ^CommandBuffer, resourceStatePassDescriptor: ^ResourceStatePassDescriptor) -> ^CommandBuffer { +CommandBuffer_resourceStateCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, resourceStatePassDescriptor: ^ResourceStatePassDescriptor) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "resourceStateCommandEncoderWithDescriptor:", resourceStatePassDescriptor) } @(objc_type=CommandBuffer, objc_name="retainedReferences") -CommandBuffer_retainedReferences :: proc(self: ^CommandBuffer) -> BOOL { +CommandBuffer_retainedReferences :: #force_inline proc(self: ^CommandBuffer) -> BOOL { return msgSend(BOOL, self, "retainedReferences") } @(objc_type=CommandBuffer, objc_name="setLabel") -CommandBuffer_setLabel :: proc(self: ^CommandBuffer, label: ^NS.String) { +CommandBuffer_setLabel :: #force_inline proc(self: ^CommandBuffer, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=CommandBuffer, objc_name="status") -CommandBuffer_status :: proc(self: ^CommandBuffer) -> CommandBufferStatus { +CommandBuffer_status :: #force_inline proc(self: ^CommandBuffer) -> CommandBufferStatus { return msgSend(CommandBufferStatus, self, "status") } @(objc_type=CommandBuffer, objc_name="waitUntilCompleted") -CommandBuffer_waitUntilCompleted :: proc(self: ^CommandBuffer) { +CommandBuffer_waitUntilCompleted :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "waitUntilCompleted") } @(objc_type=CommandBuffer, objc_name="waitUntilScheduled") -CommandBuffer_waitUntilScheduled :: proc(self: ^CommandBuffer) { +CommandBuffer_waitUntilScheduled :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "waitUntilScheduled") } @@ -5487,15 +5473,15 @@ Methods: CommandBufferEncoderInfo :: struct { using _: NS.Object } @(objc_type=CommandBufferEncoderInfo, objc_name="debugSignposts") -CommandBufferEncoderInfo_debugSignposts :: proc(self: ^CommandBufferEncoderInfo) -> ^NS.Array { +CommandBufferEncoderInfo_debugSignposts :: #force_inline proc(self: ^CommandBufferEncoderInfo) -> ^NS.Array { return msgSend(^NS.Array, self, "debugSignposts") } @(objc_type=CommandBufferEncoderInfo, objc_name="errorState") -CommandBufferEncoderInfo_errorState :: proc(self: ^CommandBufferEncoderInfo) -> CommandEncoderErrorState { +CommandBufferEncoderInfo_errorState :: #force_inline proc(self: ^CommandBufferEncoderInfo) -> CommandEncoderErrorState { return msgSend(CommandEncoderErrorState, self, "errorState") } @(objc_type=CommandBufferEncoderInfo, objc_name="label") -CommandBufferEncoderInfo_label :: proc(self: ^CommandBufferEncoderInfo) -> ^NS.String { +CommandBufferEncoderInfo_label :: #force_inline proc(self: ^CommandBufferEncoderInfo) -> ^NS.String { return msgSend(^NS.String, self, "label") } @@ -5518,31 +5504,31 @@ Methods: CommandEncoder :: struct { using _: NS.Object } @(objc_type=CommandEncoder, objc_name="device") -CommandEncoder_device :: proc(self: ^CommandEncoder) -> ^CommandEncoder { +CommandEncoder_device :: #force_inline proc(self: ^CommandEncoder) -> ^CommandEncoder { return msgSend(^CommandEncoder, self, "device") } @(objc_type=CommandEncoder, objc_name="endEncoding") -CommandEncoder_endEncoding :: proc(self: ^CommandEncoder) { +CommandEncoder_endEncoding :: #force_inline proc(self: ^CommandEncoder) { msgSend(nil, self, "endEncoding") } @(objc_type=CommandEncoder, objc_name="insertDebugSignpost") -CommandEncoder_insertDebugSignpost :: proc(self: ^CommandEncoder, string: ^NS.String) { +CommandEncoder_insertDebugSignpost :: #force_inline proc(self: ^CommandEncoder, string: ^NS.String) { msgSend(nil, self, "insertDebugSignpost:", string) } @(objc_type=CommandEncoder, objc_name="label") -CommandEncoder_label :: proc(self: ^CommandEncoder) -> ^NS.String { +CommandEncoder_label :: #force_inline proc(self: ^CommandEncoder) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CommandEncoder, objc_name="popDebugGroup") -CommandEncoder_popDebugGroup :: proc(self: ^CommandEncoder) { +CommandEncoder_popDebugGroup :: #force_inline proc(self: ^CommandEncoder) { msgSend(nil, self, "popDebugGroup") } @(objc_type=CommandEncoder, objc_name="pushDebugGroup") -CommandEncoder_pushDebugGroup :: proc(self: ^CommandEncoder, string: ^NS.String) { +CommandEncoder_pushDebugGroup :: #force_inline proc(self: ^CommandEncoder, string: ^NS.String) { msgSend(nil, self, "pushDebugGroup:", string) } @(objc_type=CommandEncoder, objc_name="setLabel") -CommandEncoder_setLabel :: proc(self: ^CommandEncoder, label: ^NS.String) { +CommandEncoder_setLabel :: #force_inline proc(self: ^CommandEncoder, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -5565,31 +5551,31 @@ Methods: CommandQueue :: struct { using _: NS.Object } @(objc_type=CommandQueue, objc_name="commandBuffer") -CommandQueue_commandBuffer :: proc(self: ^CommandQueue) -> ^CommandQueue { +CommandQueue_commandBuffer :: #force_inline proc(self: ^CommandQueue) -> ^CommandQueue { return msgSend(^CommandQueue, self, "commandBuffer") } @(objc_type=CommandQueue, objc_name="commandBufferWithDescriptor") -CommandQueue_commandBufferWithDescriptor :: proc(self: ^CommandQueue, descriptor: ^CommandBufferDescriptor) -> ^CommandQueue { +CommandQueue_commandBufferWithDescriptor :: #force_inline proc(self: ^CommandQueue, descriptor: ^CommandBufferDescriptor) -> ^CommandQueue { return msgSend(^CommandQueue, self, "commandBufferWithDescriptor:", descriptor) } @(objc_type=CommandQueue, objc_name="commandBufferWithUnretainedReferences") -CommandQueue_commandBufferWithUnretainedReferences :: proc(self: ^CommandQueue) -> ^CommandQueue { +CommandQueue_commandBufferWithUnretainedReferences :: #force_inline proc(self: ^CommandQueue) -> ^CommandQueue { return msgSend(^CommandQueue, self, "commandBufferWithUnretainedReferences") } @(objc_type=CommandQueue, objc_name="device") -CommandQueue_device :: proc(self: ^CommandQueue) -> ^CommandQueue { +CommandQueue_device :: #force_inline proc(self: ^CommandQueue) -> ^CommandQueue { return msgSend(^CommandQueue, self, "device") } @(objc_type=CommandQueue, objc_name="insertDebugCaptureBoundary") -CommandQueue_insertDebugCaptureBoundary :: proc(self: ^CommandQueue) { +CommandQueue_insertDebugCaptureBoundary :: #force_inline proc(self: ^CommandQueue) { msgSend(nil, self, "insertDebugCaptureBoundary") } @(objc_type=CommandQueue, objc_name="label") -CommandQueue_label :: proc(self: ^CommandQueue) -> ^NS.String { +CommandQueue_label :: #force_inline proc(self: ^CommandQueue) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CommandQueue, objc_name="setLabel") -CommandQueue_setLabel :: proc(self: ^CommandQueue, label: ^NS.String) { +CommandQueue_setLabel :: #force_inline proc(self: ^CommandQueue, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -5640,143 +5626,143 @@ Methods: ComputeCommandEncoder :: struct { using _: NS.Object } @(objc_type=ComputeCommandEncoder, objc_name="dispatchThreadgroups") -ComputeCommandEncoder_dispatchThreadgroups :: proc(self: ^ComputeCommandEncoder, threadgroupsPerGrid: Size, threadsPerThreadgroup: Size) { +ComputeCommandEncoder_dispatchThreadgroups :: #force_inline proc(self: ^ComputeCommandEncoder, threadgroupsPerGrid: Size, threadsPerThreadgroup: Size) { msgSend(nil, self, "dispatchThreadgroups:threadsPerThreadgroup:", threadgroupsPerGrid, threadsPerThreadgroup) } @(objc_type=ComputeCommandEncoder, objc_name="dispatchThreadgroupsWithIndirectBuffer") -ComputeCommandEncoder_dispatchThreadgroupsWithIndirectBuffer :: proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object, threadsPerThreadgroup: Size) { +ComputeCommandEncoder_dispatchThreadgroupsWithIndirectBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object, threadsPerThreadgroup: Size) { msgSend(nil, self, "dispatchThreadgroupsWithIndirectBuffer:indirectBufferOffset:threadsPerThreadgroup:", indirectBuffer, indirectBufferOffset, threadsPerThreadgroup) } @(objc_type=ComputeCommandEncoder, objc_name="dispatchThreads") -ComputeCommandEncoder_dispatchThreads :: proc(self: ^ComputeCommandEncoder, threadsPerGrid: Size, threadsPerThreadgroup: Size) { +ComputeCommandEncoder_dispatchThreads :: #force_inline proc(self: ^ComputeCommandEncoder, threadsPerGrid: Size, threadsPerThreadgroup: Size) { msgSend(nil, self, "dispatchThreads:threadsPerThreadgroup:", threadsPerGrid, threadsPerThreadgroup) } @(objc_type=ComputeCommandEncoder, objc_name="dispatchType") -ComputeCommandEncoder_dispatchType :: proc(self: ^ComputeCommandEncoder) -> DispatchType { +ComputeCommandEncoder_dispatchType :: #force_inline proc(self: ^ComputeCommandEncoder) -> DispatchType { return msgSend(DispatchType, self, "dispatchType") } @(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_") -ComputeCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: proc(self: ^ComputeCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +ComputeCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^ComputeCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "executeCommandsInBuffer:indirectBuffer:indirectBufferOffset:", indirectCommandbuffer, indirectRangeBuffer, indirectBufferOffset) } @(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBuffer_withRange_") -ComputeCommandEncoder_executeCommandsInBuffer_withRange_ :: proc(self: ^ComputeCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { +ComputeCommandEncoder_executeCommandsInBuffer_withRange_ :: #force_inline proc(self: ^ComputeCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) } @(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithResources") -ComputeCommandEncoder_memoryBarrierWithResources :: proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object) { +ComputeCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object) { msgSend(nil, self, "memoryBarrierWithResources:count:", resources, count) } @(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithScope") -ComputeCommandEncoder_memoryBarrierWithScope :: proc(self: ^ComputeCommandEncoder, scope: BarrierScope) { +ComputeCommandEncoder_memoryBarrierWithScope :: #force_inline proc(self: ^ComputeCommandEncoder, scope: BarrierScope) { msgSend(nil, self, "memoryBarrierWithScope:", scope) } @(objc_type=ComputeCommandEncoder, objc_name="sampleCountersInBuffer") -ComputeCommandEncoder_sampleCountersInBuffer :: proc(self: ^ComputeCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +ComputeCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=ComputeCommandEncoder, objc_name="setAccelerationStructure") -ComputeCommandEncoder_setAccelerationStructure :: proc(self: ^ComputeCommandEncoder, accelerationStructure: ^NS.Object, bufferIndex: ^NS.Object) { +ComputeCommandEncoder_setAccelerationStructure :: #force_inline proc(self: ^ComputeCommandEncoder, accelerationStructure: ^NS.Object, bufferIndex: ^NS.Object) { msgSend(nil, self, "setAccelerationStructure:atBufferIndex:", accelerationStructure, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setBuffer") -ComputeCommandEncoder_setBuffer :: proc(self: ^ComputeCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=ComputeCommandEncoder, objc_name="setBufferOffset") -ComputeCommandEncoder_setBufferOffset :: proc(self: ^ComputeCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setBufferOffset :: #force_inline proc(self: ^ComputeCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setBufferOffset:atIndex:", offset, index) } @(objc_type=ComputeCommandEncoder, objc_name="setBuffers") -ComputeCommandEncoder_setBuffers :: proc(self: ^ComputeCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +ComputeCommandEncoder_setBuffers :: #force_inline proc(self: ^ComputeCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=ComputeCommandEncoder, objc_name="setBytes") -ComputeCommandEncoder_setBytes :: proc(self: ^ComputeCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setBytes :: #force_inline proc(self: ^ComputeCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setBytes:length:atIndex:", bytes, length, index) } @(objc_type=ComputeCommandEncoder, objc_name="setComputePipelineState") -ComputeCommandEncoder_setComputePipelineState :: proc(self: ^ComputeCommandEncoder, pipelineState: ^NS.Object) { +ComputeCommandEncoder_setComputePipelineState :: #force_inline proc(self: ^ComputeCommandEncoder, pipelineState: ^NS.Object) { msgSend(nil, self, "setComputePipelineState:", pipelineState) } @(objc_type=ComputeCommandEncoder, objc_name="setImageblockWidth") -ComputeCommandEncoder_setImageblockWidth :: proc(self: ^ComputeCommandEncoder, width: ^NS.Object, height: ^NS.Object) { +ComputeCommandEncoder_setImageblockWidth :: #force_inline proc(self: ^ComputeCommandEncoder, width: ^NS.Object, height: ^NS.Object) { msgSend(nil, self, "setImageblockWidth:height:", width, height) } @(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTable") -ComputeCommandEncoder_setIntersectionFunctionTable :: proc(self: ^ComputeCommandEncoder, intersectionFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { +ComputeCommandEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { msgSend(nil, self, "setIntersectionFunctionTable:atBufferIndex:", intersectionFunctionTable, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTables") -ComputeCommandEncoder_setIntersectionFunctionTables :: proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { +ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setIntersectionFunctionTables:withBufferRange:", intersectionFunctionTables, range) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_atIndex_") -ComputeCommandEncoder_setSamplerState_atIndex_ :: proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setSamplerState_atIndex_ :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { msgSend(nil, self, "setSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_withRange_") -ComputeCommandEncoder_setSamplerStates_withRange_ :: proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +ComputeCommandEncoder_setSamplerStates_withRange_ :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) } @(objc_type=ComputeCommandEncoder, objc_name="setStageInRegion") -ComputeCommandEncoder_setStageInRegion :: proc(self: ^ComputeCommandEncoder, region: Region) { +ComputeCommandEncoder_setStageInRegion :: #force_inline proc(self: ^ComputeCommandEncoder, region: Region) { msgSend(nil, self, "setStageInRegion:", region) } @(objc_type=ComputeCommandEncoder, objc_name="setStageInRegionWithIndirectBuffer") -ComputeCommandEncoder_setStageInRegionWithIndirectBuffer :: proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +ComputeCommandEncoder_setStageInRegionWithIndirectBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "setStageInRegionWithIndirectBuffer:indirectBufferOffset:", indirectBuffer, indirectBufferOffset) } @(objc_type=ComputeCommandEncoder, objc_name="setTexture") -ComputeCommandEncoder_setTexture :: proc(self: ^ComputeCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setTexture :: #force_inline proc(self: ^ComputeCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setTexture:atIndex:", texture, index) } @(objc_type=ComputeCommandEncoder, objc_name="setTextures") -ComputeCommandEncoder_setTextures :: proc(self: ^ComputeCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +ComputeCommandEncoder_setTextures :: #force_inline proc(self: ^ComputeCommandEncoder, textures: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setTextures:withRange:", textures, range) } @(objc_type=ComputeCommandEncoder, objc_name="setThreadgroupMemoryLength") -ComputeCommandEncoder_setThreadgroupMemoryLength :: proc(self: ^ComputeCommandEncoder, length: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setThreadgroupMemoryLength :: #force_inline proc(self: ^ComputeCommandEncoder, length: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setThreadgroupMemoryLength:atIndex:", length, index) } @(objc_type=ComputeCommandEncoder, objc_name="setVisibleFunctionTable") -ComputeCommandEncoder_setVisibleFunctionTable :: proc(self: ^ComputeCommandEncoder, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { +ComputeCommandEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setVisibleFunctionTables") -ComputeCommandEncoder_setVisibleFunctionTables :: proc(self: ^ComputeCommandEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { +ComputeCommandEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) } @(objc_type=ComputeCommandEncoder, objc_name="updateFence") -ComputeCommandEncoder_updateFence :: proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { +ComputeCommandEncoder_updateFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=ComputeCommandEncoder, objc_name="useHeap") -ComputeCommandEncoder_useHeap :: proc(self: ^ComputeCommandEncoder, heap: ^NS.Object) { +ComputeCommandEncoder_useHeap :: #force_inline proc(self: ^ComputeCommandEncoder, heap: ^NS.Object) { msgSend(nil, self, "useHeap:", heap) } @(objc_type=ComputeCommandEncoder, objc_name="useHeaps") -ComputeCommandEncoder_useHeaps :: proc(self: ^ComputeCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { +ComputeCommandEncoder_useHeaps :: #force_inline proc(self: ^ComputeCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { msgSend(nil, self, "useHeaps:count:", heaps, count) } @(objc_type=ComputeCommandEncoder, objc_name="useResource") -ComputeCommandEncoder_useResource :: proc(self: ^ComputeCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { +ComputeCommandEncoder_useResource :: #force_inline proc(self: ^ComputeCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=ComputeCommandEncoder, objc_name="useResources") -ComputeCommandEncoder_useResources :: proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { +ComputeCommandEncoder_useResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { msgSend(nil, self, "useResources:count:usage:", resources, count, usage) } @(objc_type=ComputeCommandEncoder, objc_name="waitForFence") -ComputeCommandEncoder_waitForFence :: proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { +ComputeCommandEncoder_waitForFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "waitForFence:", fence) } @@ -5803,47 +5789,47 @@ Methods: ComputePipelineState :: struct { using _: NS.Object } @(objc_type=ComputePipelineState, objc_name="device") -ComputePipelineState_device :: proc(self: ^ComputePipelineState) -> ^ComputePipelineState { +ComputePipelineState_device :: #force_inline proc(self: ^ComputePipelineState) -> ^ComputePipelineState { return msgSend(^ComputePipelineState, self, "device") } @(objc_type=ComputePipelineState, objc_name="functionHandleWithFunction") -ComputePipelineState_functionHandleWithFunction :: proc(self: ^ComputePipelineState, function: ^NS.Object) -> ^ComputePipelineState { +ComputePipelineState_functionHandleWithFunction :: #force_inline proc(self: ^ComputePipelineState, function: ^NS.Object) -> ^ComputePipelineState { return msgSend(^ComputePipelineState, self, "functionHandleWithFunction:", function) } @(objc_type=ComputePipelineState, objc_name="imageblockMemoryLengthForDimensions") -ComputePipelineState_imageblockMemoryLengthForDimensions :: proc(self: ^ComputePipelineState, imageblockDimensions: Size) -> ^ComputePipelineState { +ComputePipelineState_imageblockMemoryLengthForDimensions :: #force_inline proc(self: ^ComputePipelineState, imageblockDimensions: Size) -> ^ComputePipelineState { return msgSend(^ComputePipelineState, self, "imageblockMemoryLengthForDimensions:", imageblockDimensions) } @(objc_type=ComputePipelineState, objc_name="label") -ComputePipelineState_label :: proc(self: ^ComputePipelineState) -> ^NS.String { +ComputePipelineState_label :: #force_inline proc(self: ^ComputePipelineState) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=ComputePipelineState, objc_name="maxTotalThreadsPerThreadgroup") -ComputePipelineState_maxTotalThreadsPerThreadgroup :: proc(self: ^ComputePipelineState) -> NS.Integer { +ComputePipelineState_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineState) -> NS.Integer { return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=ComputePipelineState, objc_name="newComputePipelineStateWithAdditionalBinaryFunctions") -ComputePipelineState_newComputePipelineStateWithAdditionalBinaryFunctions :: proc(self: ^ComputePipelineState, functions: ^NS.Array, error: ^^NS.Error ) -> ^ComputePipelineState { +ComputePipelineState_newComputePipelineStateWithAdditionalBinaryFunctions :: #force_inline proc(self: ^ComputePipelineState, functions: ^NS.Array, error: ^^NS.Error ) -> ^ComputePipelineState { return msgSend(^ComputePipelineState, self, "newComputePipelineStateWithAdditionalBinaryFunctions:error:", functions, error) } @(objc_type=ComputePipelineState, objc_name="newIntersectionFunctionTableWithDescriptor") -ComputePipelineState_newIntersectionFunctionTableWithDescriptor :: proc(self: ^ComputePipelineState, descriptor: ^IntersectionFunctionTableDescriptor) -> ^ComputePipelineState { +ComputePipelineState_newIntersectionFunctionTableWithDescriptor :: #force_inline proc(self: ^ComputePipelineState, descriptor: ^IntersectionFunctionTableDescriptor) -> ^ComputePipelineState { return msgSend(^ComputePipelineState, self, "newIntersectionFunctionTableWithDescriptor:", descriptor) } @(objc_type=ComputePipelineState, objc_name="newVisibleFunctionTableWithDescriptor") -ComputePipelineState_newVisibleFunctionTableWithDescriptor :: proc(self: ^ComputePipelineState, descriptor: ^VisibleFunctionTableDescriptor) -> ^ComputePipelineState { +ComputePipelineState_newVisibleFunctionTableWithDescriptor :: #force_inline proc(self: ^ComputePipelineState, descriptor: ^VisibleFunctionTableDescriptor) -> ^ComputePipelineState { return msgSend(^ComputePipelineState, self, "newVisibleFunctionTableWithDescriptor:", descriptor) } @(objc_type=ComputePipelineState, objc_name="staticThreadgroupMemoryLength") -ComputePipelineState_staticThreadgroupMemoryLength :: proc(self: ^ComputePipelineState) -> NS.Integer { +ComputePipelineState_staticThreadgroupMemoryLength :: #force_inline proc(self: ^ComputePipelineState) -> NS.Integer { return msgSend(NS.Integer, self, "staticThreadgroupMemoryLength") } @(objc_type=ComputePipelineState, objc_name="supportIndirectCommandBuffers") -ComputePipelineState_supportIndirectCommandBuffers :: proc(self: ^ComputePipelineState) -> BOOL { +ComputePipelineState_supportIndirectCommandBuffers :: #force_inline proc(self: ^ComputePipelineState) -> BOOL { return msgSend(BOOL, self, "supportIndirectCommandBuffers") } @(objc_type=ComputePipelineState, objc_name="threadExecutionWidth") -ComputePipelineState_threadExecutionWidth :: proc(self: ^ComputePipelineState) -> NS.Integer { +ComputePipelineState_threadExecutionWidth :: #force_inline proc(self: ^ComputePipelineState) -> NS.Integer { return msgSend(NS.Integer, self, "threadExecutionWidth") } @@ -5860,7 +5846,7 @@ Methods: Counter :: struct { using _: NS.Object } @(objc_type=Counter, objc_name="name") -Counter_name :: proc(self: ^Counter) -> ^NS.String { +Counter_name :: #force_inline proc(self: ^Counter) -> ^NS.String { return msgSend(^NS.String, self, "name") } @@ -5880,19 +5866,19 @@ Methods: CounterSampleBuffer :: struct { using _: NS.Object } @(objc_type=CounterSampleBuffer, objc_name="device") -CounterSampleBuffer_device :: proc(self: ^CounterSampleBuffer) -> ^CounterSampleBuffer { +CounterSampleBuffer_device :: #force_inline proc(self: ^CounterSampleBuffer) -> ^CounterSampleBuffer { return msgSend(^CounterSampleBuffer, self, "device") } @(objc_type=CounterSampleBuffer, objc_name="label") -CounterSampleBuffer_label :: proc(self: ^CounterSampleBuffer) -> ^NS.String { +CounterSampleBuffer_label :: #force_inline proc(self: ^CounterSampleBuffer) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CounterSampleBuffer, objc_name="resolveCounterRange") -CounterSampleBuffer_resolveCounterRange :: proc(self: ^CounterSampleBuffer, range: NS.Range) -> ^NS.Data { +CounterSampleBuffer_resolveCounterRange :: #force_inline proc(self: ^CounterSampleBuffer, range: NS.Range) -> ^NS.Data { return msgSend(^NS.Data, self, "resolveCounterRange:", range) } @(objc_type=CounterSampleBuffer, objc_name="sampleCount") -CounterSampleBuffer_sampleCount :: proc(self: ^CounterSampleBuffer) -> NS.Integer { +CounterSampleBuffer_sampleCount :: #force_inline proc(self: ^CounterSampleBuffer) -> NS.Integer { return msgSend(NS.Integer, self, "sampleCount") } @@ -5910,11 +5896,11 @@ Methods: CounterSet :: struct { using _: NS.Object } @(objc_type=CounterSet, objc_name="counters") -CounterSet_counters :: proc(self: ^CounterSet) -> ^NS.Array { +CounterSet_counters :: #force_inline proc(self: ^CounterSet) -> ^NS.Array { return msgSend(^NS.Array, self, "counters") } @(objc_type=CounterSet, objc_name="name") -CounterSet_name :: proc(self: ^CounterSet) -> ^NS.String { +CounterSet_name :: #force_inline proc(self: ^CounterSet) -> ^NS.String { return msgSend(^NS.String, self, "name") } @@ -5932,11 +5918,11 @@ Methods: DepthStencilState :: struct { using _: NS.Object } @(objc_type=DepthStencilState, objc_name="device") -DepthStencilState_device :: proc(self: ^DepthStencilState) -> ^DepthStencilState { +DepthStencilState_device :: #force_inline proc(self: ^DepthStencilState) -> ^DepthStencilState { return msgSend(^DepthStencilState, self, "device") } @(objc_type=DepthStencilState, objc_name="label") -DepthStencilState_label :: proc(self: ^DepthStencilState) -> ^NS.String { +DepthStencilState_label :: #force_inline proc(self: ^DepthStencilState) -> ^NS.String { return msgSend(^NS.String, self, "label") } @@ -6047,383 +6033,383 @@ Methods: Device :: struct { using _: NS.Object } @(objc_type=Device, objc_name="accelerationStructureSizesWithDescriptor") -Device_accelerationStructureSizesWithDescriptor :: proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> AccelerationStructureSizes { +Device_accelerationStructureSizesWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> AccelerationStructureSizes { return msgSend(AccelerationStructureSizes, self, "accelerationStructureSizesWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="areBarycentricCoordsSupported") -Device_areBarycentricCoordsSupported :: proc(self: ^Device) -> BOOL { +Device_areBarycentricCoordsSupported :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "areBarycentricCoordsSupported") } @(objc_type=Device, objc_name="areProgrammableSamplePositionsSupported") -Device_areProgrammableSamplePositionsSupported :: proc(self: ^Device) -> BOOL { +Device_areProgrammableSamplePositionsSupported :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "areProgrammableSamplePositionsSupported") } @(objc_type=Device, objc_name="areRasterOrderGroupsSupported") -Device_areRasterOrderGroupsSupported :: proc(self: ^Device) -> BOOL { +Device_areRasterOrderGroupsSupported :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "areRasterOrderGroupsSupported") } @(objc_type=Device, objc_name="argumentBuffersSupport") -Device_argumentBuffersSupport :: proc(self: ^Device) -> ArgumentBuffersTier { +Device_argumentBuffersSupport :: #force_inline proc(self: ^Device) -> ArgumentBuffersTier { return msgSend(ArgumentBuffersTier, self, "argumentBuffersSupport") } @(objc_type=Device, objc_name="convertSparsePixelRegions") -Device_convertSparsePixelRegions :: proc(self: ^Device, pixelRegions: ^Region, tileRegions: ^Region, tileSize: Size, mode: SparseTextureRegionAlignmentMode, numRegions: ^NS.Object) { +Device_convertSparsePixelRegions :: #force_inline proc(self: ^Device, pixelRegions: ^Region, tileRegions: ^Region, tileSize: Size, mode: SparseTextureRegionAlignmentMode, numRegions: ^NS.Object) { msgSend(nil, self, "convertSparsePixelRegions:toTileRegions:withTileSize:alignmentMode:numRegions:", pixelRegions, tileRegions, tileSize, mode, numRegions) } @(objc_type=Device, objc_name="convertSparseTileRegions") -Device_convertSparseTileRegions :: proc(self: ^Device, tileRegions: ^Region, pixelRegions: ^Region, tileSize: Size, numRegions: ^NS.Object) { +Device_convertSparseTileRegions :: #force_inline proc(self: ^Device, tileRegions: ^Region, pixelRegions: ^Region, tileSize: Size, numRegions: ^NS.Object) { msgSend(nil, self, "convertSparseTileRegions:toPixelRegions:withTileSize:numRegions:", tileRegions, pixelRegions, tileSize, numRegions) } @(objc_type=Device, objc_name="counterSets") -Device_counterSets :: proc(self: ^Device) -> ^NS.Array { +Device_counterSets :: #force_inline proc(self: ^Device) -> ^NS.Array { return msgSend(^NS.Array, self, "counterSets") } @(objc_type=Device, objc_name="currentAllocatedSize") -Device_currentAllocatedSize :: proc(self: ^Device) -> NS.Integer { +Device_currentAllocatedSize :: #force_inline proc(self: ^Device) -> NS.Integer { return msgSend(NS.Integer, self, "currentAllocatedSize") } @(objc_type=Device, objc_name="getDefaultSamplePositions") -Device_getDefaultSamplePositions :: proc(self: ^Device, positions: ^SamplePosition, count: ^NS.Object) { +Device_getDefaultSamplePositions :: #force_inline proc(self: ^Device, positions: ^SamplePosition, count: ^NS.Object) { msgSend(nil, self, "getDefaultSamplePositions:count:", positions, count) } @(objc_type=Device, objc_name="hasUnifiedMemory") -Device_hasUnifiedMemory :: proc(self: ^Device) -> BOOL { +Device_hasUnifiedMemory :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "hasUnifiedMemory") } @(objc_type=Device, objc_name="heapBufferSizeAndAlignWithLength") -Device_heapBufferSizeAndAlignWithLength :: proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> SizeAndAlign { +Device_heapBufferSizeAndAlignWithLength :: #force_inline proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> SizeAndAlign { return msgSend(SizeAndAlign, self, "heapBufferSizeAndAlignWithLength:options:", length, options) } @(objc_type=Device, objc_name="heapTextureSizeAndAlignWithDescriptor") -Device_heapTextureSizeAndAlignWithDescriptor :: proc(self: ^Device, desc: ^TextureDescriptor) -> SizeAndAlign { +Device_heapTextureSizeAndAlignWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> SizeAndAlign { return msgSend(SizeAndAlign, self, "heapTextureSizeAndAlignWithDescriptor:", desc) } @(objc_type=Device, objc_name="isDepth24Stencil8PixelFormatSupported") -Device_isDepth24Stencil8PixelFormatSupported :: proc(self: ^Device) -> BOOL { +Device_isDepth24Stencil8PixelFormatSupported :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "isDepth24Stencil8PixelFormatSupported") } @(objc_type=Device, objc_name="isHeadless") -Device_isHeadless :: proc(self: ^Device) -> BOOL { +Device_isHeadless :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "isHeadless") } @(objc_type=Device, objc_name="isLowPower") -Device_isLowPower :: proc(self: ^Device) -> BOOL { +Device_isLowPower :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "isLowPower") } @(objc_type=Device, objc_name="isRemovable") -Device_isRemovable :: proc(self: ^Device) -> BOOL { +Device_isRemovable :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "isRemovable") } @(objc_type=Device, objc_name="location") -Device_location :: proc(self: ^Device) -> DeviceLocation { +Device_location :: #force_inline proc(self: ^Device) -> DeviceLocation { return msgSend(DeviceLocation, self, "location") } @(objc_type=Device, objc_name="locationNumber") -Device_locationNumber :: proc(self: ^Device) -> NS.Integer { +Device_locationNumber :: #force_inline proc(self: ^Device) -> NS.Integer { return msgSend(NS.Integer, self, "locationNumber") } @(objc_type=Device, objc_name="maxArgumentBufferSamplerCount") -Device_maxArgumentBufferSamplerCount :: proc(self: ^Device) -> NS.Integer { +Device_maxArgumentBufferSamplerCount :: #force_inline proc(self: ^Device) -> NS.Integer { return msgSend(NS.Integer, self, "maxArgumentBufferSamplerCount") } @(objc_type=Device, objc_name="maxBufferLength") -Device_maxBufferLength :: proc(self: ^Device) -> NS.Integer { +Device_maxBufferLength :: #force_inline proc(self: ^Device) -> NS.Integer { return msgSend(NS.Integer, self, "maxBufferLength") } @(objc_type=Device, objc_name="maxThreadgroupMemoryLength") -Device_maxThreadgroupMemoryLength :: proc(self: ^Device) -> NS.Integer { +Device_maxThreadgroupMemoryLength :: #force_inline proc(self: ^Device) -> NS.Integer { return msgSend(NS.Integer, self, "maxThreadgroupMemoryLength") } @(objc_type=Device, objc_name="maxThreadsPerThreadgroup") -Device_maxThreadsPerThreadgroup :: proc(self: ^Device) -> Size { +Device_maxThreadsPerThreadgroup :: #force_inline proc(self: ^Device) -> Size { return msgSend(Size, self, "maxThreadsPerThreadgroup") } @(objc_type=Device, objc_name="maxTransferRate") -Device_maxTransferRate :: proc(self: ^Device) -> u64 { +Device_maxTransferRate :: #force_inline proc(self: ^Device) -> u64 { return msgSend(u64, self, "maxTransferRate") } @(objc_type=Device, objc_name="minimumLinearTextureAlignmentForPixelFormat") -Device_minimumLinearTextureAlignmentForPixelFormat :: proc(self: ^Device, format: PixelFormat) -> ^Device { +Device_minimumLinearTextureAlignmentForPixelFormat :: #force_inline proc(self: ^Device, format: PixelFormat) -> ^Device { return msgSend(^Device, self, "minimumLinearTextureAlignmentForPixelFormat:", format) } @(objc_type=Device, objc_name="minimumTextureBufferAlignmentForPixelFormat") -Device_minimumTextureBufferAlignmentForPixelFormat :: proc(self: ^Device, format: PixelFormat) -> ^Device { +Device_minimumTextureBufferAlignmentForPixelFormat :: #force_inline proc(self: ^Device, format: PixelFormat) -> ^Device { return msgSend(^Device, self, "minimumTextureBufferAlignmentForPixelFormat:", format) } @(objc_type=Device, objc_name="name") -Device_name :: proc(self: ^Device) -> ^NS.String { +Device_name :: #force_inline proc(self: ^Device) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=Device, objc_name="newAccelerationStructureWithDescriptor") -Device_newAccelerationStructureWithDescriptor :: proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> ^Device { +Device_newAccelerationStructureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> ^Device { return msgSend(^Device, self, "newAccelerationStructureWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newAccelerationStructureWithSize") -Device_newAccelerationStructureWithSize :: proc(self: ^Device, size: ^NS.Object) -> ^Device { +Device_newAccelerationStructureWithSize :: #force_inline proc(self: ^Device, size: ^NS.Object) -> ^Device { return msgSend(^Device, self, "newAccelerationStructureWithSize:", size) } @(objc_type=Device, objc_name="newArgumentEncoderWithArguments") -Device_newArgumentEncoderWithArguments :: proc(self: ^Device, arguments: ^NS.Array) -> ^Device { +Device_newArgumentEncoderWithArguments :: #force_inline proc(self: ^Device, arguments: ^NS.Array) -> ^Device { return msgSend(^Device, self, "newArgumentEncoderWithArguments:", arguments) } @(objc_type=Device, objc_name="newBinaryArchiveWithDescriptor") -Device_newBinaryArchiveWithDescriptor :: proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor, error: ^^NS.Error ) -> ^Device { +Device_newBinaryArchiveWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newBinaryArchiveWithDescriptor:error:", descriptor, error) } @(objc_type=Device, objc_name="newBufferWithBytes") -Device_newBufferWithBytes :: proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions) -> ^Device { +Device_newBufferWithBytes :: #force_inline proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions) -> ^Device { return msgSend(^Device, self, "newBufferWithBytes:length:options:", pointer, length, options) } @(objc_type=Device, objc_name="newBufferWithBytesNoCopy") -Device_newBufferWithBytesNoCopy :: proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions, deallocator: rawptr) -> ^Device { +Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions, deallocator: rawptr) -> ^Device { return msgSend(^Device, self, "newBufferWithBytesNoCopy:length:options:deallocator:", pointer, length, options, deallocator) } @(objc_type=Device, objc_name="newBufferWithLength") -Device_newBufferWithLength :: proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> ^Device { +Device_newBufferWithLength :: #force_inline proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> ^Device { return msgSend(^Device, self, "newBufferWithLength:options:", length, options) } @(objc_type=Device, objc_name="newCommandQueue") -Device_newCommandQueue :: proc(self: ^Device) -> ^Device { +Device_newCommandQueue :: #force_inline proc(self: ^Device) -> ^Device { return msgSend(^Device, self, "newCommandQueue") } @(objc_type=Device, objc_name="newCommandQueueWithMaxCommandBufferCount") -Device_newCommandQueueWithMaxCommandBufferCount :: proc(self: ^Device, maxCommandBufferCount: ^NS.Object) -> ^Device { +Device_newCommandQueueWithMaxCommandBufferCount :: #force_inline proc(self: ^Device, maxCommandBufferCount: ^NS.Object) -> ^Device { return msgSend(^Device, self, "newCommandQueueWithMaxCommandBufferCount:", maxCommandBufferCount) } @(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_completionHandler_") -Device_newComputePipelineStateWithDescriptor_options_completionHandler_ :: proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { +Device_newComputePipelineStateWithDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_reflection_error_") -Device_newComputePipelineStateWithDescriptor_options_reflection_error_ :: proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { +Device_newComputePipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newComputePipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, error) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_completionHandler_") -Device_newComputePipelineStateWithFunction_completionHandler_ :: proc(self: ^Device, computeFunction: ^NS.Object, completionHandler: NewComputePipelineStateCompletionHandler) { +Device_newComputePipelineStateWithFunction_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, completionHandler: NewComputePipelineStateCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithFunction:completionHandler:", computeFunction, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_error_") -Device_newComputePipelineStateWithFunction_error_ :: proc(self: ^Device, computeFunction: ^NS.Object, error: ^^NS.Error ) -> ^Device { +Device_newComputePipelineStateWithFunction_error_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, error) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_completionHandler_") -Device_newComputePipelineStateWithFunction_options_completionHandler_ :: proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { +Device_newComputePipelineStateWithFunction_options_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithFunction:options:completionHandler:", computeFunction, options, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_reflection_error_") -Device_newComputePipelineStateWithFunction_options_reflection_error_ :: proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { +Device_newComputePipelineStateWithFunction_options_reflection_error_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, error) } @(objc_type=Device, objc_name="newCounterSampleBufferWithDescriptor") -Device_newCounterSampleBufferWithDescriptor :: proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor, error: ^^NS.Error ) -> ^Device { +Device_newCounterSampleBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, error) } @(objc_type=Device, objc_name="newDefaultLibrary") -Device_newDefaultLibrary :: proc(self: ^Device) -> ^Device { +Device_newDefaultLibrary :: #force_inline proc(self: ^Device) -> ^Device { return msgSend(^Device, self, "newDefaultLibrary") } @(objc_type=Device, objc_name="newDefaultLibraryWithBundle") -Device_newDefaultLibraryWithBundle :: proc(self: ^Device, bundle: ^NS.Bundle, error: ^^NS.Error ) -> ^Device { +Device_newDefaultLibraryWithBundle :: #force_inline proc(self: ^Device, bundle: ^NS.Bundle, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newDefaultLibraryWithBundle:error:", bundle, error) } @(objc_type=Device, objc_name="newDepthStencilStateWithDescriptor") -Device_newDepthStencilStateWithDescriptor :: proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^Device { +Device_newDepthStencilStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^Device { return msgSend(^Device, self, "newDepthStencilStateWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newDynamicLibrary") -Device_newDynamicLibrary :: proc(self: ^Device, library: ^NS.Object, error: ^^NS.Error ) -> ^Device { +Device_newDynamicLibrary :: #force_inline proc(self: ^Device, library: ^NS.Object, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newDynamicLibrary:error:", library, error) } @(objc_type=Device, objc_name="newDynamicLibraryWithURL") -Device_newDynamicLibraryWithURL :: proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { +Device_newDynamicLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newDynamicLibraryWithURL:error:", url, error) } @(objc_type=Device, objc_name="newEvent") -Device_newEvent :: proc(self: ^Device) -> ^Device { +Device_newEvent :: #force_inline proc(self: ^Device) -> ^Device { return msgSend(^Device, self, "newEvent") } @(objc_type=Device, objc_name="newFence") -Device_newFence :: proc(self: ^Device) -> ^Device { +Device_newFence :: #force_inline proc(self: ^Device) -> ^Device { return msgSend(^Device, self, "newFence") } @(objc_type=Device, objc_name="newHeapWithDescriptor") -Device_newHeapWithDescriptor :: proc(self: ^Device, descriptor: ^HeapDescriptor) -> ^Device { +Device_newHeapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^HeapDescriptor) -> ^Device { return msgSend(^Device, self, "newHeapWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newIndirectCommandBufferWithDescriptor") -Device_newIndirectCommandBufferWithDescriptor :: proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: ^NS.Object, options: ResourceOptions) -> ^Device { +Device_newIndirectCommandBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: ^NS.Object, options: ResourceOptions) -> ^Device { return msgSend(^Device, self, "newIndirectCommandBufferWithDescriptor:maxCommandCount:options:", descriptor, maxCount, options) } @(objc_type=Device, objc_name="newLibraryWithData") -Device_newLibraryWithData :: proc(self: ^Device, data: ^NS.Object, error: ^^NS.Error ) -> ^Device { +Device_newLibraryWithData :: #force_inline proc(self: ^Device, data: ^NS.Object, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newLibraryWithData:error:", data, error) } @(objc_type=Device, objc_name="newLibraryWithFile") -Device_newLibraryWithFile :: proc(self: ^Device, filepath: ^NS.String, error: ^^NS.Error ) -> ^Device { +Device_newLibraryWithFile :: #force_inline proc(self: ^Device, filepath: ^NS.String, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newLibraryWithFile:error:", filepath, error) } @(objc_type=Device, objc_name="newLibraryWithSource_options_completionHandler_") -Device_newLibraryWithSource_options_completionHandler_ :: proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) { +Device_newLibraryWithSource_options_completionHandler_ :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) { msgSend(nil, self, "newLibraryWithSource:options:completionHandler:", source, options, completionHandler) } @(objc_type=Device, objc_name="newLibraryWithSource_options_error_") -Device_newLibraryWithSource_options_error_ :: proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, error: ^^NS.Error ) -> ^Device { +Device_newLibraryWithSource_options_error_ :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newLibraryWithSource:options:error:", source, options, error) } @(objc_type=Device, objc_name="newLibraryWithURL") -Device_newLibraryWithURL :: proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { +Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newLibraryWithURL:error:", url, error) } @(objc_type=Device, objc_name="newRasterizationRateMapWithDescriptor") -Device_newRasterizationRateMapWithDescriptor :: proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^Device { +Device_newRasterizationRateMapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^Device { return msgSend(^Device, self, "newRasterizationRateMapWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_completionHandler_") -Device_newRenderPipelineStateWithDescriptor_completionHandler_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { +Device_newRenderPipelineStateWithDescriptor_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_error_") -Device_newRenderPipelineStateWithDescriptor_error_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> ^Device { +Device_newRenderPipelineStateWithDescriptor_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, error) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_completionHandler_") -Device_newRenderPipelineStateWithDescriptor_options_completionHandler_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { +Device_newRenderPipelineStateWithDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_reflection_error_") -Device_newRenderPipelineStateWithDescriptor_options_reflection_error_ :: proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { +Device_newRenderPipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, error) } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_completionHandler_") -Device_newRenderPipelineStateWithTileDescriptor_options_completionHandler_ :: proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { +Device_newRenderPipelineStateWithTileDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithTileDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_reflection_error_") -Device_newRenderPipelineStateWithTileDescriptor_options_reflection_error_ :: proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { +Device_newRenderPipelineStateWithTileDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { return msgSend(^Device, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, error) } @(objc_type=Device, objc_name="newSamplerStateWithDescriptor") -Device_newSamplerStateWithDescriptor :: proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^Device { +Device_newSamplerStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^Device { return msgSend(^Device, self, "newSamplerStateWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newSharedEvent") -Device_newSharedEvent :: proc(self: ^Device) -> ^Device { +Device_newSharedEvent :: #force_inline proc(self: ^Device) -> ^Device { return msgSend(^Device, self, "newSharedEvent") } @(objc_type=Device, objc_name="newSharedEventWithHandle") -Device_newSharedEventWithHandle :: proc(self: ^Device, sharedEventHandle: ^SharedEventHandle) -> ^Device { +Device_newSharedEventWithHandle :: #force_inline proc(self: ^Device, sharedEventHandle: ^SharedEventHandle) -> ^Device { return msgSend(^Device, self, "newSharedEventWithHandle:", sharedEventHandle) } @(objc_type=Device, objc_name="newSharedTextureWithDescriptor") -Device_newSharedTextureWithDescriptor :: proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^Device { +Device_newSharedTextureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^Device { return msgSend(^Device, self, "newSharedTextureWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newSharedTextureWithHandle") -Device_newSharedTextureWithHandle :: proc(self: ^Device, sharedHandle: ^SharedTextureHandle) -> ^Device { +Device_newSharedTextureWithHandle :: #force_inline proc(self: ^Device, sharedHandle: ^SharedTextureHandle) -> ^Device { return msgSend(^Device, self, "newSharedTextureWithHandle:", sharedHandle) } @(objc_type=Device, objc_name="newTextureWithDescriptor") -Device_newTextureWithDescriptor :: proc(self: ^Device, desc: ^TextureDescriptor) -> ^Device { +Device_newTextureWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^Device { return msgSend(^Device, self, "newTextureWithDescriptor:", desc) } @(objc_type=Device, objc_name="newTextureWithDescriptor_iosurface_plane_") -Device_newTextureWithDescriptor_iosurface_plane_ :: proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: ^NS.Object) -> ^Device { +Device_newTextureWithDescriptor_iosurface_plane_ :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: ^NS.Object) -> ^Device { return msgSend(^Device, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) } @(objc_type=Device, objc_name="peerCount") -Device_peerCount :: proc(self: ^Device) -> u32 { +Device_peerCount :: #force_inline proc(self: ^Device) -> u32 { return msgSend(u32, self, "peerCount") } @(objc_type=Device, objc_name="peerGroupID") -Device_peerGroupID :: proc(self: ^Device) -> u64 { +Device_peerGroupID :: #force_inline proc(self: ^Device) -> u64 { return msgSend(u64, self, "peerGroupID") } @(objc_type=Device, objc_name="peerIndex") -Device_peerIndex :: proc(self: ^Device) -> u32 { +Device_peerIndex :: #force_inline proc(self: ^Device) -> u32 { return msgSend(u32, self, "peerIndex") } @(objc_type=Device, objc_name="readWriteTextureSupport") -Device_readWriteTextureSupport :: proc(self: ^Device) -> ReadWriteTextureTier { +Device_readWriteTextureSupport :: #force_inline proc(self: ^Device) -> ReadWriteTextureTier { return msgSend(ReadWriteTextureTier, self, "readWriteTextureSupport") } @(objc_type=Device, objc_name="recommendedMaxWorkingSetSize") -Device_recommendedMaxWorkingSetSize :: proc(self: ^Device) -> u64 { +Device_recommendedMaxWorkingSetSize :: #force_inline proc(self: ^Device) -> u64 { return msgSend(u64, self, "recommendedMaxWorkingSetSize") } @(objc_type=Device, objc_name="registryID") -Device_registryID :: proc(self: ^Device) -> u64 { +Device_registryID :: #force_inline proc(self: ^Device) -> u64 { return msgSend(u64, self, "registryID") } @(objc_type=Device, objc_name="sampleTimestamps") -Device_sampleTimestamps :: proc(self: ^Device, cpuTimestamp: ^Timestamp, gpuTimestamp: ^Timestamp) { +Device_sampleTimestamps :: #force_inline proc(self: ^Device, cpuTimestamp: ^Timestamp, gpuTimestamp: ^Timestamp) { msgSend(nil, self, "sampleTimestamps:gpuTimestamp:", cpuTimestamp, gpuTimestamp) } @(objc_type=Device, objc_name="sparseTileSizeInBytes") -Device_sparseTileSizeInBytes :: proc(self: ^Device) -> NS.Integer { +Device_sparseTileSizeInBytes :: #force_inline proc(self: ^Device) -> NS.Integer { return msgSend(NS.Integer, self, "sparseTileSizeInBytes") } @(objc_type=Device, objc_name="sparseTileSizeWithTextureType") -Device_sparseTileSizeWithTextureType :: proc(self: ^Device, textureType: TextureType, pixelFormat: PixelFormat, sampleCount: ^NS.Object) -> Size { +Device_sparseTileSizeWithTextureType :: #force_inline proc(self: ^Device, textureType: TextureType, pixelFormat: PixelFormat, sampleCount: ^NS.Object) -> Size { return msgSend(Size, self, "sparseTileSizeWithTextureType:pixelFormat:sampleCount:", textureType, pixelFormat, sampleCount) } @(objc_type=Device, objc_name="supports32BitFloatFiltering") -Device_supports32BitFloatFiltering :: proc(self: ^Device) -> BOOL { +Device_supports32BitFloatFiltering :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supports32BitFloatFiltering") } @(objc_type=Device, objc_name="supports32BitMSAA") -Device_supports32BitMSAA :: proc(self: ^Device) -> BOOL { +Device_supports32BitMSAA :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supports32BitMSAA") } @(objc_type=Device, objc_name="supportsBCTextureCompression") -Device_supportsBCTextureCompression :: proc(self: ^Device) -> BOOL { +Device_supportsBCTextureCompression :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsBCTextureCompression") } @(objc_type=Device, objc_name="supportsCounterSampling") -Device_supportsCounterSampling :: proc(self: ^Device, samplingPoint: CounterSamplingPoint) -> BOOL { +Device_supportsCounterSampling :: #force_inline proc(self: ^Device, samplingPoint: CounterSamplingPoint) -> BOOL { return msgSend(BOOL, self, "supportsCounterSampling:", samplingPoint) } @(objc_type=Device, objc_name="supportsDynamicLibraries") -Device_supportsDynamicLibraries :: proc(self: ^Device) -> BOOL { +Device_supportsDynamicLibraries :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsDynamicLibraries") } @(objc_type=Device, objc_name="supportsFamily") -Device_supportsFamily :: proc(self: ^Device, gpuFamily: GPUFamily) -> BOOL { +Device_supportsFamily :: #force_inline proc(self: ^Device, gpuFamily: GPUFamily) -> BOOL { return msgSend(BOOL, self, "supportsFamily:", gpuFamily) } @(objc_type=Device, objc_name="supportsFeatureSet") -Device_supportsFeatureSet :: proc(self: ^Device, featureSet: FeatureSet) -> BOOL { +Device_supportsFeatureSet :: #force_inline proc(self: ^Device, featureSet: FeatureSet) -> BOOL { return msgSend(BOOL, self, "supportsFeatureSet:", featureSet) } @(objc_type=Device, objc_name="supportsFunctionPointers") -Device_supportsFunctionPointers :: proc(self: ^Device) -> BOOL { +Device_supportsFunctionPointers :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsFunctionPointers") } @(objc_type=Device, objc_name="supportsPullModelInterpolation") -Device_supportsPullModelInterpolation :: proc(self: ^Device) -> BOOL { +Device_supportsPullModelInterpolation :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsPullModelInterpolation") } @(objc_type=Device, objc_name="supportsQueryTextureLOD") -Device_supportsQueryTextureLOD :: proc(self: ^Device) -> BOOL { +Device_supportsQueryTextureLOD :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsQueryTextureLOD") } @(objc_type=Device, objc_name="supportsRasterizationRateMapWithLayerCount") -Device_supportsRasterizationRateMapWithLayerCount :: proc(self: ^Device, layerCount: ^NS.Object) -> BOOL { +Device_supportsRasterizationRateMapWithLayerCount :: #force_inline proc(self: ^Device, layerCount: ^NS.Object) -> BOOL { return msgSend(BOOL, self, "supportsRasterizationRateMapWithLayerCount:", layerCount) } @(objc_type=Device, objc_name="supportsRaytracing") -Device_supportsRaytracing :: proc(self: ^Device) -> BOOL { +Device_supportsRaytracing :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsRaytracing") } @(objc_type=Device, objc_name="supportsShaderBarycentricCoordinates") -Device_supportsShaderBarycentricCoordinates :: proc(self: ^Device) -> BOOL { +Device_supportsShaderBarycentricCoordinates :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsShaderBarycentricCoordinates") } @(objc_type=Device, objc_name="supportsTextureSampleCount") -Device_supportsTextureSampleCount :: proc(self: ^Device, sampleCount: ^NS.Object) -> BOOL { +Device_supportsTextureSampleCount :: #force_inline proc(self: ^Device, sampleCount: ^NS.Object) -> BOOL { return msgSend(BOOL, self, "supportsTextureSampleCount:", sampleCount) } @(objc_type=Device, objc_name="supportsVertexAmplificationCount") -Device_supportsVertexAmplificationCount :: proc(self: ^Device, count: ^NS.Object) -> BOOL { +Device_supportsVertexAmplificationCount :: #force_inline proc(self: ^Device, count: ^NS.Object) -> BOOL { return msgSend(BOOL, self, "supportsVertexAmplificationCount:", count) } @@ -6445,27 +6431,27 @@ Methods: Drawable :: struct { using _: NS.Object } @(objc_type=Drawable, objc_name="addPresentedHandler") -Drawable_addPresentedHandler :: proc(self: ^Drawable, block: DrawablePresentedHandler) { +Drawable_addPresentedHandler :: #force_inline proc(self: ^Drawable, block: DrawablePresentedHandler) { msgSend(nil, self, "addPresentedHandler:", block) } @(objc_type=Drawable, objc_name="drawableID") -Drawable_drawableID :: proc(self: ^Drawable) -> NS.Integer { +Drawable_drawableID :: #force_inline proc(self: ^Drawable) -> NS.Integer { return msgSend(NS.Integer, self, "drawableID") } @(objc_type=Drawable, objc_name="present") -Drawable_present :: proc(self: ^Drawable) { +Drawable_present :: #force_inline proc(self: ^Drawable) { msgSend(nil, self, "present") } @(objc_type=Drawable, objc_name="presentAfterMinimumDuration") -Drawable_presentAfterMinimumDuration :: proc(self: ^Drawable, duration: CFTimeInterval) { +Drawable_presentAfterMinimumDuration :: #force_inline proc(self: ^Drawable, duration: CFTimeInterval) { msgSend(nil, self, "presentAfterMinimumDuration:", duration) } @(objc_type=Drawable, objc_name="presentAtTime") -Drawable_presentAtTime :: proc(self: ^Drawable, presentationTime: CFTimeInterval) { +Drawable_presentAtTime :: #force_inline proc(self: ^Drawable, presentationTime: CFTimeInterval) { msgSend(nil, self, "presentAtTime:", presentationTime) } @(objc_type=Drawable, objc_name="presentedTime") -Drawable_presentedTime :: proc(self: ^Drawable) -> CFTimeInterval { +Drawable_presentedTime :: #force_inline proc(self: ^Drawable) -> CFTimeInterval { return msgSend(CFTimeInterval, self, "presentedTime") } @@ -6486,23 +6472,23 @@ Methods: DynamicLibrary :: struct { using _: NS.Object } @(objc_type=DynamicLibrary, objc_name="device") -DynamicLibrary_device :: proc(self: ^DynamicLibrary) -> ^DynamicLibrary { +DynamicLibrary_device :: #force_inline proc(self: ^DynamicLibrary) -> ^DynamicLibrary { return msgSend(^DynamicLibrary, self, "device") } @(objc_type=DynamicLibrary, objc_name="installName") -DynamicLibrary_installName :: proc(self: ^DynamicLibrary) -> ^NS.String { +DynamicLibrary_installName :: #force_inline proc(self: ^DynamicLibrary) -> ^NS.String { return msgSend(^NS.String, self, "installName") } @(objc_type=DynamicLibrary, objc_name="label") -DynamicLibrary_label :: proc(self: ^DynamicLibrary) -> ^NS.String { +DynamicLibrary_label :: #force_inline proc(self: ^DynamicLibrary) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=DynamicLibrary, objc_name="serializeToURL") -DynamicLibrary_serializeToURL :: proc(self: ^DynamicLibrary, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { +DynamicLibrary_serializeToURL :: #force_inline proc(self: ^DynamicLibrary, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { return msgSend(BOOL, self, "serializeToURL:error:", url, error) } @(objc_type=DynamicLibrary, objc_name="setLabel") -DynamicLibrary_setLabel :: proc(self: ^DynamicLibrary, label: ^NS.String) { +DynamicLibrary_setLabel :: #force_inline proc(self: ^DynamicLibrary, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -6521,15 +6507,15 @@ Methods: Event :: struct { using _: NS.Object } @(objc_type=Event, objc_name="device") -Event_device :: proc(self: ^Event) -> ^Event { +Event_device :: #force_inline proc(self: ^Event) -> ^Event { return msgSend(^Event, self, "device") } @(objc_type=Event, objc_name="label") -Event_label :: proc(self: ^Event) -> ^NS.String { +Event_label :: #force_inline proc(self: ^Event) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Event, objc_name="setLabel") -Event_setLabel :: proc(self: ^Event, label: ^NS.String) { +Event_setLabel :: #force_inline proc(self: ^Event, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -6548,15 +6534,15 @@ Methods: Fence :: struct { using _: NS.Object } @(objc_type=Fence, objc_name="device") -Fence_device :: proc(self: ^Fence) -> ^Fence { +Fence_device :: #force_inline proc(self: ^Fence) -> ^Fence { return msgSend(^Fence, self, "device") } @(objc_type=Fence, objc_name="label") -Fence_label :: proc(self: ^Fence) -> ^NS.String { +Fence_label :: #force_inline proc(self: ^Fence) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Fence, objc_name="setLabel") -Fence_setLabel :: proc(self: ^Fence, label: ^NS.String) { +Fence_setLabel :: #force_inline proc(self: ^Fence, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @@ -6585,55 +6571,55 @@ Methods: Function :: struct { using _: NS.Object } @(objc_type=Function, objc_name="device") -Function_device :: proc(self: ^Function) -> ^Function { +Function_device :: #force_inline proc(self: ^Function) -> ^Function { return msgSend(^Function, self, "device") } @(objc_type=Function, objc_name="functionConstantsDictionary") -Function_functionConstantsDictionary :: proc(self: ^Function) -> ^NS.Dictionary { +Function_functionConstantsDictionary :: #force_inline proc(self: ^Function) -> ^NS.Dictionary { return msgSend(^NS.Dictionary, self, "functionConstantsDictionary") } @(objc_type=Function, objc_name="functionType") -Function_functionType :: proc(self: ^Function) -> FunctionType { +Function_functionType :: #force_inline proc(self: ^Function) -> FunctionType { return msgSend(FunctionType, self, "functionType") } @(objc_type=Function, objc_name="label") -Function_label :: proc(self: ^Function) -> ^NS.String { +Function_label :: #force_inline proc(self: ^Function) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Function, objc_name="name") -Function_name :: proc(self: ^Function) -> ^NS.String { +Function_name :: #force_inline proc(self: ^Function) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex") -Function_newArgumentEncoderWithBufferIndex :: proc(self: ^Function, bufferIndex: ^NS.Object) -> ^Function { +Function_newArgumentEncoderWithBufferIndex :: #force_inline proc(self: ^Function, bufferIndex: ^NS.Object) -> ^Function { return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:", bufferIndex) } @(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex_reflection_") -Function_newArgumentEncoderWithBufferIndex_reflection_ :: proc(self: ^Function, bufferIndex: ^NS.Object, reflection: ^AutoreleasedArgument) -> ^Function { +Function_newArgumentEncoderWithBufferIndex_reflection_ :: #force_inline proc(self: ^Function, bufferIndex: ^NS.Object, reflection: ^AutoreleasedArgument) -> ^Function { return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:reflection:", bufferIndex, reflection) } @(objc_type=Function, objc_name="options") -Function_options :: proc(self: ^Function) -> FunctionOptions { +Function_options :: #force_inline proc(self: ^Function) -> FunctionOptions { return msgSend(FunctionOptions, self, "options") } @(objc_type=Function, objc_name="patchControlPointCount") -Function_patchControlPointCount :: proc(self: ^Function) -> NS.Integer { +Function_patchControlPointCount :: #force_inline proc(self: ^Function) -> NS.Integer { return msgSend(NS.Integer, self, "patchControlPointCount") } @(objc_type=Function, objc_name="patchType") -Function_patchType :: proc(self: ^Function) -> PatchType { +Function_patchType :: #force_inline proc(self: ^Function) -> PatchType { return msgSend(PatchType, self, "patchType") } @(objc_type=Function, objc_name="setLabel") -Function_setLabel :: proc(self: ^Function, label: ^NS.String) { +Function_setLabel :: #force_inline proc(self: ^Function, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=Function, objc_name="stageInputAttributes") -Function_stageInputAttributes :: proc(self: ^Function) -> ^NS.Array { +Function_stageInputAttributes :: #force_inline proc(self: ^Function) -> ^NS.Array { return msgSend(^NS.Array, self, "stageInputAttributes") } @(objc_type=Function, objc_name="vertexAttributes") -Function_vertexAttributes :: proc(self: ^Function) -> ^NS.Array { +Function_vertexAttributes :: #force_inline proc(self: ^Function) -> ^NS.Array { return msgSend(^NS.Array, self, "vertexAttributes") } @@ -6652,15 +6638,15 @@ Methods: FunctionHandle :: struct { using _: NS.Object } @(objc_type=FunctionHandle, objc_name="device") -FunctionHandle_device :: proc(self: ^FunctionHandle) -> ^FunctionHandle { +FunctionHandle_device :: #force_inline proc(self: ^FunctionHandle) -> ^FunctionHandle { return msgSend(^FunctionHandle, self, "device") } @(objc_type=FunctionHandle, objc_name="functionType") -FunctionHandle_functionType :: proc(self: ^FunctionHandle) -> FunctionType { +FunctionHandle_functionType :: #force_inline proc(self: ^FunctionHandle) -> FunctionType { return msgSend(FunctionType, self, "functionType") } @(objc_type=FunctionHandle, objc_name="name") -FunctionHandle_name :: proc(self: ^FunctionHandle) -> ^NS.String { +FunctionHandle_name :: #force_inline proc(self: ^FunctionHandle) -> ^NS.String { return msgSend(^NS.String, self, "name") } @@ -6680,19 +6666,19 @@ Methods: FunctionLog :: struct { using _: NS.Object } @(objc_type=FunctionLog, objc_name="debugLocation") -FunctionLog_debugLocation :: proc(self: ^FunctionLog) -> ^FunctionLog { +FunctionLog_debugLocation :: #force_inline proc(self: ^FunctionLog) -> ^FunctionLog { return msgSend(^FunctionLog, self, "debugLocation") } @(objc_type=FunctionLog, objc_name="encoderLabel") -FunctionLog_encoderLabel :: proc(self: ^FunctionLog) -> ^NS.String { +FunctionLog_encoderLabel :: #force_inline proc(self: ^FunctionLog) -> ^NS.String { return msgSend(^NS.String, self, "encoderLabel") } @(objc_type=FunctionLog, objc_name="function") -FunctionLog_function :: proc(self: ^FunctionLog) -> ^FunctionLog { +FunctionLog_function :: #force_inline proc(self: ^FunctionLog) -> ^FunctionLog { return msgSend(^FunctionLog, self, "function") } @(objc_type=FunctionLog, objc_name="type") -FunctionLog_type :: proc(self: ^FunctionLog) -> FunctionLogType { +FunctionLog_type :: #force_inline proc(self: ^FunctionLog) -> FunctionLogType { return msgSend(FunctionLogType, self, "type") } @@ -6712,19 +6698,19 @@ Methods: FunctionLogDebugLocation :: struct { using _: NS.Object } @(objc_type=FunctionLogDebugLocation, objc_name="URL") -FunctionLogDebugLocation_URL :: proc(self: ^FunctionLogDebugLocation) -> ^NS.URL { +FunctionLogDebugLocation_URL :: #force_inline proc(self: ^FunctionLogDebugLocation) -> ^NS.URL { return msgSend(^NS.URL, self, "URL") } @(objc_type=FunctionLogDebugLocation, objc_name="column") -FunctionLogDebugLocation_column :: proc(self: ^FunctionLogDebugLocation) -> NS.Integer { +FunctionLogDebugLocation_column :: #force_inline proc(self: ^FunctionLogDebugLocation) -> NS.Integer { return msgSend(NS.Integer, self, "column") } @(objc_type=FunctionLogDebugLocation, objc_name="functionName") -FunctionLogDebugLocation_functionName :: proc(self: ^FunctionLogDebugLocation) -> ^NS.String { +FunctionLogDebugLocation_functionName :: #force_inline proc(self: ^FunctionLogDebugLocation) -> ^NS.String { return msgSend(^NS.String, self, "functionName") } @(objc_type=FunctionLogDebugLocation, objc_name="line") -FunctionLogDebugLocation_line :: proc(self: ^FunctionLogDebugLocation) -> NS.Integer { +FunctionLogDebugLocation_line :: #force_inline proc(self: ^FunctionLogDebugLocation) -> NS.Integer { return msgSend(NS.Integer, self, "line") } @@ -6757,71 +6743,71 @@ Methods: Heap :: struct { using _: NS.Object } @(objc_type=Heap, objc_name="cpuCacheMode") -Heap_cpuCacheMode :: proc(self: ^Heap) -> CPUCacheMode { +Heap_cpuCacheMode :: #force_inline proc(self: ^Heap) -> CPUCacheMode { return msgSend(CPUCacheMode, self, "cpuCacheMode") } @(objc_type=Heap, objc_name="currentAllocatedSize") -Heap_currentAllocatedSize :: proc(self: ^Heap) -> NS.Integer { +Heap_currentAllocatedSize :: #force_inline proc(self: ^Heap) -> NS.Integer { return msgSend(NS.Integer, self, "currentAllocatedSize") } @(objc_type=Heap, objc_name="device") -Heap_device :: proc(self: ^Heap) -> ^Heap { +Heap_device :: #force_inline proc(self: ^Heap) -> ^Heap { return msgSend(^Heap, self, "device") } @(objc_type=Heap, objc_name="hazardTrackingMode") -Heap_hazardTrackingMode :: proc(self: ^Heap) -> HazardTrackingMode { +Heap_hazardTrackingMode :: #force_inline proc(self: ^Heap) -> HazardTrackingMode { return msgSend(HazardTrackingMode, self, "hazardTrackingMode") } @(objc_type=Heap, objc_name="label") -Heap_label :: proc(self: ^Heap) -> ^NS.String { +Heap_label :: #force_inline proc(self: ^Heap) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Heap, objc_name="maxAvailableSizeWithAlignment") -Heap_maxAvailableSizeWithAlignment :: proc(self: ^Heap, alignment: ^NS.Object) -> ^Heap { +Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: ^NS.Object) -> ^Heap { return msgSend(^Heap, self, "maxAvailableSizeWithAlignment:", alignment) } @(objc_type=Heap, objc_name="newBufferWithLength") -Heap_newBufferWithLength :: proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions) -> ^Heap { +Heap_newBufferWithLength :: #force_inline proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:", length, options) } @(objc_type=Heap, objc_name="newBufferWithLength_options_offset_") -Heap_newBufferWithLength_options_offset_ :: proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions, offset: ^NS.Object) -> ^Heap { +Heap_newBufferWithLength_options_offset_ :: #force_inline proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions, offset: ^NS.Object) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:offset:", length, options, offset) } @(objc_type=Heap, objc_name="newTextureWithDescriptor") -Heap_newTextureWithDescriptor :: proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Heap { +Heap_newTextureWithDescriptor :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Heap { return msgSend(^Heap, self, "newTextureWithDescriptor:", desc) } @(objc_type=Heap, objc_name="newTextureWithDescriptor_offset_") -Heap_newTextureWithDescriptor_offset_ :: proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: ^NS.Object) -> ^Heap { +Heap_newTextureWithDescriptor_offset_ :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: ^NS.Object) -> ^Heap { return msgSend(^Heap, self, "newTextureWithDescriptor:offset:", descriptor, offset) } @(objc_type=Heap, objc_name="resourceOptions") -Heap_resourceOptions :: proc(self: ^Heap) -> ResourceOptions { +Heap_resourceOptions :: #force_inline proc(self: ^Heap) -> ResourceOptions { return msgSend(ResourceOptions, self, "resourceOptions") } @(objc_type=Heap, objc_name="setLabel") -Heap_setLabel :: proc(self: ^Heap, label: ^NS.String) { +Heap_setLabel :: #force_inline proc(self: ^Heap, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=Heap, objc_name="setPurgeableState") -Heap_setPurgeableState :: proc(self: ^Heap, state: PurgeableState) -> PurgeableState { +Heap_setPurgeableState :: #force_inline proc(self: ^Heap, state: PurgeableState) -> PurgeableState { return msgSend(PurgeableState, self, "setPurgeableState:", state) } @(objc_type=Heap, objc_name="size") -Heap_size :: proc(self: ^Heap) -> NS.Integer { +Heap_size :: #force_inline proc(self: ^Heap) -> NS.Integer { return msgSend(NS.Integer, self, "size") } @(objc_type=Heap, objc_name="storageMode") -Heap_storageMode :: proc(self: ^Heap) -> StorageMode { +Heap_storageMode :: #force_inline proc(self: ^Heap) -> StorageMode { return msgSend(StorageMode, self, "storageMode") } @(objc_type=Heap, objc_name="type") -Heap_type :: proc(self: ^Heap) -> FunctionLogType { +Heap_type :: #force_inline proc(self: ^Heap) -> FunctionLogType { return msgSend(FunctionLogType, self, "type") } @(objc_type=Heap, objc_name="usedSize") -Heap_usedSize :: proc(self: ^Heap) -> NS.Integer { +Heap_usedSize :: #force_inline proc(self: ^Heap) -> NS.Integer { return msgSend(NS.Integer, self, "usedSize") } @@ -6841,19 +6827,19 @@ Methods: IndirectCommandBuffer :: struct { using _: NS.Object } @(objc_type=IndirectCommandBuffer, objc_name="indirectComputeCommandAtIndex") -IndirectCommandBuffer_indirectComputeCommandAtIndex :: proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { +IndirectCommandBuffer_indirectComputeCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "indirectComputeCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="indirectRenderCommandAtIndex") -IndirectCommandBuffer_indirectRenderCommandAtIndex :: proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { +IndirectCommandBuffer_indirectRenderCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "indirectRenderCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="resetWithRange") -IndirectCommandBuffer_resetWithRange :: proc(self: ^IndirectCommandBuffer, range: NS.Range) { +IndirectCommandBuffer_resetWithRange :: #force_inline proc(self: ^IndirectCommandBuffer, range: NS.Range) { msgSend(nil, self, "resetWithRange:", range) } @(objc_type=IndirectCommandBuffer, objc_name="size") -IndirectCommandBuffer_size :: proc(self: ^IndirectCommandBuffer) -> NS.Integer { +IndirectCommandBuffer_size :: #force_inline proc(self: ^IndirectCommandBuffer) -> NS.Integer { return msgSend(NS.Integer, self, "size") } @@ -6879,43 +6865,43 @@ Methods: IndirectComputeCommand :: struct { using _: NS.Object } @(objc_type=IndirectComputeCommand, objc_name="clearBarrier") -IndirectComputeCommand_clearBarrier :: proc(self: ^IndirectComputeCommand) { +IndirectComputeCommand_clearBarrier :: #force_inline proc(self: ^IndirectComputeCommand) { msgSend(nil, self, "clearBarrier") } @(objc_type=IndirectComputeCommand, objc_name="concurrentDispatchThreadgroups") -IndirectComputeCommand_concurrentDispatchThreadgroups :: proc(self: ^IndirectComputeCommand, threadgroupsPerGrid: Size, threadsPerThreadgroup: Size) { +IndirectComputeCommand_concurrentDispatchThreadgroups :: #force_inline proc(self: ^IndirectComputeCommand, threadgroupsPerGrid: Size, threadsPerThreadgroup: Size) { msgSend(nil, self, "concurrentDispatchThreadgroups:threadsPerThreadgroup:", threadgroupsPerGrid, threadsPerThreadgroup) } @(objc_type=IndirectComputeCommand, objc_name="concurrentDispatchThreads") -IndirectComputeCommand_concurrentDispatchThreads :: proc(self: ^IndirectComputeCommand, threadsPerGrid: Size, threadsPerThreadgroup: Size) { +IndirectComputeCommand_concurrentDispatchThreads :: #force_inline proc(self: ^IndirectComputeCommand, threadsPerGrid: Size, threadsPerThreadgroup: Size) { msgSend(nil, self, "concurrentDispatchThreads:threadsPerThreadgroup:", threadsPerGrid, threadsPerThreadgroup) } @(objc_type=IndirectComputeCommand, objc_name="reset") -IndirectComputeCommand_reset :: proc(self: ^IndirectComputeCommand) { +IndirectComputeCommand_reset :: #force_inline proc(self: ^IndirectComputeCommand) { msgSend(nil, self, "reset") } @(objc_type=IndirectComputeCommand, objc_name="setBarrier") -IndirectComputeCommand_setBarrier :: proc(self: ^IndirectComputeCommand) { +IndirectComputeCommand_setBarrier :: #force_inline proc(self: ^IndirectComputeCommand) { msgSend(nil, self, "setBarrier") } @(objc_type=IndirectComputeCommand, objc_name="setComputePipelineState") -IndirectComputeCommand_setComputePipelineState :: proc(self: ^IndirectComputeCommand, pipelineState: ^NS.Object) { +IndirectComputeCommand_setComputePipelineState :: #force_inline proc(self: ^IndirectComputeCommand, pipelineState: ^NS.Object) { msgSend(nil, self, "setComputePipelineState:", pipelineState) } @(objc_type=IndirectComputeCommand, objc_name="setImageblockWidth") -IndirectComputeCommand_setImageblockWidth :: proc(self: ^IndirectComputeCommand, width: ^NS.Object, height: ^NS.Object) { +IndirectComputeCommand_setImageblockWidth :: #force_inline proc(self: ^IndirectComputeCommand, width: ^NS.Object, height: ^NS.Object) { msgSend(nil, self, "setImageblockWidth:height:", width, height) } @(objc_type=IndirectComputeCommand, objc_name="setKernelBuffer") -IndirectComputeCommand_setKernelBuffer :: proc(self: ^IndirectComputeCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IndirectComputeCommand_setKernelBuffer :: #force_inline proc(self: ^IndirectComputeCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setKernelBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=IndirectComputeCommand, objc_name="setStageInRegion") -IndirectComputeCommand_setStageInRegion :: proc(self: ^IndirectComputeCommand, region: Region) { +IndirectComputeCommand_setStageInRegion :: #force_inline proc(self: ^IndirectComputeCommand, region: Region) { msgSend(nil, self, "setStageInRegion:", region) } @(objc_type=IndirectComputeCommand, objc_name="setThreadgroupMemoryLength") -IndirectComputeCommand_setThreadgroupMemoryLength :: proc(self: ^IndirectComputeCommand, length: ^NS.Object, index: ^NS.Object) { +IndirectComputeCommand_setThreadgroupMemoryLength :: #force_inline proc(self: ^IndirectComputeCommand, length: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setThreadgroupMemoryLength:atIndex:", length, index) } @@ -6939,35 +6925,35 @@ Methods: IndirectRenderCommand :: struct { using _: NS.Object } @(objc_type=IndirectRenderCommand, objc_name="drawIndexedPatches") -IndirectRenderCommand_drawIndexedPatches :: proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { +IndirectRenderCommand_drawIndexedPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawIndexedPrimitives") -IndirectRenderCommand_drawIndexedPrimitives :: proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { +IndirectRenderCommand_drawIndexedPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) } @(objc_type=IndirectRenderCommand, objc_name="drawPatches") -IndirectRenderCommand_drawPatches :: proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { +IndirectRenderCommand_drawPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawPrimitives") -IndirectRenderCommand_drawPrimitives :: proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +IndirectRenderCommand_drawPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } @(objc_type=IndirectRenderCommand, objc_name="reset") -IndirectRenderCommand_reset :: proc(self: ^IndirectRenderCommand) { +IndirectRenderCommand_reset :: #force_inline proc(self: ^IndirectRenderCommand) { msgSend(nil, self, "reset") } @(objc_type=IndirectRenderCommand, objc_name="setFragmentBuffer") -IndirectRenderCommand_setFragmentBuffer :: proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IndirectRenderCommand_setFragmentBuffer :: #force_inline proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFragmentBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=IndirectRenderCommand, objc_name="setRenderPipelineState") -IndirectRenderCommand_setRenderPipelineState :: proc(self: ^IndirectRenderCommand, pipelineState: ^NS.Object) { +IndirectRenderCommand_setRenderPipelineState :: #force_inline proc(self: ^IndirectRenderCommand, pipelineState: ^NS.Object) { msgSend(nil, self, "setRenderPipelineState:", pipelineState) } @(objc_type=IndirectRenderCommand, objc_name="setVertexBuffer") -IndirectRenderCommand_setVertexBuffer :: proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IndirectRenderCommand_setVertexBuffer :: #force_inline proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setVertexBuffer:offset:atIndex:", buffer, offset, index) } @@ -6991,35 +6977,35 @@ Methods: IntersectionFunctionTable :: struct { using _: NS.Object } @(objc_type=IntersectionFunctionTable, objc_name="setBuffer") -IntersectionFunctionTable_setBuffer :: proc(self: ^IntersectionFunctionTable, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IntersectionFunctionTable_setBuffer :: #force_inline proc(self: ^IntersectionFunctionTable, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=IntersectionFunctionTable, objc_name="setBuffers") -IntersectionFunctionTable_setBuffers :: proc(self: ^IntersectionFunctionTable, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +IntersectionFunctionTable_setBuffers :: #force_inline proc(self: ^IntersectionFunctionTable, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=IntersectionFunctionTable, objc_name="setFunction") -IntersectionFunctionTable_setFunction :: proc(self: ^IntersectionFunctionTable, function: ^NS.Object, index: ^NS.Object) { +IntersectionFunctionTable_setFunction :: #force_inline proc(self: ^IntersectionFunctionTable, function: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFunction:atIndex:", function, index) } @(objc_type=IntersectionFunctionTable, objc_name="setFunctions") -IntersectionFunctionTable_setFunctions :: proc(self: ^IntersectionFunctionTable, functions: ^^NS.Object, range: NS.Range) { +IntersectionFunctionTable_setFunctions :: #force_inline proc(self: ^IntersectionFunctionTable, functions: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setFunctions:withRange:", functions, range) } @(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignature_atIndex_") -IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_atIndex_ :: proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: ^NS.Object) { +IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_atIndex_ :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: ^NS.Object) { msgSend(nil, self, "setOpaqueTriangleIntersectionFunctionWithSignature:atIndex:", signature, index) } @(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignature_withRange_") -IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_withRange_ :: proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, range: NS.Range) { +IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_withRange_ :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, range: NS.Range) { msgSend(nil, self, "setOpaqueTriangleIntersectionFunctionWithSignature:withRange:", signature, range) } @(objc_type=IntersectionFunctionTable, objc_name="setVisibleFunctionTable") -IntersectionFunctionTable_setVisibleFunctionTable :: proc(self: ^IntersectionFunctionTable, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { +IntersectionFunctionTable_setVisibleFunctionTable :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) } @(objc_type=IntersectionFunctionTable, objc_name="setVisibleFunctionTables") -IntersectionFunctionTable_setVisibleFunctionTables :: proc(self: ^IntersectionFunctionTable, visibleFunctionTables: ^^NS.Object, range: NS.Range) { +IntersectionFunctionTable_setVisibleFunctionTables :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTables: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) } @@ -7048,55 +7034,55 @@ Methods: Library :: struct { using _: NS.Object } @(objc_type=Library, objc_name="device") -Library_device :: proc(self: ^Library) -> ^Library { +Library_device :: #force_inline proc(self: ^Library) -> ^Library { return msgSend(^Library, self, "device") } @(objc_type=Library, objc_name="functionNames") -Library_functionNames :: proc(self: ^Library) -> ^NS.Array { +Library_functionNames :: #force_inline proc(self: ^Library) -> ^NS.Array { return msgSend(^NS.Array, self, "functionNames") } @(objc_type=Library, objc_name="installName") -Library_installName :: proc(self: ^Library) -> ^NS.String { +Library_installName :: #force_inline proc(self: ^Library) -> ^NS.String { return msgSend(^NS.String, self, "installName") } @(objc_type=Library, objc_name="label") -Library_label :: proc(self: ^Library) -> ^NS.String { +Library_label :: #force_inline proc(self: ^Library) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Library, objc_name="newFunctionWithDescriptor_completionHandler_") -Library_newFunctionWithDescriptor_completionHandler_ :: proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) { +Library_newFunctionWithDescriptor_completionHandler_ :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) { msgSend(nil, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithDescriptor_error_") -Library_newFunctionWithDescriptor_error_ :: proc(self: ^Library, descriptor: ^FunctionDescriptor, error: ^^NS.Error ) -> ^Library { +Library_newFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, error: ^^NS.Error ) -> ^Library { return msgSend(^Library, self, "newFunctionWithDescriptor:error:", descriptor, error) } @(objc_type=Library, objc_name="newFunctionWithName") -Library_newFunctionWithName :: proc(self: ^Library, functionName: ^NS.String) -> ^Library { +Library_newFunctionWithName :: #force_inline proc(self: ^Library, functionName: ^NS.String) -> ^Library { return msgSend(^Library, self, "newFunctionWithName:", functionName) } @(objc_type=Library, objc_name="newFunctionWithName_constantValues_completionHandler_") -Library_newFunctionWithName_constantValues_completionHandler_ :: proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) { +Library_newFunctionWithName_constantValues_completionHandler_ :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) { msgSend(nil, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithName_constantValues_error_") -Library_newFunctionWithName_constantValues_error_ :: proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, error: ^^NS.Error ) -> ^Library { +Library_newFunctionWithName_constantValues_error_ :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, error: ^^NS.Error ) -> ^Library { return msgSend(^Library, self, "newFunctionWithName:constantValues:error:", name, constantValues, error) } @(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_completionHandler_") -Library_newIntersectionFunctionWithDescriptor_completionHandler_ :: proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) { +Library_newIntersectionFunctionWithDescriptor_completionHandler_ :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) { msgSend(nil, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_error_") -Library_newIntersectionFunctionWithDescriptor_error_ :: proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, error: ^^NS.Error ) -> ^Library { +Library_newIntersectionFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, error: ^^NS.Error ) -> ^Library { return msgSend(^Library, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, error) } @(objc_type=Library, objc_name="setLabel") -Library_setLabel :: proc(self: ^Library, label: ^NS.String) { +Library_setLabel :: #force_inline proc(self: ^Library, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=Library, objc_name="type") -Library_type :: proc(self: ^Library) -> LibraryType { +Library_type :: #force_inline proc(self: ^Library) -> LibraryType { return msgSend(LibraryType, self, "type") } @@ -7119,31 +7105,31 @@ Methods: ParallelRenderCommandEncoder :: struct { using _: NS.Object } @(objc_type=ParallelRenderCommandEncoder, objc_name="renderCommandEncoder") -ParallelRenderCommandEncoder_renderCommandEncoder :: proc(self: ^ParallelRenderCommandEncoder) -> ^ParallelRenderCommandEncoder { +ParallelRenderCommandEncoder_renderCommandEncoder :: #force_inline proc(self: ^ParallelRenderCommandEncoder) -> ^ParallelRenderCommandEncoder { return msgSend(^ParallelRenderCommandEncoder, self, "renderCommandEncoder") } @(objc_type=ParallelRenderCommandEncoder, objc_name="setColorStoreAction") -ParallelRenderCommandEncoder_setColorStoreAction :: proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { +ParallelRenderCommandEncoder_setColorStoreAction :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { msgSend(nil, self, "setColorStoreAction:atIndex:", storeAction, colorAttachmentIndex) } @(objc_type=ParallelRenderCommandEncoder, objc_name="setColorStoreActionOptions") -ParallelRenderCommandEncoder_setColorStoreActionOptions :: proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { +ParallelRenderCommandEncoder_setColorStoreActionOptions :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { msgSend(nil, self, "setColorStoreActionOptions:atIndex:", storeActionOptions, colorAttachmentIndex) } @(objc_type=ParallelRenderCommandEncoder, objc_name="setDepthStoreAction") -ParallelRenderCommandEncoder_setDepthStoreAction :: proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction) { +ParallelRenderCommandEncoder_setDepthStoreAction :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction) { msgSend(nil, self, "setDepthStoreAction:", storeAction) } @(objc_type=ParallelRenderCommandEncoder, objc_name="setDepthStoreActionOptions") -ParallelRenderCommandEncoder_setDepthStoreActionOptions :: proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions) { +ParallelRenderCommandEncoder_setDepthStoreActionOptions :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions) { msgSend(nil, self, "setDepthStoreActionOptions:", storeActionOptions) } @(objc_type=ParallelRenderCommandEncoder, objc_name="setStencilStoreAction") -ParallelRenderCommandEncoder_setStencilStoreAction :: proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction) { +ParallelRenderCommandEncoder_setStencilStoreAction :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction) { msgSend(nil, self, "setStencilStoreAction:", storeAction) } @(objc_type=ParallelRenderCommandEncoder, objc_name="setStencilStoreActionOptions") -ParallelRenderCommandEncoder_setStencilStoreActionOptions :: proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions) { +ParallelRenderCommandEncoder_setStencilStoreActionOptions :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions) { msgSend(nil, self, "setStencilStoreActionOptions:", storeActionOptions) } @@ -7169,43 +7155,43 @@ Methods: RasterizationRateMap :: struct { using _: NS.Object } @(objc_type=RasterizationRateMap, objc_name="copyParameterDataToBuffer") -RasterizationRateMap_copyParameterDataToBuffer :: proc(self: ^RasterizationRateMap, buffer: ^NS.Object, offset: ^NS.Object) { +RasterizationRateMap_copyParameterDataToBuffer :: #force_inline proc(self: ^RasterizationRateMap, buffer: ^NS.Object, offset: ^NS.Object) { msgSend(nil, self, "copyParameterDataToBuffer:offset:", buffer, offset) } @(objc_type=RasterizationRateMap, objc_name="device") -RasterizationRateMap_device :: proc(self: ^RasterizationRateMap) -> ^RasterizationRateMap { +RasterizationRateMap_device :: #force_inline proc(self: ^RasterizationRateMap) -> ^RasterizationRateMap { return msgSend(^RasterizationRateMap, self, "device") } @(objc_type=RasterizationRateMap, objc_name="label") -RasterizationRateMap_label :: proc(self: ^RasterizationRateMap) -> ^NS.String { +RasterizationRateMap_label :: #force_inline proc(self: ^RasterizationRateMap) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=RasterizationRateMap, objc_name="layerCount") -RasterizationRateMap_layerCount :: proc(self: ^RasterizationRateMap) -> NS.Integer { +RasterizationRateMap_layerCount :: #force_inline proc(self: ^RasterizationRateMap) -> NS.Integer { return msgSend(NS.Integer, self, "layerCount") } @(objc_type=RasterizationRateMap, objc_name="mapPhysicalToScreenCoordinates") -RasterizationRateMap_mapPhysicalToScreenCoordinates :: proc(self: ^RasterizationRateMap, physicalCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { +RasterizationRateMap_mapPhysicalToScreenCoordinates :: #force_inline proc(self: ^RasterizationRateMap, physicalCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { return msgSend(Coordinate2D, self, "mapPhysicalToScreenCoordinates:forLayer:", physicalCoordinates, layerIndex) } @(objc_type=RasterizationRateMap, objc_name="mapScreenToPhysicalCoordinates") -RasterizationRateMap_mapScreenToPhysicalCoordinates :: proc(self: ^RasterizationRateMap, screenCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { +RasterizationRateMap_mapScreenToPhysicalCoordinates :: #force_inline proc(self: ^RasterizationRateMap, screenCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { return msgSend(Coordinate2D, self, "mapScreenToPhysicalCoordinates:forLayer:", screenCoordinates, layerIndex) } @(objc_type=RasterizationRateMap, objc_name="parameterBufferSizeAndAlign") -RasterizationRateMap_parameterBufferSizeAndAlign :: proc(self: ^RasterizationRateMap) -> SizeAndAlign { +RasterizationRateMap_parameterBufferSizeAndAlign :: #force_inline proc(self: ^RasterizationRateMap) -> SizeAndAlign { return msgSend(SizeAndAlign, self, "parameterBufferSizeAndAlign") } @(objc_type=RasterizationRateMap, objc_name="physicalGranularity") -RasterizationRateMap_physicalGranularity :: proc(self: ^RasterizationRateMap) -> Size { +RasterizationRateMap_physicalGranularity :: #force_inline proc(self: ^RasterizationRateMap) -> Size { return msgSend(Size, self, "physicalGranularity") } @(objc_type=RasterizationRateMap, objc_name="physicalSizeForLayer") -RasterizationRateMap_physicalSizeForLayer :: proc(self: ^RasterizationRateMap, layerIndex: ^NS.Object) -> Size { +RasterizationRateMap_physicalSizeForLayer :: #force_inline proc(self: ^RasterizationRateMap, layerIndex: ^NS.Object) -> Size { return msgSend(Size, self, "physicalSizeForLayer:", layerIndex) } @(objc_type=RasterizationRateMap, objc_name="screenSize") -RasterizationRateMap_screenSize :: proc(self: ^RasterizationRateMap) -> Size { +RasterizationRateMap_screenSize :: #force_inline proc(self: ^RasterizationRateMap) -> Size { return msgSend(Size, self, "screenSize") } @@ -7307,347 +7293,347 @@ Methods: RenderCommandEncoder :: struct { using _: NS.Object } @(objc_type=RenderCommandEncoder, objc_name="dispatchThreadsPerTile") -RenderCommandEncoder_dispatchThreadsPerTile :: proc(self: ^RenderCommandEncoder, threadsPerTile: Size) { +RenderCommandEncoder_dispatchThreadsPerTile :: #force_inline proc(self: ^RenderCommandEncoder, threadsPerTile: Size) { msgSend(nil, self, "dispatchThreadsPerTile:", threadsPerTile) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "drawIndexedPatches:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "drawIndexedPrimitives:indexType:indexBuffer:indexBufferOffset:indirectBuffer:indirectBufferOffset:", primitiveType, indexType, indexBuffer, indexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "drawPatches:patchIndexBuffer:patchIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawPrimitives_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "drawPrimitives:indirectBuffer:indirectBufferOffset:", primitiveType, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:", primitiveType, vertexStart, vertexCount) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:", primitiveType, vertexStart, vertexCount, instanceCount) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_ :: proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: proc(self: ^RenderCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "executeCommandsInBuffer:indirectBuffer:indirectBufferOffset:", indirectCommandbuffer, indirectRangeBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer_withRange_") -RenderCommandEncoder_executeCommandsInBuffer_withRange_ :: proc(self: ^RenderCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { +RenderCommandEncoder_executeCommandsInBuffer_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) } @(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithResources") -RenderCommandEncoder_memoryBarrierWithResources :: proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, after: RenderStages, before: RenderStages) { +RenderCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, after: RenderStages, before: RenderStages) { msgSend(nil, self, "memoryBarrierWithResources:count:afterStages:beforeStages:", resources, count, after, before) } @(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithScope") -RenderCommandEncoder_memoryBarrierWithScope :: proc(self: ^RenderCommandEncoder, scope: BarrierScope, after: RenderStages, before: RenderStages) { +RenderCommandEncoder_memoryBarrierWithScope :: #force_inline proc(self: ^RenderCommandEncoder, scope: BarrierScope, after: RenderStages, before: RenderStages) { msgSend(nil, self, "memoryBarrierWithScope:afterStages:beforeStages:", scope, after, before) } @(objc_type=RenderCommandEncoder, objc_name="sampleCountersInBuffer") -RenderCommandEncoder_sampleCountersInBuffer :: proc(self: ^RenderCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +RenderCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^RenderCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=RenderCommandEncoder, objc_name="setBlendColorRed") -RenderCommandEncoder_setBlendColorRed :: proc(self: ^RenderCommandEncoder, red: f32, green: f32, blue: f32, alpha: f32) { +RenderCommandEncoder_setBlendColorRed :: #force_inline proc(self: ^RenderCommandEncoder, red: f32, green: f32, blue: f32, alpha: f32) { msgSend(nil, self, "setBlendColorRed:green:blue:alpha:", red, green, blue, alpha) } @(objc_type=RenderCommandEncoder, objc_name="setColorStoreAction") -RenderCommandEncoder_setColorStoreAction :: proc(self: ^RenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { +RenderCommandEncoder_setColorStoreAction :: #force_inline proc(self: ^RenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { msgSend(nil, self, "setColorStoreAction:atIndex:", storeAction, colorAttachmentIndex) } @(objc_type=RenderCommandEncoder, objc_name="setColorStoreActionOptions") -RenderCommandEncoder_setColorStoreActionOptions :: proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { +RenderCommandEncoder_setColorStoreActionOptions :: #force_inline proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { msgSend(nil, self, "setColorStoreActionOptions:atIndex:", storeActionOptions, colorAttachmentIndex) } @(objc_type=RenderCommandEncoder, objc_name="setCullMode") -RenderCommandEncoder_setCullMode :: proc(self: ^RenderCommandEncoder, cullMode: CullMode) { +RenderCommandEncoder_setCullMode :: #force_inline proc(self: ^RenderCommandEncoder, cullMode: CullMode) { msgSend(nil, self, "setCullMode:", cullMode) } @(objc_type=RenderCommandEncoder, objc_name="setDepthBias") -RenderCommandEncoder_setDepthBias :: proc(self: ^RenderCommandEncoder, depthBias: f32, slopeScale: f32, clamp: f32) { +RenderCommandEncoder_setDepthBias :: #force_inline proc(self: ^RenderCommandEncoder, depthBias: f32, slopeScale: f32, clamp: f32) { msgSend(nil, self, "setDepthBias:slopeScale:clamp:", depthBias, slopeScale, clamp) } @(objc_type=RenderCommandEncoder, objc_name="setDepthClipMode") -RenderCommandEncoder_setDepthClipMode :: proc(self: ^RenderCommandEncoder, depthClipMode: DepthClipMode) { +RenderCommandEncoder_setDepthClipMode :: #force_inline proc(self: ^RenderCommandEncoder, depthClipMode: DepthClipMode) { msgSend(nil, self, "setDepthClipMode:", depthClipMode) } @(objc_type=RenderCommandEncoder, objc_name="setDepthStencilState") -RenderCommandEncoder_setDepthStencilState :: proc(self: ^RenderCommandEncoder, depthStencilState: ^NS.Object) { +RenderCommandEncoder_setDepthStencilState :: #force_inline proc(self: ^RenderCommandEncoder, depthStencilState: ^NS.Object) { msgSend(nil, self, "setDepthStencilState:", depthStencilState) } @(objc_type=RenderCommandEncoder, objc_name="setDepthStoreAction") -RenderCommandEncoder_setDepthStoreAction :: proc(self: ^RenderCommandEncoder, storeAction: StoreAction) { +RenderCommandEncoder_setDepthStoreAction :: #force_inline proc(self: ^RenderCommandEncoder, storeAction: StoreAction) { msgSend(nil, self, "setDepthStoreAction:", storeAction) } @(objc_type=RenderCommandEncoder, objc_name="setDepthStoreActionOptions") -RenderCommandEncoder_setDepthStoreActionOptions :: proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions) { +RenderCommandEncoder_setDepthStoreActionOptions :: #force_inline proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions) { msgSend(nil, self, "setDepthStoreActionOptions:", storeActionOptions) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBuffer") -RenderCommandEncoder_setFragmentBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFragmentBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBufferOffset") -RenderCommandEncoder_setFragmentBufferOffset :: proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFragmentBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBuffers") -RenderCommandEncoder_setFragmentBuffers :: proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +RenderCommandEncoder_setFragmentBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { msgSend(nil, self, "setFragmentBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBytes") -RenderCommandEncoder_setFragmentBytes :: proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFragmentBytes:length:atIndex:", bytes, length, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_atIndex_") -RenderCommandEncoder_setFragmentSamplerState_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentSamplerState_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFragmentSamplerState:atIndex:", sampler, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -RenderCommandEncoder_setFragmentSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +RenderCommandEncoder_setFragmentSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { msgSend(nil, self, "setFragmentSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setFragmentSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_withRange_") -RenderCommandEncoder_setFragmentSamplerStates_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setFragmentSamplerStates_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setFragmentSamplerStates:withRange:", samplers, range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentTexture") -RenderCommandEncoder_setFragmentTexture :: proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFragmentTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentTextures") -RenderCommandEncoder_setFragmentTextures :: proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setFragmentTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setFragmentTextures:withRange:", textures, range) } @(objc_type=RenderCommandEncoder, objc_name="setFrontFacingWinding") -RenderCommandEncoder_setFrontFacingWinding :: proc(self: ^RenderCommandEncoder, frontFacingWinding: Winding) { +RenderCommandEncoder_setFrontFacingWinding :: #force_inline proc(self: ^RenderCommandEncoder, frontFacingWinding: Winding) { msgSend(nil, self, "setFrontFacingWinding:", frontFacingWinding) } @(objc_type=RenderCommandEncoder, objc_name="setRenderPipelineState") -RenderCommandEncoder_setRenderPipelineState :: proc(self: ^RenderCommandEncoder, pipelineState: ^NS.Object) { +RenderCommandEncoder_setRenderPipelineState :: #force_inline proc(self: ^RenderCommandEncoder, pipelineState: ^NS.Object) { msgSend(nil, self, "setRenderPipelineState:", pipelineState) } @(objc_type=RenderCommandEncoder, objc_name="setScissorRect") -RenderCommandEncoder_setScissorRect :: proc(self: ^RenderCommandEncoder, rect: ScissorRect) { +RenderCommandEncoder_setScissorRect :: #force_inline proc(self: ^RenderCommandEncoder, rect: ScissorRect) { msgSend(nil, self, "setScissorRect:", rect) } @(objc_type=RenderCommandEncoder, objc_name="setScissorRects") -RenderCommandEncoder_setScissorRects :: proc(self: ^RenderCommandEncoder, scissorRects: ^ScissorRect, count: ^NS.Object) { +RenderCommandEncoder_setScissorRects :: #force_inline proc(self: ^RenderCommandEncoder, scissorRects: ^ScissorRect, count: ^NS.Object) { msgSend(nil, self, "setScissorRects:count:", scissorRects, count) } @(objc_type=RenderCommandEncoder, objc_name="setStencilFrontReferenceValue") -RenderCommandEncoder_setStencilFrontReferenceValue :: proc(self: ^RenderCommandEncoder, frontReferenceValue: u32, backReferenceValue: u32) { +RenderCommandEncoder_setStencilFrontReferenceValue :: #force_inline proc(self: ^RenderCommandEncoder, frontReferenceValue: u32, backReferenceValue: u32) { msgSend(nil, self, "setStencilFrontReferenceValue:backReferenceValue:", frontReferenceValue, backReferenceValue) } @(objc_type=RenderCommandEncoder, objc_name="setStencilReferenceValue") -RenderCommandEncoder_setStencilReferenceValue :: proc(self: ^RenderCommandEncoder, referenceValue: u32) { +RenderCommandEncoder_setStencilReferenceValue :: #force_inline proc(self: ^RenderCommandEncoder, referenceValue: u32) { msgSend(nil, self, "setStencilReferenceValue:", referenceValue) } @(objc_type=RenderCommandEncoder, objc_name="setStencilStoreAction") -RenderCommandEncoder_setStencilStoreAction :: proc(self: ^RenderCommandEncoder, storeAction: StoreAction) { +RenderCommandEncoder_setStencilStoreAction :: #force_inline proc(self: ^RenderCommandEncoder, storeAction: StoreAction) { msgSend(nil, self, "setStencilStoreAction:", storeAction) } @(objc_type=RenderCommandEncoder, objc_name="setStencilStoreActionOptions") -RenderCommandEncoder_setStencilStoreActionOptions :: proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions) { +RenderCommandEncoder_setStencilStoreActionOptions :: #force_inline proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions) { msgSend(nil, self, "setStencilStoreActionOptions:", storeActionOptions) } @(objc_type=RenderCommandEncoder, objc_name="setTessellationFactorBuffer") -RenderCommandEncoder_setTessellationFactorBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { +RenderCommandEncoder_setTessellationFactorBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { msgSend(nil, self, "setTessellationFactorBuffer:offset:instanceStride:", buffer, offset, instanceStride) } @(objc_type=RenderCommandEncoder, objc_name="setTessellationFactorScale") -RenderCommandEncoder_setTessellationFactorScale :: proc(self: ^RenderCommandEncoder, scale: f32) { +RenderCommandEncoder_setTessellationFactorScale :: #force_inline proc(self: ^RenderCommandEncoder, scale: f32) { msgSend(nil, self, "setTessellationFactorScale:", scale) } @(objc_type=RenderCommandEncoder, objc_name="setThreadgroupMemoryLength") -RenderCommandEncoder_setThreadgroupMemoryLength :: proc(self: ^RenderCommandEncoder, length: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setThreadgroupMemoryLength :: #force_inline proc(self: ^RenderCommandEncoder, length: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setThreadgroupMemoryLength:offset:atIndex:", length, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileBuffer") -RenderCommandEncoder_setTileBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setTileBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileBufferOffset") -RenderCommandEncoder_setTileBufferOffset :: proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setTileBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileBuffers") -RenderCommandEncoder_setTileBuffers :: proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +RenderCommandEncoder_setTileBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { msgSend(nil, self, "setTileBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=RenderCommandEncoder, objc_name="setTileBytes") -RenderCommandEncoder_setTileBytes :: proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setTileBytes:length:atIndex:", bytes, length, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_atIndex_") -RenderCommandEncoder_setTileSamplerState_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileSamplerState_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setTileSamplerState:atIndex:", sampler, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -RenderCommandEncoder_setTileSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +RenderCommandEncoder_setTileSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { msgSend(nil, self, "setTileSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -RenderCommandEncoder_setTileSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +RenderCommandEncoder_setTileSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setTileSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } @(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_withRange_") -RenderCommandEncoder_setTileSamplerStates_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setTileSamplerStates_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setTileSamplerStates:withRange:", samplers, range) } @(objc_type=RenderCommandEncoder, objc_name="setTileTexture") -RenderCommandEncoder_setTileTexture :: proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setTileTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileTextures") -RenderCommandEncoder_setTileTextures :: proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setTileTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setTileTextures:withRange:", textures, range) } @(objc_type=RenderCommandEncoder, objc_name="setTriangleFillMode") -RenderCommandEncoder_setTriangleFillMode :: proc(self: ^RenderCommandEncoder, fillMode: TriangleFillMode) { +RenderCommandEncoder_setTriangleFillMode :: #force_inline proc(self: ^RenderCommandEncoder, fillMode: TriangleFillMode) { msgSend(nil, self, "setTriangleFillMode:", fillMode) } @(objc_type=RenderCommandEncoder, objc_name="setVertexAmplificationCount") -RenderCommandEncoder_setVertexAmplificationCount :: proc(self: ^RenderCommandEncoder, count: ^NS.Object, viewMappings: ^VertexAmplificationViewMapping) { +RenderCommandEncoder_setVertexAmplificationCount :: #force_inline proc(self: ^RenderCommandEncoder, count: ^NS.Object, viewMappings: ^VertexAmplificationViewMapping) { msgSend(nil, self, "setVertexAmplificationCount:viewMappings:", count, viewMappings) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBuffer") -RenderCommandEncoder_setVertexBuffer :: proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setVertexBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBufferOffset") -RenderCommandEncoder_setVertexBufferOffset :: proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setVertexBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBuffers") -RenderCommandEncoder_setVertexBuffers :: proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +RenderCommandEncoder_setVertexBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { msgSend(nil, self, "setVertexBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBytes") -RenderCommandEncoder_setVertexBytes :: proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setVertexBytes:length:atIndex:", bytes, length, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_atIndex_") -RenderCommandEncoder_setVertexSamplerState_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexSamplerState_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setVertexSamplerState:atIndex:", sampler, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -RenderCommandEncoder_setVertexSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +RenderCommandEncoder_setVertexSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { msgSend(nil, self, "setVertexSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -RenderCommandEncoder_setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +RenderCommandEncoder_setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setVertexSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_withRange_") -RenderCommandEncoder_setVertexSamplerStates_withRange_ :: proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setVertexSamplerStates_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setVertexSamplerStates:withRange:", samplers, range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexTexture") -RenderCommandEncoder_setVertexTexture :: proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setVertexTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexTextures") -RenderCommandEncoder_setVertexTextures :: proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setVertexTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setVertexTextures:withRange:", textures, range) } @(objc_type=RenderCommandEncoder, objc_name="setViewport") -RenderCommandEncoder_setViewport :: proc(self: ^RenderCommandEncoder, viewport: Viewport) { +RenderCommandEncoder_setViewport :: #force_inline proc(self: ^RenderCommandEncoder, viewport: Viewport) { msgSend(nil, self, "setViewport:", viewport) } @(objc_type=RenderCommandEncoder, objc_name="setViewports") -RenderCommandEncoder_setViewports :: proc(self: ^RenderCommandEncoder, viewports: ^Viewport, count: ^NS.Object) { +RenderCommandEncoder_setViewports :: #force_inline proc(self: ^RenderCommandEncoder, viewports: ^Viewport, count: ^NS.Object) { msgSend(nil, self, "setViewports:count:", viewports, count) } @(objc_type=RenderCommandEncoder, objc_name="setVisibilityResultMode") -RenderCommandEncoder_setVisibilityResultMode :: proc(self: ^RenderCommandEncoder, mode: VisibilityResultMode, offset: ^NS.Object) { +RenderCommandEncoder_setVisibilityResultMode :: #force_inline proc(self: ^RenderCommandEncoder, mode: VisibilityResultMode, offset: ^NS.Object) { msgSend(nil, self, "setVisibilityResultMode:offset:", mode, offset) } @(objc_type=RenderCommandEncoder, objc_name="textureBarrier") -RenderCommandEncoder_textureBarrier :: proc(self: ^RenderCommandEncoder) { +RenderCommandEncoder_textureBarrier :: #force_inline proc(self: ^RenderCommandEncoder) { msgSend(nil, self, "textureBarrier") } @(objc_type=RenderCommandEncoder, objc_name="tileHeight") -RenderCommandEncoder_tileHeight :: proc(self: ^RenderCommandEncoder) -> NS.Integer { +RenderCommandEncoder_tileHeight :: #force_inline proc(self: ^RenderCommandEncoder) -> NS.Integer { return msgSend(NS.Integer, self, "tileHeight") } @(objc_type=RenderCommandEncoder, objc_name="tileWidth") -RenderCommandEncoder_tileWidth :: proc(self: ^RenderCommandEncoder) -> NS.Integer { +RenderCommandEncoder_tileWidth :: #force_inline proc(self: ^RenderCommandEncoder) -> NS.Integer { return msgSend(NS.Integer, self, "tileWidth") } @(objc_type=RenderCommandEncoder, objc_name="updateFence") -RenderCommandEncoder_updateFence :: proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_updateFence :: #force_inline proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { msgSend(nil, self, "updateFence:afterStages:", fence, stages) } @(objc_type=RenderCommandEncoder, objc_name="useHeap") -RenderCommandEncoder_useHeap :: proc(self: ^RenderCommandEncoder, heap: ^NS.Object) { +RenderCommandEncoder_useHeap :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^NS.Object) { msgSend(nil, self, "useHeap:", heap) } @(objc_type=RenderCommandEncoder, objc_name="useHeap_stages_") -RenderCommandEncoder_useHeap_stages_ :: proc(self: ^RenderCommandEncoder, heap: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_useHeap_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^NS.Object, stages: RenderStages) { msgSend(nil, self, "useHeap:stages:", heap, stages) } @(objc_type=RenderCommandEncoder, objc_name="useHeaps") -RenderCommandEncoder_useHeaps :: proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { +RenderCommandEncoder_useHeaps :: #force_inline proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { msgSend(nil, self, "useHeaps:count:", heaps, count) } @(objc_type=RenderCommandEncoder, objc_name="useHeaps_count_stages_") -RenderCommandEncoder_useHeaps_count_stages_ :: proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_useHeaps_count_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object, stages: RenderStages) { msgSend(nil, self, "useHeaps:count:stages:", heaps, count, stages) } @(objc_type=RenderCommandEncoder, objc_name="useResource") -RenderCommandEncoder_useResource :: proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { +RenderCommandEncoder_useResource :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=RenderCommandEncoder, objc_name="useResource_usage_stages_") -RenderCommandEncoder_useResource_usage_stages_ :: proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { +RenderCommandEncoder_useResource_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { msgSend(nil, self, "useResource:usage:stages:", resource, usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="useResources") -RenderCommandEncoder_useResources :: proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { +RenderCommandEncoder_useResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { msgSend(nil, self, "useResources:count:usage:", resources, count, usage) } @(objc_type=RenderCommandEncoder, objc_name="useResources_count_usage_stages_") -RenderCommandEncoder_useResources_count_usage_stages_ :: proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { +RenderCommandEncoder_useResources_count_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { msgSend(nil, self, "useResources:count:usage:stages:", resources, count, usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="waitForFence") -RenderCommandEncoder_waitForFence :: proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_waitForFence :: #force_inline proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { msgSend(nil, self, "waitForFence:beforeStages:", fence, stages) } @@ -7670,31 +7656,31 @@ Methods: RenderPipelineState :: struct { using _: NS.Object } @(objc_type=RenderPipelineState, objc_name="device") -RenderPipelineState_device :: proc(self: ^RenderPipelineState) -> ^RenderPipelineState { +RenderPipelineState_device :: #force_inline proc(self: ^RenderPipelineState) -> ^RenderPipelineState { return msgSend(^RenderPipelineState, self, "device") } @(objc_type=RenderPipelineState, objc_name="imageblockMemoryLengthForDimensions") -RenderPipelineState_imageblockMemoryLengthForDimensions :: proc(self: ^RenderPipelineState, imageblockDimensions: Size) -> ^RenderPipelineState { +RenderPipelineState_imageblockMemoryLengthForDimensions :: #force_inline proc(self: ^RenderPipelineState, imageblockDimensions: Size) -> ^RenderPipelineState { return msgSend(^RenderPipelineState, self, "imageblockMemoryLengthForDimensions:", imageblockDimensions) } @(objc_type=RenderPipelineState, objc_name="imageblockSampleLength") -RenderPipelineState_imageblockSampleLength :: proc(self: ^RenderPipelineState) -> NS.Integer { +RenderPipelineState_imageblockSampleLength :: #force_inline proc(self: ^RenderPipelineState) -> NS.Integer { return msgSend(NS.Integer, self, "imageblockSampleLength") } @(objc_type=RenderPipelineState, objc_name="label") -RenderPipelineState_label :: proc(self: ^RenderPipelineState) -> ^NS.String { +RenderPipelineState_label :: #force_inline proc(self: ^RenderPipelineState) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=RenderPipelineState, objc_name="maxTotalThreadsPerThreadgroup") -RenderPipelineState_maxTotalThreadsPerThreadgroup :: proc(self: ^RenderPipelineState) -> NS.Integer { +RenderPipelineState_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^RenderPipelineState) -> NS.Integer { return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=RenderPipelineState, objc_name="supportIndirectCommandBuffers") -RenderPipelineState_supportIndirectCommandBuffers :: proc(self: ^RenderPipelineState) -> BOOL { +RenderPipelineState_supportIndirectCommandBuffers :: #force_inline proc(self: ^RenderPipelineState) -> BOOL { return msgSend(BOOL, self, "supportIndirectCommandBuffers") } @(objc_type=RenderPipelineState, objc_name="threadgroupSizeMatchesTileSize") -RenderPipelineState_threadgroupSizeMatchesTileSize :: proc(self: ^RenderPipelineState) -> BOOL { +RenderPipelineState_threadgroupSizeMatchesTileSize :: #force_inline proc(self: ^RenderPipelineState) -> BOOL { return msgSend(BOOL, self, "threadgroupSizeMatchesTileSize") } @@ -7723,55 +7709,55 @@ Methods: Resource :: struct { using _: NS.Object } @(objc_type=Resource, objc_name="allocatedSize") -Resource_allocatedSize :: proc(self: ^Resource) -> NS.Integer { +Resource_allocatedSize :: #force_inline proc(self: ^Resource) -> NS.Integer { return msgSend(NS.Integer, self, "allocatedSize") } @(objc_type=Resource, objc_name="cpuCacheMode") -Resource_cpuCacheMode :: proc(self: ^Resource) -> CPUCacheMode { +Resource_cpuCacheMode :: #force_inline proc(self: ^Resource) -> CPUCacheMode { return msgSend(CPUCacheMode, self, "cpuCacheMode") } @(objc_type=Resource, objc_name="device") -Resource_device :: proc(self: ^Resource) -> ^Resource { +Resource_device :: #force_inline proc(self: ^Resource) -> ^Resource { return msgSend(^Resource, self, "device") } @(objc_type=Resource, objc_name="hazardTrackingMode") -Resource_hazardTrackingMode :: proc(self: ^Resource) -> HazardTrackingMode { +Resource_hazardTrackingMode :: #force_inline proc(self: ^Resource) -> HazardTrackingMode { return msgSend(HazardTrackingMode, self, "hazardTrackingMode") } @(objc_type=Resource, objc_name="heap") -Resource_heap :: proc(self: ^Resource) -> ^Resource { +Resource_heap :: #force_inline proc(self: ^Resource) -> ^Resource { return msgSend(^Resource, self, "heap") } @(objc_type=Resource, objc_name="heapOffset") -Resource_heapOffset :: proc(self: ^Resource) -> NS.Integer { +Resource_heapOffset :: #force_inline proc(self: ^Resource) -> NS.Integer { return msgSend(NS.Integer, self, "heapOffset") } @(objc_type=Resource, objc_name="isAliasable") -Resource_isAliasable :: proc(self: ^Resource) -> BOOL { +Resource_isAliasable :: #force_inline proc(self: ^Resource) -> BOOL { return msgSend(BOOL, self, "isAliasable") } @(objc_type=Resource, objc_name="label") -Resource_label :: proc(self: ^Resource) -> ^NS.String { +Resource_label :: #force_inline proc(self: ^Resource) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Resource, objc_name="makeAliasable") -Resource_makeAliasable :: proc(self: ^Resource) { +Resource_makeAliasable :: #force_inline proc(self: ^Resource) { msgSend(nil, self, "makeAliasable") } @(objc_type=Resource, objc_name="resourceOptions") -Resource_resourceOptions :: proc(self: ^Resource) -> ResourceOptions { +Resource_resourceOptions :: #force_inline proc(self: ^Resource) -> ResourceOptions { return msgSend(ResourceOptions, self, "resourceOptions") } @(objc_type=Resource, objc_name="setLabel") -Resource_setLabel :: proc(self: ^Resource, label: ^NS.String) { +Resource_setLabel :: #force_inline proc(self: ^Resource, label: ^NS.String) { msgSend(nil, self, "setLabel:", label) } @(objc_type=Resource, objc_name="setPurgeableState") -Resource_setPurgeableState :: proc(self: ^Resource, state: PurgeableState) -> PurgeableState { +Resource_setPurgeableState :: #force_inline proc(self: ^Resource, state: PurgeableState) -> PurgeableState { return msgSend(PurgeableState, self, "setPurgeableState:", state) } @(objc_type=Resource, objc_name="storageMode") -Resource_storageMode :: proc(self: ^Resource) -> StorageMode { +Resource_storageMode :: #force_inline proc(self: ^Resource) -> StorageMode { return msgSend(StorageMode, self, "storageMode") } @@ -7792,23 +7778,23 @@ Methods: ResourceStateCommandEncoder :: struct { using _: NS.Object } @(objc_type=ResourceStateCommandEncoder, objc_name="updateFence") -ResourceStateCommandEncoder_updateFence :: proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { +ResourceStateCommandEncoder_updateFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_") -ResourceStateCommandEncoder_updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_ :: proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +ResourceStateCommandEncoder_updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { msgSend(nil, self, "updateTextureMapping:mode:indirectBuffer:indirectBufferOffset:", texture, mode, indirectBuffer, indirectBufferOffset) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_region_mipLevel_slice_") -ResourceStateCommandEncoder_updateTextureMapping_mode_region_mipLevel_slice_ :: proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, region: Region, mipLevel: NS.Integer, slice: NS.Integer) { +ResourceStateCommandEncoder_updateTextureMapping_mode_region_mipLevel_slice_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, region: Region, mipLevel: NS.Integer, slice: NS.Integer) { msgSend(nil, self, "updateTextureMapping:mode:region:mipLevel:slice:", texture, mode, region, mipLevel, slice) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMappings") -ResourceStateCommandEncoder_updateTextureMappings :: proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, regions: ^Region, mipLevels: NS.Integer, slices: NS.Integer, numRegions: ^NS.Object) { +ResourceStateCommandEncoder_updateTextureMappings :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, regions: ^Region, mipLevels: NS.Integer, slices: NS.Integer, numRegions: ^NS.Object) { msgSend(nil, self, "updateTextureMappings:mode:regions:mipLevels:slices:numRegions:", texture, mode, regions, mipLevels, slices, numRegions) } @(objc_type=ResourceStateCommandEncoder, objc_name="waitForFence") -ResourceStateCommandEncoder_waitForFence :: proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { +ResourceStateCommandEncoder_waitForFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { msgSend(nil, self, "waitForFence:", fence) } @@ -7826,11 +7812,11 @@ Methods: SamplerState :: struct { using _: NS.Object } @(objc_type=SamplerState, objc_name="device") -SamplerState_device :: proc(self: ^SamplerState) -> ^SamplerState { +SamplerState_device :: #force_inline proc(self: ^SamplerState) -> ^SamplerState { return msgSend(^SamplerState, self, "device") } @(objc_type=SamplerState, objc_name="label") -SamplerState_label :: proc(self: ^SamplerState) -> ^NS.String { +SamplerState_label :: #force_inline proc(self: ^SamplerState) -> ^NS.String { return msgSend(^NS.String, self, "label") } @@ -7850,19 +7836,19 @@ Methods: SharedEvent :: struct { using _: NS.Object } @(objc_type=SharedEvent, objc_name="newSharedEventHandle") -SharedEvent_newSharedEventHandle :: proc(self: ^SharedEvent) -> ^SharedEventHandle { +SharedEvent_newSharedEventHandle :: #force_inline proc(self: ^SharedEvent) -> ^SharedEventHandle { return msgSend(^SharedEventHandle, self, "newSharedEventHandle") } @(objc_type=SharedEvent, objc_name="notifyListener") -SharedEvent_notifyListener :: proc(self: ^SharedEvent, listener: ^SharedEventListener, value: u64, block: SharedEventNotificationBlock) { +SharedEvent_notifyListener :: #force_inline proc(self: ^SharedEvent, listener: ^SharedEventListener, value: u64, block: SharedEventNotificationBlock) { msgSend(nil, self, "notifyListener:atValue:block:", listener, value, block) } @(objc_type=SharedEvent, objc_name="setSignaledValue") -SharedEvent_setSignaledValue :: proc(self: ^SharedEvent, signaledValue: u64) { +SharedEvent_setSignaledValue :: #force_inline proc(self: ^SharedEvent, signaledValue: u64) { msgSend(nil, self, "setSignaledValue:", signaledValue) } @(objc_type=SharedEvent, objc_name="signaledValue") -SharedEvent_signaledValue :: proc(self: ^SharedEvent) -> u64 { +SharedEvent_signaledValue :: #force_inline proc(self: ^SharedEvent) -> u64 { return msgSend(u64, self, "signaledValue") } @@ -7913,143 +7899,143 @@ Methods: Texture :: struct { using _: NS.Object } @(objc_type=Texture, objc_name="allowGPUOptimizedContents") -Texture_allowGPUOptimizedContents :: proc(self: ^Texture) -> BOOL { +Texture_allowGPUOptimizedContents :: #force_inline proc(self: ^Texture) -> BOOL { return msgSend(BOOL, self, "allowGPUOptimizedContents") } @(objc_type=Texture, objc_name="arrayLength") -Texture_arrayLength :: proc(self: ^Texture) -> NS.Integer { +Texture_arrayLength :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "arrayLength") } @(objc_type=Texture, objc_name="buffer") -Texture_buffer :: proc(self: ^Texture) -> ^Texture { +Texture_buffer :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "buffer") } @(objc_type=Texture, objc_name="bufferBytesPerRow") -Texture_bufferBytesPerRow :: proc(self: ^Texture) -> NS.Integer { +Texture_bufferBytesPerRow :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "bufferBytesPerRow") } @(objc_type=Texture, objc_name="bufferOffset") -Texture_bufferOffset :: proc(self: ^Texture) -> NS.Integer { +Texture_bufferOffset :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "bufferOffset") } @(objc_type=Texture, objc_name="depth") -Texture_depth :: proc(self: ^Texture) -> NS.Integer { +Texture_depth :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "depth") } @(objc_type=Texture, objc_name="firstMipmapInTail") -Texture_firstMipmapInTail :: proc(self: ^Texture) -> NS.Integer { +Texture_firstMipmapInTail :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "firstMipmapInTail") } @(objc_type=Texture, objc_name="getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_") -Texture_getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_ :: proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object, region: Region, level: ^NS.Object, slice: ^NS.Object) { +Texture_getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object, region: Region, level: ^NS.Object, slice: ^NS.Object) { msgSend(nil, self, "getBytes:bytesPerRow:bytesPerImage:fromRegion:mipmapLevel:slice:", pixelBytes, bytesPerRow, bytesPerImage, region, level, slice) } @(objc_type=Texture, objc_name="getBytes_bytesPerRow_fromRegion_mipmapLevel_") -Texture_getBytes_bytesPerRow_fromRegion_mipmapLevel_ :: proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, region: Region, level: ^NS.Object) { +Texture_getBytes_bytesPerRow_fromRegion_mipmapLevel_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, region: Region, level: ^NS.Object) { msgSend(nil, self, "getBytes:bytesPerRow:fromRegion:mipmapLevel:", pixelBytes, bytesPerRow, region, level) } @(objc_type=Texture, objc_name="height") -Texture_height :: proc(self: ^Texture) -> NS.Integer { +Texture_height :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "height") } @(objc_type=Texture, objc_name="iosurface") -Texture_iosurface :: proc(self: ^Texture) -> IOSurfaceRef { +Texture_iosurface :: #force_inline proc(self: ^Texture) -> IOSurfaceRef { return msgSend(IOSurfaceRef, self, "iosurface") } @(objc_type=Texture, objc_name="iosurfacePlane") -Texture_iosurfacePlane :: proc(self: ^Texture) -> NS.Integer { +Texture_iosurfacePlane :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "iosurfacePlane") } @(objc_type=Texture, objc_name="isFramebufferOnly") -Texture_isFramebufferOnly :: proc(self: ^Texture) -> BOOL { +Texture_isFramebufferOnly :: #force_inline proc(self: ^Texture) -> BOOL { return msgSend(BOOL, self, "isFramebufferOnly") } @(objc_type=Texture, objc_name="isShareable") -Texture_isShareable :: proc(self: ^Texture) -> BOOL { +Texture_isShareable :: #force_inline proc(self: ^Texture) -> BOOL { return msgSend(BOOL, self, "isShareable") } @(objc_type=Texture, objc_name="isSparse") -Texture_isSparse :: proc(self: ^Texture) -> BOOL { +Texture_isSparse :: #force_inline proc(self: ^Texture) -> BOOL { return msgSend(BOOL, self, "isSparse") } @(objc_type=Texture, objc_name="mipmapLevelCount") -Texture_mipmapLevelCount :: proc(self: ^Texture) -> NS.Integer { +Texture_mipmapLevelCount :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "mipmapLevelCount") } @(objc_type=Texture, objc_name="newRemoteTextureViewForDevice") -Texture_newRemoteTextureViewForDevice :: proc(self: ^Texture, device: ^NS.Object) -> ^Texture { +Texture_newRemoteTextureViewForDevice :: #force_inline proc(self: ^Texture, device: ^NS.Object) -> ^Texture { return msgSend(^Texture, self, "newRemoteTextureViewForDevice:", device) } @(objc_type=Texture, objc_name="newSharedTextureHandle") -Texture_newSharedTextureHandle :: proc(self: ^Texture) -> ^SharedTextureHandle { +Texture_newSharedTextureHandle :: #force_inline proc(self: ^Texture) -> ^SharedTextureHandle { return msgSend(^SharedTextureHandle, self, "newSharedTextureHandle") } @(objc_type=Texture, objc_name="newTextureViewWithPixelFormat") -Texture_newTextureViewWithPixelFormat :: proc(self: ^Texture, pixelFormat: PixelFormat) -> ^Texture { +Texture_newTextureViewWithPixelFormat :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat) -> ^Texture { return msgSend(^Texture, self, "newTextureViewWithPixelFormat:", pixelFormat) } @(objc_type=Texture, objc_name="newTextureViewWithPixelFormat_textureType_levels_slices_") -Texture_newTextureViewWithPixelFormat_textureType_levels_slices_ :: proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range) -> ^Texture { +Texture_newTextureViewWithPixelFormat_textureType_levels_slices_ :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range) -> ^Texture { return msgSend(^Texture, self, "newTextureViewWithPixelFormat:textureType:levels:slices:", pixelFormat, textureType, levelRange, sliceRange) } @(objc_type=Texture, objc_name="newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_") -Texture_newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_ :: proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range, swizzle: TextureSwizzleChannels) -> ^Texture { +Texture_newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_ :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range, swizzle: TextureSwizzleChannels) -> ^Texture { return msgSend(^Texture, self, "newTextureViewWithPixelFormat:textureType:levels:slices:swizzle:", pixelFormat, textureType, levelRange, sliceRange, swizzle) } @(objc_type=Texture, objc_name="parentRelativeLevel") -Texture_parentRelativeLevel :: proc(self: ^Texture) -> NS.Integer { +Texture_parentRelativeLevel :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "parentRelativeLevel") } @(objc_type=Texture, objc_name="parentRelativeSlice") -Texture_parentRelativeSlice :: proc(self: ^Texture) -> NS.Integer { +Texture_parentRelativeSlice :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "parentRelativeSlice") } @(objc_type=Texture, objc_name="parentTexture") -Texture_parentTexture :: proc(self: ^Texture) -> ^Texture { +Texture_parentTexture :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "parentTexture") } @(objc_type=Texture, objc_name="pixelFormat") -Texture_pixelFormat :: proc(self: ^Texture) -> PixelFormat { +Texture_pixelFormat :: #force_inline proc(self: ^Texture) -> PixelFormat { return msgSend(PixelFormat, self, "pixelFormat") } @(objc_type=Texture, objc_name="remoteStorageTexture") -Texture_remoteStorageTexture :: proc(self: ^Texture) -> ^Texture { +Texture_remoteStorageTexture :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "remoteStorageTexture") } @(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_") -Texture_replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_ :: proc(self: ^Texture, region: Region, level: ^NS.Object, slice: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object) { +Texture_replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_ :: #force_inline proc(self: ^Texture, region: Region, level: ^NS.Object, slice: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object) { msgSend(nil, self, "replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:", region, level, slice, pixelBytes, bytesPerRow, bytesPerImage) } @(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_withBytes_bytesPerRow_") -Texture_replaceRegion_mipmapLevel_withBytes_bytesPerRow_ :: proc(self: ^Texture, region: Region, level: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object) { +Texture_replaceRegion_mipmapLevel_withBytes_bytesPerRow_ :: #force_inline proc(self: ^Texture, region: Region, level: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object) { msgSend(nil, self, "replaceRegion:mipmapLevel:withBytes:bytesPerRow:", region, level, pixelBytes, bytesPerRow) } @(objc_type=Texture, objc_name="rootResource") -Texture_rootResource :: proc(self: ^Texture) -> ^Texture { +Texture_rootResource :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "rootResource") } @(objc_type=Texture, objc_name="sampleCount") -Texture_sampleCount :: proc(self: ^Texture) -> NS.Integer { +Texture_sampleCount :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "sampleCount") } @(objc_type=Texture, objc_name="swizzle") -Texture_swizzle :: proc(self: ^Texture) -> TextureSwizzleChannels { +Texture_swizzle :: #force_inline proc(self: ^Texture) -> TextureSwizzleChannels { return msgSend(TextureSwizzleChannels, self, "swizzle") } @(objc_type=Texture, objc_name="tailSizeInBytes") -Texture_tailSizeInBytes :: proc(self: ^Texture) -> NS.Integer { +Texture_tailSizeInBytes :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "tailSizeInBytes") } @(objc_type=Texture, objc_name="textureType") -Texture_textureType :: proc(self: ^Texture) -> TextureType { +Texture_textureType :: #force_inline proc(self: ^Texture) -> TextureType { return msgSend(TextureType, self, "textureType") } @(objc_type=Texture, objc_name="usage") -Texture_usage :: proc(self: ^Texture) -> TextureUsage { +Texture_usage :: #force_inline proc(self: ^Texture) -> TextureUsage { return msgSend(TextureUsage, self, "usage") } @(objc_type=Texture, objc_name="width") -Texture_width :: proc(self: ^Texture) -> NS.Integer { +Texture_width :: #force_inline proc(self: ^Texture) -> NS.Integer { return msgSend(NS.Integer, self, "width") } @@ -8067,10 +8053,10 @@ Methods: VisibleFunctionTable :: struct { using _: NS.Object } @(objc_type=VisibleFunctionTable, objc_name="setFunction") -VisibleFunctionTable_setFunction :: proc(self: ^VisibleFunctionTable, function: ^NS.Object, index: ^NS.Object) { +VisibleFunctionTable_setFunction :: #force_inline proc(self: ^VisibleFunctionTable, function: ^NS.Object, index: ^NS.Object) { msgSend(nil, self, "setFunction:atIndex:", function, index) } @(objc_type=VisibleFunctionTable, objc_name="setFunctions") -VisibleFunctionTable_setFunctions :: proc(self: ^VisibleFunctionTable, functions: ^^NS.Object, range: NS.Range) { +VisibleFunctionTable_setFunctions :: #force_inline proc(self: ^VisibleFunctionTable, functions: ^^NS.Object, range: NS.Range) { msgSend(nil, self, "setFunctions:withRange:", functions, range) } diff --git a/vendor/Metal/MetalProcedures.odin b/vendor/Metal/MetalProcedures.odin new file mode 100644 index 000000000..120396b5d --- /dev/null +++ b/vendor/Metal/MetalProcedures.odin @@ -0,0 +1,14 @@ +package objc_Metal + +import NS "core:sys/darwin/Foundation" + +@(require) +foreign import "system:Metal.framework" + +@(default_calling_convention="c", link_prefix="MTL") +foreign Metal { + CopyAllDevices :: proc() -> ^NS.Array --- + CopyAllDevicesWithObserver :: proc(observer: ^^NS.Object, handler: DeviceNotificationHandler) -> ^NS.Array --- + CreateSystemDefaultDevice :: proc() -> ^NS.Object --- + RemoveDeviceObserver :: proc(observer: ^NS.Object) --- +} \ No newline at end of file From ff5d6a994bbaf379729a56e151bb888ce12fa975 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 17:59:40 +0000 Subject: [PATCH 0137/1052] Move vendor:Metal to core:sys/darwin/Metal --- {vendor => core/sys/darwin}/Metal/MetalClasses.odin | 0 {vendor => core/sys/darwin}/Metal/MetalEnums.odin | 4 ++-- {vendor => core/sys/darwin}/Metal/MetalErrors.odin | 0 {vendor => core/sys/darwin}/Metal/MetalProcedures.odin | 0 {vendor => core/sys/darwin}/Metal/MetalTypes.odin | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename {vendor => core/sys/darwin}/Metal/MetalClasses.odin (100%) rename {vendor => core/sys/darwin}/Metal/MetalEnums.odin (99%) rename {vendor => core/sys/darwin}/Metal/MetalErrors.odin (100%) rename {vendor => core/sys/darwin}/Metal/MetalProcedures.odin (100%) rename {vendor => core/sys/darwin}/Metal/MetalTypes.odin (100%) diff --git a/vendor/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin similarity index 100% rename from vendor/Metal/MetalClasses.odin rename to core/sys/darwin/Metal/MetalClasses.odin diff --git a/vendor/Metal/MetalEnums.odin b/core/sys/darwin/Metal/MetalEnums.odin similarity index 99% rename from vendor/Metal/MetalEnums.odin rename to core/sys/darwin/Metal/MetalEnums.odin index a0bd7b970..0e3aec321 100644 --- a/vendor/Metal/MetalEnums.odin +++ b/core/sys/darwin/Metal/MetalEnums.odin @@ -197,7 +197,7 @@ CommandEncoderErrorState :: enum NS.Integer { CommandBufferHandler :: distinct rawptr DispatchType :: enum NS.UInteger { - Serial = 0, + Serial = 0, Concurrent = 1, } @@ -220,7 +220,7 @@ BarrierScope :: distinct bit_set[BarrierScopeFlag; NS.UInteger] CounterSampleBufferError :: enum NS.Integer { OutOfMemory = 0, - Invalid = 1, + Invalid = 1, } CompareFunction :: enum NS.UInteger { diff --git a/vendor/Metal/MetalErrors.odin b/core/sys/darwin/Metal/MetalErrors.odin similarity index 100% rename from vendor/Metal/MetalErrors.odin rename to core/sys/darwin/Metal/MetalErrors.odin diff --git a/vendor/Metal/MetalProcedures.odin b/core/sys/darwin/Metal/MetalProcedures.odin similarity index 100% rename from vendor/Metal/MetalProcedures.odin rename to core/sys/darwin/Metal/MetalProcedures.odin diff --git a/vendor/Metal/MetalTypes.odin b/core/sys/darwin/Metal/MetalTypes.odin similarity index 100% rename from vendor/Metal/MetalTypes.odin rename to core/sys/darwin/Metal/MetalTypes.odin From 5fe9aa919b97dcfac7db3b49a8e339ec45f98a6b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 21:24:28 +0000 Subject: [PATCH 0138/1052] Correct types in methods --- core/sys/darwin/Metal/MetalClasses.odin | 1483 ++++++++++---------- core/sys/darwin/Metal/MetalProcedures.odin | 6 +- core/sys/darwin/Metal/MetalTypes.odin | 4 + examples/objc/objc_main.odin | 8 + 4 files changed, 793 insertions(+), 708 deletions(-) create mode 100644 examples/objc/objc_main.odin diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 4f788cb55..5695cbb6f 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -37,40 +37,88 @@ AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: #force_i return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, self, "boundingBoxBuffer") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxBufferOffset") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "boundingBoxBufferOffset") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxBufferOffset") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxCount") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "boundingBoxCount") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxCount") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxStride") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "boundingBoxStride") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxStride") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="descriptor") AccelerationStructureBoundingBoxGeometryDescriptor_descriptor :: #force_inline proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, AccelerationStructureBoundingBoxGeometryDescriptor, "descriptor") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxBuffer") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBuffer :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBuffer: ^NS.Object) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBuffer :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBuffer: ^Buffer) { msgSend(nil, self, "setBoundingBoxBuffer:", boundingBoxBuffer) } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxBufferOffset") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBufferOffset :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBufferOffset: NS.Integer) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxBufferOffset :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxBufferOffset: NS.UInteger) { msgSend(nil, self, "setBoundingBoxBufferOffset:", boundingBoxBufferOffset) } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxCount") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxCount :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxCount: NS.Integer) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxCount :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxCount: NS.UInteger) { msgSend(nil, self, "setBoundingBoxCount:", boundingBoxCount) } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxStride") -AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxStride :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxStride: NS.Integer) { +AccelerationStructureBoundingBoxGeometryDescriptor_setBoundingBoxStride :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor, boundingBoxStride: NS.UInteger) { msgSend(nil, self, "setBoundingBoxStride:", boundingBoxStride) } //////////////////////////////////////////////////////////////////////////////// +/* +Class: + MotionKeyframeData +Class Methods: + alloc + data +Methods: + init + buffer + setBuffer + offset + setOffset +*/ + +@(objc_class="MTLMotionKeyframeData") +MotionKeyframeData :: struct { using _: NS.Object } + +@(objc_type=MotionKeyframeData, objc_class_name="alloc") +MotionKeyframeData_alloc :: #force_inline proc() -> ^MotionKeyframeData { + return msgSend(^MotionKeyframeData, MotionKeyframeData, "alloc") +} +@(objc_type=MotionKeyframeData, objc_class_name="data") +MotionKeyframeData_data :: #force_inline proc() -> ^MotionKeyframeData { + return msgSend(^MotionKeyframeData, MotionKeyframeData, "data") +} +@(objc_type=MotionKeyframeData, objc_class_name="init") +MotionKeyframeData_init :: #force_inline proc(self: ^MotionKeyframeData) -> ^MotionKeyframeData { + return msgSend(^MotionKeyframeData, self, "init") +} +@(objc_type=MotionKeyframeData, objc_class_name="buffer") +MotionKeyframeData_buffer :: #force_inline proc(self: ^MotionKeyframeData) -> ^Buffer { + return msgSend(^Buffer, self, "buffer") +} +@(objc_type=MotionKeyframeData, objc_class_name="setBuffer") +MotionKeyframeData_setBuffer :: #force_inline proc(self: ^MotionKeyframeData, buffer: ^Buffer) { + msgSend(nil, self, "setBuffer:", buffer) +} +@(objc_type=MotionKeyframeData, objc_class_name="offset") +MotionKeyframeData_offset :: #force_inline proc(self: ^MotionKeyframeData) -> NS.UInteger { + return msgSend(NS.UInteger, self, "offset") +} +@(objc_type=MotionKeyframeData, objc_class_name="setOffset") +MotionKeyframeData_setOffset :: #force_inline proc(self: ^MotionKeyframeData, offset: NS.UInteger) { + msgSend(nil, self, "setOffset:", offset) +} + +//////////////////////////////////////////////////////////////////////////////// + /* Class: AccelerationStructureDescriptor @@ -133,8 +181,8 @@ AccelerationStructureGeometryDescriptor_allowDuplicateIntersectionFunctionInvoca return msgSend(BOOL, self, "allowDuplicateIntersectionFunctionInvocation") } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="intersectionFunctionTableOffset") -AccelerationStructureGeometryDescriptor_intersectionFunctionTableOffset :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "intersectionFunctionTableOffset") +AccelerationStructureGeometryDescriptor_intersectionFunctionTableOffset :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "intersectionFunctionTableOffset") } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="opaque") AccelerationStructureGeometryDescriptor_opaque :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor) -> BOOL { @@ -145,7 +193,7 @@ AccelerationStructureGeometryDescriptor_setAllowDuplicateIntersectionFunctionInv msgSend(nil, self, "setAllowDuplicateIntersectionFunctionInvocation:", allowDuplicateIntersectionFunctionInvocation) } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setIntersectionFunctionTableOffset") -AccelerationStructureGeometryDescriptor_setIntersectionFunctionTableOffset :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor, intersectionFunctionTableOffset: NS.Integer) { +AccelerationStructureGeometryDescriptor_setIntersectionFunctionTableOffset :: #force_inline proc(self: ^AccelerationStructureGeometryDescriptor, intersectionFunctionTableOffset: NS.UInteger) { msgSend(nil, self, "setIntersectionFunctionTableOffset:", intersectionFunctionTableOffset) } @(objc_type=AccelerationStructureGeometryDescriptor, objc_name="setOpaque") @@ -198,19 +246,19 @@ AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: #force_inline pro return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "indexBuffer") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "indexBufferOffset") +AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "indexBufferOffset") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexType") AccelerationStructureTriangleGeometryDescriptor_indexType :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> IndexType { return msgSend(IndexType, self, "indexType") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexBuffer") -AccelerationStructureTriangleGeometryDescriptor_setIndexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBuffer: ^NS.Object) { +AccelerationStructureTriangleGeometryDescriptor_setIndexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBuffer: ^Buffer) { msgSend(nil, self, "setIndexBuffer:", indexBuffer) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_setIndexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBufferOffset: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setIndexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, indexBufferOffset: NS.UInteger) { msgSend(nil, self, "setIndexBufferOffset:", indexBufferOffset) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setIndexType") @@ -218,36 +266,36 @@ AccelerationStructureTriangleGeometryDescriptor_setIndexType :: #force_inline pr msgSend(nil, self, "setIndexType:", indexType) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setTriangleCount") -AccelerationStructureTriangleGeometryDescriptor_setTriangleCount :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, triangleCount: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setTriangleCount :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, triangleCount: NS.UInteger) { msgSend(nil, self, "setTriangleCount:", triangleCount) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexBuffer") -AccelerationStructureTriangleGeometryDescriptor_setVertexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBuffer: ^NS.Object) { +AccelerationStructureTriangleGeometryDescriptor_setVertexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBuffer: ^Buffer) { msgSend(nil, self, "setVertexBuffer:", vertexBuffer) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_setVertexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBufferOffset: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setVertexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexBufferOffset: NS.UInteger) { msgSend(nil, self, "setVertexBufferOffset:", vertexBufferOffset) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="setVertexStride") -AccelerationStructureTriangleGeometryDescriptor_setVertexStride :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexStride: NS.Integer) { +AccelerationStructureTriangleGeometryDescriptor_setVertexStride :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor, vertexStride: NS.UInteger) { msgSend(nil, self, "setVertexStride:", vertexStride) } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="triangleCount") -AccelerationStructureTriangleGeometryDescriptor_triangleCount :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "triangleCount") +AccelerationStructureTriangleGeometryDescriptor_triangleCount :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "triangleCount") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBuffer") AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "vertexBuffer") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBufferOffset") -AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "vertexBufferOffset") +AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "vertexBufferOffset") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexStride") -AccelerationStructureTriangleGeometryDescriptor_vertexStride :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "vertexStride") +AccelerationStructureTriangleGeometryDescriptor_vertexStride :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "vertexStride") } //////////////////////////////////////////////////////////////////////////////// @@ -292,16 +340,16 @@ Argument_access :: #force_inline proc(self: ^Argument) -> ArgumentAccess { return msgSend(ArgumentAccess, self, "access") } @(objc_type=Argument, objc_name="arrayLength") -Argument_arrayLength :: #force_inline proc(self: ^Argument) -> NS.Integer { - return msgSend(NS.Integer, self, "arrayLength") +Argument_arrayLength :: #force_inline proc(self: ^Argument) -> NS.UInteger { + return msgSend(NS.UInteger, self, "arrayLength") } @(objc_type=Argument, objc_name="bufferAlignment") -Argument_bufferAlignment :: #force_inline proc(self: ^Argument) -> NS.Integer { - return msgSend(NS.Integer, self, "bufferAlignment") +Argument_bufferAlignment :: #force_inline proc(self: ^Argument) -> NS.UInteger { + return msgSend(NS.UInteger, self, "bufferAlignment") } @(objc_type=Argument, objc_name="bufferDataSize") -Argument_bufferDataSize :: #force_inline proc(self: ^Argument) -> NS.Integer { - return msgSend(NS.Integer, self, "bufferDataSize") +Argument_bufferDataSize :: #force_inline proc(self: ^Argument) -> NS.UInteger { + return msgSend(NS.UInteger, self, "bufferDataSize") } @(objc_type=Argument, objc_name="bufferDataType") Argument_bufferDataType :: #force_inline proc(self: ^Argument) -> DataType { @@ -316,8 +364,8 @@ Argument_bufferStructType :: #force_inline proc(self: ^Argument) -> ^StructType return msgSend(^StructType, self, "bufferStructType") } @(objc_type=Argument, objc_name="index") -Argument_index :: #force_inline proc(self: ^Argument) -> NS.Integer { - return msgSend(NS.Integer, self, "index") +Argument_index :: #force_inline proc(self: ^Argument) -> NS.UInteger { + return msgSend(NS.UInteger, self, "index") } @(objc_type=Argument, objc_name="isActive") Argument_isActive :: #force_inline proc(self: ^Argument) -> BOOL { @@ -340,12 +388,12 @@ Argument_textureType :: #force_inline proc(self: ^Argument) -> TextureType { return msgSend(TextureType, self, "textureType") } @(objc_type=Argument, objc_name="threadgroupMemoryAlignment") -Argument_threadgroupMemoryAlignment :: #force_inline proc(self: ^Argument) -> NS.Integer { - return msgSend(NS.Integer, self, "threadgroupMemoryAlignment") +Argument_threadgroupMemoryAlignment :: #force_inline proc(self: ^Argument) -> NS.UInteger { + return msgSend(NS.UInteger, self, "threadgroupMemoryAlignment") } @(objc_type=Argument, objc_name="threadgroupMemoryDataSize") -Argument_threadgroupMemoryDataSize :: #force_inline proc(self: ^Argument) -> NS.Integer { - return msgSend(NS.Integer, self, "threadgroupMemoryDataSize") +Argument_threadgroupMemoryDataSize :: #force_inline proc(self: ^Argument) -> NS.UInteger { + return msgSend(NS.UInteger, self, "threadgroupMemoryDataSize") } @(objc_type=Argument, objc_name="type") Argument_type :: #force_inline proc(self: ^Argument) -> ArgumentType { @@ -395,31 +443,31 @@ ArgumentDescriptor_argumentDescriptor :: #force_inline proc() -> ^ArgumentDescri return msgSend(^ArgumentDescriptor, ArgumentDescriptor, "argumentDescriptor") } @(objc_type=ArgumentDescriptor, objc_name="arrayLength") -ArgumentDescriptor_arrayLength :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "arrayLength") +ArgumentDescriptor_arrayLength :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "arrayLength") } @(objc_type=ArgumentDescriptor, objc_name="constantBlockAlignment") -ArgumentDescriptor_constantBlockAlignment :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "constantBlockAlignment") +ArgumentDescriptor_constantBlockAlignment :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "constantBlockAlignment") } @(objc_type=ArgumentDescriptor, objc_name="dataType") ArgumentDescriptor_dataType :: #force_inline proc(self: ^ArgumentDescriptor) -> DataType { return msgSend(DataType, self, "dataType") } @(objc_type=ArgumentDescriptor, objc_name="index") -ArgumentDescriptor_index :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "index") +ArgumentDescriptor_index :: #force_inline proc(self: ^ArgumentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "index") } @(objc_type=ArgumentDescriptor, objc_name="setAccess") ArgumentDescriptor_setAccess :: #force_inline proc(self: ^ArgumentDescriptor, access: ArgumentAccess) { msgSend(nil, self, "setAccess:", access) } @(objc_type=ArgumentDescriptor, objc_name="setArrayLength") -ArgumentDescriptor_setArrayLength :: #force_inline proc(self: ^ArgumentDescriptor, arrayLength: NS.Integer) { +ArgumentDescriptor_setArrayLength :: #force_inline proc(self: ^ArgumentDescriptor, arrayLength: NS.UInteger) { msgSend(nil, self, "setArrayLength:", arrayLength) } @(objc_type=ArgumentDescriptor, objc_name="setConstantBlockAlignment") -ArgumentDescriptor_setConstantBlockAlignment :: #force_inline proc(self: ^ArgumentDescriptor, constantBlockAlignment: NS.Integer) { +ArgumentDescriptor_setConstantBlockAlignment :: #force_inline proc(self: ^ArgumentDescriptor, constantBlockAlignment: NS.UInteger) { msgSend(nil, self, "setConstantBlockAlignment:", constantBlockAlignment) } @(objc_type=ArgumentDescriptor, objc_name="setDataType") @@ -427,7 +475,7 @@ ArgumentDescriptor_setDataType :: #force_inline proc(self: ^ArgumentDescriptor, msgSend(nil, self, "setDataType:", dataType) } @(objc_type=ArgumentDescriptor, objc_name="setIndex") -ArgumentDescriptor_setIndex :: #force_inline proc(self: ^ArgumentDescriptor, index: NS.Integer) { +ArgumentDescriptor_setIndex :: #force_inline proc(self: ^ArgumentDescriptor, index: NS.UInteger) { msgSend(nil, self, "setIndex:", index) } @(objc_type=ArgumentDescriptor, objc_name="setTextureType") @@ -469,12 +517,12 @@ ArrayType_init :: #force_inline proc(self: ^ArrayType) -> ^ArrayType { return msgSend(^ArrayType, self, "init") } @(objc_type=ArrayType, objc_name="argumentIndexStride") -ArrayType_argumentIndexStride :: #force_inline proc(self: ^ArrayType) -> NS.Integer { - return msgSend(NS.Integer, self, "argumentIndexStride") +ArrayType_argumentIndexStride :: #force_inline proc(self: ^ArrayType) -> NS.UInteger { + return msgSend(NS.UInteger, self, "argumentIndexStride") } @(objc_type=ArrayType, objc_name="arrayLength") -ArrayType_arrayLength :: #force_inline proc(self: ^ArrayType) -> NS.Integer { - return msgSend(NS.Integer, self, "arrayLength") +ArrayType_arrayLength :: #force_inline proc(self: ^ArrayType) -> NS.UInteger { + return msgSend(NS.UInteger, self, "arrayLength") } @(objc_type=ArrayType, objc_name="elementArrayType") ArrayType_elementArrayType :: #force_inline proc(self: ^ArrayType) -> ^ArrayType { @@ -497,8 +545,8 @@ ArrayType_elementType :: #force_inline proc(self: ^ArrayType) -> DataType { return msgSend(DataType, self, "elementType") } @(objc_type=ArrayType, objc_name="stride") -ArrayType_stride :: #force_inline proc(self: ^ArrayType) -> NS.Integer { - return msgSend(NS.Integer, self, "stride") +ArrayType_stride :: #force_inline proc(self: ^ArrayType) -> NS.UInteger { + return msgSend(NS.UInteger, self, "stride") } //////////////////////////////////////////////////////////////////////////////// @@ -529,8 +577,8 @@ Attribute_init :: #force_inline proc(self: ^Attribute) -> ^Attribute { return msgSend(^Attribute, self, "init") } @(objc_type=Attribute, objc_name="attributeIndex") -Attribute_attributeIndex :: #force_inline proc(self: ^Attribute) -> NS.Integer { - return msgSend(NS.Integer, self, "attributeIndex") +Attribute_attributeIndex :: #force_inline proc(self: ^Attribute) -> NS.UInteger { + return msgSend(NS.UInteger, self, "attributeIndex") } @(objc_type=Attribute, objc_name="attributeType") Attribute_attributeType :: #force_inline proc(self: ^Attribute) -> DataType { @@ -581,19 +629,19 @@ AttributeDescriptor_init :: #force_inline proc(self: ^AttributeDescriptor) -> ^A return msgSend(^AttributeDescriptor, self, "init") } @(objc_type=AttributeDescriptor, objc_name="bufferIndex") -AttributeDescriptor_bufferIndex :: #force_inline proc(self: ^AttributeDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "bufferIndex") +AttributeDescriptor_bufferIndex :: #force_inline proc(self: ^AttributeDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "bufferIndex") } @(objc_type=AttributeDescriptor, objc_name="format") AttributeDescriptor_format :: #force_inline proc(self: ^AttributeDescriptor) -> AttributeFormat { return msgSend(AttributeFormat, self, "format") } @(objc_type=AttributeDescriptor, objc_name="offset") -AttributeDescriptor_offset :: #force_inline proc(self: ^AttributeDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "offset") +AttributeDescriptor_offset :: #force_inline proc(self: ^AttributeDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "offset") } @(objc_type=AttributeDescriptor, objc_name="setBufferIndex") -AttributeDescriptor_setBufferIndex :: #force_inline proc(self: ^AttributeDescriptor, bufferIndex: NS.Integer) { +AttributeDescriptor_setBufferIndex :: #force_inline proc(self: ^AttributeDescriptor, bufferIndex: NS.UInteger) { msgSend(nil, self, "setBufferIndex:", bufferIndex) } @(objc_type=AttributeDescriptor, objc_name="setFormat") @@ -601,7 +649,7 @@ AttributeDescriptor_setFormat :: #force_inline proc(self: ^AttributeDescriptor, msgSend(nil, self, "setFormat:", format) } @(objc_type=AttributeDescriptor, objc_name="setOffset") -AttributeDescriptor_setOffset :: #force_inline proc(self: ^AttributeDescriptor, offset: NS.Integer) { +AttributeDescriptor_setOffset :: #force_inline proc(self: ^AttributeDescriptor, offset: NS.UInteger) { msgSend(nil, self, "setOffset:", offset) } @@ -629,11 +677,11 @@ AttributeDescriptorArray_init :: #force_inline proc(self: ^AttributeDescriptorAr return msgSend(^AttributeDescriptorArray, self, "init") } @(objc_type=AttributeDescriptorArray, objc_name="objectAtIndexedSubscript") -AttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^AttributeDescriptorArray, index: ^NS.Object) -> ^AttributeDescriptor { +AttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^AttributeDescriptorArray, index: NS.UInteger) -> ^AttributeDescriptor { return msgSend(^AttributeDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=AttributeDescriptorArray, objc_name="setObject") -AttributeDescriptorArray_setObject :: #force_inline proc(self: ^AttributeDescriptorArray, attributeDesc: ^AttributeDescriptor, index: ^NS.Object) { +AttributeDescriptorArray_setObject :: #force_inline proc(self: ^AttributeDescriptorArray, attributeDesc: ^AttributeDescriptor, index: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attributeDesc, index) } @@ -729,28 +777,28 @@ BlitPassSampleBufferAttachmentDescriptor_init :: #force_inline proc(self: ^BlitP return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") +BlitPassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { +BlitPassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -BlitPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +BlitPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, sampleBuffer: ^Buffer) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { +BlitPassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") -BlitPassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") +BlitPassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "startOfEncoderSampleIndex") } //////////////////////////////////////////////////////////////////////////////// @@ -777,11 +825,11 @@ BlitPassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^ return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -BlitPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^BlitPassSampleBufferAttachmentDescriptor { +BlitPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -BlitPassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachment: ^BlitPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +BlitPassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachment: ^BlitPassSampleBufferAttachmentDescriptor, attachmentIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -817,11 +865,11 @@ BufferLayoutDescriptor_setStepFunction :: #force_inline proc(self: ^BufferLayout msgSend(nil, self, "setStepFunction:", stepFunction) } @(objc_type=BufferLayoutDescriptor, objc_name="setStepRate") -BufferLayoutDescriptor_setStepRate :: #force_inline proc(self: ^BufferLayoutDescriptor, stepRate: NS.Integer) { +BufferLayoutDescriptor_setStepRate :: #force_inline proc(self: ^BufferLayoutDescriptor, stepRate: NS.UInteger) { msgSend(nil, self, "setStepRate:", stepRate) } @(objc_type=BufferLayoutDescriptor, objc_name="setStride") -BufferLayoutDescriptor_setStride :: #force_inline proc(self: ^BufferLayoutDescriptor, stride: NS.Integer) { +BufferLayoutDescriptor_setStride :: #force_inline proc(self: ^BufferLayoutDescriptor, stride: NS.UInteger) { msgSend(nil, self, "setStride:", stride) } @(objc_type=BufferLayoutDescriptor, objc_name="stepFunction") @@ -829,12 +877,12 @@ BufferLayoutDescriptor_stepFunction :: #force_inline proc(self: ^BufferLayoutDes return msgSend(StepFunction, self, "stepFunction") } @(objc_type=BufferLayoutDescriptor, objc_name="stepRate") -BufferLayoutDescriptor_stepRate :: #force_inline proc(self: ^BufferLayoutDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "stepRate") +BufferLayoutDescriptor_stepRate :: #force_inline proc(self: ^BufferLayoutDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "stepRate") } @(objc_type=BufferLayoutDescriptor, objc_name="stride") -BufferLayoutDescriptor_stride :: #force_inline proc(self: ^BufferLayoutDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "stride") +BufferLayoutDescriptor_stride :: #force_inline proc(self: ^BufferLayoutDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "stride") } //////////////////////////////////////////////////////////////////////////////// @@ -861,11 +909,11 @@ BufferLayoutDescriptorArray_init :: #force_inline proc(self: ^BufferLayoutDescri return msgSend(^BufferLayoutDescriptorArray, self, "init") } @(objc_type=BufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") -BufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BufferLayoutDescriptorArray, index: ^NS.Object) -> ^BufferLayoutDescriptor { +BufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BufferLayoutDescriptorArray, index: NS.UInteger) -> ^BufferLayoutDescriptor { return msgSend(^BufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=BufferLayoutDescriptorArray, objc_name="setObject") -BufferLayoutDescriptorArray_setObject :: #force_inline proc(self: ^BufferLayoutDescriptorArray, bufferDesc: ^BufferLayoutDescriptor, index: ^NS.Object) { +BufferLayoutDescriptorArray_setObject :: #force_inline proc(self: ^BufferLayoutDescriptorArray, bufferDesc: ^BufferLayoutDescriptor, index: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", bufferDesc, index) } @@ -909,7 +957,7 @@ CaptureDescriptor_outputURL :: #force_inline proc(self: ^CaptureDescriptor) -> ^ return msgSend(^NS.URL, self, "outputURL") } @(objc_type=CaptureDescriptor, objc_name="setCaptureObject") -CaptureDescriptor_setCaptureObject :: #force_inline proc(self: ^CaptureDescriptor, captureObject: ^NS.Object) { +CaptureDescriptor_setCaptureObject :: #force_inline proc(self: ^CaptureDescriptor, captureObject: id) { msgSend(nil, self, "setCaptureObject:", captureObject) } @(objc_type=CaptureDescriptor, objc_name="setDestination") @@ -963,15 +1011,15 @@ CaptureManager_isCapturing :: #force_inline proc(self: ^CaptureManager) -> BOOL return msgSend(BOOL, self, "isCapturing") } @(objc_type=CaptureManager, objc_name="newCaptureScopeWithCommandQueue") -CaptureManager_newCaptureScopeWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^NS.Object) -> ^CaptureManager { +CaptureManager_newCaptureScopeWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^CommandQueue) -> ^CaptureManager { return msgSend(^CaptureManager, self, "newCaptureScopeWithCommandQueue:", commandQueue) } @(objc_type=CaptureManager, objc_name="newCaptureScopeWithDevice") -CaptureManager_newCaptureScopeWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^NS.Object) -> ^CaptureManager { +CaptureManager_newCaptureScopeWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^Device) -> ^CaptureManager { return msgSend(^CaptureManager, self, "newCaptureScopeWithDevice:", device) } @(objc_type=CaptureManager, objc_name="setDefaultCaptureScope") -CaptureManager_setDefaultCaptureScope :: #force_inline proc(self: ^CaptureManager, defaultCaptureScope: ^NS.Object) { +CaptureManager_setDefaultCaptureScope :: #force_inline proc(self: ^CaptureManager, defaultCaptureScope: ^CaptureScope) { msgSend(nil, self, "setDefaultCaptureScope:", defaultCaptureScope) } @(objc_type=CaptureManager, objc_class_name="sharedCaptureManager") @@ -979,19 +1027,20 @@ CaptureManager_sharedCaptureManager :: #force_inline proc() -> ^CaptureManager { return msgSend(^CaptureManager, CaptureManager, "sharedCaptureManager") } @(objc_type=CaptureManager, objc_name="startCaptureWithCommandQueue") -CaptureManager_startCaptureWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^NS.Object) { +CaptureManager_startCaptureWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^CommandQueue) { msgSend(nil, self, "startCaptureWithCommandQueue:", commandQueue) } @(objc_type=CaptureManager, objc_name="startCaptureWithDescriptor") -CaptureManager_startCaptureWithDescriptor :: #force_inline proc(self: ^CaptureManager, descriptor: ^CaptureDescriptor, error: ^^NS.Error ) -> BOOL { - return msgSend(BOOL, self, "startCaptureWithDescriptor:error:", descriptor, error) +CaptureManager_startCaptureWithDescriptor :: #force_inline proc(self: ^CaptureManager, descriptor: ^CaptureDescriptor) -> (ok: bool, error: ^NS.Error) { + ok = msgSend(BOOL, self, "startCaptureWithDescriptor:error:", descriptor, &error) + return } @(objc_type=CaptureManager, objc_name="startCaptureWithDevice") -CaptureManager_startCaptureWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^NS.Object) { +CaptureManager_startCaptureWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^Device) { msgSend(nil, self, "startCaptureWithDevice:", device) } @(objc_type=CaptureManager, objc_name="startCaptureWithScope") -CaptureManager_startCaptureWithScope :: #force_inline proc(self: ^CaptureManager, captureScope: ^NS.Object) { +CaptureManager_startCaptureWithScope :: #force_inline proc(self: ^CaptureManager, captureScope: ^CaptureScope) { msgSend(nil, self, "startCaptureWithScope:", captureScope) } @(objc_type=CaptureManager, objc_name="stopCapture") @@ -1207,28 +1256,28 @@ ComputePassSampleBufferAttachmentDescriptor_init :: #force_inline proc(self: ^Co return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") +ComputePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { +ComputePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -ComputePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +ComputePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, sampleBuffer: ^Buffer) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { +ComputePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") -ComputePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") +ComputePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "startOfEncoderSampleIndex") } //////////////////////////////////////////////////////////////////////////////// @@ -1255,11 +1304,11 @@ ComputePassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -ComputePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ComputePassSampleBufferAttachmentDescriptor { +ComputePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -ComputePassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachment: ^ComputePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +ComputePassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachment: ^ComputePassSampleBufferAttachmentDescriptor, attachmentIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -1333,12 +1382,12 @@ ComputePipelineDescriptor_linkedFunctions :: #force_inline proc(self: ^ComputePi return msgSend(^LinkedFunctions, self, "linkedFunctions") } @(objc_type=ComputePipelineDescriptor, objc_name="maxCallStackDepth") -ComputePipelineDescriptor_maxCallStackDepth :: #force_inline proc(self: ^ComputePipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxCallStackDepth") +ComputePipelineDescriptor_maxCallStackDepth :: #force_inline proc(self: ^ComputePipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxCallStackDepth") } @(objc_type=ComputePipelineDescriptor, objc_name="maxTotalThreadsPerThreadgroup") -ComputePipelineDescriptor_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +ComputePipelineDescriptor_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=ComputePipelineDescriptor, objc_name="reset") ComputePipelineDescriptor_reset :: #force_inline proc(self: ^ComputePipelineDescriptor) { @@ -1349,7 +1398,7 @@ ComputePipelineDescriptor_setBinaryArchives :: #force_inline proc(self: ^Compute msgSend(nil, self, "setBinaryArchives:", binaryArchives) } @(objc_type=ComputePipelineDescriptor, objc_name="setComputeFunction") -ComputePipelineDescriptor_setComputeFunction :: #force_inline proc(self: ^ComputePipelineDescriptor, computeFunction: ^NS.Object) { +ComputePipelineDescriptor_setComputeFunction :: #force_inline proc(self: ^ComputePipelineDescriptor, computeFunction: ^Function) { msgSend(nil, self, "setComputeFunction:", computeFunction) } @(objc_type=ComputePipelineDescriptor, objc_name="setInsertLibraries") @@ -1365,11 +1414,11 @@ ComputePipelineDescriptor_setLinkedFunctions :: #force_inline proc(self: ^Comput msgSend(nil, self, "setLinkedFunctions:", linkedFunctions) } @(objc_type=ComputePipelineDescriptor, objc_name="setMaxCallStackDepth") -ComputePipelineDescriptor_setMaxCallStackDepth :: #force_inline proc(self: ^ComputePipelineDescriptor, maxCallStackDepth: NS.Integer) { +ComputePipelineDescriptor_setMaxCallStackDepth :: #force_inline proc(self: ^ComputePipelineDescriptor, maxCallStackDepth: NS.UInteger) { msgSend(nil, self, "setMaxCallStackDepth:", maxCallStackDepth) } @(objc_type=ComputePipelineDescriptor, objc_name="setMaxTotalThreadsPerThreadgroup") -ComputePipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { +ComputePipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.UInteger) { msgSend(nil, self, "setMaxTotalThreadsPerThreadgroup:", maxTotalThreadsPerThreadgroup) } @(objc_type=ComputePipelineDescriptor, objc_name="setStageInputDescriptor") @@ -1470,11 +1519,11 @@ CounterSampleBufferDescriptor_label :: #force_inline proc(self: ^CounterSampleBu return msgSend(^NS.String, self, "label") } @(objc_type=CounterSampleBufferDescriptor, objc_name="sampleCount") -CounterSampleBufferDescriptor_sampleCount :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "sampleCount") +CounterSampleBufferDescriptor_sampleCount :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "sampleCount") } @(objc_type=CounterSampleBufferDescriptor, objc_name="setCounterSet") -CounterSampleBufferDescriptor_setCounterSet :: #force_inline proc(self: ^CounterSampleBufferDescriptor, counterSet: ^NS.Object) { +CounterSampleBufferDescriptor_setCounterSet :: #force_inline proc(self: ^CounterSampleBufferDescriptor, counterSet: ^CounterSet) { msgSend(nil, self, "setCounterSet:", counterSet) } @(objc_type=CounterSampleBufferDescriptor, objc_name="setLabel") @@ -1482,7 +1531,7 @@ CounterSampleBufferDescriptor_setLabel :: #force_inline proc(self: ^CounterSampl msgSend(nil, self, "setLabel:", label) } @(objc_type=CounterSampleBufferDescriptor, objc_name="setSampleCount") -CounterSampleBufferDescriptor_setSampleCount :: #force_inline proc(self: ^CounterSampleBufferDescriptor, sampleCount: NS.Integer) { +CounterSampleBufferDescriptor_setSampleCount :: #force_inline proc(self: ^CounterSampleBufferDescriptor, sampleCount: NS.UInteger) { msgSend(nil, self, "setSampleCount:", sampleCount) } @(objc_type=CounterSampleBufferDescriptor, objc_name="setStorageMode") @@ -1592,8 +1641,8 @@ FunctionConstant_init :: #force_inline proc(self: ^FunctionConstant) -> ^Functio return msgSend(^FunctionConstant, self, "init") } @(objc_type=FunctionConstant, objc_name="index") -FunctionConstant_index :: #force_inline proc(self: ^FunctionConstant) -> NS.Integer { - return msgSend(NS.Integer, self, "index") +FunctionConstant_index :: #force_inline proc(self: ^FunctionConstant) -> NS.UInteger { + return msgSend(NS.UInteger, self, "index") } @(objc_type=FunctionConstant, objc_name="name") FunctionConstant_name :: #force_inline proc(self: ^FunctionConstant) -> ^NS.String { @@ -1637,12 +1686,12 @@ FunctionConstantValues_init :: #force_inline proc(self: ^FunctionConstantValues) FunctionConstantValues_reset :: #force_inline proc(self: ^FunctionConstantValues) { msgSend(nil, self, "reset") } -@(objc_type=FunctionConstantValues, objc_name="setConstantValue_type_atIndex_") -FunctionConstantValues_setConstantValue_type_atIndex_ :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, index: ^NS.Object) { +@(objc_type=FunctionConstantValues, objc_name="setConstantValueAtIndex") +FunctionConstantValues_setConstantValueAtIndex :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, index: NS.UInteger) { msgSend(nil, self, "setConstantValue:type:atIndex:", value, type, index) } -@(objc_type=FunctionConstantValues, objc_name="setConstantValue_type_withName_") -FunctionConstantValues_setConstantValue_type_withName_ :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, name: ^NS.String) { +@(objc_type=FunctionConstantValues, objc_name="setConstantValueWithName") +FunctionConstantValues_setConstantValueWithName :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, name: ^NS.String) { msgSend(nil, self, "setConstantValue:type:withName:", value, type, name) } @(objc_type=FunctionConstantValues, objc_name="setConstantValues") @@ -1797,7 +1846,7 @@ HeapDescriptor_setResourceOptions :: #force_inline proc(self: ^HeapDescriptor, r msgSend(nil, self, "setResourceOptions:", resourceOptions) } @(objc_type=HeapDescriptor, objc_name="setSize") -HeapDescriptor_setSize :: #force_inline proc(self: ^HeapDescriptor, size: NS.Integer) { +HeapDescriptor_setSize :: #force_inline proc(self: ^HeapDescriptor, size: NS.UInteger) { msgSend(nil, self, "setSize:", size) } @(objc_type=HeapDescriptor, objc_name="setStorageMode") @@ -1809,8 +1858,8 @@ HeapDescriptor_setType :: #force_inline proc(self: ^HeapDescriptor, type: HeapTy msgSend(nil, self, "setType:", type) } @(objc_type=HeapDescriptor, objc_name="size") -HeapDescriptor_size :: #force_inline proc(self: ^HeapDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "size") +HeapDescriptor_size :: #force_inline proc(self: ^HeapDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "size") } @(objc_type=HeapDescriptor, objc_name="storageMode") HeapDescriptor_storageMode :: #force_inline proc(self: ^HeapDescriptor) -> StorageMode { @@ -1867,16 +1916,16 @@ IndirectCommandBufferDescriptor_inheritPipelineState :: #force_inline proc(self: return msgSend(BOOL, self, "inheritPipelineState") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="maxFragmentBufferBindCount") -IndirectCommandBufferDescriptor_maxFragmentBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxFragmentBufferBindCount") +IndirectCommandBufferDescriptor_maxFragmentBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxFragmentBufferBindCount") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="maxKernelBufferBindCount") -IndirectCommandBufferDescriptor_maxKernelBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxKernelBufferBindCount") +IndirectCommandBufferDescriptor_maxKernelBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxKernelBufferBindCount") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="maxVertexBufferBindCount") -IndirectCommandBufferDescriptor_maxVertexBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxVertexBufferBindCount") +IndirectCommandBufferDescriptor_maxVertexBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxVertexBufferBindCount") } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setCommandTypes") IndirectCommandBufferDescriptor_setCommandTypes :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, commandTypes: IndirectCommandType) { @@ -1891,15 +1940,15 @@ IndirectCommandBufferDescriptor_setInheritPipelineState :: #force_inline proc(se msgSend(nil, self, "setInheritPipelineState:", inheritPipelineState) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxFragmentBufferBindCount") -IndirectCommandBufferDescriptor_setMaxFragmentBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxFragmentBufferBindCount: NS.Integer) { +IndirectCommandBufferDescriptor_setMaxFragmentBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxFragmentBufferBindCount: NS.UInteger) { msgSend(nil, self, "setMaxFragmentBufferBindCount:", maxFragmentBufferBindCount) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxKernelBufferBindCount") -IndirectCommandBufferDescriptor_setMaxKernelBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxKernelBufferBindCount: NS.Integer) { +IndirectCommandBufferDescriptor_setMaxKernelBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxKernelBufferBindCount: NS.UInteger) { msgSend(nil, self, "setMaxKernelBufferBindCount:", maxKernelBufferBindCount) } @(objc_type=IndirectCommandBufferDescriptor, objc_name="setMaxVertexBufferBindCount") -IndirectCommandBufferDescriptor_setMaxVertexBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxVertexBufferBindCount: NS.Integer) { +IndirectCommandBufferDescriptor_setMaxVertexBufferBindCount :: #force_inline proc(self: ^IndirectCommandBufferDescriptor, maxVertexBufferBindCount: NS.UInteger) { msgSend(nil, self, "setMaxVertexBufferBindCount:", maxVertexBufferBindCount) } @@ -1940,39 +1989,39 @@ InstanceAccelerationStructureDescriptor_descriptor :: #force_inline proc() -> ^I return msgSend(^InstanceAccelerationStructureDescriptor, InstanceAccelerationStructureDescriptor, "descriptor") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceCount") -InstanceAccelerationStructureDescriptor_instanceCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "instanceCount") +InstanceAccelerationStructureDescriptor_instanceCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "instanceCount") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBuffer") InstanceAccelerationStructureDescriptor_instanceDescriptorBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, self, "instanceDescriptorBuffer") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBufferOffset") -InstanceAccelerationStructureDescriptor_instanceDescriptorBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "instanceDescriptorBufferOffset") +InstanceAccelerationStructureDescriptor_instanceDescriptorBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "instanceDescriptorBufferOffset") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorStride") -InstanceAccelerationStructureDescriptor_instanceDescriptorStride :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "instanceDescriptorStride") +InstanceAccelerationStructureDescriptor_instanceDescriptorStride :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "instanceDescriptorStride") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instancedAccelerationStructures") InstanceAccelerationStructureDescriptor_instancedAccelerationStructures :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^NS.Array { return msgSend(^NS.Array, self, "instancedAccelerationStructures") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceCount") -InstanceAccelerationStructureDescriptor_setInstanceCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceCount: NS.Integer) { +InstanceAccelerationStructureDescriptor_setInstanceCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceCount: NS.UInteger) { msgSend(nil, self, "setInstanceCount:", instanceCount) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorBuffer") -InstanceAccelerationStructureDescriptor_setInstanceDescriptorBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBuffer: ^NS.Object) { +InstanceAccelerationStructureDescriptor_setInstanceDescriptorBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBuffer: ^Buffer) { msgSend(nil, self, "setInstanceDescriptorBuffer:", instanceDescriptorBuffer) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorBufferOffset") -InstanceAccelerationStructureDescriptor_setInstanceDescriptorBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBufferOffset: NS.Integer) { +InstanceAccelerationStructureDescriptor_setInstanceDescriptorBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorBufferOffset: NS.UInteger) { msgSend(nil, self, "setInstanceDescriptorBufferOffset:", instanceDescriptorBufferOffset) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorStride") -InstanceAccelerationStructureDescriptor_setInstanceDescriptorStride :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorStride: NS.Integer) { +InstanceAccelerationStructureDescriptor_setInstanceDescriptorStride :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, instanceDescriptorStride: NS.UInteger) { msgSend(nil, self, "setInstanceDescriptorStride:", instanceDescriptorStride) } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstancedAccelerationStructures") @@ -2005,15 +2054,15 @@ IntersectionFunctionTableDescriptor_init :: #force_inline proc(self: ^Intersecti return msgSend(^IntersectionFunctionTableDescriptor, self, "init") } @(objc_type=IntersectionFunctionTableDescriptor, objc_name="functionCount") -IntersectionFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "functionCount") +IntersectionFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "functionCount") } @(objc_type=IntersectionFunctionTableDescriptor, objc_class_name="intersectionFunctionTableDescriptor") IntersectionFunctionTableDescriptor_intersectionFunctionTableDescriptor :: #force_inline proc() -> ^IntersectionFunctionTableDescriptor { return msgSend(^IntersectionFunctionTableDescriptor, IntersectionFunctionTableDescriptor, "intersectionFunctionTableDescriptor") } @(objc_type=IntersectionFunctionTableDescriptor, objc_name="setFunctionCount") -IntersectionFunctionTableDescriptor_setFunctionCount :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor, functionCount: NS.Integer) { +IntersectionFunctionTableDescriptor_setFunctionCount :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor, functionCount: NS.UInteger) { msgSend(nil, self, "setFunctionCount:", functionCount) } @@ -2130,11 +2179,11 @@ PipelineBufferDescriptorArray_init :: #force_inline proc(self: ^PipelineBufferDe return msgSend(^PipelineBufferDescriptorArray, self, "init") } @(objc_type=PipelineBufferDescriptorArray, objc_name="objectAtIndexedSubscript") -PipelineBufferDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^PipelineBufferDescriptorArray, bufferIndex: ^NS.Object) -> ^PipelineBufferDescriptor { +PipelineBufferDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^PipelineBufferDescriptorArray, bufferIndex: NS.UInteger) -> ^PipelineBufferDescriptor { return msgSend(^PipelineBufferDescriptor, self, "objectAtIndexedSubscript:", bufferIndex) } @(objc_type=PipelineBufferDescriptorArray, objc_name="setObject") -PipelineBufferDescriptorArray_setObject :: #force_inline proc(self: ^PipelineBufferDescriptorArray, buffer: ^PipelineBufferDescriptor, bufferIndex: ^NS.Object) { +PipelineBufferDescriptorArray_setObject :: #force_inline proc(self: ^PipelineBufferDescriptorArray, buffer: ^PipelineBufferDescriptor, bufferIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", buffer, bufferIndex) } @@ -2171,12 +2220,12 @@ PointerType_access :: #force_inline proc(self: ^PointerType) -> ArgumentAccess { return msgSend(ArgumentAccess, self, "access") } @(objc_type=PointerType, objc_name="alignment") -PointerType_alignment :: #force_inline proc(self: ^PointerType) -> NS.Integer { - return msgSend(NS.Integer, self, "alignment") +PointerType_alignment :: #force_inline proc(self: ^PointerType) -> NS.UInteger { + return msgSend(NS.UInteger, self, "alignment") } @(objc_type=PointerType, objc_name="dataSize") -PointerType_dataSize :: #force_inline proc(self: ^PointerType) -> NS.Integer { - return msgSend(NS.Integer, self, "dataSize") +PointerType_dataSize :: #force_inline proc(self: ^PointerType) -> NS.UInteger { + return msgSend(NS.UInteger, self, "dataSize") } @(objc_type=PointerType, objc_name="elementArrayType") PointerType_elementArrayType :: #force_inline proc(self: ^PointerType) -> ^ArrayType { @@ -2256,11 +2305,11 @@ RasterizationRateLayerArray_init :: #force_inline proc(self: ^RasterizationRateL return msgSend(^RasterizationRateLayerArray, self, "init") } @(objc_type=RasterizationRateLayerArray, objc_name="objectAtIndexedSubscript") -RasterizationRateLayerArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateLayerArray, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { +RasterizationRateLayerArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateLayerArray, layerIndex: NS.UInteger) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "objectAtIndexedSubscript:", layerIndex) } @(objc_type=RasterizationRateLayerArray, objc_name="setObject") -RasterizationRateLayerArray_setObject :: #force_inline proc(self: ^RasterizationRateLayerArray, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { +RasterizationRateLayerArray_setObject :: #force_inline proc(self: ^RasterizationRateLayerArray, layer: ^RasterizationRateLayerDescriptor, layerIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", layer, layerIndex) } @@ -2358,12 +2407,12 @@ RasterizationRateMapDescriptor_label :: #force_inline proc(self: ^RasterizationR return msgSend(^NS.String, self, "label") } @(objc_type=RasterizationRateMapDescriptor, objc_name="layerAtIndex") -RasterizationRateMapDescriptor_layerAtIndex :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layerIndex: ^NS.Object) -> ^RasterizationRateLayerDescriptor { +RasterizationRateMapDescriptor_layerAtIndex :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layerIndex: NS.UInteger) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "layerAtIndex:", layerIndex) } @(objc_type=RasterizationRateMapDescriptor, objc_name="layerCount") -RasterizationRateMapDescriptor_layerCount :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "layerCount") +RasterizationRateMapDescriptor_layerCount :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "layerCount") } @(objc_type=RasterizationRateMapDescriptor, objc_name="layers") RasterizationRateMapDescriptor_layers :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateLayerArray { @@ -2373,12 +2422,12 @@ RasterizationRateMapDescriptor_layers :: #force_inline proc(self: ^Rasterization RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize :: #force_inline proc(screenSize: Size) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:", screenSize) } -@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize_layer_") -RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layer_ :: #force_inline proc(screenSize: Size, layer: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { +@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSizeWithLayer") +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSizeWithLayer :: #force_inline proc(screenSize: Size, layer: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layer:", screenSize, layer) } -@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize_layerCount_layers_") -RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize_layerCount_layers_ :: #force_inline proc(screenSize: Size, layerCount: ^NS.Object, layers: ^^RasterizationRateLayerDescriptor ) -> ^RasterizationRateMapDescriptor { +@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSizeWithLayers") +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSizeWithLayers :: #force_inline proc(screenSize: Size, layerCount: NS.UInteger, layers: [^]^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layerCount:layers:", screenSize, layerCount, layers) } @(objc_type=RasterizationRateMapDescriptor, objc_name="screenSize") @@ -2390,7 +2439,7 @@ RasterizationRateMapDescriptor_setLabel :: #force_inline proc(self: ^Rasterizati msgSend(nil, self, "setLabel:", label) } @(objc_type=RasterizationRateMapDescriptor, objc_name="setLayer") -RasterizationRateMapDescriptor_setLayer :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layer: ^RasterizationRateLayerDescriptor, layerIndex: ^NS.Object) { +RasterizationRateMapDescriptor_setLayer :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layer: ^RasterizationRateLayerDescriptor, layerIndex: NS.UInteger) { msgSend(nil, self, "setLayer:atIndex:", layer, layerIndex) } @(objc_type=RasterizationRateMapDescriptor, objc_name="setScreenSize") @@ -2422,11 +2471,11 @@ RasterizationRateSampleArray_init :: #force_inline proc(self: ^RasterizationRate return msgSend(^RasterizationRateSampleArray, self, "init") } @(objc_type=RasterizationRateSampleArray, objc_name="objectAtIndexedSubscript") -RasterizationRateSampleArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateSampleArray, index: ^NS.Object) -> ^NS.Number { - return msgSend(^NS.Number, self, "objectAtIndexedSubscript:", index) +RasterizationRateSampleArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateSampleArray, index: NS.UInteger) -> NS.UInteger { + return msgSend(NS.UInteger, self, "objectAtIndexedSubscript:", index) } @(objc_type=RasterizationRateSampleArray, objc_name="setObject") -RasterizationRateSampleArray_setObject :: #force_inline proc(self: ^RasterizationRateSampleArray, value: ^NS.Number, index: ^NS.Object) { +RasterizationRateSampleArray_setObject :: #force_inline proc(self: ^RasterizationRateSampleArray, value: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", value, index) } @@ -2474,39 +2523,39 @@ RenderPassAttachmentDescriptor_init :: #force_inline proc(self: ^RenderPassAttac return msgSend(^RenderPassAttachmentDescriptor, self, "init") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="depthPlane") -RenderPassAttachmentDescriptor_depthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "depthPlane") +RenderPassAttachmentDescriptor_depthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "depthPlane") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="level") -RenderPassAttachmentDescriptor_level :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "level") +RenderPassAttachmentDescriptor_level :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "level") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="loadAction") RenderPassAttachmentDescriptor_loadAction :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> LoadAction { return msgSend(LoadAction, self, "loadAction") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveDepthPlane") -RenderPassAttachmentDescriptor_resolveDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "resolveDepthPlane") +RenderPassAttachmentDescriptor_resolveDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "resolveDepthPlane") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveLevel") -RenderPassAttachmentDescriptor_resolveLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "resolveLevel") +RenderPassAttachmentDescriptor_resolveLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "resolveLevel") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveSlice") -RenderPassAttachmentDescriptor_resolveSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "resolveSlice") +RenderPassAttachmentDescriptor_resolveSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "resolveSlice") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveTexture") RenderPassAttachmentDescriptor_resolveTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { return msgSend(^RenderPassAttachmentDescriptor, self, "resolveTexture") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setDepthPlane") -RenderPassAttachmentDescriptor_setDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, depthPlane: NS.Integer) { +RenderPassAttachmentDescriptor_setDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, depthPlane: NS.UInteger) { msgSend(nil, self, "setDepthPlane:", depthPlane) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setLevel") -RenderPassAttachmentDescriptor_setLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, level: NS.Integer) { +RenderPassAttachmentDescriptor_setLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, level: NS.UInteger) { msgSend(nil, self, "setLevel:", level) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setLoadAction") @@ -2514,23 +2563,23 @@ RenderPassAttachmentDescriptor_setLoadAction :: #force_inline proc(self: ^Render msgSend(nil, self, "setLoadAction:", loadAction) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveDepthPlane") -RenderPassAttachmentDescriptor_setResolveDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveDepthPlane: NS.Integer) { +RenderPassAttachmentDescriptor_setResolveDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveDepthPlane: NS.UInteger) { msgSend(nil, self, "setResolveDepthPlane:", resolveDepthPlane) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveLevel") -RenderPassAttachmentDescriptor_setResolveLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveLevel: NS.Integer) { +RenderPassAttachmentDescriptor_setResolveLevel :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveLevel: NS.UInteger) { msgSend(nil, self, "setResolveLevel:", resolveLevel) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveSlice") -RenderPassAttachmentDescriptor_setResolveSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveSlice: NS.Integer) { +RenderPassAttachmentDescriptor_setResolveSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveSlice: NS.UInteger) { msgSend(nil, self, "setResolveSlice:", resolveSlice) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setResolveTexture") -RenderPassAttachmentDescriptor_setResolveTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveTexture: ^NS.Object) { +RenderPassAttachmentDescriptor_setResolveTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, resolveTexture: ^Texture) { msgSend(nil, self, "setResolveTexture:", resolveTexture) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setSlice") -RenderPassAttachmentDescriptor_setSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, slice: NS.Integer) { +RenderPassAttachmentDescriptor_setSlice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, slice: NS.UInteger) { msgSend(nil, self, "setSlice:", slice) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setStoreAction") @@ -2542,12 +2591,12 @@ RenderPassAttachmentDescriptor_setStoreActionOptions :: #force_inline proc(self: msgSend(nil, self, "setStoreActionOptions:", storeActionOptions) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setTexture") -RenderPassAttachmentDescriptor_setTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, texture: ^NS.Object) { +RenderPassAttachmentDescriptor_setTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, texture: ^Texture) { msgSend(nil, self, "setTexture:", texture) } @(objc_type=RenderPassAttachmentDescriptor, objc_name="slice") -RenderPassAttachmentDescriptor_slice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "slice") +RenderPassAttachmentDescriptor_slice :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "slice") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="storeAction") RenderPassAttachmentDescriptor_storeAction :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> StoreAction { @@ -2618,11 +2667,11 @@ RenderPassColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^Rende return msgSend(^RenderPassColorAttachmentDescriptorArray, self, "init") } @(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPassColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassColorAttachmentDescriptor { +RenderPassColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPassColorAttachmentDescriptor { return msgSend(^RenderPassColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="setObject") -RenderPassColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachment: ^RenderPassColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { +RenderPassColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachment: ^RenderPassColorAttachmentDescriptor, attachmentIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -2723,20 +2772,20 @@ RenderPassDescriptor_colorAttachments :: #force_inline proc(self: ^RenderPassDes return msgSend(^RenderPassColorAttachmentDescriptorArray, self, "colorAttachments") } @(objc_type=RenderPassDescriptor, objc_name="defaultRasterSampleCount") -RenderPassDescriptor_defaultRasterSampleCount :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "defaultRasterSampleCount") +RenderPassDescriptor_defaultRasterSampleCount :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "defaultRasterSampleCount") } @(objc_type=RenderPassDescriptor, objc_name="depthAttachment") RenderPassDescriptor_depthAttachment :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDepthAttachmentDescriptor { return msgSend(^RenderPassDepthAttachmentDescriptor, self, "depthAttachment") } @(objc_type=RenderPassDescriptor, objc_name="getSamplePositions") -RenderPassDescriptor_getSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) -> ^RenderPassDescriptor { +RenderPassDescriptor_getSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: NS.UInteger) -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, self, "getSamplePositions:count:", positions, count) } @(objc_type=RenderPassDescriptor, objc_name="imageblockSampleLength") -RenderPassDescriptor_imageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "imageblockSampleLength") +RenderPassDescriptor_imageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "imageblockSampleLength") } @(objc_type=RenderPassDescriptor, objc_name="rasterizationRateMap") RenderPassDescriptor_rasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { @@ -2747,23 +2796,23 @@ RenderPassDescriptor_renderPassDescriptor :: #force_inline proc() -> ^RenderPass return msgSend(^RenderPassDescriptor, RenderPassDescriptor, "renderPassDescriptor") } @(objc_type=RenderPassDescriptor, objc_name="renderTargetArrayLength") -RenderPassDescriptor_renderTargetArrayLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "renderTargetArrayLength") +RenderPassDescriptor_renderTargetArrayLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "renderTargetArrayLength") } @(objc_type=RenderPassDescriptor, objc_name="renderTargetHeight") -RenderPassDescriptor_renderTargetHeight :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "renderTargetHeight") +RenderPassDescriptor_renderTargetHeight :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "renderTargetHeight") } @(objc_type=RenderPassDescriptor, objc_name="renderTargetWidth") -RenderPassDescriptor_renderTargetWidth :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "renderTargetWidth") +RenderPassDescriptor_renderTargetWidth :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "renderTargetWidth") } @(objc_type=RenderPassDescriptor, objc_name="sampleBufferAttachments") RenderPassDescriptor_sampleBufferAttachments :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptorArray { return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, self, "sampleBufferAttachments") } @(objc_type=RenderPassDescriptor, objc_name="setDefaultRasterSampleCount") -RenderPassDescriptor_setDefaultRasterSampleCount :: #force_inline proc(self: ^RenderPassDescriptor, defaultRasterSampleCount: NS.Integer) { +RenderPassDescriptor_setDefaultRasterSampleCount :: #force_inline proc(self: ^RenderPassDescriptor, defaultRasterSampleCount: NS.UInteger) { msgSend(nil, self, "setDefaultRasterSampleCount:", defaultRasterSampleCount) } @(objc_type=RenderPassDescriptor, objc_name="setDepthAttachment") @@ -2771,27 +2820,27 @@ RenderPassDescriptor_setDepthAttachment :: #force_inline proc(self: ^RenderPassD msgSend(nil, self, "setDepthAttachment:", depthAttachment) } @(objc_type=RenderPassDescriptor, objc_name="setImageblockSampleLength") -RenderPassDescriptor_setImageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor, imageblockSampleLength: NS.Integer) { +RenderPassDescriptor_setImageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor, imageblockSampleLength: NS.UInteger) { msgSend(nil, self, "setImageblockSampleLength:", imageblockSampleLength) } @(objc_type=RenderPassDescriptor, objc_name="setRasterizationRateMap") -RenderPassDescriptor_setRasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor, rasterizationRateMap: ^NS.Object) { +RenderPassDescriptor_setRasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor, rasterizationRateMap: ^RasterizationRateMap) { msgSend(nil, self, "setRasterizationRateMap:", rasterizationRateMap) } @(objc_type=RenderPassDescriptor, objc_name="setRenderTargetArrayLength") -RenderPassDescriptor_setRenderTargetArrayLength :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetArrayLength: NS.Integer) { +RenderPassDescriptor_setRenderTargetArrayLength :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetArrayLength: NS.UInteger) { msgSend(nil, self, "setRenderTargetArrayLength:", renderTargetArrayLength) } @(objc_type=RenderPassDescriptor, objc_name="setRenderTargetHeight") -RenderPassDescriptor_setRenderTargetHeight :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetHeight: NS.Integer) { +RenderPassDescriptor_setRenderTargetHeight :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetHeight: NS.UInteger) { msgSend(nil, self, "setRenderTargetHeight:", renderTargetHeight) } @(objc_type=RenderPassDescriptor, objc_name="setRenderTargetWidth") -RenderPassDescriptor_setRenderTargetWidth :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetWidth: NS.Integer) { +RenderPassDescriptor_setRenderTargetWidth :: #force_inline proc(self: ^RenderPassDescriptor, renderTargetWidth: NS.UInteger) { msgSend(nil, self, "setRenderTargetWidth:", renderTargetWidth) } @(objc_type=RenderPassDescriptor, objc_name="setSamplePositions") -RenderPassDescriptor_setSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: ^NS.Object) { +RenderPassDescriptor_setSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: NS.UInteger) { msgSend(nil, self, "setSamplePositions:count:", positions, count) } @(objc_type=RenderPassDescriptor, objc_name="setStencilAttachment") @@ -2799,19 +2848,19 @@ RenderPassDescriptor_setStencilAttachment :: #force_inline proc(self: ^RenderPas msgSend(nil, self, "setStencilAttachment:", stencilAttachment) } @(objc_type=RenderPassDescriptor, objc_name="setThreadgroupMemoryLength") -RenderPassDescriptor_setThreadgroupMemoryLength :: #force_inline proc(self: ^RenderPassDescriptor, threadgroupMemoryLength: NS.Integer) { +RenderPassDescriptor_setThreadgroupMemoryLength :: #force_inline proc(self: ^RenderPassDescriptor, threadgroupMemoryLength: NS.UInteger) { msgSend(nil, self, "setThreadgroupMemoryLength:", threadgroupMemoryLength) } @(objc_type=RenderPassDescriptor, objc_name="setTileHeight") -RenderPassDescriptor_setTileHeight :: #force_inline proc(self: ^RenderPassDescriptor, tileHeight: NS.Integer) { +RenderPassDescriptor_setTileHeight :: #force_inline proc(self: ^RenderPassDescriptor, tileHeight: NS.UInteger) { msgSend(nil, self, "setTileHeight:", tileHeight) } @(objc_type=RenderPassDescriptor, objc_name="setTileWidth") -RenderPassDescriptor_setTileWidth :: #force_inline proc(self: ^RenderPassDescriptor, tileWidth: NS.Integer) { +RenderPassDescriptor_setTileWidth :: #force_inline proc(self: ^RenderPassDescriptor, tileWidth: NS.UInteger) { msgSend(nil, self, "setTileWidth:", tileWidth) } @(objc_type=RenderPassDescriptor, objc_name="setVisibilityResultBuffer") -RenderPassDescriptor_setVisibilityResultBuffer :: #force_inline proc(self: ^RenderPassDescriptor, visibilityResultBuffer: ^NS.Object) { +RenderPassDescriptor_setVisibilityResultBuffer :: #force_inline proc(self: ^RenderPassDescriptor, visibilityResultBuffer: ^Buffer) { msgSend(nil, self, "setVisibilityResultBuffer:", visibilityResultBuffer) } @(objc_type=RenderPassDescriptor, objc_name="stencilAttachment") @@ -2819,16 +2868,16 @@ RenderPassDescriptor_stencilAttachment :: #force_inline proc(self: ^RenderPassDe return msgSend(^RenderPassStencilAttachmentDescriptor, self, "stencilAttachment") } @(objc_type=RenderPassDescriptor, objc_name="threadgroupMemoryLength") -RenderPassDescriptor_threadgroupMemoryLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "threadgroupMemoryLength") +RenderPassDescriptor_threadgroupMemoryLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "threadgroupMemoryLength") } @(objc_type=RenderPassDescriptor, objc_name="tileHeight") -RenderPassDescriptor_tileHeight :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "tileHeight") +RenderPassDescriptor_tileHeight :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "tileHeight") } @(objc_type=RenderPassDescriptor, objc_name="tileWidth") -RenderPassDescriptor_tileWidth :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "tileWidth") +RenderPassDescriptor_tileWidth :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "tileWidth") } @(objc_type=RenderPassDescriptor, objc_name="visibilityResultBuffer") RenderPassDescriptor_visibilityResultBuffer :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { @@ -2867,44 +2916,44 @@ RenderPassSampleBufferAttachmentDescriptor_init :: #force_inline proc(self: ^Ren return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="endOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_endOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "endOfFragmentSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_endOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "endOfFragmentSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="endOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_endOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "endOfVertexSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_endOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "endOfVertexSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setEndOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfFragmentSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setEndOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfFragmentSampleIndex: NS.UInteger) { msgSend(nil, self, "setEndOfFragmentSampleIndex:", endOfFragmentSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setEndOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfVertexSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setEndOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfVertexSampleIndex: NS.UInteger) { msgSend(nil, self, "setEndOfVertexSampleIndex:", endOfVertexSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -RenderPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +RenderPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, sampleBuffer: ^Buffer) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setStartOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setStartOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfFragmentSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setStartOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfFragmentSampleIndex: NS.UInteger) { msgSend(nil, self, "setStartOfFragmentSampleIndex:", startOfFragmentSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setStartOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_setStartOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfVertexSampleIndex: NS.Integer) { +RenderPassSampleBufferAttachmentDescriptor_setStartOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, startOfVertexSampleIndex: NS.UInteger) { msgSend(nil, self, "setStartOfVertexSampleIndex:", startOfVertexSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="startOfFragmentSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_startOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "startOfFragmentSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_startOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "startOfFragmentSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="startOfVertexSampleIndex") -RenderPassSampleBufferAttachmentDescriptor_startOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "startOfVertexSampleIndex") +RenderPassSampleBufferAttachmentDescriptor_startOfVertexSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "startOfVertexSampleIndex") } //////////////////////////////////////////////////////////////////////////////// @@ -2931,11 +2980,11 @@ RenderPassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPassSampleBufferAttachmentDescriptor { +RenderPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -RenderPassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachment: ^RenderPassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +RenderPassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachment: ^RenderPassSampleBufferAttachmentDescriptor, attachmentIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -3117,11 +3166,11 @@ RenderPipelineColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^R return msgSend(^RenderPipelineColorAttachmentDescriptorArray, self, "init") } @(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^RenderPipelineColorAttachmentDescriptor { +RenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPipelineColorAttachmentDescriptor { return msgSend(^RenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") -RenderPipelineColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachment: ^RenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { +RenderPipelineColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachment: ^RenderPipelineColorAttachmentDescriptor, attachmentIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -3239,24 +3288,24 @@ RenderPipelineDescriptor_label :: #force_inline proc(self: ^RenderPipelineDescri return msgSend(^NS.String, self, "label") } @(objc_type=RenderPipelineDescriptor, objc_name="maxTessellationFactor") -RenderPipelineDescriptor_maxTessellationFactor :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxTessellationFactor") +RenderPipelineDescriptor_maxTessellationFactor :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTessellationFactor") } @(objc_type=RenderPipelineDescriptor, objc_name="maxVertexAmplificationCount") -RenderPipelineDescriptor_maxVertexAmplificationCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxVertexAmplificationCount") +RenderPipelineDescriptor_maxVertexAmplificationCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxVertexAmplificationCount") } @(objc_type=RenderPipelineDescriptor, objc_name="rasterSampleCount") -RenderPipelineDescriptor_rasterSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "rasterSampleCount") +RenderPipelineDescriptor_rasterSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "rasterSampleCount") } @(objc_type=RenderPipelineDescriptor, objc_name="reset") RenderPipelineDescriptor_reset :: #force_inline proc(self: ^RenderPipelineDescriptor) { msgSend(nil, self, "reset") } @(objc_type=RenderPipelineDescriptor, objc_name="sampleCount") -RenderPipelineDescriptor_sampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "sampleCount") +RenderPipelineDescriptor_sampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "sampleCount") } @(objc_type=RenderPipelineDescriptor, objc_name="setAlphaToCoverageEnabled") RenderPipelineDescriptor_setAlphaToCoverageEnabled :: #force_inline proc(self: ^RenderPipelineDescriptor, alphaToCoverageEnabled: BOOL) { @@ -3275,7 +3324,7 @@ RenderPipelineDescriptor_setDepthAttachmentPixelFormat :: #force_inline proc(sel msgSend(nil, self, "setDepthAttachmentPixelFormat:", depthAttachmentPixelFormat) } @(objc_type=RenderPipelineDescriptor, objc_name="setFragmentFunction") -RenderPipelineDescriptor_setFragmentFunction :: #force_inline proc(self: ^RenderPipelineDescriptor, fragmentFunction: ^NS.Object) { +RenderPipelineDescriptor_setFragmentFunction :: #force_inline proc(self: ^RenderPipelineDescriptor, fragmentFunction: ^Function) { msgSend(nil, self, "setFragmentFunction:", fragmentFunction) } @(objc_type=RenderPipelineDescriptor, objc_name="setInputPrimitiveTopology") @@ -3287,15 +3336,15 @@ RenderPipelineDescriptor_setLabel :: #force_inline proc(self: ^RenderPipelineDes msgSend(nil, self, "setLabel:", label) } @(objc_type=RenderPipelineDescriptor, objc_name="setMaxTessellationFactor") -RenderPipelineDescriptor_setMaxTessellationFactor :: #force_inline proc(self: ^RenderPipelineDescriptor, maxTessellationFactor: NS.Integer) { +RenderPipelineDescriptor_setMaxTessellationFactor :: #force_inline proc(self: ^RenderPipelineDescriptor, maxTessellationFactor: NS.UInteger) { msgSend(nil, self, "setMaxTessellationFactor:", maxTessellationFactor) } @(objc_type=RenderPipelineDescriptor, objc_name="setMaxVertexAmplificationCount") -RenderPipelineDescriptor_setMaxVertexAmplificationCount :: #force_inline proc(self: ^RenderPipelineDescriptor, maxVertexAmplificationCount: NS.Integer) { +RenderPipelineDescriptor_setMaxVertexAmplificationCount :: #force_inline proc(self: ^RenderPipelineDescriptor, maxVertexAmplificationCount: NS.UInteger) { msgSend(nil, self, "setMaxVertexAmplificationCount:", maxVertexAmplificationCount) } @(objc_type=RenderPipelineDescriptor, objc_name="setRasterSampleCount") -RenderPipelineDescriptor_setRasterSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor, rasterSampleCount: NS.Integer) { +RenderPipelineDescriptor_setRasterSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor, rasterSampleCount: NS.UInteger) { msgSend(nil, self, "setRasterSampleCount:", rasterSampleCount) } @(objc_type=RenderPipelineDescriptor, objc_name="setRasterizationEnabled") @@ -3303,7 +3352,7 @@ RenderPipelineDescriptor_setRasterizationEnabled :: #force_inline proc(self: ^Re msgSend(nil, self, "setRasterizationEnabled:", rasterizationEnabled) } @(objc_type=RenderPipelineDescriptor, objc_name="setSampleCount") -RenderPipelineDescriptor_setSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor, sampleCount: NS.Integer) { +RenderPipelineDescriptor_setSampleCount :: #force_inline proc(self: ^RenderPipelineDescriptor, sampleCount: NS.UInteger) { msgSend(nil, self, "setSampleCount:", sampleCount) } @(objc_type=RenderPipelineDescriptor, objc_name="setStencilAttachmentPixelFormat") @@ -3343,7 +3392,7 @@ RenderPipelineDescriptor_setVertexDescriptor :: #force_inline proc(self: ^Render msgSend(nil, self, "setVertexDescriptor:", vertexDescriptor) } @(objc_type=RenderPipelineDescriptor, objc_name="setVertexFunction") -RenderPipelineDescriptor_setVertexFunction :: #force_inline proc(self: ^RenderPipelineDescriptor, vertexFunction: ^NS.Object) { +RenderPipelineDescriptor_setVertexFunction :: #force_inline proc(self: ^RenderPipelineDescriptor, vertexFunction: ^Function) { msgSend(nil, self, "setVertexFunction:", vertexFunction) } @(objc_type=RenderPipelineDescriptor, objc_name="stencilAttachmentPixelFormat") @@ -3484,28 +3533,28 @@ ResourceStatePassSampleBufferAttachmentDescriptor_init :: #force_inline proc(sel return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "init") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="endOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "endOfEncoderSampleIndex") +ResourceStatePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.Integer) { +ResourceStatePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -ResourceStatePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, sampleBuffer: ^NS.Object) { +ResourceStatePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, sampleBuffer: ^Buffer) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.Integer) { +ResourceStatePassSampleBufferAttachmentDescriptor_setStartOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, startOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setStartOfEncoderSampleIndex:", startOfEncoderSampleIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="startOfEncoderSampleIndex") -ResourceStatePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "startOfEncoderSampleIndex") +ResourceStatePassSampleBufferAttachmentDescriptor_startOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "startOfEncoderSampleIndex") } //////////////////////////////////////////////////////////////////////////////// @@ -3532,11 +3581,11 @@ ResourceStatePassSampleBufferAttachmentDescriptorArray_init :: #force_inline pro return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, self, "init") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -ResourceStatePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { +ResourceStatePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") -ResourceStatePassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachment: ^ResourceStatePassSampleBufferAttachmentDescriptor, attachmentIndex: ^NS.Object) { +ResourceStatePassSampleBufferAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachment: ^ResourceStatePassSampleBufferAttachmentDescriptor, attachmentIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -3620,8 +3669,8 @@ SamplerDescriptor_magFilter :: #force_inline proc(self: ^SamplerDescriptor) -> S return msgSend(SamplerMinMagFilter, self, "magFilter") } @(objc_type=SamplerDescriptor, objc_name="maxAnisotropy") -SamplerDescriptor_maxAnisotropy :: #force_inline proc(self: ^SamplerDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxAnisotropy") +SamplerDescriptor_maxAnisotropy :: #force_inline proc(self: ^SamplerDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxAnisotropy") } @(objc_type=SamplerDescriptor, objc_name="minFilter") SamplerDescriptor_minFilter :: #force_inline proc(self: ^SamplerDescriptor) -> SamplerMinMagFilter { @@ -3672,7 +3721,7 @@ SamplerDescriptor_setMagFilter :: #force_inline proc(self: ^SamplerDescriptor, m msgSend(nil, self, "setMagFilter:", magFilter) } @(objc_type=SamplerDescriptor, objc_name="setMaxAnisotropy") -SamplerDescriptor_setMaxAnisotropy :: #force_inline proc(self: ^SamplerDescriptor, maxAnisotropy: NS.Integer) { +SamplerDescriptor_setMaxAnisotropy :: #force_inline proc(self: ^SamplerDescriptor, maxAnisotropy: NS.UInteger) { msgSend(nil, self, "setMaxAnisotropy:", maxAnisotropy) } @(objc_type=SamplerDescriptor, objc_name="setMinFilter") @@ -3759,15 +3808,15 @@ SharedEventListener_alloc :: #force_inline proc() -> ^SharedEventListener { return msgSend(^SharedEventListener, SharedEventListener, "alloc") } @(objc_type=SharedEventListener, objc_name="dispatchQueue") -SharedEventListener_dispatchQueue :: #force_inline proc(self: ^SharedEventListener) -> NS.Integer { - return msgSend(NS.Integer, self, "dispatchQueue") +SharedEventListener_dispatchQueue :: #force_inline proc(self: ^SharedEventListener) -> NS.UInteger { + return msgSend(NS.UInteger, self, "dispatchQueue") } @(objc_type=SharedEventListener, objc_name="init") SharedEventListener_init :: #force_inline proc(self: ^SharedEventListener) -> ^SharedEventListener { return msgSend(^SharedEventListener, self, "init") } @(objc_type=SharedEventListener, objc_name="initWithDispatchQueue") -SharedEventListener_initWithDispatchQueue :: #force_inline proc(self: ^SharedEventListener, dispatchQueue: ^NS.Object) -> ^SharedEventListener { +SharedEventListener_initWithDispatchQueue :: #force_inline proc(self: ^SharedEventListener, dispatchQueue: dispatch_queue_t) -> ^SharedEventListener { return msgSend(^SharedEventListener, self, "initWithDispatchQueue:", dispatchQueue) } @@ -3837,8 +3886,8 @@ StageInputOutputDescriptor_attributes :: #force_inline proc(self: ^StageInputOut return msgSend(^AttributeDescriptorArray, self, "attributes") } @(objc_type=StageInputOutputDescriptor, objc_name="indexBufferIndex") -StageInputOutputDescriptor_indexBufferIndex :: #force_inline proc(self: ^StageInputOutputDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "indexBufferIndex") +StageInputOutputDescriptor_indexBufferIndex :: #force_inline proc(self: ^StageInputOutputDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "indexBufferIndex") } @(objc_type=StageInputOutputDescriptor, objc_name="indexType") StageInputOutputDescriptor_indexType :: #force_inline proc(self: ^StageInputOutputDescriptor) -> IndexType { @@ -3853,7 +3902,7 @@ StageInputOutputDescriptor_reset :: #force_inline proc(self: ^StageInputOutputDe msgSend(nil, self, "reset") } @(objc_type=StageInputOutputDescriptor, objc_name="setIndexBufferIndex") -StageInputOutputDescriptor_setIndexBufferIndex :: #force_inline proc(self: ^StageInputOutputDescriptor, indexBufferIndex: NS.Integer) { +StageInputOutputDescriptor_setIndexBufferIndex :: #force_inline proc(self: ^StageInputOutputDescriptor, indexBufferIndex: NS.UInteger) { msgSend(nil, self, "setIndexBufferIndex:", indexBufferIndex) } @(objc_type=StageInputOutputDescriptor, objc_name="setIndexType") @@ -3977,8 +4026,8 @@ StructMember_init :: #force_inline proc(self: ^StructMember) -> ^StructMember { return msgSend(^StructMember, self, "init") } @(objc_type=StructMember, objc_name="argumentIndex") -StructMember_argumentIndex :: #force_inline proc(self: ^StructMember) -> NS.Integer { - return msgSend(NS.Integer, self, "argumentIndex") +StructMember_argumentIndex :: #force_inline proc(self: ^StructMember) -> NS.UInteger { + return msgSend(NS.UInteger, self, "argumentIndex") } @(objc_type=StructMember, objc_name="arrayType") StructMember_arrayType :: #force_inline proc(self: ^StructMember) -> ^ArrayType { @@ -3993,8 +4042,8 @@ StructMember_name :: #force_inline proc(self: ^StructMember) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=StructMember, objc_name="offset") -StructMember_offset :: #force_inline proc(self: ^StructMember) -> NS.Integer { - return msgSend(NS.Integer, self, "offset") +StructMember_offset :: #force_inline proc(self: ^StructMember) -> NS.UInteger { + return msgSend(NS.UInteger, self, "offset") } @(objc_type=StructMember, objc_name="pointerType") StructMember_pointerType :: #force_inline proc(self: ^StructMember) -> ^PointerType { @@ -4100,28 +4149,28 @@ TextureDescriptor_allowGPUOptimizedContents :: #force_inline proc(self: ^Texture return msgSend(BOOL, self, "allowGPUOptimizedContents") } @(objc_type=TextureDescriptor, objc_name="arrayLength") -TextureDescriptor_arrayLength :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "arrayLength") +TextureDescriptor_arrayLength :: #force_inline proc(self: ^TextureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "arrayLength") } @(objc_type=TextureDescriptor, objc_name="cpuCacheMode") TextureDescriptor_cpuCacheMode :: #force_inline proc(self: ^TextureDescriptor) -> CPUCacheMode { return msgSend(CPUCacheMode, self, "cpuCacheMode") } @(objc_type=TextureDescriptor, objc_name="depth") -TextureDescriptor_depth :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "depth") +TextureDescriptor_depth :: #force_inline proc(self: ^TextureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "depth") } @(objc_type=TextureDescriptor, objc_name="hazardTrackingMode") TextureDescriptor_hazardTrackingMode :: #force_inline proc(self: ^TextureDescriptor) -> HazardTrackingMode { return msgSend(HazardTrackingMode, self, "hazardTrackingMode") } @(objc_type=TextureDescriptor, objc_name="height") -TextureDescriptor_height :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "height") +TextureDescriptor_height :: #force_inline proc(self: ^TextureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "height") } @(objc_type=TextureDescriptor, objc_name="mipmapLevelCount") -TextureDescriptor_mipmapLevelCount :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "mipmapLevelCount") +TextureDescriptor_mipmapLevelCount :: #force_inline proc(self: ^TextureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "mipmapLevelCount") } @(objc_type=TextureDescriptor, objc_name="pixelFormat") TextureDescriptor_pixelFormat :: #force_inline proc(self: ^TextureDescriptor) -> PixelFormat { @@ -4132,15 +4181,15 @@ TextureDescriptor_resourceOptions :: #force_inline proc(self: ^TextureDescriptor return msgSend(ResourceOptions, self, "resourceOptions") } @(objc_type=TextureDescriptor, objc_name="sampleCount") -TextureDescriptor_sampleCount :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "sampleCount") +TextureDescriptor_sampleCount :: #force_inline proc(self: ^TextureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "sampleCount") } @(objc_type=TextureDescriptor, objc_name="setAllowGPUOptimizedContents") TextureDescriptor_setAllowGPUOptimizedContents :: #force_inline proc(self: ^TextureDescriptor, allowGPUOptimizedContents: BOOL) { msgSend(nil, self, "setAllowGPUOptimizedContents:", allowGPUOptimizedContents) } @(objc_type=TextureDescriptor, objc_name="setArrayLength") -TextureDescriptor_setArrayLength :: #force_inline proc(self: ^TextureDescriptor, arrayLength: NS.Integer) { +TextureDescriptor_setArrayLength :: #force_inline proc(self: ^TextureDescriptor, arrayLength: NS.UInteger) { msgSend(nil, self, "setArrayLength:", arrayLength) } @(objc_type=TextureDescriptor, objc_name="setCpuCacheMode") @@ -4148,7 +4197,7 @@ TextureDescriptor_setCpuCacheMode :: #force_inline proc(self: ^TextureDescriptor msgSend(nil, self, "setCpuCacheMode:", cpuCacheMode) } @(objc_type=TextureDescriptor, objc_name="setDepth") -TextureDescriptor_setDepth :: #force_inline proc(self: ^TextureDescriptor, depth: NS.Integer) { +TextureDescriptor_setDepth :: #force_inline proc(self: ^TextureDescriptor, depth: NS.UInteger) { msgSend(nil, self, "setDepth:", depth) } @(objc_type=TextureDescriptor, objc_name="setHazardTrackingMode") @@ -4156,11 +4205,11 @@ TextureDescriptor_setHazardTrackingMode :: #force_inline proc(self: ^TextureDesc msgSend(nil, self, "setHazardTrackingMode:", hazardTrackingMode) } @(objc_type=TextureDescriptor, objc_name="setHeight") -TextureDescriptor_setHeight :: #force_inline proc(self: ^TextureDescriptor, height: NS.Integer) { +TextureDescriptor_setHeight :: #force_inline proc(self: ^TextureDescriptor, height: NS.UInteger) { msgSend(nil, self, "setHeight:", height) } @(objc_type=TextureDescriptor, objc_name="setMipmapLevelCount") -TextureDescriptor_setMipmapLevelCount :: #force_inline proc(self: ^TextureDescriptor, mipmapLevelCount: NS.Integer) { +TextureDescriptor_setMipmapLevelCount :: #force_inline proc(self: ^TextureDescriptor, mipmapLevelCount: NS.UInteger) { msgSend(nil, self, "setMipmapLevelCount:", mipmapLevelCount) } @(objc_type=TextureDescriptor, objc_name="setPixelFormat") @@ -4172,7 +4221,7 @@ TextureDescriptor_setResourceOptions :: #force_inline proc(self: ^TextureDescrip msgSend(nil, self, "setResourceOptions:", resourceOptions) } @(objc_type=TextureDescriptor, objc_name="setSampleCount") -TextureDescriptor_setSampleCount :: #force_inline proc(self: ^TextureDescriptor, sampleCount: NS.Integer) { +TextureDescriptor_setSampleCount :: #force_inline proc(self: ^TextureDescriptor, sampleCount: NS.UInteger) { msgSend(nil, self, "setSampleCount:", sampleCount) } @(objc_type=TextureDescriptor, objc_name="setStorageMode") @@ -4192,7 +4241,7 @@ TextureDescriptor_setUsage :: #force_inline proc(self: ^TextureDescriptor, usage msgSend(nil, self, "setUsage:", usage) } @(objc_type=TextureDescriptor, objc_name="setWidth") -TextureDescriptor_setWidth :: #force_inline proc(self: ^TextureDescriptor, width: NS.Integer) { +TextureDescriptor_setWidth :: #force_inline proc(self: ^TextureDescriptor, width: NS.UInteger) { msgSend(nil, self, "setWidth:", width) } @(objc_type=TextureDescriptor, objc_name="storageMode") @@ -4204,15 +4253,15 @@ TextureDescriptor_swizzle :: #force_inline proc(self: ^TextureDescriptor) -> Tex return msgSend(TextureSwizzleChannels, self, "swizzle") } @(objc_type=TextureDescriptor, objc_class_name="texture2DDescriptorWithPixelFormat") -TextureDescriptor_texture2DDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: ^NS.Object, height: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { +TextureDescriptor_texture2DDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, height: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "texture2DDescriptorWithPixelFormat:width:height:mipmapped:", pixelFormat, width, height, mipmapped) } @(objc_type=TextureDescriptor, objc_class_name="textureBufferDescriptorWithPixelFormat") -TextureDescriptor_textureBufferDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: ^NS.Object, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { +TextureDescriptor_textureBufferDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureBufferDescriptorWithPixelFormat:width:resourceOptions:usage:", pixelFormat, width, resourceOptions, usage) } @(objc_type=TextureDescriptor, objc_class_name="textureCubeDescriptorWithPixelFormat") -TextureDescriptor_textureCubeDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, size: ^NS.Object, mipmapped: BOOL) -> ^TextureDescriptor { +TextureDescriptor_textureCubeDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, size: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureCubeDescriptorWithPixelFormat:size:mipmapped:", pixelFormat, size, mipmapped) } @(objc_type=TextureDescriptor, objc_name="textureType") @@ -4224,8 +4273,8 @@ TextureDescriptor_usage :: #force_inline proc(self: ^TextureDescriptor) -> Textu return msgSend(TextureUsage, self, "usage") } @(objc_type=TextureDescriptor, objc_name="width") -TextureDescriptor_width :: #force_inline proc(self: ^TextureDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "width") +TextureDescriptor_width :: #force_inline proc(self: ^TextureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "width") } //////////////////////////////////////////////////////////////////////////////// @@ -4326,11 +4375,11 @@ TileRenderPipelineColorAttachmentDescriptorArray_init :: #force_inline proc(self return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, self, "init") } @(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -TileRenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachmentIndex: ^NS.Object) -> ^TileRenderPipelineColorAttachmentDescriptor { +TileRenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^TileRenderPipelineColorAttachmentDescriptor { return msgSend(^TileRenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") -TileRenderPipelineColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachment: ^TileRenderPipelineColorAttachmentDescriptor, attachmentIndex: ^NS.Object) { +TileRenderPipelineColorAttachmentDescriptorArray_setObject :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachment: ^TileRenderPipelineColorAttachmentDescriptor, attachmentIndex: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attachment, attachmentIndex) } @@ -4383,12 +4432,12 @@ TileRenderPipelineDescriptor_label :: #force_inline proc(self: ^TileRenderPipeli return msgSend(^NS.String, self, "label") } @(objc_type=TileRenderPipelineDescriptor, objc_name="maxTotalThreadsPerThreadgroup") -TileRenderPipelineDescriptor_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +TileRenderPipelineDescriptor_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=TileRenderPipelineDescriptor, objc_name="rasterSampleCount") -TileRenderPipelineDescriptor_rasterSampleCount :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "rasterSampleCount") +TileRenderPipelineDescriptor_rasterSampleCount :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "rasterSampleCount") } @(objc_type=TileRenderPipelineDescriptor, objc_name="reset") TileRenderPipelineDescriptor_reset :: #force_inline proc(self: ^TileRenderPipelineDescriptor) { @@ -4403,11 +4452,11 @@ TileRenderPipelineDescriptor_setLabel :: #force_inline proc(self: ^TileRenderPip msgSend(nil, self, "setLabel:", label) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setMaxTotalThreadsPerThreadgroup") -TileRenderPipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^TileRenderPipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.Integer) { +TileRenderPipelineDescriptor_setMaxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^TileRenderPipelineDescriptor, maxTotalThreadsPerThreadgroup: NS.UInteger) { msgSend(nil, self, "setMaxTotalThreadsPerThreadgroup:", maxTotalThreadsPerThreadgroup) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setRasterSampleCount") -TileRenderPipelineDescriptor_setRasterSampleCount :: #force_inline proc(self: ^TileRenderPipelineDescriptor, rasterSampleCount: NS.Integer) { +TileRenderPipelineDescriptor_setRasterSampleCount :: #force_inline proc(self: ^TileRenderPipelineDescriptor, rasterSampleCount: NS.UInteger) { msgSend(nil, self, "setRasterSampleCount:", rasterSampleCount) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setThreadgroupSizeMatchesTileSize") @@ -4415,7 +4464,7 @@ TileRenderPipelineDescriptor_setThreadgroupSizeMatchesTileSize :: #force_inline msgSend(nil, self, "setThreadgroupSizeMatchesTileSize:", threadgroupSizeMatchesTileSize) } @(objc_type=TileRenderPipelineDescriptor, objc_name="setTileFunction") -TileRenderPipelineDescriptor_setTileFunction :: #force_inline proc(self: ^TileRenderPipelineDescriptor, tileFunction: ^NS.Object) { +TileRenderPipelineDescriptor_setTileFunction :: #force_inline proc(self: ^TileRenderPipelineDescriptor, tileFunction: ^Function) { msgSend(nil, self, "setTileFunction:", tileFunction) } @(objc_type=TileRenderPipelineDescriptor, objc_name="threadgroupSizeMatchesTileSize") @@ -4486,8 +4535,8 @@ VertexAttribute_init :: #force_inline proc(self: ^VertexAttribute) -> ^VertexAtt return msgSend(^VertexAttribute, self, "init") } @(objc_type=VertexAttribute, objc_name="attributeIndex") -VertexAttribute_attributeIndex :: #force_inline proc(self: ^VertexAttribute) -> NS.Integer { - return msgSend(NS.Integer, self, "attributeIndex") +VertexAttribute_attributeIndex :: #force_inline proc(self: ^VertexAttribute) -> NS.UInteger { + return msgSend(NS.UInteger, self, "attributeIndex") } @(objc_type=VertexAttribute, objc_name="attributeType") VertexAttribute_attributeType :: #force_inline proc(self: ^VertexAttribute) -> DataType { @@ -4538,19 +4587,19 @@ VertexAttributeDescriptor_init :: #force_inline proc(self: ^VertexAttributeDescr return msgSend(^VertexAttributeDescriptor, self, "init") } @(objc_type=VertexAttributeDescriptor, objc_name="bufferIndex") -VertexAttributeDescriptor_bufferIndex :: #force_inline proc(self: ^VertexAttributeDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "bufferIndex") +VertexAttributeDescriptor_bufferIndex :: #force_inline proc(self: ^VertexAttributeDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "bufferIndex") } @(objc_type=VertexAttributeDescriptor, objc_name="format") VertexAttributeDescriptor_format :: #force_inline proc(self: ^VertexAttributeDescriptor) -> VertexFormat { return msgSend(VertexFormat, self, "format") } @(objc_type=VertexAttributeDescriptor, objc_name="offset") -VertexAttributeDescriptor_offset :: #force_inline proc(self: ^VertexAttributeDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "offset") +VertexAttributeDescriptor_offset :: #force_inline proc(self: ^VertexAttributeDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "offset") } @(objc_type=VertexAttributeDescriptor, objc_name="setBufferIndex") -VertexAttributeDescriptor_setBufferIndex :: #force_inline proc(self: ^VertexAttributeDescriptor, bufferIndex: NS.Integer) { +VertexAttributeDescriptor_setBufferIndex :: #force_inline proc(self: ^VertexAttributeDescriptor, bufferIndex: NS.UInteger) { msgSend(nil, self, "setBufferIndex:", bufferIndex) } @(objc_type=VertexAttributeDescriptor, objc_name="setFormat") @@ -4558,7 +4607,7 @@ VertexAttributeDescriptor_setFormat :: #force_inline proc(self: ^VertexAttribute msgSend(nil, self, "setFormat:", format) } @(objc_type=VertexAttributeDescriptor, objc_name="setOffset") -VertexAttributeDescriptor_setOffset :: #force_inline proc(self: ^VertexAttributeDescriptor, offset: NS.Integer) { +VertexAttributeDescriptor_setOffset :: #force_inline proc(self: ^VertexAttributeDescriptor, offset: NS.UInteger) { msgSend(nil, self, "setOffset:", offset) } @@ -4586,11 +4635,11 @@ VertexAttributeDescriptorArray_init :: #force_inline proc(self: ^VertexAttribute return msgSend(^VertexAttributeDescriptorArray, self, "init") } @(objc_type=VertexAttributeDescriptorArray, objc_name="objectAtIndexedSubscript") -VertexAttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexAttributeDescriptorArray, index: ^NS.Object) -> ^VertexAttributeDescriptor { +VertexAttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexAttributeDescriptorArray, index: NS.UInteger) -> ^VertexAttributeDescriptor { return msgSend(^VertexAttributeDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=VertexAttributeDescriptorArray, objc_name="setObject") -VertexAttributeDescriptorArray_setObject :: #force_inline proc(self: ^VertexAttributeDescriptorArray, attributeDesc: ^VertexAttributeDescriptor, index: ^NS.Object) { +VertexAttributeDescriptorArray_setObject :: #force_inline proc(self: ^VertexAttributeDescriptorArray, attributeDesc: ^VertexAttributeDescriptor, index: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", attributeDesc, index) } @@ -4626,11 +4675,11 @@ VertexBufferLayoutDescriptor_setStepFunction :: #force_inline proc(self: ^Vertex msgSend(nil, self, "setStepFunction:", stepFunction) } @(objc_type=VertexBufferLayoutDescriptor, objc_name="setStepRate") -VertexBufferLayoutDescriptor_setStepRate :: #force_inline proc(self: ^VertexBufferLayoutDescriptor, stepRate: NS.Integer) { +VertexBufferLayoutDescriptor_setStepRate :: #force_inline proc(self: ^VertexBufferLayoutDescriptor, stepRate: NS.UInteger) { msgSend(nil, self, "setStepRate:", stepRate) } @(objc_type=VertexBufferLayoutDescriptor, objc_name="setStride") -VertexBufferLayoutDescriptor_setStride :: #force_inline proc(self: ^VertexBufferLayoutDescriptor, stride: NS.Integer) { +VertexBufferLayoutDescriptor_setStride :: #force_inline proc(self: ^VertexBufferLayoutDescriptor, stride: NS.UInteger) { msgSend(nil, self, "setStride:", stride) } @(objc_type=VertexBufferLayoutDescriptor, objc_name="stepFunction") @@ -4638,12 +4687,12 @@ VertexBufferLayoutDescriptor_stepFunction :: #force_inline proc(self: ^VertexBuf return msgSend(VertexStepFunction, self, "stepFunction") } @(objc_type=VertexBufferLayoutDescriptor, objc_name="stepRate") -VertexBufferLayoutDescriptor_stepRate :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "stepRate") +VertexBufferLayoutDescriptor_stepRate :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "stepRate") } @(objc_type=VertexBufferLayoutDescriptor, objc_name="stride") -VertexBufferLayoutDescriptor_stride :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "stride") +VertexBufferLayoutDescriptor_stride :: #force_inline proc(self: ^VertexBufferLayoutDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "stride") } //////////////////////////////////////////////////////////////////////////////// @@ -4670,11 +4719,11 @@ VertexBufferLayoutDescriptorArray_init :: #force_inline proc(self: ^VertexBuffer return msgSend(^VertexBufferLayoutDescriptorArray, self, "init") } @(objc_type=VertexBufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") -VertexBufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, index: ^NS.Object) -> ^VertexBufferLayoutDescriptor { +VertexBufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, index: NS.UInteger) -> ^VertexBufferLayoutDescriptor { return msgSend(^VertexBufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=VertexBufferLayoutDescriptorArray, objc_name="setObject") -VertexBufferLayoutDescriptorArray_setObject :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, bufferDesc: ^VertexBufferLayoutDescriptor, index: ^NS.Object) { +VertexBufferLayoutDescriptorArray_setObject :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, bufferDesc: ^VertexBufferLayoutDescriptor, index: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", bufferDesc, index) } @@ -4745,11 +4794,11 @@ VisibleFunctionTableDescriptor_init :: #force_inline proc(self: ^VisibleFunction return msgSend(^VisibleFunctionTableDescriptor, self, "init") } @(objc_type=VisibleFunctionTableDescriptor, objc_name="functionCount") -VisibleFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^VisibleFunctionTableDescriptor) -> NS.Integer { - return msgSend(NS.Integer, self, "functionCount") +VisibleFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^VisibleFunctionTableDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "functionCount") } @(objc_type=VisibleFunctionTableDescriptor, objc_name="setFunctionCount") -VisibleFunctionTableDescriptor_setFunctionCount :: #force_inline proc(self: ^VisibleFunctionTableDescriptor, functionCount: NS.Integer) { +VisibleFunctionTableDescriptor_setFunctionCount :: #force_inline proc(self: ^VisibleFunctionTableDescriptor, functionCount: NS.UInteger) { msgSend(nil, self, "setFunctionCount:", functionCount) } @(objc_type=VisibleFunctionTableDescriptor, objc_class_name="visibleFunctionTableDescriptor") @@ -4767,11 +4816,11 @@ Methods: size */ @(objc_class="MTLAccelerationStructure") -AccelerationStructure :: struct { using _: NS.Object } +AccelerationStructure :: struct { using _: Resource } @(objc_type=AccelerationStructure, objc_name="size") -AccelerationStructure_size :: #force_inline proc(self: ^AccelerationStructure) -> NS.Integer { - return msgSend(NS.Integer, self, "size") +AccelerationStructure_size :: #force_inline proc(self: ^AccelerationStructure) -> NS.UInteger { + return msgSend(NS.UInteger, self, "size") } //////////////////////////////////////////////////////////////////////////////// @@ -4798,51 +4847,51 @@ Methods: AccelerationStructureCommandEncoder :: struct { using _: NS.Object } @(objc_type=AccelerationStructureCommandEncoder, objc_name="buildAccelerationStructure") -AccelerationStructureCommandEncoder_buildAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { +AccelerationStructureCommandEncoder_buildAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^AccelerationStructure, descriptor: ^AccelerationStructureDescriptor, scratchBuffer: ^Buffer, scratchBufferOffset: NS.UInteger) { msgSend(nil, self, "buildAccelerationStructure:descriptor:scratchBuffer:scratchBufferOffset:", accelerationStructure, descriptor, scratchBuffer, scratchBufferOffset) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAccelerationStructure") -AccelerationStructureCommandEncoder_copyAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { +AccelerationStructureCommandEncoder_copyAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^AccelerationStructure, destinationAccelerationStructure: ^AccelerationStructure) { msgSend(nil, self, "copyAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAndCompactAccelerationStructure") -AccelerationStructureCommandEncoder_copyAndCompactAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, destinationAccelerationStructure: ^NS.Object) { +AccelerationStructureCommandEncoder_copyAndCompactAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^AccelerationStructure, destinationAccelerationStructure: ^AccelerationStructure) { msgSend(nil, self, "copyAndCompactAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="refitAccelerationStructure") -AccelerationStructureCommandEncoder_refitAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^NS.Object, descriptor: ^AccelerationStructureDescriptor, destinationAccelerationStructure: ^NS.Object, scratchBuffer: ^NS.Object, scratchBufferOffset: ^NS.Object) { +AccelerationStructureCommandEncoder_refitAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^AccelerationStructure, descriptor: ^AccelerationStructureDescriptor, destinationAccelerationStructure: ^AccelerationStructure, scratchBuffer: ^Buffer, scratchBufferOffset: NS.UInteger) { msgSend(nil, self, "refitAccelerationStructure:descriptor:destination:scratchBuffer:scratchBufferOffset:", sourceAccelerationStructure, descriptor, destinationAccelerationStructure, scratchBuffer, scratchBufferOffset) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="sampleCountersInBuffer") -AccelerationStructureCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +AccelerationStructureCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sampleBuffer: ^Buffer, sampleIndex: NS.UInteger, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="updateFence") -AccelerationStructureCommandEncoder_updateFence :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { +AccelerationStructureCommandEncoder_updateFence :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, fence: ^Fence) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useHeap") -AccelerationStructureCommandEncoder_useHeap :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heap: ^NS.Object) { +AccelerationStructureCommandEncoder_useHeap :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heap: ^Heap) { msgSend(nil, self, "useHeap:", heap) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useHeaps") -AccelerationStructureCommandEncoder_useHeaps :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { +AccelerationStructureCommandEncoder_useHeaps :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heaps: [^]^Heap, count: NS.UInteger) { msgSend(nil, self, "useHeaps:count:", heaps, count) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useResource") -AccelerationStructureCommandEncoder_useResource :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { +AccelerationStructureCommandEncoder_useResource :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resource: ^Resource, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useResources") -AccelerationStructureCommandEncoder_useResources :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { +AccelerationStructureCommandEncoder_useResources :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage) { msgSend(nil, self, "useResources:count:usage:", resources, count, usage) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="waitForFence") -AccelerationStructureCommandEncoder_waitForFence :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, fence: ^NS.Object) { +AccelerationStructureCommandEncoder_waitForFence :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, fence: ^Fence) { msgSend(nil, self, "waitForFence:", fence) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="writeCompactedAccelerationStructureSize") -AccelerationStructureCommandEncoder_writeCompactedAccelerationStructureSize :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object) { +AccelerationStructureCommandEncoder_writeCompactedAccelerationStructureSize :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^AccelerationStructure, buffer: ^Buffer, offset: NS.UInteger) { msgSend(nil, self, "writeCompactedAccelerationStructureSize:toBuffer:offset:", accelerationStructure, buffer, offset) } @@ -4884,11 +4933,11 @@ Methods: ArgumentEncoder :: struct { using _: NS.Object } @(objc_type=ArgumentEncoder, objc_name="alignment") -ArgumentEncoder_alignment :: #force_inline proc(self: ^ArgumentEncoder) -> NS.Integer { - return msgSend(NS.Integer, self, "alignment") +ArgumentEncoder_alignment :: #force_inline proc(self: ^ArgumentEncoder) -> NS.UInteger { + return msgSend(NS.UInteger, self, "alignment") } @(objc_type=ArgumentEncoder, objc_name="constantDataAtIndex") -ArgumentEncoder_constantDataAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: ^NS.Object) -> rawptr { +ArgumentEncoder_constantDataAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: NS.UInteger) -> rawptr { return msgSend(rawptr, self, "constantDataAtIndex:", index) } @(objc_type=ArgumentEncoder, objc_name="device") @@ -4896,59 +4945,59 @@ ArgumentEncoder_device :: #force_inline proc(self: ^ArgumentEncoder) -> ^Argumen return msgSend(^ArgumentEncoder, self, "device") } @(objc_type=ArgumentEncoder, objc_name="encodedLength") -ArgumentEncoder_encodedLength :: #force_inline proc(self: ^ArgumentEncoder) -> NS.Integer { - return msgSend(NS.Integer, self, "encodedLength") +ArgumentEncoder_encodedLength :: #force_inline proc(self: ^ArgumentEncoder) -> NS.UInteger { + return msgSend(NS.UInteger, self, "encodedLength") } @(objc_type=ArgumentEncoder, objc_name="label") ArgumentEncoder_label :: #force_inline proc(self: ^ArgumentEncoder) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=ArgumentEncoder, objc_name="newArgumentEncoderForBufferAtIndex") -ArgumentEncoder_newArgumentEncoderForBufferAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: ^NS.Object) -> ^ArgumentEncoder { +ArgumentEncoder_newArgumentEncoderForBufferAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: NS.UInteger) -> ^ArgumentEncoder { return msgSend(^ArgumentEncoder, self, "newArgumentEncoderForBufferAtIndex:", index) } @(objc_type=ArgumentEncoder, objc_name="setAccelerationStructure") -ArgumentEncoder_setAccelerationStructure :: #force_inline proc(self: ^ArgumentEncoder, accelerationStructure: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setAccelerationStructure :: #force_inline proc(self: ^ArgumentEncoder, accelerationStructure: ^AccelerationStructure, index: NS.UInteger) { msgSend(nil, self, "setAccelerationStructure:atIndex:", accelerationStructure, index) } -@(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_offset_") -ArgumentEncoder_setArgumentBuffer_offset_ :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, offset: ^NS.Object) { +@(objc_type=ArgumentEncoder, objc_name="setArgumentBufferWithOffset") +ArgumentEncoder_setArgumentBufferWithOffset :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^Buffer, offset: NS.UInteger) { msgSend(nil, self, "setArgumentBuffer:offset:", argumentBuffer, offset) } -@(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_startOffset_arrayElement_") -ArgumentEncoder_setArgumentBuffer_startOffset_arrayElement_ :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^NS.Object, startOffset: ^NS.Object, arrayElement: ^NS.Object) { +@(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_startOffsetWithStartOffset") +ArgumentEncoder_setArgumentBuffer_startOffsetWithStartOffset :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^Buffer, startOffset: NS.UInteger, arrayElement: NS.UInteger) { msgSend(nil, self, "setArgumentBuffer:startOffset:arrayElement:", argumentBuffer, startOffset, arrayElement) } @(objc_type=ArgumentEncoder, objc_name="setBuffer") -ArgumentEncoder_setBuffer :: #force_inline proc(self: ^ArgumentEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setBuffer :: #force_inline proc(self: ^ArgumentEncoder, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=ArgumentEncoder, objc_name="setBuffers") -ArgumentEncoder_setBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +ArgumentEncoder_setBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineState") -ArgumentEncoder_setComputePipelineState :: #force_inline proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setComputePipelineState :: #force_inline proc(self: ^ArgumentEncoder, pipeline: ^ComputePipelineState, index: NS.UInteger) { msgSend(nil, self, "setComputePipelineState:atIndex:", pipeline, index) } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineStates") -ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: [^]^ComputePipelineState, range: NS.Range) { msgSend(nil, self, "setComputePipelineStates:withRange:", pipelines, range) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffer") -ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^Buffer, index: NS.UInteger) { msgSend(nil, self, "setIndirectCommandBuffer:atIndex:", indirectCommandBuffer, index) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffers") -ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: [^]^Buffer, range: NS.Range) { msgSend(nil, self, "setIndirectCommandBuffers:withRange:", buffers, range) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTable") -ArgumentEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTable: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTable: ^IntersectionFunctionTable, index: NS.UInteger) { msgSend(nil, self, "setIntersectionFunctionTable:atIndex:", intersectionFunctionTable, index) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTables") -ArgumentEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTables: [^]^IntersectionFunctionTable, range: NS.Range) { msgSend(nil, self, "setIntersectionFunctionTables:withRange:", intersectionFunctionTables, range) } @(objc_type=ArgumentEncoder, objc_name="setLabel") @@ -4956,35 +5005,35 @@ ArgumentEncoder_setLabel :: #force_inline proc(self: ^ArgumentEncoder, label: ^N msgSend(nil, self, "setLabel:", label) } @(objc_type=ArgumentEncoder, objc_name="setRenderPipelineState") -ArgumentEncoder_setRenderPipelineState :: #force_inline proc(self: ^ArgumentEncoder, pipeline: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setRenderPipelineState :: #force_inline proc(self: ^ArgumentEncoder, pipeline: ^RenderPipelineState, index: NS.UInteger) { msgSend(nil, self, "setRenderPipelineState:atIndex:", pipeline, index) } @(objc_type=ArgumentEncoder, objc_name="setRenderPipelineStates") -ArgumentEncoder_setRenderPipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setRenderPipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: [^]^RenderPipelineState, range: NS.Range) { msgSend(nil, self, "setRenderPipelineStates:withRange:", pipelines, range) } @(objc_type=ArgumentEncoder, objc_name="setSamplerState") -ArgumentEncoder_setSamplerState :: #force_inline proc(self: ^ArgumentEncoder, sampler: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setSamplerState :: #force_inline proc(self: ^ArgumentEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) } @(objc_type=ArgumentEncoder, objc_name="setSamplerStates") -ArgumentEncoder_setSamplerStates :: #force_inline proc(self: ^ArgumentEncoder, samplers: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setSamplerStates :: #force_inline proc(self: ^ArgumentEncoder, samplers: [^]^SamplerState, range: NS.Range) { msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) } @(objc_type=ArgumentEncoder, objc_name="setTexture") -ArgumentEncoder_setTexture :: #force_inline proc(self: ^ArgumentEncoder, texture: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setTexture :: #force_inline proc(self: ^ArgumentEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setTexture:atIndex:", texture, index) } @(objc_type=ArgumentEncoder, objc_name="setTextures") -ArgumentEncoder_setTextures :: #force_inline proc(self: ^ArgumentEncoder, textures: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setTextures :: #force_inline proc(self: ^ArgumentEncoder, textures: [^]^Texture, range: NS.Range) { msgSend(nil, self, "setTextures:withRange:", textures, range) } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTable") -ArgumentEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTable: ^NS.Object, index: ^NS.Object) { +ArgumentEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTable: ^VisibleFunctionTable, index: NS.UInteger) { msgSend(nil, self, "setVisibleFunctionTable:atIndex:", visibleFunctionTable, index) } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTables") -ArgumentEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { +ArgumentEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTables: [^]^VisibleFunctionTable, range: NS.Range) { msgSend(nil, self, "setVisibleFunctionTables:withRange:", visibleFunctionTables, range) } @@ -5007,16 +5056,19 @@ Methods: BinaryArchive :: struct { using _: NS.Copying(BinaryArchive) } @(objc_type=BinaryArchive, objc_name="addComputePipelineFunctionsWithDescriptor") -BinaryArchive_addComputePipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor, error: ^^NS.Error ) -> BOOL { - return msgSend(BOOL, self, "addComputePipelineFunctionsWithDescriptor:error:", descriptor, error) +BinaryArchive_addComputePipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor) -> (ok: bool, error: ^NS.Error) { + ok = msgSend(BOOL, self, "addComputePipelineFunctionsWithDescriptor:error:", descriptor, &error) + return } @(objc_type=BinaryArchive, objc_name="addRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { - return msgSend(BOOL, self, "addRenderPipelineFunctionsWithDescriptor:error:", descriptor, error) +BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor) -> (ok: bool, error: ^NS.Error) { + ok = msgSend(BOOL, self, "addRenderPipelineFunctionsWithDescriptor:error:", descriptor, &error) + return } @(objc_type=BinaryArchive, objc_name="addTileRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor, error: ^^NS.Error ) -> BOOL { - return msgSend(BOOL, self, "addTileRenderPipelineFunctionsWithDescriptor:error:", descriptor, error) +BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor) -> (ok: bool, error: ^NS.Error) { + ok = msgSend(BOOL, self, "addTileRenderPipelineFunctionsWithDescriptor:error:", descriptor, &error) + return } @(objc_type=BinaryArchive, objc_name="device") BinaryArchive_device :: #force_inline proc(self: ^BinaryArchive) -> ^BinaryArchive { @@ -5027,8 +5079,9 @@ BinaryArchive_label :: #force_inline proc(self: ^BinaryArchive) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=BinaryArchive, objc_name="serializeToURL") -BinaryArchive_serializeToURL :: #force_inline proc(self: ^BinaryArchive, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { - return msgSend(BOOL, self, "serializeToURL:error:", url, error) +BinaryArchive_serializeToURL :: #force_inline proc(self: ^BinaryArchive, url: ^NS.URL) -> (ok: bool, error: ^NS.Error) { + ok = msgSend(BOOL, self, "serializeToURL:error:", url, &error) + return } @(objc_type=BinaryArchive, objc_name="setLabel") BinaryArchive_setLabel :: #force_inline proc(self: ^BinaryArchive, label: ^NS.String) { @@ -5072,103 +5125,103 @@ Methods: BlitCommandEncoder :: struct { using _: NS.Object } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { +BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, sourceBytesPerRow: ^NS.Object, sourceBytesPerImage: ^NS.Object, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin, options: BlitOption) { +BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin, options: BlitOption) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:options:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin, options) } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^NS.Object, sourceOffset: ^NS.Object, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, size: ^NS.Object) { +BlitCommandEncoder_copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, size: NS.UInteger) { msgSend(nil, self, "copyFromBuffer:sourceOffset:toBuffer:destinationOffset:size:", sourceBuffer, sourceOffset, destinationBuffer, destinationOffset, size) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, destinationBytesPerRow: NS.UInteger, destinationBytesPerImage: NS.UInteger) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object, destinationBytesPerRow: ^NS.Object, destinationBytesPerImage: ^NS.Object, options: BlitOption) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, destinationBytesPerRow: NS.UInteger, destinationBytesPerImage: NS.UInteger, options: BlitOption) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:options:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage, options) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, sourceOrigin: Origin, sourceSize: Size, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, destinationOrigin: Origin) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, sourceSlice: ^NS.Object, sourceLevel: ^NS.Object, destinationTexture: ^NS.Object, destinationSlice: ^NS.Object, destinationLevel: ^NS.Object, sliceCount: ^NS.Object, levelCount: ^NS.Object) { +BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, sliceCount: NS.UInteger, levelCount: NS.UInteger) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:toTexture:destinationSlice:destinationLevel:sliceCount:levelCount:", sourceTexture, sourceSlice, sourceLevel, destinationTexture, destinationSlice, destinationLevel, sliceCount, levelCount) } -@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_toTexture_") -BlitCommandEncoder_copyFromTexture_toTexture_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^NS.Object, destinationTexture: ^NS.Object) { +@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture") +BlitCommandEncoder_copyFromTexture :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, destinationTexture: ^Texture) { msgSend(nil, self, "copyFromTexture:toTexture:", sourceTexture, destinationTexture) } @(objc_type=BlitCommandEncoder, objc_name="copyIndirectCommandBuffer") -BlitCommandEncoder_copyIndirectCommandBuffer :: #force_inline proc(self: ^BlitCommandEncoder, source: ^NS.Object, sourceRange: NS.Range, destination: ^NS.Object, destinationIndex: ^NS.Object) { +BlitCommandEncoder_copyIndirectCommandBuffer :: #force_inline proc(self: ^BlitCommandEncoder, source: ^IndirectCommandBuffer, sourceRange: NS.Range, destination: ^IndirectCommandBuffer, destinationIndex: NS.UInteger) { msgSend(nil, self, "copyIndirectCommandBuffer:sourceRange:destination:destinationIndex:", source, sourceRange, destination, destinationIndex) } @(objc_type=BlitCommandEncoder, objc_name="fillBuffer") -BlitCommandEncoder_fillBuffer :: #force_inline proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range, value: u8) { +BlitCommandEncoder_fillBuffer :: #force_inline proc(self: ^BlitCommandEncoder, buffer: ^Buffer, range: NS.Range, value: u8) { msgSend(nil, self, "fillBuffer:range:value:", buffer, range, value) } @(objc_type=BlitCommandEncoder, objc_name="generateMipmapsForTexture") -BlitCommandEncoder_generateMipmapsForTexture :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { +BlitCommandEncoder_generateMipmapsForTexture :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture) { msgSend(nil, self, "generateMipmapsForTexture:", texture) } @(objc_type=BlitCommandEncoder, objc_name="getTextureAccessCounters") -BlitCommandEncoder_getTextureAccessCounters :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object, resetCounters: BOOL, countersBuffer: ^NS.Object, countersBufferOffset: ^NS.Object) { +BlitCommandEncoder_getTextureAccessCounters :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture, region: Region, mipLevel: NS.UInteger, slice: NS.UInteger, resetCounters: BOOL, countersBuffer: ^Buffer, countersBufferOffset: NS.UInteger) { msgSend(nil, self, "getTextureAccessCounters:region:mipLevel:slice:resetCounters:countersBuffer:countersBufferOffset:", texture, region, mipLevel, slice, resetCounters, countersBuffer, countersBufferOffset) } @(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForCPUAccess") -BlitCommandEncoder_optimizeContentsForCPUAccess :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { +BlitCommandEncoder_optimizeContentsForCPUAccess :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture) { msgSend(nil, self, "optimizeContentsForCPUAccess:", texture) } -@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForCPUAccess_slice_level_") -BlitCommandEncoder_optimizeContentsForCPUAccess_slice_level_ :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { +@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForCPUAccessWithSliceAndLevel") +BlitCommandEncoder_optimizeContentsForCPUAccessWithSliceAndLevel :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture, slice: NS.UInteger, level: NS.UInteger) { msgSend(nil, self, "optimizeContentsForCPUAccess:slice:level:", texture, slice, level) } @(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForGPUAccess") -BlitCommandEncoder_optimizeContentsForGPUAccess :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object) { +BlitCommandEncoder_optimizeContentsForGPUAccess :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture) { msgSend(nil, self, "optimizeContentsForGPUAccess:", texture) } -@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForGPUAccess_slice_level_") -BlitCommandEncoder_optimizeContentsForGPUAccess_slice_level_ :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { +@(objc_type=BlitCommandEncoder, objc_name="optimizeContentsForGPUAccessWithSliceAndLevel") +BlitCommandEncoder_optimizeContentsForGPUAccessWithSliceAndLevel :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture, slice: NS.UInteger, level: NS.UInteger) { msgSend(nil, self, "optimizeContentsForGPUAccess:slice:level:", texture, slice, level) } @(objc_type=BlitCommandEncoder, objc_name="optimizeIndirectCommandBuffer") -BlitCommandEncoder_optimizeIndirectCommandBuffer :: #force_inline proc(self: ^BlitCommandEncoder, indirectCommandBuffer: ^NS.Object, range: NS.Range) { +BlitCommandEncoder_optimizeIndirectCommandBuffer :: #force_inline proc(self: ^BlitCommandEncoder, indirectCommandBuffer: ^Buffer, range: NS.Range) { msgSend(nil, self, "optimizeIndirectCommandBuffer:withRange:", indirectCommandBuffer, range) } @(objc_type=BlitCommandEncoder, objc_name="resetCommandsInBuffer") -BlitCommandEncoder_resetCommandsInBuffer :: #force_inline proc(self: ^BlitCommandEncoder, buffer: ^NS.Object, range: NS.Range) { +BlitCommandEncoder_resetCommandsInBuffer :: #force_inline proc(self: ^BlitCommandEncoder, buffer: ^Buffer, range: NS.Range) { msgSend(nil, self, "resetCommandsInBuffer:withRange:", buffer, range) } @(objc_type=BlitCommandEncoder, objc_name="resetTextureAccessCounters") -BlitCommandEncoder_resetTextureAccessCounters :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, region: Region, mipLevel: ^NS.Object, slice: ^NS.Object) { +BlitCommandEncoder_resetTextureAccessCounters :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture, region: Region, mipLevel: NS.UInteger, slice: NS.UInteger) { msgSend(nil, self, "resetTextureAccessCounters:region:mipLevel:slice:", texture, region, mipLevel, slice) } @(objc_type=BlitCommandEncoder, objc_name="resolveCounters") -BlitCommandEncoder_resolveCounters :: #force_inline proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, range: NS.Range, destinationBuffer: ^NS.Object, destinationOffset: ^NS.Object) { +BlitCommandEncoder_resolveCounters :: #force_inline proc(self: ^BlitCommandEncoder, sampleBuffer: ^Buffer, range: NS.Range, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger) { msgSend(nil, self, "resolveCounters:inRange:destinationBuffer:destinationOffset:", sampleBuffer, range, destinationBuffer, destinationOffset) } @(objc_type=BlitCommandEncoder, objc_name="sampleCountersInBuffer") -BlitCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^BlitCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +BlitCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^BlitCommandEncoder, sampleBuffer: ^Buffer, sampleIndex: NS.UInteger, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=BlitCommandEncoder, objc_name="synchronizeResource") -BlitCommandEncoder_synchronizeResource :: #force_inline proc(self: ^BlitCommandEncoder, resource: ^NS.Object) { +BlitCommandEncoder_synchronizeResource :: #force_inline proc(self: ^BlitCommandEncoder, resource: ^Resource) { msgSend(nil, self, "synchronizeResource:", resource) } @(objc_type=BlitCommandEncoder, objc_name="synchronizeTexture") -BlitCommandEncoder_synchronizeTexture :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^NS.Object, slice: ^NS.Object, level: ^NS.Object) { +BlitCommandEncoder_synchronizeTexture :: #force_inline proc(self: ^BlitCommandEncoder, texture: ^Texture, slice: NS.UInteger, level: NS.UInteger) { msgSend(nil, self, "synchronizeTexture:slice:level:", texture, slice, level) } @(objc_type=BlitCommandEncoder, objc_name="updateFence") -BlitCommandEncoder_updateFence :: #force_inline proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { +BlitCommandEncoder_updateFence :: #force_inline proc(self: ^BlitCommandEncoder, fence: ^Fence) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=BlitCommandEncoder, objc_name="waitForFence") -BlitCommandEncoder_waitForFence :: #force_inline proc(self: ^BlitCommandEncoder, fence: ^NS.Object) { +BlitCommandEncoder_waitForFence :: #force_inline proc(self: ^BlitCommandEncoder, fence: ^Fence) { msgSend(nil, self, "waitForFence:", fence) } @@ -5189,7 +5242,7 @@ Methods: removeAllDebugMarkers */ @(objc_class="MTLBuffer") -Buffer :: struct { using _: NS.Object } +Buffer :: struct { using _: Resource } @(objc_type=Buffer, objc_name="addDebugMarker") Buffer_addDebugMarker :: #force_inline proc(self: ^Buffer, marker: ^NS.String, range: NS.Range) { @@ -5204,15 +5257,15 @@ Buffer_didModifyRange :: #force_inline proc(self: ^Buffer, range: NS.Range) { msgSend(nil, self, "didModifyRange:", range) } @(objc_type=Buffer, objc_name="length") -Buffer_length :: #force_inline proc(self: ^Buffer) -> NS.Integer { - return msgSend(NS.Integer, self, "length") +Buffer_length :: #force_inline proc(self: ^Buffer) -> NS.UInteger { + return msgSend(NS.UInteger, self, "length") } @(objc_type=Buffer, objc_name="newRemoteBufferViewForDevice") -Buffer_newRemoteBufferViewForDevice :: #force_inline proc(self: ^Buffer, device: ^NS.Object) -> ^Buffer { +Buffer_newRemoteBufferViewForDevice :: #force_inline proc(self: ^Buffer, device: ^Device) -> ^Buffer { return msgSend(^Buffer, self, "newRemoteBufferViewForDevice:", device) } @(objc_type=Buffer, objc_name="newTextureWithDescriptor") -Buffer_newTextureWithDescriptor :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: ^NS.Object, bytesPerRow: ^NS.Object) -> ^Buffer { +Buffer_newTextureWithDescriptor :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: NS.UInteger, bytesPerRow: NS.UInteger) -> ^Buffer { return msgSend(^Buffer, self, "newTextureWithDescriptor:offset:bytesPerRow:", descriptor, offset, bytesPerRow) } @(objc_type=Buffer, objc_name="remoteStorageBuffer") @@ -5366,11 +5419,11 @@ CommandBuffer_device :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuff return msgSend(^CommandBuffer, self, "device") } @(objc_type=CommandBuffer, objc_name="encodeSignalEvent") -CommandBuffer_encodeSignalEvent :: #force_inline proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { +CommandBuffer_encodeSignalEvent :: #force_inline proc(self: ^CommandBuffer, event: ^Event, value: u64) { msgSend(nil, self, "encodeSignalEvent:value:", event, value) } @(objc_type=CommandBuffer, objc_name="encodeWaitForEvent") -CommandBuffer_encodeWaitForEvent :: #force_inline proc(self: ^CommandBuffer, event: ^NS.Object, value: u64) { +CommandBuffer_encodeWaitForEvent :: #force_inline proc(self: ^CommandBuffer, event: ^Event, value: u64) { msgSend(nil, self, "encodeWaitForEvent:value:", event, value) } @(objc_type=CommandBuffer, objc_name="enqueue") @@ -5410,15 +5463,15 @@ CommandBuffer_popDebugGroup :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "popDebugGroup") } @(objc_type=CommandBuffer, objc_name="presentDrawable") -CommandBuffer_presentDrawable :: #force_inline proc(self: ^CommandBuffer, drawable: ^NS.Object) { +CommandBuffer_presentDrawable :: #force_inline proc(self: ^CommandBuffer, drawable: ^Drawable) { msgSend(nil, self, "presentDrawable:", drawable) } -@(objc_type=CommandBuffer, objc_name="presentDrawable_afterMinimumDuration_") -CommandBuffer_presentDrawable_afterMinimumDuration_ :: #force_inline proc(self: ^CommandBuffer, drawable: ^NS.Object, duration: CFTimeInterval) { +@(objc_type=CommandBuffer, objc_name="presentDrawableAfterMinimumDuration") +CommandBuffer_presentDrawableAfterMinimumDuration :: #force_inline proc(self: ^CommandBuffer, drawable: ^Drawable, duration: CFTimeInterval) { msgSend(nil, self, "presentDrawable:afterMinimumDuration:", drawable, duration) } -@(objc_type=CommandBuffer, objc_name="presentDrawable_atTime_") -CommandBuffer_presentDrawable_atTime_ :: #force_inline proc(self: ^CommandBuffer, drawable: ^NS.Object, presentationTime: CFTimeInterval) { +@(objc_type=CommandBuffer, objc_name="presentDrawableAtTime") +CommandBuffer_presentDrawableAtTime :: #force_inline proc(self: ^CommandBuffer, drawable: ^Drawable, presentationTime: CFTimeInterval) { msgSend(nil, self, "presentDrawable:atTime:", drawable, presentationTime) } @(objc_type=CommandBuffer, objc_name="pushDebugGroup") @@ -5630,7 +5683,7 @@ ComputeCommandEncoder_dispatchThreadgroups :: #force_inline proc(self: ^ComputeC msgSend(nil, self, "dispatchThreadgroups:threadsPerThreadgroup:", threadgroupsPerGrid, threadsPerThreadgroup) } @(objc_type=ComputeCommandEncoder, objc_name="dispatchThreadgroupsWithIndirectBuffer") -ComputeCommandEncoder_dispatchThreadgroupsWithIndirectBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object, threadsPerThreadgroup: Size) { +ComputeCommandEncoder_dispatchThreadgroupsWithIndirectBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger, threadsPerThreadgroup: Size) { msgSend(nil, self, "dispatchThreadgroupsWithIndirectBuffer:indirectBufferOffset:threadsPerThreadgroup:", indirectBuffer, indirectBufferOffset, threadsPerThreadgroup) } @(objc_type=ComputeCommandEncoder, objc_name="dispatchThreads") @@ -5641,16 +5694,16 @@ ComputeCommandEncoder_dispatchThreads :: #force_inline proc(self: ^ComputeComman ComputeCommandEncoder_dispatchType :: #force_inline proc(self: ^ComputeCommandEncoder) -> DispatchType { return msgSend(DispatchType, self, "dispatchType") } -@(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_") -ComputeCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^ComputeCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +@(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBuffer") +ComputeCommandEncoder_executeCommandsInBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, indirectCommandbuffer: ^Buffer, indirectRangeBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "executeCommandsInBuffer:indirectBuffer:indirectBufferOffset:", indirectCommandbuffer, indirectRangeBuffer, indirectBufferOffset) } -@(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBuffer_withRange_") -ComputeCommandEncoder_executeCommandsInBuffer_withRange_ :: #force_inline proc(self: ^ComputeCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { +@(objc_type=ComputeCommandEncoder, objc_name="executeCommandsInBufferWithRange") +ComputeCommandEncoder_executeCommandsInBufferWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, indirectCommandBuffer: ^Buffer, executionRange: NS.Range) { msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) } @(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithResources") -ComputeCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object) { +ComputeCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: [^]^Resource, count: NS.UInteger) { msgSend(nil, self, "memoryBarrierWithResources:count:", resources, count) } @(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithScope") @@ -5658,59 +5711,59 @@ ComputeCommandEncoder_memoryBarrierWithScope :: #force_inline proc(self: ^Comput msgSend(nil, self, "memoryBarrierWithScope:", scope) } @(objc_type=ComputeCommandEncoder, objc_name="sampleCountersInBuffer") -ComputeCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +ComputeCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, sampleBuffer: ^Buffer, sampleIndex: NS.UInteger, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=ComputeCommandEncoder, objc_name="setAccelerationStructure") -ComputeCommandEncoder_setAccelerationStructure :: #force_inline proc(self: ^ComputeCommandEncoder, accelerationStructure: ^NS.Object, bufferIndex: ^NS.Object) { +ComputeCommandEncoder_setAccelerationStructure :: #force_inline proc(self: ^ComputeCommandEncoder, accelerationStructure: ^AccelerationStructure, bufferIndex: NS.UInteger) { msgSend(nil, self, "setAccelerationStructure:atBufferIndex:", accelerationStructure, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setBuffer") -ComputeCommandEncoder_setBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=ComputeCommandEncoder, objc_name="setBufferOffset") -ComputeCommandEncoder_setBufferOffset :: #force_inline proc(self: ^ComputeCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setBufferOffset :: #force_inline proc(self: ^ComputeCommandEncoder, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setBufferOffset:atIndex:", offset, index) } @(objc_type=ComputeCommandEncoder, objc_name="setBuffers") -ComputeCommandEncoder_setBuffers :: #force_inline proc(self: ^ComputeCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +ComputeCommandEncoder_setBuffers :: #force_inline proc(self: ^ComputeCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=ComputeCommandEncoder, objc_name="setBytes") -ComputeCommandEncoder_setBytes :: #force_inline proc(self: ^ComputeCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setBytes :: #force_inline proc(self: ^ComputeCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setBytes:length:atIndex:", bytes, length, index) } @(objc_type=ComputeCommandEncoder, objc_name="setComputePipelineState") -ComputeCommandEncoder_setComputePipelineState :: #force_inline proc(self: ^ComputeCommandEncoder, pipelineState: ^NS.Object) { +ComputeCommandEncoder_setComputePipelineState :: #force_inline proc(self: ^ComputeCommandEncoder, pipelineState: ^ComputePipelineState) { msgSend(nil, self, "setComputePipelineState:", pipelineState) } @(objc_type=ComputeCommandEncoder, objc_name="setImageblockWidth") -ComputeCommandEncoder_setImageblockWidth :: #force_inline proc(self: ^ComputeCommandEncoder, width: ^NS.Object, height: ^NS.Object) { +ComputeCommandEncoder_setImageblockWidth :: #force_inline proc(self: ^ComputeCommandEncoder, width: NS.UInteger, height: NS.UInteger) { msgSend(nil, self, "setImageblockWidth:height:", width, height) } @(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTable") -ComputeCommandEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { +ComputeCommandEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTable: ^IntersectionFunctionTable, bufferIndex: NS.UInteger) { msgSend(nil, self, "setIntersectionFunctionTable:atBufferIndex:", intersectionFunctionTable, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTables") -ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: ^^NS.Object, range: NS.Range) { +ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: [^]^IntersectionFunctionTable, range: NS.Range) { msgSend(nil, self, "setIntersectionFunctionTables:withBufferRange:", intersectionFunctionTables, range) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_atIndex_") -ComputeCommandEncoder_setSamplerState_atIndex_ :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStateAtIndex") +ComputeCommandEncoder_setSamplerStateAtIndex :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_lodMinClamp_lodMaxClampAtIndex") +ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_lodMinClamps_lodMaxClampsWithRange") +ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_withRange_") -ComputeCommandEncoder_setSamplerStates_withRange_ :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStatesWithRange") +ComputeCommandEncoder_setSamplerStatesWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) } @(objc_type=ComputeCommandEncoder, objc_name="setStageInRegion") @@ -5718,51 +5771,51 @@ ComputeCommandEncoder_setStageInRegion :: #force_inline proc(self: ^ComputeComma msgSend(nil, self, "setStageInRegion:", region) } @(objc_type=ComputeCommandEncoder, objc_name="setStageInRegionWithIndirectBuffer") -ComputeCommandEncoder_setStageInRegionWithIndirectBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +ComputeCommandEncoder_setStageInRegionWithIndirectBuffer :: #force_inline proc(self: ^ComputeCommandEncoder, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "setStageInRegionWithIndirectBuffer:indirectBufferOffset:", indirectBuffer, indirectBufferOffset) } @(objc_type=ComputeCommandEncoder, objc_name="setTexture") -ComputeCommandEncoder_setTexture :: #force_inline proc(self: ^ComputeCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setTexture :: #force_inline proc(self: ^ComputeCommandEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setTexture:atIndex:", texture, index) } @(objc_type=ComputeCommandEncoder, objc_name="setTextures") -ComputeCommandEncoder_setTextures :: #force_inline proc(self: ^ComputeCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +ComputeCommandEncoder_setTextures :: #force_inline proc(self: ^ComputeCommandEncoder, textures: [^]^Texture, range: NS.Range) { msgSend(nil, self, "setTextures:withRange:", textures, range) } @(objc_type=ComputeCommandEncoder, objc_name="setThreadgroupMemoryLength") -ComputeCommandEncoder_setThreadgroupMemoryLength :: #force_inline proc(self: ^ComputeCommandEncoder, length: ^NS.Object, index: ^NS.Object) { +ComputeCommandEncoder_setThreadgroupMemoryLength :: #force_inline proc(self: ^ComputeCommandEncoder, length: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setThreadgroupMemoryLength:atIndex:", length, index) } @(objc_type=ComputeCommandEncoder, objc_name="setVisibleFunctionTable") -ComputeCommandEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { +ComputeCommandEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTable: ^VisibleFunctionTable, bufferIndex: NS.UInteger) { msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setVisibleFunctionTables") -ComputeCommandEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTables: ^^NS.Object, range: NS.Range) { +ComputeCommandEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTables: [^]^VisibleFunctionTable, range: NS.Range) { msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) } @(objc_type=ComputeCommandEncoder, objc_name="updateFence") -ComputeCommandEncoder_updateFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { +ComputeCommandEncoder_updateFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^Fence) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=ComputeCommandEncoder, objc_name="useHeap") -ComputeCommandEncoder_useHeap :: #force_inline proc(self: ^ComputeCommandEncoder, heap: ^NS.Object) { +ComputeCommandEncoder_useHeap :: #force_inline proc(self: ^ComputeCommandEncoder, heap: ^Heap) { msgSend(nil, self, "useHeap:", heap) } @(objc_type=ComputeCommandEncoder, objc_name="useHeaps") -ComputeCommandEncoder_useHeaps :: #force_inline proc(self: ^ComputeCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { +ComputeCommandEncoder_useHeaps :: #force_inline proc(self: ^ComputeCommandEncoder, heaps: [^]^Heap, count: NS.UInteger) { msgSend(nil, self, "useHeaps:count:", heaps, count) } @(objc_type=ComputeCommandEncoder, objc_name="useResource") -ComputeCommandEncoder_useResource :: #force_inline proc(self: ^ComputeCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { +ComputeCommandEncoder_useResource :: #force_inline proc(self: ^ComputeCommandEncoder, resource: ^Resource, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=ComputeCommandEncoder, objc_name="useResources") -ComputeCommandEncoder_useResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { +ComputeCommandEncoder_useResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage) { msgSend(nil, self, "useResources:count:usage:", resources, count, usage) } @(objc_type=ComputeCommandEncoder, objc_name="waitForFence") -ComputeCommandEncoder_waitForFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^NS.Object) { +ComputeCommandEncoder_waitForFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^Fence) { msgSend(nil, self, "waitForFence:", fence) } @@ -5793,7 +5846,7 @@ ComputePipelineState_device :: #force_inline proc(self: ^ComputePipelineState) - return msgSend(^ComputePipelineState, self, "device") } @(objc_type=ComputePipelineState, objc_name="functionHandleWithFunction") -ComputePipelineState_functionHandleWithFunction :: #force_inline proc(self: ^ComputePipelineState, function: ^NS.Object) -> ^ComputePipelineState { +ComputePipelineState_functionHandleWithFunction :: #force_inline proc(self: ^ComputePipelineState, function: ^Function) -> ^ComputePipelineState { return msgSend(^ComputePipelineState, self, "functionHandleWithFunction:", function) } @(objc_type=ComputePipelineState, objc_name="imageblockMemoryLengthForDimensions") @@ -5805,12 +5858,13 @@ ComputePipelineState_label :: #force_inline proc(self: ^ComputePipelineState) -> return msgSend(^NS.String, self, "label") } @(objc_type=ComputePipelineState, objc_name="maxTotalThreadsPerThreadgroup") -ComputePipelineState_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineState) -> NS.Integer { - return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +ComputePipelineState_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineState) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=ComputePipelineState, objc_name="newComputePipelineStateWithAdditionalBinaryFunctions") -ComputePipelineState_newComputePipelineStateWithAdditionalBinaryFunctions :: #force_inline proc(self: ^ComputePipelineState, functions: ^NS.Array, error: ^^NS.Error ) -> ^ComputePipelineState { - return msgSend(^ComputePipelineState, self, "newComputePipelineStateWithAdditionalBinaryFunctions:error:", functions, error) +ComputePipelineState_newComputePipelineStateWithAdditionalBinaryFunctions :: #force_inline proc(self: ^ComputePipelineState, functions: ^NS.Array) -> (state: ^ComputePipelineState, error: ^NS.Error) { + state = msgSend(^ComputePipelineState, self, "newComputePipelineStateWithAdditionalBinaryFunctions:error:", functions, &error) + return } @(objc_type=ComputePipelineState, objc_name="newIntersectionFunctionTableWithDescriptor") ComputePipelineState_newIntersectionFunctionTableWithDescriptor :: #force_inline proc(self: ^ComputePipelineState, descriptor: ^IntersectionFunctionTableDescriptor) -> ^ComputePipelineState { @@ -5821,16 +5875,16 @@ ComputePipelineState_newVisibleFunctionTableWithDescriptor :: #force_inline proc return msgSend(^ComputePipelineState, self, "newVisibleFunctionTableWithDescriptor:", descriptor) } @(objc_type=ComputePipelineState, objc_name="staticThreadgroupMemoryLength") -ComputePipelineState_staticThreadgroupMemoryLength :: #force_inline proc(self: ^ComputePipelineState) -> NS.Integer { - return msgSend(NS.Integer, self, "staticThreadgroupMemoryLength") +ComputePipelineState_staticThreadgroupMemoryLength :: #force_inline proc(self: ^ComputePipelineState) -> NS.UInteger { + return msgSend(NS.UInteger, self, "staticThreadgroupMemoryLength") } @(objc_type=ComputePipelineState, objc_name="supportIndirectCommandBuffers") ComputePipelineState_supportIndirectCommandBuffers :: #force_inline proc(self: ^ComputePipelineState) -> BOOL { return msgSend(BOOL, self, "supportIndirectCommandBuffers") } @(objc_type=ComputePipelineState, objc_name="threadExecutionWidth") -ComputePipelineState_threadExecutionWidth :: #force_inline proc(self: ^ComputePipelineState) -> NS.Integer { - return msgSend(NS.Integer, self, "threadExecutionWidth") +ComputePipelineState_threadExecutionWidth :: #force_inline proc(self: ^ComputePipelineState) -> NS.UInteger { + return msgSend(NS.UInteger, self, "threadExecutionWidth") } //////////////////////////////////////////////////////////////////////////////// @@ -5878,8 +5932,8 @@ CounterSampleBuffer_resolveCounterRange :: #force_inline proc(self: ^CounterSamp return msgSend(^NS.Data, self, "resolveCounterRange:", range) } @(objc_type=CounterSampleBuffer, objc_name="sampleCount") -CounterSampleBuffer_sampleCount :: #force_inline proc(self: ^CounterSampleBuffer) -> NS.Integer { - return msgSend(NS.Integer, self, "sampleCount") +CounterSampleBuffer_sampleCount :: #force_inline proc(self: ^CounterSampleBuffer) -> NS.UInteger { + return msgSend(NS.UInteger, self, "sampleCount") } //////////////////////////////////////////////////////////////////////////////// @@ -6053,11 +6107,11 @@ Device_argumentBuffersSupport :: #force_inline proc(self: ^Device) -> ArgumentBu return msgSend(ArgumentBuffersTier, self, "argumentBuffersSupport") } @(objc_type=Device, objc_name="convertSparsePixelRegions") -Device_convertSparsePixelRegions :: #force_inline proc(self: ^Device, pixelRegions: ^Region, tileRegions: ^Region, tileSize: Size, mode: SparseTextureRegionAlignmentMode, numRegions: ^NS.Object) { +Device_convertSparsePixelRegions :: #force_inline proc(self: ^Device, pixelRegions: ^Region, tileRegions: ^Region, tileSize: Size, mode: SparseTextureRegionAlignmentMode, numRegions: NS.UInteger) { msgSend(nil, self, "convertSparsePixelRegions:toTileRegions:withTileSize:alignmentMode:numRegions:", pixelRegions, tileRegions, tileSize, mode, numRegions) } @(objc_type=Device, objc_name="convertSparseTileRegions") -Device_convertSparseTileRegions :: #force_inline proc(self: ^Device, tileRegions: ^Region, pixelRegions: ^Region, tileSize: Size, numRegions: ^NS.Object) { +Device_convertSparseTileRegions :: #force_inline proc(self: ^Device, tileRegions: ^Region, pixelRegions: ^Region, tileSize: Size, numRegions: NS.UInteger) { msgSend(nil, self, "convertSparseTileRegions:toPixelRegions:withTileSize:numRegions:", tileRegions, pixelRegions, tileSize, numRegions) } @(objc_type=Device, objc_name="counterSets") @@ -6065,11 +6119,11 @@ Device_counterSets :: #force_inline proc(self: ^Device) -> ^NS.Array { return msgSend(^NS.Array, self, "counterSets") } @(objc_type=Device, objc_name="currentAllocatedSize") -Device_currentAllocatedSize :: #force_inline proc(self: ^Device) -> NS.Integer { - return msgSend(NS.Integer, self, "currentAllocatedSize") +Device_currentAllocatedSize :: #force_inline proc(self: ^Device) -> NS.UInteger { + return msgSend(NS.UInteger, self, "currentAllocatedSize") } @(objc_type=Device, objc_name="getDefaultSamplePositions") -Device_getDefaultSamplePositions :: #force_inline proc(self: ^Device, positions: ^SamplePosition, count: ^NS.Object) { +Device_getDefaultSamplePositions :: #force_inline proc(self: ^Device, positions: ^SamplePosition, count: NS.UInteger) { msgSend(nil, self, "getDefaultSamplePositions:count:", positions, count) } @(objc_type=Device, objc_name="hasUnifiedMemory") @@ -6077,7 +6131,7 @@ Device_hasUnifiedMemory :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "hasUnifiedMemory") } @(objc_type=Device, objc_name="heapBufferSizeAndAlignWithLength") -Device_heapBufferSizeAndAlignWithLength :: #force_inline proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> SizeAndAlign { +Device_heapBufferSizeAndAlignWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> SizeAndAlign { return msgSend(SizeAndAlign, self, "heapBufferSizeAndAlignWithLength:options:", length, options) } @(objc_type=Device, objc_name="heapTextureSizeAndAlignWithDescriptor") @@ -6105,20 +6159,20 @@ Device_location :: #force_inline proc(self: ^Device) -> DeviceLocation { return msgSend(DeviceLocation, self, "location") } @(objc_type=Device, objc_name="locationNumber") -Device_locationNumber :: #force_inline proc(self: ^Device) -> NS.Integer { - return msgSend(NS.Integer, self, "locationNumber") +Device_locationNumber :: #force_inline proc(self: ^Device) -> NS.UInteger { + return msgSend(NS.UInteger, self, "locationNumber") } @(objc_type=Device, objc_name="maxArgumentBufferSamplerCount") -Device_maxArgumentBufferSamplerCount :: #force_inline proc(self: ^Device) -> NS.Integer { - return msgSend(NS.Integer, self, "maxArgumentBufferSamplerCount") +Device_maxArgumentBufferSamplerCount :: #force_inline proc(self: ^Device) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxArgumentBufferSamplerCount") } @(objc_type=Device, objc_name="maxBufferLength") -Device_maxBufferLength :: #force_inline proc(self: ^Device) -> NS.Integer { - return msgSend(NS.Integer, self, "maxBufferLength") +Device_maxBufferLength :: #force_inline proc(self: ^Device) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxBufferLength") } @(objc_type=Device, objc_name="maxThreadgroupMemoryLength") -Device_maxThreadgroupMemoryLength :: #force_inline proc(self: ^Device) -> NS.Integer { - return msgSend(NS.Integer, self, "maxThreadgroupMemoryLength") +Device_maxThreadgroupMemoryLength :: #force_inline proc(self: ^Device) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxThreadgroupMemoryLength") } @(objc_type=Device, objc_name="maxThreadsPerThreadgroup") Device_maxThreadsPerThreadgroup :: #force_inline proc(self: ^Device) -> Size { @@ -6145,7 +6199,7 @@ Device_newAccelerationStructureWithDescriptor :: #force_inline proc(self: ^Devic return msgSend(^Device, self, "newAccelerationStructureWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newAccelerationStructureWithSize") -Device_newAccelerationStructureWithSize :: #force_inline proc(self: ^Device, size: ^NS.Object) -> ^Device { +Device_newAccelerationStructureWithSize :: #force_inline proc(self: ^Device, size: NS.UInteger) -> ^Device { return msgSend(^Device, self, "newAccelerationStructureWithSize:", size) } @(objc_type=Device, objc_name="newArgumentEncoderWithArguments") @@ -6153,19 +6207,20 @@ Device_newArgumentEncoderWithArguments :: #force_inline proc(self: ^Device, argu return msgSend(^Device, self, "newArgumentEncoderWithArguments:", arguments) } @(objc_type=Device, objc_name="newBinaryArchiveWithDescriptor") -Device_newBinaryArchiveWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newBinaryArchiveWithDescriptor:error:", descriptor, error) +Device_newBinaryArchiveWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newBinaryArchiveWithDescriptor:error:", descriptor, &error) + return } @(objc_type=Device, objc_name="newBufferWithBytes") -Device_newBufferWithBytes :: #force_inline proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions) -> ^Device { +Device_newBufferWithBytes :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions) -> ^Device { return msgSend(^Device, self, "newBufferWithBytes:length:options:", pointer, length, options) } @(objc_type=Device, objc_name="newBufferWithBytesNoCopy") -Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, pointer: rawptr, length: ^NS.Object, options: ResourceOptions, deallocator: rawptr) -> ^Device { +Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions, deallocator: rawptr) -> ^Device { return msgSend(^Device, self, "newBufferWithBytesNoCopy:length:options:deallocator:", pointer, length, options, deallocator) } @(objc_type=Device, objc_name="newBufferWithLength") -Device_newBufferWithLength :: #force_inline proc(self: ^Device, length: ^NS.Object, options: ResourceOptions) -> ^Device { +Device_newBufferWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Device { return msgSend(^Device, self, "newBufferWithLength:options:", length, options) } @(objc_type=Device, objc_name="newCommandQueue") @@ -6173,7 +6228,7 @@ Device_newCommandQueue :: #force_inline proc(self: ^Device) -> ^Device { return msgSend(^Device, self, "newCommandQueue") } @(objc_type=Device, objc_name="newCommandQueueWithMaxCommandBufferCount") -Device_newCommandQueueWithMaxCommandBufferCount :: #force_inline proc(self: ^Device, maxCommandBufferCount: ^NS.Object) -> ^Device { +Device_newCommandQueueWithMaxCommandBufferCount :: #force_inline proc(self: ^Device, maxCommandBufferCount: NS.UInteger) -> ^Device { return msgSend(^Device, self, "newCommandQueueWithMaxCommandBufferCount:", maxCommandBufferCount) } @(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_completionHandler_") @@ -6181,48 +6236,55 @@ Device_newComputePipelineStateWithDescriptor_options_completionHandler_ :: #forc msgSend(nil, self, "newComputePipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_reflection_error_") -Device_newComputePipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newComputePipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, error) +Device_newComputePipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newComputePipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) + return } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_completionHandler_") -Device_newComputePipelineStateWithFunction_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, completionHandler: NewComputePipelineStateCompletionHandler) { +Device_newComputePipelineStateWithFunction_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^Function, completionHandler: NewComputePipelineStateCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithFunction:completionHandler:", computeFunction, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_error_") -Device_newComputePipelineStateWithFunction_error_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, error) +Device_newComputePipelineStateWithFunction_error_ :: #force_inline proc(self: ^Device, computeFunction: ^Function) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, &error) + return } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_completionHandler_") -Device_newComputePipelineStateWithFunction_options_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { +Device_newComputePipelineStateWithFunction_options_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithFunction:options:completionHandler:", computeFunction, options, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_reflection_error_") -Device_newComputePipelineStateWithFunction_options_reflection_error_ :: #force_inline proc(self: ^Device, computeFunction: ^NS.Object, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, error) +Device_newComputePipelineStateWithFunction_options_reflection_error_ :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, &error) + return } @(objc_type=Device, objc_name="newCounterSampleBufferWithDescriptor") -Device_newCounterSampleBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, error) +Device_newCounterSampleBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, &error) + return } @(objc_type=Device, objc_name="newDefaultLibrary") Device_newDefaultLibrary :: #force_inline proc(self: ^Device) -> ^Device { return msgSend(^Device, self, "newDefaultLibrary") } @(objc_type=Device, objc_name="newDefaultLibraryWithBundle") -Device_newDefaultLibraryWithBundle :: #force_inline proc(self: ^Device, bundle: ^NS.Bundle, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newDefaultLibraryWithBundle:error:", bundle, error) +Device_newDefaultLibraryWithBundle :: #force_inline proc(self: ^Device, bundle: ^NS.Bundle) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newDefaultLibraryWithBundle:error:", bundle, &error) + return } @(objc_type=Device, objc_name="newDepthStencilStateWithDescriptor") Device_newDepthStencilStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^Device { return msgSend(^Device, self, "newDepthStencilStateWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newDynamicLibrary") -Device_newDynamicLibrary :: #force_inline proc(self: ^Device, library: ^NS.Object, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newDynamicLibrary:error:", library, error) +Device_newDynamicLibrary :: #force_inline proc(self: ^Device, library: ^Library) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newDynamicLibrary:error:", library, &error) + return } @(objc_type=Device, objc_name="newDynamicLibraryWithURL") -Device_newDynamicLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newDynamicLibraryWithURL:error:", url, error) +Device_newDynamicLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newDynamicLibraryWithURL:error:", url, &error) + return } @(objc_type=Device, objc_name="newEvent") Device_newEvent :: #force_inline proc(self: ^Device) -> ^Device { @@ -6237,28 +6299,32 @@ Device_newHeapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^H return msgSend(^Device, self, "newHeapWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newIndirectCommandBufferWithDescriptor") -Device_newIndirectCommandBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: ^NS.Object, options: ResourceOptions) -> ^Device { +Device_newIndirectCommandBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: NS.UInteger, options: ResourceOptions) -> ^Device { return msgSend(^Device, self, "newIndirectCommandBufferWithDescriptor:maxCommandCount:options:", descriptor, maxCount, options) } @(objc_type=Device, objc_name="newLibraryWithData") -Device_newLibraryWithData :: #force_inline proc(self: ^Device, data: ^NS.Object, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newLibraryWithData:error:", data, error) +Device_newLibraryWithData :: #force_inline proc(self: ^Device, data: dispatch_data_t) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newLibraryWithData:error:", data, &error) + return } @(objc_type=Device, objc_name="newLibraryWithFile") -Device_newLibraryWithFile :: #force_inline proc(self: ^Device, filepath: ^NS.String, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newLibraryWithFile:error:", filepath, error) +Device_newLibraryWithFile :: #force_inline proc(self: ^Device, filepath: ^NS.String) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newLibraryWithFile:error:", filepath, &error) + return } @(objc_type=Device, objc_name="newLibraryWithSource_options_completionHandler_") Device_newLibraryWithSource_options_completionHandler_ :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) { msgSend(nil, self, "newLibraryWithSource:options:completionHandler:", source, options, completionHandler) } @(objc_type=Device, objc_name="newLibraryWithSource_options_error_") -Device_newLibraryWithSource_options_error_ :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newLibraryWithSource:options:error:", source, options, error) +Device_newLibraryWithSource_options_error_ :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newLibraryWithSource:options:error:", source, options, &error) + return } @(objc_type=Device, objc_name="newLibraryWithURL") -Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newLibraryWithURL:error:", url, error) +Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newLibraryWithURL:error:", url, &error) + return } @(objc_type=Device, objc_name="newRasterizationRateMapWithDescriptor") Device_newRasterizationRateMapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^Device { @@ -6269,24 +6335,27 @@ Device_newRenderPipelineStateWithDescriptor_completionHandler_ :: #force_inline msgSend(nil, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_error_") -Device_newRenderPipelineStateWithDescriptor_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, error) +Device_newRenderPipelineStateWithDescriptor_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, &error) + return } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_completionHandler_") Device_newRenderPipelineStateWithDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_reflection_error_") -Device_newRenderPipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, error) +Device_newRenderPipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) + return } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_completionHandler_") Device_newRenderPipelineStateWithTileDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithTileDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_reflection_error_") -Device_newRenderPipelineStateWithTileDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection, error: ^^NS.Error ) -> ^Device { - return msgSend(^Device, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, error) +Device_newRenderPipelineStateWithTileDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { + device = msgSend(^Device, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) + return } @(objc_type=Device, objc_name="newSamplerStateWithDescriptor") Device_newSamplerStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^Device { @@ -6313,7 +6382,7 @@ Device_newTextureWithDescriptor :: #force_inline proc(self: ^Device, desc: ^Text return msgSend(^Device, self, "newTextureWithDescriptor:", desc) } @(objc_type=Device, objc_name="newTextureWithDescriptor_iosurface_plane_") -Device_newTextureWithDescriptor_iosurface_plane_ :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: ^NS.Object) -> ^Device { +Device_newTextureWithDescriptor_iosurface_plane_ :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Device { return msgSend(^Device, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) } @(objc_type=Device, objc_name="peerCount") @@ -6345,11 +6414,11 @@ Device_sampleTimestamps :: #force_inline proc(self: ^Device, cpuTimestamp: ^Time msgSend(nil, self, "sampleTimestamps:gpuTimestamp:", cpuTimestamp, gpuTimestamp) } @(objc_type=Device, objc_name="sparseTileSizeInBytes") -Device_sparseTileSizeInBytes :: #force_inline proc(self: ^Device) -> NS.Integer { - return msgSend(NS.Integer, self, "sparseTileSizeInBytes") +Device_sparseTileSizeInBytes :: #force_inline proc(self: ^Device) -> NS.UInteger { + return msgSend(NS.UInteger, self, "sparseTileSizeInBytes") } @(objc_type=Device, objc_name="sparseTileSizeWithTextureType") -Device_sparseTileSizeWithTextureType :: #force_inline proc(self: ^Device, textureType: TextureType, pixelFormat: PixelFormat, sampleCount: ^NS.Object) -> Size { +Device_sparseTileSizeWithTextureType :: #force_inline proc(self: ^Device, textureType: TextureType, pixelFormat: PixelFormat, sampleCount: NS.UInteger) -> Size { return msgSend(Size, self, "sparseTileSizeWithTextureType:pixelFormat:sampleCount:", textureType, pixelFormat, sampleCount) } @(objc_type=Device, objc_name="supports32BitFloatFiltering") @@ -6393,7 +6462,7 @@ Device_supportsQueryTextureLOD :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "supportsQueryTextureLOD") } @(objc_type=Device, objc_name="supportsRasterizationRateMapWithLayerCount") -Device_supportsRasterizationRateMapWithLayerCount :: #force_inline proc(self: ^Device, layerCount: ^NS.Object) -> BOOL { +Device_supportsRasterizationRateMapWithLayerCount :: #force_inline proc(self: ^Device, layerCount: NS.UInteger) -> BOOL { return msgSend(BOOL, self, "supportsRasterizationRateMapWithLayerCount:", layerCount) } @(objc_type=Device, objc_name="supportsRaytracing") @@ -6405,11 +6474,11 @@ Device_supportsShaderBarycentricCoordinates :: #force_inline proc(self: ^Device) return msgSend(BOOL, self, "supportsShaderBarycentricCoordinates") } @(objc_type=Device, objc_name="supportsTextureSampleCount") -Device_supportsTextureSampleCount :: #force_inline proc(self: ^Device, sampleCount: ^NS.Object) -> BOOL { +Device_supportsTextureSampleCount :: #force_inline proc(self: ^Device, sampleCount: NS.UInteger) -> BOOL { return msgSend(BOOL, self, "supportsTextureSampleCount:", sampleCount) } @(objc_type=Device, objc_name="supportsVertexAmplificationCount") -Device_supportsVertexAmplificationCount :: #force_inline proc(self: ^Device, count: ^NS.Object) -> BOOL { +Device_supportsVertexAmplificationCount :: #force_inline proc(self: ^Device, count: NS.UInteger) -> BOOL { return msgSend(BOOL, self, "supportsVertexAmplificationCount:", count) } @@ -6435,8 +6504,8 @@ Drawable_addPresentedHandler :: #force_inline proc(self: ^Drawable, block: Drawa msgSend(nil, self, "addPresentedHandler:", block) } @(objc_type=Drawable, objc_name="drawableID") -Drawable_drawableID :: #force_inline proc(self: ^Drawable) -> NS.Integer { - return msgSend(NS.Integer, self, "drawableID") +Drawable_drawableID :: #force_inline proc(self: ^Drawable) -> NS.UInteger { + return msgSend(NS.UInteger, self, "drawableID") } @(objc_type=Drawable, objc_name="present") Drawable_present :: #force_inline proc(self: ^Drawable) { @@ -6484,8 +6553,9 @@ DynamicLibrary_label :: #force_inline proc(self: ^DynamicLibrary) -> ^NS.String return msgSend(^NS.String, self, "label") } @(objc_type=DynamicLibrary, objc_name="serializeToURL") -DynamicLibrary_serializeToURL :: #force_inline proc(self: ^DynamicLibrary, url: ^NS.URL, error: ^^NS.Error ) -> BOOL { - return msgSend(BOOL, self, "serializeToURL:error:", url, error) +DynamicLibrary_serializeToURL :: #force_inline proc(self: ^DynamicLibrary, url: ^NS.URL) -> (ok: bool, error: ^NS.Error) { + ok = msgSend(BOOL, self, "serializeToURL:error:", url, &error) + return } @(objc_type=DynamicLibrary, objc_name="setLabel") DynamicLibrary_setLabel :: #force_inline proc(self: ^DynamicLibrary, label: ^NS.String) { @@ -6591,11 +6661,11 @@ Function_name :: #force_inline proc(self: ^Function) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex") -Function_newArgumentEncoderWithBufferIndex :: #force_inline proc(self: ^Function, bufferIndex: ^NS.Object) -> ^Function { +Function_newArgumentEncoderWithBufferIndex :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger) -> ^Function { return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:", bufferIndex) } @(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex_reflection_") -Function_newArgumentEncoderWithBufferIndex_reflection_ :: #force_inline proc(self: ^Function, bufferIndex: ^NS.Object, reflection: ^AutoreleasedArgument) -> ^Function { +Function_newArgumentEncoderWithBufferIndex_reflection_ :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger, reflection: ^AutoreleasedArgument) -> ^Function { return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:reflection:", bufferIndex, reflection) } @(objc_type=Function, objc_name="options") @@ -6603,8 +6673,8 @@ Function_options :: #force_inline proc(self: ^Function) -> FunctionOptions { return msgSend(FunctionOptions, self, "options") } @(objc_type=Function, objc_name="patchControlPointCount") -Function_patchControlPointCount :: #force_inline proc(self: ^Function) -> NS.Integer { - return msgSend(NS.Integer, self, "patchControlPointCount") +Function_patchControlPointCount :: #force_inline proc(self: ^Function) -> NS.UInteger { + return msgSend(NS.UInteger, self, "patchControlPointCount") } @(objc_type=Function, objc_name="patchType") Function_patchType :: #force_inline proc(self: ^Function) -> PatchType { @@ -6702,16 +6772,16 @@ FunctionLogDebugLocation_URL :: #force_inline proc(self: ^FunctionLogDebugLocati return msgSend(^NS.URL, self, "URL") } @(objc_type=FunctionLogDebugLocation, objc_name="column") -FunctionLogDebugLocation_column :: #force_inline proc(self: ^FunctionLogDebugLocation) -> NS.Integer { - return msgSend(NS.Integer, self, "column") +FunctionLogDebugLocation_column :: #force_inline proc(self: ^FunctionLogDebugLocation) -> NS.UInteger { + return msgSend(NS.UInteger, self, "column") } @(objc_type=FunctionLogDebugLocation, objc_name="functionName") FunctionLogDebugLocation_functionName :: #force_inline proc(self: ^FunctionLogDebugLocation) -> ^NS.String { return msgSend(^NS.String, self, "functionName") } @(objc_type=FunctionLogDebugLocation, objc_name="line") -FunctionLogDebugLocation_line :: #force_inline proc(self: ^FunctionLogDebugLocation) -> NS.Integer { - return msgSend(NS.Integer, self, "line") +FunctionLogDebugLocation_line :: #force_inline proc(self: ^FunctionLogDebugLocation) -> NS.UInteger { + return msgSend(NS.UInteger, self, "line") } //////////////////////////////////////////////////////////////////////////////// @@ -6747,8 +6817,8 @@ Heap_cpuCacheMode :: #force_inline proc(self: ^Heap) -> CPUCacheMode { return msgSend(CPUCacheMode, self, "cpuCacheMode") } @(objc_type=Heap, objc_name="currentAllocatedSize") -Heap_currentAllocatedSize :: #force_inline proc(self: ^Heap) -> NS.Integer { - return msgSend(NS.Integer, self, "currentAllocatedSize") +Heap_currentAllocatedSize :: #force_inline proc(self: ^Heap) -> NS.UInteger { + return msgSend(NS.UInteger, self, "currentAllocatedSize") } @(objc_type=Heap, objc_name="device") Heap_device :: #force_inline proc(self: ^Heap) -> ^Heap { @@ -6763,15 +6833,15 @@ Heap_label :: #force_inline proc(self: ^Heap) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Heap, objc_name="maxAvailableSizeWithAlignment") -Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: ^NS.Object) -> ^Heap { +Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "maxAvailableSizeWithAlignment:", alignment) } @(objc_type=Heap, objc_name="newBufferWithLength") -Heap_newBufferWithLength :: #force_inline proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions) -> ^Heap { +Heap_newBufferWithLength :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:", length, options) } @(objc_type=Heap, objc_name="newBufferWithLength_options_offset_") -Heap_newBufferWithLength_options_offset_ :: #force_inline proc(self: ^Heap, length: ^NS.Object, options: ResourceOptions, offset: ^NS.Object) -> ^Heap { +Heap_newBufferWithLength_options_offset_ :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:offset:", length, options, offset) } @(objc_type=Heap, objc_name="newTextureWithDescriptor") @@ -6779,7 +6849,7 @@ Heap_newTextureWithDescriptor :: #force_inline proc(self: ^Heap, desc: ^TextureD return msgSend(^Heap, self, "newTextureWithDescriptor:", desc) } @(objc_type=Heap, objc_name="newTextureWithDescriptor_offset_") -Heap_newTextureWithDescriptor_offset_ :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: ^NS.Object) -> ^Heap { +Heap_newTextureWithDescriptor_offset_ :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "newTextureWithDescriptor:offset:", descriptor, offset) } @(objc_type=Heap, objc_name="resourceOptions") @@ -6795,8 +6865,8 @@ Heap_setPurgeableState :: #force_inline proc(self: ^Heap, state: PurgeableState) return msgSend(PurgeableState, self, "setPurgeableState:", state) } @(objc_type=Heap, objc_name="size") -Heap_size :: #force_inline proc(self: ^Heap) -> NS.Integer { - return msgSend(NS.Integer, self, "size") +Heap_size :: #force_inline proc(self: ^Heap) -> NS.UInteger { + return msgSend(NS.UInteger, self, "size") } @(objc_type=Heap, objc_name="storageMode") Heap_storageMode :: #force_inline proc(self: ^Heap) -> StorageMode { @@ -6807,8 +6877,8 @@ Heap_type :: #force_inline proc(self: ^Heap) -> FunctionLogType { return msgSend(FunctionLogType, self, "type") } @(objc_type=Heap, objc_name="usedSize") -Heap_usedSize :: #force_inline proc(self: ^Heap) -> NS.Integer { - return msgSend(NS.Integer, self, "usedSize") +Heap_usedSize :: #force_inline proc(self: ^Heap) -> NS.UInteger { + return msgSend(NS.UInteger, self, "usedSize") } //////////////////////////////////////////////////////////////////////////////// @@ -6824,14 +6894,14 @@ Methods: size */ @(objc_class="MTLIndirectCommandBuffer") -IndirectCommandBuffer :: struct { using _: NS.Object } +IndirectCommandBuffer :: struct { using _: Resource } @(objc_type=IndirectCommandBuffer, objc_name="indirectComputeCommandAtIndex") -IndirectCommandBuffer_indirectComputeCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { +IndirectCommandBuffer_indirectComputeCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "indirectComputeCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="indirectRenderCommandAtIndex") -IndirectCommandBuffer_indirectRenderCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: ^NS.Object) -> ^IndirectCommandBuffer { +IndirectCommandBuffer_indirectRenderCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "indirectRenderCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="resetWithRange") @@ -6839,8 +6909,8 @@ IndirectCommandBuffer_resetWithRange :: #force_inline proc(self: ^IndirectComman msgSend(nil, self, "resetWithRange:", range) } @(objc_type=IndirectCommandBuffer, objc_name="size") -IndirectCommandBuffer_size :: #force_inline proc(self: ^IndirectCommandBuffer) -> NS.Integer { - return msgSend(NS.Integer, self, "size") +IndirectCommandBuffer_size :: #force_inline proc(self: ^IndirectCommandBuffer) -> NS.UInteger { + return msgSend(NS.UInteger, self, "size") } //////////////////////////////////////////////////////////////////////////////// @@ -6885,15 +6955,15 @@ IndirectComputeCommand_setBarrier :: #force_inline proc(self: ^IndirectComputeCo msgSend(nil, self, "setBarrier") } @(objc_type=IndirectComputeCommand, objc_name="setComputePipelineState") -IndirectComputeCommand_setComputePipelineState :: #force_inline proc(self: ^IndirectComputeCommand, pipelineState: ^NS.Object) { +IndirectComputeCommand_setComputePipelineState :: #force_inline proc(self: ^IndirectComputeCommand, pipelineState: ^ComputePipelineState) { msgSend(nil, self, "setComputePipelineState:", pipelineState) } @(objc_type=IndirectComputeCommand, objc_name="setImageblockWidth") -IndirectComputeCommand_setImageblockWidth :: #force_inline proc(self: ^IndirectComputeCommand, width: ^NS.Object, height: ^NS.Object) { +IndirectComputeCommand_setImageblockWidth :: #force_inline proc(self: ^IndirectComputeCommand, width: NS.UInteger, height: NS.UInteger) { msgSend(nil, self, "setImageblockWidth:height:", width, height) } @(objc_type=IndirectComputeCommand, objc_name="setKernelBuffer") -IndirectComputeCommand_setKernelBuffer :: #force_inline proc(self: ^IndirectComputeCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IndirectComputeCommand_setKernelBuffer :: #force_inline proc(self: ^IndirectComputeCommand, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setKernelBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=IndirectComputeCommand, objc_name="setStageInRegion") @@ -6901,7 +6971,7 @@ IndirectComputeCommand_setStageInRegion :: #force_inline proc(self: ^IndirectCom msgSend(nil, self, "setStageInRegion:", region) } @(objc_type=IndirectComputeCommand, objc_name="setThreadgroupMemoryLength") -IndirectComputeCommand_setThreadgroupMemoryLength :: #force_inline proc(self: ^IndirectComputeCommand, length: ^NS.Object, index: ^NS.Object) { +IndirectComputeCommand_setThreadgroupMemoryLength :: #force_inline proc(self: ^IndirectComputeCommand, length: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setThreadgroupMemoryLength:atIndex:", length, index) } @@ -6925,19 +6995,19 @@ Methods: IndirectRenderCommand :: struct { using _: NS.Object } @(objc_type=IndirectRenderCommand, objc_name="drawIndexedPatches") -IndirectRenderCommand_drawIndexedPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { +IndirectRenderCommand_drawIndexedPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger, buffer: ^Buffer, offset: NS.UInteger, instanceStride: NS.UInteger) { msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawIndexedPrimitives") -IndirectRenderCommand_drawIndexedPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { +IndirectRenderCommand_drawIndexedPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseVertex: NS.Integer, baseInstance: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) } @(objc_type=IndirectRenderCommand, objc_name="drawPatches") -IndirectRenderCommand_drawPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { +IndirectRenderCommand_drawPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger, buffer: ^Buffer, offset: NS.UInteger, instanceStride: NS.UInteger) { msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawPrimitives") -IndirectRenderCommand_drawPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +IndirectRenderCommand_drawPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } @(objc_type=IndirectRenderCommand, objc_name="reset") @@ -6945,15 +7015,15 @@ IndirectRenderCommand_reset :: #force_inline proc(self: ^IndirectRenderCommand) msgSend(nil, self, "reset") } @(objc_type=IndirectRenderCommand, objc_name="setFragmentBuffer") -IndirectRenderCommand_setFragmentBuffer :: #force_inline proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IndirectRenderCommand_setFragmentBuffer :: #force_inline proc(self: ^IndirectRenderCommand, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setFragmentBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=IndirectRenderCommand, objc_name="setRenderPipelineState") -IndirectRenderCommand_setRenderPipelineState :: #force_inline proc(self: ^IndirectRenderCommand, pipelineState: ^NS.Object) { +IndirectRenderCommand_setRenderPipelineState :: #force_inline proc(self: ^IndirectRenderCommand, pipelineState: ^RenderPipelineState) { msgSend(nil, self, "setRenderPipelineState:", pipelineState) } @(objc_type=IndirectRenderCommand, objc_name="setVertexBuffer") -IndirectRenderCommand_setVertexBuffer :: #force_inline proc(self: ^IndirectRenderCommand, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IndirectRenderCommand_setVertexBuffer :: #force_inline proc(self: ^IndirectRenderCommand, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setVertexBuffer:offset:atIndex:", buffer, offset, index) } @@ -6974,38 +7044,38 @@ Methods: setVisibleFunctionTables */ @(objc_class="MTLIntersectionFunctionTable") -IntersectionFunctionTable :: struct { using _: NS.Object } +IntersectionFunctionTable :: struct { using _: Resource } @(objc_type=IntersectionFunctionTable, objc_name="setBuffer") -IntersectionFunctionTable_setBuffer :: #force_inline proc(self: ^IntersectionFunctionTable, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +IntersectionFunctionTable_setBuffer :: #force_inline proc(self: ^IntersectionFunctionTable, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=IntersectionFunctionTable, objc_name="setBuffers") -IntersectionFunctionTable_setBuffers :: #force_inline proc(self: ^IntersectionFunctionTable, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +IntersectionFunctionTable_setBuffers :: #force_inline proc(self: ^IntersectionFunctionTable, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=IntersectionFunctionTable, objc_name="setFunction") -IntersectionFunctionTable_setFunction :: #force_inline proc(self: ^IntersectionFunctionTable, function: ^NS.Object, index: ^NS.Object) { +IntersectionFunctionTable_setFunction :: #force_inline proc(self: ^IntersectionFunctionTable, function: ^FunctionHandle, index: NS.UInteger) { msgSend(nil, self, "setFunction:atIndex:", function, index) } @(objc_type=IntersectionFunctionTable, objc_name="setFunctions") -IntersectionFunctionTable_setFunctions :: #force_inline proc(self: ^IntersectionFunctionTable, functions: ^^NS.Object, range: NS.Range) { +IntersectionFunctionTable_setFunctions :: #force_inline proc(self: ^IntersectionFunctionTable, functions: [^]^FunctionHandle, range: NS.Range) { msgSend(nil, self, "setFunctions:withRange:", functions, range) } -@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignature_atIndex_") -IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_atIndex_ :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: ^NS.Object) { +@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignatureAtIndex") +IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignatureAtIndex :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: NS.UInteger) { msgSend(nil, self, "setOpaqueTriangleIntersectionFunctionWithSignature:atIndex:", signature, index) } -@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignature_withRange_") -IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature_withRange_ :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, range: NS.Range) { +@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignatureWithRange") +IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignatureWithRange :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, range: NS.Range) { msgSend(nil, self, "setOpaqueTriangleIntersectionFunctionWithSignature:withRange:", signature, range) } @(objc_type=IntersectionFunctionTable, objc_name="setVisibleFunctionTable") -IntersectionFunctionTable_setVisibleFunctionTable :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTable: ^NS.Object, bufferIndex: ^NS.Object) { +IntersectionFunctionTable_setVisibleFunctionTable :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTable: ^VisibleFunctionTable, bufferIndex: NS.UInteger) { msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) } @(objc_type=IntersectionFunctionTable, objc_name="setVisibleFunctionTables") -IntersectionFunctionTable_setVisibleFunctionTables :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTables: ^^NS.Object, range: NS.Range) { +IntersectionFunctionTable_setVisibleFunctionTables :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTables: [^]^VisibleFunctionTable, range: NS.Range) { msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) } @@ -7054,8 +7124,9 @@ Library_newFunctionWithDescriptor_completionHandler_ :: #force_inline proc(self: msgSend(nil, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithDescriptor_error_") -Library_newFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, error: ^^NS.Error ) -> ^Library { - return msgSend(^Library, self, "newFunctionWithDescriptor:error:", descriptor, error) +Library_newFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newFunctionWithDescriptor:error:", descriptor, &error) + return } @(objc_type=Library, objc_name="newFunctionWithName") Library_newFunctionWithName :: #force_inline proc(self: ^Library, functionName: ^NS.String) -> ^Library { @@ -7066,16 +7137,18 @@ Library_newFunctionWithName_constantValues_completionHandler_ :: #force_inline p msgSend(nil, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithName_constantValues_error_") -Library_newFunctionWithName_constantValues_error_ :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, error: ^^NS.Error ) -> ^Library { - return msgSend(^Library, self, "newFunctionWithName:constantValues:error:", name, constantValues, error) +Library_newFunctionWithName_constantValues_error_ :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newFunctionWithName:constantValues:error:", name, constantValues, &error) + return } @(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_completionHandler_") Library_newIntersectionFunctionWithDescriptor_completionHandler_ :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) { msgSend(nil, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_error_") -Library_newIntersectionFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, error: ^^NS.Error ) -> ^Library { - return msgSend(^Library, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, error) +Library_newIntersectionFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, &error) + return } @(objc_type=Library, objc_name="setLabel") Library_setLabel :: #force_inline proc(self: ^Library, label: ^NS.String) { @@ -7109,11 +7182,11 @@ ParallelRenderCommandEncoder_renderCommandEncoder :: #force_inline proc(self: ^P return msgSend(^ParallelRenderCommandEncoder, self, "renderCommandEncoder") } @(objc_type=ParallelRenderCommandEncoder, objc_name="setColorStoreAction") -ParallelRenderCommandEncoder_setColorStoreAction :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { +ParallelRenderCommandEncoder_setColorStoreAction :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: NS.UInteger) { msgSend(nil, self, "setColorStoreAction:atIndex:", storeAction, colorAttachmentIndex) } @(objc_type=ParallelRenderCommandEncoder, objc_name="setColorStoreActionOptions") -ParallelRenderCommandEncoder_setColorStoreActionOptions :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { +ParallelRenderCommandEncoder_setColorStoreActionOptions :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: NS.UInteger) { msgSend(nil, self, "setColorStoreActionOptions:atIndex:", storeActionOptions, colorAttachmentIndex) } @(objc_type=ParallelRenderCommandEncoder, objc_name="setDepthStoreAction") @@ -7155,7 +7228,7 @@ Methods: RasterizationRateMap :: struct { using _: NS.Object } @(objc_type=RasterizationRateMap, objc_name="copyParameterDataToBuffer") -RasterizationRateMap_copyParameterDataToBuffer :: #force_inline proc(self: ^RasterizationRateMap, buffer: ^NS.Object, offset: ^NS.Object) { +RasterizationRateMap_copyParameterDataToBuffer :: #force_inline proc(self: ^RasterizationRateMap, buffer: ^Buffer, offset: NS.UInteger) { msgSend(nil, self, "copyParameterDataToBuffer:offset:", buffer, offset) } @(objc_type=RasterizationRateMap, objc_name="device") @@ -7167,15 +7240,15 @@ RasterizationRateMap_label :: #force_inline proc(self: ^RasterizationRateMap) -> return msgSend(^NS.String, self, "label") } @(objc_type=RasterizationRateMap, objc_name="layerCount") -RasterizationRateMap_layerCount :: #force_inline proc(self: ^RasterizationRateMap) -> NS.Integer { - return msgSend(NS.Integer, self, "layerCount") +RasterizationRateMap_layerCount :: #force_inline proc(self: ^RasterizationRateMap) -> NS.UInteger { + return msgSend(NS.UInteger, self, "layerCount") } @(objc_type=RasterizationRateMap, objc_name="mapPhysicalToScreenCoordinates") -RasterizationRateMap_mapPhysicalToScreenCoordinates :: #force_inline proc(self: ^RasterizationRateMap, physicalCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { +RasterizationRateMap_mapPhysicalToScreenCoordinates :: #force_inline proc(self: ^RasterizationRateMap, physicalCoordinates: Coordinate2D, layerIndex: NS.UInteger) -> Coordinate2D { return msgSend(Coordinate2D, self, "mapPhysicalToScreenCoordinates:forLayer:", physicalCoordinates, layerIndex) } @(objc_type=RasterizationRateMap, objc_name="mapScreenToPhysicalCoordinates") -RasterizationRateMap_mapScreenToPhysicalCoordinates :: #force_inline proc(self: ^RasterizationRateMap, screenCoordinates: Coordinate2D, layerIndex: ^NS.Object) -> Coordinate2D { +RasterizationRateMap_mapScreenToPhysicalCoordinates :: #force_inline proc(self: ^RasterizationRateMap, screenCoordinates: Coordinate2D, layerIndex: NS.UInteger) -> Coordinate2D { return msgSend(Coordinate2D, self, "mapScreenToPhysicalCoordinates:forLayer:", screenCoordinates, layerIndex) } @(objc_type=RasterizationRateMap, objc_name="parameterBufferSizeAndAlign") @@ -7187,7 +7260,7 @@ RasterizationRateMap_physicalGranularity :: #force_inline proc(self: ^Rasterizat return msgSend(Size, self, "physicalGranularity") } @(objc_type=RasterizationRateMap, objc_name="physicalSizeForLayer") -RasterizationRateMap_physicalSizeForLayer :: #force_inline proc(self: ^RasterizationRateMap, layerIndex: ^NS.Object) -> Size { +RasterizationRateMap_physicalSizeForLayer :: #force_inline proc(self: ^RasterizationRateMap, layerIndex: NS.UInteger) -> Size { return msgSend(Size, self, "physicalSizeForLayer:", layerIndex) } @(objc_type=RasterizationRateMap, objc_name="screenSize") @@ -7297,63 +7370,63 @@ RenderCommandEncoder_dispatchThreadsPerTile :: #force_inline proc(self: ^RenderC msgSend(nil, self, "dispatchThreadsPerTile:", threadsPerTile) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawIndexedPatches:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, controlPointIndexBuffer: ^NS.Object, controlPointIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, instanceCount: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: ^NS.Object, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseVertex: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseVertex: NS.Integer, baseInstance: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexType: IndexType, indexBuffer: ^NS.Object, indexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexType:indexBuffer:indexBufferOffset:indirectBuffer:indirectBufferOffset:", primitiveType, indexType, indexBuffer, indexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawPatches:patchIndexBuffer:patchIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: ^NS.Object, patchStart: ^NS.Object, patchCount: ^NS.Object, patchIndexBuffer: ^NS.Object, patchIndexBufferOffset: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawPrimitives_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawPrimitives:indirectBuffer:indirectBufferOffset:", primitiveType, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:", primitiveType, vertexStart, vertexCount) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:", primitiveType, vertexStart, vertexCount, instanceCount) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: ^NS.Object, vertexCount: ^NS.Object, instanceCount: ^NS.Object, baseInstance: ^NS.Object) { +RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } -@(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_executeCommandsInBuffer_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, indirectCommandbuffer: ^NS.Object, indirectRangeBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +@(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer") +RenderCommandEncoder_executeCommandsInBuffer :: #force_inline proc(self: ^RenderCommandEncoder, indirectCommandbuffer: ^Buffer, indirectRangeBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "executeCommandsInBuffer:indirectBuffer:indirectBufferOffset:", indirectCommandbuffer, indirectRangeBuffer, indirectBufferOffset) } -@(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer_withRange_") -RenderCommandEncoder_executeCommandsInBuffer_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, indirectCommandBuffer: ^NS.Object, executionRange: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBufferWithRange") +RenderCommandEncoder_executeCommandsInBufferWithRange :: #force_inline proc(self: ^RenderCommandEncoder, indirectCommandBuffer: ^Buffer, executionRange: NS.Range) { msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) } @(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithResources") -RenderCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, after: RenderStages, before: RenderStages) { +RenderCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, after: RenderStages, before: RenderStages) { msgSend(nil, self, "memoryBarrierWithResources:count:afterStages:beforeStages:", resources, count, after, before) } @(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithScope") @@ -7361,7 +7434,7 @@ RenderCommandEncoder_memoryBarrierWithScope :: #force_inline proc(self: ^RenderC msgSend(nil, self, "memoryBarrierWithScope:afterStages:beforeStages:", scope, after, before) } @(objc_type=RenderCommandEncoder, objc_name="sampleCountersInBuffer") -RenderCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^RenderCommandEncoder, sampleBuffer: ^NS.Object, sampleIndex: ^NS.Object, barrier: BOOL) { +RenderCommandEncoder_sampleCountersInBuffer :: #force_inline proc(self: ^RenderCommandEncoder, sampleBuffer: ^Buffer, sampleIndex: NS.UInteger, barrier: BOOL) { msgSend(nil, self, "sampleCountersInBuffer:atSampleIndex:withBarrier:", sampleBuffer, sampleIndex, barrier) } @(objc_type=RenderCommandEncoder, objc_name="setBlendColorRed") @@ -7369,11 +7442,11 @@ RenderCommandEncoder_setBlendColorRed :: #force_inline proc(self: ^RenderCommand msgSend(nil, self, "setBlendColorRed:green:blue:alpha:", red, green, blue, alpha) } @(objc_type=RenderCommandEncoder, objc_name="setColorStoreAction") -RenderCommandEncoder_setColorStoreAction :: #force_inline proc(self: ^RenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: ^NS.Object) { +RenderCommandEncoder_setColorStoreAction :: #force_inline proc(self: ^RenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: NS.UInteger) { msgSend(nil, self, "setColorStoreAction:atIndex:", storeAction, colorAttachmentIndex) } @(objc_type=RenderCommandEncoder, objc_name="setColorStoreActionOptions") -RenderCommandEncoder_setColorStoreActionOptions :: #force_inline proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: ^NS.Object) { +RenderCommandEncoder_setColorStoreActionOptions :: #force_inline proc(self: ^RenderCommandEncoder, storeActionOptions: StoreActionOptions, colorAttachmentIndex: NS.UInteger) { msgSend(nil, self, "setColorStoreActionOptions:atIndex:", storeActionOptions, colorAttachmentIndex) } @(objc_type=RenderCommandEncoder, objc_name="setCullMode") @@ -7389,7 +7462,7 @@ RenderCommandEncoder_setDepthClipMode :: #force_inline proc(self: ^RenderCommand msgSend(nil, self, "setDepthClipMode:", depthClipMode) } @(objc_type=RenderCommandEncoder, objc_name="setDepthStencilState") -RenderCommandEncoder_setDepthStencilState :: #force_inline proc(self: ^RenderCommandEncoder, depthStencilState: ^NS.Object) { +RenderCommandEncoder_setDepthStencilState :: #force_inline proc(self: ^RenderCommandEncoder, depthStencilState: ^DepthStencilState) { msgSend(nil, self, "setDepthStencilState:", depthStencilState) } @(objc_type=RenderCommandEncoder, objc_name="setDepthStoreAction") @@ -7401,43 +7474,43 @@ RenderCommandEncoder_setDepthStoreActionOptions :: #force_inline proc(self: ^Ren msgSend(nil, self, "setDepthStoreActionOptions:", storeActionOptions) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBuffer") -RenderCommandEncoder_setFragmentBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setFragmentBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBufferOffset") -RenderCommandEncoder_setFragmentBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setFragmentBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBuffers") -RenderCommandEncoder_setFragmentBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +RenderCommandEncoder_setFragmentBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { msgSend(nil, self, "setFragmentBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBytes") -RenderCommandEncoder_setFragmentBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setFragmentBytes:length:atIndex:", bytes, length, index) } -@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_atIndex_") -RenderCommandEncoder_setFragmentSamplerState_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStateAtIndex") +RenderCommandEncoder_setFragmentSamplerStateAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setFragmentSamplerState:atIndex:", sampler, index) } -@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -RenderCommandEncoder_setFragmentSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_lodMinClamp_lodMaxClampAtIndex") +RenderCommandEncoder_setFragmentSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setFragmentSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_lodMinClamps_lodMaxClampsWithRange") +RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setFragmentSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } -@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_withRange_") -RenderCommandEncoder_setFragmentSamplerStates_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStatesWithRange") +RenderCommandEncoder_setFragmentSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { msgSend(nil, self, "setFragmentSamplerStates:withRange:", samplers, range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentTexture") -RenderCommandEncoder_setFragmentTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setFragmentTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setFragmentTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentTextures") -RenderCommandEncoder_setFragmentTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setFragmentTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: [^]^Texture, range: NS.Range) { msgSend(nil, self, "setFragmentTextures:withRange:", textures, range) } @(objc_type=RenderCommandEncoder, objc_name="setFrontFacingWinding") @@ -7445,7 +7518,7 @@ RenderCommandEncoder_setFrontFacingWinding :: #force_inline proc(self: ^RenderCo msgSend(nil, self, "setFrontFacingWinding:", frontFacingWinding) } @(objc_type=RenderCommandEncoder, objc_name="setRenderPipelineState") -RenderCommandEncoder_setRenderPipelineState :: #force_inline proc(self: ^RenderCommandEncoder, pipelineState: ^NS.Object) { +RenderCommandEncoder_setRenderPipelineState :: #force_inline proc(self: ^RenderCommandEncoder, pipelineState: ^RenderPipelineState) { msgSend(nil, self, "setRenderPipelineState:", pipelineState) } @(objc_type=RenderCommandEncoder, objc_name="setScissorRect") @@ -7453,7 +7526,7 @@ RenderCommandEncoder_setScissorRect :: #force_inline proc(self: ^RenderCommandEn msgSend(nil, self, "setScissorRect:", rect) } @(objc_type=RenderCommandEncoder, objc_name="setScissorRects") -RenderCommandEncoder_setScissorRects :: #force_inline proc(self: ^RenderCommandEncoder, scissorRects: ^ScissorRect, count: ^NS.Object) { +RenderCommandEncoder_setScissorRects :: #force_inline proc(self: ^RenderCommandEncoder, scissorRects: ^ScissorRect, count: NS.UInteger) { msgSend(nil, self, "setScissorRects:count:", scissorRects, count) } @(objc_type=RenderCommandEncoder, objc_name="setStencilFrontReferenceValue") @@ -7473,7 +7546,7 @@ RenderCommandEncoder_setStencilStoreActionOptions :: #force_inline proc(self: ^R msgSend(nil, self, "setStencilStoreActionOptions:", storeActionOptions) } @(objc_type=RenderCommandEncoder, objc_name="setTessellationFactorBuffer") -RenderCommandEncoder_setTessellationFactorBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, instanceStride: ^NS.Object) { +RenderCommandEncoder_setTessellationFactorBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^Buffer, offset: NS.UInteger, instanceStride: NS.UInteger) { msgSend(nil, self, "setTessellationFactorBuffer:offset:instanceStride:", buffer, offset, instanceStride) } @(objc_type=RenderCommandEncoder, objc_name="setTessellationFactorScale") @@ -7481,47 +7554,47 @@ RenderCommandEncoder_setTessellationFactorScale :: #force_inline proc(self: ^Ren msgSend(nil, self, "setTessellationFactorScale:", scale) } @(objc_type=RenderCommandEncoder, objc_name="setThreadgroupMemoryLength") -RenderCommandEncoder_setThreadgroupMemoryLength :: #force_inline proc(self: ^RenderCommandEncoder, length: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setThreadgroupMemoryLength :: #force_inline proc(self: ^RenderCommandEncoder, length: NS.UInteger, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setThreadgroupMemoryLength:offset:atIndex:", length, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileBuffer") -RenderCommandEncoder_setTileBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setTileBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileBufferOffset") -RenderCommandEncoder_setTileBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setTileBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileBuffers") -RenderCommandEncoder_setTileBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +RenderCommandEncoder_setTileBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { msgSend(nil, self, "setTileBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=RenderCommandEncoder, objc_name="setTileBytes") -RenderCommandEncoder_setTileBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setTileBytes:length:atIndex:", bytes, length, index) } -@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_atIndex_") -RenderCommandEncoder_setTileSamplerState_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStateAtIndex") +RenderCommandEncoder_setTileSamplerStateAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setTileSamplerState:atIndex:", sampler, index) } -@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -RenderCommandEncoder_setTileSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_lodMinClamp_lodMaxClampAtIndex") +RenderCommandEncoder_setTileSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setTileSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -RenderCommandEncoder_setTileSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_lodMinClamps_lodMaxClampsWithRange") +RenderCommandEncoder_setTileSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setTileSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } -@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_withRange_") -RenderCommandEncoder_setTileSamplerStates_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStatesWithRange") +RenderCommandEncoder_setTileSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { msgSend(nil, self, "setTileSamplerStates:withRange:", samplers, range) } @(objc_type=RenderCommandEncoder, objc_name="setTileTexture") -RenderCommandEncoder_setTileTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setTileTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setTileTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileTextures") -RenderCommandEncoder_setTileTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setTileTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: [^]^Texture, range: NS.Range) { msgSend(nil, self, "setTileTextures:withRange:", textures, range) } @(objc_type=RenderCommandEncoder, objc_name="setTriangleFillMode") @@ -7529,47 +7602,47 @@ RenderCommandEncoder_setTriangleFillMode :: #force_inline proc(self: ^RenderComm msgSend(nil, self, "setTriangleFillMode:", fillMode) } @(objc_type=RenderCommandEncoder, objc_name="setVertexAmplificationCount") -RenderCommandEncoder_setVertexAmplificationCount :: #force_inline proc(self: ^RenderCommandEncoder, count: ^NS.Object, viewMappings: ^VertexAmplificationViewMapping) { +RenderCommandEncoder_setVertexAmplificationCount :: #force_inline proc(self: ^RenderCommandEncoder, count: NS.UInteger, viewMappings: ^VertexAmplificationViewMapping) { msgSend(nil, self, "setVertexAmplificationCount:viewMappings:", count, viewMappings) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBuffer") -RenderCommandEncoder_setVertexBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^NS.Object, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setVertexBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBufferOffset") -RenderCommandEncoder_setVertexBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexBufferOffset :: #force_inline proc(self: ^RenderCommandEncoder, offset: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setVertexBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBuffers") -RenderCommandEncoder_setVertexBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: ^^NS.Object, offsets: NS.Integer, range: NS.Range) { +RenderCommandEncoder_setVertexBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { msgSend(nil, self, "setVertexBuffers:offsets:withRange:", buffers, offsets, range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBytes") -RenderCommandEncoder_setVertexBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { msgSend(nil, self, "setVertexBytes:length:atIndex:", bytes, length, index) } -@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_atIndex_") -RenderCommandEncoder_setVertexSamplerState_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, index: ^NS.Object) { +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStateAtIndex") +RenderCommandEncoder_setVertexSamplerStateAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setVertexSamplerState:atIndex:", sampler, index) } -@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_lodMinClamp_lodMaxClamp_atIndex_") -RenderCommandEncoder_setVertexSamplerState_lodMinClamp_lodMaxClamp_atIndex_ :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^NS.Object, lodMinClamp: f32, lodMaxClamp: f32, index: ^NS.Object) { +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_lodMinClamp_lodMaxClampAtIndex") +RenderCommandEncoder_setVertexSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setVertexSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange_") -RenderCommandEncoder_setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_lodMinClamps_lodMaxClampsWithRange") +RenderCommandEncoder_setVertexSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { msgSend(nil, self, "setVertexSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) } -@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_withRange_") -RenderCommandEncoder_setVertexSamplerStates_withRange_ :: #force_inline proc(self: ^RenderCommandEncoder, samplers: ^^NS.Object, range: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStatesWithRange") +RenderCommandEncoder_setVertexSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { msgSend(nil, self, "setVertexSamplerStates:withRange:", samplers, range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexTexture") -RenderCommandEncoder_setVertexTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^NS.Object, index: ^NS.Object) { +RenderCommandEncoder_setVertexTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setVertexTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexTextures") -RenderCommandEncoder_setVertexTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: ^^NS.Object, range: NS.Range) { +RenderCommandEncoder_setVertexTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: [^]^Texture, range: NS.Range) { msgSend(nil, self, "setVertexTextures:withRange:", textures, range) } @(objc_type=RenderCommandEncoder, objc_name="setViewport") @@ -7577,11 +7650,11 @@ RenderCommandEncoder_setViewport :: #force_inline proc(self: ^RenderCommandEncod msgSend(nil, self, "setViewport:", viewport) } @(objc_type=RenderCommandEncoder, objc_name="setViewports") -RenderCommandEncoder_setViewports :: #force_inline proc(self: ^RenderCommandEncoder, viewports: ^Viewport, count: ^NS.Object) { +RenderCommandEncoder_setViewports :: #force_inline proc(self: ^RenderCommandEncoder, viewports: ^Viewport, count: NS.UInteger) { msgSend(nil, self, "setViewports:count:", viewports, count) } @(objc_type=RenderCommandEncoder, objc_name="setVisibilityResultMode") -RenderCommandEncoder_setVisibilityResultMode :: #force_inline proc(self: ^RenderCommandEncoder, mode: VisibilityResultMode, offset: ^NS.Object) { +RenderCommandEncoder_setVisibilityResultMode :: #force_inline proc(self: ^RenderCommandEncoder, mode: VisibilityResultMode, offset: NS.UInteger) { msgSend(nil, self, "setVisibilityResultMode:offset:", mode, offset) } @(objc_type=RenderCommandEncoder, objc_name="textureBarrier") @@ -7589,51 +7662,51 @@ RenderCommandEncoder_textureBarrier :: #force_inline proc(self: ^RenderCommandEn msgSend(nil, self, "textureBarrier") } @(objc_type=RenderCommandEncoder, objc_name="tileHeight") -RenderCommandEncoder_tileHeight :: #force_inline proc(self: ^RenderCommandEncoder) -> NS.Integer { - return msgSend(NS.Integer, self, "tileHeight") +RenderCommandEncoder_tileHeight :: #force_inline proc(self: ^RenderCommandEncoder) -> NS.UInteger { + return msgSend(NS.UInteger, self, "tileHeight") } @(objc_type=RenderCommandEncoder, objc_name="tileWidth") -RenderCommandEncoder_tileWidth :: #force_inline proc(self: ^RenderCommandEncoder) -> NS.Integer { - return msgSend(NS.Integer, self, "tileWidth") +RenderCommandEncoder_tileWidth :: #force_inline proc(self: ^RenderCommandEncoder) -> NS.UInteger { + return msgSend(NS.UInteger, self, "tileWidth") } @(objc_type=RenderCommandEncoder, objc_name="updateFence") -RenderCommandEncoder_updateFence :: #force_inline proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_updateFence :: #force_inline proc(self: ^RenderCommandEncoder, fence: ^Fence, stages: RenderStages) { msgSend(nil, self, "updateFence:afterStages:", fence, stages) } @(objc_type=RenderCommandEncoder, objc_name="useHeap") -RenderCommandEncoder_useHeap :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^NS.Object) { +RenderCommandEncoder_useHeap :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^Heap) { msgSend(nil, self, "useHeap:", heap) } @(objc_type=RenderCommandEncoder, objc_name="useHeap_stages_") -RenderCommandEncoder_useHeap_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_useHeap_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^Heap, stages: RenderStages) { msgSend(nil, self, "useHeap:stages:", heap, stages) } @(objc_type=RenderCommandEncoder, objc_name="useHeaps") -RenderCommandEncoder_useHeaps :: #force_inline proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object) { +RenderCommandEncoder_useHeaps :: #force_inline proc(self: ^RenderCommandEncoder, heaps: [^]^Heap, count: NS.UInteger) { msgSend(nil, self, "useHeaps:count:", heaps, count) } @(objc_type=RenderCommandEncoder, objc_name="useHeaps_count_stages_") -RenderCommandEncoder_useHeaps_count_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heaps: ^^NS.Object, count: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_useHeaps_count_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heaps: [^]^Heap, count: NS.UInteger, stages: RenderStages) { msgSend(nil, self, "useHeaps:count:stages:", heaps, count, stages) } @(objc_type=RenderCommandEncoder, objc_name="useResource") -RenderCommandEncoder_useResource :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage) { +RenderCommandEncoder_useResource :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^Resource, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=RenderCommandEncoder, objc_name="useResource_usage_stages_") -RenderCommandEncoder_useResource_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { +RenderCommandEncoder_useResource_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^Resource, usage: ResourceUsage, stages: RenderStages) { msgSend(nil, self, "useResource:usage:stages:", resource, usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="useResources") -RenderCommandEncoder_useResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage) { +RenderCommandEncoder_useResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage) { msgSend(nil, self, "useResources:count:usage:", resources, count, usage) } @(objc_type=RenderCommandEncoder, objc_name="useResources_count_usage_stages_") -RenderCommandEncoder_useResources_count_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resources: ^^NS.Object, count: ^NS.Object, usage: ResourceUsage, stages: RenderStages) { +RenderCommandEncoder_useResources_count_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage, stages: RenderStages) { msgSend(nil, self, "useResources:count:usage:stages:", resources, count, usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="waitForFence") -RenderCommandEncoder_waitForFence :: #force_inline proc(self: ^RenderCommandEncoder, fence: ^NS.Object, stages: RenderStages) { +RenderCommandEncoder_waitForFence :: #force_inline proc(self: ^RenderCommandEncoder, fence: ^Fence, stages: RenderStages) { msgSend(nil, self, "waitForFence:beforeStages:", fence, stages) } @@ -7664,16 +7737,16 @@ RenderPipelineState_imageblockMemoryLengthForDimensions :: #force_inline proc(se return msgSend(^RenderPipelineState, self, "imageblockMemoryLengthForDimensions:", imageblockDimensions) } @(objc_type=RenderPipelineState, objc_name="imageblockSampleLength") -RenderPipelineState_imageblockSampleLength :: #force_inline proc(self: ^RenderPipelineState) -> NS.Integer { - return msgSend(NS.Integer, self, "imageblockSampleLength") +RenderPipelineState_imageblockSampleLength :: #force_inline proc(self: ^RenderPipelineState) -> NS.UInteger { + return msgSend(NS.UInteger, self, "imageblockSampleLength") } @(objc_type=RenderPipelineState, objc_name="label") RenderPipelineState_label :: #force_inline proc(self: ^RenderPipelineState) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=RenderPipelineState, objc_name="maxTotalThreadsPerThreadgroup") -RenderPipelineState_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^RenderPipelineState) -> NS.Integer { - return msgSend(NS.Integer, self, "maxTotalThreadsPerThreadgroup") +RenderPipelineState_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^RenderPipelineState) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTotalThreadsPerThreadgroup") } @(objc_type=RenderPipelineState, objc_name="supportIndirectCommandBuffers") RenderPipelineState_supportIndirectCommandBuffers :: #force_inline proc(self: ^RenderPipelineState) -> BOOL { @@ -7709,8 +7782,8 @@ Methods: Resource :: struct { using _: NS.Object } @(objc_type=Resource, objc_name="allocatedSize") -Resource_allocatedSize :: #force_inline proc(self: ^Resource) -> NS.Integer { - return msgSend(NS.Integer, self, "allocatedSize") +Resource_allocatedSize :: #force_inline proc(self: ^Resource) -> NS.UInteger { + return msgSend(NS.UInteger, self, "allocatedSize") } @(objc_type=Resource, objc_name="cpuCacheMode") Resource_cpuCacheMode :: #force_inline proc(self: ^Resource) -> CPUCacheMode { @@ -7729,8 +7802,8 @@ Resource_heap :: #force_inline proc(self: ^Resource) -> ^Resource { return msgSend(^Resource, self, "heap") } @(objc_type=Resource, objc_name="heapOffset") -Resource_heapOffset :: #force_inline proc(self: ^Resource) -> NS.Integer { - return msgSend(NS.Integer, self, "heapOffset") +Resource_heapOffset :: #force_inline proc(self: ^Resource) -> NS.UInteger { + return msgSend(NS.UInteger, self, "heapOffset") } @(objc_type=Resource, objc_name="isAliasable") Resource_isAliasable :: #force_inline proc(self: ^Resource) -> BOOL { @@ -7778,23 +7851,23 @@ Methods: ResourceStateCommandEncoder :: struct { using _: NS.Object } @(objc_type=ResourceStateCommandEncoder, objc_name="updateFence") -ResourceStateCommandEncoder_updateFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { +ResourceStateCommandEncoder_updateFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^Fence) { msgSend(nil, self, "updateFence:", fence) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_") -ResourceStateCommandEncoder_updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, indirectBuffer: ^NS.Object, indirectBufferOffset: ^NS.Object) { +ResourceStateCommandEncoder_updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "updateTextureMapping:mode:indirectBuffer:indirectBufferOffset:", texture, mode, indirectBuffer, indirectBufferOffset) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_region_mipLevel_slice_") -ResourceStateCommandEncoder_updateTextureMapping_mode_region_mipLevel_slice_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, region: Region, mipLevel: NS.Integer, slice: NS.Integer) { +ResourceStateCommandEncoder_updateTextureMapping_mode_region_mipLevel_slice_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, region: Region, mipLevel: NS.UInteger, slice: NS.UInteger) { msgSend(nil, self, "updateTextureMapping:mode:region:mipLevel:slice:", texture, mode, region, mipLevel, slice) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMappings") -ResourceStateCommandEncoder_updateTextureMappings :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^NS.Object, mode: SparseTextureMappingMode, regions: ^Region, mipLevels: NS.Integer, slices: NS.Integer, numRegions: ^NS.Object) { +ResourceStateCommandEncoder_updateTextureMappings :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, regions: ^Region, mipLevels: NS.UInteger, slices: NS.UInteger, numRegions: NS.UInteger) { msgSend(nil, self, "updateTextureMappings:mode:regions:mipLevels:slices:numRegions:", texture, mode, regions, mipLevels, slices, numRegions) } @(objc_type=ResourceStateCommandEncoder, objc_name="waitForFence") -ResourceStateCommandEncoder_waitForFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^NS.Object) { +ResourceStateCommandEncoder_waitForFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^Fence) { msgSend(nil, self, "waitForFence:", fence) } @@ -7896,55 +7969,55 @@ Methods: width */ @(objc_class="MTLTexture") -Texture :: struct { using _: NS.Object } +Texture :: struct { using _: Resource } @(objc_type=Texture, objc_name="allowGPUOptimizedContents") Texture_allowGPUOptimizedContents :: #force_inline proc(self: ^Texture) -> BOOL { return msgSend(BOOL, self, "allowGPUOptimizedContents") } @(objc_type=Texture, objc_name="arrayLength") -Texture_arrayLength :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "arrayLength") +Texture_arrayLength :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "arrayLength") } @(objc_type=Texture, objc_name="buffer") Texture_buffer :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "buffer") } @(objc_type=Texture, objc_name="bufferBytesPerRow") -Texture_bufferBytesPerRow :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "bufferBytesPerRow") +Texture_bufferBytesPerRow :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "bufferBytesPerRow") } @(objc_type=Texture, objc_name="bufferOffset") -Texture_bufferOffset :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "bufferOffset") +Texture_bufferOffset :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "bufferOffset") } @(objc_type=Texture, objc_name="depth") -Texture_depth :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "depth") +Texture_depth :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "depth") } @(objc_type=Texture, objc_name="firstMipmapInTail") -Texture_firstMipmapInTail :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "firstMipmapInTail") +Texture_firstMipmapInTail :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "firstMipmapInTail") } @(objc_type=Texture, objc_name="getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_") -Texture_getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object, region: Region, level: ^NS.Object, slice: ^NS.Object) { +Texture_getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: NS.UInteger, bytesPerImage: NS.UInteger, region: Region, level: NS.UInteger, slice: NS.UInteger) { msgSend(nil, self, "getBytes:bytesPerRow:bytesPerImage:fromRegion:mipmapLevel:slice:", pixelBytes, bytesPerRow, bytesPerImage, region, level, slice) } @(objc_type=Texture, objc_name="getBytes_bytesPerRow_fromRegion_mipmapLevel_") -Texture_getBytes_bytesPerRow_fromRegion_mipmapLevel_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: ^NS.Object, region: Region, level: ^NS.Object) { +Texture_getBytes_bytesPerRow_fromRegion_mipmapLevel_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: NS.UInteger, region: Region, level: NS.UInteger) { msgSend(nil, self, "getBytes:bytesPerRow:fromRegion:mipmapLevel:", pixelBytes, bytesPerRow, region, level) } @(objc_type=Texture, objc_name="height") -Texture_height :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "height") +Texture_height :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "height") } @(objc_type=Texture, objc_name="iosurface") Texture_iosurface :: #force_inline proc(self: ^Texture) -> IOSurfaceRef { return msgSend(IOSurfaceRef, self, "iosurface") } @(objc_type=Texture, objc_name="iosurfacePlane") -Texture_iosurfacePlane :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "iosurfacePlane") +Texture_iosurfacePlane :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "iosurfacePlane") } @(objc_type=Texture, objc_name="isFramebufferOnly") Texture_isFramebufferOnly :: #force_inline proc(self: ^Texture) -> BOOL { @@ -7959,11 +8032,11 @@ Texture_isSparse :: #force_inline proc(self: ^Texture) -> BOOL { return msgSend(BOOL, self, "isSparse") } @(objc_type=Texture, objc_name="mipmapLevelCount") -Texture_mipmapLevelCount :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "mipmapLevelCount") +Texture_mipmapLevelCount :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "mipmapLevelCount") } @(objc_type=Texture, objc_name="newRemoteTextureViewForDevice") -Texture_newRemoteTextureViewForDevice :: #force_inline proc(self: ^Texture, device: ^NS.Object) -> ^Texture { +Texture_newRemoteTextureViewForDevice :: #force_inline proc(self: ^Texture, device: ^Device) -> ^Texture { return msgSend(^Texture, self, "newRemoteTextureViewForDevice:", device) } @(objc_type=Texture, objc_name="newSharedTextureHandle") @@ -7983,12 +8056,12 @@ Texture_newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_ :: #for return msgSend(^Texture, self, "newTextureViewWithPixelFormat:textureType:levels:slices:swizzle:", pixelFormat, textureType, levelRange, sliceRange, swizzle) } @(objc_type=Texture, objc_name="parentRelativeLevel") -Texture_parentRelativeLevel :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "parentRelativeLevel") +Texture_parentRelativeLevel :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "parentRelativeLevel") } @(objc_type=Texture, objc_name="parentRelativeSlice") -Texture_parentRelativeSlice :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "parentRelativeSlice") +Texture_parentRelativeSlice :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "parentRelativeSlice") } @(objc_type=Texture, objc_name="parentTexture") Texture_parentTexture :: #force_inline proc(self: ^Texture) -> ^Texture { @@ -8003,11 +8076,11 @@ Texture_remoteStorageTexture :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "remoteStorageTexture") } @(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_") -Texture_replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_ :: #force_inline proc(self: ^Texture, region: Region, level: ^NS.Object, slice: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object, bytesPerImage: ^NS.Object) { +Texture_replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_ :: #force_inline proc(self: ^Texture, region: Region, level: NS.UInteger, slice: NS.UInteger, pixelBytes: rawptr, bytesPerRow: NS.UInteger, bytesPerImage: NS.UInteger) { msgSend(nil, self, "replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:", region, level, slice, pixelBytes, bytesPerRow, bytesPerImage) } @(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_withBytes_bytesPerRow_") -Texture_replaceRegion_mipmapLevel_withBytes_bytesPerRow_ :: #force_inline proc(self: ^Texture, region: Region, level: ^NS.Object, pixelBytes: rawptr, bytesPerRow: ^NS.Object) { +Texture_replaceRegion_mipmapLevel_withBytes_bytesPerRow_ :: #force_inline proc(self: ^Texture, region: Region, level: NS.UInteger, pixelBytes: rawptr, bytesPerRow: NS.UInteger) { msgSend(nil, self, "replaceRegion:mipmapLevel:withBytes:bytesPerRow:", region, level, pixelBytes, bytesPerRow) } @(objc_type=Texture, objc_name="rootResource") @@ -8015,16 +8088,16 @@ Texture_rootResource :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "rootResource") } @(objc_type=Texture, objc_name="sampleCount") -Texture_sampleCount :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "sampleCount") +Texture_sampleCount :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "sampleCount") } @(objc_type=Texture, objc_name="swizzle") Texture_swizzle :: #force_inline proc(self: ^Texture) -> TextureSwizzleChannels { return msgSend(TextureSwizzleChannels, self, "swizzle") } @(objc_type=Texture, objc_name="tailSizeInBytes") -Texture_tailSizeInBytes :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "tailSizeInBytes") +Texture_tailSizeInBytes :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "tailSizeInBytes") } @(objc_type=Texture, objc_name="textureType") Texture_textureType :: #force_inline proc(self: ^Texture) -> TextureType { @@ -8035,8 +8108,8 @@ Texture_usage :: #force_inline proc(self: ^Texture) -> TextureUsage { return msgSend(TextureUsage, self, "usage") } @(objc_type=Texture, objc_name="width") -Texture_width :: #force_inline proc(self: ^Texture) -> NS.Integer { - return msgSend(NS.Integer, self, "width") +Texture_width :: #force_inline proc(self: ^Texture) -> NS.UInteger { + return msgSend(NS.UInteger, self, "width") } //////////////////////////////////////////////////////////////////////////////// @@ -8050,13 +8123,13 @@ Methods: setFunctions */ @(objc_class="MTLVisibleFunctionTable") -VisibleFunctionTable :: struct { using _: NS.Object } +VisibleFunctionTable :: struct { using _: Resource } @(objc_type=VisibleFunctionTable, objc_name="setFunction") -VisibleFunctionTable_setFunction :: #force_inline proc(self: ^VisibleFunctionTable, function: ^NS.Object, index: ^NS.Object) { +VisibleFunctionTable_setFunction :: #force_inline proc(self: ^VisibleFunctionTable, function: ^FunctionHandle, index: NS.UInteger) { msgSend(nil, self, "setFunction:atIndex:", function, index) } @(objc_type=VisibleFunctionTable, objc_name="setFunctions") -VisibleFunctionTable_setFunctions :: #force_inline proc(self: ^VisibleFunctionTable, functions: ^^NS.Object, range: NS.Range) { +VisibleFunctionTable_setFunctions :: #force_inline proc(self: ^VisibleFunctionTable, functions: [^]^FunctionHandle, range: NS.Range) { msgSend(nil, self, "setFunctions:withRange:", functions, range) } diff --git a/core/sys/darwin/Metal/MetalProcedures.odin b/core/sys/darwin/Metal/MetalProcedures.odin index 120396b5d..6db5fe316 100644 --- a/core/sys/darwin/Metal/MetalProcedures.odin +++ b/core/sys/darwin/Metal/MetalProcedures.odin @@ -8,7 +8,7 @@ foreign import "system:Metal.framework" @(default_calling_convention="c", link_prefix="MTL") foreign Metal { CopyAllDevices :: proc() -> ^NS.Array --- - CopyAllDevicesWithObserver :: proc(observer: ^^NS.Object, handler: DeviceNotificationHandler) -> ^NS.Array --- - CreateSystemDefaultDevice :: proc() -> ^NS.Object --- - RemoveDeviceObserver :: proc(observer: ^NS.Object) --- + CopyAllDevicesWithObserver :: proc(observer: ^id, handler: DeviceNotificationHandler) -> ^NS.Array --- + CreateSystemDefaultDevice :: proc() -> ^Device --- + RemoveDeviceObserver :: proc(observer: id) --- } \ No newline at end of file diff --git a/core/sys/darwin/Metal/MetalTypes.odin b/core/sys/darwin/Metal/MetalTypes.odin index c8c02e5f2..24a951853 100644 --- a/core/sys/darwin/Metal/MetalTypes.odin +++ b/core/sys/darwin/Metal/MetalTypes.odin @@ -4,11 +4,15 @@ import NS "core:sys/darwin/Foundation" import "core:intrinsics" BOOL :: NS.BOOL +id :: ^NS.Object CFTimeInterval :: NS.TimeInterval IOSurfaceRef :: distinct rawptr +dispatch_queue_t :: id +dispatch_data_t :: id + @(private) msgSend :: intrinsics.objc_send diff --git a/examples/objc/objc_main.odin b/examples/objc/objc_main.odin new file mode 100644 index 000000000..0f8d1f5bf --- /dev/null +++ b/examples/objc/objc_main.odin @@ -0,0 +1,8 @@ +package objc_test + +import NS "core:sys/darwin/Foundation" +import MTL "core:sys/darwin/Metal" + +main :: proc() { + +} \ No newline at end of file From b647b45ba50c4cb7de0fab970da73212f9a74176 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 21:25:20 +0000 Subject: [PATCH 0139/1052] Remove temp file --- examples/objc/objc_main.odin | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 examples/objc/objc_main.odin diff --git a/examples/objc/objc_main.odin b/examples/objc/objc_main.odin deleted file mode 100644 index 0f8d1f5bf..000000000 --- a/examples/objc/objc_main.odin +++ /dev/null @@ -1,8 +0,0 @@ -package objc_test - -import NS "core:sys/darwin/Foundation" -import MTL "core:sys/darwin/Metal" - -main :: proc() { - -} \ No newline at end of file From 39a0f8c96a4cd35d0593ed9230e2434859212f58 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 21:28:56 +0000 Subject: [PATCH 0140/1052] Use distinct array types --- core/sys/darwin/Metal/MetalTypes.odin | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/sys/darwin/Metal/MetalTypes.odin b/core/sys/darwin/Metal/MetalTypes.odin index 24a951853..e1269f926 100644 --- a/core/sys/darwin/Metal/MetalTypes.odin +++ b/core/sys/darwin/Metal/MetalTypes.odin @@ -131,10 +131,7 @@ Region :: struct { size: Size, } -SamplePosition :: struct { - x: f32, - y: f32, -} +SamplePosition :: distinct [2]f32 ScissorRect :: struct { x: NS.Integer, From e2aa8f426da252f946af743a624cd097b7f09937 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 21:45:34 +0000 Subject: [PATCH 0141/1052] Improve type hierarchy and method names --- core/sys/darwin/Metal/MetalClasses.odin | 162 ++++++++++++------------ 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 5695cbb6f..159cc723b 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -22,7 +22,7 @@ Methods: setBoundingBoxStride */ @(objc_class="MTLAccelerationStructureBoundingBoxGeometryDescriptor") -AccelerationStructureBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureBoundingBoxGeometryDescriptor) } +AccelerationStructureBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureBoundingBoxGeometryDescriptor), using _: AccelerationStructureDescriptor } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="alloc") AccelerationStructureBoundingBoxGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { @@ -227,7 +227,7 @@ Methods: vertexStride */ @(objc_class="MTLAccelerationStructureTriangleGeometryDescriptor") -AccelerationStructureTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureTriangleGeometryDescriptor) } +AccelerationStructureTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureTriangleGeometryDescriptor), using _: AccelerationStructureDescriptor } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_class_name="alloc") AccelerationStructureTriangleGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureTriangleGeometryDescriptor { @@ -506,7 +506,7 @@ Methods: stride */ @(objc_class="MTLArrayType") -ArrayType :: struct { using _: NS.Object } +ArrayType :: struct { using _: Type } @(objc_type=ArrayType, objc_class_name="alloc") ArrayType_alloc :: #force_inline proc() -> ^ArrayType { @@ -1974,7 +1974,7 @@ Methods: setInstancedAccelerationStructures */ @(objc_class="MTLInstanceAccelerationStructureDescriptor") -InstanceAccelerationStructureDescriptor :: struct { using _: NS.Copying(InstanceAccelerationStructureDescriptor) } +InstanceAccelerationStructureDescriptor :: struct { using _: NS.Copying(InstanceAccelerationStructureDescriptor), using _: AccelerationStructureDescriptor } @(objc_type=InstanceAccelerationStructureDescriptor, objc_class_name="alloc") InstanceAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^InstanceAccelerationStructureDescriptor { @@ -2205,7 +2205,7 @@ Methods: elementType */ @(objc_class="MTLPointerType") -PointerType :: struct { using _: NS.Object } +PointerType :: struct { using _: Type } @(objc_type=PointerType, objc_class_name="alloc") PointerType_alloc :: #force_inline proc() -> ^PointerType { @@ -2258,7 +2258,7 @@ Methods: setGeometryDescriptors */ @(objc_class="MTLPrimitiveAccelerationStructureDescriptor") -PrimitiveAccelerationStructureDescriptor :: struct { using _: NS.Copying(PrimitiveAccelerationStructureDescriptor) } +PrimitiveAccelerationStructureDescriptor :: struct { using _: NS.Copying(PrimitiveAccelerationStructureDescriptor), using _: AccelerationStructureDescriptor } @(objc_type=PrimitiveAccelerationStructureDescriptor, objc_class_name="alloc") PrimitiveAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^PrimitiveAccelerationStructureDescriptor { @@ -2624,7 +2624,7 @@ Methods: setClearColor */ @(objc_class="MTLRenderPassColorAttachmentDescriptor") -RenderPassColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassColorAttachmentDescriptor) } +RenderPassColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassColorAttachmentDescriptor), using _: RenderPassAttachmentDescriptor } @(objc_type=RenderPassColorAttachmentDescriptor, objc_class_name="alloc") RenderPassColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassColorAttachmentDescriptor { @@ -2690,7 +2690,7 @@ Methods: setDepthResolveFilter */ @(objc_class="MTLRenderPassDepthAttachmentDescriptor") -RenderPassDepthAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassDepthAttachmentDescriptor) } +RenderPassDepthAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassDepthAttachmentDescriptor), using _: RenderPassAttachmentDescriptor } @(objc_type=RenderPassDepthAttachmentDescriptor, objc_class_name="alloc") RenderPassDepthAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassDepthAttachmentDescriptor { @@ -2757,7 +2757,7 @@ Methods: visibilityResultBuffer */ @(objc_class="MTLRenderPassDescriptor") -RenderPassDescriptor :: struct { using _: NS.Copying(RenderPassDescriptor) } +RenderPassDescriptor :: struct { using _: NS.Copying(RenderPassDescriptor), using _: AccelerationStructureDescriptor } @(objc_type=RenderPassDescriptor, objc_class_name="alloc") RenderPassDescriptor_alloc :: #force_inline proc() -> ^RenderPassDescriptor { @@ -3059,7 +3059,7 @@ Methods: writeMask */ @(objc_class="MTLRenderPipelineColorAttachmentDescriptor") -RenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPipelineColorAttachmentDescriptor) } +RenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPipelineColorAttachmentDescriptor), using _: RenderPassAttachmentDescriptor } @(objc_type=RenderPipelineColorAttachmentDescriptor, objc_class_name="alloc") RenderPipelineColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPipelineColorAttachmentDescriptor { @@ -4071,7 +4071,7 @@ Methods: members */ @(objc_class="MTLStructType") -StructType :: struct { using _: NS.Object } +StructType :: struct { using _: Type } @(objc_type=StructType, objc_class_name="alloc") StructType_alloc :: #force_inline proc() -> ^StructType { @@ -4292,7 +4292,7 @@ Methods: textureType */ @(objc_class="MTLTextureReferenceType") -TextureReferenceType :: struct { using _: NS.Object } +TextureReferenceType :: struct { using _: Type } @(objc_type=TextureReferenceType, objc_class_name="alloc") TextureReferenceType_alloc :: #force_inline proc() -> ^TextureReferenceType { @@ -4844,7 +4844,7 @@ Methods: writeCompactedAccelerationStructureSize */ @(objc_class="MTLAccelerationStructureCommandEncoder") -AccelerationStructureCommandEncoder :: struct { using _: NS.Object } +AccelerationStructureCommandEncoder :: struct { using _: CommandEncoder } @(objc_type=AccelerationStructureCommandEncoder, objc_name="buildAccelerationStructure") AccelerationStructureCommandEncoder_buildAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, accelerationStructure: ^AccelerationStructure, descriptor: ^AccelerationStructureDescriptor, scratchBuffer: ^Buffer, scratchBufferOffset: NS.UInteger) { @@ -5122,14 +5122,14 @@ Methods: waitForFence */ @(objc_class="MTLBlitCommandEncoder") -BlitCommandEncoder :: struct { using _: NS.Object } +BlitCommandEncoder :: struct { using _: CommandEncoder } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin) { +BlitCommandEncoder_copyFromBufferEx :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin, options: BlitOption) { +BlitCommandEncoder_copyFromBufferExWithOptions :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin, options: BlitOption) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:options:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin, options) } @(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_") @@ -5676,7 +5676,7 @@ Methods: waitForFence */ @(objc_class="MTLComputeCommandEncoder") -ComputeCommandEncoder :: struct { using _: NS.Object } +ComputeCommandEncoder :: struct { using _: CommandEncoder } @(objc_type=ComputeCommandEncoder, objc_name="dispatchThreadgroups") ComputeCommandEncoder_dispatchThreadgroups :: #force_inline proc(self: ^ComputeCommandEncoder, threadgroupsPerGrid: Size, threadsPerThreadgroup: Size) { @@ -6231,30 +6231,30 @@ Device_newCommandQueue :: #force_inline proc(self: ^Device) -> ^Device { Device_newCommandQueueWithMaxCommandBufferCount :: #force_inline proc(self: ^Device, maxCommandBufferCount: NS.UInteger) -> ^Device { return msgSend(^Device, self, "newCommandQueueWithMaxCommandBufferCount:", maxCommandBufferCount) } -@(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_completionHandler_") -Device_newComputePipelineStateWithDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { +@(objc_type=Device, objc_name="newComputePipelineStateWithDescriptorWithCompletionHandler") +Device_newComputePipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } -@(objc_type=Device, objc_name="newComputePipelineStateWithDescriptor_options_reflection_error_") -Device_newComputePipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newComputePipelineStateWithDescriptorWithReflection") +Device_newComputePipelineStateWithDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newComputePipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } -@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_completionHandler_") -Device_newComputePipelineStateWithFunction_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^Function, completionHandler: NewComputePipelineStateCompletionHandler) { +@(objc_type=Device, objc_name="newComputePipelineStateWithFunctionWithCompletionHandler") +Device_newComputePipelineStateWithFunctionWithCompletionHandler :: #force_inline proc(self: ^Device, computeFunction: ^Function, completionHandler: NewComputePipelineStateCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithFunction:completionHandler:", computeFunction, completionHandler) } -@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_error_") -Device_newComputePipelineStateWithFunction_error_ :: #force_inline proc(self: ^Device, computeFunction: ^Function) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newComputePipelineStateWithFunction") +Device_newComputePipelineStateWithFunction :: #force_inline proc(self: ^Device, computeFunction: ^Function) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, &error) return } -@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_completionHandler_") -Device_newComputePipelineStateWithFunction_options_completionHandler_ :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { +@(objc_type=Device, objc_name="newComputePipelineStateWithFunctionWithOptionsAndCompletionHandler") +Device_newComputePipelineStateWithFunctionWithOptionsAndCompletionHandler :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newComputePipelineStateWithFunction:options:completionHandler:", computeFunction, options, completionHandler) } -@(objc_type=Device, objc_name="newComputePipelineStateWithFunction_options_reflection_error_") -Device_newComputePipelineStateWithFunction_options_reflection_error_ :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newComputePipelineStateWithFunctionWithReflection") +Device_newComputePipelineStateWithFunctionWithReflection :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, &error) return } @@ -6312,12 +6312,12 @@ Device_newLibraryWithFile :: #force_inline proc(self: ^Device, filepath: ^NS.Str device = msgSend(^Device, self, "newLibraryWithFile:error:", filepath, &error) return } -@(objc_type=Device, objc_name="newLibraryWithSource_options_completionHandler_") -Device_newLibraryWithSource_options_completionHandler_ :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) { +@(objc_type=Device, objc_name="newLibraryWithSourceWithCompletionHandler") +Device_newLibraryWithSourceWithCompletionHandler :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) { msgSend(nil, self, "newLibraryWithSource:options:completionHandler:", source, options, completionHandler) } -@(objc_type=Device, objc_name="newLibraryWithSource_options_error_") -Device_newLibraryWithSource_options_error_ :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newLibraryWithSource") +Device_newLibraryWithSource :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newLibraryWithSource:options:error:", source, options, &error) return } @@ -6330,30 +6330,30 @@ Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> ( Device_newRasterizationRateMapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^Device { return msgSend(^Device, self, "newRasterizationRateMapWithDescriptor:", descriptor) } -@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_completionHandler_") -Device_newRenderPipelineStateWithDescriptor_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithCompletionHandler") +Device_newRenderPipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) } -@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_error_") -Device_newRenderPipelineStateWithDescriptor_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor") +Device_newRenderPipelineStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, &error) return } -@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_completionHandler_") -Device_newRenderPipelineStateWithDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler") +Device_newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } -@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor_options_reflection_error_") -Device_newRenderPipelineStateWithDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithReflection") +Device_newRenderPipelineStateWithDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } -@(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_completionHandler_") -Device_newRenderPipelineStateWithTileDescriptor_options_completionHandler_ :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { +@(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptorWithCompletionHandler") +Device_newRenderPipelineStateWithTileDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithTileDescriptor:options:completionHandler:", descriptor, options, completionHandler) } -@(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptor_options_reflection_error_") -Device_newRenderPipelineStateWithTileDescriptor_options_reflection_error_ :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptorWithReflection") +Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } @@ -6381,8 +6381,8 @@ Device_newSharedTextureWithHandle :: #force_inline proc(self: ^Device, sharedHan Device_newTextureWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^Device { return msgSend(^Device, self, "newTextureWithDescriptor:", desc) } -@(objc_type=Device, objc_name="newTextureWithDescriptor_iosurface_plane_") -Device_newTextureWithDescriptor_iosurface_plane_ :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Device { +@(objc_type=Device, objc_name="newTextureWithDescriptorWithIOSurface") +Device_newTextureWithDescriptorWithIOSurface :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Device { return msgSend(^Device, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) } @(objc_type=Device, objc_name="peerCount") @@ -6664,8 +6664,8 @@ Function_name :: #force_inline proc(self: ^Function) -> ^NS.String { Function_newArgumentEncoderWithBufferIndex :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger) -> ^Function { return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:", bufferIndex) } -@(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex_reflection_") -Function_newArgumentEncoderWithBufferIndex_reflection_ :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger, reflection: ^AutoreleasedArgument) -> ^Function { +@(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndexWithReflection") +Function_newArgumentEncoderWithBufferIndexWithReflection :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger, reflection: ^AutoreleasedArgument) -> ^Function { return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:reflection:", bufferIndex, reflection) } @(objc_type=Function, objc_name="options") @@ -6840,16 +6840,16 @@ Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: Heap_newBufferWithLength :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:", length, options) } -@(objc_type=Heap, objc_name="newBufferWithLength_options_offset_") -Heap_newBufferWithLength_options_offset_ :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Heap { +@(objc_type=Heap, objc_name="newBufferWithLengthWithOptions") +Heap_newBufferWithLengthWithOptions :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:offset:", length, options, offset) } @(objc_type=Heap, objc_name="newTextureWithDescriptor") Heap_newTextureWithDescriptor :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Heap { return msgSend(^Heap, self, "newTextureWithDescriptor:", desc) } -@(objc_type=Heap, objc_name="newTextureWithDescriptor_offset_") -Heap_newTextureWithDescriptor_offset_ :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Heap { +@(objc_type=Heap, objc_name="newTextureWithDescriptorWithOffset") +Heap_newTextureWithDescriptorWithOffset :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "newTextureWithDescriptor:offset:", descriptor, offset) } @(objc_type=Heap, objc_name="resourceOptions") @@ -7119,12 +7119,12 @@ Library_installName :: #force_inline proc(self: ^Library) -> ^NS.String { Library_label :: #force_inline proc(self: ^Library) -> ^NS.String { return msgSend(^NS.String, self, "label") } -@(objc_type=Library, objc_name="newFunctionWithDescriptor_completionHandler_") -Library_newFunctionWithDescriptor_completionHandler_ :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) { +@(objc_type=Library, objc_name="newFunctionWithDescriptorWithCompletionHandler") +Library_newFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) { msgSend(nil, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } -@(objc_type=Library, objc_name="newFunctionWithDescriptor_error_") -Library_newFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { +@(objc_type=Library, objc_name="newFunctionWithDescriptor") +Library_newFunctionWithDescriptor :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { library = msgSend(^Library, self, "newFunctionWithDescriptor:error:", descriptor, &error) return } @@ -7132,21 +7132,21 @@ Library_newFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, d Library_newFunctionWithName :: #force_inline proc(self: ^Library, functionName: ^NS.String) -> ^Library { return msgSend(^Library, self, "newFunctionWithName:", functionName) } -@(objc_type=Library, objc_name="newFunctionWithName_constantValues_completionHandler_") -Library_newFunctionWithName_constantValues_completionHandler_ :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) { +@(objc_type=Library, objc_name="newFunctionWithNameWithConstantValuesAndCompletionHandler") +Library_newFunctionWithNameWithConstantValuesAndCompletionHandler :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) { msgSend(nil, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) } -@(objc_type=Library, objc_name="newFunctionWithName_constantValues_error_") -Library_newFunctionWithName_constantValues_error_ :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues) -> (library: ^Library, error: ^NS.Error) { +@(objc_type=Library, objc_name="newFunctionWithNameWithConstantValues") +Library_newFunctionWithNameWithConstantValues :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues) -> (library: ^Library, error: ^NS.Error) { library = msgSend(^Library, self, "newFunctionWithName:constantValues:error:", name, constantValues, &error) return } -@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_completionHandler_") -Library_newIntersectionFunctionWithDescriptor_completionHandler_ :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) { +@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptorWithCompletionHandler") +Library_newIntersectionFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) { msgSend(nil, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } -@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor_error_") -Library_newIntersectionFunctionWithDescriptor_error_ :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { +@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor") +Library_newIntersectionFunctionWithDescriptor :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { library = msgSend(^Library, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, &error) return } @@ -7175,7 +7175,7 @@ Methods: setStencilStoreActionOptions */ @(objc_class="MTLParallelRenderCommandEncoder") -ParallelRenderCommandEncoder :: struct { using _: NS.Object } +ParallelRenderCommandEncoder :: struct { using _: CommandEncoder } @(objc_type=ParallelRenderCommandEncoder, objc_name="renderCommandEncoder") ParallelRenderCommandEncoder_renderCommandEncoder :: #force_inline proc(self: ^ParallelRenderCommandEncoder) -> ^ParallelRenderCommandEncoder { @@ -7363,7 +7363,7 @@ Methods: waitForFence */ @(objc_class="MTLRenderCommandEncoder") -RenderCommandEncoder :: struct { using _: NS.Object } +RenderCommandEncoder :: struct { using _: CommandEncoder } @(objc_type=RenderCommandEncoder, objc_name="dispatchThreadsPerTile") RenderCommandEncoder_dispatchThreadsPerTile :: #force_inline proc(self: ^RenderCommandEncoder, threadsPerTile: Size) { @@ -7677,32 +7677,32 @@ RenderCommandEncoder_updateFence :: #force_inline proc(self: ^RenderCommandEncod RenderCommandEncoder_useHeap :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^Heap) { msgSend(nil, self, "useHeap:", heap) } -@(objc_type=RenderCommandEncoder, objc_name="useHeap_stages_") -RenderCommandEncoder_useHeap_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^Heap, stages: RenderStages) { +@(objc_type=RenderCommandEncoder, objc_name="useHeapWithStages") +RenderCommandEncoder_useHeapWithStages :: #force_inline proc(self: ^RenderCommandEncoder, heap: ^Heap, stages: RenderStages) { msgSend(nil, self, "useHeap:stages:", heap, stages) } @(objc_type=RenderCommandEncoder, objc_name="useHeaps") RenderCommandEncoder_useHeaps :: #force_inline proc(self: ^RenderCommandEncoder, heaps: [^]^Heap, count: NS.UInteger) { msgSend(nil, self, "useHeaps:count:", heaps, count) } -@(objc_type=RenderCommandEncoder, objc_name="useHeaps_count_stages_") -RenderCommandEncoder_useHeaps_count_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, heaps: [^]^Heap, count: NS.UInteger, stages: RenderStages) { +@(objc_type=RenderCommandEncoder, objc_name="useHeapsWithStages") +RenderCommandEncoder_useHeapsWithStages :: #force_inline proc(self: ^RenderCommandEncoder, heaps: [^]^Heap, count: NS.UInteger, stages: RenderStages) { msgSend(nil, self, "useHeaps:count:stages:", heaps, count, stages) } @(objc_type=RenderCommandEncoder, objc_name="useResource") RenderCommandEncoder_useResource :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^Resource, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } -@(objc_type=RenderCommandEncoder, objc_name="useResource_usage_stages_") -RenderCommandEncoder_useResource_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^Resource, usage: ResourceUsage, stages: RenderStages) { +@(objc_type=RenderCommandEncoder, objc_name="useResourceWithStages") +RenderCommandEncoder_useResourceWithStages :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^Resource, usage: ResourceUsage, stages: RenderStages) { msgSend(nil, self, "useResource:usage:stages:", resource, usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="useResources") RenderCommandEncoder_useResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage) { msgSend(nil, self, "useResources:count:usage:", resources, count, usage) } -@(objc_type=RenderCommandEncoder, objc_name="useResources_count_usage_stages_") -RenderCommandEncoder_useResources_count_usage_stages_ :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage, stages: RenderStages) { +@(objc_type=RenderCommandEncoder, objc_name="useResourcesStages") +RenderCommandEncoder_useResourcesStages :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage, stages: RenderStages) { msgSend(nil, self, "useResources:count:usage:stages:", resources, count, usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="waitForFence") @@ -7848,18 +7848,18 @@ Methods: waitForFence */ @(objc_class="MTLResourceStateCommandEncoder") -ResourceStateCommandEncoder :: struct { using _: NS.Object } +ResourceStateCommandEncoder :: struct { using _: CommandEncoder } @(objc_type=ResourceStateCommandEncoder, objc_name="updateFence") ResourceStateCommandEncoder_updateFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^Fence) { msgSend(nil, self, "updateFence:", fence) } -@(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_") -ResourceStateCommandEncoder_updateTextureMapping_mode_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { +@(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMappingIndirect") +ResourceStateCommandEncoder_updateTextureMappingIndirect :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "updateTextureMapping:mode:indirectBuffer:indirectBufferOffset:", texture, mode, indirectBuffer, indirectBufferOffset) } -@(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping_mode_region_mipLevel_slice_") -ResourceStateCommandEncoder_updateTextureMapping_mode_region_mipLevel_slice_ :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, region: Region, mipLevel: NS.UInteger, slice: NS.UInteger) { +@(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMapping") +ResourceStateCommandEncoder_updateTextureMapping :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, region: Region, mipLevel: NS.UInteger, slice: NS.UInteger) { msgSend(nil, self, "updateTextureMapping:mode:region:mipLevel:slice:", texture, mode, region, mipLevel, slice) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMappings") @@ -7906,7 +7906,7 @@ Methods: signaledValue */ @(objc_class="MTLSharedEvent") -SharedEvent :: struct { using _: NS.Object } +SharedEvent :: struct { using _: Event } @(objc_type=SharedEvent, objc_name="newSharedEventHandle") SharedEvent_newSharedEventHandle :: #force_inline proc(self: ^SharedEvent) -> ^SharedEventHandle { From 8966294823d7397abaa639f37f55f26496466ba3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Feb 2022 22:03:15 +0000 Subject: [PATCH 0142/1052] Correct method name --- core/sys/darwin/Metal/MetalClasses.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 159cc723b..26e5e2452 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -6051,7 +6051,7 @@ Methods: newRenderPipelineStateWithDescriptor newRenderPipelineStateWithTileDescriptor newRenderPipelineStateWithTileDescriptor - newSamplerStateWithDescriptor + newSamplerState newSharedEvent newSharedEventWithHandle newSharedTextureWithDescriptor @@ -6357,9 +6357,9 @@ Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline p device = msgSend(^Device, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } -@(objc_type=Device, objc_name="newSamplerStateWithDescriptor") -Device_newSamplerStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^Device { - return msgSend(^Device, self, "newSamplerStateWithDescriptor:", descriptor) +@(objc_type=Device, objc_name="newSamplerState") +Device_newSamplerState :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^Device { + return msgSend(^Device, self, "newSamplerState:", descriptor) } @(objc_type=Device, objc_name="newSharedEvent") Device_newSharedEvent :: #force_inline proc(self: ^Device) -> ^Device { From e59064dd59d69fe94b5c6ba8c24ed92bc2143e4e Mon Sep 17 00:00:00 2001 From: FancyKillerPanda Date: Sun, 13 Feb 2022 10:33:48 +1100 Subject: [PATCH 0143/1052] Updated vendor/sdl2/ttf LIB and DLL. --- vendor/sdl2/ttf/SDL2_ttf.dll | Bin 33792 -> 1534464 bytes vendor/sdl2/ttf/SDL2_ttf.lib | Bin 12122 -> 18406 bytes vendor/sdl2/ttf/sdl_ttf.odin | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/sdl2/ttf/SDL2_ttf.dll b/vendor/sdl2/ttf/SDL2_ttf.dll index 575636a915df04b5a82b36a5635e59624380c9de..2acc0e5bc8b9ca9933e585af49f64923297e41c2 100644 GIT binary patch literal 1534464 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 z

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%0AaPqQ5@O3xS$Xd^ba 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

B^x7efaE;|TzT#<&wtO!PS(#JdB%+pYgXf9 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

)2tolW(?QM)sc; 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≥r8X?EVV(^GHq5c1&kM;j{kJ5#IO?^Z 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 z zBwt#!0kj_}fy$Q2m*;GkFE1&RFE2eIUoM<0UtYdLzI=S2d}UjneC4gha&7)*xpoe4 z-XgiSWT9NU=1sYFZMj^#Zj)TQ@r1Z|WS4yL$T9iiF_2QLtyVQ#*t~W)Ki1c-dClfq zYDW2UtzJhCZy^WNW=*MFvkbr3aL$|c?)UtV!ozPxs!d>NP7l+v5#$XDi}O)!eD zY~F}=nFm@0T7&jM>GPI=ic!1SYR%SdQm@tO-XEuLenw8o%$}ZH< zMQ-+tRN8IYiRAC6Hhr;E|2fYzeD9UM@X0nwDVdW~TlmIjc2Y)4=JZH>@iawLHQs29 z`rSfDz!Pb*RoEvoF{J^C#xq3$i7Jr>Q5;kE?9?3P^QsRBZLj;3>=zyo-D9${rlk(b zoPp{-fY;u-PZG*^VS9+=DN~ecV=q1Bk5|T3$@W5DF{G87kYq=(u-GX2eIki&HA1Y+ z#yvnhoW2bY*u~>sPFLKIT!DMQPz$I<4v3yz?*yV-Ky=%Z?sL$+H@g0>ZKlo5-|H`9 zUbCq>pz6twHurrhkF1ofaIeZ!+O$P8&$n?!{T@}%w_8Otr^mNZMOm4u=i8fVBD&wo zJF32(G5Vg$7yhK8&a}nd$thEs$;-yoHAaoEYpe!VPQX5p_KAGJ?|-JQ@kbD0B$MlN zb&a1sTi5s===DT=brJX-$OH19d7pU7XyC9x&GOR?fb@(hnay;>3Z5vAmQq%gRnz^PGS-;HJ)uR6fLvFD8rRY51&i zdNK`Xi%`qZ3I~sljZK&k7dt6#^r*Pl(Fwz1g7HvR{pHYW%~7t@ZQtgDBiq-CndsM&Xh4~{l9Ul`;$5(&xS>Ws( z!5>dXt+UgUa?>+2Xc#ry@HLGL3Q)EhCTmJ|r1lABa-?r0>o@EE@G|v^jNCuuqxlRR zHDW~U$OJJcc5uv?;R%xl4viTt29Fwd~k?PlX(vaa3;)YHd9W!zWj+7iOMopfU{^E>OF${lwBt2OSju|m*_=HI#V@AY^ z_~9|gU|j65Awv^X$$-phDIz{LVcf7m2}4y;%%DM&;u9tek5$>xsZ(c6OUf28V`E3h z42hkjSc{z6Vetv0 zErQsQ14j*_8up0l+qJb_9>D`_cvO&Q0lH5#PCfME$EV&a5#l+lhJVl4tEJ-hWm zQ-7q$szpnoksCG-DN`bvm~AMpI>V{k>m*Z?11N{uKhE zmbXT2x@uYdKaolXqn*8jqZ8d!r_H&wi>q53b-$(G|D=x@J7m(pn7CmHF~fPVkYxC% zaj~NZ#>8s_2o{ruDg&`;Yz!PVe0c0Y8a?r1;HbC>qiL8TPQ)h+8yQ1l?2jEbFm{p> zA(R1)Zas-YL@b6m6pC!{upwhcYuS(~Ni73!FpU=sz`^*yzUn|F9X4 zr#NERNZuPcYV?Sv-2{|CJT)d}5La$=%s4G_DZ901HtfmRQDd6o zIVEBd>MImKWzt!whokR}jh&=T5{T<8QRfj|oEKKjVW~AwZ5Dyn z43_#S4QOG<3(Nil>|5%?h86*tTDS?qQm3Y>T11v=a`BsLI%&ih%y|PaM3rV5HFz+p zEL3SzoiTeO(b$&a0?Xdnt;SWF6|^-ssm`*TW(vJr+OOJM%iG$JhuV<$WVv;|p*&An z%iGzI%QnhC*hczcY)=7MU#~c}x0XL+Bc16iw{C}*ZP*vuC}*CHbY8bn-z7HE?_=Y5 z#n_OS+DK=I4SBhZa-Osy|Ja87D;x5EvE2H&-?UNwOE%;+Hqx)RA^*jO+_kLbe%{4~ z{9zmNCv3>a+K{K%kk7CopJhY7%!a(whJ3#b`3W2H&uqxQw;`{!A^+8e+~YvY?H_7G z{*Vp%6E@@%ZOAii$n$K-i*3kv*^s|$Lw=g&*73(|Lw?gnI=}L`uui8H#}jM$LAJLZ zcWZ6Pf3=bCNE`O8%UeELq zJ*s`-Ru$vezLfd0?W%kxJCyBG`RH;LD-Wrd#pSQu&wBQgSzpQiSru%5R7LT&+W)lj zSR-A(qOE?5Y9GhtQl*yP=+8O5&lp)%eNg4=*{_l@n#-5P`bxI9E??>YOXbV@w0XI- zl4s@6MQVKgl`eW)E_drL16i(%w|w1Py*~cH;CQ-hOn?7M{AFT&+NBufqRoJ5_#;{B z>ql`-To*U+PKq18fs~AI@YRc(qCwmexA8r{yW%HY@#u)Jd;MGdj8E173eVrf@AL(J zN#f?BV;`VvX1=9+#q}7-@hsP#Pq~Dw@Gk ziP(a_R4_yuDh-pKke-x=OCzL_(kLlTdP*8C#Y+j&7-_6DP8u&wkS0n`OV3EpO3z7? zq(mu6nk*$tDN?F5MVcz5N$Jw_(hJfwX}XjlWlCAni&D0fBjrjnq?e?ZrJ2$z(yLsW z|GxJ4IyQQoov;@UxCh~ccM+WNPOl3ee|NllpT)A^*#Q7+S_%-ZrW8N(0?0${%lSD_pwHe6P6g!PwKCnYr8=fc#7cY<^bN5Zv3;#rhZw&>l!}dF z6C(W^D~{_mm~*NoPxsAg_Gy&X(Q) ze|nwLmfi?G6~UI?4oZ66tR+3&hnA4P4fqst-y#wS9vfB1!t8Mg532mfzl=1h8fO{!MK|dMEjh{fqo*Y>~bd^w#w! ze>#UJY88OLc>>g@4_4VI4`=8<0@~8IhW@kr=$&P}XMP`jYv{kWp{Me@ApIY#^z^#+ zSrF-6p?8;>myh({fhaz?K|ct3{Qtv7ZPW((p-|eYpF8x!@1ysCKF)@o()WZu!G<1U z(H8pg_tVSxJ8}2XdqJOgAH6s9DK_*pJ{^1DhqspEpGTDK_=03b5d60QZM9!8^tQ$a z`THRK3LE}Zz7Ei9TVbc>@s;$R(V7qq^^Axc<8h@0&2lV$H zAJE$xA9Q@%p?um_X*GX1LD62PmqqjbLHW0Z-q!fh(zS);PqC7Y?-c|~_fX6gb0rZy zpp7tGYILTdFmWPt zY*B$~y-fF1y?k56vODbmgNlOFk=<4M`fpjTCL>HNkN!!ON8eRZ|9r~8!Gpzrd~Qp3 zg-v=| zlChpqu)RB@%viT{maD^$$7p{5_j_KA$q=eWL%TDha^*#4%9GTUo< zYmBQ`?Gi7l7{&%s+)t~x|CVXIRsXe4??3S}8x(${=2ym8$ym+!pVG0VZ@T`B{y!KG z8jhp~u(1UP#KlL(&;!$vy}C!qqxtFONH!Dkxk=f%gOYNS!~=BYI!A;JO`X|Q1jh^- zH6V3rdIqI6NO{6rx#--&wdUL&^jNcm1rEiR@A)}Tb(Ld@FI7X-ew#H^#j0@}7Z6wU z@uf6Pl^4dV7&V@G#^_-xU&iSrj#7DB?NY^ln!Z_l88%4fXS8)uM6pnwU)Krm7h060 z3%*w4!E(k8j62S#@(Sin%)iHc9P=MBAI-d0UJa|Q#z#H3qs;9Q#i-d^V=3ELGg|94 z-o$$DA7k;fEFO=g$DOGsD7Pli2hwwLvtJRTvQtvC@m#)$pFz*QPsbCpV$85X1Cnx5 z#dz$H*NCL7QB$Vmq~?mjg9f~ko0=nrFhV&na|T>q;ygxX=B6j7ior9cO;dXB;H2s4 z(_T?_$EBuEP0QtHS7S1!;*EmzoWbccQ&Zy7bCc7=m<*I;T6#umTxL!>JB&6XrfHdWC+1%{R7gEQir{q$3=viB|06d3{6~mJ{jLJ<*%_bAnL1`2HzD^mRn=*79 zMs&*9abg69Zfa8QjO``DboTo49D%;2@)*8R;}W^+?ccUx?`*@q(uTdK4g2?O*mq=m>I?eg1-8ZZ?_$HA zj#W#?tD6mbTm7Mz4SQSt;V~QbvW@b@>g@IH9|rrDj@MH>}{QY-(Y)c3w`^8ZLxiRvSCmDEw$%w zHtcQ1pVr^1@yEJ6w&IVM&R(DYG#lmd*V*gqn`Og3%!WP1SbctAm92-)ULT)bpr!oi zx{W>#Jz~S2#yi>5xxGG}AvWwEVS7rSe6%gzhW&ULXz91sjDaaO>}RsQ^_YC#hCSWA zru41tvuxN`vOW3ex7Tdgn_xt?)UL0Cv~7+J`_(Ye?Ej(}1DERT^<|}ZN%Xwt@&?<} zTtwG?^jk~)VUy0D+PP}%{m)BwS=ncexxf7(EBiP;|IwFAzyH3Ked&L&*ZclA`{^0U znbUC+kee!}yn?f*^kjK*dajK1@6_D1962{THC0JAlUDmPCeypZlT%Y{+s?>%AtUqU z44G2J3Y!+8GTygK%S;jJ8Oj@sGG3`m$$VMPNq-e*1IRu*J2g31PD@R~xqzIUmWt<~ zGVm&}OfM+IJqc$ln(O3gnaMB6x%8lwCd$DA7sjfFi;WWJW@gIMlQLf6n#h^iNG~Th zDI*zQlX+$O$GJfuccGtDys>(LTvwI~4p9VEUT+#&1EpHr6-ZF0F4|wV}T8yS30^f83_} z#*x@B1^H~QZ_L?R-?#=;u%*7y33wDT_igo!Gm+N2pn2eJ^<7%$d4TwHs!D98aZNFo zuDw$%rLj(9m&P~68=8md{td+winkOe?(+tiq9-3pm+U%&9tZsmL~5^gV65FaHz}|HTC2QGqeQ81T;$AC2qYKq}jK z;!&XlU;y}Mh?j*J4Wzc1NIWL4vA{g=mBc5i{?rbXe;()G0lbpGkD5Q#Tge{{O8F;& zSMpC({i$7*{813fzXy0F|0p$oYHKBbG(P434tOp9L`od_(t(Qu5YjPC0MbjfqoGH0 zD)KBwB&$@a5)cQyGGD?z5j^?Jgs5~WA$Vm2nrH_YO$dE8fc&YSkeudJLR4GP7Xsp; zf0%g4X$~dqM+pBaz*ErE@gjK|V;CXyWz0jR=nEK!5<*`Op!})*$UlM63pfV+1t8@g z&T@)7WY?Pz{vQD-e`;Tnr!WQ)LcfD~E&bWd4`TflAmtBN<>whjKSKDg0wh4Myb%r~ zWu68;!uqp7IzGzZxPg2c$$=59Kf*kXIg&4898QSz?*S-(>c6BP%}8UJ>c1IC_3y%R zdd80IdJ@9_Jpk2TS^q#jndHDgLg=?JPyL(Z`HTYyp}z>A{PADWPh|8Zgnl`I>OYX> zv?ii-9wLPPYXH^1E%A^)&)AI+`U>W?{<(npCs=2Lm2B0buu{=H}i z{7Z~|36cJ10II(dyP#L@5CKD2zlRXK*1zX6KbZB`fRsOyQtX~%^e2RHEr9Bu%yQ-Z zT%`9H>wf@J{X4QggRwj7-)5d-ER|yk<48iJ|0_U0{-0t!jVC((vw-^X|03&q5W@dm z0F_^BUy4hVPXHnGo0zBYLh?Mu7((dJ1IS-%p9!p|_(%F8fPVbH!utNK{}QMl|LLsn z%KCEVk(84Ee8ypf5H;|sVe}?B%1cj5>&O2L*7qTV|0e+b_)lehFza_Qul27v z%*V3+DvwgAP z{zjH-afZed9sj=r_2WN>?UeC=@_hhaKmN6T+J)?(-^TV@`m>lH$ofk_${+ugazD+e z^k?{&fY*=z*I55BA@tt>^yB{p)+_NE`oqj?@o6FRPZC0Z7eM)I$7dYtDV|m;2c`M= zf0^|U62ku!KtKMcvObjc`d<)@v@cQxpH`YH+2>rhR z`thI1`UhBlf_W`IEoFWb>wgF8$A28_-GP5*{(lE{RDNyzC$hgxi1KY@o`CwLi7}cG zdNY9hwedfm8YkN-51Lmx&6{Q>47Qsf1ULkXe3384J7 z@t?qYFW{e<|38MEe*CAfe-I(k-^sj|{%qz4vAz~a`D^8ShV_1|e*>r=|F5(D5!QbP z)Q|sZtdC&*QRZD37cmZJ{l9^fzcxNcv)&W7Ox&jrjs!TLKu%3mA*V_Dx0 zSg9P8=Hve**7qeu`925e$Nv=8hp>Jx^IHF&%lu&0Uk6hDNJ^>ybBz9k5UvC0$Nyhh z{}}843Dl4O4AysN{c+~q7?&`PWc_bI{rG>1^&Y@KGyne`c2s_?eUsQffDq;1%)G>y z#~4Eh{RIH|Ywa_E^&MDW4AhVRS6JVl^~WQ2yHZ z9K(8VlH>UQr}_U=*y+cAD*Fc$BK_UWYyE2u^RcY|5lH!KCa+* zAnPv!DS!M|8sTZij)d@E3DA%K*I55B>%Rr+$Nvkg4`=d=1qGLxyV}yv>iipN65!H=|`Y;jIg@|GT z5w$%L%|S%e7nS}9q)p39%Y)LU^e7FoqgX`oAOO?@6az{E<$>M-Ns@Zqgs#0vNQAD@ zNGKRxYmty4UBi*Eppaxx6et>$DE{<@II^4F%U%KI2n`!ng!Yn`a9?Xh+>+4v-*75 z|K^ir`cI$zfB5;bW*;xpS54Ws!<#MijHMGgiW54C6FP|#I*Ah=ta3s}=>VOFofF6f zL@VFs+n@1o3;(w8Z`-23vv5IYaWNP`b|4239bt8|!zgis-VJ&;=-r@qYo>37a#8v1 zlyYi*8ror`v}HY&!+N7PM_a1DW``09SLE-C{9Td1EAn?m{;mdPR!84-5pAGv1AQCl z+d$t2`Zi5^cj1ZrJ?-p3P9PfPmJKc4q$g=s@)U~_do*sNfo1%iLUpu3$eU@GdjF=7 zv3jq{pT%*DhRr>;%leq@_TT@051Wg6PEX^lQ9huiQ_6Pqg*xR4HvWKX+`z#tJq~M~ zj7a-My&qf8IE`^8u8JqTIE&F_OBhT_PN8! z1^vqf{mTXY%LU`i#m)=lBfRYVKr;4&fMK8r>_-86gZc?4yGKCLph2Lapy80mff7LD zVfzeZiJ%nhrzr)&Hz=D5MDq)sZzk~fHLd$+lOgZaf1}oGJQ^YzvM6q#(t57%*_P{F z^_41*W-P2x`ND5owztj~Wp4UzX0v`eSUIb+HgDpcepmZv7NZxV%-Ce8?QnUjKj(63 zsOhaRjQP?}+5R&X-5C=Zt=#@JTN-w=@z2ost~VQHkO}r--Ts`CN(Bk*BN9K{oupv5}T+WnVw$&*f=q!LHsakEn4s8)weE**N|$D*F5l z^`8xX&dtWNud7u3+Res$`8OMnyn3@SY8LX&Lz{srVLKia1)Y|L(<{({3JY#F`Vc`+ z{#A2tHr6A}diW=TD6Nl>C(-V0D$NE?0Tpez**I+T&BpDUZZ;NgM?V4f+i|n8E$Dsl zB-;o&vgT%EHmCf`3SAOZu#<3f2HhvHOel!9$MCt4QNGI0aY+MdX2R#5fx)uof7G&>9q7q zoz!%z80#6`|Ci}2*D_InL{3jImPV=hRWjbMjQ7)N>C68|={NolH!S%0`>*V%e&5yI z!?UfIcf0mJ9eg|bb@J~l2LyIe4gP~({btYoT7a)7^Y^c{Guy-_{{Fs+ju(`ERqddn zi7`>*AL0Jy$QYnvR%aDuwu@%0w8}Rtj_o2~cs&=OCDi(UE7&9|HXL!=&)M~GWe26^q)*Mj z+YowId#xe|=j{XWf2bIU_X*UOGU%lU^{ofm!;1o`+3|SYqlw88NRrnYv3N`?1#gVR zF9;FSk(gVO2IE_$s4jDDd3_DOubUU`3s_wjlMKJX4E z0cClCv?4YqnUd$1C)9UKn%;WAjw;b!I~kTkFR)N9VptBp_kum$+a}D6ZT3FOlX2q7 zxS^o&pb7Nlp`@%VOI5jUXqg;*k%(V)i9=f|izhk;>YlzG6qT+e6yDMn3foluCQfaD z=4_OjI2kMI9x88XBK@l)7U`dQt!C_4F?K8t58e;a-WD1s#zo=(c+dnft_S{Ow+D6s z_*MIj3hX(aJCjwfwy?_@)%CxLAe#H0*rXZyNo|G{>CUdtM#*IbYg7H=*ifb(bBWjy{7jktra@n2TQzC{(BTn=hysqDxyxP zaW?Bq6?JaPuIV_(W5!ZO%`Phk56vRl-EZ@OQs(@${41OI=ANcITpr6G=26f4nwvFo zGqu0BVI#fjyJ~t-_f)LDrDEc36=lvZj~!lsz@2pbz{2fM)$4g-ft4>?D_I`r+h>EqL$eRT4U=bz5b%(?z*#orp|ZCN^d#hLZfHs{p~vmI8+AD*6!{de_e0&6ix9ZIoQcaBkb(iaI)VyGl z>>6rsOr0g(H>4S|3^VzN{>-zqpilZ*$ou->$1aZ_YMJ`2**RfyOb$ zzZu^#erc?>+imx@-A8s`CmD^;8qlCj4!JR-My1+G|n?FG457- zn@i0_^w*?(@u6{zaWi);C(iUTbw%Sr;}NRy5w$CtBqvloPjWVX%vG11l{C!kbR^Br zc-45Ohv!9@vx~YfB=7l@p6SebmsF#Dp8X>G5=$d_)n2Hpzl~^R zym9SzQeL2g{rbxdH5f|9}3UF+^=A1Yz(?&nZn`!Ms=KX}l6(2xpK=Tifeu}-nQx_`B5D9m(R%*ES7%8L z4g(#Ybjaccd_UFT@RUPp3tgkyQb+qMx`MQcEfTQ~TOHnXIO#aS@eRkVj&C}C<>crT zMYNjUDn}U!dE#S-{am?PH7rS9$@UJPI(+F+?QqR;lzMP{)&8#< z`1|QPULQJI4!0ftO-JjPI)LVhPaNGHeH>-SaK~Pbk2@lu(aht2f)A6AC8~eGQN2VGB8;CS5eBTHv}&@z`DOE)_H!|{^ioy%7+mad}*2TW}q%pK}(*Iufv zxoF8DWtzds)yc;q=!l?qgT0@hZgh%p8tN3U1p9o+)2W|RG`CYbZWJ$ztDhxy24~ng zr8(s|&2w69(RaGYp`^hg+cY&#dctY3zH@A$X0}*-m}zj@@AM|mEk5-%7?_3iw`#8; zpc+>=eZh3hKIGKw+Wym5i#JQLA zqs}il=Qx)+zvKLQ>(JJ{TgSAX*!qQcZ{56OZb&utnwMmBj&&aH{G2+u-M)SuON3(Q z1hW=7m*2QtYu19=RUWhc$#%|vah~nG*m<)$VlQzxl>%viI2vmED4{vnwA zTvA-7Yn?Wb6ARLHzOYP#%RHANOY25s*5zsN3irmeJ2x(y8}3}cX1wpzqmBIws!608tnR<>mk=~T&rChTz_|qavSTG?6%GAEw|6#u?&U> zo-j#0&sg~GJj;CU>dpCH=N=o8Y;=uu?d_VN_Se%?dDll=W2o{c)XL|HQ?A3=?MBmh zb4W3|PI1k0UDGrPI5jQhPrI623tWpij&`?{<02lW9&T3?Ui_WLB&;QE&9 zr&Ky!@BhYrKFy~J=UZ3m z8g5(E9i|)H`no--boV@|n_IL+b>7nVyJFSe6dWJUG`hXu_LAFQEv6EO@$R>iW*Ogb zo9|Zaw!SH7lw8z0kZ~8s)de{Qw>@qL)i9jSBW9&~${>Zgz0d6u@$;41+qaSoZfD&t zSTf7KsJ6bYsa|?wu6Ux2LmSUFUEB0&GqBAl-P$+?;WpXOrehnK4(~~=Z}--@J6);K z1>Prhy}27V^7BtF5>K|tY4evh^V~h%W88HiwkONmP^6w}m0Sx_OBEdwo4la#mXh zy7jge+-sBV-2L3UxJS76R=fKZEj;(-v#m;fK<;ZpG8Jq~yrM-=#Qxasc6B!fpAk9O)z*8lqXi)gep z$#x#09^E}2^cbx+#iLqNJWPGW<8coq{=K90k$c<;AJMnY! z-lY>5&#s<5wICkN^&C*6EAt>-sUkU{=`@kjqGs(3lX30H#bTuAT+aobMV?=KUiZA$ z*4Wm&Z9v<|why%(&^7@F;S)6yN&}PaJlA?|_T1z7q1xy}v__AmM)$1nJW2!e@68(h z34No-Dnn-mn?^y3M-sil3Z`UU_Pa56! zbv|A{^ThL2+a;Xlt;vSAYumnOZfK}UF|^&*_JE~3U*YJeJGs7!c>pVjk;!&#&$Rua z?T=oA)Q0<_=EiNDD_&I3O{5Lfd~I*Fy+_UWo*LKYim$y~y}Z3-uQ0FPUXSo(q`O#l zme==R>Sm3vxswZqr4&&!!r@)_d*3m82iJm3~pyQ{qdngKXT8X6N<3SC!Y--hq~*GG@9dASBb^ z^}W}{rdjS(L&hAb)a#blFWwH`Zr;9J%kM3b>pa);2VE`y#kH%}Ej~G>MX{uW0u9`x23g|QJ!&w_q#ktF0xF&4>a}d#7u*CjrToe zy3LcWdSmggUQoTJoIuUZF}8DP7tk(@LP)+i+s>n12R>%Mb1UCdgGr`xSw_?48rnVF zZm^|Lf2A{>S>jB)_;ydXo5J-T-ZYQ3ZcC>f1R4GfXch*z0#8d6NweQvbajkqG=$w0S#aSO0 zqK!>4wBOVIaMLQ%9WlB6@%A5R0d73cDHGdQX>-am`Xx$S(|XYFN~X!Uu{Oid{#PIS z%WCQG{z_|src1q^y6E?uuC6^5>%5<`efrd@{XZqokmobt)}8vAhT6Jpli_guLJ{vX z)z`!KLEpo^|MdO2V?xLDjx##W>$r5VgU<|~FMMux7}4S74*!g5+O8+~^A z9Pl~n^N!EQ2g=IIqD;Xq>9 zOX&$t*TDLuo~=6AcW~|C-Jw&5;0}=;`gC}-LoC})X4|n`hA~`*WG=%~T!wL6hG)49 z&u|%@?q%0uT!%>=rgq3=i|5#45?f5Z(qr`6{kI((;m%f$8*{* zaN5r&8GPIOMo>4+lP3Dgy1|%oy}p)1Rduqx??B(lzAyL|`|hM3oG&H%j`W?Vv!248 z>o=`uKX>J)qd`oGb`bb-UKcgED23(cPHTa(J{ZJbK zi97%%`+lJ-LRzZ9_kwSoE?|tXT-BPAX5Z1FV_?Uqjt_Snnq=tc(y_f|m=3X&Fzmt= z-HNrVWyN}4FF%G01lnoqwRA(ri5(L!U&j)1^F3Z=r0PaeuewXOo1b+@a2(0GU3Ad!t~p>bW5p80Ttg;G48Hrjesw%b7o9S6ZQ2`2pZ5FSatQn1NHzLh@Vn|)f2o$1M{nP% zooSM0-~K7nByDe~!F+~$dG|2kqcHn&jGf#%`F0A`l{`d$F|xHf8|1!h=+wJYbj`J< z>u4|3ajBEWED>WmrFVL*)2vP(_{aK>^Z&sA8~^j2y*vANUeb9*=YJ^ET%P#8Qw~@8 zXTG{HE!o&z`dD>`JIR(IM!hwKxz`{#>)blTIYf{)2doWL(l>#i;-#!ja? z)%ZV*byue|o&L%5bQZ6>ym;L;SNzcF7k{IFYyUw1ZvMU4>RV1WJK5mx;qRlC;=87_ z>(xZ0e`rgGGo1aeO^daQib=G@+_WQr?Kihw) z|4M)D2GzW9N09_jEqk z{Mw6~+6iaeZZOwgzLIO`e6sT=ma6QtKEp3l+AUv7>wLL$9WSzGay#daEf8bn*0Pt} zS$;$wD36k#mXoyw&Zm~+@z+#?94tp!a`Dui0gY4#Pq}Us_SM~n8_Ip*B|d(ykDDvT z$*;+?+S4p8`AsItO$KctES-=Scjw0LP}p7g?^XFVHWX9>pqhy)NN? zobb#E3&n(hrvh>V76u#-xEOFP;J3iAz}|t61P)3v1dIzvQ|3?c&wxaB_)T{WZL(6~ zfWHLfQ-x1y6@Dqj5U?y@E0-xxni;T;of}d0fIR_+w5l)Rs^7-l*nsx}s&rR7!teZX zLcPZ=)Ii58PdXTIhcEx#O*aPG2f7F9ZhFRA4z;5`?2gtoLVqsSD|}$@-N`WoJ{kDp z`P!+5!1%!DEJ-|H`-eMC)2`LtzI`p#5cqoFJd5F!KN_Y@ED#d|_XU0sc&m$Bm#4by z?Q*os`$>ktiolbWAm3MAPQQ|D2>dMYpA@?Cq`w4mgu2^E9V@UV@G7Mo#LdnpLW5cAoPgLt9*I% zP||vl6yzJSI@B(7Q0VN?_rmPL28I1K>_peWUBBx#zuWb2j~BlM9|2f z(LrN_CI&qhG&yKW(DOkVQKr!6dYD3!dYVEf_cDbh_cn#5^f86H_cev4K4=P^($5q+ zwZADOvB%tyjzRfBbAuKHEeR?LDv2_Mr1mg{OzCL~Nrqi3*g5q#g*x_J5aJ(H9&|Y9 zSkQ@}cY{6%`XuO7(3e5qM45sTdzgZdPZ076LOwyrCn&YADQL=rrl6_)OhIY=O+o3s z7KFM4H3Z!a`Z?(LU_-D&uye3muxD^Pl=CH&^JSECCd&B=%K0kF`5MakI`aPu^8YLH z|6A_`p{~I_gZl%c^5Db4$AV7;zZ?8P@F&5ig1-z#{X>`cFa;FBe{(NW!1CUvfEDn61O98^zZU-M z;J^OC1)(0n4Z(MVe-8dV#1P^T;vC`@;u%8q-+=r};lC02Z$kcC;J+3A+u*+){yX5m zv)_VH&yb!WeM24!c`Rf=$l#DCLPmy+4x#$*hW}pp?}vXm{13wa5d4q8{}}w=g8$q7 z7lgJA$qsobVF*mC*Z#t{=49R82(4$zY6{p@P8BjdwMPi zHH4IhREJy)xe{_Mq(0yWb{KOn_@NbvwtG$O?~ zq&ONWW+25Z$h{$N2YGwQeIV}uxi50+h@AY8Qy_YZU8rBE92yiF78(&671}$rU+5#D z(MY!o{Da^h4F3@LhxRdr*u%do{JX(F9R3l#7lgQlJ`SQ!#^55rBmn+q1B-mL$8Eh3#|{m9eOYH*DwM982Ar> z|3LT;f`2Uh2g82|{D;DS82q0=Pw@})3zNfw!otEL!lJ@@hxH44B#i3+Bau|EJ;q4E&!>atu2ab~fx>*rl+>u5G&dp0B~3!fWZKR&$k!L6|Sr+)XmI za=1Lh5OzK6?p1Sx`F6U=d2Yk?J3n5*j>B~`R#TVnX#8UhceGnF#=CVt)m+1AT86P} zx30arKHQY{2{qBjF5l78J2Ba=Yh2e?y5@IXM1j86e7m+T!_ak7SKNGP_|Y;AOro72Uyy6bh9GEF^v={oLQ$=G#6*X>=)yB_cQe%CK}jkMn~A<+pgPgig9#D0L* zl02s$ae-itsOUDVTSB+gZqvHWpfde*;re8gv3;_k+r(~@XjiIJe$^@` zz~Fjaipg*q%iS8qG^Xh^BPzwd+lp=*y6x?Du-loY3tiGh^N*IJ^P+Mv?RkZiFD`a_ zr`uBV;V=w3MW8o*l-wppD z{FCrg;a`S-6aIbpzu@f$?@sXchj(Xq%kU0>cObmGz&i-u!M&Zs?}h&wAtLM|oFZHz z+#|dqd?Nhd9RlxAc!$BeE4;hGI~?8-@Q#FccX&V0$2p>J#6uB}MGS}-9PvcN$cWJq zVZ$-VX3~gtrsCTfy78uX99h#LS4-BTNyqBMKrGMHEIXk5~oo z*6?K%?!FK2D0ugPcTaftf_Lu+og>O44o4h|I1%w~#0L?dM4XEFG6M6T zT_1Qq1@FGd`$6R058nOZ{Sdq#hW8`zezc!+M192VhzD$ib0MM2?Ic4ez1w9tQ6x z;Qb`Lhr@dWyhp-&6ug(gdvp)G$i&F?k((orM>$8n6!~i8UnBD)=SD7wToPFnSrWM# z>BJ+Q1f(+t>5N4>9ch&&VdT~E{950KO(B$W)i9N5k1XNbHId9#-xvNrO157XTbVe?T16yKE} z?QfFZ4n`Te8@oG3ndCO;)vkvgbnNceeewgFAE=Ldzeiw?^j?PUf!(9}8M=pckLY1? zc)p*>!KJ@b_W|7pcYmV$$nK-NkL^CO`~O4Nb$~^2b?x=;F1AFI7>$Wh0c$kE(h-ne zL_kDD6f7*TuuHE37MP`pQlwh2p{O9D(iDg$YK$>O6KfKam;_-3B2Ah#=08*J%q;o- z=lSxv%-nnD)^pxd?*@HB!_R=wkQx#i{zimGfH9#FXhLYnpmfk;LL=C4v`&mpq0TMc z3A#GELAr+|Vx452RGmznojQ3ELPHKME1>=~s52AFYw3;Csnn^~snKcBY0|lk{8ySdoKhm9{tF1d%cLCHfhB_ut#}w); zhB{`3V|8tH9d(!KF4tYDyIR*rcZ04!l(U9%Hc-wM%Gp6VduZDM+IEC?mqNSFMq_n1 z>n7`_>SpTh)Xmc^)ZMKMdq86u)N_G)u29bn>Me(Q?oe+9^vMJ2u55%tPDVoAQ@Y>l zK9PuZ8+9+}Uedj)dmRcMgM!IWFcS*yg^!%o6YKu0`td`A^zf=DIvaUtRa~$(UQ!Od?HyS(K95( zx8T)nV?un#gb?3_689Dp;`=7!BrXzniKoO{;w#xG36KO!LM4$BLj02+AqJ)|{>6Y0 zKY-f5Lhaw6_U};pA=Lf@YX50EPO?LiD=CnaNcKq%N{&d5OHN8oL+!tyb_>*g1hreC zb{o`ILG8y-yB%tGK<&=OLP@jabIBDb|FP69YKfZ` z6Izq%&*>9dQ_h(P^~&^)=~WsKnx7gHnv0AGO`Y@S;n!RBwdY~g!yB6GO$hXPFw*;4 z?D|@)9ix&AjB3Pkr1wN`s1uM*OOKS0*m7{8Trpbz9sN)ACHfZnUivcq zbN)zwivCOtPV!lBGK1#f@9;FF_W@Pu+v&UF@8#p~fv>O{s#+Q$){oZTte>U7SHA)v z*dy?9)>!`}2mHdXERq^snjvsQ(iS&Ay>~xs-!u z--IIlcKv@_2EpgNN2-(@)gS0+>3aOEvu#jL{2R@%fA=tpaAMAtaV@Is>v<2380QW_=PflnV zb*aE7G>p)8rNTsN4c9Ol&FXNGVTfUj;Wop=jOBS0r)RYR!{IPnRrB zThs7~k*3kSNBu3WPgHTp@R`wg(hEc>8Dk_MHx{`0hY@eA`bn*-QZm+PGWXD$au=EP z3H6ScwSZKzf{Vez-a%EDsuT1*+vAaulaXgz%itg*Y^)p@Zt0f_jW!x7jH1|`nM&_W z#O=&ftYsEQ35{}$jv0L^MMi~2hgt@E@u&s;;O0F0Kri{#z782Osx<;D0S=1sp}_RT zC}i}F(M>@0&;RX@L`L_Fes5{*P{k73D-w~>BcowzWt7@WjkRy1FEG|I_H9u~k?{w{S}F{T^YD+{0AkjA3Iy4}Y{9XdJVTVSdPZqaaH>FM z>|zY=;S{ER#lY@S{k;iej3bRV89y^wY!Yg6)TG%|^r#n(omO$6&^X!nxbZ!3I}jP~ zG%hgSYh2dW`wU#wTd4`x`iq`$tw%#qgjUO=FtKr+akKGdi{GV--(rg2 zA&cLJhSIc(jQ=ujH}0k1?_=KYeFh$aGD53Uj*R~?k*Hb%MJ8iSCYek(nGfytP!oC$ zsti)Uz9ehWKd%n;QIEcYIee)~B%ZgE4X0`4n>d$)L&WKxA^m zX<`rag?4hglVf@uD>nVmRAyResxs{jK&CTIJv$Z1bgtsV;tv3Cvi0^$81u;YyP(cs2dN)mX~fSX_@*nT zf>?ZdapPhLN@3I+H|W+~Icjoa7-D@|Iv5(XBnd5kxVV!SK_~5uNEJU?+;29jg_=f8 zzBQR2;z$1Z0)I0dvvX#b&Av5zWHH{t*`m;LspTrm6wB?F1=bU-K_Mm`ZDwh<)XdK; z*o-jSYgW#7sJivZ0Of}$SZB71H+vRzM?ZyWFpDrtz|&BTr{PmMGRri}XSYSvAWgTe z@b(}iw_=ont!5{AjjrRUy%<|`KrIr7%x;_gij5>fh75^i8fJawV)Kv9tIW@tUm@A( zKbyQY(Axzh8R8Zw6!3aXPj7Dz|5LBS zxfyxD^StzrOBdfZziHlLK4ks|!Y}H~@2c4uZ&7eXu6(6u-i6m(53l*{{+7oo{M1#B zEZ()SlL{?9w3ubFfL+?t^b#(DCA849FvClD8ZY4@(u9sY6=Dl73qOlcizJKf+%b>k zdVRMGhSt*6+SS<#<@bW=mDB7XPVc4{CbTHEG_kamB8xIh{nk(oi?bF@77v%iEIGO4 zA+y|behfqwUszo4Y=LbN2x>?mcYVE`J%gQasQMw2u^sr~oQq+|qIJnK8M5eH^7i9F zra&;Vc)kQtf2d-JIbU(*FGKy-A;6>qSC26YGL8h10 z94%>Fauw(o0}|#`b%I%_{V^GQJJ+0!%$ZX*2mu^(#Y25jXo<>lJlV0XC9l*wMsX5e z$5izE1tZH3Ea#C#uZ#P71NXD8CzO~yi;I;V-3!Y(CyRGHZ6k%2>ns(PagSO6XLQmB z`Xg>nY~}XE?|m&4#5wpBL!PTKBFp_&C02h}i@`tH@~D-mOlVnUdDe1(XXc0p2!jAhIt*xP1qsi04nag)*U5FGH}+N^CXG zO4Dk-)grQyH{razF$atlUF=HeImZYO_^}Rk~F^S@acI^d+z860+zE&;zHTU#yN;Ra@1O zWQ^9U>QE|E4eWd;w7Oz-!|D$AUYC0RZd>orqb^##D(!4*mm#ZmtA4K30@hc8ZP*MV zZUHUC5P}o2$a=E%bjE~8uzd4x9QK(OFSItbwzFQ&E$1d~Ie!8+Z|!9rtBOn2)VAJW zEvLQ(RCUfTy}*J2*~Sps9}cKqz>^;Wb_oKk57;Pd;%pjh?%GQ1ezw2vu+U-M(p5{> zEe%>4v$RM$*1E>}g7r1)8`gKNyR3(87TACohT(4nOQA|>;5nKmR38DMvi{Y&6%(pb zOsGD>N5&wlr;VhuJ#FzKn=v-;*-W*W$u_2>X7L@mtx+6lA8sh2^>>WW#@xon z##hxF1VTIbzM< zwUmN(n|wwKKbF+i+mzWHC$;r=u#3Rhq5d!ec?BYy&uqRUX{CBIuLrj2QJZ1g3AP{E&QTzn*R~=643P9dOW5<6cHkWTleZK9>g{S9 z7$jq5pB-ggJcs|1i)}4zx7cRdS=yCKMYfK%9=5)={@ki0u@kwUp2BIc9JUJE7`z<& z@p4S#X5@XDhHbHJrR`-qk=;9XbN)x{+UEht_KfZMCxDkiiFuP)9_}`@e$IDeVJ^87a8V(||OC*YI^ad(}{@Tx92A7iX7d zmm@`X-gZG0pTa_vegaA6dKgJc{{!`x3M^qQQ!6z#64{m6-D#Bz?M~WVvir6r0@>Br zH34QM<=S!dKVwLKM?DzZtD=9rMLM))DUjVmdpp%ofY|Pd{RI2z_H*qGp=VF+1?nH) zr1s4z>M!NEXG_&ejTut=^JCbl_RH)~cFEG`d~fe;MtKU5_cr^fvYXx5AObPma5~ zrI~_H9oik|IqExFI<9k!l?okt9mhJpOQt(P4$mFlP}4Sv!Y0(u$#i~#;j1yo@dL*h zv@Yr`Ol#M7vNVE3T)2O4kr9YwKRqG-PJKGm1cW09l3qk``D3YM2VqQyew znC!TNtMVRI1K*ELr{Fxrz4jIl$G z!;Y`6EGGn0R}zA^?S)RGowS_h+KHUrb(-w-q0@9dLh!CWA$ZS#5KJ;81n-kIQ*JmA zf_EImP9{#~PS#EiPRrZ~!G}M15CZX!s|bPUt{owmwhB3|a9U+c2tHUt2!xKvX@ir$ zBO!PTzWVWX_`m7jK+&-`;L*4ru0YQw-+_lSJjG5qPWeuyPKTY2ITM13?n=P~r`=Ez z-GgRE-G}x*dH}thavw_1{0Ux+?*r;bYN`Y$oi4>9r)y5%xAepk&w;LW1`)##Vvy4> zOFxAW5R77-+Lw+cVM?mxEvJ5`H#}L}pF>49RGX=ix0g;{s>Lf3z!kCW>jf6x+1rEn zehU6^9SS{Z$A5iIk_XUR9qJ!?sp=#{-j4#|R1Jbw3XH#dhGNjtq@~$iNoXmtG!xW+ zg!YdlF8BdRWNQ*3IQAk&wDi!@6H8AoJ@+LQ+BAIoYe>684BsJ*>oQ{a9+`!Q7``7^ zCwex7_cb(Td z?{zMBKI1&FOmCUVGB55l2C`i1M4;Gty7OG;Po2%2mtmpLm@+)i<;!Dlz8Il1y`-)) zy&NobmO95c6DkPK6JK;zV43S;yDCPhsp-5KbVh`xRy=afbl!!T;|a_h=W_VUkHc4& z!-US~oi91FN)TN@TH?FT-#Gt{#XJM&yI7zzz@NOU*6}I`(-%7bvrJ>zdw6{A05RF$ zAeTtdvT4gcQB$|LGU^uB9*B$_8`$3tWvrGh#h<94=r^ORu7KPweLbonP-kG*c?yJx zGW>MyH4(5$K`3icW93Ub-t z5=eq-%_*eY9!KdWusWi#_{4k@Aacof+2c~?a)CyK6B!5o8Sj!f(52GlG>HT6Qalg` znogoK%)A>Ya=GC;-F2R;k5uIHlgnQ&?XCiLJ0GDzm==IAmmZgAc%L1?`%EhgxoWsh z#EYNB-zl$lv|)YHx(=z(RpM&qYQwgClx|rYT6SIP>VaE6id)tOeT=KrHH5*ZGscrV z8`5vREgR#S?%M2n+4X^It80(jG&idNH`?7+bp?NSvZXs^5c!nzQ49%kyC*BGTw|uuNZvQMFvwYI>=~Cpj+pW6m z#b76N8#ryOQkda(g4$(dkZquHZjjqKfGC3uD)9#i15$%!2rAv~x&7|e?$+%#M9UDv zlw&_FI?kpV7(?xFV)z%vIFrE<8Gmk)z8oBcFhPLX65+4{EuXzy7qXZLo-JPp*lpGT zN&ZPiAE7;&AFI9c37FMDn3z)(hL(FT_viEj6Y(bB6ONWgFHd63K<{!W!oKGbC0Wf$ zj~utWeEHes&C9=9{-gT`?jO6)b1!vofB+mYuTUs=LYwLd{p)?M?+UK(-*y2mN*Byt z{>Spp zt_dGuHc)s$(m2*~F ztc><-Sv75ya@CO6RiOFWix07CXcEruU*l?5P=jUIs{*}g}M zE}4SAJ(4_>9y>gWJq~zOGJ^gkhAe)_x!ql-kLipnJh!{6jN9EcmH@5_6nT8*@q@=b zk3U#-D%xE?Vih(qrYil|kG@1angTbXKdslyf+^pb)LxvNF^2vL_hwu;=4U zfU|i5)0LGgYgb-a`C#Q=o*JGrJzYH`JU4r0c%JY))P%}uqM<6kKACPFzw>_s|65WGI zbc7sv&hfO8BF}}M#;xGVNy|m@p7xg=z43%(K50RCqynQtATc*ofjn1w2DYhsVFCL( zI$PBgj2;THRrC{gh3La z-4iZemAmTXs)kkHth&ntX-!(SZ`Bdze0;zhhRIwnEZWF~7n<*{`kZa%jULBN9H0{q zR&|pZ4MBO!cfa)=d@-Pco{J+iyo6p8ygu}D@RE7OarHjxUqdYiul#7>}*BY*+IefZzoIJ=})8EjUGBr`8&@0_5$E$?NhVvm-w|GKuek$_y zI_y>1+SN-Y21BJ-(oRL|yc)eOeOJM=`3ycOOt7@-#MC8dJ@{gg?Z@-QBGmwQ*^Z6T$y z$Ki>H5PDzn{@xq({|pwrPS2DR$GNU2BJb8UpSE_jgr^I%y!*ZXSu=IbY>rm13q)&# zYsQdrC|Iu`9{0$acW8UZvm?A6GKzVo)j2Q-8njMQ{UUrRPeX-k?AEMaBMm@noY$`iD>15hkOUs1J`2hb1g%M5^V6D^HGi)eUb}v6xNp2~s_%jITI)ZNiq_<< zDOppt<`g}I4IC}n&;eS34pk?}YhwpN2w8J(%@=FF!*qB#Pi|cfaw~rB!tK;CnDE~R z28(5pnKI#;H)~zju9l0|j#)c%?V`0yK%KUB;@T-ReYe4SuS~u?^ybb8k^io`$bXL& zIaILyz#3;Al=@1rR<>55AYKW>h*u&-)~iu#m1|F~ZCLxAkG+qV&w8Jb$6$(%Kx?zt z7UP~qM4`2%Ymd-}IhCQJyJ1eiJPg2F^S!Pv(73JreC^doy@|w}vVK)-95JW5rzK3h z_LsH)`n=<#<)incB`8(=>)J{o1VxSBf9{jK&Wh_6$WR#ee!t z#Si}MlPSfmKJ)S4t%CzCZ3?AW^VoNk?<`+kUo&4{-vHkTym~TrOFzLZKG5gne_4DUy<0+6 zqye=fme5)cY~1Ib&qK_{pI|l~+95?g-9FDb4lctS984j;qkTX857VB_GVKiBQJBmz zZKEjUYwhbquTml~ZQtd-t0<7vdJp6ZU>>>mlk{6#Fcgy~F!b&7 zeX&lsPHWx#bvEnPtxI0FbKSvpmFvD;cYEFMc#=7d*WY-O1J+IW?dx6=mRRwy8iWs8SDn%Lt8F~=t=${ zNVI;>`m*(B)_;MQ=`5cBy(&^CK(C6`2+*q%Sfus$*0cM64_>4XI4FlA&JPKfE5dFo^-}%HJZP43b&Vu&0fyhG$&CCGN2GhC>@pZfMwWX~Uh3rW~Fy z;D)f08$w-gH)L{9bLaAi5pMW(dUFi{jA zgu?_bd9j4xPk_iTI>XUM&5gS1br0dX;O$B4NG8d}8{IbE@q5>AfuBSw+UUJex-oHM z0lUI`1JTCdjW9KsrNmHpW-2Vz#*~d&_&n{!OEtAKLbUO~#^W37H(te?z>L2M-u$4x z3Eupuwh7+ck_k8dy0Orx+dPn+joY;rbR{60hH;WWP zKU+UHzct*#Eaw*HOgQq};HTh*9iR$J72olT@yo>gNZ)T8Gn=pU@wDFI>y$jZdSRNw zkY9yg6V~QZ{fAxm#lT>1R5~j5yY6?#?-#%4%zHq}yD2@$WsE>lQHfu>UpMve3b(Vt zv`yw+RiYzOAudXwqv1&UzVu^SMKwc4dHzPKWVabhqP3BL|P?1w1R&`yX)&oi5>VPB0lfk+ z33Slh4?J3FO_3wt zz49LeMQM-^U5lm5CIEnDoPvXCa_~kLi~Q&NOTdk(FOEP`#x+D0FY>qbck|EmFW@F+ zMQ0fDU*#X(1*-5k}M{!4Yy7xwkw(QK2}i_)Kv%WKzfn(zpFP0wxB07+?~x zBH&O!RlwDNI|01`uLF$(L4^132^jU?ME57vtQ=riX3%tVn+yeL2I$j{1-wL@^`tnm z7>;j%Wq=btzRmdfE|!Y|d;$Ujq62o})4NFR^ukRG0SN(_YTkcu%CXiuQvEC+>l|d~ zVga5brR2weMxOYxvkO1~cTU~N*n@yy10cCH4Q91?AX%%YeW>d(+%W*2Z+d|-C=dm{ zHzEP>vc6uhMh8v{oKFfW;6X~cU|%Fxiv8;{UY73$TY`jv&Vk2e0!mMrDXt4#ALt(# z6_^y56}Yz+;$iCaQJ_393?gLeg5W=V((3@M_xC(!gCAJKF@zv=n`ReNvPc5$t2 zifo!pQ#MDYBU>VKtA!w*T8L~H*VaRrPc3e_R=wrg5iQs9TdwsN%KT-)vS`xvU>?gg zCz8~LkrWpOAX%C$2itl+A^D}OShkPkmp@~EIVTXwDrI$8r#E9B94%S1>`N@m%wigw zBg+!sll>w4H)vAO^WZVTM!}ZBE-n3W%DFPxW6GyN)+>9)_%z5E>wy##W5b|v%phMG z$~A(tf|dk11SJF=5Bf=pg60Josh<*NXE`zUzI)UThk`4DBD>;Hkati3=cxUvV(=Mc zg`xK1o4@hD9S|bJ#I6Ko1{L#<$gAU>>dvsQjww*ksi2$mnSswV23_O#=T#-s>Jxm7 z66s?EMIQzAsTDoR6z%F9P{EY8;ElW`6a`NRp3C~A{}TKW?}+6N4MK)s_9z7<@DMm*A(WA-O0xJ-8zHd@!V*4c-~N zkHV*{%g`1Qcd{-+)6`#vW0k;iwNh_$q&SA77I%UnqYWGJl-=JMohgR2T=FsUDe{?e z9l2#K?DGbFB%dIE4}#Si0^vVAhz9iy-!NjsH}E%n18L@DHX|@$)=6Y(lyM<`MmG=J&t3rx(J881s@&BvQ;!1cr(f^A&~) zGsOzpeoJxYv6RhcY#)TDfg=-ygHVCyw4qH4I}}k?TKbtb>o8#(gA{R!T?(YwtVqM@ z;yPdUf<32;G8Iqmq1v7{H~<#qo_27Bk&{m8vk)VNlyeBC21i%O;zf#^ieD5e#T#z@ z<2yUKFd_qPD(@@$c~hAK%ns*OM-M~ZranG?6EUjfMPG+1B3-a3WL}7Vh-HWuXGjCy z&MxiSu_(ko#D&%!2C&Mr$7GT<&36?bkyJVxD%8ubcRm-?9PA*p+2D@p*O>XVGd#b zVKHH+!hR3y2p5JshTjT@N$Dc5)FCa}px4*83J`_Hg{Fk&h8Dvc=Ajwr)3_FogR)mf zNHijap$9@wgQ;>`bJw}10e?hJW(>OSOkuEq)eG|wK+&YMRR4x;S-VbdF?I-)p zl+Yz}0K;aYEbC-HmOO7&0srq|YaI+iVPnIlss;v0G{{u5R-mvMVdgzB0MPfLumxcT z_$#}aBF6oAXba^i%q47f%P@YR4`2Zo2Mhyrmh3YvFo|KdHis35mBERML1AfOIk@Cr zreRaS9r#%V_&zi9eIgu%)rQ@cp|HlVuiH9Xf!g3#C*k}sm31I)g88|i2kbJ;Z_pov z^@IVsC3OZ8L^_h;%7G{5{$4ncxy{(<9!57S522m(HEgTY}!=ejd zFzg_V;!ya3@QU8nCrnAbp*CE}JRXHNgf$-o{>&9N8tMraMN~!HjQBkQ z0uv)@A}W4UBJIWm?@PF8;zjJc$fTB*^&DB?w=fVO6K#iK}#$cY%oZ^t-(v>Zjw zh@8(_Fzq=D=C_J5kq(jWkv@^q$jy;EBlks~WTl2IuJ5L_{5A$8g-Cg1H2y*s{=%3M z23Ko!OWybq7cVU4^!|~}kyj(Z^3O;rm+22#b9(>FA;c(yP!#!R3@*EtAY!ZUamMuf(psM4rE zWGJdE>Mqc{ur%$3QKzFWMSbOuqUxhAfK~uvaA#@7!GC1@#1NGKF6u|H1I^MT{{s^c zt)kKFvdAu z@~VpFXv1jdXb<9E?Ej43Feq{|TmQZRp?rO({#V<0%O>4joqMbU}T$D`|`FHi=m zXk~N`$FuD?HeDXQkGEQK&_{7TM=xm+9LZUJ+Z~6ZzmKMTlgPY7(LYB&;#xh3TO}m_ zP!|%7`XqXofoY54QH&^NB4;h(4SYGb;bIoV7{+ke#B-dOYfbc+}JRnJTw*#u5?{51UcZ z1mI6_oP&&Yp@o9bxXGI$HYIIp-1KF_#|aA(cPIHI1t%$!>NZ{JDGc zE2de$jaY!+)ED4)ex#!t%xK)}crl*Q5{-dORFdDH$?d@1`{I~H#n?#%5+BCnT6Ous;4Mw8)pW^?-6KD-k9TX|x zp+bri>{Ak(;=vG-AyO)W>%7vz#Ib48rjK#46+DZo8%cC{O!_b+gn(%R2GG?@nxXpn z+$D;@YNlgirC<+9n`^v>*>g=Fo{tnG>Dr0E8lKl z!g)&>$V8iNY-&#sB)la@o9=9aETCAlOlKF;1CLfIsoeyECd&wuKtROBBT0=XZ(fGM z#Z=V;+O;;wS2D^}u90Ax(46p9!ox(v#2l$O!9HPm!rBDC1TN%>cbTIDeR!w9R!ay@ zVB^1c>KnR}OGMrdD*J@*6YkJoT+6YWwXk)b zz;~V`PDq@dI2TGiO&k&blc)xbrm6#|5WEvz)Jlzu6eU_FMkXdDCPV9q&WS4%eG_Fk z&=Y|)OIaz!;E_T95gcRw;Y6b{9s&09C~!o=OVwLQDJn76ix!?$SWy!oFk zqAk<6EZWK?TBxJVu4eR!(T6j-W&D=+F*~TkXH@?QwL4$5^wRs-A$;5xyR8~qKiIlt ztIO66TO+onZr#20v=nV|-twkP6(ri?wIyK7r7gGA4)SYK*9m39x9ldBNHVk~VM~Tu ziRU8}o^PH}_zZ0++j2&&;LDK(UyOY4s+&s+wB^q&-D=fAPE^Y>@CJ?xm5a$9uDenS zFKnHF&1?HrfvMu(w`y)R#2naS>q5+dEiljhU9I&$I)Ejp*)?8|%;Ka+~osa}rJdMxjX@ zjj@E!o-C*o)7IPkwkfb-o4z(nIm2XIER$+-2B;jirEjZBp7=NpZOh)a9|&O=FHYnm z@ScG!3)UOzv`rm|O&3^fYut8o+k@oMjF~TR+m+saU{j2md~fMBDz{_BsY_ zQ*9$ndaR`{hAmEdVKT-(=CY1Afn+>G1O#DHLH#+T-y&9MCK4!Ifszf9P5Y&g0+XK{ zJPdBo`Zn2x2M^YUr4L_D4oKdToSD2!ijoz{QS@0e;Dm;HjvAVGF?mZ2hkGH+wlhGO zd@#8p`3x%nFt4SoOoEaxCV$PoZlxO!2p1;bPkxk4TfS+JX%xzlQddktZbfROh*I83 zF-vhsaY>19?I5*k6w~^&os91nrhJ^Donl1Arp@aC7X?9e$^zC*JnJ1YTx~v?b%Cxl zht$-LN})o8P>NRy^H={G4i#>YD12x-m60mCJ5*CIAs`gc6Wjy5KC~O9T;N1TQ139<_r-*pz*f zw@)cbJj06am<~{4qJ%hvDe)OhiFM?NI8EGa>1zRRN}`dtj7bow8)ZE^jGqF?#0awyS{OxC25t_T0N1UiECc`qB~AcLK_R1axso8LK31-^_>8>C$>}LS?S z^GQcMQtnY6<;v`!%Q$sJ3YB%r+sa?44t%Dh(o|9Jp6}vyAdfEYJfZ`+{R*M-Y3e(v zA5hg_q>8vN6!NMU(AAfXsGk1uxd*Gu{M(~ZNj%FdU3>tixEr7dYi zyeTaVPZj@>R*`lAvti3LY(alziRbPQo(vNQf|yj8_FGz8x){Gd{zUb7s7s2{deffc zXD7(z|DS&xm!tHl=`$#ApJ*157b-N;jnjS8+tPb8#$?#E1)}sN>8ra`Acrx1hul-F zR3(F$e?g;aC|sPbNY6>%pMEU;XDLdLOixzF(J^Z9`91ZQffz~KM4|Mm^zWd7n)EMv z_!v8ir~DQ1<>Ux{sYq_#Q@Dx#GaY~#+vEJ6c$6_Q!y-0a`@M{58FMpqGmJRit4Z|? zT;XZwqM!SyL3E+Ofed3cuYQF3iZt zD9SjbhW*PqhUG?;gA^GWg5F$=E-E z@|ogyT7Urt=>8}TDl#Xsc?~K7+-GWL!X41Spek{XPsO54qfATuXFbcIdhy^Q<8uY) zG9xo%Gq+`yWFF2umw7q!L1tg(%k5LQui5So(e>w8qkC$r9A&0w=COz*l=eajd5k}h z6O1yCXI9f!>s-W7bGZd2xUv3~d6T!G1z{-j&&&>7rG(B#A^4e{rTslEaWu zUL7m9oM+{hi<{8)nC&Uus&;k;nsNEY1hhSG`+okrOZeUA5xWHu+wW!hWW{7PWZm2` zddIsvR_#d1K9XIZeIxrxjyT6L&oIv-&ns{Jt|hyic6mt0Y=6A{W!9*yF8KY$S%4^OYgSrTPF4ktu9sqT?MR~Qtl})n|K*_? zx_05CYe$maXI;#?hUvWnL+_nr!mRsQe`USk`pjlcQ%Y`TK}-;P;Ip0q7JEu3_=gP0 z?2gM0Mms*(;Vc#In7QMV9dP3|GiUqgdHN9MX@|)UYdlZ;@H~A8XPg0NU_093vm=n5 zw<4gWXh+x%@Uerqa}>iv)UgWDjvYJocP`nPpc;x8y<`85FLwN~qie^|&M7-*NzslY zJ8IO4Vx$_yoY<;BJFe}x4GCy4u{7$344TXz`chK6$SN0&aT!B6+dE$G9H&N09t)ag!Swigw!V^kr>K-|uwi%`hZ&?0`%vJ7qhgIIOXcCOd9DvRuL9 zox67)-g$E8^_@TLY|lp7v$G}H=Gp7A1G6JBV^*;94~A11nM^rbzO&)KUh0MP>O{io z?7YA854<`Mx=r8n5D6->ojp5Wa9-*P?4|yR0%ecMhKsaEMD5LIz0`N`;Od8*OZws{ zlx>p@F`y)c+zKw~+3wk1luLR(?UMe2aY;{PHSn5AaVR@Jdq3%tp1mzQlVK~fW1y*= z>>|3UOvWX>lp@e;LAJV)UBQ#Be7IvckbRjq;RnM|_MPm%AVCUgn+ClsTqOo}3G9>O z9FDS|X20gR%W`~FOCwOu_?#tDVa}wS={d96IWMPYbr#HO&cYl+Jgen+R%i7va@i-5 z8ab8uujTFn!n? zF*>I%=R(f6IZtw4<<8FCi1&u08fbgm-Z9hzi7RsM<$wm5hIOCuOT0Qf0@k&Y$_NF@ z73aRM4&v^N0C6sW|8f`Rs^Py5s;YJF2>f?{MAha0N#mFsH#%3Do0EGo_eSn7xm|f0 zt)%x)CnRvuehWTRm_Ddj7*BXiI7fagT+=egGy z={=fen@OPQCo>q5#r?@gO6`c;mL4$m(oIA~q1^u5*DyO^0);Zb+gnv_WTs$ZAYPa^ zF>gxV%tus!WI99(tJ>g&lFYn7hD>Haeh{oDr*cNYoF2_ko$+4WWad-)d&LsuMaG>dd za9B>i3km;dEKtNU=xMY+m3x3N|D*hX{5mPh*UVo}Mb76h%-7FfLJ#9zPJ>gxsTuNJ z@>kODow@hlQkI-MBwNo9&5t6LW`EEo*bKp7ep-HZ{_gxk`BjXQ2=8K>2VnIF->w;V zNd*+8G$m%-XCmN#W_8q-fuj7c^B?B7=D&n{FY|Bag8)cc9!Gi5)zRBjsKq44byg`D z&gWgE-Of6q+>|Ltc@~Vr49+K5STL<%K>>smtH6Qtw*oqO#(dggq@N9cFOrK2912zx z_!LxfXCs5<`pY6wfnPxg+y5WQ%P)@bIG118xMjng77;8Mw?4x}g+aD%{U_QrzG;mV1w^K%iH6zwnR3 zjv|esnML!9^oo`hg%#x$l@^^YYASkA)LQhU2yFi}1CX+3upPq(zd{H?AcY=&vVfg| zsOYVt_o(d>3=#c3poeV(jjHBsDz*?Zmis=2YYRblH~c%C;v&-`8+?k}@hJ`lxx2`- zXhTr|2Qs8xL4@FQj5M?qs3@i={Xa-UlSLXz9@2RCzwvN`9Qe?SLPcK`U85009MH9* z8%1|0@R3D>kEf(Uh13cQE;2AAiiIJ9W=OhM^iMG&!`(bO`yuk#Gg4UmPO*NmZ7?dH zQaqp9`lFr{&&1avb+bM!lScS0xsW%>qg7GD;uXc-#gGY-ghN%3Pn2=Ac}xY&&6*Q~ ziX)420#R{%G4YtP0)S#vP}SWs04aA#C8^-E!45JdKFPjj#)^x}i?0^nD;ZTX0d7H! zL&ep__4F=$4^tf`6nq(-clvqp4d(d&OZnCmKP>Lxc#bm%L{1h%!besP2&D|$xF%*{ z!+mk6WJU?k9VUhJokJw$>(8vbLlO)}+L*Er z@RIbB{Q;;Xwj_n87hXo{g~frWWM@esqa1dA)b)(a1^>pC{>NpYwHK`Og0t*(WF^fd zS4%kmukYz;apBI;_fZ9csFGKEx9rW_yKC?M(iNpX`&S;29k_Jh!NGM00}r7?7Khdx z@|RB7{o(G#yX|%_+wHMixjScf>F(pZ@9loHr)Tfvy^&J1d*<$i-F=L9fG{9PUr5$m zxR5f#k6B)7xR?o+$J0?G#7)|4wLLv-k@V(GoD9Zz_+%gbtVO-hV#_usq!-O~yK z>f24;g$fr|2+q?GXbu4JJsNxBNXaZqFn`bVJ)iE;+he@PW{=yRz&RXRgW{;?!8 z_I8sVXRxSD%2dr<-jN*>i}rZ#@gcV#@n$XFOPbrroW4&Op9pwkMB;P!+$Vc-_UzwN zw&(bsnmrfy+}-nw`sb|3&pjtU_l)~o9`AEw;d5W^`Ii2i5Bs@f@^i!7=ZwjFRoXfq z1C~Uw!ac)#N9}!E^%P^6%W%H{{=JW+8Gz)#omQSHZrnR>uhCw!y>@$7?)BG0dl&81 zgYbYx2oGqilfwVuT8-*H_Kh^*VIz4O`9AiI;DL(k9pR3Q1{Q?=1a63>dT-edaogV7 zy%+c1+WY(7zJ06rN%w6kb>{eu6;_Jc@4e16`pRAfHd1C7w5JeNh`qeTPA=a2df%jd z)AoI`&k17w_X+onqj^O#hPRuUsFpT0>A_op_UZ1kRFf25t--31&1%jWuhw#V_t*aw zhFK9K-j}*BZ(mcXUa2K71^aR`Nl%(!&c6Noj_s?#Tr7mQ=3)lQhCp||D4p3Gm?_ZN z_v5}__o?y)@j;Yj;8{DxFX|nchn)@m?D47=RQ# zs-8{~89$+nIJSK%@P{F@q=OCYI8f{%@&*?|Q!=1}>u)tHSVhWCxvlwOwD=gexz{!oc#;-+mpU3 z$NS`HzutZ`9C1Gb5E(71emv09-PeJg1T>-dm-qV}Fg##&VA+8+a8HNE{;2&$`|J1r zxc}jSccp0mru`Y}{fkxW)+A8s>@VGaf~VBk#8>J-MxXu7`>%I`6U!4kFznB3tJabj z)Htzd|KkG)s&wstsa7S90fhGI>YeyFbl`&nkbV+WKCI>_K}`b`%aQCjZlm8*o4TK# zK@b8yQE8wqPZuma5PKl`!1e=`oL+qe zWPB_-aOS`{dVl)k{i(Sb>RmfO8> zLD9i?4t{*_6Y}a8CLnGmsj6are@y97m_KF=^)bJub7OwkhwaAGa86^T$h9Jv__CyGfhByrf2@;czcd9lL>l2dKQRv{!gZ1n=*Xd# z!)1Z!Q2wFa6b4_@&GMwmAkm>yhZ+ujdFT$Nhqipe{N|?-YMr0eNb#Fr0ItSniJJ~R zKm69=j}Ff~Jp1sX!xo2&^n`~6hee0SKzL^paI>ZW_)i}le(&%U^6oc?CTk)ub!!68 zcySZvSWW7jt|=NFwmqB$@n~oef^ILA>6ICmnU`6YIhU;|lh;DL?S(qHDDOf&z<~?6sSE0Jb791Q zFYpI^fs8fkjmQvKm1UJ3E~_bPD*Fm}aoMgi@Q@=L7+ zN#>1pCiBh;dMzsZ<;ct<21izal_o==UDi?7TQ+<-;*qb9+&ntr=!~N#M{SS#9*sG=ha;<7S&mvm>pi>zMMr)<^6j-@9NjI@)ve8OD}tDT|SE zhHv>O?2WZvrcpk%+@V}vez?4;{6P>ZpHaRL@DoJvQGsik=3T1iKvK(%$}MP;nu$s3 z_I5HeRtzd%QSL?JtuwKx+_zjxW##SwZ9Zh>{#7n4k1F3@UIP2PJfS?9-sgIFpA%{% z?F_3#%HbxrtGt>gww4aaQ^g(SSIX)8eOP?UCS>l|BrIRPsRCTn`S|sfyol;aj zRQ?99@1E`m$>ISC07{OE{K6R@`<>N*jiiXv?uMRsn&|sey&3ptL4+UKIEHL!oi3?D&o2 zFHeY1%s2rkC~WMp^T!?>>o_)ieD-nu<5|Z`jyJ)_FCP0|9YsZ}VIP_}viLAS%@SrE zijKWL{xOM%LeX)J;}bECGUFS*6bwRItme0G9wj_(cHHN`qf4i4s-||zjyq1(vc9H z6=uR;kB);^FVBncLwq@s_9gBJ@8ovb-zVPV?XtZQ=)~+3dxO)^uP1a)EIwhyLAN=S zG%yYd2cZ*7Pi!IyWg5D4!s~?JiBOJ4Q3s87VEmXBNYGu1yr!ZrPNbg5<=R}#mAFI7 zuMk*G>7>yli1_0CxIMzqiO)`4<1AYnDgTOKCE9x87WPBf%%iv~BZVirPdu-9mm6{} zH{|XLF>lEG`@wCUvOvvZnB(afVa37<_lj_-u)?5XNrgST=YOa7ydLLqzfL7b6{{;) z8&v`ST)%=$vy^wEsA5~i_KLiUeQZmA(JlFLI-I|-mMcP7ak8Sm;xo4FS9Do>uIyLr z!5V%Vhbn%mfQ+z|17|+vZ>>a06&-95)DSPK_@{DArB>w%Za%WP`FK(}nKvJBb4TU8 z%4I4Us?@2pAOk(vj*!+C&bJWMj&fr7Aw74q@klF!E2AqDE7RCY*>vy6bG^^zMp{`^ zd9d;rTlOkl){ZNCHMU3)Tlt{sLe`#TB(K};N^L@QneOmpYhV>0)=dPUl{(Q#y z9~u)IQ>9}oyDOiaeCy<@li?>5PZpf4J^6rbxrt<$%2B>21w4g=EKq!M>PfAW^G+I_ zbiiQKhytXh{B?Zu*$BvaK^<~l1g?3~_hcaEnoXE%^703Har1rdWCm}(w?GDK_#epC zkX`^HGM}{!kblF(Q!L}3m))u-K>AxwUOdTO?Phb5)qmJv(hgUUicdbSl2n;ig;d4B z@BWi7t5B6z)hEpM)@SaEv4H?i$aPiqR@DdaMMn8%KZM0xyKZ_#4d{O)Of74Lu*$k> zO;vybRXJ99kWv#>;CUupj=VOFd6GdtF=U+RZR3Sio2#m;>Se;J)T+`dNF!a9RaL~5 z&!Wqla8I_=PmJk*Oc_~yF^3L53=mh{scNt4JEe8Xgv1BRQPL{XvV!@2Fh&a-JDy3? z(Auikr$(Rph?8|5{MSPE8x5*`NbA+9PfqEO)~iQ2fN(tzY#>P89EVQ1p7O$91G5A8 zA1Y@AoZ86igF-g;RLZGcr|M1(RQpuNSLap#S^csF^6>yR!cN{6@U4!ZaB%bq-r00AcNJHoGPCBoS?9Y!t_UAeMVId#npO>R*ziJ*U*v6t7 zUvBeXs7~c={$#MnSC>>@ZiT2axE;s5y1cr&x(SbR8jqw;WAtFFhI>0fpeE@OZS^`( zeV5nZ;hs2D{kXc1)d^~|3hY^szBo@{a{A-bb584?c00Z5^oG+3rwdOvoW6Ye`_o;g z2T%WtKOD@`jc!`xQqB%KZT4R?Qa(+u!r6qB8-Nm=mYt5kl%N|^f^hIhIh}lZ2WKh@ z##W+v3Uqq!>8k%&iRQ8@=k2_C_<%DBnM9$}w@?2<>l`)%96kN#X%%G>%A-v}&lp3{ zCYBdyCd8pL;xh|Lf0Q$CpP{dRf_)C20%txxGmCC2o$*K6OL0YSa2utPgAjt#^3i8p z&+4CDa@M8h{Ti*BYf_CfK4)ZSBF}6-JNB$L2Lck<`8&@Yxut>V3~}bKHmT@L_L<@{ z^=Gc&>Gpu6d~m__nL}s5LyX$succfl;_D5MNeYJF!0jjl5Vv^d`!o0OBY$4ujc_Sd z;hC;817}{H6~TFdtEGy%NP&%*Q$QYzp>SeOAsK~g3`=$PowFa}r82u=j_gbZ&vI@+&N9(iud}<)mYuDIBYM{Ftm16K+3k2xhH6Lj{D>pksD4D7*i5pm zPgP+`&8oAN%;z<$hNYR}nzLV?y?yr2vmIxj)r{6dXTLdnvlb-s8uCAVboS@7zd;h5 z8czc+s)5voHMTYB zaLFAABd?rmme+VQpL^vTi)z-_L_=H;&_?B}Piy4(&8N(xMKxRSqeZ|On903@f4~jE zHHT{Ia03f!*!W+#zmRHkVa-L{z(Pv>k*XL|^RRYo?fbQhYF%nQYyIlRw|7I({?(e! zn(mq*P$Pdyu0a_5+cgCDdZ^T7kbVved2{5cu~v&mO}2IoMWb4yTGsRWbCO5lE`JVr z1W2X01@w=7_+@XbMr~wmVQpRQ54FG7zLuie_}X-J!6i;jaCslpzqR{nkMq>O$$a&1 zP$;Txs{L9`m%EvfR2+Ih%E0L`^tMEy+DEmJdyC7Ep#ksN_~LEqn%}L7xdP+5PwMpR zEb4sfq;;F?O6nTxuGalf*IW0j9^s7~#2#iQdx&zjtj_7b#Bdi)48!1D)yeDF{1;vL zT!jG%tW(zIa3nAYlfbzORJXql?wuXsk~fDXftfrKIE5pD#!;y5Ufpjr-AV!ySoa9F z5M+FrolBFzVTJ_8b0lz69I78v?@p4y`giKh0#N;wdWZlAUqfPc1lldepUD` z7$q8^VFGJYn{cKof42nd{e}q*Bv0>})7xQq%b{ zYW6@%cYcN>RI>367aOiO+;8Y<`1jn0=jNYtJ{NfIz`0W#ZZZ!*4L2KZ2M`8dg%bt` zv0e#WNd~|>8*UzhoQGk=oRgqkV$yBV4~~VRbK-Mjg9(FO;Yx!;=O(tc^mUSV1RDGh zhR)4AH!FfLxZMk{?}Ura>7O$`XMWBK{>p=t<_7oSO9v>;8R&crj(}R7c3VLO-r#Y`A2?M(F%;a$;0)VPXe~eY%*7 z63hFs^6s}-bnf=~EmG0B-_EJdb)ADCQpU%tkv@thoE+8I6Flbpxbsub&pmH=-tN4| z`HknpATtr?M(nJnS;!#CN;_6u5Kq*IkG>kwk*Vb?u;Z&W9M$QKDYoJagL}vM?DI#d zV7XwWp!_^PeH_5~Co**Y)cK1ex2N%cwx?12=<|P^f7AGWOZr!40BRI9zQs5@Zh$j!F@TK{qlC!KJxpE-l1nLDlQe_*0_8@ zTw`O?<)-`1fz3G=E?#oHTyXi|<&#&wyVCmQ;xD_e9>4mpbX?=j#-AIz8V8!*YVv6c zZAxz{Y}(DP_%XO1sPT_R2+w&2T{;GP3dY5_^Uel}-1xFdh>^}QOp#~HMNLzhW;QKq za>2tgQ9~_XDo~R_ldYN!{LNKt1K+5QVZQ2wK(Ha+xVCW==u%T6ZyJfgXDSukx=qV6 z*71b!t4*omzncyWxu{vAd1CYQ=0*79nf&p-+Mll=CbcjldPrq7%ys}`;Lbk+LR z+g5+SrokH9nu%-P(JS+w78u@oJV@bRH+8;SLYcCH*AF zw5G+Hc59N>j8nh2*|E^tuWQoOC9fH>W;pK+JSutvFN)sAG~C)Cf9!oC@bDV%nmKD; zR6ogeT=Te^p*yPH9me5R+6vbdm(RH6H6N|{LN#4z>~Jp33R<&0KP~^*+6n6d)_1W4 zt|?h_e9ce!EWfT+5q!w2{#caxHNUUX?*IExE%UJsIX@`BlA3K2%B0U{v=$%R^SuH2 zE%FEE52LN4`EB#NE3FvybgsP4TP{WY8t(-R^4mK4sx2UYV*b+n4OymqZ~mkCbMqIf zzBMo7+nZ%e+f8hSGUkl8@O3-?%ly?RaazJfEKLtMMa$wEw7rNk>{sS*&){@yZO z`n`5J|NFHav5)~?pIuvJZOqzc7CHaYT2tBn_p~zoZ@+UuCaJC7pfXb7n4LzCac$4F z1JzvNaLH>QSc~(a=$n6@$N~$TL2Gl?KE8JL+LzY8wst4ZQ>0Zl=qd2Xs!S_OK0l`{ zKM`70@coP3yqFcRcG23EYd2ctwI8j;h>Vf~t2Jv18jY?R*QuqgL#d%G#gW&RtTl{E zXW^hLgdBGXy5+U!)?QWP-a$>2a;G9bTG-~ZHtU+MYrU?^x-si4>n5$6z3$z08`kYw zcYNJ1>m$}TSl?`YJJq69%Ud{tk#EUKTUSp1Uu;FUYm*^kkq6hg*J&~yc!qaCmI%Mm7 z>jRa+!LvLfl#UdZOnGLqb?a-N{7t!S;il6`Vs3b>kkyP zFX&m|DVVMIAS{#Q^_lA**Ln~e)_V+<)6A2Xyr%VY*Z*Vv+Vxv3^7XY)Z^*^pZTfhn;3gYyBa)MP}e`)|9i!wvBp+Mm2~5tB$8qBq=g z8k0lHcSxF(RTO75ty8MjX)Nkf%zipWYjLEtrDt$~_>*+(t+a#|w9i&MaZ)EuC;h5kZM)%#4U4IFHY=gphUYiDDrPmuiP*+s(N6qRSwi&kuYw1&^D*D15u;G`DVH;~>Njv6AC(Vp$u;CAnyy3>i z0Obqy�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

O z7wC+AvTowBPt^=Ow#l{}jZ>~i(>R=HsavAueil8n3(Enunel=QO9d(g2^HZx7#pN zs%iDIyREs|84lZ2{t{WZ%Fw2J+mAA{NNrAfa?*>F-kkK|q%SA^I7#B9KPLk?8OX^X zP6l%_gp;A1By;irC&M^N;Utxl;hc=%WF#k}I2p~!7*6POUk>&>*sxt^8fCc*yVq+= zXYO2=-IB#psaSDIy=fLUk#t%<;Y|cL;B^mI^SXqqdy6v5xt=&ALb%)uB`QbAIK39s zBghol7KeikwpcZz40|T74@kFoaEOAE2wEBq%|y5-aT~+vG780RFFp&)88s*33^Cyo ztSDKX4pc%$=4ubiKq*nxO2JSWilQt#u1P>~QxqOXB~r^`RMvC`u4oL(ny#j@rg4hf z8b@VKW5{jo1>v`*hWEOfLauQX0-Zq!GzKBi)f57aQ$nC|6atN*RL~e+(P=C%=NhY2 z3>wELA9=jR4zfm9|i;^|N59VG&AEc+^&v>+)$lp;p>Oq4xJgYjC-Ff2H;p zYJ?kGIT1ZE$zEe;~Cl z30#&>@o}}%X%gCHUjx$ex+yW#W=8 z_3Xi6PMjjcQf%4wG*kkZi{Wc3xxH{ zjhF|%_fHpn$3V%)zZBlTbq*ZgbXU>&X=!$^vP&=yRj1R6TTRk&!i;;oqTSd`q$ztW z{F3hg&^F?d&kLkOtztRU3kcA^yZ5@g^(q4#*L@R!#O&+7JYX4c9Ei@j?n?sZ0|_vH zXEpX`t-S8bT6Nv`I#2{$0TQ77UnqKYn@L=Kx*4{JO8vitD~EKq}A{<`ZJ! z4{#i))%cPx8OQ^c0mp&3CYO9kFk9CG?*t^qLmpTH90trSFZr^7B`~}5IdojYftn)M zr5@L(bKI1l<<~D|cu(atKLdMr`Aj=Uk+x&S-y`xE&Rv?3%_U_Jr*MHQG;7vG?t2m46?)=f~bCSQC`n#~w zWuF&lYe4Vl%f18PKNEVF!L!PjeJS|P&B*%&9XW>_v_ zVeJ+DBzPWzHG&CjmZA#45lgRPQxVr)g6&8qm`m7JL@y>u4ItYL+mPM^ABevo7L1Kb z;n@5{#{=EN=CS9nr1J&#CjM}VGuy(7uxxWXR`2g*yV!2FAB#5+vJ&N(lpnBw^H+RS zma)Al5L>3|u{_6_@%(H1E(t%Jp-Gw~t&m0L_3z-Jk{0m^dGcM;k! zY)`9;qo7`Ai?FOzg84=)AKi?wY(-djILQ5z!uKe=%To4FwhAAwC8$5d0aDAcfr{dQ zY||F66VMMsNa!G#58>Zd$jESYIes@nR)+gV`6~zyZMv(*K7&~)`y9WQu&7l=+?IJT z?6lj{Z5UwKG1HH0{Ok_5Q6L!K_<~_A7|!by(eAG=2f|#}55hA<*K{KW@a^0%Ug-ih9=HP8m2cWn*Ody}32 zhrRcJkE1x>$7lCuPqHQ3a>d;z+p=tI83Cr*2CQaDRx>JY6rSQq>zLFDUgtal7s|8AccfLnkfgT-}B7OUelc=8DB6#7@_lF+N6D?+b_t_uZ2&jND*nAd=L1DH2M$#_Tb7bu#GLKiA{N$6q)FAH6& z;1!|ELsy5c30)PsQiZPzT^qU~bYp0L=z0~tDfI5p&7t>&-Wz&P=mVh-hTb2#CG?Td zM?)VDeJJ#a&?iG54}C0jTj=)Cr$VB%ZI~4qE=q?5C3Eds~Lg=!wwdpLd|HKmh z|DWQt;P&tnGm|Urufz0h!S-NluqAkQus*mqcvi4BSQo4bR)^zVe!GIZgFAyef=$8Z zU}LZ$ct-Hd;OW6V&kepSI2yblcwzAT;CTvvW$=n{ zyqixnyfk=;ioZB`k%E^8FH1;&ZSb0e_-I~<{8tCBI;?bwc*Wzog5AN+U`LpLZ*X6* zC+H7{UHbjO8-mvduN#MV;~x(`5&U`ZXW{spg6|2wJ9uL_{K4Rdf*%OJKOBBv@Rs1s z!S{y4E}zN3j|4v){CMya!H)$$IxhX4!MlQY1V0mlzcu*D;O)Ur2X700Dh3~)*KdQ* zs`y_9f1%)0!6y}bI`}IEe;0gCK{wqq!QTW!!Li_5!8c>@Zam@dgMSFV5PUu+{_fys zRrqtkdt&hFE*0FU5`Ozcl*hxD4B8$ZbSj{Haes)8N|nqDBEGYb9OE1r$GSLzBtb9= zC(}~ecB*aiA6Fv8g&i2Crp61MB2$5P9Png@5ixC#!;lkBp2!m+S5lEflyg}s=xQJl zo5RCJ<&@YP$2Pv`anX|u>LQ~wQDsLUtZ0v*FnC!?7&A%6hAdJP@B|z1LA?PRl^zMFEHWzO*ke|qJW`K6cvx_>F(&lIf%1=*WLqT%g@qhF8sqdGoo;RG;yT4 z$M~-RJR4^`-^qmI>-X8WV%IhL8k)Jx5_S{SZ!Sg(N8>yO=dn09;5-iJ@i^&D1Uw1n zMx2{)ZpKM>ih)}I^Nha$u+aFo0v6*e!C8uP8_tAo2G%Xqk!JqWX2c&Zg$q+>q=r+u zxWj{KGg7_kNV8{5bXYUqsUyXklIEE)Yeq_1iU((^IlRF0NYjT*WvrNi*Kw)RA_kQ4 zGEi#bS^jvvF-&}P$>P&14Wy+apJ*!j-IOkjPnj%?M}1=shRGv>r+<9;iA9M$3PJ}G zWu-s*pg#1$JjijP@@qObRRq$4aDTb_hXury-=&MzLu{#%ha%-Z{@qv&-JHoWHYQR1)4H`C%ryLB(@+cJ%dc(0wFwQ~d?$hjE5ECeMD@>- zv)rs>wg9*M@$$xoC#wHgYKAP;qNbt-c&PIK+wEW5s;fClVeFr+-L!vVVgI`R6O`Z8 zjV=*+u`CmpKi*1o`sjb%4s@NnHP3k0uc6Dw%~{uTv^4ZbYS{I=rH(*1Z`IGK{!U}q z`q};!K20i3xU_~M-2P+nI+V!%6VXNEX#48$Mwg%d@#T+{;9$Pw<#to){L%l@+Qa?5 zv3|5tjgK!su!z$hV5YOO*!P(nhr4VqEA-KM{0gjHQdlQi>@1H`hB= zZum|8<0}lY($XqoF|^2u%RhU@Y|te;bngcXFxLL|%O6|r#39zOy8fH8>l%!={~1wI zYd-NB(9#}i{YT4`y#I@6BI46pj7~ope{|iu^u&>y8`eMvyWq)drWa?} zY9ck8to=t@PHcXM6N+df;#1PFEweADeCkN`dS;}iO-Fm4nKm<(hm~ZE=8k=}K3u+v zYt)#}<-yUTM`?}}`a0%fEVozjCNJB}RHRcdrz0t>QeD(B} zFG&>VyOX)khIC2t;B5o=Y?->NY+NpGB-1BzTRgu~_fPl?{K*U*&M;x&Lc>5Utihjg zgr?hWYj}awFj+py@co?wemo{A{B51}ge`5oeR$*&Z*J)9Q{m>mUKJkdYEW>np zJP#Wm*XnQP1APO+MlU4xb?CT9Ok7NUBYjmW9iDF`WfL6#N>`D+}3?)2Oi~^)G;DP@P@R> z9c^*az6UqR=wl?JqRIH8&0sS0|7n_N^Zt+KZE=GFX36~qWt`kykho7qIJoJ>u~XCz z1_@F{8b0GD@JTQmH__N)8k2EzgZmpi@y{>08(eI}4DbU6EkNC8BW!#}Nu^+R;pF)A z8j-VA6n%JJJm(nuSjT(ZNgJ~Z(n<@b&nVk|T5b03xqJ6CWY1qv-ox`8C;V)~0S+fBccwx?FM8(HlJSgp?DrPd;^4O;PzNQ?^tV z=gq9npSrbVTl%z$jH>J%3wJf2IlFDn8E2h6?}(;FE!o*!{>3Z$M!S2?>0c5U7+U6g z*UED*yy&uvFUh(z`-)XpU9H7K+r*BE-g?>X>B}piBzz78XZa9l74$b!O+DgnGX8;gom0O_}a2@kka5mD?$ z5s`yqV**4pr;?P?Z7OFMmX@kuS$VmF1r;i%0+&sZ4sVK+5Ct*?&;{a)?59nytf{P= zQ(0MATUob#hY2Hya9nUFkh^wQss!-vtlYEx^fPq&*^2(m?K^hpFoG(5Opxi%icXJ= z_ab*5a5dm~cI8=TMP;B;L?h~FHZ-anT-eZ{f=$iM3hruAsST4|F1NEZdQY5uklzTX zfx$tA?;KLx4AV}Rdyhs#KvN(splUk9 za0`dEcNFhHUa@lIypfTtk&%(}M=p5Rxh9Mt!g0Y1fxPJA5tRVm3rCQCLv(r)ToO$H z&XZ=w0qH7d4!}KDT`z0F9 z)~LMz!n{j z1tMqTdv1E~dv98M)6Fip`KFuRhY%0An{UdYww2q!|D0jdk0uBBawkSyGw~gO1-OYe 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

gEXWtTDE@#gXp1Om*M)h5} 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 literal 33792 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 LpP&D2EAW2-=w@;! diff --git a/vendor/sdl2/ttf/SDL2_ttf.lib b/vendor/sdl2/ttf/SDL2_ttf.lib index 28810a7bcbb11ecbda3401928fd0953062f51493..bd53219e9d3f99c34e4907ed9faa6e13e8c11de1 100644 GIT binary patch literal 18406 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 literal 12122 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 Date: Sun, 13 Feb 2022 11:54:40 +0000 Subject: [PATCH 0144/1052] Add utility classes for dealing with Windows Most for GLFW and SDL only --- core/sys/darwin/Foundation/NSWindow.odin | 41 ++++++++++++++++ core/sys/darwin/QuartzCore/QuartzCore.odin | 54 ++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 core/sys/darwin/Foundation/NSWindow.odin create mode 100644 core/sys/darwin/QuartzCore/QuartzCore.odin diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin new file mode 100644 index 000000000..014550aa5 --- /dev/null +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -0,0 +1,41 @@ +package objc_Foundation + +import NS "core:sys/darwin/Foundation" + +@(objc_class="CALayer") +Layer :: struct { using _: NS.Object } + +@(objc_class="NSResponder") +Responder :: struct {using _: Object} + +@(objc_class="NSView") +View :: struct {using _: Responder} + +@(objc_class="NSWindow") +Window :: struct {using _: Responder} + +@(objc_type=Window, objc_name="contentView") +Window_contentView :: proc(self: ^Window) -> ^View { + return msgSend(^View, self, "contentView") +} + +@(objc_type=View, objc_name="layer") +View_layer :: proc(self: ^View) -> ^Layer { + return msgSend(^Layer, self, "layer") +} + +@(objc_type=View, objc_name="setLayer") +View_setLayer :: proc(self: ^View, layer: ^Layer) { + msgSend(nil, self, "setLayer:", layer) +} + + +@(objc_type=View, objc_name="wantsLayer") +View_wantsLayer :: proc(self: ^View) -> BOOL { + return msgSend(BOOL, self, "wantsLayer") +} + +@(objc_type=View, objc_name="setWantsLayer") +View_setWantsLayer :: proc(self: ^View, wantsLayer: BOOL) { + msgSend(nil, self, "setWantsLayer:", wantsLayer) +} diff --git a/core/sys/darwin/QuartzCore/QuartzCore.odin b/core/sys/darwin/QuartzCore/QuartzCore.odin new file mode 100644 index 000000000..49ed51622 --- /dev/null +++ b/core/sys/darwin/QuartzCore/QuartzCore.odin @@ -0,0 +1,54 @@ +package objc_QuartzCore + +import NS "core:sys/darwin/Foundation" +import MTL "core:sys/darwin/Metal" +import "core:intrinsics" + +@(private) +msgSend :: intrinsics.objc_send + +@(objc_class="CAMetalLayer") +MetalLayer :: struct{ using _: NS.Layer} + +@(objc_type=MetalLayer, objc_name="device") +MetalLayer_device :: proc(self: ^MetalLayer) -> ^MTL.Device { + return msgSend(^MTL.Device, self, "device") +} +@(objc_type=MetalLayer, objc_name="setDevice") +MetalLayer_setDevice :: proc(self: ^MetalLayer, device: ^MTL.Device) { + msgSend(nil, self, "setDevice:", device) +} + +@(objc_type=MetalLayer, objc_name="opaque") +MetalLayer_opaque :: proc(self: ^MetalLayer) -> NS.BOOL { + return msgSend(NS.BOOL, self, "opaque") +} +@(objc_type=MetalLayer, objc_name="setOpaque") +MetalLayer_setOpaque :: proc(self: ^MetalLayer, opaque: NS.BOOL) { + msgSend(nil, self, "setOpaque:", opaque) +} + +@(objc_type=MetalLayer, objc_name="preferredDevice") +MetalLayer_preferredDevice :: proc(self: ^MetalLayer) -> ^MTL.Device { + return msgSend(^MTL.Device, self, "preferredDevice") +} +@(objc_type=MetalLayer, objc_name="pixelFormat") +MetalLayer_pixelFormat :: proc(self: ^MetalLayer) -> MTL.PixelFormat { + return msgSend(MTL.PixelFormat, self, "pixelFormat") +} +@(objc_type=MetalLayer, objc_name="framebufferOnly") +MetalLayer_framebufferOnly :: proc(self: ^MetalLayer) -> NS.BOOL { + return msgSend(NS.BOOL, self, "framebufferOnly") +} + + +@(objc_class="CAMetalDrawable") +MetalDrawable :: struct { using _: MTL.Drawable } + +MetalDrawable_layer :: proc(self: ^MetalDrawable) -> ^MetalLayer { + return msgSend(^MetalLayer, self, "layer") +} + +MetalDrawable_texture :: proc(self: ^MetalDrawable) -> ^MTL.Texture { + return msgSend(^MTL.Texture, self, "texture") +} \ No newline at end of file From 88b1b2c629cd425c8215718e40a252b78a62b34e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Feb 2022 15:11:45 +0000 Subject: [PATCH 0145/1052] Correct types --- core/sys/darwin/Foundation/NSWindow.odin | 19 +- core/sys/darwin/Metal/MetalClasses.odin | 196 ++++++++++----------- core/sys/darwin/QuartzCore/QuartzCore.odin | 33 ++++ 3 files changed, 149 insertions(+), 99 deletions(-) diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin index 014550aa5..0c64cc8c7 100644 --- a/core/sys/darwin/Foundation/NSWindow.odin +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -2,6 +2,11 @@ package objc_Foundation import NS "core:sys/darwin/Foundation" +Rect :: struct { + x, y: f64, + width, height: f64, +} + @(objc_class="CALayer") Layer :: struct { using _: NS.Object } @@ -19,6 +24,19 @@ Window_contentView :: proc(self: ^Window) -> ^View { return msgSend(^View, self, "contentView") } +@(objc_type=Window, objc_name="frame") +Window_frame :: proc(self: ^Window) -> Rect { + return msgSend(Rect, self, "frame") +} + +@(objc_type=Window, objc_name="setFrame") +Window_setFrame :: proc(self: ^Window, frame: Rect) { + msgSend(nil, self, "setFrame:", frame) +} + + + + @(objc_type=View, objc_name="layer") View_layer :: proc(self: ^View) -> ^Layer { return msgSend(^Layer, self, "layer") @@ -29,7 +47,6 @@ View_setLayer :: proc(self: ^View, layer: ^Layer) { msgSend(nil, self, "setLayer:", layer) } - @(objc_type=View, objc_name="wantsLayer") View_wantsLayer :: proc(self: ^View) -> BOOL { return msgSend(BOOL, self, "wantsLayer") diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 26e5e2452..f2652d19b 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -2666,8 +2666,8 @@ RenderPassColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^Rende RenderPassColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray) -> ^RenderPassColorAttachmentDescriptorArray { return msgSend(^RenderPassColorAttachmentDescriptorArray, self, "init") } -@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPassColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPassColorAttachmentDescriptor { +@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="object") +RenderPassColorAttachmentDescriptorArray_object :: #force_inline proc(self: ^RenderPassColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPassColorAttachmentDescriptor { return msgSend(^RenderPassColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="setObject") @@ -5375,8 +5375,8 @@ CommandBuffer_GPUStartTime :: #force_inline proc(self: ^CommandBuffer) -> CFTime return msgSend(CFTimeInterval, self, "GPUStartTime") } @(objc_type=CommandBuffer, objc_name="accelerationStructureCommandEncoder") -CommandBuffer_accelerationStructureCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "accelerationStructureCommandEncoder") +CommandBuffer_accelerationStructureCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^AccelerationStructureCommandEncoder { + return msgSend(^AccelerationStructureCommandEncoder, self, "accelerationStructureCommandEncoder") } @(objc_type=CommandBuffer, objc_name="addCompletedHandler") CommandBuffer_addCompletedHandler :: #force_inline proc(self: ^CommandBuffer, block: CommandBufferHandler) { @@ -5387,32 +5387,32 @@ CommandBuffer_addScheduledHandler :: #force_inline proc(self: ^CommandBuffer, bl msgSend(nil, self, "addScheduledHandler:", block) } @(objc_type=CommandBuffer, objc_name="blitCommandEncoder") -CommandBuffer_blitCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "blitCommandEncoder") +CommandBuffer_blitCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^BlitCommandEncoder { + return msgSend(^BlitCommandEncoder, self, "blitCommandEncoder") } @(objc_type=CommandBuffer, objc_name="blitCommandEncoderWithDescriptor") -CommandBuffer_blitCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, blitPassDescriptor: ^BlitPassDescriptor) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "blitCommandEncoderWithDescriptor:", blitPassDescriptor) +CommandBuffer_blitCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, blitPassDescriptor: ^BlitPassDescriptor) -> ^BlitCommandEncoder { + return msgSend(^BlitCommandEncoder, self, "blitCommandEncoderWithDescriptor:", blitPassDescriptor) } @(objc_type=CommandBuffer, objc_name="commandQueue") -CommandBuffer_commandQueue :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "commandQueue") +CommandBuffer_commandQueue :: #force_inline proc(self: ^CommandBuffer) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "commandQueue") } @(objc_type=CommandBuffer, objc_name="commit") CommandBuffer_commit :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "commit") } @(objc_type=CommandBuffer, objc_name="computeCommandEncoder") -CommandBuffer_computeCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "computeCommandEncoder") +CommandBuffer_computeCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandEncoder { + return msgSend(^CommandEncoder, self, "computeCommandEncoder") } @(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDescriptor") -CommandBuffer_computeCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, computePassDescriptor: ^ComputePassDescriptor) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "computeCommandEncoderWithDescriptor:", computePassDescriptor) +CommandBuffer_computeCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, computePassDescriptor: ^ComputePassDescriptor) -> ^CommandEncoder { + return msgSend(^CommandEncoder, self, "computeCommandEncoderWithDescriptor:", computePassDescriptor) } @(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDispatchType") -CommandBuffer_computeCommandEncoderWithDispatchType :: #force_inline proc(self: ^CommandBuffer, dispatchType: DispatchType) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "computeCommandEncoderWithDispatchType:", dispatchType) +CommandBuffer_computeCommandEncoderWithDispatchType :: #force_inline proc(self: ^CommandBuffer, dispatchType: DispatchType) -> ^CommandEncoder { + return msgSend(^CommandEncoder, self, "computeCommandEncoderWithDispatchType:", dispatchType) } @(objc_type=CommandBuffer, objc_name="device") CommandBuffer_device :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { @@ -5451,12 +5451,12 @@ CommandBuffer_label :: #force_inline proc(self: ^CommandBuffer) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CommandBuffer, objc_name="logs") -CommandBuffer_logs :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "logs") +CommandBuffer_logs :: #force_inline proc(self: ^CommandBuffer) -> id { + return msgSend(id, self, "logs") } @(objc_type=CommandBuffer, objc_name="parallelRenderCommandEncoderWithDescriptor") -CommandBuffer_parallelRenderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "parallelRenderCommandEncoderWithDescriptor:", renderPassDescriptor) +CommandBuffer_parallelRenderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^ParallelRenderCommandEncoder { + return msgSend(^ParallelRenderCommandEncoder, self, "parallelRenderCommandEncoderWithDescriptor:", renderPassDescriptor) } @(objc_type=CommandBuffer, objc_name="popDebugGroup") CommandBuffer_popDebugGroup :: #force_inline proc(self: ^CommandBuffer) { @@ -5479,16 +5479,16 @@ CommandBuffer_pushDebugGroup :: #force_inline proc(self: ^CommandBuffer, string: msgSend(nil, self, "pushDebugGroup:", string) } @(objc_type=CommandBuffer, objc_name="renderCommandEncoderWithDescriptor") -CommandBuffer_renderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "renderCommandEncoderWithDescriptor:", renderPassDescriptor) +CommandBuffer_renderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^RenderCommandEncoder { + return msgSend(^RenderCommandEncoder, self, "renderCommandEncoderWithDescriptor:", renderPassDescriptor) } @(objc_type=CommandBuffer, objc_name="resourceStateCommandEncoder") CommandBuffer_resourceStateCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { return msgSend(^CommandBuffer, self, "resourceStateCommandEncoder") } @(objc_type=CommandBuffer, objc_name="resourceStateCommandEncoderWithDescriptor") -CommandBuffer_resourceStateCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, resourceStatePassDescriptor: ^ResourceStatePassDescriptor) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "resourceStateCommandEncoderWithDescriptor:", resourceStatePassDescriptor) +CommandBuffer_resourceStateCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, resourceStatePassDescriptor: ^ResourceStatePassDescriptor) -> ^ResourceStateCommandEncoder { + return msgSend(^ResourceStateCommandEncoder, self, "resourceStateCommandEncoderWithDescriptor:", resourceStatePassDescriptor) } @(objc_type=CommandBuffer, objc_name="retainedReferences") CommandBuffer_retainedReferences :: #force_inline proc(self: ^CommandBuffer) -> BOOL { @@ -5604,8 +5604,8 @@ Methods: CommandQueue :: struct { using _: NS.Object } @(objc_type=CommandQueue, objc_name="commandBuffer") -CommandQueue_commandBuffer :: #force_inline proc(self: ^CommandQueue) -> ^CommandQueue { - return msgSend(^CommandQueue, self, "commandBuffer") +CommandQueue_commandBuffer :: #force_inline proc(self: ^CommandQueue) -> ^CommandBuffer { + return msgSend(^CommandBuffer, self, "commandBuffer") } @(objc_type=CommandQueue, objc_name="commandBufferWithDescriptor") CommandQueue_commandBufferWithDescriptor :: #force_inline proc(self: ^CommandQueue, descriptor: ^CommandBufferDescriptor) -> ^CommandQueue { @@ -5616,8 +5616,8 @@ CommandQueue_commandBufferWithUnretainedReferences :: #force_inline proc(self: ^ return msgSend(^CommandQueue, self, "commandBufferWithUnretainedReferences") } @(objc_type=CommandQueue, objc_name="device") -CommandQueue_device :: #force_inline proc(self: ^CommandQueue) -> ^CommandQueue { - return msgSend(^CommandQueue, self, "device") +CommandQueue_device :: #force_inline proc(self: ^CommandQueue) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=CommandQueue, objc_name="insertDebugCaptureBoundary") CommandQueue_insertDebugCaptureBoundary :: #force_inline proc(self: ^CommandQueue) { @@ -6195,41 +6195,41 @@ Device_name :: #force_inline proc(self: ^Device) -> ^NS.String { return msgSend(^NS.String, self, "name") } @(objc_type=Device, objc_name="newAccelerationStructureWithDescriptor") -Device_newAccelerationStructureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> ^Device { - return msgSend(^Device, self, "newAccelerationStructureWithDescriptor:", descriptor) +Device_newAccelerationStructureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^AccelerationStructureDescriptor) -> ^AccelerationStructure { + return msgSend(^AccelerationStructure, self, "newAccelerationStructureWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newAccelerationStructureWithSize") -Device_newAccelerationStructureWithSize :: #force_inline proc(self: ^Device, size: NS.UInteger) -> ^Device { - return msgSend(^Device, self, "newAccelerationStructureWithSize:", size) +Device_newAccelerationStructureWithSize :: #force_inline proc(self: ^Device, size: NS.UInteger) -> ^AccelerationStructure { + return msgSend(^AccelerationStructure, self, "newAccelerationStructureWithSize:", size) } @(objc_type=Device, objc_name="newArgumentEncoderWithArguments") -Device_newArgumentEncoderWithArguments :: #force_inline proc(self: ^Device, arguments: ^NS.Array) -> ^Device { - return msgSend(^Device, self, "newArgumentEncoderWithArguments:", arguments) +Device_newArgumentEncoderWithArguments :: #force_inline proc(self: ^Device, arguments: ^NS.Array) -> ^ArgumentEncoder { + return msgSend(^ArgumentEncoder, self, "newArgumentEncoderWithArguments:", arguments) } @(objc_type=Device, objc_name="newBinaryArchiveWithDescriptor") -Device_newBinaryArchiveWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newBinaryArchiveWithDescriptor:error:", descriptor, &error) +Device_newBinaryArchiveWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor) -> (res: ^BinaryArchive, error: ^NS.Error) { + res = msgSend(^BinaryArchive, self, "newBinaryArchiveWithDescriptor:error:", descriptor, &error) return } @(objc_type=Device, objc_name="newBufferWithBytes") -Device_newBufferWithBytes :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions) -> ^Device { - return msgSend(^Device, self, "newBufferWithBytes:length:options:", pointer, length, options) +Device_newBufferWithBytes :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { + return msgSend(^Buffer, self, "newBufferWithBytes:length:options:", pointer, length, options) } @(objc_type=Device, objc_name="newBufferWithBytesNoCopy") -Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions, deallocator: rawptr) -> ^Device { - return msgSend(^Device, self, "newBufferWithBytesNoCopy:length:options:deallocator:", pointer, length, options, deallocator) +Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions, deallocator: rawptr) -> ^Buffer { + return msgSend(^Buffer, self, "newBufferWithBytesNoCopy:length:options:deallocator:", pointer, length, options, deallocator) } @(objc_type=Device, objc_name="newBufferWithLength") -Device_newBufferWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Device { - return msgSend(^Device, self, "newBufferWithLength:options:", length, options) +Device_newBufferWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { + return msgSend(^Buffer, self, "newBufferWithLength:options:", length, options) } @(objc_type=Device, objc_name="newCommandQueue") -Device_newCommandQueue :: #force_inline proc(self: ^Device) -> ^Device { - return msgSend(^Device, self, "newCommandQueue") +Device_newCommandQueue :: #force_inline proc(self: ^Device) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "newCommandQueue") } @(objc_type=Device, objc_name="newCommandQueueWithMaxCommandBufferCount") -Device_newCommandQueueWithMaxCommandBufferCount :: #force_inline proc(self: ^Device, maxCommandBufferCount: NS.UInteger) -> ^Device { - return msgSend(^Device, self, "newCommandQueueWithMaxCommandBufferCount:", maxCommandBufferCount) +Device_newCommandQueueWithMaxCommandBufferCount :: #force_inline proc(self: ^Device, maxCommandBufferCount: NS.UInteger) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "newCommandQueueWithMaxCommandBufferCount:", maxCommandBufferCount) } @(objc_type=Device, objc_name="newComputePipelineStateWithDescriptorWithCompletionHandler") Device_newComputePipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { @@ -6245,8 +6245,8 @@ Device_newComputePipelineStateWithFunctionWithCompletionHandler :: #force_inline msgSend(nil, self, "newComputePipelineStateWithFunction:completionHandler:", computeFunction, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction") -Device_newComputePipelineStateWithFunction :: #force_inline proc(self: ^Device, computeFunction: ^Function) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, &error) +Device_newComputePipelineStateWithFunction :: #force_inline proc(self: ^Device, computeFunction: ^Function) -> (res: ^Device, error: ^NS.Error) { + res = msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, &error) return } @(objc_type=Device, objc_name="newComputePipelineStateWithFunctionWithOptionsAndCompletionHandler") @@ -6264,79 +6264,79 @@ Device_newCounterSampleBufferWithDescriptor :: #force_inline proc(self: ^Device, return } @(objc_type=Device, objc_name="newDefaultLibrary") -Device_newDefaultLibrary :: #force_inline proc(self: ^Device) -> ^Device { - return msgSend(^Device, self, "newDefaultLibrary") +Device_newDefaultLibrary :: #force_inline proc(self: ^Device) -> ^Library { + return msgSend(^Library, self, "newDefaultLibrary") } @(objc_type=Device, objc_name="newDefaultLibraryWithBundle") -Device_newDefaultLibraryWithBundle :: #force_inline proc(self: ^Device, bundle: ^NS.Bundle) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newDefaultLibraryWithBundle:error:", bundle, &error) +Device_newDefaultLibraryWithBundle :: #force_inline proc(self: ^Device, bundle: ^NS.Bundle) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newDefaultLibraryWithBundle:error:", bundle, &error) return } @(objc_type=Device, objc_name="newDepthStencilStateWithDescriptor") -Device_newDepthStencilStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^Device { - return msgSend(^Device, self, "newDepthStencilStateWithDescriptor:", descriptor) +Device_newDepthStencilStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^DepthStencilState { + return msgSend(^DepthStencilState, self, "newDepthStencilStateWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newDynamicLibrary") -Device_newDynamicLibrary :: #force_inline proc(self: ^Device, library: ^Library) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newDynamicLibrary:error:", library, &error) +Device_newDynamicLibrary :: #force_inline proc(self: ^Device, library: ^Library) -> (dyn_library: ^DynamicLibrary, error: ^NS.Error) { + dyn_library = msgSend(^DynamicLibrary, self, "newDynamicLibrary:error:", library, &error) return } @(objc_type=Device, objc_name="newDynamicLibraryWithURL") -Device_newDynamicLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newDynamicLibraryWithURL:error:", url, &error) +Device_newDynamicLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> (dyn_library: ^DynamicLibrary, error: ^NS.Error) { + dyn_library = msgSend(^DynamicLibrary, self, "newDynamicLibraryWithURL:error:", url, &error) return } @(objc_type=Device, objc_name="newEvent") -Device_newEvent :: #force_inline proc(self: ^Device) -> ^Device { - return msgSend(^Device, self, "newEvent") +Device_newEvent :: #force_inline proc(self: ^Device) -> ^Event { + return msgSend(^Event, self, "newEvent") } @(objc_type=Device, objc_name="newFence") -Device_newFence :: #force_inline proc(self: ^Device) -> ^Device { - return msgSend(^Device, self, "newFence") +Device_newFence :: #force_inline proc(self: ^Device) -> ^Fence { + return msgSend(^Fence, self, "newFence") } @(objc_type=Device, objc_name="newHeapWithDescriptor") -Device_newHeapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^HeapDescriptor) -> ^Device { - return msgSend(^Device, self, "newHeapWithDescriptor:", descriptor) +Device_newHeapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^HeapDescriptor) -> ^Heap { + return msgSend(^Heap, self, "newHeapWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newIndirectCommandBufferWithDescriptor") -Device_newIndirectCommandBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: NS.UInteger, options: ResourceOptions) -> ^Device { - return msgSend(^Device, self, "newIndirectCommandBufferWithDescriptor:maxCommandCount:options:", descriptor, maxCount, options) +Device_newIndirectCommandBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: NS.UInteger, options: ResourceOptions) -> ^IndirectCommandBuffer { + return msgSend(^IndirectCommandBuffer, self, "newIndirectCommandBufferWithDescriptor:maxCommandCount:options:", descriptor, maxCount, options) } @(objc_type=Device, objc_name="newLibraryWithData") -Device_newLibraryWithData :: #force_inline proc(self: ^Device, data: dispatch_data_t) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newLibraryWithData:error:", data, &error) +Device_newLibraryWithData :: #force_inline proc(self: ^Device, data: dispatch_data_t) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newLibraryWithData:error:", data, &error) return } @(objc_type=Device, objc_name="newLibraryWithFile") -Device_newLibraryWithFile :: #force_inline proc(self: ^Device, filepath: ^NS.String) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newLibraryWithFile:error:", filepath, &error) +Device_newLibraryWithFile :: #force_inline proc(self: ^Device, filepath: ^NS.String) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newLibraryWithFile:error:", filepath, &error) return } @(objc_type=Device, objc_name="newLibraryWithSourceWithCompletionHandler") -Device_newLibraryWithSourceWithCompletionHandler :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) { - msgSend(nil, self, "newLibraryWithSource:options:completionHandler:", source, options, completionHandler) +Device_newLibraryWithSourceWithCompletionHandler :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions, completionHandler: NewLibraryCompletionHandler) -> ^Library { + return msgSend(^Library, self, "newLibraryWithSource:options:completionHandler:", source, options, completionHandler) } @(objc_type=Device, objc_name="newLibraryWithSource") -Device_newLibraryWithSource :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newLibraryWithSource:options:error:", source, options, &error) +Device_newLibraryWithSource :: #force_inline proc(self: ^Device, source: ^NS.String, options: ^CompileOptions) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newLibraryWithSource:options:error:", source, options, &error) return } @(objc_type=Device, objc_name="newLibraryWithURL") -Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newLibraryWithURL:error:", url, &error) +Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> (library: ^Library, error: ^NS.Error) { + library = msgSend(^Library, self, "newLibraryWithURL:error:", url, &error) return } @(objc_type=Device, objc_name="newRasterizationRateMapWithDescriptor") -Device_newRasterizationRateMapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^Device { - return msgSend(^Device, self, "newRasterizationRateMapWithDescriptor:", descriptor) +Device_newRasterizationRateMapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMap { + return msgSend(^RasterizationRateMap, self, "newRasterizationRateMapWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithCompletionHandler") Device_newRenderPipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor") -Device_newRenderPipelineStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, &error) +Device_newRenderPipelineStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { + pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, &error) return } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler") @@ -6344,8 +6344,8 @@ Device_newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler :: #f msgSend(nil, self, "newRenderPipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithReflection") -Device_newRenderPipelineStateWithDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newRenderPipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) +Device_newRenderPipelineStateWithDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { + pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptorWithCompletionHandler") @@ -6353,37 +6353,37 @@ Device_newRenderPipelineStateWithTileDescriptorWithCompletionHandler :: #force_i msgSend(nil, self, "newRenderPipelineStateWithTileDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptorWithReflection") -Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) +Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { + pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } @(objc_type=Device, objc_name="newSamplerState") -Device_newSamplerState :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^Device { - return msgSend(^Device, self, "newSamplerState:", descriptor) +Device_newSamplerState :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^SamplerState { + return msgSend(^SamplerState, self, "newSamplerState:", descriptor) } @(objc_type=Device, objc_name="newSharedEvent") -Device_newSharedEvent :: #force_inline proc(self: ^Device) -> ^Device { - return msgSend(^Device, self, "newSharedEvent") +Device_newSharedEvent :: #force_inline proc(self: ^Device) -> ^SharedEvent { + return msgSend(^SharedEvent, self, "newSharedEvent") } @(objc_type=Device, objc_name="newSharedEventWithHandle") -Device_newSharedEventWithHandle :: #force_inline proc(self: ^Device, sharedEventHandle: ^SharedEventHandle) -> ^Device { - return msgSend(^Device, self, "newSharedEventWithHandle:", sharedEventHandle) +Device_newSharedEventWithHandle :: #force_inline proc(self: ^Device, sharedEventHandle: ^SharedEventHandle) -> ^SharedEvent { + return msgSend(^SharedEvent, self, "newSharedEventWithHandle:", sharedEventHandle) } @(objc_type=Device, objc_name="newSharedTextureWithDescriptor") -Device_newSharedTextureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^Device { - return msgSend(^Device, self, "newSharedTextureWithDescriptor:", descriptor) +Device_newSharedTextureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^SharedEvent { + return msgSend(^SharedEvent, self, "newSharedTextureWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newSharedTextureWithHandle") -Device_newSharedTextureWithHandle :: #force_inline proc(self: ^Device, sharedHandle: ^SharedTextureHandle) -> ^Device { - return msgSend(^Device, self, "newSharedTextureWithHandle:", sharedHandle) +Device_newSharedTextureWithHandle :: #force_inline proc(self: ^Device, sharedHandle: ^SharedTextureHandle) -> ^SharedEvent { + return msgSend(^SharedEvent, self, "newSharedTextureWithHandle:", sharedHandle) } @(objc_type=Device, objc_name="newTextureWithDescriptor") -Device_newTextureWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^Device { - return msgSend(^Device, self, "newTextureWithDescriptor:", desc) +Device_newTextureWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^SharedEvent { + return msgSend(^SharedEvent, self, "newTextureWithDescriptor:", desc) } @(objc_type=Device, objc_name="newTextureWithDescriptorWithIOSurface") -Device_newTextureWithDescriptorWithIOSurface :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Device { - return msgSend(^Device, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) +Device_newTextureWithDescriptorWithIOSurface :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Texture { + return msgSend(^Texture, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) } @(objc_type=Device, objc_name="peerCount") Device_peerCount :: #force_inline proc(self: ^Device) -> u32 { diff --git a/core/sys/darwin/QuartzCore/QuartzCore.odin b/core/sys/darwin/QuartzCore/QuartzCore.odin index 49ed51622..0afb8aa37 100644 --- a/core/sys/darwin/QuartzCore/QuartzCore.odin +++ b/core/sys/darwin/QuartzCore/QuartzCore.odin @@ -10,6 +10,11 @@ msgSend :: intrinsics.objc_send @(objc_class="CAMetalLayer") MetalLayer :: struct{ using _: NS.Layer} +@(objc_type=MetalLayer, objc_class_name="layer") +MetalLayer_layer :: proc() -> ^MetalLayer { + return msgSend(^MetalLayer, MetalLayer, "layer") +} + @(objc_type=MetalLayer, objc_name="device") MetalLayer_device :: proc(self: ^MetalLayer) -> ^MTL.Device { return msgSend(^MTL.Device, self, "device") @@ -19,6 +24,7 @@ MetalLayer_setDevice :: proc(self: ^MetalLayer, device: ^MTL.Device) { msgSend(nil, self, "setDevice:", device) } + @(objc_type=MetalLayer, objc_name="opaque") MetalLayer_opaque :: proc(self: ^MetalLayer) -> NS.BOOL { return msgSend(NS.BOOL, self, "opaque") @@ -36,19 +42,46 @@ MetalLayer_preferredDevice :: proc(self: ^MetalLayer) -> ^MTL.Device { MetalLayer_pixelFormat :: proc(self: ^MetalLayer) -> MTL.PixelFormat { return msgSend(MTL.PixelFormat, self, "pixelFormat") } +@(objc_type=MetalLayer, objc_name="setPixelFormat") +MetalLayer_setPixelFormat :: proc(self: ^MetalLayer, pixelFormat: MTL.PixelFormat) { + msgSend(nil, self, "setPixelFormat:", pixelFormat) +} + @(objc_type=MetalLayer, objc_name="framebufferOnly") MetalLayer_framebufferOnly :: proc(self: ^MetalLayer) -> NS.BOOL { return msgSend(NS.BOOL, self, "framebufferOnly") } +@(objc_type=MetalLayer, objc_name="setFramebufferOnly") +MetalLayer_setFramebufferOnly :: proc(self: ^MetalLayer, ok: NS.BOOL) { + msgSend(nil, self, "setFramebufferOnly:", ok) +} + +@(objc_type=MetalLayer, objc_name="frame") +MetalLayer_frame :: proc(self: ^MetalLayer) -> NS.Rect { + return msgSend(NS.Rect, self, "frame") +} +@(objc_type=MetalLayer, objc_name="setFrame") +MetalLayer_setFrame :: proc(self: ^MetalLayer, frame: NS.Rect) { + msgSend(nil, self, "setFrame:", frame) +} + + +@(objc_type=MetalLayer, objc_name="nextDrawable") +MetalLayer_nextDrawable :: proc(self: ^MetalLayer) -> ^MetalDrawable { + return msgSend(^MetalDrawable, self, "nextDrawable") +} + @(objc_class="CAMetalDrawable") MetalDrawable :: struct { using _: MTL.Drawable } +@(objc_type=MetalDrawable, objc_name="layer") MetalDrawable_layer :: proc(self: ^MetalDrawable) -> ^MetalLayer { return msgSend(^MetalLayer, self, "layer") } +@(objc_type=MetalDrawable, objc_name="texture") MetalDrawable_texture :: proc(self: ^MetalDrawable) -> ^MTL.Texture { return msgSend(^MTL.Texture, self, "texture") } \ No newline at end of file From 9dc83bc1b3b9084c80eb672b6de03a039c806228 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Feb 2022 16:32:31 +0000 Subject: [PATCH 0146/1052] Add more methods --- core/sys/darwin/Foundation/NSWindow.odin | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin index 0c64cc8c7..6791db4ef 100644 --- a/core/sys/darwin/Foundation/NSWindow.odin +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -7,6 +7,9 @@ Rect :: struct { width, height: f64, } +@(objc_class="NSColor") +Color :: struct {using _: Object} + @(objc_class="CALayer") Layer :: struct { using _: NS.Object } @@ -28,14 +31,29 @@ Window_contentView :: proc(self: ^Window) -> ^View { Window_frame :: proc(self: ^Window) -> Rect { return msgSend(Rect, self, "frame") } - @(objc_type=Window, objc_name="setFrame") Window_setFrame :: proc(self: ^Window, frame: Rect) { msgSend(nil, self, "setFrame:", frame) } +@(objc_type=Window, objc_name="opaque") +Window_opaque :: proc(self: ^Window) -> NS.BOOL { + return msgSend(NS.BOOL, self, "opaque") +} +@(objc_type=Window, objc_name="setOpaque") +Window_setOpaque :: proc(self: ^Window, ok: NS.BOOL) { + msgSend(nil, self, "setOpaque:", ok) +} +@(objc_type=Window, objc_name="backgroundColor") +Window_backgroundColor :: proc(self: ^Window) -> ^NS.Color { + return msgSend(^NS.Color, self, "backgroundColor") +} +@(objc_type=Window, objc_name="setBackgroundColor") +Window_setBackgroundColor :: proc(self: ^Window, color: ^NS.Color) { + msgSend(nil, self, "setBackgroundColor:", color) +} @(objc_type=View, objc_name="layer") View_layer :: proc(self: ^View) -> ^Layer { From 2958c1d6aa620221ff5896b386f3e35ca4522357 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Feb 2022 16:56:27 +0000 Subject: [PATCH 0147/1052] Add `new` shorthand --- core/sys/darwin/Foundation/NSObject.odin | 3 ++ core/sys/darwin/Foundation/NSWindow.odin | 47 +++++++++++++----------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin index cd0919edd..82d837fb8 100644 --- a/core/sys/darwin/Foundation/NSObject.odin +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -31,6 +31,9 @@ copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Ob return msgSend(^T, self, "copy") } +new :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) { + return init(alloc(T)) +} @(objc_type=Object, objc_name="retain") retain :: proc(self: ^Object) { diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin index 6791db4ef..e109284d1 100644 --- a/core/sys/darwin/Foundation/NSWindow.odin +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -19,6 +19,32 @@ Responder :: struct {using _: Object} @(objc_class="NSView") View :: struct {using _: Responder} +@(objc_type=View, objc_name="layer") +View_layer :: proc(self: ^View) -> ^Layer { + return msgSend(^Layer, self, "layer") +} + +@(objc_type=View, objc_name="setLayer") +View_setLayer :: proc(self: ^View, layer: ^Layer) { + msgSend(nil, self, "setLayer:", layer) +} +@(objc_type=View, objc_name="setSubLayer") +View_setSubLayer :: proc(self: ^View, layer: ^Layer) { + msgSend(nil, self, "setSubLayer:", layer) +} + + +@(objc_type=View, objc_name="wantsLayer") +View_wantsLayer :: proc(self: ^View) -> BOOL { + return msgSend(BOOL, self, "wantsLayer") +} + +@(objc_type=View, objc_name="setWantsLayer") +View_setWantsLayer :: proc(self: ^View, wantsLayer: BOOL) { + msgSend(nil, self, "setWantsLayer:", wantsLayer) +} + + @(objc_class="NSWindow") Window :: struct {using _: Responder} @@ -45,7 +71,6 @@ Window_setOpaque :: proc(self: ^Window, ok: NS.BOOL) { msgSend(nil, self, "setOpaque:", ok) } - @(objc_type=Window, objc_name="backgroundColor") Window_backgroundColor :: proc(self: ^Window) -> ^NS.Color { return msgSend(^NS.Color, self, "backgroundColor") @@ -54,23 +79,3 @@ Window_backgroundColor :: proc(self: ^Window) -> ^NS.Color { Window_setBackgroundColor :: proc(self: ^Window, color: ^NS.Color) { msgSend(nil, self, "setBackgroundColor:", color) } - -@(objc_type=View, objc_name="layer") -View_layer :: proc(self: ^View) -> ^Layer { - return msgSend(^Layer, self, "layer") -} - -@(objc_type=View, objc_name="setLayer") -View_setLayer :: proc(self: ^View, layer: ^Layer) { - msgSend(nil, self, "setLayer:", layer) -} - -@(objc_type=View, objc_name="wantsLayer") -View_wantsLayer :: proc(self: ^View) -> BOOL { - return msgSend(BOOL, self, "wantsLayer") -} - -@(objc_type=View, objc_name="setWantsLayer") -View_setWantsLayer :: proc(self: ^View, wantsLayer: BOOL) { - msgSend(nil, self, "setWantsLayer:", wantsLayer) -} From f56114719081164fb38a700dacc298173b0f34dc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 10:57:29 +0000 Subject: [PATCH 0148/1052] Correct _split_iterator --- core/bytes/bytes.odin | 40 ++++++-------------------- core/strings/strings.odin | 59 ++++++++------------------------------- 2 files changed, 20 insertions(+), 79 deletions(-) diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin index 1bf11e0b0..fb36b2d6e 100644 --- a/core/bytes/bytes.odin +++ b/core/bytes/bytes.odin @@ -219,39 +219,24 @@ split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) -> @private _split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []byte, ok: bool) { - s, n := s, n - - if n == 0 { - return - } - - if sep == nil { + if sep == "" { res = s[:] ok = true s^ = s[len(s):] return } - if n < 0 { - n = count(s^, sep) + 1 - } - - n -= 1 - - i := 0 - for ; i < n; i += 1 { - m := index(s^, sep) - if m < 0 { - break - } + m := index(s^, sep) + if m < 0 { + // not found + res = s[:] + ok = res != "" + s^ = s[len(s):] + } else { res = s[:m+sep_save] ok = true s^ = s[m+len(sep):] - return } - res = s[:] - ok = res != nil - s^ = s[len(s):] return } @@ -260,19 +245,10 @@ split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) { return _split_iterator(s, sep, 0, -1) } -split_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) { - return _split_iterator(s, sep, 0, n) -} - split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) { return _split_iterator(s, sep, len(sep), -1) } -split_after_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) { - return _split_iterator(s, sep, len(sep), n) -} - - index_byte :: proc(s: []byte, c: byte) -> int { for i := 0; i < len(s); i += 1 { diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 67046c669..4daa0bacd 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -298,13 +298,7 @@ split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> @private -_split_iterator :: proc(s: ^string, sep: string, sep_save, n: int) -> (res: string, ok: bool) { - s, n := s, n - - if n == 0 { - return - } - +_split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, ok: bool) { if sep == "" { res = s[:] ok = true @@ -312,44 +306,27 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save, n: int) -> (res: stri return } - if n < 0 { - n = count(s^, sep) + 1 - } - - n -= 1 - - i := 0 - for ; i < n; i += 1 { - m := index(s^, sep) - if m < 0 { - break - } + m := index(s^, sep) + if m < 0 { + // not found + res = s[:] + ok = res != "" + s^ = s[len(s):] + } else { res = s[:m+sep_save] ok = true s^ = s[m+len(sep):] - return } - res = s[:] - ok = res != "" - s^ = s[len(s):] return } split_iterator :: proc(s: ^string, sep: string) -> (string, bool) { - return _split_iterator(s, sep, 0, -1) -} - -split_n_iterator :: proc(s: ^string, sep: string, n: int) -> (string, bool) { - return _split_iterator(s, sep, 0, n) + return _split_iterator(s, sep, 0) } split_after_iterator :: proc(s: ^string, sep: string) -> (string, bool) { - return _split_iterator(s, sep, len(sep), -1) -} - -split_after_n_iterator :: proc(s: ^string, sep: string, n: int) -> (string, bool) { - return _split_iterator(s, sep, len(sep), n) + return _split_iterator(s, sep, len(sep)) } @@ -402,25 +379,13 @@ split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) - split_lines_iterator :: proc(s: ^string) -> (line: string, ok: bool) { sep :: "\n" - line = _split_iterator(s, sep, 0, -1) or_return - return _trim_cr(line), true -} - -split_lines_n_iterator :: proc(s: ^string, n: int) -> (line: string, ok: bool) { - sep :: "\n" - line = _split_iterator(s, sep, 0, n) or_return + line = _split_iterator(s, sep, 0) or_return return _trim_cr(line), true } split_lines_after_iterator :: proc(s: ^string) -> (line: string, ok: bool) { sep :: "\n" - line = _split_iterator(s, sep, len(sep), -1) or_return - return _trim_cr(line), true -} - -split_lines_after_n_iterator :: proc(s: ^string, n: int) -> (line: string, ok: bool) { - sep :: "\n" - line = _split_iterator(s, sep, len(sep), n) or_return + line = _split_iterator(s, sep, len(sep)) or_return return _trim_cr(line), true } From 441365b3886967465da4f9201e8dfdfc059931e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 10:58:01 +0000 Subject: [PATCH 0149/1052] Set the macOS minimum version to 12 for ARM CPUs --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index fe56d451f..27c71c8eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -485,7 +485,7 @@ i32 linker_stage(lbGenerator *gen) { // NOTE: If you change this (although this minimum is as low as you can go with Odin working) // make sure to also change the 'mtriple' param passed to 'opt' #if defined(GB_CPU_ARM) - " -mmacosx-version-min=11.0.0 " + " -mmacosx-version-min=12.0.0 " #else " -mmacosx-version-min=10.8.0 " #endif From 2e7157ae9cd0eb38133a750e7f4845661d8751ba Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 11:01:34 +0000 Subject: [PATCH 0150/1052] Correct bytes._split_iterator --- core/bytes/bytes.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin index fb36b2d6e..09a3ed259 100644 --- a/core/bytes/bytes.odin +++ b/core/bytes/bytes.odin @@ -218,8 +218,8 @@ split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) -> @private -_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []byte, ok: bool) { - if sep == "" { +_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save: int) -> (res: []byte, ok: bool) { + if len(sep) == 0 { res = s[:] ok = true s^ = s[len(s):] @@ -230,7 +230,7 @@ _split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []by if m < 0 { // not found res = s[:] - ok = res != "" + ok = len(res) != 0 s^ = s[len(s):] } else { res = s[:m+sep_save] @@ -242,11 +242,11 @@ _split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []by split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) { - return _split_iterator(s, sep, 0, -1) + return _split_iterator(s, sep, 0) } split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) { - return _split_iterator(s, sep, len(sep), -1) + return _split_iterator(s, sep, len(sep)) } From c34ae884ad411de4e98bad48445f6e77ef9abe2d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 11:04:29 +0000 Subject: [PATCH 0151/1052] Change to "object" --- core/sys/darwin/Metal/MetalClasses.odin | 86 ++++++++++++------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index f2652d19b..6abf923ae 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -676,8 +676,8 @@ AttributeDescriptorArray_alloc :: #force_inline proc() -> ^AttributeDescriptorAr AttributeDescriptorArray_init :: #force_inline proc(self: ^AttributeDescriptorArray) -> ^AttributeDescriptorArray { return msgSend(^AttributeDescriptorArray, self, "init") } -@(objc_type=AttributeDescriptorArray, objc_name="objectAtIndexedSubscript") -AttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^AttributeDescriptorArray, index: NS.UInteger) -> ^AttributeDescriptor { +@(objc_type=AttributeDescriptorArray, objc_name="object") +AttributeDescriptorArray_object :: #force_inline proc(self: ^AttributeDescriptorArray, index: NS.UInteger) -> ^AttributeDescriptor { return msgSend(^AttributeDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=AttributeDescriptorArray, objc_name="setObject") @@ -824,8 +824,8 @@ BlitPassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^ BlitPassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray) -> ^BlitPassSampleBufferAttachmentDescriptorArray { return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, self, "init") } -@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -BlitPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^BlitPassSampleBufferAttachmentDescriptor { +@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="object") +BlitPassSampleBufferAttachmentDescriptorArray_object :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") @@ -908,8 +908,8 @@ BufferLayoutDescriptorArray_alloc :: #force_inline proc() -> ^BufferLayoutDescri BufferLayoutDescriptorArray_init :: #force_inline proc(self: ^BufferLayoutDescriptorArray) -> ^BufferLayoutDescriptorArray { return msgSend(^BufferLayoutDescriptorArray, self, "init") } -@(objc_type=BufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") -BufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^BufferLayoutDescriptorArray, index: NS.UInteger) -> ^BufferLayoutDescriptor { +@(objc_type=BufferLayoutDescriptorArray, objc_name="object") +BufferLayoutDescriptorArray_object :: #force_inline proc(self: ^BufferLayoutDescriptorArray, index: NS.UInteger) -> ^BufferLayoutDescriptor { return msgSend(^BufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=BufferLayoutDescriptorArray, objc_name="setObject") @@ -1303,8 +1303,8 @@ ComputePassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() - ComputePassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray) -> ^ComputePassSampleBufferAttachmentDescriptorArray { return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, self, "init") } -@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -ComputePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^ComputePassSampleBufferAttachmentDescriptor { +@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="object") +ComputePassSampleBufferAttachmentDescriptorArray_object :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") @@ -2178,8 +2178,8 @@ PipelineBufferDescriptorArray_alloc :: #force_inline proc() -> ^PipelineBufferDe PipelineBufferDescriptorArray_init :: #force_inline proc(self: ^PipelineBufferDescriptorArray) -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, self, "init") } -@(objc_type=PipelineBufferDescriptorArray, objc_name="objectAtIndexedSubscript") -PipelineBufferDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^PipelineBufferDescriptorArray, bufferIndex: NS.UInteger) -> ^PipelineBufferDescriptor { +@(objc_type=PipelineBufferDescriptorArray, objc_name="object") +PipelineBufferDescriptorArray_object :: #force_inline proc(self: ^PipelineBufferDescriptorArray, bufferIndex: NS.UInteger) -> ^PipelineBufferDescriptor { return msgSend(^PipelineBufferDescriptor, self, "objectAtIndexedSubscript:", bufferIndex) } @(objc_type=PipelineBufferDescriptorArray, objc_name="setObject") @@ -2304,8 +2304,8 @@ RasterizationRateLayerArray_alloc :: #force_inline proc() -> ^RasterizationRateL RasterizationRateLayerArray_init :: #force_inline proc(self: ^RasterizationRateLayerArray) -> ^RasterizationRateLayerArray { return msgSend(^RasterizationRateLayerArray, self, "init") } -@(objc_type=RasterizationRateLayerArray, objc_name="objectAtIndexedSubscript") -RasterizationRateLayerArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateLayerArray, layerIndex: NS.UInteger) -> ^RasterizationRateLayerDescriptor { +@(objc_type=RasterizationRateLayerArray, objc_name="object") +RasterizationRateLayerArray_object :: #force_inline proc(self: ^RasterizationRateLayerArray, layerIndex: NS.UInteger) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "objectAtIndexedSubscript:", layerIndex) } @(objc_type=RasterizationRateLayerArray, objc_name="setObject") @@ -2470,8 +2470,8 @@ RasterizationRateSampleArray_alloc :: #force_inline proc() -> ^RasterizationRate RasterizationRateSampleArray_init :: #force_inline proc(self: ^RasterizationRateSampleArray) -> ^RasterizationRateSampleArray { return msgSend(^RasterizationRateSampleArray, self, "init") } -@(objc_type=RasterizationRateSampleArray, objc_name="objectAtIndexedSubscript") -RasterizationRateSampleArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RasterizationRateSampleArray, index: NS.UInteger) -> NS.UInteger { +@(objc_type=RasterizationRateSampleArray, objc_name="object") +RasterizationRateSampleArray_object :: #force_inline proc(self: ^RasterizationRateSampleArray, index: NS.UInteger) -> NS.UInteger { return msgSend(NS.UInteger, self, "objectAtIndexedSubscript:", index) } @(objc_type=RasterizationRateSampleArray, objc_name="setObject") @@ -2979,8 +2979,8 @@ RenderPassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> RenderPassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray) -> ^RenderPassSampleBufferAttachmentDescriptorArray { return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, self, "init") } -@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPassSampleBufferAttachmentDescriptor { +@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="object") +RenderPassSampleBufferAttachmentDescriptorArray_object :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="setObject") @@ -3165,8 +3165,8 @@ RenderPipelineColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^R RenderPipelineColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray) -> ^RenderPipelineColorAttachmentDescriptorArray { return msgSend(^RenderPipelineColorAttachmentDescriptorArray, self, "init") } -@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -RenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPipelineColorAttachmentDescriptor { +@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="object") +RenderPipelineColorAttachmentDescriptorArray_object :: #force_inline proc(self: ^RenderPipelineColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^RenderPipelineColorAttachmentDescriptor { return msgSend(^RenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") @@ -3580,8 +3580,8 @@ ResourceStatePassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline pr ResourceStatePassSampleBufferAttachmentDescriptorArray_init :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray) -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, self, "init") } -@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -ResourceStatePassSampleBufferAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="object") +ResourceStatePassSampleBufferAttachmentDescriptorArray_object :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="setObject") @@ -4374,8 +4374,8 @@ TileRenderPipelineColorAttachmentDescriptorArray_alloc :: #force_inline proc() - TileRenderPipelineColorAttachmentDescriptorArray_init :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray) -> ^TileRenderPipelineColorAttachmentDescriptorArray { return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, self, "init") } -@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="objectAtIndexedSubscript") -TileRenderPipelineColorAttachmentDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^TileRenderPipelineColorAttachmentDescriptor { +@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="object") +TileRenderPipelineColorAttachmentDescriptorArray_object :: #force_inline proc(self: ^TileRenderPipelineColorAttachmentDescriptorArray, attachmentIndex: NS.UInteger) -> ^TileRenderPipelineColorAttachmentDescriptor { return msgSend(^TileRenderPipelineColorAttachmentDescriptor, self, "objectAtIndexedSubscript:", attachmentIndex) } @(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="setObject") @@ -4634,8 +4634,8 @@ VertexAttributeDescriptorArray_alloc :: #force_inline proc() -> ^VertexAttribute VertexAttributeDescriptorArray_init :: #force_inline proc(self: ^VertexAttributeDescriptorArray) -> ^VertexAttributeDescriptorArray { return msgSend(^VertexAttributeDescriptorArray, self, "init") } -@(objc_type=VertexAttributeDescriptorArray, objc_name="objectAtIndexedSubscript") -VertexAttributeDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexAttributeDescriptorArray, index: NS.UInteger) -> ^VertexAttributeDescriptor { +@(objc_type=VertexAttributeDescriptorArray, objc_name="object") +VertexAttributeDescriptorArray_object :: #force_inline proc(self: ^VertexAttributeDescriptorArray, index: NS.UInteger) -> ^VertexAttributeDescriptor { return msgSend(^VertexAttributeDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=VertexAttributeDescriptorArray, objc_name="setObject") @@ -4718,8 +4718,8 @@ VertexBufferLayoutDescriptorArray_alloc :: #force_inline proc() -> ^VertexBuffer VertexBufferLayoutDescriptorArray_init :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray) -> ^VertexBufferLayoutDescriptorArray { return msgSend(^VertexBufferLayoutDescriptorArray, self, "init") } -@(objc_type=VertexBufferLayoutDescriptorArray, objc_name="objectAtIndexedSubscript") -VertexBufferLayoutDescriptorArray_objectAtIndexedSubscript :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, index: NS.UInteger) -> ^VertexBufferLayoutDescriptor { +@(objc_type=VertexBufferLayoutDescriptorArray, objc_name="object") +VertexBufferLayoutDescriptorArray_object :: #force_inline proc(self: ^VertexBufferLayoutDescriptorArray, index: NS.UInteger) -> ^VertexBufferLayoutDescriptor { return msgSend(^VertexBufferLayoutDescriptor, self, "objectAtIndexedSubscript:", index) } @(objc_type=VertexBufferLayoutDescriptorArray, objc_name="setObject") @@ -7007,7 +7007,7 @@ IndirectRenderCommand_drawPatches :: #force_inline proc(self: ^IndirectRenderCom msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawPrimitives") -IndirectRenderCommand_drawPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { +IndirectRenderCommand_drawPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger = 0, baseInstance: NS.UInteger = 0) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } @(objc_type=IndirectRenderCommand, objc_name="reset") @@ -7104,8 +7104,8 @@ Methods: Library :: struct { using _: NS.Object } @(objc_type=Library, objc_name="device") -Library_device :: #force_inline proc(self: ^Library) -> ^Library { - return msgSend(^Library, self, "device") +Library_device :: #force_inline proc(self: ^Library) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=Library, objc_name="functionNames") Library_functionNames :: #force_inline proc(self: ^Library) -> ^NS.Array { @@ -7120,34 +7120,34 @@ Library_label :: #force_inline proc(self: ^Library) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Library, objc_name="newFunctionWithDescriptorWithCompletionHandler") -Library_newFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) { - msgSend(nil, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) +Library_newFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) -> ^Function { + return msgSend(^Function, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithDescriptor") -Library_newFunctionWithDescriptor :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { - library = msgSend(^Library, self, "newFunctionWithDescriptor:error:", descriptor, &error) +Library_newFunctionWithDescriptor :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor) -> (function: ^Function, error: ^NS.Error) { + function = msgSend(^Function, self, "newFunctionWithDescriptor:error:", descriptor, &error) return } @(objc_type=Library, objc_name="newFunctionWithName") -Library_newFunctionWithName :: #force_inline proc(self: ^Library, functionName: ^NS.String) -> ^Library { - return msgSend(^Library, self, "newFunctionWithName:", functionName) +Library_newFunctionWithName :: #force_inline proc(self: ^Library, functionName: ^NS.String) -> ^Function { + return msgSend(^Function, self, "newFunctionWithName:", functionName) } @(objc_type=Library, objc_name="newFunctionWithNameWithConstantValuesAndCompletionHandler") -Library_newFunctionWithNameWithConstantValuesAndCompletionHandler :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) { - msgSend(nil, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) +Library_newFunctionWithNameWithConstantValuesAndCompletionHandler :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) -> ^Function { + return msgSend(^Function, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithNameWithConstantValues") -Library_newFunctionWithNameWithConstantValues :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues) -> (library: ^Library, error: ^NS.Error) { - library = msgSend(^Library, self, "newFunctionWithName:constantValues:error:", name, constantValues, &error) +Library_newFunctionWithNameWithConstantValues :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues) -> (function: ^Function, error: ^NS.Error) { + function = msgSend(^Function, self, "newFunctionWithName:constantValues:error:", name, constantValues, &error) return } @(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptorWithCompletionHandler") -Library_newIntersectionFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) { - msgSend(nil, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) +Library_newIntersectionFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) -> ^Function { + return msgSend(^Function, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor") -Library_newIntersectionFunctionWithDescriptor :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor) -> (library: ^Library, error: ^NS.Error) { - library = msgSend(^Library, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, &error) +Library_newIntersectionFunctionWithDescriptor :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor) -> (function: ^Function, error: ^NS.Error) { + function = msgSend(^Function, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, &error) return } @(objc_type=Library, objc_name="setLabel") From 7386ca9272c527800720c0dd53a9ad351345aa41 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 11:21:21 +0000 Subject: [PATCH 0152/1052] Add new objc intrinsics: objc_(register|find)_(selector|class) --- core/sys/darwin/Foundation/NSObject.odin | 2 +- src/check_builtin.cpp | 28 ++++- src/checker_builtin_procs.hpp | 11 +- src/llvm_backend.cpp | 5 +- src/llvm_backend_proc.cpp | 8 +- src/llvm_backend_utility.cpp | 133 +++++++++++++++++------ 6 files changed, 140 insertions(+), 47 deletions(-) diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin index 82d837fb8..55d87a14b 100644 --- a/core/sys/darwin/Foundation/NSObject.odin +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -70,7 +70,7 @@ description :: proc(self: ^Object) -> ^String { @(objc_type=Object, objc_name="debugDescription") debugDescription :: proc(self: ^Object) -> ^String { - if msgSendSafeCheck(self, intrinsics.objc_selector_name("debugDescription")) { + if msgSendSafeCheck(self, intrinsics.objc_find_selector("debugDescription")) { return msgSend(^String, self, "debugDescription") } return nil diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a9ee5d25f..a6b1759f5 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -348,13 +348,27 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call return true; } break; - case BuiltinProc_objc_selector_name: { + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_selector: + case BuiltinProc_objc_register_class: + { String sel_name = {}; if (!is_constant_string(c, builtin_name, ce->args[0], &sel_name)) { return false; } - operand->type = t_objc_SEL; + switch (id) { + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_register_selector: + operand->type = t_objc_SEL; + break; + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_class: + operand->type = t_objc_Class; + break; + + } operand->mode = Addressing_Value; return true; } break; @@ -398,7 +412,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_max: case BuiltinProc_type_is_subtype_of: case BuiltinProc_objc_send: - case BuiltinProc_objc_selector_name: + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_selector: + case BuiltinProc_objc_register_class: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -440,7 +457,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; case BuiltinProc_objc_send: - case BuiltinProc_objc_selector_name: + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_selector: + case BuiltinProc_objc_register_class: return check_builtin_objc_procedure(c, operand, call, id, type_hint); case BuiltinProc___entry_point: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c14c18412..19fa94ee6 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -253,7 +253,10 @@ BuiltinProc__type_end, BuiltinProc___entry_point, BuiltinProc_objc_send, - BuiltinProc_objc_selector_name, + BuiltinProc_objc_find_selector, + BuiltinProc_objc_find_class, + BuiltinProc_objc_register_selector, + BuiltinProc_objc_register_class, BuiltinProc_COUNT, }; @@ -509,5 +512,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("objc_selector_name"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("objc_find_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, }; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7941c65a3..52c46cadc 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -672,12 +672,14 @@ void lb_finalize_objc_names(lbProcedure *p) { lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); + + auto args = array_make(permanent_allocator(), 1); + LLVMSetLinkage(p->value, LLVMInternalLinkage); lb_begin_procedure_body(p); for_array(i, m->objc_classes.entries) { auto const &entry = m->objc_classes.entries[i]; String name = entry.key.string; - auto args = array_make(permanent_allocator(), 1); args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); lb_addr_store(p, entry.value, ptr); @@ -686,7 +688,6 @@ void lb_finalize_objc_names(lbProcedure *p) { for_array(i, m->objc_selectors.entries) { auto const &entry = m->objc_selectors.entries[i]; String name = entry.key.string; - auto args = array_make(permanent_allocator(), 1); args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); lb_addr_store(p, entry.value, ptr); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index caa3dfa1a..2a0380605 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2108,10 +2108,12 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_objc_send: - return lb_handle_obj_send(p, expr); + return lb_handle_objc_send(p, expr); - case BuiltinProc_objc_selector_name: - return lb_handle_obj_selector_name(p, expr); + case BuiltinProc_objc_find_selector: return lb_handle_objc_find_selector(p, expr); + case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr); + case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr); + case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 8ef66df7a..75fb89314 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1823,7 +1823,101 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) { lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name); -lbValue lb_handle_obj_id(lbProcedure *p, Ast *expr) { + +lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) { + lbAddr *found = string_map_get(&p->module->objc_selectors, name); + if (found) { + return *found; + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_selectors, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_selectors, name, local_addr); + } + return local_addr; + } +} + +lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + return lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, name)); +} + +lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + lbModule *m = p->module; + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + lbAddr dst = lb_handle_objc_find_or_register_selector(p, name); + + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); + lb_addr_store(p, dst, ptr); + + return lb_addr_load(p, dst); +} + +lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) { + lbAddr *found = string_map_get(&p->module->objc_classes, name); + if (found) { + return *found; + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_classes, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_classes, name, local_addr); + } + return local_addr; + } +} + +lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name)); +} + +lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + lbModule *m = p->module; + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + lbAddr dst = lb_handle_objc_find_or_register_class(p, name); + + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); + lb_addr_store(p, dst, ptr); + + return lb_addr_load(p, dst); +} + + +lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) { TypeAndValue const &tav = type_and_value_of_expr(expr); if (tav.mode == Addressing_Type) { Type *type = tav.type; @@ -1854,29 +1948,7 @@ lbValue lb_handle_obj_id(lbProcedure *p, Ast *expr) { return lb_build_expr(p, expr); } - -lbValue lb_handle_obj_selector(lbProcedure *p, String const &name) { - lbAddr *found = string_map_get(&p->module->objc_selectors, name); - if (found) { - return lb_addr_load(p, *found); - } else { - lbModule *default_module = &p->module->gen->default_module; - Entity *e = nullptr; - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); - - lbValue ptr = lb_find_value_from_entity(p->module, e); - lbAddr local_addr = lb_addr(ptr); - - string_map_set(&default_module->objc_selectors, name, default_addr); - if (default_module != p->module) { - string_map_set(&p->module->objc_selectors, name, local_addr); - } - return lb_addr_load(p, local_addr); - } -} - - -lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { +lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); lbModule *m = p->module; @@ -1887,10 +1959,10 @@ lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { GB_ASSERT(ce->args.count >= 3); auto args = array_make(permanent_allocator(), 0, ce->args.count-1); - lbValue id = lb_handle_obj_id(p, ce->args[1]); + lbValue id = lb_handle_objc_id(p, ce->args[1]); Ast *sel_expr = ce->args[2]; GB_ASSERT(sel_expr->tav.value.kind == ExactValue_String); - lbValue sel = lb_handle_obj_selector(p, sel_expr->tav.value.value_string); + lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, sel_expr->tav.value.value_string)); array_add(&args, id); array_add(&args, sel); @@ -1917,12 +1989,3 @@ lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { } -lbValue lb_handle_obj_selector_name(lbProcedure *p, Ast *expr) { - ast_node(ce, CallExpr, expr); - - auto tav = ce->args[0]->tav; - GB_ASSERT(tav.value.kind == ExactValue_String); - String name = tav.value.value_string; - return lb_handle_obj_selector(p, name); - -} \ No newline at end of file From ff7d591ebf7cf63f94c8e1f0f9c81c1475c90593 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 11:55:59 +0000 Subject: [PATCH 0153/1052] Correct AccelerationStructure classes --- core/sys/darwin/Metal/MetalClasses.odin | 264 ++++++++++++++++++++++-- core/sys/darwin/Metal/MetalEnums.odin | 11 + 2 files changed, 253 insertions(+), 22 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 6abf923ae..49f31bae9 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -33,8 +33,8 @@ AccelerationStructureBoundingBoxGeometryDescriptor_init :: #force_inline proc(se return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, self, "init") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxBuffer") -AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^AccelerationStructureBoundingBoxGeometryDescriptor { - return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, self, "boundingBoxBuffer") +AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBuffer :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "boundingBoxBuffer") } @(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="boundingBoxBufferOffset") AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxBufferOffset :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { @@ -117,6 +117,138 @@ MotionKeyframeData_setOffset :: #force_inline proc(self: ^MotionKeyframeData, of msgSend(nil, self, "setOffset:", offset) } +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructureMotionTriangleGeometryDescriptor +*/ + +@(objc_class="MTLAccelerationStructureMotionTriangleGeometryDescriptor") +AccelerationStructureMotionTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionTriangleGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } + +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_class_name="alloc") +AccelerationStructureMotionTriangleGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureMotionTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureMotionTriangleGeometryDescriptor, AccelerationStructureMotionTriangleGeometryDescriptor, "alloc") +} +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="init") +AccelerationStructureMotionTriangleGeometryDescriptor_init :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor) -> ^AccelerationStructureMotionTriangleGeometryDescriptor { + return msgSend(^AccelerationStructureMotionTriangleGeometryDescriptor, self, "init") +} + +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="vertexBuffers") +AccelerationStructureMotionTriangleGeometryDescriptor_vertexBuffers :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "vertexBuffers") +} +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="setVertexBuffers") +AccelerationStructureMotionTriangleGeometryDescriptor_setVertexBuffers :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor, buffers: ^NS.Array) { + msgSend(nil, self, "setVertexBuffers:", buffers) +} + +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="vertexStride") +AccelerationStructureMotionTriangleGeometryDescriptor_vertexStride :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "vertexStride") +} +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="setVertexStride") +AccelerationStructureMotionTriangleGeometryDescriptor_setVertexStride :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor, stride: NS.UInteger) { + msgSend(nil, self, "setVertexStride:", stride) +} + + +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="indexBuffer") +AccelerationStructureMotionTriangleGeometryDescriptor_indexBuffer :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "indexBuffer") +} +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="setIndexBuffer") +AccelerationStructureMotionTriangleGeometryDescriptor_setIndexBuffer :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor, buffer: ^Buffer) { + msgSend(nil, self, "setIndexBuffer:", buffer) +} + + +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="indexBufferOffset") +AccelerationStructureMotionTriangleGeometryDescriptor_indexBufferOffset :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "indexBufferOffset") +} +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="setIndexBufferOffset") +AccelerationStructureMotionTriangleGeometryDescriptor_setIndexBufferOffset :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor, offset: NS.UInteger) { + msgSend(nil, self, "setIndexBufferOffset:", offset) +} + +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="indexType") +AccelerationStructureMotionTriangleGeometryDescriptor_indexType :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor) -> IndexType { + return msgSend(IndexType, self, "indexType") +} +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="setIndexType") +AccelerationStructureMotionTriangleGeometryDescriptor_setIndexType :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor, indexType: IndexType) { + msgSend(nil, self, "setIndexType:", indexType) +} + +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="triangleCount") +AccelerationStructureMotionTriangleGeometryDescriptor_triangleCount :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "triangleCount") +} +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="setTriangleCount") +AccelerationStructureMotionTriangleGeometryDescriptor_setTriangleCount :: #force_inline proc(self: ^AccelerationStructureMotionTriangleGeometryDescriptor, count: NS.UInteger) { + msgSend(nil, self, "setTriangleCount:", count) +} + +//////////////////////////////////////////////////////////////////////////////// + +/* +Class: + AccelerationStructureMotionBoundingBoxGeometryDescriptor +*/ + +@(objc_class="MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor") +AccelerationStructureMotionBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionBoundingBoxGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } + +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_class_name="alloc") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureMotionBoundingBoxGeometryDescriptor { + return msgSend(^AccelerationStructureMotionBoundingBoxGeometryDescriptor, AccelerationStructureMotionBoundingBoxGeometryDescriptor, "alloc") +} +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="init") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_init :: #force_inline proc(self: ^AccelerationStructureMotionBoundingBoxGeometryDescriptor) -> ^AccelerationStructureMotionBoundingBoxGeometryDescriptor { + return msgSend(^AccelerationStructureMotionBoundingBoxGeometryDescriptor, self, "init") +} + +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_class_name="descriptor") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_descriptor :: #force_inline proc() -> ^AccelerationStructureMotionBoundingBoxGeometryDescriptor { + return msgSend(^AccelerationStructureMotionBoundingBoxGeometryDescriptor, AccelerationStructureMotionBoundingBoxGeometryDescriptor, "descriptor") +} + +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="boundingBoxBuffers") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_boundingBoxBuffers :: #force_inline proc(self: ^AccelerationStructureMotionBoundingBoxGeometryDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "boundingBoxBuffers") +} +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="setBoundBoxBuffers") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_setBoundBoxBuffers :: #force_inline proc(self: ^AccelerationStructureMotionBoundingBoxGeometryDescriptor, buffers: ^NS.Array) { + msgSend(nil, self, "setBoundBoxBuffers:", buffers) +} + +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="boundingBoxStride") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_boundingBoxStride :: #force_inline proc(self: ^AccelerationStructureMotionBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxStride") +} +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxStride") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_setBoundingBoxStride :: #force_inline proc(self: ^AccelerationStructureMotionBoundingBoxGeometryDescriptor, stride: NS.UInteger) { + msgSend(nil, self, "setBoundingBoxStride:", stride) +} + +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="boundingBoxCount") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_boundingBoxCount :: #force_inline proc(self: ^AccelerationStructureMotionBoundingBoxGeometryDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "boundingBoxCount") +} +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="setBoundingBoxCount") +AccelerationStructureMotionBoundingBoxGeometryDescriptor_setBoundingBoxCount :: #force_inline proc(self: ^AccelerationStructureMotionBoundingBoxGeometryDescriptor, offset: NS.UInteger) { + msgSend(nil, self, "setBoundingBoxCount:", offset) +} + + + + + + + //////////////////////////////////////////////////////////////////////////////// /* @@ -242,8 +374,8 @@ AccelerationStructureTriangleGeometryDescriptor_descriptor :: #force_inline proc return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "descriptor") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexBuffer") -AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { - return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "indexBuffer") +AccelerationStructureTriangleGeometryDescriptor_indexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "indexBuffer") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="indexBufferOffset") AccelerationStructureTriangleGeometryDescriptor_indexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { @@ -286,8 +418,8 @@ AccelerationStructureTriangleGeometryDescriptor_triangleCount :: #force_inline p return msgSend(NS.UInteger, self, "triangleCount") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBuffer") -AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { - return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "vertexBuffer") +AccelerationStructureTriangleGeometryDescriptor_vertexBuffer :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "vertexBuffer") } @(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="vertexBufferOffset") AccelerationStructureTriangleGeometryDescriptor_vertexBufferOffset :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> NS.UInteger { @@ -781,8 +913,8 @@ BlitPassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inlin return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^BlitPassSampleBufferAttachmentDescriptor { - return msgSend(^BlitPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "sampleBuffer") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") BlitPassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { @@ -1260,8 +1392,8 @@ ComputePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_in return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^ComputePassSampleBufferAttachmentDescriptor { - return msgSend(^ComputePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "sampleBuffer") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") ComputePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { @@ -1993,8 +2125,8 @@ InstanceAccelerationStructureDescriptor_instanceCount :: #force_inline proc(self return msgSend(NS.UInteger, self, "instanceCount") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBuffer") -InstanceAccelerationStructureDescriptor_instanceDescriptorBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { - return msgSend(^InstanceAccelerationStructureDescriptor, self, "instanceDescriptorBuffer") +InstanceAccelerationStructureDescriptor_instanceDescriptorBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "instanceDescriptorBuffer") } @(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorBufferOffset") InstanceAccelerationStructureDescriptor_instanceDescriptorBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.UInteger { @@ -2029,6 +2161,46 @@ InstanceAccelerationStructureDescriptor_setInstancedAccelerationStructures :: #f msgSend(nil, self, "setInstancedAccelerationStructures:", instancedAccelerationStructures) } +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="instanceDescriptorType") +InstanceAccelerationStructureDescriptor_instanceDescriptorType :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> AccelerationStructureInstanceDescriptorType { + return msgSend(AccelerationStructureInstanceDescriptorType, self, "instanceDescriptorType") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setInstanceDescriptorType") +InstanceAccelerationStructureDescriptor_setInstanceDescriptorType :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, buffer: AccelerationStructureInstanceDescriptorType) { + msgSend(nil, self, "setInstanceDescriptorType:", buffer) +} + + +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="motionTransformBuffer") +InstanceAccelerationStructureDescriptor_motionTransformBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "motionTransformBuffer") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setMotionTransformBuffer") +InstanceAccelerationStructureDescriptor_setMotionTransformBuffer :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, buffer: ^Buffer) { + msgSend(nil, self, "setMotionTransformBuffer:", buffer) +} + + +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="motionTransformBufferOffset") +InstanceAccelerationStructureDescriptor_motionTransformBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "motionTransformBufferOffset") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setMotionTransformBufferOffset") +InstanceAccelerationStructureDescriptor_setMotionTransformBufferOffset :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, offset: NS.UInteger) { + msgSend(nil, self, "setMotionTransformBufferOffset:", offset) +} + +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="motionTransformCount") +InstanceAccelerationStructureDescriptor_motionTransformCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "motionTransformCount") +} +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="setMotionTransformCount") +InstanceAccelerationStructureDescriptor_setMotionTransformCount :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor, offset: NS.UInteger) { + msgSend(nil, self, "setMotionTransformCount:", offset) +} + + + //////////////////////////////////////////////////////////////////////////////// /* @@ -2281,6 +2453,54 @@ PrimitiveAccelerationStructureDescriptor_setGeometryDescriptors :: #force_inline msgSend(nil, self, "setGeometryDescriptors:", geometryDescriptors) } +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="motionStartBorderMode") +PrimitiveAccelerationStructureDescriptor_motionStartBorderMode :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> MotionBorderMode { + return msgSend(MotionBorderMode, self, "motionStartBorderMode") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="setMotionStartBorderMode") +PrimitiveAccelerationStructureDescriptor_setMotionStartBorderMode :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor, motionStartBorderMode: MotionBorderMode) { + msgSend(nil, self, "setMotionStartBorderMode:", motionStartBorderMode) +} + +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="motionEndBorderMode") +PrimitiveAccelerationStructureDescriptor_motionEndBorderMode :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> MotionBorderMode { + return msgSend(MotionBorderMode, self, "motionEndBorderMode") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="setMotionEndBorderMode") +PrimitiveAccelerationStructureDescriptor_setMotionEndBorderMode :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor, motionEndBorderMode: MotionBorderMode) { + msgSend(nil, self, "setMotionEndBorderMode:", motionEndBorderMode) +} + +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="motionStartTime") +PrimitiveAccelerationStructureDescriptor_motionStartTime :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> f32 { + return msgSend(f32, self, "motionStartTime") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="setMotionStartTime") +PrimitiveAccelerationStructureDescriptor_setMotionStartTime :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor, motionStartTime: f32) { + msgSend(nil, self, "setMotionStartTime:", motionStartTime) +} + + +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="motionEndTime") +PrimitiveAccelerationStructureDescriptor_motionEndTime :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> f32 { + return msgSend(f32, self, "motionEndTime") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="setMotionEndTime") +PrimitiveAccelerationStructureDescriptor_setMotionEndTime :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor, motionEndTime: f32) { + msgSend(nil, self, "setMotionEndTime:", motionEndTime) +} + +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="motionKeyframeCount") +PrimitiveAccelerationStructureDescriptor_motionKeyframeCount :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "motionKeyframeCount") +} +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="setMotionKeyframeCount") +PrimitiveAccelerationStructureDescriptor_setMotionKeyframeCount :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor, motionKeyframeCount: NS.UInteger) { + msgSend(nil, self, "setMotionKeyframeCount:", motionKeyframeCount) +} + + + //////////////////////////////////////////////////////////////////////////////// /* @@ -2880,8 +3100,8 @@ RenderPassDescriptor_tileWidth :: #force_inline proc(self: ^RenderPassDescriptor return msgSend(NS.UInteger, self, "tileWidth") } @(objc_type=RenderPassDescriptor, objc_name="visibilityResultBuffer") -RenderPassDescriptor_visibilityResultBuffer :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { - return msgSend(^RenderPassDescriptor, self, "visibilityResultBuffer") +RenderPassDescriptor_visibilityResultBuffer :: #force_inline proc(self: ^RenderPassDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "visibilityResultBuffer") } //////////////////////////////////////////////////////////////////////////////// @@ -2924,8 +3144,8 @@ RenderPassSampleBufferAttachmentDescriptor_endOfVertexSampleIndex :: #force_inli return msgSend(NS.UInteger, self, "endOfVertexSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^RenderPassSampleBufferAttachmentDescriptor { - return msgSend(^RenderPassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "sampleBuffer") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfFragmentSampleIndex") RenderPassSampleBufferAttachmentDescriptor_setEndOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfFragmentSampleIndex: NS.UInteger) { @@ -3537,8 +3757,8 @@ ResourceStatePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #fo return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^ResourceStatePassSampleBufferAttachmentDescriptor { - return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, self, "sampleBuffer") +ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^Buffer { + return msgSend(^Buffer, self, "sampleBuffer") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") ResourceStatePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { @@ -4985,11 +5205,11 @@ ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEn msgSend(nil, self, "setComputePipelineStates:withRange:", pipelines, range) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffer") -ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^Buffer, index: NS.UInteger) { +ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^IndirectCommandBuffer, index: NS.UInteger) { msgSend(nil, self, "setIndirectCommandBuffer:atIndex:", indirectCommandBuffer, index) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffers") -ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: [^]^Buffer, range: NS.Range) { +ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: [^]^IndirectCommandBuffer, range: NS.Range) { msgSend(nil, self, "setIndirectCommandBuffers:withRange:", buffers, range) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTable") @@ -7980,8 +8200,8 @@ Texture_arrayLength :: #force_inline proc(self: ^Texture) -> NS.UInteger { return msgSend(NS.UInteger, self, "arrayLength") } @(objc_type=Texture, objc_name="buffer") -Texture_buffer :: #force_inline proc(self: ^Texture) -> ^Texture { - return msgSend(^Texture, self, "buffer") +Texture_buffer :: #force_inline proc(self: ^Texture) -> ^Buffer { + return msgSend(^Buffer, self, "buffer") } @(objc_type=Texture, objc_name="bufferBytesPerRow") Texture_bufferBytesPerRow :: #force_inline proc(self: ^Texture) -> NS.UInteger { diff --git a/core/sys/darwin/Metal/MetalEnums.odin b/core/sys/darwin/Metal/MetalEnums.odin index 0e3aec321..47059ee66 100644 --- a/core/sys/darwin/Metal/MetalEnums.odin +++ b/core/sys/darwin/Metal/MetalEnums.odin @@ -17,6 +17,17 @@ AccelerationStructureInstanceOption :: enum u32 { NonOpaque = 3, } +MotionBorderMode :: enum u32 { + Clamp = 0, + Vanish = 1, +} + +AccelerationStructureInstanceDescriptorType :: enum NS.UInteger { + Default = 0, + UserID = 1, + Motion = 2, +}; + DataType :: enum NS.UInteger { None = 0, From debe2de5fe549775c9c40a307a5009c9ee388c88 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 12:12:23 +0000 Subject: [PATCH 0154/1052] Correct Acceleration Structure Types --- core/sys/darwin/Metal/MetalClasses.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 49f31bae9..682b1dd20 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5071,11 +5071,11 @@ AccelerationStructureCommandEncoder_buildAccelerationStructure :: #force_inline msgSend(nil, self, "buildAccelerationStructure:descriptor:scratchBuffer:scratchBufferOffset:", accelerationStructure, descriptor, scratchBuffer, scratchBufferOffset) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAccelerationStructure") -AccelerationStructureCommandEncoder_copyAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^AccelerationStructure, destinationAccelerationStructure: ^AccelerationStructure) { +AccelerationStructureCommandEncoder_copyAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure, destinationAccelerationStructure: ^AccelerationStructure) { msgSend(nil, self, "copyAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="copyAndCompactAccelerationStructure") -AccelerationStructureCommandEncoder_copyAndCompactAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure: ^AccelerationStructure, destinationAccelerationStructure: ^AccelerationStructure) { +AccelerationStructureCommandEncoder_copyAndCompactAccelerationStructure :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, sourceAccelerationStructure, destinationAccelerationStructure: ^AccelerationStructure) { msgSend(nil, self, "copyAndCompactAccelerationStructure:toAccelerationStructure:", sourceAccelerationStructure, destinationAccelerationStructure) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="refitAccelerationStructure") @@ -5095,16 +5095,16 @@ AccelerationStructureCommandEncoder_useHeap :: #force_inline proc(self: ^Acceler msgSend(nil, self, "useHeap:", heap) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useHeaps") -AccelerationStructureCommandEncoder_useHeaps :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heaps: [^]^Heap, count: NS.UInteger) { - msgSend(nil, self, "useHeaps:count:", heaps, count) +AccelerationStructureCommandEncoder_useHeaps :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, heaps: []^Heap) { + msgSend(nil, self, "useHeaps:count:", raw_data(heaps), NS.UInteger(len(heaps))) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useResource") AccelerationStructureCommandEncoder_useResource :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resource: ^Resource, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="useResources") -AccelerationStructureCommandEncoder_useResources :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage) { - msgSend(nil, self, "useResources:count:usage:", resources, count, usage) +AccelerationStructureCommandEncoder_useResources :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, resources: []^Resource, usage: ResourceUsage) { + msgSend(nil, self, "useResources:count:usage:", resources, NS.UInteger(len(resources)), usage) } @(objc_type=AccelerationStructureCommandEncoder, objc_name="waitForFence") AccelerationStructureCommandEncoder_waitForFence :: #force_inline proc(self: ^AccelerationStructureCommandEncoder, fence: ^Fence) { From 83a61694635b047ecfaa294a74e3338920f9111c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 12:32:45 +0000 Subject: [PATCH 0155/1052] Update ArgumentEncoder --- core/sys/darwin/Metal/MetalClasses.odin | 51 ++++++++++++++++--------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 682b1dd20..d60a743a6 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5161,8 +5161,8 @@ ArgumentEncoder_constantDataAtIndex :: #force_inline proc(self: ^ArgumentEncoder return msgSend(rawptr, self, "constantDataAtIndex:", index) } @(objc_type=ArgumentEncoder, objc_name="device") -ArgumentEncoder_device :: #force_inline proc(self: ^ArgumentEncoder) -> ^ArgumentEncoder { - return msgSend(^ArgumentEncoder, self, "device") +ArgumentEncoder_device :: #force_inline proc(self: ^ArgumentEncoder) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=ArgumentEncoder, objc_name="encodedLength") ArgumentEncoder_encodedLength :: #force_inline proc(self: ^ArgumentEncoder) -> NS.UInteger { @@ -5193,32 +5193,39 @@ ArgumentEncoder_setBuffer :: #force_inline proc(self: ^ArgumentEncoder, buffer: msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=ArgumentEncoder, objc_name="setBuffers") -ArgumentEncoder_setBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { - msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) +ArgumentEncoder_setBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: []^Buffer, offsets: []NS.UInteger, range: NS.Range) { + assert(len(buffers) == len(offsets)) + msgSend(nil, self, "setBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineState") ArgumentEncoder_setComputePipelineState :: #force_inline proc(self: ^ArgumentEncoder, pipeline: ^ComputePipelineState, index: NS.UInteger) { msgSend(nil, self, "setComputePipelineState:atIndex:", pipeline, index) } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineStates") -ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: [^]^ComputePipelineState, range: NS.Range) { - msgSend(nil, self, "setComputePipelineStates:withRange:", pipelines, range) +ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: []^ComputePipelineState, range: NS.Range) { + assert(range.location < NS.UInteger(len(pipelines))) + assert(range.length <= NS.UInteger(len(pipelines))) + msgSend(nil, self, "setComputePipelineStates:withRange:", raw_data(pipelines), range) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffer") ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEncoder, indirectCommandBuffer: ^IndirectCommandBuffer, index: NS.UInteger) { msgSend(nil, self, "setIndirectCommandBuffer:atIndex:", indirectCommandBuffer, index) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffers") -ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: [^]^IndirectCommandBuffer, range: NS.Range) { - msgSend(nil, self, "setIndirectCommandBuffers:withRange:", buffers, range) +ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: []^IndirectCommandBuffer, range: NS.Range) { + assert(range.location < NS.UInteger(len(buffers))) + assert(range.length <= NS.UInteger(len(buffers))) + msgSend(nil, self, "setIndirectCommandBuffers:withRange:", raw_data(buffers), range) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTable") ArgumentEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTable: ^IntersectionFunctionTable, index: NS.UInteger) { msgSend(nil, self, "setIntersectionFunctionTable:atIndex:", intersectionFunctionTable, index) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTables") -ArgumentEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTables: [^]^IntersectionFunctionTable, range: NS.Range) { - msgSend(nil, self, "setIntersectionFunctionTables:withRange:", intersectionFunctionTables, range) +ArgumentEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTables: []^IntersectionFunctionTable, range: NS.Range) { + assert(range.location < NS.UInteger(len(intersectionFunctionTables))) + assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) + msgSend(nil, self, "setIntersectionFunctionTables:withRange:", raw_data(intersectionFunctionTables), range) } @(objc_type=ArgumentEncoder, objc_name="setLabel") ArgumentEncoder_setLabel :: #force_inline proc(self: ^ArgumentEncoder, label: ^NS.String) { @@ -5229,32 +5236,40 @@ ArgumentEncoder_setRenderPipelineState :: #force_inline proc(self: ^ArgumentEnco msgSend(nil, self, "setRenderPipelineState:atIndex:", pipeline, index) } @(objc_type=ArgumentEncoder, objc_name="setRenderPipelineStates") -ArgumentEncoder_setRenderPipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: [^]^RenderPipelineState, range: NS.Range) { - msgSend(nil, self, "setRenderPipelineStates:withRange:", pipelines, range) +ArgumentEncoder_setRenderPipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: []^RenderPipelineState, range: NS.Range) { + assert(range.location < NS.UInteger(len(pipelines))) + assert(range.length <= NS.UInteger(len(pipelines))) + msgSend(nil, self, "setRenderPipelineStates:withRange:", raw_data(pipelines), range) } @(objc_type=ArgumentEncoder, objc_name="setSamplerState") ArgumentEncoder_setSamplerState :: #force_inline proc(self: ^ArgumentEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) } @(objc_type=ArgumentEncoder, objc_name="setSamplerStates") -ArgumentEncoder_setSamplerStates :: #force_inline proc(self: ^ArgumentEncoder, samplers: [^]^SamplerState, range: NS.Range) { - msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) +ArgumentEncoder_setSamplerStates :: #force_inline proc(self: ^ArgumentEncoder, samplers: []^SamplerState, range: NS.Range) { + assert(range.location < NS.UInteger(len(samplers))) + assert(range.length <= NS.UInteger(len(samplers))) + msgSend(nil, self, "setSamplerStates:withRange:", raw_data(samplers), range) } @(objc_type=ArgumentEncoder, objc_name="setTexture") ArgumentEncoder_setTexture :: #force_inline proc(self: ^ArgumentEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setTexture:atIndex:", texture, index) } @(objc_type=ArgumentEncoder, objc_name="setTextures") -ArgumentEncoder_setTextures :: #force_inline proc(self: ^ArgumentEncoder, textures: [^]^Texture, range: NS.Range) { - msgSend(nil, self, "setTextures:withRange:", textures, range) +ArgumentEncoder_setTextures :: #force_inline proc(self: ^ArgumentEncoder, textures: []^Texture, range: NS.Range) { + assert(range.location < NS.UInteger(len(textures))) + assert(range.length <= NS.UInteger(len(textures))) + msgSend(nil, self, "setTextures:withRange:", raw_data(textures), range) } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTable") ArgumentEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTable: ^VisibleFunctionTable, index: NS.UInteger) { msgSend(nil, self, "setVisibleFunctionTable:atIndex:", visibleFunctionTable, index) } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTables") -ArgumentEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTables: [^]^VisibleFunctionTable, range: NS.Range) { - msgSend(nil, self, "setVisibleFunctionTables:withRange:", visibleFunctionTables, range) +ArgumentEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTables: []^VisibleFunctionTable, range: NS.Range) { + assert(range.location < NS.UInteger(len(visibleFunctionTables))) + assert(range.length <= NS.UInteger(len(visibleFunctionTables))) + msgSend(nil, self, "setVisibleFunctionTables:withRange:", raw_data(visibleFunctionTables), range) } //////////////////////////////////////////////////////////////////////////////// From 9a43c0672ef941465736f44a773dec2ef7f11718 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 12:36:28 +0000 Subject: [PATCH 0156/1052] Correct BinaryArchive --- core/sys/darwin/Metal/MetalClasses.odin | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index d60a743a6..fefeaeb47 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -1163,7 +1163,7 @@ CaptureManager_startCaptureWithCommandQueue :: #force_inline proc(self: ^Capture msgSend(nil, self, "startCaptureWithCommandQueue:", commandQueue) } @(objc_type=CaptureManager, objc_name="startCaptureWithDescriptor") -CaptureManager_startCaptureWithDescriptor :: #force_inline proc(self: ^CaptureManager, descriptor: ^CaptureDescriptor) -> (ok: bool, error: ^NS.Error) { +CaptureManager_startCaptureWithDescriptor :: #force_inline proc(self: ^CaptureManager, descriptor: ^CaptureDescriptor) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "startCaptureWithDescriptor:error:", descriptor, &error) return } @@ -5291,30 +5291,30 @@ Methods: BinaryArchive :: struct { using _: NS.Copying(BinaryArchive) } @(objc_type=BinaryArchive, objc_name="addComputePipelineFunctionsWithDescriptor") -BinaryArchive_addComputePipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor) -> (ok: bool, error: ^NS.Error) { +BinaryArchive_addComputePipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "addComputePipelineFunctionsWithDescriptor:error:", descriptor, &error) return } @(objc_type=BinaryArchive, objc_name="addRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor) -> (ok: bool, error: ^NS.Error) { +BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "addRenderPipelineFunctionsWithDescriptor:error:", descriptor, &error) return } @(objc_type=BinaryArchive, objc_name="addTileRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor) -> (ok: bool, error: ^NS.Error) { +BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "addTileRenderPipelineFunctionsWithDescriptor:error:", descriptor, &error) return } @(objc_type=BinaryArchive, objc_name="device") -BinaryArchive_device :: #force_inline proc(self: ^BinaryArchive) -> ^BinaryArchive { - return msgSend(^BinaryArchive, self, "device") +BinaryArchive_device :: #force_inline proc(self: ^BinaryArchive) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=BinaryArchive, objc_name="label") BinaryArchive_label :: #force_inline proc(self: ^BinaryArchive) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=BinaryArchive, objc_name="serializeToURL") -BinaryArchive_serializeToURL :: #force_inline proc(self: ^BinaryArchive, url: ^NS.URL) -> (ok: bool, error: ^NS.Error) { +BinaryArchive_serializeToURL :: #force_inline proc(self: ^BinaryArchive, url: ^NS.URL) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "serializeToURL:error:", url, &error) return } @@ -5323,6 +5323,13 @@ BinaryArchive_setLabel :: #force_inline proc(self: ^BinaryArchive, label: ^NS.St msgSend(nil, self, "setLabel:", label) } + +@(objc_type=BinaryArchive, objc_name="addFunction") +BinaryArchive_addFunction :: #force_inline proc(self: ^BinaryArchive, descriptor: ^FunctionDescriptor, library: ^Library) -> (ok: BOOL, error: ^NS.Error) { + ok = msgSend(BOOL, self, "addFunction:", descriptor, library, &error) + return +} + //////////////////////////////////////////////////////////////////////////////// /* @@ -6788,7 +6795,7 @@ DynamicLibrary_label :: #force_inline proc(self: ^DynamicLibrary) -> ^NS.String return msgSend(^NS.String, self, "label") } @(objc_type=DynamicLibrary, objc_name="serializeToURL") -DynamicLibrary_serializeToURL :: #force_inline proc(self: ^DynamicLibrary, url: ^NS.URL) -> (ok: bool, error: ^NS.Error) { +DynamicLibrary_serializeToURL :: #force_inline proc(self: ^DynamicLibrary, url: ^NS.URL) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "serializeToURL:error:", url, &error) return } From 09e9dca86951dbedac057105437fdf3ca60f3b52 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 12:43:01 +0000 Subject: [PATCH 0157/1052] Improve BlitCommandEncoder --- core/sys/darwin/Metal/MetalClasses.odin | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index fefeaeb47..ad59ccaee 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5366,32 +5366,32 @@ Methods: @(objc_class="MTLBlitCommandEncoder") BlitCommandEncoder :: struct { using _: CommandEncoder } -@(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") +@(objc_type=BlitCommandEncoder, objc_name="copyFromBufferEx") BlitCommandEncoder_copyFromBufferEx :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) } -@(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options_") +@(objc_type=BlitCommandEncoder, objc_name="copyFromBufferExWithOptions") BlitCommandEncoder_copyFromBufferExWithOptions :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, sourceBytesPerRow: NS.UInteger, sourceBytesPerImage: NS.UInteger, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin, options: BlitOption) { msgSend(nil, self, "copyFromBuffer:sourceOffset:sourceBytesPerRow:sourceBytesPerImage:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:options:", sourceBuffer, sourceOffset, sourceBytesPerRow, sourceBytesPerImage, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin, options) } -@(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_") -BlitCommandEncoder_copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, size: NS.UInteger) { +@(objc_type=BlitCommandEncoder, objc_name="copyFromBuffer") +BlitCommandEncoder_copyFromBuffer :: #force_inline proc(self: ^BlitCommandEncoder, sourceBuffer: ^Buffer, sourceOffset: NS.UInteger, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, size: NS.UInteger) { msgSend(nil, self, "copyFromBuffer:sourceOffset:toBuffer:destinationOffset:size:", sourceBuffer, sourceOffset, destinationBuffer, destinationOffset, size) } -@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, destinationBytesPerRow: NS.UInteger, destinationBytesPerImage: NS.UInteger) { +@(objc_type=BlitCommandEncoder, objc_name="copyFromTextureEx") +BlitCommandEncoder_copyFromTextureEx :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, destinationBytesPerRow: NS.UInteger, destinationBytesPerImage: NS.UInteger) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage) } -@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, destinationBytesPerRow: NS.UInteger, destinationBytesPerImage: NS.UInteger, options: BlitOption) { +@(objc_type=BlitCommandEncoder, objc_name="copyFromTextureExWithOptions") +BlitCommandEncoder_copyFromTextureExWithOptions :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationBuffer: ^Buffer, destinationOffset: NS.UInteger, destinationBytesPerRow: NS.UInteger, destinationBytesPerImage: NS.UInteger, options: BlitOption) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:options:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationBuffer, destinationOffset, destinationBytesPerRow, destinationBytesPerImage, options) } -@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin) { +@(objc_type=BlitCommandEncoder, objc_name="copyFromTextureWithDestinationOrigin") +BlitCommandEncoder_copyFromTextureWithDestinationOrigin :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, sourceOrigin: Origin, sourceSize: Size, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, destinationOrigin: Origin) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:", sourceTexture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, destinationTexture, destinationSlice, destinationLevel, destinationOrigin) } -@(objc_type=BlitCommandEncoder, objc_name="copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_") -BlitCommandEncoder_copyFromTexture_sourceSlice_sourceLevel_toTexture_destinationSlice_destinationLevel_sliceCount_levelCount_ :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, sliceCount: NS.UInteger, levelCount: NS.UInteger) { +@(objc_type=BlitCommandEncoder, objc_name="copyFromTextureWithCounts") +BlitCommandEncoder_copyFromTextureWithCounts :: #force_inline proc(self: ^BlitCommandEncoder, sourceTexture: ^Texture, sourceSlice: NS.UInteger, sourceLevel: NS.UInteger, destinationTexture: ^Texture, destinationSlice: NS.UInteger, destinationLevel: NS.UInteger, sliceCount: NS.UInteger, levelCount: NS.UInteger) { msgSend(nil, self, "copyFromTexture:sourceSlice:sourceLevel:toTexture:destinationSlice:destinationLevel:sliceCount:levelCount:", sourceTexture, sourceSlice, sourceLevel, destinationTexture, destinationSlice, destinationLevel, sliceCount, levelCount) } @(objc_type=BlitCommandEncoder, objc_name="copyFromTexture") From 02646b789c7d999139cbbbfd8b0f7e392d51341a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 12:44:57 +0000 Subject: [PATCH 0158/1052] Correct typo --- core/sys/darwin/Metal/MetalClasses.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index ad59ccaee..a2d483317 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -6599,9 +6599,9 @@ Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline p pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } -@(objc_type=Device, objc_name="newSamplerState") +@(objc_type=Device, objc_name="newSamplerStateWithDescriptor") Device_newSamplerState :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^SamplerState { - return msgSend(^SamplerState, self, "newSamplerState:", descriptor) + return msgSend(^SamplerState, self, "newSamplerStateWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newSharedEvent") Device_newSharedEvent :: #force_inline proc(self: ^Device) -> ^SharedEvent { From 5936fa88717f82869e5378beb440891b72a693a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 12:46:46 +0000 Subject: [PATCH 0159/1052] Correct Blit Pass --- core/sys/darwin/Metal/MetalClasses.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index a2d483317..26f603564 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -913,15 +913,15 @@ BlitPassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_inlin return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^Buffer { - return msgSend(^Buffer, self, "sampleBuffer") +BlitPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor) -> ^CounterSampleBuffer { + return msgSend(^CounterSampleBuffer, self, "sampleBuffer") } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") BlitPassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -BlitPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, sampleBuffer: ^Buffer) { +BlitPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^BlitPassSampleBufferAttachmentDescriptor, sampleBuffer: ^CounterSampleBuffer) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") From 95e9bbf99f3110194edb20f166e896f8cadc68d7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 12:52:30 +0000 Subject: [PATCH 0160/1052] Improve Buffer --- core/sys/darwin/Metal/MetalClasses.odin | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 26f603564..c025778ea 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5491,8 +5491,14 @@ Buffer_addDebugMarker :: #force_inline proc(self: ^Buffer, marker: ^NS.String, r msgSend(nil, self, "addDebugMarker:range:", marker, range) } @(objc_type=Buffer, objc_name="contents") -Buffer_contents :: #force_inline proc(self: ^Buffer) -> rawptr { - return msgSend(rawptr, self, "contents") +Buffer_contents :: #force_inline proc(self: ^Buffer) -> []byte { + contents := msgSend([^]byte, self, "contents") + length := Buffer_length(self) + return contents[:length] +} +@(objc_type=Buffer, objc_name="contentsPointer") +Buffer_contentsPointer :: #force_inline proc(self: ^Buffer) -> rawptr { + return msgSend([^]byte, self, "contents") } @(objc_type=Buffer, objc_name="didModifyRange") Buffer_didModifyRange :: #force_inline proc(self: ^Buffer, range: NS.Range) { @@ -5519,6 +5525,11 @@ Buffer_removeAllDebugMarkers :: #force_inline proc(self: ^Buffer) { msgSend(nil, self, "removeAllDebugMarkers") } +@(objc_type=Buffer, objc_name="newTexture") +Buffer_newTexture :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: NS.UInteger, bytesPerRow: NS.UInteger) -> ^Texture { + return msgSend(^Texture, self, "newTextureWithDescriptor:offset:bytesPerRow:") +} + //////////////////////////////////////////////////////////////////////////////// /* From bef806bef479c5a7b952369ca07538952813e2fe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 14:24:36 +0000 Subject: [PATCH 0161/1052] Update Capture Manager classes --- core/sys/darwin/Metal/MetalClasses.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index c025778ea..6ce2d940d 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -1077,8 +1077,8 @@ CaptureDescriptor_init :: #force_inline proc(self: ^CaptureDescriptor) -> ^Captu return msgSend(^CaptureDescriptor, self, "init") } @(objc_type=CaptureDescriptor, objc_name="captureObject") -CaptureDescriptor_captureObject :: #force_inline proc(self: ^CaptureDescriptor) -> ^CaptureDescriptor { - return msgSend(^CaptureDescriptor, self, "captureObject") +CaptureDescriptor_captureObject :: #force_inline proc(self: ^CaptureDescriptor) -> id { + return msgSend(id, self, "captureObject") } @(objc_type=CaptureDescriptor, objc_name="destination") CaptureDescriptor_destination :: #force_inline proc(self: ^CaptureDescriptor) -> CaptureDestination { @@ -1143,12 +1143,12 @@ CaptureManager_isCapturing :: #force_inline proc(self: ^CaptureManager) -> BOOL return msgSend(BOOL, self, "isCapturing") } @(objc_type=CaptureManager, objc_name="newCaptureScopeWithCommandQueue") -CaptureManager_newCaptureScopeWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^CommandQueue) -> ^CaptureManager { - return msgSend(^CaptureManager, self, "newCaptureScopeWithCommandQueue:", commandQueue) +CaptureManager_newCaptureScopeWithCommandQueue :: #force_inline proc(self: ^CaptureManager, commandQueue: ^CommandQueue) -> ^CaptureScope { + return msgSend(^CaptureScope, self, "newCaptureScopeWithCommandQueue:", commandQueue) } @(objc_type=CaptureManager, objc_name="newCaptureScopeWithDevice") -CaptureManager_newCaptureScopeWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^Device) -> ^CaptureManager { - return msgSend(^CaptureManager, self, "newCaptureScopeWithDevice:", device) +CaptureManager_newCaptureScopeWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^Device) -> ^CaptureScope { + return msgSend(^CaptureScope, self, "newCaptureScopeWithDevice:", device) } @(objc_type=CaptureManager, objc_name="setDefaultCaptureScope") CaptureManager_setDefaultCaptureScope :: #force_inline proc(self: ^CaptureManager, defaultCaptureScope: ^CaptureScope) { From f9fc4883990d879b28361b308fc1406244756d16 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 14:26:35 +0000 Subject: [PATCH 0162/1052] Correct CaptureScope --- core/sys/darwin/Metal/MetalClasses.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 6ce2d940d..b11c8f73d 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5552,12 +5552,12 @@ CaptureScope_beginScope :: #force_inline proc(self: ^CaptureScope) { msgSend(nil, self, "beginScope") } @(objc_type=CaptureScope, objc_name="commandQueue") -CaptureScope_commandQueue :: #force_inline proc(self: ^CaptureScope) -> ^CaptureScope { - return msgSend(^CaptureScope, self, "commandQueue") +CaptureScope_commandQueue :: #force_inline proc(self: ^CaptureScope) -> ^CommandQueue { + return msgSend(^CommandQueue, self, "commandQueue") } @(objc_type=CaptureScope, objc_name="device") -CaptureScope_device :: #force_inline proc(self: ^CaptureScope) -> ^CaptureScope { - return msgSend(^CaptureScope, self, "device") +CaptureScope_device :: #force_inline proc(self: ^CaptureScope) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=CaptureScope, objc_name="endScope") CaptureScope_endScope :: #force_inline proc(self: ^CaptureScope) { From a88d1499035cfcf733d4269ec75546e98eb5f893 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 14:33:02 +0000 Subject: [PATCH 0163/1052] Improve CommandBuffer --- core/sys/darwin/Metal/MetalClasses.odin | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index b11c8f73d..6ca13c644 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5656,20 +5656,20 @@ CommandBuffer_commit :: #force_inline proc(self: ^CommandBuffer) { msgSend(nil, self, "commit") } @(objc_type=CommandBuffer, objc_name="computeCommandEncoder") -CommandBuffer_computeCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^CommandEncoder { - return msgSend(^CommandEncoder, self, "computeCommandEncoder") +CommandBuffer_computeCommandEncoder :: #force_inline proc(self: ^CommandBuffer) -> ^ComputeCommandEncoder { + return msgSend(^ComputeCommandEncoder, self, "computeCommandEncoder") } @(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDescriptor") -CommandBuffer_computeCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, computePassDescriptor: ^ComputePassDescriptor) -> ^CommandEncoder { - return msgSend(^CommandEncoder, self, "computeCommandEncoderWithDescriptor:", computePassDescriptor) +CommandBuffer_computeCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, computePassDescriptor: ^ComputePassDescriptor) -> ^ComputeCommandEncoder { + return msgSend(^ComputeCommandEncoder, self, "computeCommandEncoderWithDescriptor:", computePassDescriptor) } @(objc_type=CommandBuffer, objc_name="computeCommandEncoderWithDispatchType") -CommandBuffer_computeCommandEncoderWithDispatchType :: #force_inline proc(self: ^CommandBuffer, dispatchType: DispatchType) -> ^CommandEncoder { - return msgSend(^CommandEncoder, self, "computeCommandEncoderWithDispatchType:", dispatchType) +CommandBuffer_computeCommandEncoderWithDispatchType :: #force_inline proc(self: ^CommandBuffer, dispatchType: DispatchType) -> ^ComputeCommandEncoder { + return msgSend(^ComputeCommandEncoder, self, "computeCommandEncoderWithDispatchType:", dispatchType) } @(objc_type=CommandBuffer, objc_name="device") -CommandBuffer_device :: #force_inline proc(self: ^CommandBuffer) -> ^CommandBuffer { - return msgSend(^CommandBuffer, self, "device") +CommandBuffer_device :: #force_inline proc(self: ^CommandBuffer) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=CommandBuffer, objc_name="encodeSignalEvent") CommandBuffer_encodeSignalEvent :: #force_inline proc(self: ^CommandBuffer, event: ^Event, value: u64) { @@ -5704,8 +5704,8 @@ CommandBuffer_label :: #force_inline proc(self: ^CommandBuffer) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=CommandBuffer, objc_name="logs") -CommandBuffer_logs :: #force_inline proc(self: ^CommandBuffer) -> id { - return msgSend(id, self, "logs") +CommandBuffer_logs :: #force_inline proc(self: ^CommandBuffer) -> ^LogContainer { + return msgSend(^LogContainer, self, "logs") } @(objc_type=CommandBuffer, objc_name="parallelRenderCommandEncoderWithDescriptor") CommandBuffer_parallelRenderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^ParallelRenderCommandEncoder { @@ -6975,6 +6975,16 @@ FunctionHandle_name :: #force_inline proc(self: ^FunctionHandle) -> ^NS.String { //////////////////////////////////////////////////////////////////////////////// +/* +Class: + LogContainer +*/ + +@(objc_class="MTLLogContainer") +LogContainer :: struct { using _: NS.FastEnumeration } + +//////////////////////////////////////////////////////////////////////////////// + /* Class: FunctionLog From 6fef44c041762d5ef552e793006ee36de2a227fe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 14:33:50 +0000 Subject: [PATCH 0164/1052] Improve CommandEncoder --- core/sys/darwin/Metal/MetalClasses.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 6ca13c644..868ac2498 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5810,8 +5810,8 @@ Methods: CommandEncoder :: struct { using _: NS.Object } @(objc_type=CommandEncoder, objc_name="device") -CommandEncoder_device :: #force_inline proc(self: ^CommandEncoder) -> ^CommandEncoder { - return msgSend(^CommandEncoder, self, "device") +CommandEncoder_device :: #force_inline proc(self: ^CommandEncoder) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=CommandEncoder, objc_name="endEncoding") CommandEncoder_endEncoding :: #force_inline proc(self: ^CommandEncoder) { From 153140eb8f5b3c2e5a4f90dd6caf7b34a46e77de Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 14:43:50 +0000 Subject: [PATCH 0165/1052] Improve ComputeCommandEncoder --- core/sys/darwin/Metal/MetalClasses.odin | 46 +++++++++++-------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 868ac2498..f849338cc 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5203,7 +5203,6 @@ ArgumentEncoder_setComputePipelineState :: #force_inline proc(self: ^ArgumentEnc } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineStates") ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: []^ComputePipelineState, range: NS.Range) { - assert(range.location < NS.UInteger(len(pipelines))) assert(range.length <= NS.UInteger(len(pipelines))) msgSend(nil, self, "setComputePipelineStates:withRange:", raw_data(pipelines), range) } @@ -5213,7 +5212,6 @@ ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEn } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffers") ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: []^IndirectCommandBuffer, range: NS.Range) { - assert(range.location < NS.UInteger(len(buffers))) assert(range.length <= NS.UInteger(len(buffers))) msgSend(nil, self, "setIndirectCommandBuffers:withRange:", raw_data(buffers), range) } @@ -5223,7 +5221,6 @@ ArgumentEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^Argume } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTables") ArgumentEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTables: []^IntersectionFunctionTable, range: NS.Range) { - assert(range.location < NS.UInteger(len(intersectionFunctionTables))) assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) msgSend(nil, self, "setIntersectionFunctionTables:withRange:", raw_data(intersectionFunctionTables), range) } @@ -5237,7 +5234,6 @@ ArgumentEncoder_setRenderPipelineState :: #force_inline proc(self: ^ArgumentEnco } @(objc_type=ArgumentEncoder, objc_name="setRenderPipelineStates") ArgumentEncoder_setRenderPipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: []^RenderPipelineState, range: NS.Range) { - assert(range.location < NS.UInteger(len(pipelines))) assert(range.length <= NS.UInteger(len(pipelines))) msgSend(nil, self, "setRenderPipelineStates:withRange:", raw_data(pipelines), range) } @@ -5247,7 +5243,6 @@ ArgumentEncoder_setSamplerState :: #force_inline proc(self: ^ArgumentEncoder, sa } @(objc_type=ArgumentEncoder, objc_name="setSamplerStates") ArgumentEncoder_setSamplerStates :: #force_inline proc(self: ^ArgumentEncoder, samplers: []^SamplerState, range: NS.Range) { - assert(range.location < NS.UInteger(len(samplers))) assert(range.length <= NS.UInteger(len(samplers))) msgSend(nil, self, "setSamplerStates:withRange:", raw_data(samplers), range) } @@ -5257,7 +5252,6 @@ ArgumentEncoder_setTexture :: #force_inline proc(self: ^ArgumentEncoder, texture } @(objc_type=ArgumentEncoder, objc_name="setTextures") ArgumentEncoder_setTextures :: #force_inline proc(self: ^ArgumentEncoder, textures: []^Texture, range: NS.Range) { - assert(range.location < NS.UInteger(len(textures))) assert(range.length <= NS.UInteger(len(textures))) msgSend(nil, self, "setTextures:withRange:", raw_data(textures), range) } @@ -5267,7 +5261,6 @@ ArgumentEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ArgumentEnc } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTables") ArgumentEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTables: []^VisibleFunctionTable, range: NS.Range) { - assert(range.location < NS.UInteger(len(visibleFunctionTables))) assert(range.length <= NS.UInteger(len(visibleFunctionTables))) msgSend(nil, self, "setVisibleFunctionTables:withRange:", raw_data(visibleFunctionTables), range) } @@ -5956,8 +5949,8 @@ ComputeCommandEncoder_executeCommandsInBufferWithRange :: #force_inline proc(sel msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) } @(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithResources") -ComputeCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: [^]^Resource, count: NS.UInteger) { - msgSend(nil, self, "memoryBarrierWithResources:count:", resources, count) +ComputeCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: []^Resource) { + msgSend(nil, self, "memoryBarrierWithResources:count:", raw_data(resources), NS.UInteger(len(resources))) } @(objc_type=ComputeCommandEncoder, objc_name="memoryBarrierWithScope") ComputeCommandEncoder_memoryBarrierWithScope :: #force_inline proc(self: ^ComputeCommandEncoder, scope: BarrierScope) { @@ -5980,8 +5973,10 @@ ComputeCommandEncoder_setBufferOffset :: #force_inline proc(self: ^ComputeComman msgSend(nil, self, "setBufferOffset:atIndex:", offset, index) } @(objc_type=ComputeCommandEncoder, objc_name="setBuffers") -ComputeCommandEncoder_setBuffers :: #force_inline proc(self: ^ComputeCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { - msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) +ComputeCommandEncoder_setBuffers :: #force_inline proc(self: ^ComputeCommandEncoder, buffers: []^Buffer, offsets: []NS.UInteger, range: NS.Range) { + assert(len(buffers) == len(offsets)) + assert(range.length <= NS.UInteger(len(buffers))) + msgSend(nil, self, "setBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=ComputeCommandEncoder, objc_name="setBytes") ComputeCommandEncoder_setBytes :: #force_inline proc(self: ^ComputeCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { @@ -6000,8 +5995,9 @@ ComputeCommandEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ msgSend(nil, self, "setIntersectionFunctionTable:atBufferIndex:", intersectionFunctionTable, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTables") -ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: [^]^IntersectionFunctionTable, range: NS.Range) { - msgSend(nil, self, "setIntersectionFunctionTables:withBufferRange:", intersectionFunctionTables, range) +ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: []^IntersectionFunctionTable, range: NS.Range) { + assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) + msgSend(nil, self, "setIntersectionFunctionTables:withBufferRange:", raw_data(intersectionFunctionTables), range) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerStateAtIndex") ComputeCommandEncoder_setSamplerStateAtIndex :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { @@ -6012,12 +6008,12 @@ ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_i msgSend(nil, self, "setSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_lodMinClamps_lodMaxClampsWithRange") -ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { - msgSend(nil, self, "setSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: []^SamplerState, lodMinClamps, lodMaxClamps: []f32, range: NS.Range) { + msgSend(nil, self, "setSamplerStates:lodMinClamps:lodMaxClamps:withRange:", raw_data(samplers), raw_data(lodMinClamps), raw_data(lodMaxClamps), range) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerStatesWithRange") -ComputeCommandEncoder_setSamplerStatesWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { - msgSend(nil, self, "setSamplerStates:withRange:", samplers, range) +ComputeCommandEncoder_setSamplerStatesWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: []^SamplerState, range: NS.Range) { + msgSend(nil, self, "setSamplerStates:withRange:", raw_data(samplers), range) } @(objc_type=ComputeCommandEncoder, objc_name="setStageInRegion") ComputeCommandEncoder_setStageInRegion :: #force_inline proc(self: ^ComputeCommandEncoder, region: Region) { @@ -6032,8 +6028,8 @@ ComputeCommandEncoder_setTexture :: #force_inline proc(self: ^ComputeCommandEnco msgSend(nil, self, "setTexture:atIndex:", texture, index) } @(objc_type=ComputeCommandEncoder, objc_name="setTextures") -ComputeCommandEncoder_setTextures :: #force_inline proc(self: ^ComputeCommandEncoder, textures: [^]^Texture, range: NS.Range) { - msgSend(nil, self, "setTextures:withRange:", textures, range) +ComputeCommandEncoder_setTextures :: #force_inline proc(self: ^ComputeCommandEncoder, textures: []^Texture, range: NS.Range) { + msgSend(nil, self, "setTextures:withRange:", raw_data(textures), range) } @(objc_type=ComputeCommandEncoder, objc_name="setThreadgroupMemoryLength") ComputeCommandEncoder_setThreadgroupMemoryLength :: #force_inline proc(self: ^ComputeCommandEncoder, length: NS.UInteger, index: NS.UInteger) { @@ -6044,8 +6040,8 @@ ComputeCommandEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^Compu msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) } @(objc_type=ComputeCommandEncoder, objc_name="setVisibleFunctionTables") -ComputeCommandEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTables: [^]^VisibleFunctionTable, range: NS.Range) { - msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) +ComputeCommandEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, visibleFunctionTables: []^VisibleFunctionTable, range: NS.Range) { + msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", raw_data(visibleFunctionTables), range) } @(objc_type=ComputeCommandEncoder, objc_name="updateFence") ComputeCommandEncoder_updateFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^Fence) { @@ -6056,16 +6052,16 @@ ComputeCommandEncoder_useHeap :: #force_inline proc(self: ^ComputeCommandEncoder msgSend(nil, self, "useHeap:", heap) } @(objc_type=ComputeCommandEncoder, objc_name="useHeaps") -ComputeCommandEncoder_useHeaps :: #force_inline proc(self: ^ComputeCommandEncoder, heaps: [^]^Heap, count: NS.UInteger) { - msgSend(nil, self, "useHeaps:count:", heaps, count) +ComputeCommandEncoder_useHeaps :: #force_inline proc(self: ^ComputeCommandEncoder, heaps: []^Heap) { + msgSend(nil, self, "useHeaps:count:", raw_data(heaps), NS.UInteger(len(heaps))) } @(objc_type=ComputeCommandEncoder, objc_name="useResource") ComputeCommandEncoder_useResource :: #force_inline proc(self: ^ComputeCommandEncoder, resource: ^Resource, usage: ResourceUsage) { msgSend(nil, self, "useResource:usage:", resource, usage) } @(objc_type=ComputeCommandEncoder, objc_name="useResources") -ComputeCommandEncoder_useResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage) { - msgSend(nil, self, "useResources:count:usage:", resources, count, usage) +ComputeCommandEncoder_useResources :: #force_inline proc(self: ^ComputeCommandEncoder, resources: []^Resource, usage: ResourceUsage) { + msgSend(nil, self, "useResources:count:usage:", raw_data(resources), NS.UInteger(len(resources)), usage) } @(objc_type=ComputeCommandEncoder, objc_name="waitForFence") ComputeCommandEncoder_waitForFence :: #force_inline proc(self: ^ComputeCommandEncoder, fence: ^Fence) { From af6e53c05c462a6a5cfe060509c954c5eccd9fe5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 15:14:41 +0000 Subject: [PATCH 0166/1052] Improve Compute classes --- core/sys/darwin/Metal/MetalClasses.odin | 80 ++++++++++++------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index f849338cc..be706212f 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -1392,8 +1392,8 @@ ComputePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #force_in return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^Buffer { - return msgSend(^Buffer, self, "sampleBuffer") +ComputePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor) -> ^CounterSampleBuffer { + return msgSend(^CounterSampleBuffer, self, "sampleBuffer") } @(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") ComputePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ComputePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { @@ -1498,8 +1498,8 @@ ComputePipelineDescriptor_buffers :: #force_inline proc(self: ^ComputePipelineDe return msgSend(^PipelineBufferDescriptorArray, self, "buffers") } @(objc_type=ComputePipelineDescriptor, objc_name="computeFunction") -ComputePipelineDescriptor_computeFunction :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^ComputePipelineDescriptor { - return msgSend(^ComputePipelineDescriptor, self, "computeFunction") +ComputePipelineDescriptor_computeFunction :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^Function { + return msgSend(^Function, self, "computeFunction") } @(objc_type=ComputePipelineDescriptor, objc_name="insertLibraries") ComputePipelineDescriptor_insertLibraries :: #force_inline proc(self: ^ComputePipelineDescriptor) -> ^NS.Array { @@ -2647,8 +2647,8 @@ RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSizeWithL return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layer:", screenSize, layer) } @(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSizeWithLayers") -RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSizeWithLayers :: #force_inline proc(screenSize: Size, layerCount: NS.UInteger, layers: [^]^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { - return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layerCount:layers:", screenSize, layerCount, layers) +RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSizeWithLayers :: #force_inline proc(screenSize: Size, layers: []^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { + return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layerCount:layers:", screenSize, NS.UInteger(len(layers)), layers) } @(objc_type=RasterizationRateMapDescriptor, objc_name="screenSize") RasterizationRateMapDescriptor_screenSize :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> Size { @@ -6091,12 +6091,12 @@ Methods: ComputePipelineState :: struct { using _: NS.Object } @(objc_type=ComputePipelineState, objc_name="device") -ComputePipelineState_device :: #force_inline proc(self: ^ComputePipelineState) -> ^ComputePipelineState { - return msgSend(^ComputePipelineState, self, "device") +ComputePipelineState_device :: #force_inline proc(self: ^ComputePipelineState) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=ComputePipelineState, objc_name="functionHandleWithFunction") -ComputePipelineState_functionHandleWithFunction :: #force_inline proc(self: ^ComputePipelineState, function: ^Function) -> ^ComputePipelineState { - return msgSend(^ComputePipelineState, self, "functionHandleWithFunction:", function) +ComputePipelineState_functionHandleWithFunction :: #force_inline proc(self: ^ComputePipelineState, function: ^Function) -> ^FunctionHandle { + return msgSend(^FunctionHandle, self, "functionHandleWithFunction:", function) } @(objc_type=ComputePipelineState, objc_name="imageblockMemoryLengthForDimensions") ComputePipelineState_imageblockMemoryLengthForDimensions :: #force_inline proc(self: ^ComputePipelineState, imageblockDimensions: Size) -> ^ComputePipelineState { @@ -6110,18 +6110,18 @@ ComputePipelineState_label :: #force_inline proc(self: ^ComputePipelineState) -> ComputePipelineState_maxTotalThreadsPerThreadgroup :: #force_inline proc(self: ^ComputePipelineState) -> NS.UInteger { return msgSend(NS.UInteger, self, "maxTotalThreadsPerThreadgroup") } -@(objc_type=ComputePipelineState, objc_name="newComputePipelineStateWithAdditionalBinaryFunctions") -ComputePipelineState_newComputePipelineStateWithAdditionalBinaryFunctions :: #force_inline proc(self: ^ComputePipelineState, functions: ^NS.Array) -> (state: ^ComputePipelineState, error: ^NS.Error) { +@(objc_type=ComputePipelineState, objc_name="newComputePipelineState") +ComputePipelineState_newComputePipelineState :: #force_inline proc(self: ^ComputePipelineState, functions: ^NS.Array) -> (state: ^ComputePipelineState, error: ^NS.Error) { state = msgSend(^ComputePipelineState, self, "newComputePipelineStateWithAdditionalBinaryFunctions:error:", functions, &error) return } -@(objc_type=ComputePipelineState, objc_name="newIntersectionFunctionTableWithDescriptor") -ComputePipelineState_newIntersectionFunctionTableWithDescriptor :: #force_inline proc(self: ^ComputePipelineState, descriptor: ^IntersectionFunctionTableDescriptor) -> ^ComputePipelineState { - return msgSend(^ComputePipelineState, self, "newIntersectionFunctionTableWithDescriptor:", descriptor) +@(objc_type=ComputePipelineState, objc_name="newIntersectionFunctionTable") +ComputePipelineState_newIntersectionFunctionTable :: #force_inline proc(self: ^ComputePipelineState, descriptor: ^IntersectionFunctionTableDescriptor) -> ^IntersectionFunctionTable { + return msgSend(^IntersectionFunctionTable, self, "newIntersectionFunctionTableWithDescriptor:", descriptor) } -@(objc_type=ComputePipelineState, objc_name="newVisibleFunctionTableWithDescriptor") -ComputePipelineState_newVisibleFunctionTableWithDescriptor :: #force_inline proc(self: ^ComputePipelineState, descriptor: ^VisibleFunctionTableDescriptor) -> ^ComputePipelineState { - return msgSend(^ComputePipelineState, self, "newVisibleFunctionTableWithDescriptor:", descriptor) +@(objc_type=ComputePipelineState, objc_name="newVisibleFunctionTable") +ComputePipelineState_newVisibleFunctionTable :: #force_inline proc(self: ^ComputePipelineState, descriptor: ^VisibleFunctionTableDescriptor) -> ^VisibleFunctionTable { + return msgSend(^VisibleFunctionTable, self, "newVisibleFunctionTableWithDescriptor:", descriptor) } @(objc_type=ComputePipelineState, objc_name="staticThreadgroupMemoryLength") ComputePipelineState_staticThreadgroupMemoryLength :: #force_inline proc(self: ^ComputePipelineState) -> NS.UInteger { @@ -7310,16 +7310,16 @@ IntersectionFunctionTable_setBuffer :: #force_inline proc(self: ^IntersectionFun msgSend(nil, self, "setBuffer:offset:atIndex:", buffer, offset, index) } @(objc_type=IntersectionFunctionTable, objc_name="setBuffers") -IntersectionFunctionTable_setBuffers :: #force_inline proc(self: ^IntersectionFunctionTable, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { - msgSend(nil, self, "setBuffers:offsets:withRange:", buffers, offsets, range) +IntersectionFunctionTable_setBuffers :: #force_inline proc(self: ^IntersectionFunctionTable, buffers: []^Buffer, offsets: []NS.UInteger, range: NS.Range) { + msgSend(nil, self, "setBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=IntersectionFunctionTable, objc_name="setFunction") IntersectionFunctionTable_setFunction :: #force_inline proc(self: ^IntersectionFunctionTable, function: ^FunctionHandle, index: NS.UInteger) { msgSend(nil, self, "setFunction:atIndex:", function, index) } @(objc_type=IntersectionFunctionTable, objc_name="setFunctions") -IntersectionFunctionTable_setFunctions :: #force_inline proc(self: ^IntersectionFunctionTable, functions: [^]^FunctionHandle, range: NS.Range) { - msgSend(nil, self, "setFunctions:withRange:", functions, range) +IntersectionFunctionTable_setFunctions :: #force_inline proc(self: ^IntersectionFunctionTable, functions: []^FunctionHandle, range: NS.Range) { + msgSend(nil, self, "setFunctions:withRange:", raw_data(functions), range) } @(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignatureAtIndex") IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignatureAtIndex :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: NS.UInteger) { @@ -7334,8 +7334,8 @@ IntersectionFunctionTable_setVisibleFunctionTable :: #force_inline proc(self: ^I msgSend(nil, self, "setVisibleFunctionTable:atBufferIndex:", visibleFunctionTable, bufferIndex) } @(objc_type=IntersectionFunctionTable, objc_name="setVisibleFunctionTables") -IntersectionFunctionTable_setVisibleFunctionTables :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTables: [^]^VisibleFunctionTable, range: NS.Range) { - msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", visibleFunctionTables, range) +IntersectionFunctionTable_setVisibleFunctionTables :: #force_inline proc(self: ^IntersectionFunctionTable, visibleFunctionTables: []^VisibleFunctionTable, range: NS.Range) { + msgSend(nil, self, "setVisibleFunctionTables:withBufferRange:", raw_data(visibleFunctionTables), range) } //////////////////////////////////////////////////////////////////////////////// @@ -7685,8 +7685,8 @@ RenderCommandEncoder_executeCommandsInBufferWithRange :: #force_inline proc(self msgSend(nil, self, "executeCommandsInBuffer:withRange:", indirectCommandBuffer, executionRange) } @(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithResources") -RenderCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, after: RenderStages, before: RenderStages) { - msgSend(nil, self, "memoryBarrierWithResources:count:afterStages:beforeStages:", resources, count, after, before) +RenderCommandEncoder_memoryBarrierWithResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: []^Resource, after: RenderStages, before: RenderStages) { + msgSend(nil, self, "memoryBarrierWithResources:count:afterStages:beforeStages:", raw_data(resources), NS.UInteger(len(resources)), after, before) } @(objc_type=RenderCommandEncoder, objc_name="memoryBarrierWithScope") RenderCommandEncoder_memoryBarrierWithScope :: #force_inline proc(self: ^RenderCommandEncoder, scope: BarrierScope, after: RenderStages, before: RenderStages) { @@ -7741,12 +7741,12 @@ RenderCommandEncoder_setFragmentBufferOffset :: #force_inline proc(self: ^Render msgSend(nil, self, "setFragmentBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBuffers") -RenderCommandEncoder_setFragmentBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { - msgSend(nil, self, "setFragmentBuffers:offsets:withRange:", buffers, offsets, range) +RenderCommandEncoder_setFragmentBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: []^Buffer, offsets: []NS.UInteger, range: NS.Range) { + msgSend(nil, self, "setFragmentBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentBytes") -RenderCommandEncoder_setFragmentBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { - msgSend(nil, self, "setFragmentBytes:length:atIndex:", bytes, length, index) +RenderCommandEncoder_setFragmentBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: []byte, index: NS.UInteger) { + msgSend(nil, self, "setFragmentBytes:length:atIndex:", raw_data(bytes), NS.UInteger(len(bytes)), index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStateAtIndex") RenderCommandEncoder_setFragmentSamplerStateAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { @@ -7757,20 +7757,20 @@ RenderCommandEncoder_setFragmentSamplerState_lodMinClamp_lodMaxClampAtIndex :: # msgSend(nil, self, "setFragmentSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_lodMinClamps_lodMaxClampsWithRange") -RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { - msgSend(nil, self, "setFragmentSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, lodMinClamps: []f32, lodMaxClamps: []f32, range: NS.Range) { + msgSend(nil, self, "setFragmentSamplerStates:lodMinClamps:lodMaxClamps:withRange:", raw_data(samplers), raw_data(lodMinClamps), raw_data(lodMaxClamps), range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStatesWithRange") -RenderCommandEncoder_setFragmentSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { - msgSend(nil, self, "setFragmentSamplerStates:withRange:", samplers, range) +RenderCommandEncoder_setFragmentSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, range: NS.Range) { + msgSend(nil, self, "setFragmentSamplerStates:withRange:", raw_data(samplers), range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentTexture") RenderCommandEncoder_setFragmentTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setFragmentTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentTextures") -RenderCommandEncoder_setFragmentTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: [^]^Texture, range: NS.Range) { - msgSend(nil, self, "setFragmentTextures:withRange:", textures, range) +RenderCommandEncoder_setFragmentTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: []^Texture, range: NS.Range) { + msgSend(nil, self, "setFragmentTextures:withRange:", raw_data(textures), range) } @(objc_type=RenderCommandEncoder, objc_name="setFrontFacingWinding") RenderCommandEncoder_setFrontFacingWinding :: #force_inline proc(self: ^RenderCommandEncoder, frontFacingWinding: Winding) { @@ -7785,8 +7785,8 @@ RenderCommandEncoder_setScissorRect :: #force_inline proc(self: ^RenderCommandEn msgSend(nil, self, "setScissorRect:", rect) } @(objc_type=RenderCommandEncoder, objc_name="setScissorRects") -RenderCommandEncoder_setScissorRects :: #force_inline proc(self: ^RenderCommandEncoder, scissorRects: ^ScissorRect, count: NS.UInteger) { - msgSend(nil, self, "setScissorRects:count:", scissorRects, count) +RenderCommandEncoder_setScissorRects :: #force_inline proc(self: ^RenderCommandEncoder, scissorRects: []ScissorRect) { + msgSend(nil, self, "setScissorRects:count:", raw_data(scissorRects), NS.UInteger(len(scissorRects))) } @(objc_type=RenderCommandEncoder, objc_name="setStencilFrontReferenceValue") RenderCommandEncoder_setStencilFrontReferenceValue :: #force_inline proc(self: ^RenderCommandEncoder, frontReferenceValue: u32, backReferenceValue: u32) { @@ -7861,8 +7861,8 @@ RenderCommandEncoder_setTriangleFillMode :: #force_inline proc(self: ^RenderComm msgSend(nil, self, "setTriangleFillMode:", fillMode) } @(objc_type=RenderCommandEncoder, objc_name="setVertexAmplificationCount") -RenderCommandEncoder_setVertexAmplificationCount :: #force_inline proc(self: ^RenderCommandEncoder, count: NS.UInteger, viewMappings: ^VertexAmplificationViewMapping) { - msgSend(nil, self, "setVertexAmplificationCount:viewMappings:", count, viewMappings) +RenderCommandEncoder_setVertexAmplificationCount :: #force_inline proc(self: ^RenderCommandEncoder, viewMappings: []VertexAmplificationViewMapping) { + msgSend(nil, self, "setVertexAmplificationCount:viewMappings:", NS.UInteger(len(viewMappings)), raw_data(viewMappings)) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBuffer") RenderCommandEncoder_setVertexBuffer :: #force_inline proc(self: ^RenderCommandEncoder, buffer: ^Buffer, offset: NS.UInteger, index: NS.UInteger) { From 31c6ecad347985d3e0bc104e3151f70fa9dbb843 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 15:15:32 +0000 Subject: [PATCH 0167/1052] Correct Counter classes --- core/sys/darwin/Metal/MetalClasses.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index be706212f..ea0cf2682 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -1643,8 +1643,8 @@ CounterSampleBufferDescriptor_init :: #force_inline proc(self: ^CounterSampleBuf return msgSend(^CounterSampleBufferDescriptor, self, "init") } @(objc_type=CounterSampleBufferDescriptor, objc_name="counterSet") -CounterSampleBufferDescriptor_counterSet :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSampleBufferDescriptor { - return msgSend(^CounterSampleBufferDescriptor, self, "counterSet") +CounterSampleBufferDescriptor_counterSet :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> ^CounterSet { + return msgSend(^CounterSet, self, "counterSet") } @(objc_type=CounterSampleBufferDescriptor, objc_name="label") CounterSampleBufferDescriptor_label :: #force_inline proc(self: ^CounterSampleBufferDescriptor) -> ^NS.String { From 47f3773146cd6686da8b73be1dc82c6c1e475a50 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 15:18:38 +0000 Subject: [PATCH 0168/1052] Correct Depth classes --- core/sys/darwin/Metal/MetalClasses.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index ea0cf2682..895d72839 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -6221,8 +6221,8 @@ Methods: DepthStencilState :: struct { using _: NS.Object } @(objc_type=DepthStencilState, objc_name="device") -DepthStencilState_device :: #force_inline proc(self: ^DepthStencilState) -> ^DepthStencilState { - return msgSend(^DepthStencilState, self, "device") +DepthStencilState_device :: #force_inline proc(self: ^DepthStencilState) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=DepthStencilState, objc_name="label") DepthStencilState_label :: #force_inline proc(self: ^DepthStencilState) -> ^NS.String { From e47953f7cabd2351fea6a3ca96d49c3914cd2cff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 15:45:02 +0000 Subject: [PATCH 0169/1052] Improve procedure signature and names --- core/sys/darwin/Metal/MetalClasses.odin | 181 ++++++++++++------------ core/sys/darwin/Metal/MetalTypes.odin | 4 +- 2 files changed, 94 insertions(+), 91 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 895d72839..1f4ae50cb 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -1818,8 +1818,8 @@ FunctionConstantValues_init :: #force_inline proc(self: ^FunctionConstantValues) FunctionConstantValues_reset :: #force_inline proc(self: ^FunctionConstantValues) { msgSend(nil, self, "reset") } -@(objc_type=FunctionConstantValues, objc_name="setConstantValueAtIndex") -FunctionConstantValues_setConstantValueAtIndex :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, index: NS.UInteger) { +@(objc_type=FunctionConstantValues, objc_name="setConstantValue") +FunctionConstantValues_setConstantValue :: #force_inline proc(self: ^FunctionConstantValues, value: rawptr, type: DataType, index: NS.UInteger) { msgSend(nil, self, "setConstantValue:type:atIndex:", value, type, index) } @(objc_type=FunctionConstantValues, objc_name="setConstantValueWithName") @@ -2626,8 +2626,8 @@ RasterizationRateMapDescriptor_init :: #force_inline proc(self: ^RasterizationRa RasterizationRateMapDescriptor_label :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> ^NS.String { return msgSend(^NS.String, self, "label") } -@(objc_type=RasterizationRateMapDescriptor, objc_name="layerAtIndex") -RasterizationRateMapDescriptor_layerAtIndex :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layerIndex: NS.UInteger) -> ^RasterizationRateLayerDescriptor { +@(objc_type=RasterizationRateMapDescriptor, objc_name="layer") +RasterizationRateMapDescriptor_layer :: #force_inline proc(self: ^RasterizationRateMapDescriptor, layerIndex: NS.UInteger) -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, self, "layerAtIndex:", layerIndex) } @(objc_type=RasterizationRateMapDescriptor, objc_name="layerCount") @@ -3000,8 +3000,8 @@ RenderPassDescriptor_depthAttachment :: #force_inline proc(self: ^RenderPassDesc return msgSend(^RenderPassDepthAttachmentDescriptor, self, "depthAttachment") } @(objc_type=RenderPassDescriptor, objc_name="getSamplePositions") -RenderPassDescriptor_getSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: NS.UInteger) -> ^RenderPassDescriptor { - return msgSend(^RenderPassDescriptor, self, "getSamplePositions:count:", positions, count) +RenderPassDescriptor_getSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: []SamplePosition) -> ^RenderPassDescriptor { + return msgSend(^RenderPassDescriptor, self, "getSamplePositions:count:", raw_data(positions), NS.UInteger(len(positions))) } @(objc_type=RenderPassDescriptor, objc_name="imageblockSampleLength") RenderPassDescriptor_imageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { @@ -3060,8 +3060,8 @@ RenderPassDescriptor_setRenderTargetWidth :: #force_inline proc(self: ^RenderPas msgSend(nil, self, "setRenderTargetWidth:", renderTargetWidth) } @(objc_type=RenderPassDescriptor, objc_name="setSamplePositions") -RenderPassDescriptor_setSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: ^SamplePosition, count: NS.UInteger) { - msgSend(nil, self, "setSamplePositions:count:", positions, count) +RenderPassDescriptor_setSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: []SamplePosition) { + msgSend(nil, self, "setSamplePositions:count:", raw_data(positions), NS.UInteger(len(positions))) } @(objc_type=RenderPassDescriptor, objc_name="setStencilAttachment") RenderPassDescriptor_setStencilAttachment :: #force_inline proc(self: ^RenderPassDescriptor, stencilAttachment: ^RenderPassStencilAttachmentDescriptor) { @@ -5156,8 +5156,8 @@ ArgumentEncoder :: struct { using _: NS.Object } ArgumentEncoder_alignment :: #force_inline proc(self: ^ArgumentEncoder) -> NS.UInteger { return msgSend(NS.UInteger, self, "alignment") } -@(objc_type=ArgumentEncoder, objc_name="constantDataAtIndex") -ArgumentEncoder_constantDataAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: NS.UInteger) -> rawptr { +@(objc_type=ArgumentEncoder, objc_name="constantData") +ArgumentEncoder_constantData :: #force_inline proc(self: ^ArgumentEncoder, index: NS.UInteger) -> rawptr { return msgSend(rawptr, self, "constantDataAtIndex:", index) } @(objc_type=ArgumentEncoder, objc_name="device") @@ -5172,8 +5172,8 @@ ArgumentEncoder_encodedLength :: #force_inline proc(self: ^ArgumentEncoder) -> N ArgumentEncoder_label :: #force_inline proc(self: ^ArgumentEncoder) -> ^NS.String { return msgSend(^NS.String, self, "label") } -@(objc_type=ArgumentEncoder, objc_name="newArgumentEncoderForBufferAtIndex") -ArgumentEncoder_newArgumentEncoderForBufferAtIndex :: #force_inline proc(self: ^ArgumentEncoder, index: NS.UInteger) -> ^ArgumentEncoder { +@(objc_type=ArgumentEncoder, objc_name="newArgumentEncoderForBuffer") +ArgumentEncoder_newArgumentEncoderForBuffer :: #force_inline proc(self: ^ArgumentEncoder, index: NS.UInteger) -> ^ArgumentEncoder { return msgSend(^ArgumentEncoder, self, "newArgumentEncoderForBufferAtIndex:", index) } @(objc_type=ArgumentEncoder, objc_name="setAccelerationStructure") @@ -5491,7 +5491,7 @@ Buffer_contents :: #force_inline proc(self: ^Buffer) -> []byte { } @(objc_type=Buffer, objc_name="contentsPointer") Buffer_contentsPointer :: #force_inline proc(self: ^Buffer) -> rawptr { - return msgSend([^]byte, self, "contents") + return msgSend(rawptr, self, "contents") } @(objc_type=Buffer, objc_name="didModifyRange") Buffer_didModifyRange :: #force_inline proc(self: ^Buffer, range: NS.Range) { @@ -5979,8 +5979,8 @@ ComputeCommandEncoder_setBuffers :: #force_inline proc(self: ^ComputeCommandEnco msgSend(nil, self, "setBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=ComputeCommandEncoder, objc_name="setBytes") -ComputeCommandEncoder_setBytes :: #force_inline proc(self: ^ComputeCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { - msgSend(nil, self, "setBytes:length:atIndex:", bytes, length, index) +ComputeCommandEncoder_setBytes :: #force_inline proc(self: ^ComputeCommandEncoder, bytes: []byte, index: NS.UInteger) { + msgSend(nil, self, "setBytes:length:atIndex:", raw_data(bytes), NS.UInteger(len(bytes)), index) } @(objc_type=ComputeCommandEncoder, objc_name="setComputePipelineState") ComputeCommandEncoder_setComputePipelineState :: #force_inline proc(self: ^ComputeCommandEncoder, pipelineState: ^ComputePipelineState) { @@ -5999,16 +5999,16 @@ ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) msgSend(nil, self, "setIntersectionFunctionTables:withBufferRange:", raw_data(intersectionFunctionTables), range) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStateAtIndex") -ComputeCommandEncoder_setSamplerStateAtIndex :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState") +ComputeCommandEncoder_setSamplerState :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_lodMinClamp_lodMaxClampAtIndex") -ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_lodMinClamp_lodMaxClamp") +ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClamp :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStates_lodMinClamps_lodMaxClampsWithRange") -ComputeCommandEncoder_setSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: []^SamplerState, lodMinClamps, lodMaxClamps: []f32, range: NS.Range) { +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStatesWithLod") +ComputeCommandEncoder_setSamplerStatesWithLod :: #force_inline proc(self: ^ComputeCommandEncoder, samplers: []^SamplerState, lodMinClamps, lodMaxClamps: []f32, range: NS.Range) { msgSend(nil, self, "setSamplerStates:lodMinClamps:lodMaxClamps:withRange:", raw_data(samplers), raw_data(lodMinClamps), raw_data(lodMaxClamps), range) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerStatesWithRange") @@ -6356,11 +6356,11 @@ Device_argumentBuffersSupport :: #force_inline proc(self: ^Device) -> ArgumentBu return msgSend(ArgumentBuffersTier, self, "argumentBuffersSupport") } @(objc_type=Device, objc_name="convertSparsePixelRegions") -Device_convertSparsePixelRegions :: #force_inline proc(self: ^Device, pixelRegions: ^Region, tileRegions: ^Region, tileSize: Size, mode: SparseTextureRegionAlignmentMode, numRegions: NS.UInteger) { +Device_convertSparsePixelRegions :: #force_inline proc(self: ^Device, pixelRegions, tileRegions: ^Region, tileSize: Size, mode: SparseTextureRegionAlignmentMode, numRegions: NS.UInteger) { msgSend(nil, self, "convertSparsePixelRegions:toTileRegions:withTileSize:alignmentMode:numRegions:", pixelRegions, tileRegions, tileSize, mode, numRegions) } @(objc_type=Device, objc_name="convertSparseTileRegions") -Device_convertSparseTileRegions :: #force_inline proc(self: ^Device, tileRegions: ^Region, pixelRegions: ^Region, tileSize: Size, numRegions: NS.UInteger) { +Device_convertSparseTileRegions :: #force_inline proc(self: ^Device, tileRegions, pixelRegions: ^Region, tileSize: Size, numRegions: NS.UInteger) { msgSend(nil, self, "convertSparseTileRegions:toPixelRegions:withTileSize:numRegions:", tileRegions, pixelRegions, tileSize, numRegions) } @(objc_type=Device, objc_name="counterSets") @@ -6372,20 +6372,22 @@ Device_currentAllocatedSize :: #force_inline proc(self: ^Device) -> NS.UInteger return msgSend(NS.UInteger, self, "currentAllocatedSize") } @(objc_type=Device, objc_name="getDefaultSamplePositions") -Device_getDefaultSamplePositions :: #force_inline proc(self: ^Device, positions: ^SamplePosition, count: NS.UInteger) { - msgSend(nil, self, "getDefaultSamplePositions:count:", positions, count) +Device_getDefaultSamplePositions :: #force_inline proc(self: ^Device, positions: []SamplePosition) { + msgSend(nil, self, "getDefaultSamplePositions:count:", raw_data(positions), NS.UInteger(len(positions))) } @(objc_type=Device, objc_name="hasUnifiedMemory") Device_hasUnifiedMemory :: #force_inline proc(self: ^Device) -> BOOL { return msgSend(BOOL, self, "hasUnifiedMemory") } @(objc_type=Device, objc_name="heapBufferSizeAndAlignWithLength") -Device_heapBufferSizeAndAlignWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> SizeAndAlign { - return msgSend(SizeAndAlign, self, "heapBufferSizeAndAlignWithLength:options:", length, options) +Device_heapBufferSizeAndAlignWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> (size, align: NS.UInteger) { + res := msgSend(SizeAndAlign, self, "heapBufferSizeAndAlignWithLength:options:", length, options) + return res.size, res.align } @(objc_type=Device, objc_name="heapTextureSizeAndAlignWithDescriptor") -Device_heapTextureSizeAndAlignWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> SizeAndAlign { - return msgSend(SizeAndAlign, self, "heapTextureSizeAndAlignWithDescriptor:", desc) +Device_heapTextureSizeAndAlignWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> (size, align: NS.UInteger) { + res := msgSend(SizeAndAlign, self, "heapTextureSizeAndAlignWithDescriptor:", desc) + return res.size, res.align } @(objc_type=Device, objc_name="isDepth24Stencil8PixelFormatSupported") Device_isDepth24Stencil8PixelFormatSupported :: #force_inline proc(self: ^Device) -> BOOL { @@ -6461,12 +6463,12 @@ Device_newBinaryArchiveWithDescriptor :: #force_inline proc(self: ^Device, descr return } @(objc_type=Device, objc_name="newBufferWithBytes") -Device_newBufferWithBytes :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { - return msgSend(^Buffer, self, "newBufferWithBytes:length:options:", pointer, length, options) +Device_newBufferWithBytes :: #force_inline proc(self: ^Device, bytes: []byte, options: ResourceOptions) -> ^Buffer { + return msgSend(^Buffer, self, "newBufferWithBytes:length:options:", raw_data(bytes), NS.UInteger(len(bytes)), options) } @(objc_type=Device, objc_name="newBufferWithBytesNoCopy") -Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, pointer: rawptr, length: NS.UInteger, options: ResourceOptions, deallocator: rawptr) -> ^Buffer { - return msgSend(^Buffer, self, "newBufferWithBytesNoCopy:length:options:deallocator:", pointer, length, options, deallocator) +Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, bytes: []byte, options: ResourceOptions, deallocator: rawptr) -> ^Buffer { + return msgSend(^Buffer, self, "newBufferWithBytesNoCopy:length:options:deallocator:", raw_data(bytes), NS.UInteger(len(bytes)), options, deallocator) } @(objc_type=Device, objc_name="newBufferWithLength") Device_newBufferWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { @@ -7155,12 +7157,12 @@ Methods: @(objc_class="MTLIndirectCommandBuffer") IndirectCommandBuffer :: struct { using _: Resource } -@(objc_type=IndirectCommandBuffer, objc_name="indirectComputeCommandAtIndex") -IndirectCommandBuffer_indirectComputeCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { +@(objc_type=IndirectCommandBuffer, objc_name="indirectComputeCommand") +IndirectCommandBuffer_indirectComputeCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "indirectComputeCommandAtIndex:", commandIndex) } -@(objc_type=IndirectCommandBuffer, objc_name="indirectRenderCommandAtIndex") -IndirectCommandBuffer_indirectRenderCommandAtIndex :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { +@(objc_type=IndirectCommandBuffer, objc_name="indirectRenderCommand") +IndirectCommandBuffer_indirectRenderCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "indirectRenderCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="resetWithRange") @@ -7321,8 +7323,8 @@ IntersectionFunctionTable_setFunction :: #force_inline proc(self: ^IntersectionF IntersectionFunctionTable_setFunctions :: #force_inline proc(self: ^IntersectionFunctionTable, functions: []^FunctionHandle, range: NS.Range) { msgSend(nil, self, "setFunctions:withRange:", raw_data(functions), range) } -@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignatureAtIndex") -IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignatureAtIndex :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: NS.UInteger) { +@(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignature") +IntersectionFunctionTable_setOpaqueTriangleIntersectionFunctionWithSignature :: #force_inline proc(self: ^IntersectionFunctionTable, signature: IntersectionFunctionSignature, index: NS.UInteger) { msgSend(nil, self, "setOpaqueTriangleIntersectionFunctionWithSignature:atIndex:", signature, index) } @(objc_type=IntersectionFunctionTable, objc_name="setOpaqueTriangleIntersectionFunctionWithSignatureWithRange") @@ -7511,8 +7513,9 @@ RasterizationRateMap_mapScreenToPhysicalCoordinates :: #force_inline proc(self: return msgSend(Coordinate2D, self, "mapScreenToPhysicalCoordinates:forLayer:", screenCoordinates, layerIndex) } @(objc_type=RasterizationRateMap, objc_name="parameterBufferSizeAndAlign") -RasterizationRateMap_parameterBufferSizeAndAlign :: #force_inline proc(self: ^RasterizationRateMap) -> SizeAndAlign { - return msgSend(SizeAndAlign, self, "parameterBufferSizeAndAlign") +RasterizationRateMap_parameterBufferSizeAndAlign :: #force_inline proc(self: ^RasterizationRateMap) -> (size, align: NS.UInteger) { + res := msgSend(SizeAndAlign, self, "parameterBufferSizeAndAlign") + return res.size, res.align } @(objc_type=RasterizationRateMap, objc_name="physicalGranularity") RasterizationRateMap_physicalGranularity :: #force_inline proc(self: ^RasterizationRateMap) -> Size { @@ -7748,16 +7751,16 @@ RenderCommandEncoder_setFragmentBuffers :: #force_inline proc(self: ^RenderComma RenderCommandEncoder_setFragmentBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: []byte, index: NS.UInteger) { msgSend(nil, self, "setFragmentBytes:length:atIndex:", raw_data(bytes), NS.UInteger(len(bytes)), index) } -@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStateAtIndex") -RenderCommandEncoder_setFragmentSamplerStateAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState") +RenderCommandEncoder_setFragmentSamplerState :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setFragmentSamplerState:atIndex:", sampler, index) } -@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerState_lodMinClamp_lodMaxClampAtIndex") -RenderCommandEncoder_setFragmentSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStateWithLod") +RenderCommandEncoder_setFragmentSamplerStateWithLod :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setFragmentSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStates_lodMinClamps_lodMaxClampsWithRange") -RenderCommandEncoder_setFragmentSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, lodMinClamps: []f32, lodMaxClamps: []f32, range: NS.Range) { +@(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStatesWithLod") +RenderCommandEncoder_setFragmentSamplerStatesWithLod :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, lodMinClamps, lodMaxClamps: []f32, range: NS.Range) { msgSend(nil, self, "setFragmentSamplerStates:lodMinClamps:lodMaxClamps:withRange:", raw_data(samplers), raw_data(lodMinClamps), raw_data(lodMaxClamps), range) } @(objc_type=RenderCommandEncoder, objc_name="setFragmentSamplerStatesWithRange") @@ -7825,36 +7828,36 @@ RenderCommandEncoder_setTileBufferOffset :: #force_inline proc(self: ^RenderComm msgSend(nil, self, "setTileBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileBuffers") -RenderCommandEncoder_setTileBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { - msgSend(nil, self, "setTileBuffers:offsets:withRange:", buffers, offsets, range) +RenderCommandEncoder_setTileBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: []^Buffer, offsets: []NS.UInteger, range: NS.Range) { + msgSend(nil, self, "setTileBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=RenderCommandEncoder, objc_name="setTileBytes") -RenderCommandEncoder_setTileBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { - msgSend(nil, self, "setTileBytes:length:atIndex:", bytes, length, index) +RenderCommandEncoder_setTileBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: []byte, index: NS.UInteger) { + msgSend(nil, self, "setTileBytes:length:atIndex:", raw_data(bytes), NS.UInteger(len(bytes)), index) } -@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStateAtIndex") -RenderCommandEncoder_setTileSamplerStateAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState") +RenderCommandEncoder_setTileSamplerState :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setTileSamplerState:atIndex:", sampler, index) } -@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerState_lodMinClamp_lodMaxClampAtIndex") -RenderCommandEncoder_setTileSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStateWithLod") +RenderCommandEncoder_setTileSamplerStateWithLod :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setTileSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStates_lodMinClamps_lodMaxClampsWithRange") -RenderCommandEncoder_setTileSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { - msgSend(nil, self, "setTileSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +@(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStatesWithLod") +RenderCommandEncoder_setTileSamplerStatesWithLod :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, lodMinClamps, lodMaxClamps: []f32, range: NS.Range) { + msgSend(nil, self, "setTileSamplerStates:lodMinClamps:lodMaxClamps:withRange:", raw_data(samplers), raw_data(lodMinClamps), raw_data(lodMaxClamps), range) } @(objc_type=RenderCommandEncoder, objc_name="setTileSamplerStatesWithRange") -RenderCommandEncoder_setTileSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { - msgSend(nil, self, "setTileSamplerStates:withRange:", samplers, range) +RenderCommandEncoder_setTileSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, range: NS.Range) { + msgSend(nil, self, "setTileSamplerStates:withRange:", raw_data(samplers), range) } @(objc_type=RenderCommandEncoder, objc_name="setTileTexture") RenderCommandEncoder_setTileTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setTileTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setTileTextures") -RenderCommandEncoder_setTileTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: [^]^Texture, range: NS.Range) { - msgSend(nil, self, "setTileTextures:withRange:", textures, range) +RenderCommandEncoder_setTileTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: []^Texture, range: NS.Range) { + msgSend(nil, self, "setTileTextures:withRange:", raw_data(textures), range) } @(objc_type=RenderCommandEncoder, objc_name="setTriangleFillMode") RenderCommandEncoder_setTriangleFillMode :: #force_inline proc(self: ^RenderCommandEncoder, fillMode: TriangleFillMode) { @@ -7873,44 +7876,44 @@ RenderCommandEncoder_setVertexBufferOffset :: #force_inline proc(self: ^RenderCo msgSend(nil, self, "setVertexBufferOffset:atIndex:", offset, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBuffers") -RenderCommandEncoder_setVertexBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: [^]^Buffer, offsets: [^]NS.UInteger, range: NS.Range) { - msgSend(nil, self, "setVertexBuffers:offsets:withRange:", buffers, offsets, range) +RenderCommandEncoder_setVertexBuffers :: #force_inline proc(self: ^RenderCommandEncoder, buffers: []^Buffer, offsets: []NS.UInteger, range: NS.Range) { + msgSend(nil, self, "setVertexBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexBytes") -RenderCommandEncoder_setVertexBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: rawptr, length: NS.UInteger, index: NS.UInteger) { - msgSend(nil, self, "setVertexBytes:length:atIndex:", bytes, length, index) +RenderCommandEncoder_setVertexBytes :: #force_inline proc(self: ^RenderCommandEncoder, bytes: []byte, index: NS.UInteger) { + msgSend(nil, self, "setVertexBytes:length:atIndex:", raw_data(bytes), NS.UInteger(len(bytes)), index) } -@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStateAtIndex") -RenderCommandEncoder_setVertexSamplerStateAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState") +RenderCommandEncoder_setVertexSamplerState :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setVertexSamplerState:atIndex:", sampler, index) } -@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerState_lodMinClamp_lodMaxClampAtIndex") -RenderCommandEncoder_setVertexSamplerState_lodMinClamp_lodMaxClampAtIndex :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStateWithLod") +RenderCommandEncoder_setVertexSamplerStateWithLod :: #force_inline proc(self: ^RenderCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setVertexSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } -@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStates_lodMinClamps_lodMaxClampsWithRange") -RenderCommandEncoder_setVertexSamplerStates_lodMinClamps_lodMaxClampsWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, lodMinClamps: ^f32, lodMaxClamps: ^f32, range: NS.Range) { - msgSend(nil, self, "setVertexSamplerStates:lodMinClamps:lodMaxClamps:withRange:", samplers, lodMinClamps, lodMaxClamps, range) +@(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStatesWithLod") +RenderCommandEncoder_setVertexSamplerStatesWithLod :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, lodMinClamps, lodMaxClamps: []f32, range: NS.Range) { + msgSend(nil, self, "setVertexSamplerStates:lodMinClamps:lodMaxClamps:withRange:", raw_data(samplers), raw_data(lodMinClamps), raw_data(lodMaxClamps), range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexSamplerStatesWithRange") -RenderCommandEncoder_setVertexSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: [^]^SamplerState, range: NS.Range) { - msgSend(nil, self, "setVertexSamplerStates:withRange:", samplers, range) +RenderCommandEncoder_setVertexSamplerStatesWithRange :: #force_inline proc(self: ^RenderCommandEncoder, samplers: []^SamplerState, range: NS.Range) { + msgSend(nil, self, "setVertexSamplerStates:withRange:", raw_data(samplers), range) } @(objc_type=RenderCommandEncoder, objc_name="setVertexTexture") RenderCommandEncoder_setVertexTexture :: #force_inline proc(self: ^RenderCommandEncoder, texture: ^Texture, index: NS.UInteger) { msgSend(nil, self, "setVertexTexture:atIndex:", texture, index) } @(objc_type=RenderCommandEncoder, objc_name="setVertexTextures") -RenderCommandEncoder_setVertexTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: [^]^Texture, range: NS.Range) { - msgSend(nil, self, "setVertexTextures:withRange:", textures, range) +RenderCommandEncoder_setVertexTextures :: #force_inline proc(self: ^RenderCommandEncoder, textures: []^Texture, range: NS.Range) { + msgSend(nil, self, "setVertexTextures:withRange:", raw_data(textures), range) } @(objc_type=RenderCommandEncoder, objc_name="setViewport") RenderCommandEncoder_setViewport :: #force_inline proc(self: ^RenderCommandEncoder, viewport: Viewport) { msgSend(nil, self, "setViewport:", viewport) } @(objc_type=RenderCommandEncoder, objc_name="setViewports") -RenderCommandEncoder_setViewports :: #force_inline proc(self: ^RenderCommandEncoder, viewports: ^Viewport, count: NS.UInteger) { - msgSend(nil, self, "setViewports:count:", viewports, count) +RenderCommandEncoder_setViewports :: #force_inline proc(self: ^RenderCommandEncoder, viewports: []Viewport) { + msgSend(nil, self, "setViewports:count:", raw_data(viewports), NS.UInteger(len(viewports))) } @(objc_type=RenderCommandEncoder, objc_name="setVisibilityResultMode") RenderCommandEncoder_setVisibilityResultMode :: #force_inline proc(self: ^RenderCommandEncoder, mode: VisibilityResultMode, offset: NS.UInteger) { @@ -7941,12 +7944,12 @@ RenderCommandEncoder_useHeapWithStages :: #force_inline proc(self: ^RenderComman msgSend(nil, self, "useHeap:stages:", heap, stages) } @(objc_type=RenderCommandEncoder, objc_name="useHeaps") -RenderCommandEncoder_useHeaps :: #force_inline proc(self: ^RenderCommandEncoder, heaps: [^]^Heap, count: NS.UInteger) { - msgSend(nil, self, "useHeaps:count:", heaps, count) +RenderCommandEncoder_useHeaps :: #force_inline proc(self: ^RenderCommandEncoder, heaps: []^Heap) { + msgSend(nil, self, "useHeaps:count:", raw_data(heaps), NS.UInteger(len(heaps))) } @(objc_type=RenderCommandEncoder, objc_name="useHeapsWithStages") -RenderCommandEncoder_useHeapsWithStages :: #force_inline proc(self: ^RenderCommandEncoder, heaps: [^]^Heap, count: NS.UInteger, stages: RenderStages) { - msgSend(nil, self, "useHeaps:count:stages:", heaps, count, stages) +RenderCommandEncoder_useHeapsWithStages :: #force_inline proc(self: ^RenderCommandEncoder, heaps: []^Heap, stages: RenderStages) { + msgSend(nil, self, "useHeaps:count:stages:", raw_data(heaps), NS.UInteger(len(heaps)), stages) } @(objc_type=RenderCommandEncoder, objc_name="useResource") RenderCommandEncoder_useResource :: #force_inline proc(self: ^RenderCommandEncoder, resource: ^Resource, usage: ResourceUsage) { @@ -7957,12 +7960,12 @@ RenderCommandEncoder_useResourceWithStages :: #force_inline proc(self: ^RenderCo msgSend(nil, self, "useResource:usage:stages:", resource, usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="useResources") -RenderCommandEncoder_useResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage) { - msgSend(nil, self, "useResources:count:usage:", resources, count, usage) +RenderCommandEncoder_useResources :: #force_inline proc(self: ^RenderCommandEncoder, resources: []^Resource, usage: ResourceUsage) { + msgSend(nil, self, "useResources:count:usage:", raw_data(resources), NS.UInteger(len(resources)), usage) } @(objc_type=RenderCommandEncoder, objc_name="useResourcesStages") -RenderCommandEncoder_useResourcesStages :: #force_inline proc(self: ^RenderCommandEncoder, resources: [^]^Resource, count: NS.UInteger, usage: ResourceUsage, stages: RenderStages) { - msgSend(nil, self, "useResources:count:usage:stages:", resources, count, usage, stages) +RenderCommandEncoder_useResourcesStages :: #force_inline proc(self: ^RenderCommandEncoder, resources: []^Resource, usage: ResourceUsage, stages: RenderStages) { + msgSend(nil, self, "useResources:count:usage:stages:", raw_data(resources), NS.UInteger(len(resources)), usage, stages) } @(objc_type=RenderCommandEncoder, objc_name="waitForFence") RenderCommandEncoder_waitForFence :: #force_inline proc(self: ^RenderCommandEncoder, fence: ^Fence, stages: RenderStages) { @@ -8389,6 +8392,6 @@ VisibleFunctionTable_setFunction :: #force_inline proc(self: ^VisibleFunctionTab msgSend(nil, self, "setFunction:atIndex:", function, index) } @(objc_type=VisibleFunctionTable, objc_name="setFunctions") -VisibleFunctionTable_setFunctions :: #force_inline proc(self: ^VisibleFunctionTable, functions: [^]^FunctionHandle, range: NS.Range) { - msgSend(nil, self, "setFunctions:withRange:", functions, range) +VisibleFunctionTable_setFunctions :: #force_inline proc(self: ^VisibleFunctionTable, functions: []^FunctionHandle, range: NS.Range) { + msgSend(nil, self, "setFunctions:withRange:", raw_data(functions), range) } diff --git a/core/sys/darwin/Metal/MetalTypes.odin b/core/sys/darwin/Metal/MetalTypes.odin index e1269f926..4928847a9 100644 --- a/core/sys/darwin/Metal/MetalTypes.odin +++ b/core/sys/darwin/Metal/MetalTypes.odin @@ -147,8 +147,8 @@ Size :: struct { } SizeAndAlign :: struct { - size: NS.Integer, - align: NS.Integer, + size: NS.UInteger, + align: NS.UInteger, } StageInRegionIndirectArguments :: struct { From 4d0fd4cf1991f52db6e8586f2463470617982989 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 15:56:32 +0000 Subject: [PATCH 0170/1052] Correct `device()` usage --- core/sys/darwin/Metal/MetalClasses.odin | 48 ++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 1f4ae50cb..8edb65694 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -4064,8 +4064,8 @@ SharedTextureHandle_init :: #force_inline proc(self: ^SharedTextureHandle) -> ^S return msgSend(^SharedTextureHandle, self, "init") } @(objc_type=SharedTextureHandle, objc_name="device") -SharedTextureHandle_device :: #force_inline proc(self: ^SharedTextureHandle) -> ^SharedTextureHandle { - return msgSend(^SharedTextureHandle, self, "device") +SharedTextureHandle_device :: #force_inline proc(self: ^SharedTextureHandle) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=SharedTextureHandle, objc_name="label") SharedTextureHandle_label :: #force_inline proc(self: ^SharedTextureHandle) -> ^NS.String { @@ -6169,8 +6169,8 @@ Methods: CounterSampleBuffer :: struct { using _: NS.Object } @(objc_type=CounterSampleBuffer, objc_name="device") -CounterSampleBuffer_device :: #force_inline proc(self: ^CounterSampleBuffer) -> ^CounterSampleBuffer { - return msgSend(^CounterSampleBuffer, self, "device") +CounterSampleBuffer_device :: #force_inline proc(self: ^CounterSampleBuffer) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=CounterSampleBuffer, objc_name="label") CounterSampleBuffer_label :: #force_inline proc(self: ^CounterSampleBuffer) -> ^NS.String { @@ -6792,8 +6792,8 @@ Methods: DynamicLibrary :: struct { using _: NS.Object } @(objc_type=DynamicLibrary, objc_name="device") -DynamicLibrary_device :: #force_inline proc(self: ^DynamicLibrary) -> ^DynamicLibrary { - return msgSend(^DynamicLibrary, self, "device") +DynamicLibrary_device :: #force_inline proc(self: ^DynamicLibrary) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=DynamicLibrary, objc_name="installName") DynamicLibrary_installName :: #force_inline proc(self: ^DynamicLibrary) -> ^NS.String { @@ -6828,8 +6828,8 @@ Methods: Event :: struct { using _: NS.Object } @(objc_type=Event, objc_name="device") -Event_device :: #force_inline proc(self: ^Event) -> ^Event { - return msgSend(^Event, self, "device") +Event_device :: #force_inline proc(self: ^Event) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=Event, objc_name="label") Event_label :: #force_inline proc(self: ^Event) -> ^NS.String { @@ -6855,8 +6855,8 @@ Methods: Fence :: struct { using _: NS.Object } @(objc_type=Fence, objc_name="device") -Fence_device :: #force_inline proc(self: ^Fence) -> ^Fence { - return msgSend(^Fence, self, "device") +Fence_device :: #force_inline proc(self: ^Fence) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=Fence, objc_name="label") Fence_label :: #force_inline proc(self: ^Fence) -> ^NS.String { @@ -6892,8 +6892,8 @@ Methods: Function :: struct { using _: NS.Object } @(objc_type=Function, objc_name="device") -Function_device :: #force_inline proc(self: ^Function) -> ^Function { - return msgSend(^Function, self, "device") +Function_device :: #force_inline proc(self: ^Function) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=Function, objc_name="functionConstantsDictionary") Function_functionConstantsDictionary :: #force_inline proc(self: ^Function) -> ^NS.Dictionary { @@ -6959,8 +6959,8 @@ Methods: FunctionHandle :: struct { using _: NS.Object } @(objc_type=FunctionHandle, objc_name="device") -FunctionHandle_device :: #force_inline proc(self: ^FunctionHandle) -> ^FunctionHandle { - return msgSend(^FunctionHandle, self, "device") +FunctionHandle_device :: #force_inline proc(self: ^FunctionHandle) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=FunctionHandle, objc_name="functionType") FunctionHandle_functionType :: #force_inline proc(self: ^FunctionHandle) -> FunctionType { @@ -7082,8 +7082,8 @@ Heap_currentAllocatedSize :: #force_inline proc(self: ^Heap) -> NS.UInteger { return msgSend(NS.UInteger, self, "currentAllocatedSize") } @(objc_type=Heap, objc_name="device") -Heap_device :: #force_inline proc(self: ^Heap) -> ^Heap { - return msgSend(^Heap, self, "device") +Heap_device :: #force_inline proc(self: ^Heap) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=Heap, objc_name="hazardTrackingMode") Heap_hazardTrackingMode :: #force_inline proc(self: ^Heap) -> HazardTrackingMode { @@ -7493,8 +7493,8 @@ RasterizationRateMap_copyParameterDataToBuffer :: #force_inline proc(self: ^Rast msgSend(nil, self, "copyParameterDataToBuffer:offset:", buffer, offset) } @(objc_type=RasterizationRateMap, objc_name="device") -RasterizationRateMap_device :: #force_inline proc(self: ^RasterizationRateMap) -> ^RasterizationRateMap { - return msgSend(^RasterizationRateMap, self, "device") +RasterizationRateMap_device :: #force_inline proc(self: ^RasterizationRateMap) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=RasterizationRateMap, objc_name="label") RasterizationRateMap_label :: #force_inline proc(self: ^RasterizationRateMap) -> ^NS.String { @@ -7991,8 +7991,8 @@ Methods: RenderPipelineState :: struct { using _: NS.Object } @(objc_type=RenderPipelineState, objc_name="device") -RenderPipelineState_device :: #force_inline proc(self: ^RenderPipelineState) -> ^RenderPipelineState { - return msgSend(^RenderPipelineState, self, "device") +RenderPipelineState_device :: #force_inline proc(self: ^RenderPipelineState) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=RenderPipelineState, objc_name="imageblockMemoryLengthForDimensions") RenderPipelineState_imageblockMemoryLengthForDimensions :: #force_inline proc(self: ^RenderPipelineState, imageblockDimensions: Size) -> ^RenderPipelineState { @@ -8052,8 +8052,8 @@ Resource_cpuCacheMode :: #force_inline proc(self: ^Resource) -> CPUCacheMode { return msgSend(CPUCacheMode, self, "cpuCacheMode") } @(objc_type=Resource, objc_name="device") -Resource_device :: #force_inline proc(self: ^Resource) -> ^Resource { - return msgSend(^Resource, self, "device") +Resource_device :: #force_inline proc(self: ^Resource) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=Resource, objc_name="hazardTrackingMode") Resource_hazardTrackingMode :: #force_inline proc(self: ^Resource) -> HazardTrackingMode { @@ -8147,8 +8147,8 @@ Methods: SamplerState :: struct { using _: NS.Object } @(objc_type=SamplerState, objc_name="device") -SamplerState_device :: #force_inline proc(self: ^SamplerState) -> ^SamplerState { - return msgSend(^SamplerState, self, "device") +SamplerState_device :: #force_inline proc(self: ^SamplerState) -> ^Device { + return msgSend(^Device, self, "device") } @(objc_type=SamplerState, objc_name="label") SamplerState_label :: #force_inline proc(self: ^SamplerState) -> ^NS.String { From 5212f62f54f5e7a88a6b7d5c40eed1761b526b52 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:18:23 +0000 Subject: [PATCH 0171/1052] Improve many methods with WithDescriptor suffixes --- core/sys/darwin/Metal/MetalClasses.odin | 118 ++++++++++++------------ 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 8edb65694..da1bffef4 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -4028,8 +4028,8 @@ SharedEventListener_alloc :: #force_inline proc() -> ^SharedEventListener { return msgSend(^SharedEventListener, SharedEventListener, "alloc") } @(objc_type=SharedEventListener, objc_name="dispatchQueue") -SharedEventListener_dispatchQueue :: #force_inline proc(self: ^SharedEventListener) -> NS.UInteger { - return msgSend(NS.UInteger, self, "dispatchQueue") +SharedEventListener_dispatchQueue :: #force_inline proc(self: ^SharedEventListener) -> dispatch_queue_t { + return msgSend(dispatch_queue_t, self, "dispatchQueue") } @(objc_type=SharedEventListener, objc_name="init") SharedEventListener_init :: #force_inline proc(self: ^SharedEventListener) -> ^SharedEventListener { @@ -5283,18 +5283,18 @@ Methods: @(objc_class="MTLBinaryArchive") BinaryArchive :: struct { using _: NS.Copying(BinaryArchive) } -@(objc_type=BinaryArchive, objc_name="addComputePipelineFunctionsWithDescriptor") -BinaryArchive_addComputePipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { +@(objc_type=BinaryArchive, objc_name="addComputePipelineFunctions") +BinaryArchive_addComputePipelineFunctions :: #force_inline proc(self: ^BinaryArchive, descriptor: ^ComputePipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "addComputePipelineFunctionsWithDescriptor:error:", descriptor, &error) return } -@(objc_type=BinaryArchive, objc_name="addRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { +@(objc_type=BinaryArchive, objc_name="addRenderPipelineFunctions") +BinaryArchive_addRenderPipelineFunctions :: #force_inline proc(self: ^BinaryArchive, descriptor: ^RenderPipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "addRenderPipelineFunctionsWithDescriptor:error:", descriptor, &error) return } -@(objc_type=BinaryArchive, objc_name="addTileRenderPipelineFunctionsWithDescriptor") -BinaryArchive_addTileRenderPipelineFunctionsWithDescriptor :: #force_inline proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { +@(objc_type=BinaryArchive, objc_name="addTileRenderPipelineFunctions") +BinaryArchive_addTileRenderPipelineFunctions :: #force_inline proc(self: ^BinaryArchive, descriptor: ^TileRenderPipelineDescriptor) -> (ok: BOOL, error: ^NS.Error) { ok = msgSend(BOOL, self, "addTileRenderPipelineFunctionsWithDescriptor:error:", descriptor, &error) return } @@ -5505,8 +5505,8 @@ Buffer_length :: #force_inline proc(self: ^Buffer) -> NS.UInteger { Buffer_newRemoteBufferViewForDevice :: #force_inline proc(self: ^Buffer, device: ^Device) -> ^Buffer { return msgSend(^Buffer, self, "newRemoteBufferViewForDevice:", device) } -@(objc_type=Buffer, objc_name="newTextureWithDescriptor") -Buffer_newTextureWithDescriptor :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: NS.UInteger, bytesPerRow: NS.UInteger) -> ^Buffer { +@(objc_type=Buffer, objc_name="newTexture") +Buffer_newTexture :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: NS.UInteger, bytesPerRow: NS.UInteger) -> ^Buffer { return msgSend(^Buffer, self, "newTextureWithDescriptor:offset:bytesPerRow:", descriptor, offset, bytesPerRow) } @(objc_type=Buffer, objc_name="remoteStorageBuffer") @@ -5518,11 +5518,6 @@ Buffer_removeAllDebugMarkers :: #force_inline proc(self: ^Buffer) { msgSend(nil, self, "removeAllDebugMarkers") } -@(objc_type=Buffer, objc_name="newTexture") -Buffer_newTexture :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: NS.UInteger, bytesPerRow: NS.UInteger) -> ^Texture { - return msgSend(^Texture, self, "newTextureWithDescriptor:offset:bytesPerRow:") -} - //////////////////////////////////////////////////////////////////////////////// /* @@ -5700,8 +5695,8 @@ CommandBuffer_label :: #force_inline proc(self: ^CommandBuffer) -> ^NS.String { CommandBuffer_logs :: #force_inline proc(self: ^CommandBuffer) -> ^LogContainer { return msgSend(^LogContainer, self, "logs") } -@(objc_type=CommandBuffer, objc_name="parallelRenderCommandEncoderWithDescriptor") -CommandBuffer_parallelRenderCommandEncoderWithDescriptor :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^ParallelRenderCommandEncoder { +@(objc_type=CommandBuffer, objc_name="parallelRenderCommandEncoder") +CommandBuffer_parallelRenderCommandEncoder :: #force_inline proc(self: ^CommandBuffer, renderPassDescriptor: ^RenderPassDescriptor) -> ^ParallelRenderCommandEncoder { return msgSend(^ParallelRenderCommandEncoder, self, "parallelRenderCommandEncoderWithDescriptor:", renderPassDescriptor) } @(objc_type=CommandBuffer, objc_name="popDebugGroup") @@ -6457,8 +6452,8 @@ Device_newAccelerationStructureWithSize :: #force_inline proc(self: ^Device, siz Device_newArgumentEncoderWithArguments :: #force_inline proc(self: ^Device, arguments: ^NS.Array) -> ^ArgumentEncoder { return msgSend(^ArgumentEncoder, self, "newArgumentEncoderWithArguments:", arguments) } -@(objc_type=Device, objc_name="newBinaryArchiveWithDescriptor") -Device_newBinaryArchiveWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor) -> (res: ^BinaryArchive, error: ^NS.Error) { +@(objc_type=Device, objc_name="newBinaryArchive") +Device_newBinaryArchive :: #force_inline proc(self: ^Device, descriptor: ^BinaryArchiveDescriptor) -> (res: ^BinaryArchive, error: ^NS.Error) { res = msgSend(^BinaryArchive, self, "newBinaryArchiveWithDescriptor:error:", descriptor, &error) return } @@ -6470,8 +6465,8 @@ Device_newBufferWithBytes :: #force_inline proc(self: ^Device, bytes: []byte, op Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, bytes: []byte, options: ResourceOptions, deallocator: rawptr) -> ^Buffer { return msgSend(^Buffer, self, "newBufferWithBytesNoCopy:length:options:deallocator:", raw_data(bytes), NS.UInteger(len(bytes)), options, deallocator) } -@(objc_type=Device, objc_name="newBufferWithLength") -Device_newBufferWithLength :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { +@(objc_type=Device, objc_name="newBuffer") +Device_newBuffer :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { return msgSend(^Buffer, self, "newBufferWithLength:options:", length, options) } @(objc_type=Device, objc_name="newCommandQueue") @@ -6509,8 +6504,8 @@ Device_newComputePipelineStateWithFunctionWithReflection :: #force_inline proc(s device = msgSend(^Device, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, &error) return } -@(objc_type=Device, objc_name="newCounterSampleBufferWithDescriptor") -Device_newCounterSampleBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor) -> (device: ^Device, error: ^NS.Error) { +@(objc_type=Device, objc_name="newCounterSampleBuffer") +Device_newCounterSampleBuffer :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor) -> (device: ^Device, error: ^NS.Error) { device = msgSend(^Device, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, &error) return } @@ -6523,8 +6518,8 @@ Device_newDefaultLibraryWithBundle :: #force_inline proc(self: ^Device, bundle: library = msgSend(^Library, self, "newDefaultLibraryWithBundle:error:", bundle, &error) return } -@(objc_type=Device, objc_name="newDepthStencilStateWithDescriptor") -Device_newDepthStencilStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^DepthStencilState { +@(objc_type=Device, objc_name="newDepthStencilState") +Device_newDepthStencilState :: #force_inline proc(self: ^Device, descriptor: ^DepthStencilDescriptor) -> ^DepthStencilState { return msgSend(^DepthStencilState, self, "newDepthStencilStateWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newDynamicLibrary") @@ -6545,12 +6540,12 @@ Device_newEvent :: #force_inline proc(self: ^Device) -> ^Event { Device_newFence :: #force_inline proc(self: ^Device) -> ^Fence { return msgSend(^Fence, self, "newFence") } -@(objc_type=Device, objc_name="newHeapWithDescriptor") -Device_newHeapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^HeapDescriptor) -> ^Heap { +@(objc_type=Device, objc_name="newHeap") +Device_newHeap :: #force_inline proc(self: ^Device, descriptor: ^HeapDescriptor) -> ^Heap { return msgSend(^Heap, self, "newHeapWithDescriptor:", descriptor) } -@(objc_type=Device, objc_name="newIndirectCommandBufferWithDescriptor") -Device_newIndirectCommandBufferWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: NS.UInteger, options: ResourceOptions) -> ^IndirectCommandBuffer { +@(objc_type=Device, objc_name="newIndirectCommandBuffer") +Device_newIndirectCommandBuffer :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: NS.UInteger, options: ResourceOptions) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "newIndirectCommandBufferWithDescriptor:maxCommandCount:options:", descriptor, maxCount, options) } @(objc_type=Device, objc_name="newLibraryWithData") @@ -6577,16 +6572,16 @@ Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> ( library = msgSend(^Library, self, "newLibraryWithURL:error:", url, &error) return } -@(objc_type=Device, objc_name="newRasterizationRateMapWithDescriptor") -Device_newRasterizationRateMapWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMap { +@(objc_type=Device, objc_name="newRasterizationRateMap") +Device_newRasterizationRateMap :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMap { return msgSend(^RasterizationRateMap, self, "newRasterizationRateMapWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithCompletionHandler") Device_newRenderPipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { msgSend(nil, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) } -@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor") -Device_newRenderPipelineStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { +@(objc_type=Device, objc_name="newRenderPipelineState") +Device_newRenderPipelineState :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, &error) return } @@ -6608,7 +6603,7 @@ Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline p pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } -@(objc_type=Device, objc_name="newSamplerStateWithDescriptor") +@(objc_type=Device, objc_name="newSamplerState") Device_newSamplerState :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^SamplerState { return msgSend(^SamplerState, self, "newSamplerStateWithDescriptor:", descriptor) } @@ -6620,20 +6615,20 @@ Device_newSharedEvent :: #force_inline proc(self: ^Device) -> ^SharedEvent { Device_newSharedEventWithHandle :: #force_inline proc(self: ^Device, sharedEventHandle: ^SharedEventHandle) -> ^SharedEvent { return msgSend(^SharedEvent, self, "newSharedEventWithHandle:", sharedEventHandle) } -@(objc_type=Device, objc_name="newSharedTextureWithDescriptor") -Device_newSharedTextureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^SharedEvent { +@(objc_type=Device, objc_name="newSharedTexture") +Device_newSharedTexture :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^SharedEvent { return msgSend(^SharedEvent, self, "newSharedTextureWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newSharedTextureWithHandle") Device_newSharedTextureWithHandle :: #force_inline proc(self: ^Device, sharedHandle: ^SharedTextureHandle) -> ^SharedEvent { return msgSend(^SharedEvent, self, "newSharedTextureWithHandle:", sharedHandle) } -@(objc_type=Device, objc_name="newTextureWithDescriptor") -Device_newTextureWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^SharedEvent { +@(objc_type=Device, objc_name="newTexture") +Device_newTexture :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^SharedEvent { return msgSend(^SharedEvent, self, "newTextureWithDescriptor:", desc) } -@(objc_type=Device, objc_name="newTextureWithDescriptorWithIOSurface") -Device_newTextureWithDescriptorWithIOSurface :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Texture { +@(objc_type=Device, objc_name="newTextureWithIOSurface") +Device_newTextureWithIOSurface :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Texture { return msgSend(^Texture, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) } @(objc_type=Device, objc_name="peerCount") @@ -7097,20 +7092,20 @@ Heap_label :: #force_inline proc(self: ^Heap) -> ^NS.String { Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "maxAvailableSizeWithAlignment:", alignment) } -@(objc_type=Heap, objc_name="newBufferWithLength") -Heap_newBufferWithLength :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Heap { +@(objc_type=Heap, objc_name="newBuffer") +Heap_newBuffer :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:", length, options) } -@(objc_type=Heap, objc_name="newBufferWithLengthWithOptions") -Heap_newBufferWithLengthWithOptions :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Heap { +@(objc_type=Heap, objc_name="newBufferWithOptions") +Heap_newBufferWithOptions :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "newBufferWithLength:options:offset:", length, options, offset) } -@(objc_type=Heap, objc_name="newTextureWithDescriptor") -Heap_newTextureWithDescriptor :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Heap { +@(objc_type=Heap, objc_name="newTexture") +Heap_newTexture :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Heap { return msgSend(^Heap, self, "newTextureWithDescriptor:", desc) } -@(objc_type=Heap, objc_name="newTextureWithDescriptorWithOffset") -Heap_newTextureWithDescriptorWithOffset :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Heap { +@(objc_type=Heap, objc_name="newTextureWithOffset") +Heap_newTextureWithOffset :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Heap { return msgSend(^Heap, self, "newTextureWithDescriptor:offset:", descriptor, offset) } @(objc_type=Heap, objc_name="resourceOptions") @@ -7380,8 +7375,8 @@ Library_installName :: #force_inline proc(self: ^Library) -> ^NS.String { Library_label :: #force_inline proc(self: ^Library) -> ^NS.String { return msgSend(^NS.String, self, "label") } -@(objc_type=Library, objc_name="newFunctionWithDescriptorWithCompletionHandler") -Library_newFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) -> ^Function { +@(objc_type=Library, objc_name="newFunctionWithCompletionHandler") +Library_newFunctionWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) -> ^Function { return msgSend(^Function, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithDescriptor") @@ -7393,21 +7388,21 @@ Library_newFunctionWithDescriptor :: #force_inline proc(self: ^Library, descript Library_newFunctionWithName :: #force_inline proc(self: ^Library, functionName: ^NS.String) -> ^Function { return msgSend(^Function, self, "newFunctionWithName:", functionName) } -@(objc_type=Library, objc_name="newFunctionWithNameWithConstantValuesAndCompletionHandler") -Library_newFunctionWithNameWithConstantValuesAndCompletionHandler :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) -> ^Function { +@(objc_type=Library, objc_name="newFunctionWithConstantValuesAndCompletionHandler") +Library_newFunctionWithConstantValuesAndCompletionHandler :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) -> ^Function { return msgSend(^Function, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) } -@(objc_type=Library, objc_name="newFunctionWithNameWithConstantValues") -Library_newFunctionWithNameWithConstantValues :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues) -> (function: ^Function, error: ^NS.Error) { +@(objc_type=Library, objc_name="newFunctionWithConstantValues") +Library_newFunctionWithConstantValues :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues) -> (function: ^Function, error: ^NS.Error) { function = msgSend(^Function, self, "newFunctionWithName:constantValues:error:", name, constantValues, &error) return } -@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptorWithCompletionHandler") -Library_newIntersectionFunctionWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) -> ^Function { +@(objc_type=Library, objc_name="newIntersectionFunctionWithCompletionHandler") +Library_newIntersectionFunctionWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) -> ^Function { return msgSend(^Function, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } -@(objc_type=Library, objc_name="newIntersectionFunctionWithDescriptor") -Library_newIntersectionFunctionWithDescriptor :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor) -> (function: ^Function, error: ^NS.Error) { +@(objc_type=Library, objc_name="newIntersectionFunction") +Library_newIntersectionFunction :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor) -> (function: ^Function, error: ^NS.Error) { function = msgSend(^Function, self, "newIntersectionFunctionWithDescriptor:error:", descriptor, &error) return } @@ -8395,3 +8390,10 @@ VisibleFunctionTable_setFunction :: #force_inline proc(self: ^VisibleFunctionTab VisibleFunctionTable_setFunctions :: #force_inline proc(self: ^VisibleFunctionTable, functions: []^FunctionHandle, range: NS.Range) { msgSend(nil, self, "setFunctions:withRange:", raw_data(functions), range) } + + + +// TODO: Entire FunctionStitching API (which appears not to be in been missed from the generator) + + + From 83d63e572a94566de21dbe49b8e29543e69853e6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:21:00 +0000 Subject: [PATCH 0172/1052] Improve indirect stuff --- core/sys/darwin/Metal/MetalClasses.odin | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index da1bffef4..b4625eb51 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -7153,12 +7153,12 @@ Methods: IndirectCommandBuffer :: struct { using _: Resource } @(objc_type=IndirectCommandBuffer, objc_name="indirectComputeCommand") -IndirectCommandBuffer_indirectComputeCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { - return msgSend(^IndirectCommandBuffer, self, "indirectComputeCommandAtIndex:", commandIndex) +IndirectCommandBuffer_indirectComputeCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectComputeBuffer { + return msgSend(^IndirectComputeBuffer, self, "indirectComputeCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="indirectRenderCommand") -IndirectCommandBuffer_indirectRenderCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectCommandBuffer { - return msgSend(^IndirectCommandBuffer, self, "indirectRenderCommandAtIndex:", commandIndex) +IndirectCommandBuffer_indirectRenderCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectRenderBuffer { + return msgSend(^IndirectRenderBuffer, self, "indirectRenderCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="resetWithRange") IndirectCommandBuffer_resetWithRange :: #force_inline proc(self: ^IndirectCommandBuffer, range: NS.Range) { @@ -7251,7 +7251,7 @@ Methods: IndirectRenderCommand :: struct { using _: NS.Object } @(objc_type=IndirectRenderCommand, objc_name="drawIndexedPatches") -IndirectRenderCommand_drawIndexedPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger, buffer: ^Buffer, offset: NS.UInteger, instanceStride: NS.UInteger) { +IndirectRenderCommand_drawIndexedPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger, buffer: ^Buffer, offset: NS.UInteger, instanceStride: NS.UInteger) { msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawIndexedPrimitives") @@ -7259,7 +7259,7 @@ IndirectRenderCommand_drawIndexedPrimitives :: #force_inline proc(self: ^Indirec msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) } @(objc_type=IndirectRenderCommand, objc_name="drawPatches") -IndirectRenderCommand_drawPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger, buffer: ^Buffer, offset: NS.UInteger, instanceStride: NS.UInteger) { +IndirectRenderCommand_drawPatches :: #force_inline proc(self: ^IndirectRenderCommand, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger, buffer: ^Buffer, offset: NS.UInteger, instanceStride: NS.UInteger) { msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawPrimitives") @@ -7631,7 +7631,7 @@ RenderCommandEncoder_drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_ msgSend(nil, self, "drawIndexedPatches:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { +RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_") @@ -7655,7 +7655,7 @@ RenderCommandEncoder_drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirec msgSend(nil, self, "drawPatches:patchIndexBuffer:patchIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, indirectBuffer, indirectBufferOffset) } @(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart: NS.UInteger, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { +RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_indirectBuffer_indirectBufferOffset_") From b755609438816381accefec8c208d8a2d4690ed4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:25:20 +0000 Subject: [PATCH 0173/1052] Improve Library related stuff --- core/sys/darwin/Metal/MetalClasses.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index b4625eb51..e5a4b7508 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -6906,13 +6906,13 @@ Function_label :: #force_inline proc(self: ^Function) -> ^NS.String { Function_name :: #force_inline proc(self: ^Function) -> ^NS.String { return msgSend(^NS.String, self, "name") } -@(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndex") -Function_newArgumentEncoderWithBufferIndex :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger) -> ^Function { - return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:", bufferIndex) +@(objc_type=Function, objc_name="newArgumentEncoder") +Function_newArgumentEncoder :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger) -> ^ArgumentEncoder { + return msgSend(^ArgumentEncoder, self, "newArgumentEncoderWithBufferIndex:", bufferIndex) } -@(objc_type=Function, objc_name="newArgumentEncoderWithBufferIndexWithReflection") -Function_newArgumentEncoderWithBufferIndexWithReflection :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger, reflection: ^AutoreleasedArgument) -> ^Function { - return msgSend(^Function, self, "newArgumentEncoderWithBufferIndex:reflection:", bufferIndex, reflection) +@(objc_type=Function, objc_name="newArgumentEncoderWithReflection") +Function_newArgumentEncoderWithReflection :: #force_inline proc(self: ^Function, bufferIndex: NS.UInteger, reflection: ^AutoreleasedArgument) -> ^ArgumentEncoder { + return msgSend(^ArgumentEncoder, self, "newArgumentEncoderWithBufferIndex:reflection:", bufferIndex, reflection) } @(objc_type=Function, objc_name="options") Function_options :: #force_inline proc(self: ^Function) -> FunctionOptions { From 934e66ab3bb34cdbb9e1a011531d13e9a691c37a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:26:42 +0000 Subject: [PATCH 0174/1052] More improvements --- core/sys/darwin/Metal/MetalClasses.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index e5a4b7508..0eb5c42cf 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -7434,8 +7434,8 @@ Methods: ParallelRenderCommandEncoder :: struct { using _: CommandEncoder } @(objc_type=ParallelRenderCommandEncoder, objc_name="renderCommandEncoder") -ParallelRenderCommandEncoder_renderCommandEncoder :: #force_inline proc(self: ^ParallelRenderCommandEncoder) -> ^ParallelRenderCommandEncoder { - return msgSend(^ParallelRenderCommandEncoder, self, "renderCommandEncoder") +ParallelRenderCommandEncoder_renderCommandEncoder :: #force_inline proc(self: ^ParallelRenderCommandEncoder) -> ^RenderCommandEncoder { + return msgSend(^RenderCommandEncoder, self, "renderCommandEncoder") } @(objc_type=ParallelRenderCommandEncoder, objc_name="setColorStoreAction") ParallelRenderCommandEncoder_setColorStoreAction :: #force_inline proc(self: ^ParallelRenderCommandEncoder, storeAction: StoreAction, colorAttachmentIndex: NS.UInteger) { From 4cc597f4df826ac249ce74ec0d188cc3441acdb8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:32:54 +0000 Subject: [PATCH 0175/1052] RasterizationRate improvements --- core/sys/darwin/Metal/MetalClasses.odin | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 0eb5c42cf..07dce72b0 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -2562,8 +2562,8 @@ RasterizationRateLayerDescriptor_horizontal :: #force_inline proc(self: ^Rasteri return msgSend(^RasterizationRateSampleArray, self, "horizontal") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="horizontalSampleStorage") -RasterizationRateLayerDescriptor_horizontalSampleStorage :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { - return msgSend(^f32, self, "horizontalSampleStorage") +RasterizationRateLayerDescriptor_horizontalSampleStorage :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> [^]f32 { // TODO: how could this be made into a slice? + return msgSend([^]f32, self, "horizontalSampleStorage") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="init") RasterizationRateLayerDescriptor_init :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateLayerDescriptor { @@ -2574,8 +2574,8 @@ RasterizationRateLayerDescriptor_initWithSampleCount :: #force_inline proc(self: return msgSend(^RasterizationRateLayerDescriptor, self, "initWithSampleCount:", sampleCount) } @(objc_type=RasterizationRateLayerDescriptor, objc_name="initWithSampleCountWithDimensions") -RasterizationRateLayerDescriptor_initWithSampleCountWithDimensions :: #force_inline proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size, horizontal: ^f32, vertical: ^f32) -> ^RasterizationRateLayerDescriptor { - return msgSend(^RasterizationRateLayerDescriptor, self, "initWithSampleCount:horizontal:vertical:", sampleCount, horizontal, vertical) +RasterizationRateLayerDescriptor_initWithSampleCountWithDimensions :: #force_inline proc(self: ^RasterizationRateLayerDescriptor, sampleCount: Size, horizontal: []f32, vertical: []f32) -> ^RasterizationRateLayerDescriptor { + return msgSend(^RasterizationRateLayerDescriptor, self, "initWithSampleCount:horizontal:vertical:", sampleCount, raw_data(horizontal), raw_data(vertical)) } @(objc_type=RasterizationRateLayerDescriptor, objc_name="sampleCount") RasterizationRateLayerDescriptor_sampleCount :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> Size { @@ -2586,8 +2586,8 @@ RasterizationRateLayerDescriptor_vertical :: #force_inline proc(self: ^Rasteriza return msgSend(^RasterizationRateSampleArray, self, "vertical") } @(objc_type=RasterizationRateLayerDescriptor, objc_name="verticalSampleStorage") -RasterizationRateLayerDescriptor_verticalSampleStorage :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> ^f32 { - return msgSend(^f32, self, "verticalSampleStorage") +RasterizationRateLayerDescriptor_verticalSampleStorage :: #force_inline proc(self: ^RasterizationRateLayerDescriptor) -> [^]f32 { // TODO: how could this be made into a slice? + return msgSend([^]f32, self, "verticalSampleStorage") } //////////////////////////////////////////////////////////////////////////////// @@ -2691,11 +2691,11 @@ RasterizationRateSampleArray_init :: #force_inline proc(self: ^RasterizationRate return msgSend(^RasterizationRateSampleArray, self, "init") } @(objc_type=RasterizationRateSampleArray, objc_name="object") -RasterizationRateSampleArray_object :: #force_inline proc(self: ^RasterizationRateSampleArray, index: NS.UInteger) -> NS.UInteger { - return msgSend(NS.UInteger, self, "objectAtIndexedSubscript:", index) +RasterizationRateSampleArray_object :: #force_inline proc(self: ^RasterizationRateSampleArray, index: NS.UInteger) -> ^NS.Number { + return msgSend(^NS.Number, self, "objectAtIndexedSubscript:", index) } @(objc_type=RasterizationRateSampleArray, objc_name="setObject") -RasterizationRateSampleArray_setObject :: #force_inline proc(self: ^RasterizationRateSampleArray, value: NS.UInteger, index: NS.UInteger) { +RasterizationRateSampleArray_setObject :: #force_inline proc(self: ^RasterizationRateSampleArray, value: ^NS.Number, index: NS.UInteger) { msgSend(nil, self, "setObject:atIndexedSubscript:", value, index) } @@ -7153,12 +7153,12 @@ Methods: IndirectCommandBuffer :: struct { using _: Resource } @(objc_type=IndirectCommandBuffer, objc_name="indirectComputeCommand") -IndirectCommandBuffer_indirectComputeCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectComputeBuffer { - return msgSend(^IndirectComputeBuffer, self, "indirectComputeCommandAtIndex:", commandIndex) +IndirectCommandBuffer_indirectComputeCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectComputeCommand { + return msgSend(^IndirectComputeCommand, self, "indirectComputeCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="indirectRenderCommand") -IndirectCommandBuffer_indirectRenderCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectRenderBuffer { - return msgSend(^IndirectRenderBuffer, self, "indirectRenderCommandAtIndex:", commandIndex) +IndirectCommandBuffer_indirectRenderCommand :: #force_inline proc(self: ^IndirectCommandBuffer, commandIndex: NS.UInteger) -> ^IndirectRenderCommand { + return msgSend(^IndirectRenderCommand, self, "indirectRenderCommandAtIndex:", commandIndex) } @(objc_type=IndirectCommandBuffer, objc_name="resetWithRange") IndirectCommandBuffer_resetWithRange :: #force_inline proc(self: ^IndirectCommandBuffer, range: NS.Range) { From 7b42cbea209b4481e4ce10775485e6dea63ee7f8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:42:53 +0000 Subject: [PATCH 0176/1052] Improve draw method names on RenderCommandEncoder --- core/sys/darwin/Metal/MetalClasses.odin | 48 ++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 07dce72b0..4a1aeb55f 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -7626,52 +7626,52 @@ RenderCommandEncoder :: struct { using _: CommandEncoder } RenderCommandEncoder_dispatchThreadsPerTile :: #force_inline proc(self: ^RenderCommandEncoder, threadsPerTile: Size) { msgSend(nil, self, "dispatchThreadsPerTile:", threadsPerTile) } -@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawIndexedPatches_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatchesWihtIndirect") +RenderCommandEncoder_drawIndexedPatchesWihtIndirect :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawIndexedPatches:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, indirectBuffer, indirectBufferOffset) } -@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawIndexedPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_controlPointIndexBuffer_controlPointIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawIndexPatchesWithInstances") +RenderCommandEncoder_drawIndexPatchesWithInstance :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, controlPointIndexBuffer: ^Buffer, controlPointIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, controlPointIndexBuffer, controlPointIndexBufferOffset, instanceCount, baseInstance) } -@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives") +RenderCommandEncoder_drawIndexedPrimitives :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset) } -@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, instanceCount: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitivesWithInstanceCount") +RenderCommandEncoder_drawIndexedPrimitivesWithInstanceCount :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, instanceCount: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount) } -@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_") -RenderCommandEncoder_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseVertex: NS.Integer, baseInstance: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawIndexPrimitivesWithBaseVertex") +RenderCommandEncoder_drawIndexPrimitivesWithBaseVertex :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexCount: NS.UInteger, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseVertex: NS.Integer, baseInstance: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:", primitiveType, indexCount, indexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance) } -@(objc_type=RenderCommandEncoder, objc_name="drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawIndexPrimitivesWithIndirect") +RenderCommandEncoder_drawIndexPrimitivesWithIndirect :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indexType: IndexType, indexBuffer: ^Buffer, indexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawIndexedPrimitives:indexType:indexBuffer:indexBufferOffset:indirectBuffer:indirectBufferOffset:", primitiveType, indexType, indexBuffer, indexBufferOffset, indirectBuffer, indirectBufferOffset) } -@(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawPatches_patchIndexBuffer_patchIndexBufferOffset_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawPatches") +RenderCommandEncoder_drawPatches :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawPatches:patchIndexBuffer:patchIndexBufferOffset:indirectBuffer:indirectBufferOffset:", numberOfPatchControlPoints, patchIndexBuffer, patchIndexBufferOffset, indirectBuffer, indirectBufferOffset) } -@(objc_type=RenderCommandEncoder, objc_name="drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_") -RenderCommandEncoder_drawPatches_patchStart_patchCount_patchIndexBuffer_patchIndexBufferOffset_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawPatchesWithInstances") +RenderCommandEncoder_drawPatchesWithInstance :: #force_inline proc(self: ^RenderCommandEncoder, numberOfPatchControlPoints: NS.UInteger, patchStart, patchCount: NS.UInteger, patchIndexBuffer: ^Buffer, patchIndexBufferOffset: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance) } -@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_indirectBuffer_indirectBufferOffset_") -RenderCommandEncoder_drawPrimitives_indirectBuffer_indirectBufferOffset_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitivesWithIndirect") +RenderCommandEncoder_drawPrimitivesWithIndirect :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, indirectBuffer: ^Buffer, indirectBufferOffset: NS.UInteger) { msgSend(nil, self, "drawPrimitives:indirectBuffer:indirectBufferOffset:", primitiveType, indirectBuffer, indirectBufferOffset) } -@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives") +RenderCommandEncoder_drawPrimitives :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:", primitiveType, vertexStart, vertexCount) } -@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitivesWithInstanceCount") +RenderCommandEncoder_drawPrimitivesWithInstanceCount :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:", primitiveType, vertexStart, vertexCount, instanceCount) } -@(objc_type=RenderCommandEncoder, objc_name="drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_") -RenderCommandEncoder_drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance_ :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { +@(objc_type=RenderCommandEncoder, objc_name="drawPrimitivesWithInstances") +RenderCommandEncoder_drawPrimitivesWithInstance :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer") From 60f4d8f1ec47a47c26693656fa417ed08a8427c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:46:27 +0000 Subject: [PATCH 0177/1052] Correct Render Pass types --- core/sys/darwin/Metal/MetalClasses.odin | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 4a1aeb55f..1ad39e925 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -2767,8 +2767,8 @@ RenderPassAttachmentDescriptor_resolveSlice :: #force_inline proc(self: ^RenderP return msgSend(NS.UInteger, self, "resolveSlice") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="resolveTexture") -RenderPassAttachmentDescriptor_resolveTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { - return msgSend(^RenderPassAttachmentDescriptor, self, "resolveTexture") +RenderPassAttachmentDescriptor_resolveTexture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^Texture { + return msgSend(^Texture, self, "resolveTexture") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="setDepthPlane") RenderPassAttachmentDescriptor_setDepthPlane :: #force_inline proc(self: ^RenderPassAttachmentDescriptor, depthPlane: NS.UInteger) { @@ -2827,8 +2827,8 @@ RenderPassAttachmentDescriptor_storeActionOptions :: #force_inline proc(self: ^R return msgSend(StoreActionOptions, self, "storeActionOptions") } @(objc_type=RenderPassAttachmentDescriptor, objc_name="texture") -RenderPassAttachmentDescriptor_texture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^RenderPassAttachmentDescriptor { - return msgSend(^RenderPassAttachmentDescriptor, self, "texture") +RenderPassAttachmentDescriptor_texture :: #force_inline proc(self: ^RenderPassAttachmentDescriptor) -> ^Texture { + return msgSend(^Texture, self, "texture") } //////////////////////////////////////////////////////////////////////////////// @@ -3000,16 +3000,16 @@ RenderPassDescriptor_depthAttachment :: #force_inline proc(self: ^RenderPassDesc return msgSend(^RenderPassDepthAttachmentDescriptor, self, "depthAttachment") } @(objc_type=RenderPassDescriptor, objc_name="getSamplePositions") -RenderPassDescriptor_getSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: []SamplePosition) -> ^RenderPassDescriptor { - return msgSend(^RenderPassDescriptor, self, "getSamplePositions:count:", raw_data(positions), NS.UInteger(len(positions))) +RenderPassDescriptor_getSamplePositions :: #force_inline proc(self: ^RenderPassDescriptor, positions: []SamplePosition) -> NS.UInteger { + return msgSend(NS.UInteger, self, "getSamplePositions:count:", raw_data(positions), NS.UInteger(len(positions))) } @(objc_type=RenderPassDescriptor, objc_name="imageblockSampleLength") RenderPassDescriptor_imageblockSampleLength :: #force_inline proc(self: ^RenderPassDescriptor) -> NS.UInteger { return msgSend(NS.UInteger, self, "imageblockSampleLength") } @(objc_type=RenderPassDescriptor, objc_name="rasterizationRateMap") -RenderPassDescriptor_rasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RenderPassDescriptor { - return msgSend(^RenderPassDescriptor, self, "rasterizationRateMap") +RenderPassDescriptor_rasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RasterizationRateMap { + return msgSend(^RasterizationRateMap, self, "rasterizationRateMap") } @(objc_type=RenderPassDescriptor, objc_class_name="renderPassDescriptor") RenderPassDescriptor_renderPassDescriptor :: #force_inline proc() -> ^RenderPassDescriptor { @@ -3144,8 +3144,8 @@ RenderPassSampleBufferAttachmentDescriptor_endOfVertexSampleIndex :: #force_inli return msgSend(NS.UInteger, self, "endOfVertexSampleIndex") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^Buffer { - return msgSend(^Buffer, self, "sampleBuffer") +RenderPassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor) -> ^CounterSampleBuffer { + return msgSend(^CounterSampleBuffer, self, "sampleBuffer") } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setEndOfFragmentSampleIndex") RenderPassSampleBufferAttachmentDescriptor_setEndOfFragmentSampleIndex :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, endOfFragmentSampleIndex: NS.UInteger) { @@ -3156,7 +3156,7 @@ RenderPassSampleBufferAttachmentDescriptor_setEndOfVertexSampleIndex :: #force_i msgSend(nil, self, "setEndOfVertexSampleIndex:", endOfVertexSampleIndex) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -RenderPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, sampleBuffer: ^Buffer) { +RenderPassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^RenderPassSampleBufferAttachmentDescriptor, sampleBuffer: ^CounterSampleBuffer) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="setStartOfFragmentSampleIndex") From 7392a3047a91a182512b12dfb4826aec9af89dcc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 16:58:56 +0000 Subject: [PATCH 0178/1052] Add RenderPipeline missing types and methods --- core/sys/darwin/Metal/MetalClasses.odin | 78 +++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 1ad39e925..41c498378 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -3480,8 +3480,8 @@ RenderPipelineDescriptor_fragmentBuffers :: #force_inline proc(self: ^RenderPipe return msgSend(^PipelineBufferDescriptorArray, self, "fragmentBuffers") } @(objc_type=RenderPipelineDescriptor, objc_name="fragmentFunction") -RenderPipelineDescriptor_fragmentFunction :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { - return msgSend(^RenderPipelineDescriptor, self, "fragmentFunction") +RenderPipelineDescriptor_fragmentFunction :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^Function { + return msgSend(^Function, self, "fragmentFunction") } @(objc_type=RenderPipelineDescriptor, objc_name="inputPrimitiveTopology") RenderPipelineDescriptor_inputPrimitiveTopology :: #force_inline proc(self: ^RenderPipelineDescriptor) -> PrimitiveTopologyClass { @@ -3652,8 +3652,8 @@ RenderPipelineDescriptor_vertexDescriptor :: #force_inline proc(self: ^RenderPip return msgSend(^VertexDescriptor, self, "vertexDescriptor") } @(objc_type=RenderPipelineDescriptor, objc_name="vertexFunction") -RenderPipelineDescriptor_vertexFunction :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^RenderPipelineDescriptor { - return msgSend(^RenderPipelineDescriptor, self, "vertexFunction") +RenderPipelineDescriptor_vertexFunction :: #force_inline proc(self: ^RenderPipelineDescriptor) -> ^Function { + return msgSend(^Function, self, "vertexFunction") } //////////////////////////////////////////////////////////////////////////////// @@ -7969,6 +7969,51 @@ RenderCommandEncoder_waitForFence :: #force_inline proc(self: ^RenderCommandEnco //////////////////////////////////////////////////////////////////////////////// +/* +Class: + RenderPipelineFunctionsDescriptor +*/ +@(objc_class="MTLRenderPipelineFunctionsDescriptor") +RenderPipelineFunctionsDescriptor :: struct { using _: NS.Copying(RenderPipelineFunctionsDescriptor) } + +@(objc_type=RenderPipelineFunctionsDescriptor, objc_class_name="alloc") +RenderPipelineFunctionsDescriptor_alloc :: #force_inline proc() -> ^RenderPipelineFunctionsDescriptor { + return msgSend(^RenderPipelineFunctionsDescriptor, RenderPipelineFunctionsDescriptor, "alloc") +} + +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="init") +RenderPipelineFunctionsDescriptor_init :: #force_inline proc(self: ^RenderPipelineFunctionsDescriptor) -> ^RenderPipelineFunctionsDescriptor { + return msgSend(^RenderPipelineFunctionsDescriptor, self, "init") +} + +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="vertexAdditionalBinaryFunctions") +RenderPipelineFunctionsDescriptor_vertexAdditionalBinaryFunctions :: #force_inline proc(self: ^RenderPipelineFunctionsDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "vertexAdditionalBinaryFunctions") +} +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="fragmentAdditionalBinaryFunctions") +RenderPipelineFunctionsDescriptor_fragmentAdditionalBinaryFunctions :: #force_inline proc(self: ^RenderPipelineFunctionsDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "fragmentAdditionalBinaryFunctions") +} +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="tileAdditionalBinaryFunctions") +RenderPipelineFunctionsDescriptor_tileAdditionalBinaryFunctions :: #force_inline proc(self: ^RenderPipelineFunctionsDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "tileAdditionalBinaryFunctions") +} + +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="setVertexAdditionalBinaryFunctions") +RenderPipelineFunctionsDescriptor_setVertexAdditionalBinaryFunctions :: #force_inline proc(self: ^RenderPipelineFunctionsDescriptor, binaryFunctions: ^NS.Array) { + msgSend(nil, self, "setVertexAdditionalBinaryFunctions:", binaryFunctions) +} +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="setFragmentAdditionalBinaryFunctions") +RenderPipelineFunctionsDescriptor_setFragmentAdditionalBinaryFunctions :: #force_inline proc(self: ^RenderPipelineFunctionsDescriptor, binaryFunctions: ^NS.Array) { + msgSend(nil, self, "setFragmentAdditionalBinaryFunctions:", binaryFunctions) +} +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="setTileAdditionalBinaryFunctions") +RenderPipelineFunctionsDescriptor_setTileAdditionalBinaryFunctions :: #force_inline proc(self: ^RenderPipelineFunctionsDescriptor, binaryFunctions: ^NS.Array) { + msgSend(nil, self, "tileAdditionalBinaryFunctions:", binaryFunctions) +} + +//////////////////////////////////////////////////////////////////////////////// + /* Class: RenderPipelineState @@ -7990,8 +8035,8 @@ RenderPipelineState_device :: #force_inline proc(self: ^RenderPipelineState) -> return msgSend(^Device, self, "device") } @(objc_type=RenderPipelineState, objc_name="imageblockMemoryLengthForDimensions") -RenderPipelineState_imageblockMemoryLengthForDimensions :: #force_inline proc(self: ^RenderPipelineState, imageblockDimensions: Size) -> ^RenderPipelineState { - return msgSend(^RenderPipelineState, self, "imageblockMemoryLengthForDimensions:", imageblockDimensions) +RenderPipelineState_imageblockMemoryLengthForDimensions :: #force_inline proc(self: ^RenderPipelineState, imageblockDimensions: Size) -> NS.UInteger { + return msgSend(NS.UInteger, self, "imageblockMemoryLengthForDimensions:", imageblockDimensions) } @(objc_type=RenderPipelineState, objc_name="imageblockSampleLength") RenderPipelineState_imageblockSampleLength :: #force_inline proc(self: ^RenderPipelineState) -> NS.UInteger { @@ -8014,6 +8059,27 @@ RenderPipelineState_threadgroupSizeMatchesTileSize :: #force_inline proc(self: ^ return msgSend(BOOL, self, "threadgroupSizeMatchesTileSize") } +@(objc_type=RenderPipelineState, objc_name="functionHandle") +RenderPipelineState_functionHandle :: #force_inline proc(self: ^RenderPipelineState, function: ^Function, stage: RenderStages) -> ^FunctionHandle { + return msgSend(^FunctionHandle, self, "functionHandleWithFunction:stage:", function, stage) +} + +@(objc_type=RenderPipelineState, objc_name="newVisibleFunctionTable") +RenderPipelineState_newVisibleFunctionTable :: #force_inline proc(self: ^RenderPipelineState, descriptor: ^VisibleFunctionTableDescriptor, stage: RenderStages) -> ^VisibleFunctionTable { + return msgSend(^VisibleFunctionTable, self, "newVisibleFunctionTableWithDescriptor:stage:", descriptor, stage) +} + +@(objc_type=RenderPipelineState, objc_name="newIntersectionFunctionTable") +RenderPipelineState_newIntersectionFunctionTable :: #force_inline proc(self: ^RenderPipelineState, descriptor: ^IntersectionFunctionTableDescriptor, stage: RenderStages) -> ^IntersectionFunctionTable { + return msgSend(^IntersectionFunctionTable, self, "newIntersectionFunctionTable:stage:", descriptor, stage) +} + +@(objc_type=RenderPipelineState, objc_name="newRenderPipelineState") +RenderPipelineState_newRenderPipelineState :: #force_inline proc(self: ^RenderPipelineState, additionalBinaryFunctions: ^RenderPipelineFunctionsDescriptor) -> (state: ^RenderPipelineState, error: ^NS.Error) { + state = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithAdditionalBinaryFunctions:error:", additionalBinaryFunctions, &error) + return +} + //////////////////////////////////////////////////////////////////////////////// /* From 3d2405ac2c1eb135688b060b383e1cdd5dcc739f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 17:02:05 +0000 Subject: [PATCH 0179/1052] Correct more method types --- core/sys/darwin/Metal/MetalClasses.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 41c498378..6994b3181 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -4696,8 +4696,8 @@ TileRenderPipelineDescriptor_tileBuffers :: #force_inline proc(self: ^TileRender return msgSend(^PipelineBufferDescriptorArray, self, "tileBuffers") } @(objc_type=TileRenderPipelineDescriptor, objc_name="tileFunction") -TileRenderPipelineDescriptor_tileFunction :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^TileRenderPipelineDescriptor { - return msgSend(^TileRenderPipelineDescriptor, self, "tileFunction") +TileRenderPipelineDescriptor_tileFunction :: #force_inline proc(self: ^TileRenderPipelineDescriptor) -> ^Function { + return msgSend(^Function, self, "tileFunction") } //////////////////////////////////////////////////////////////////////////////// @@ -8121,8 +8121,8 @@ Resource_hazardTrackingMode :: #force_inline proc(self: ^Resource) -> HazardTrac return msgSend(HazardTrackingMode, self, "hazardTrackingMode") } @(objc_type=Resource, objc_name="heap") -Resource_heap :: #force_inline proc(self: ^Resource) -> ^Resource { - return msgSend(^Resource, self, "heap") +Resource_heap :: #force_inline proc(self: ^Resource) -> ^Heap { + return msgSend(^Heap, self, "heap") } @(objc_type=Resource, objc_name="heapOffset") Resource_heapOffset :: #force_inline proc(self: ^Resource) -> NS.UInteger { @@ -8186,8 +8186,8 @@ ResourceStateCommandEncoder_updateTextureMapping :: #force_inline proc(self: ^Re msgSend(nil, self, "updateTextureMapping:mode:region:mipLevel:slice:", texture, mode, region, mipLevel, slice) } @(objc_type=ResourceStateCommandEncoder, objc_name="updateTextureMappings") -ResourceStateCommandEncoder_updateTextureMappings :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, regions: ^Region, mipLevels: NS.UInteger, slices: NS.UInteger, numRegions: NS.UInteger) { - msgSend(nil, self, "updateTextureMappings:mode:regions:mipLevels:slices:numRegions:", texture, mode, regions, mipLevels, slices, numRegions) +ResourceStateCommandEncoder_updateTextureMappings :: #force_inline proc(self: ^ResourceStateCommandEncoder, texture: ^Texture, mode: SparseTextureMappingMode, regions: []Region, mipLevels: []NS.UInteger, slices: NS.UInteger) { + msgSend(nil, self, "updateTextureMappings:mode:regions:mipLevels:slices:numRegions:", texture, mode, raw_data(regions), raw_data(mipLevels), slices, NS.UInteger(len(regions))) } @(objc_type=ResourceStateCommandEncoder, objc_name="waitForFence") ResourceStateCommandEncoder_waitForFence :: #force_inline proc(self: ^ResourceStateCommandEncoder, fence: ^Fence) { From 643e36b87bb320818dcc9656ee1137dba9e74217 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 17:07:18 +0000 Subject: [PATCH 0180/1052] Improve Texture method names --- core/sys/darwin/Metal/MetalClasses.odin | 50 ++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 6994b3181..af9f03518 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -3757,15 +3757,15 @@ ResourceStatePassSampleBufferAttachmentDescriptor_endOfEncoderSampleIndex :: #fo return msgSend(NS.UInteger, self, "endOfEncoderSampleIndex") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="sampleBuffer") -ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^Buffer { - return msgSend(^Buffer, self, "sampleBuffer") +ResourceStatePassSampleBufferAttachmentDescriptor_sampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor) -> ^CounterSampleBuffer { + return msgSend(^CounterSampleBuffer, self, "sampleBuffer") } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setEndOfEncoderSampleIndex") ResourceStatePassSampleBufferAttachmentDescriptor_setEndOfEncoderSampleIndex :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, endOfEncoderSampleIndex: NS.UInteger) { msgSend(nil, self, "setEndOfEncoderSampleIndex:", endOfEncoderSampleIndex) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setSampleBuffer") -ResourceStatePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, sampleBuffer: ^Buffer) { +ResourceStatePassSampleBufferAttachmentDescriptor_setSampleBuffer :: #force_inline proc(self: ^ResourceStatePassSampleBufferAttachmentDescriptor, sampleBuffer: ^CounterSampleBuffer) { msgSend(nil, self, "setSampleBuffer:", sampleBuffer) } @(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="setStartOfEncoderSampleIndex") @@ -4472,16 +4472,16 @@ TextureDescriptor_storageMode :: #force_inline proc(self: ^TextureDescriptor) -> TextureDescriptor_swizzle :: #force_inline proc(self: ^TextureDescriptor) -> TextureSwizzleChannels { return msgSend(TextureSwizzleChannels, self, "swizzle") } -@(objc_type=TextureDescriptor, objc_class_name="texture2DDescriptorWithPixelFormat") -TextureDescriptor_texture2DDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, height: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { +@(objc_type=TextureDescriptor, objc_class_name="texture2DDescriptor") +TextureDescriptor_texture2DDescriptor :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, height: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "texture2DDescriptorWithPixelFormat:width:height:mipmapped:", pixelFormat, width, height, mipmapped) } -@(objc_type=TextureDescriptor, objc_class_name="textureBufferDescriptorWithPixelFormat") -TextureDescriptor_textureBufferDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { +@(objc_type=TextureDescriptor, objc_class_name="textureBufferDescriptor") +TextureDescriptor_textureBufferDescriptor :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureBufferDescriptorWithPixelFormat:width:resourceOptions:usage:", pixelFormat, width, resourceOptions, usage) } -@(objc_type=TextureDescriptor, objc_class_name="textureCubeDescriptorWithPixelFormat") -TextureDescriptor_textureCubeDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, size: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { +@(objc_type=TextureDescriptor, objc_class_name="textureCubeDescriptor") +TextureDescriptor_textureCubeDescriptor :: #force_inline proc(pixelFormat: PixelFormat, size: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureCubeDescriptorWithPixelFormat:size:mipmapped:", pixelFormat, size, mipmapped) } @(objc_type=TextureDescriptor, objc_name="textureType") @@ -8322,12 +8322,12 @@ Texture_depth :: #force_inline proc(self: ^Texture) -> NS.UInteger { Texture_firstMipmapInTail :: #force_inline proc(self: ^Texture) -> NS.UInteger { return msgSend(NS.UInteger, self, "firstMipmapInTail") } -@(objc_type=Texture, objc_name="getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_") -Texture_getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: NS.UInteger, bytesPerImage: NS.UInteger, region: Region, level: NS.UInteger, slice: NS.UInteger) { +@(objc_type=Texture, objc_name="getBytesWithLevel") +Texture_getBytesWithLevel :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: NS.UInteger, bytesPerImage: NS.UInteger, region: Region, level: NS.UInteger, slice: NS.UInteger) { msgSend(nil, self, "getBytes:bytesPerRow:bytesPerImage:fromRegion:mipmapLevel:slice:", pixelBytes, bytesPerRow, bytesPerImage, region, level, slice) } -@(objc_type=Texture, objc_name="getBytes_bytesPerRow_fromRegion_mipmapLevel_") -Texture_getBytes_bytesPerRow_fromRegion_mipmapLevel_ :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: NS.UInteger, region: Region, level: NS.UInteger) { +@(objc_type=Texture, objc_name="getBytes") +Texture_getBytes :: #force_inline proc(self: ^Texture, pixelBytes: rawptr, bytesPerRow: NS.UInteger, region: Region, level: NS.UInteger) { msgSend(nil, self, "getBytes:bytesPerRow:fromRegion:mipmapLevel:", pixelBytes, bytesPerRow, region, level) } @(objc_type=Texture, objc_name="height") @@ -8366,16 +8366,16 @@ Texture_newRemoteTextureViewForDevice :: #force_inline proc(self: ^Texture, devi Texture_newSharedTextureHandle :: #force_inline proc(self: ^Texture) -> ^SharedTextureHandle { return msgSend(^SharedTextureHandle, self, "newSharedTextureHandle") } -@(objc_type=Texture, objc_name="newTextureViewWithPixelFormat") -Texture_newTextureViewWithPixelFormat :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat) -> ^Texture { +@(objc_type=Texture, objc_name="newTextureView") +Texture_newTextureView :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat) -> ^Texture { return msgSend(^Texture, self, "newTextureViewWithPixelFormat:", pixelFormat) } -@(objc_type=Texture, objc_name="newTextureViewWithPixelFormat_textureType_levels_slices_") -Texture_newTextureViewWithPixelFormat_textureType_levels_slices_ :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range) -> ^Texture { +@(objc_type=Texture, objc_name="newTextureViewWithLevels") +Texture_newTextureViewWithLevels :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range) -> ^Texture { return msgSend(^Texture, self, "newTextureViewWithPixelFormat:textureType:levels:slices:", pixelFormat, textureType, levelRange, sliceRange) } -@(objc_type=Texture, objc_name="newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_") -Texture_newTextureViewWithPixelFormat_textureType_levels_slices_swizzle_ :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range, swizzle: TextureSwizzleChannels) -> ^Texture { +@(objc_type=Texture, objc_name="newTextureViewWithLevelsAndSwizzle") +Texture_newTextureViewWithLevelsAndSwizzle :: #force_inline proc(self: ^Texture, pixelFormat: PixelFormat, textureType: TextureType, levelRange: NS.Range, sliceRange: NS.Range, swizzle: TextureSwizzleChannels) -> ^Texture { return msgSend(^Texture, self, "newTextureViewWithPixelFormat:textureType:levels:slices:swizzle:", pixelFormat, textureType, levelRange, sliceRange, swizzle) } @(objc_type=Texture, objc_name="parentRelativeLevel") @@ -8398,17 +8398,17 @@ Texture_pixelFormat :: #force_inline proc(self: ^Texture) -> PixelFormat { Texture_remoteStorageTexture :: #force_inline proc(self: ^Texture) -> ^Texture { return msgSend(^Texture, self, "remoteStorageTexture") } -@(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_") -Texture_replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage_ :: #force_inline proc(self: ^Texture, region: Region, level: NS.UInteger, slice: NS.UInteger, pixelBytes: rawptr, bytesPerRow: NS.UInteger, bytesPerImage: NS.UInteger) { +@(objc_type=Texture, objc_name="replaceRegionWithLevel") +Texture_replaceRegionWithLevel :: #force_inline proc(self: ^Texture, region: Region, level: NS.UInteger, slice: NS.UInteger, pixelBytes: rawptr, bytesPerRow: NS.UInteger, bytesPerImage: NS.UInteger) { msgSend(nil, self, "replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:", region, level, slice, pixelBytes, bytesPerRow, bytesPerImage) } -@(objc_type=Texture, objc_name="replaceRegion_mipmapLevel_withBytes_bytesPerRow_") -Texture_replaceRegion_mipmapLevel_withBytes_bytesPerRow_ :: #force_inline proc(self: ^Texture, region: Region, level: NS.UInteger, pixelBytes: rawptr, bytesPerRow: NS.UInteger) { +@(objc_type=Texture, objc_name="replaceRegion") +Texture_replaceRegion :: #force_inline proc(self: ^Texture, region: Region, level: NS.UInteger, pixelBytes: rawptr, bytesPerRow: NS.UInteger) { msgSend(nil, self, "replaceRegion:mipmapLevel:withBytes:bytesPerRow:", region, level, pixelBytes, bytesPerRow) } @(objc_type=Texture, objc_name="rootResource") -Texture_rootResource :: #force_inline proc(self: ^Texture) -> ^Texture { - return msgSend(^Texture, self, "rootResource") +Texture_rootResource :: #force_inline proc(self: ^Texture) -> ^Resource { + return msgSend(^Resource, self, "rootResource") } @(objc_type=Texture, objc_name="sampleCount") Texture_sampleCount :: #force_inline proc(self: ^Texture) -> NS.UInteger { From 1afa7967f23adcf84466db830c899cbb17521acc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 17:09:30 +0000 Subject: [PATCH 0181/1052] Fix method names --- core/sys/darwin/Metal/MetalClasses.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index af9f03518..3a0e32c9f 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5184,7 +5184,7 @@ ArgumentEncoder_setAccelerationStructure :: #force_inline proc(self: ^ArgumentEn ArgumentEncoder_setArgumentBufferWithOffset :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^Buffer, offset: NS.UInteger) { msgSend(nil, self, "setArgumentBuffer:offset:", argumentBuffer, offset) } -@(objc_type=ArgumentEncoder, objc_name="setArgumentBuffer_startOffsetWithStartOffset") +@(objc_type=ArgumentEncoder, objc_name="setArgumentBufferWithStartOffset") ArgumentEncoder_setArgumentBuffer_startOffsetWithStartOffset :: #force_inline proc(self: ^ArgumentEncoder, argumentBuffer: ^Buffer, startOffset: NS.UInteger, arrayElement: NS.UInteger) { msgSend(nil, self, "setArgumentBuffer:startOffset:arrayElement:", argumentBuffer, startOffset, arrayElement) } @@ -5998,7 +5998,7 @@ ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ComputeCommandEncoder_setSamplerState :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:atIndex:", sampler, index) } -@(objc_type=ComputeCommandEncoder, objc_name="setSamplerState_lodMinClamp_lodMaxClamp") +@(objc_type=ComputeCommandEncoder, objc_name="setSamplerStateWithLod") ComputeCommandEncoder_setSamplerState_lodMinClamp_lodMaxClamp :: #force_inline proc(self: ^ComputeCommandEncoder, sampler: ^SamplerState, lodMinClamp: f32, lodMaxClamp: f32, index: NS.UInteger) { msgSend(nil, self, "setSamplerState:lodMinClamp:lodMaxClamp:atIndex:", sampler, lodMinClamp, lodMaxClamp, index) } From e69738c0791b74ce50d120a35f0274593185f727 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 17:23:14 +0000 Subject: [PATCH 0182/1052] Minor style change --- core/sys/darwin/Metal/MetalClasses.odin | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 3a0e32c9f..7472fa37b 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -5203,7 +5203,7 @@ ArgumentEncoder_setComputePipelineState :: #force_inline proc(self: ^ArgumentEnc } @(objc_type=ArgumentEncoder, objc_name="setComputePipelineStates") ArgumentEncoder_setComputePipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: []^ComputePipelineState, range: NS.Range) { - assert(range.length <= NS.UInteger(len(pipelines))) + assert(range.length <= NS.UInteger(len(pipelines))) msgSend(nil, self, "setComputePipelineStates:withRange:", raw_data(pipelines), range) } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffer") @@ -5212,7 +5212,7 @@ ArgumentEncoder_setIndirectCommandBuffer :: #force_inline proc(self: ^ArgumentEn } @(objc_type=ArgumentEncoder, objc_name="setIndirectCommandBuffers") ArgumentEncoder_setIndirectCommandBuffers :: #force_inline proc(self: ^ArgumentEncoder, buffers: []^IndirectCommandBuffer, range: NS.Range) { - assert(range.length <= NS.UInteger(len(buffers))) + assert(range.length <= NS.UInteger(len(buffers))) msgSend(nil, self, "setIndirectCommandBuffers:withRange:", raw_data(buffers), range) } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTable") @@ -5221,7 +5221,7 @@ ArgumentEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^Argume } @(objc_type=ArgumentEncoder, objc_name="setIntersectionFunctionTables") ArgumentEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, intersectionFunctionTables: []^IntersectionFunctionTable, range: NS.Range) { - assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) + assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) msgSend(nil, self, "setIntersectionFunctionTables:withRange:", raw_data(intersectionFunctionTables), range) } @(objc_type=ArgumentEncoder, objc_name="setLabel") @@ -5234,7 +5234,7 @@ ArgumentEncoder_setRenderPipelineState :: #force_inline proc(self: ^ArgumentEnco } @(objc_type=ArgumentEncoder, objc_name="setRenderPipelineStates") ArgumentEncoder_setRenderPipelineStates :: #force_inline proc(self: ^ArgumentEncoder, pipelines: []^RenderPipelineState, range: NS.Range) { - assert(range.length <= NS.UInteger(len(pipelines))) + assert(range.length <= NS.UInteger(len(pipelines))) msgSend(nil, self, "setRenderPipelineStates:withRange:", raw_data(pipelines), range) } @(objc_type=ArgumentEncoder, objc_name="setSamplerState") @@ -5243,7 +5243,7 @@ ArgumentEncoder_setSamplerState :: #force_inline proc(self: ^ArgumentEncoder, sa } @(objc_type=ArgumentEncoder, objc_name="setSamplerStates") ArgumentEncoder_setSamplerStates :: #force_inline proc(self: ^ArgumentEncoder, samplers: []^SamplerState, range: NS.Range) { - assert(range.length <= NS.UInteger(len(samplers))) + assert(range.length <= NS.UInteger(len(samplers))) msgSend(nil, self, "setSamplerStates:withRange:", raw_data(samplers), range) } @(objc_type=ArgumentEncoder, objc_name="setTexture") @@ -5252,7 +5252,7 @@ ArgumentEncoder_setTexture :: #force_inline proc(self: ^ArgumentEncoder, texture } @(objc_type=ArgumentEncoder, objc_name="setTextures") ArgumentEncoder_setTextures :: #force_inline proc(self: ^ArgumentEncoder, textures: []^Texture, range: NS.Range) { - assert(range.length <= NS.UInteger(len(textures))) + assert(range.length <= NS.UInteger(len(textures))) msgSend(nil, self, "setTextures:withRange:", raw_data(textures), range) } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTable") @@ -5261,7 +5261,7 @@ ArgumentEncoder_setVisibleFunctionTable :: #force_inline proc(self: ^ArgumentEnc } @(objc_type=ArgumentEncoder, objc_name="setVisibleFunctionTables") ArgumentEncoder_setVisibleFunctionTables :: #force_inline proc(self: ^ArgumentEncoder, visibleFunctionTables: []^VisibleFunctionTable, range: NS.Range) { - assert(range.length <= NS.UInteger(len(visibleFunctionTables))) + assert(range.length <= NS.UInteger(len(visibleFunctionTables))) msgSend(nil, self, "setVisibleFunctionTables:withRange:", raw_data(visibleFunctionTables), range) } @@ -5970,7 +5970,7 @@ ComputeCommandEncoder_setBufferOffset :: #force_inline proc(self: ^ComputeComman @(objc_type=ComputeCommandEncoder, objc_name="setBuffers") ComputeCommandEncoder_setBuffers :: #force_inline proc(self: ^ComputeCommandEncoder, buffers: []^Buffer, offsets: []NS.UInteger, range: NS.Range) { assert(len(buffers) == len(offsets)) - assert(range.length <= NS.UInteger(len(buffers))) + assert(range.length <= NS.UInteger(len(buffers))) msgSend(nil, self, "setBuffers:offsets:withRange:", raw_data(buffers), raw_data(offsets), range) } @(objc_type=ComputeCommandEncoder, objc_name="setBytes") @@ -5991,7 +5991,7 @@ ComputeCommandEncoder_setIntersectionFunctionTable :: #force_inline proc(self: ^ } @(objc_type=ComputeCommandEncoder, objc_name="setIntersectionFunctionTables") ComputeCommandEncoder_setIntersectionFunctionTables :: #force_inline proc(self: ^ComputeCommandEncoder, intersectionFunctionTables: []^IntersectionFunctionTable, range: NS.Range) { - assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) + assert(range.length <= NS.UInteger(len(intersectionFunctionTables))) msgSend(nil, self, "setIntersectionFunctionTables:withBufferRange:", raw_data(intersectionFunctionTables), range) } @(objc_type=ComputeCommandEncoder, objc_name="setSamplerState") From 03aec70287714fb9d66864e6db0d9e6375c18362 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 17:31:55 +0000 Subject: [PATCH 0183/1052] Change objc_class_name to objc_name with objc_is_class_method --- core/sys/darwin/Foundation/NSArray.odin | 2 +- .../darwin/Foundation/NSAutoreleasePool.odin | 2 +- core/sys/darwin/Foundation/NSBundle.odin | 8 +- core/sys/darwin/Foundation/NSData.odin | 2 +- core/sys/darwin/Foundation/NSDate.odin | 2 +- core/sys/darwin/Foundation/NSDictionary.odin | 8 +- core/sys/darwin/Foundation/NSEnumerator.odin | 2 +- core/sys/darwin/Foundation/NSError.odin | 4 +- core/sys/darwin/Foundation/NSLock.odin | 2 +- .../sys/darwin/Foundation/NSNotification.odin | 2 +- core/sys/darwin/Foundation/NSNumber.odin | 34 +-- core/sys/darwin/Foundation/NSString.odin | 2 +- core/sys/darwin/Foundation/NSURL.odin | 2 +- core/sys/darwin/Metal/MetalClasses.odin | 226 +++++++++--------- core/sys/darwin/QuartzCore/QuartzCore.odin | 2 +- src/check_decl.cpp | 24 +- src/checker.cpp | 12 +- src/checker.hpp | 2 +- 18 files changed, 166 insertions(+), 172 deletions(-) diff --git a/core/sys/darwin/Foundation/NSArray.odin b/core/sys/darwin/Foundation/NSArray.odin index e17223ff7..d6021838b 100644 --- a/core/sys/darwin/Foundation/NSArray.odin +++ b/core/sys/darwin/Foundation/NSArray.odin @@ -7,7 +7,7 @@ Array :: struct { using _: Copying(Array), } -@(objc_type=Array, objc_class_name="alloc") +@(objc_type=Array, objc_name="alloc", objc_is_class_method=true) Array_alloc :: proc() -> ^Array { return msgSend(^Array, Array, "alloc") } diff --git a/core/sys/darwin/Foundation/NSAutoreleasePool.odin b/core/sys/darwin/Foundation/NSAutoreleasePool.odin index 17ec88ba1..a388a7146 100644 --- a/core/sys/darwin/Foundation/NSAutoreleasePool.odin +++ b/core/sys/darwin/Foundation/NSAutoreleasePool.odin @@ -3,7 +3,7 @@ package objc_Foundation @(objc_class="NSAutoreleasePool") AutoreleasePool :: struct {using _: Object} -@(objc_type=AutoreleasePool, objc_class_name="alloc") +@(objc_type=AutoreleasePool, objc_name="alloc", objc_is_class_method=true) AutoreleasePool_alloc :: proc() -> ^AutoreleasePool { return msgSend(^AutoreleasePool, AutoreleasePool, "alloc") } diff --git a/core/sys/darwin/Foundation/NSBundle.odin b/core/sys/darwin/Foundation/NSBundle.odin index a18809b7e..4f5a8e928 100644 --- a/core/sys/darwin/Foundation/NSBundle.odin +++ b/core/sys/darwin/Foundation/NSBundle.odin @@ -3,23 +3,23 @@ package objc_Foundation @(objc_class="NSBundle") Bundle :: struct { using _: Object } -@(objc_type=Bundle, objc_class_name="mainBundle") +@(objc_type=Bundle, objc_name="mainBundle", objc_is_class_method=true) Bundle_mainBundle :: proc() -> ^Bundle { return msgSend(^Bundle, Bundle, "mainBundle") } -@(objc_type=Bundle, objc_class_name="bundleWithPath") +@(objc_type=Bundle, objc_name="bundleWithPath", objc_is_class_method=true) Bundle_bundleWithPath :: proc(path: ^String) -> ^Bundle { return msgSend(^Bundle, Bundle, "bundleWithPath:", path) } -@(objc_type=Bundle, objc_class_name="bundleWithURL") +@(objc_type=Bundle, objc_name="bundleWithURL", objc_is_class_method=true) Bundle_bundleWithURL :: proc(url: ^URL) -> ^Bundle { return msgSend(^Bundle, Bundle, "bundleWithUrl:", url) } -@(objc_type=Bundle, objc_class_name="alloc") +@(objc_type=Bundle, objc_name="alloc", objc_is_class_method=true) Bundle_alloc :: proc() -> ^Bundle { return msgSend(^Bundle, Bundle, "alloc") } diff --git a/core/sys/darwin/Foundation/NSData.odin b/core/sys/darwin/Foundation/NSData.odin index e28f6a644..3c6369e86 100644 --- a/core/sys/darwin/Foundation/NSData.odin +++ b/core/sys/darwin/Foundation/NSData.odin @@ -3,7 +3,7 @@ package objc_Foundation @(objc_class="NSData") Data :: struct {using _: Copying(Data)} -@(objc_type=Data, objc_class_name="alloc") +@(objc_type=Data, objc_name="alloc", objc_is_class_method=true) Data_alloc :: proc() -> ^Data { return msgSend(^Data, Data, "alloc") } diff --git a/core/sys/darwin/Foundation/NSDate.odin b/core/sys/darwin/Foundation/NSDate.odin index 85bb14c3e..cd63d313a 100644 --- a/core/sys/darwin/Foundation/NSDate.odin +++ b/core/sys/darwin/Foundation/NSDate.odin @@ -3,7 +3,7 @@ package objc_Foundation @(objc_class="NSDate") Date :: struct {using _: Copying(Date)} -@(objc_type=Date, objc_class_name="alloc") +@(objc_type=Date, objc_name="alloc", objc_is_class_method=true) Date_alloc :: proc() -> ^Date { return msgSend(^Date, Date, "alloc") } diff --git a/core/sys/darwin/Foundation/NSDictionary.odin b/core/sys/darwin/Foundation/NSDictionary.odin index 3eb378dc7..1f009841a 100644 --- a/core/sys/darwin/Foundation/NSDictionary.odin +++ b/core/sys/darwin/Foundation/NSDictionary.odin @@ -3,23 +3,23 @@ package objc_Foundation @(objc_class="NSDictionary") Dictionary :: struct {using _: Copying(Dictionary)} -@(objc_type=Dictionary, objc_class_name="dictionary") +@(objc_type=Dictionary, objc_name="dictionary", objc_is_class_method=true) Dictionary_dictionary :: proc() -> ^Dictionary { return msgSend(^Dictionary, Dictionary, "dictionary") } -@(objc_type=Dictionary, objc_class_name="dictionaryWithObject") +@(objc_type=Dictionary, objc_name="dictionaryWithObject", objc_is_class_method=true) Dictionary_dictionaryWithObject :: proc(object: ^Object, forKey: ^Object) -> ^Dictionary { return msgSend(^Dictionary, Dictionary, "dictionaryWithObject:forKey:", object, forKey) } -@(objc_type=Dictionary, objc_class_name="dictionaryWithObjects") +@(objc_type=Dictionary, objc_name="dictionaryWithObjects", objc_is_class_method=true) Dictionary_dictionaryWithObjects :: proc(objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { return msgSend(^Dictionary, Dictionary, "dictionaryWithObjects:forKeys:count", objects, forKeys, count) } -@(objc_type=Dictionary, objc_class_name="alloc") +@(objc_type=Dictionary, objc_name="alloc", objc_is_class_method=true) Dictionary_alloc :: proc() -> ^Dictionary { return msgSend(^Dictionary, Dictionary, "alloc") } diff --git a/core/sys/darwin/Foundation/NSEnumerator.odin b/core/sys/darwin/Foundation/NSEnumerator.odin index 8a5a32e69..1c7ddeed2 100644 --- a/core/sys/darwin/Foundation/NSEnumerator.odin +++ b/core/sys/darwin/Foundation/NSEnumerator.odin @@ -19,7 +19,7 @@ Enumerator :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics } -@(objc_type=FastEnumeration, objc_class_name="alloc") +@(objc_type=FastEnumeration, objc_name="alloc", objc_is_class_method=true) FastEnumeration_alloc :: proc() -> ^FastEnumeration { return msgSend(^FastEnumeration, FastEnumeration, "alloc") } diff --git a/core/sys/darwin/Foundation/NSError.odin b/core/sys/darwin/Foundation/NSError.odin index bff0088e9..23e6eaba7 100644 --- a/core/sys/darwin/Foundation/NSError.odin +++ b/core/sys/darwin/Foundation/NSError.odin @@ -32,7 +32,7 @@ foreign Foundation { Error :: struct { using _: Copying(Error) } -@(objc_type=Error, objc_class_name="alloc") +@(objc_type=Error, objc_name="alloc", objc_is_class_method=true) Error_alloc :: proc() -> ^Error { return msgSend(^Error, Error, "alloc") } @@ -42,7 +42,7 @@ Error_init :: proc(self: ^Error) -> ^Error { return msgSend(^Error, self, "init") } -@(objc_type=Error, objc_class_name="errorWithDomain") +@(objc_type=Error, objc_name="errorWithDomain", objc_is_class_method=true) Error_errorWithDomain :: proc(domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error { return msgSend(^Error, Error, "errorWithDomain:code:userInfo:", domain, code, userInfo) } diff --git a/core/sys/darwin/Foundation/NSLock.odin b/core/sys/darwin/Foundation/NSLock.odin index 3bcc06eab..c48b5dbad 100644 --- a/core/sys/darwin/Foundation/NSLock.odin +++ b/core/sys/darwin/Foundation/NSLock.odin @@ -13,7 +13,7 @@ Locking_unlock :: proc(self: ^Locking($T)) { Condition :: struct {using _: Locking(Condition) } -@(objc_type=Condition, objc_class_name="alloc") +@(objc_type=Condition, objc_name="alloc", objc_is_class_method=true) Condition_alloc :: proc() -> ^Condition { return msgSend(^Condition, Condition, "alloc") } diff --git a/core/sys/darwin/Foundation/NSNotification.odin b/core/sys/darwin/Foundation/NSNotification.odin index d8b142e53..182d33896 100644 --- a/core/sys/darwin/Foundation/NSNotification.odin +++ b/core/sys/darwin/Foundation/NSNotification.odin @@ -4,7 +4,7 @@ package objc_Foundation Notification :: struct{using _: Object} -@(objc_type=Notification, objc_class_name="alloc") +@(objc_type=Notification, objc_name="alloc", objc_is_class_method=true) Notification_alloc :: proc() -> ^Notification { return msgSend(^Notification, Notification, "alloc") } diff --git a/core/sys/darwin/Foundation/NSNumber.odin b/core/sys/darwin/Foundation/NSNumber.odin index f77b0866a..4f7ef311b 100644 --- a/core/sys/darwin/Foundation/NSNumber.odin +++ b/core/sys/darwin/Foundation/NSNumber.odin @@ -8,7 +8,7 @@ import "core:c" @(objc_class="NSValue") Value :: struct{using _: Copying(Value)} -@(objc_type=Value, objc_class_name="alloc") +@(objc_type=Value, objc_name="alloc", objc_is_class_method=true) Value_alloc :: proc() -> ^Value { return msgSend(^Value, Value, "alloc") } @@ -18,12 +18,12 @@ Value_init :: proc(self: ^Value) -> ^Value { return msgSend(^Value, self, "init") } -@(objc_type=Value, objc_class_name="valueWithBytes") +@(objc_type=Value, objc_name="valueWithBytes", objc_is_class_method=true) Value_valueWithBytes :: proc(value: rawptr, type: cstring) -> ^Value { return msgSend(^Value, Value, "valueWithBytes:objCType:", value, type) } -@(objc_type=Value, objc_class_name="valueWithPointer") +@(objc_type=Value, objc_name="valueWithPointer", objc_is_class_method=true) Value_valueWithPointer :: proc(pointer: rawptr) -> ^Value { return msgSend(^Value, Value, "valueWithPointer:", pointer) } @@ -64,7 +64,7 @@ Value_pointerValue :: proc(self: ^Value) -> rawptr { Number :: struct{using _: Copying(Number), using _: Value} -@(objc_type=Number, objc_class_name="alloc") +@(objc_type=Number, objc_name="alloc", objc_is_class_method=true) Number_alloc :: proc() -> ^Number { return msgSend(^Number, Number, "alloc") } @@ -74,19 +74,19 @@ Number_init :: proc(self: ^Number) -> ^Number { return msgSend(^Number, self, "init") } -@(objc_type=Number, objc_class_name="numberWithI8") Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) } -@(objc_type=Number, objc_class_name="numberWithU8") Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) } -@(objc_type=Number, objc_class_name="numberWithI16") Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) } -@(objc_type=Number, objc_class_name="numberWithU16") Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) } -@(objc_type=Number, objc_class_name="numberWithI32") Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) } -@(objc_type=Number, objc_class_name="numberWithU32") Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) } -@(objc_type=Number, objc_class_name="numberWithInt") Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) } -@(objc_type=Number, objc_class_name="numberWithUint") Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) } -@(objc_type=Number, objc_class_name="numberWithU64") Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) } -@(objc_type=Number, objc_class_name="numberWithI64") Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) } -@(objc_type=Number, objc_class_name="numberWithF32") Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) } -@(objc_type=Number, objc_class_name="numberWithF64") Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) } -@(objc_type=Number, objc_class_name="numberWithBool") Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) } +@(objc_type=Number, objc_name="numberWithI8", objc_is_class_method=true) Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) } +@(objc_type=Number, objc_name="numberWithU8", objc_is_class_method=true) Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) } +@(objc_type=Number, objc_name="numberWithI16", objc_is_class_method=true) Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) } +@(objc_type=Number, objc_name="numberWithU16", objc_is_class_method=true) Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) } +@(objc_type=Number, objc_name="numberWithI32", objc_is_class_method=true) Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) } +@(objc_type=Number, objc_name="numberWithU32", objc_is_class_method=true) Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) } +@(objc_type=Number, objc_name="numberWithInt", objc_is_class_method=true) Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) } +@(objc_type=Number, objc_name="numberWithUint", objc_is_class_method=true) Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) } +@(objc_type=Number, objc_name="numberWithU64", objc_is_class_method=true) Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) } +@(objc_type=Number, objc_name="numberWithI64", objc_is_class_method=true) Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) } +@(objc_type=Number, objc_name="numberWithF32", objc_is_class_method=true) Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) } +@(objc_type=Number, objc_name="numberWithF64", objc_is_class_method=true) Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) } +@(objc_type=Number, objc_name="numberWithBool", objc_is_class_method=true) Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) } Number_number :: proc{ Number_numberWithI8, diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin index 06dbc27a3..66442383a 100644 --- a/core/sys/darwin/Foundation/NSString.odin +++ b/core/sys/darwin/Foundation/NSString.odin @@ -59,7 +59,7 @@ MakeConstantString :: proc "c" (#const c: cstring) -> ^String { } -@(objc_type=String, objc_class_name="alloc") +@(objc_type=String, objc_name="alloc", objc_is_class_method=true) String_alloc :: proc() -> ^String { return msgSend(^String, String, "alloc") } diff --git a/core/sys/darwin/Foundation/NSURL.odin b/core/sys/darwin/Foundation/NSURL.odin index 42edf91c0..9813b6e59 100644 --- a/core/sys/darwin/Foundation/NSURL.odin +++ b/core/sys/darwin/Foundation/NSURL.odin @@ -4,7 +4,7 @@ package objc_Foundation URL :: struct{using _: Copying(URL)} -@(objc_type=URL, objc_class_name="alloc") +@(objc_type=URL, objc_name="alloc", objc_is_class_method=true) URL_alloc :: proc() -> ^URL { return msgSend(^URL, URL, "alloc") } diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 7472fa37b..2686ce2ae 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -24,7 +24,7 @@ Methods: @(objc_class="MTLAccelerationStructureBoundingBoxGeometryDescriptor") AccelerationStructureBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureBoundingBoxGeometryDescriptor), using _: AccelerationStructureDescriptor } -@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="alloc") +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="alloc", objc_is_class_method=true) AccelerationStructureBoundingBoxGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, AccelerationStructureBoundingBoxGeometryDescriptor, "alloc") } @@ -48,7 +48,7 @@ AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxCount :: #force_in AccelerationStructureBoundingBoxGeometryDescriptor_boundingBoxStride :: #force_inline proc(self: ^AccelerationStructureBoundingBoxGeometryDescriptor) -> NS.UInteger { return msgSend(NS.UInteger, self, "boundingBoxStride") } -@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_class_name="descriptor") +@(objc_type=AccelerationStructureBoundingBoxGeometryDescriptor, objc_name="descriptor", objc_is_class_method=true) AccelerationStructureBoundingBoxGeometryDescriptor_descriptor :: #force_inline proc() -> ^AccelerationStructureBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureBoundingBoxGeometryDescriptor, AccelerationStructureBoundingBoxGeometryDescriptor, "descriptor") } @@ -88,31 +88,31 @@ Methods: @(objc_class="MTLMotionKeyframeData") MotionKeyframeData :: struct { using _: NS.Object } -@(objc_type=MotionKeyframeData, objc_class_name="alloc") +@(objc_type=MotionKeyframeData, objc_name="alloc", objc_is_class_method=true) MotionKeyframeData_alloc :: #force_inline proc() -> ^MotionKeyframeData { return msgSend(^MotionKeyframeData, MotionKeyframeData, "alloc") } -@(objc_type=MotionKeyframeData, objc_class_name="data") +@(objc_type=MotionKeyframeData, objc_name="data", objc_is_class_method=true) MotionKeyframeData_data :: #force_inline proc() -> ^MotionKeyframeData { return msgSend(^MotionKeyframeData, MotionKeyframeData, "data") } -@(objc_type=MotionKeyframeData, objc_class_name="init") +@(objc_type=MotionKeyframeData, objc_name="init", objc_is_class_method=true) MotionKeyframeData_init :: #force_inline proc(self: ^MotionKeyframeData) -> ^MotionKeyframeData { return msgSend(^MotionKeyframeData, self, "init") } -@(objc_type=MotionKeyframeData, objc_class_name="buffer") +@(objc_type=MotionKeyframeData, objc_name="buffer", objc_is_class_method=true) MotionKeyframeData_buffer :: #force_inline proc(self: ^MotionKeyframeData) -> ^Buffer { return msgSend(^Buffer, self, "buffer") } -@(objc_type=MotionKeyframeData, objc_class_name="setBuffer") +@(objc_type=MotionKeyframeData, objc_name="setBuffer", objc_is_class_method=true) MotionKeyframeData_setBuffer :: #force_inline proc(self: ^MotionKeyframeData, buffer: ^Buffer) { msgSend(nil, self, "setBuffer:", buffer) } -@(objc_type=MotionKeyframeData, objc_class_name="offset") +@(objc_type=MotionKeyframeData, objc_name="offset", objc_is_class_method=true) MotionKeyframeData_offset :: #force_inline proc(self: ^MotionKeyframeData) -> NS.UInteger { return msgSend(NS.UInteger, self, "offset") } -@(objc_type=MotionKeyframeData, objc_class_name="setOffset") +@(objc_type=MotionKeyframeData, objc_name="setOffset", objc_is_class_method=true) MotionKeyframeData_setOffset :: #force_inline proc(self: ^MotionKeyframeData, offset: NS.UInteger) { msgSend(nil, self, "setOffset:", offset) } @@ -127,7 +127,7 @@ Class: @(objc_class="MTLAccelerationStructureMotionTriangleGeometryDescriptor") AccelerationStructureMotionTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionTriangleGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } -@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_class_name="alloc") +@(objc_type=AccelerationStructureMotionTriangleGeometryDescriptor, objc_name="alloc", objc_is_class_method=true) AccelerationStructureMotionTriangleGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureMotionTriangleGeometryDescriptor { return msgSend(^AccelerationStructureMotionTriangleGeometryDescriptor, AccelerationStructureMotionTriangleGeometryDescriptor, "alloc") } @@ -202,7 +202,7 @@ Class: @(objc_class="MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor") AccelerationStructureMotionBoundingBoxGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureMotionBoundingBoxGeometryDescriptor), using _: AccelerationStructureGeometryDescriptor } -@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_class_name="alloc") +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="alloc", objc_is_class_method=true) AccelerationStructureMotionBoundingBoxGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureMotionBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureMotionBoundingBoxGeometryDescriptor, AccelerationStructureMotionBoundingBoxGeometryDescriptor, "alloc") } @@ -211,7 +211,7 @@ AccelerationStructureMotionBoundingBoxGeometryDescriptor_init :: #force_inline p return msgSend(^AccelerationStructureMotionBoundingBoxGeometryDescriptor, self, "init") } -@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_class_name="descriptor") +@(objc_type=AccelerationStructureMotionBoundingBoxGeometryDescriptor, objc_name="descriptor", objc_is_class_method=true) AccelerationStructureMotionBoundingBoxGeometryDescriptor_descriptor :: #force_inline proc() -> ^AccelerationStructureMotionBoundingBoxGeometryDescriptor { return msgSend(^AccelerationStructureMotionBoundingBoxGeometryDescriptor, AccelerationStructureMotionBoundingBoxGeometryDescriptor, "descriptor") } @@ -264,7 +264,7 @@ Methods: @(objc_class="MTLAccelerationStructureDescriptor") AccelerationStructureDescriptor :: struct { using _: NS.Copying(AccelerationStructureDescriptor) } -@(objc_type=AccelerationStructureDescriptor, objc_class_name="alloc") +@(objc_type=AccelerationStructureDescriptor, objc_name="alloc", objc_is_class_method=true) AccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureDescriptor { return msgSend(^AccelerationStructureDescriptor, AccelerationStructureDescriptor, "alloc") } @@ -300,7 +300,7 @@ Methods: @(objc_class="MTLAccelerationStructureGeometryDescriptor") AccelerationStructureGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureGeometryDescriptor) } -@(objc_type=AccelerationStructureGeometryDescriptor, objc_class_name="alloc") +@(objc_type=AccelerationStructureGeometryDescriptor, objc_name="alloc", objc_is_class_method=true) AccelerationStructureGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureGeometryDescriptor { return msgSend(^AccelerationStructureGeometryDescriptor, AccelerationStructureGeometryDescriptor, "alloc") } @@ -361,7 +361,7 @@ Methods: @(objc_class="MTLAccelerationStructureTriangleGeometryDescriptor") AccelerationStructureTriangleGeometryDescriptor :: struct { using _: NS.Copying(AccelerationStructureTriangleGeometryDescriptor), using _: AccelerationStructureDescriptor } -@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_class_name="alloc") +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="alloc", objc_is_class_method=true) AccelerationStructureTriangleGeometryDescriptor_alloc :: #force_inline proc() -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "alloc") } @@ -369,7 +369,7 @@ AccelerationStructureTriangleGeometryDescriptor_alloc :: #force_inline proc() -> AccelerationStructureTriangleGeometryDescriptor_init :: #force_inline proc(self: ^AccelerationStructureTriangleGeometryDescriptor) -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, self, "init") } -@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_class_name="descriptor") +@(objc_type=AccelerationStructureTriangleGeometryDescriptor, objc_name="descriptor", objc_is_class_method=true) AccelerationStructureTriangleGeometryDescriptor_descriptor :: #force_inline proc() -> ^AccelerationStructureTriangleGeometryDescriptor { return msgSend(^AccelerationStructureTriangleGeometryDescriptor, AccelerationStructureTriangleGeometryDescriptor, "descriptor") } @@ -459,7 +459,7 @@ Methods: @(objc_class="MTLArgument") Argument :: struct { using _: NS.Object } -@(objc_type=Argument, objc_class_name="alloc") +@(objc_type=Argument, objc_name="alloc", objc_is_class_method=true) Argument_alloc :: #force_inline proc() -> ^Argument { return msgSend(^Argument, Argument, "alloc") } @@ -558,7 +558,7 @@ Methods: @(objc_class="MTLArgumentDescriptor") ArgumentDescriptor :: struct { using _: NS.Copying(ArgumentDescriptor) } -@(objc_type=ArgumentDescriptor, objc_class_name="alloc") +@(objc_type=ArgumentDescriptor, objc_name="alloc", objc_is_class_method=true) ArgumentDescriptor_alloc :: #force_inline proc() -> ^ArgumentDescriptor { return msgSend(^ArgumentDescriptor, ArgumentDescriptor, "alloc") } @@ -570,7 +570,7 @@ ArgumentDescriptor_init :: #force_inline proc(self: ^ArgumentDescriptor) -> ^Arg ArgumentDescriptor_access :: #force_inline proc(self: ^ArgumentDescriptor) -> ArgumentAccess { return msgSend(ArgumentAccess, self, "access") } -@(objc_type=ArgumentDescriptor, objc_class_name="argumentDescriptor") +@(objc_type=ArgumentDescriptor, objc_name="argumentDescriptor", objc_is_class_method=true) ArgumentDescriptor_argumentDescriptor :: #force_inline proc() -> ^ArgumentDescriptor { return msgSend(^ArgumentDescriptor, ArgumentDescriptor, "argumentDescriptor") } @@ -640,7 +640,7 @@ Methods: @(objc_class="MTLArrayType") ArrayType :: struct { using _: Type } -@(objc_type=ArrayType, objc_class_name="alloc") +@(objc_type=ArrayType, objc_name="alloc", objc_is_class_method=true) ArrayType_alloc :: #force_inline proc() -> ^ArrayType { return msgSend(^ArrayType, ArrayType, "alloc") } @@ -700,7 +700,7 @@ Methods: @(objc_class="MTLAttribute") Attribute :: struct { using _: NS.Object } -@(objc_type=Attribute, objc_class_name="alloc") +@(objc_type=Attribute, objc_name="alloc", objc_is_class_method=true) Attribute_alloc :: #force_inline proc() -> ^Attribute { return msgSend(^Attribute, Attribute, "alloc") } @@ -752,7 +752,7 @@ Methods: @(objc_class="MTLAttributeDescriptor") AttributeDescriptor :: struct { using _: NS.Copying(AttributeDescriptor) } -@(objc_type=AttributeDescriptor, objc_class_name="alloc") +@(objc_type=AttributeDescriptor, objc_name="alloc", objc_is_class_method=true) AttributeDescriptor_alloc :: #force_inline proc() -> ^AttributeDescriptor { return msgSend(^AttributeDescriptor, AttributeDescriptor, "alloc") } @@ -800,7 +800,7 @@ Methods: @(objc_class="MTLAttributeDescriptorArray") AttributeDescriptorArray :: struct { using _: NS.Object } -@(objc_type=AttributeDescriptorArray, objc_class_name="alloc") +@(objc_type=AttributeDescriptorArray, objc_name="alloc", objc_is_class_method=true) AttributeDescriptorArray_alloc :: #force_inline proc() -> ^AttributeDescriptorArray { return msgSend(^AttributeDescriptorArray, AttributeDescriptorArray, "alloc") } @@ -832,7 +832,7 @@ Methods: @(objc_class="MTLBinaryArchiveDescriptor") BinaryArchiveDescriptor :: struct { using _: NS.Copying(BinaryArchiveDescriptor) } -@(objc_type=BinaryArchiveDescriptor, objc_class_name="alloc") +@(objc_type=BinaryArchiveDescriptor, objc_name="alloc", objc_is_class_method=true) BinaryArchiveDescriptor_alloc :: #force_inline proc() -> ^BinaryArchiveDescriptor { return msgSend(^BinaryArchiveDescriptor, BinaryArchiveDescriptor, "alloc") } @@ -864,7 +864,7 @@ Methods: @(objc_class="MTLBlitPassDescriptor") BlitPassDescriptor :: struct { using _: NS.Copying(BlitPassDescriptor) } -@(objc_type=BlitPassDescriptor, objc_class_name="alloc") +@(objc_type=BlitPassDescriptor, objc_name="alloc", objc_is_class_method=true) BlitPassDescriptor_alloc :: #force_inline proc() -> ^BlitPassDescriptor { return msgSend(^BlitPassDescriptor, BlitPassDescriptor, "alloc") } @@ -872,7 +872,7 @@ BlitPassDescriptor_alloc :: #force_inline proc() -> ^BlitPassDescriptor { BlitPassDescriptor_init :: #force_inline proc(self: ^BlitPassDescriptor) -> ^BlitPassDescriptor { return msgSend(^BlitPassDescriptor, self, "init") } -@(objc_type=BlitPassDescriptor, objc_class_name="blitPassDescriptor") +@(objc_type=BlitPassDescriptor, objc_name="blitPassDescriptor", objc_is_class_method=true) BlitPassDescriptor_blitPassDescriptor :: #force_inline proc() -> ^BlitPassDescriptor { return msgSend(^BlitPassDescriptor, BlitPassDescriptor, "blitPassDescriptor") } @@ -900,7 +900,7 @@ Methods: @(objc_class="MTLBlitPassSampleBufferAttachmentDescriptor") BlitPassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(BlitPassSampleBufferAttachmentDescriptor) } -@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=BlitPassSampleBufferAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) BlitPassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^BlitPassSampleBufferAttachmentDescriptor { return msgSend(^BlitPassSampleBufferAttachmentDescriptor, BlitPassSampleBufferAttachmentDescriptor, "alloc") } @@ -948,7 +948,7 @@ Methods: @(objc_class="MTLBlitPassSampleBufferAttachmentDescriptorArray") BlitPassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } -@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +@(objc_type=BlitPassSampleBufferAttachmentDescriptorArray, objc_name="alloc", objc_is_class_method=true) BlitPassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^BlitPassSampleBufferAttachmentDescriptorArray { return msgSend(^BlitPassSampleBufferAttachmentDescriptorArray, BlitPassSampleBufferAttachmentDescriptorArray, "alloc") } @@ -984,7 +984,7 @@ Methods: @(objc_class="MTLBufferLayoutDescriptor") BufferLayoutDescriptor :: struct { using _: NS.Copying(BufferLayoutDescriptor) } -@(objc_type=BufferLayoutDescriptor, objc_class_name="alloc") +@(objc_type=BufferLayoutDescriptor, objc_name="alloc", objc_is_class_method=true) BufferLayoutDescriptor_alloc :: #force_inline proc() -> ^BufferLayoutDescriptor { return msgSend(^BufferLayoutDescriptor, BufferLayoutDescriptor, "alloc") } @@ -1032,7 +1032,7 @@ Methods: @(objc_class="MTLBufferLayoutDescriptorArray") BufferLayoutDescriptorArray :: struct { using _: NS.Object } -@(objc_type=BufferLayoutDescriptorArray, objc_class_name="alloc") +@(objc_type=BufferLayoutDescriptorArray, objc_name="alloc", objc_is_class_method=true) BufferLayoutDescriptorArray_alloc :: #force_inline proc() -> ^BufferLayoutDescriptorArray { return msgSend(^BufferLayoutDescriptorArray, BufferLayoutDescriptorArray, "alloc") } @@ -1068,7 +1068,7 @@ Methods: @(objc_class="MTLCaptureDescriptor") CaptureDescriptor :: struct { using _: NS.Copying(CaptureDescriptor) } -@(objc_type=CaptureDescriptor, objc_class_name="alloc") +@(objc_type=CaptureDescriptor, objc_name="alloc", objc_is_class_method=true) CaptureDescriptor_alloc :: #force_inline proc() -> ^CaptureDescriptor { return msgSend(^CaptureDescriptor, CaptureDescriptor, "alloc") } @@ -1126,7 +1126,7 @@ Methods: @(objc_class="MTLCaptureManager") CaptureManager :: struct { using _: NS.Object } -@(objc_type=CaptureManager, objc_class_name="alloc") +@(objc_type=CaptureManager, objc_name="alloc", objc_is_class_method=true) CaptureManager_alloc :: #force_inline proc() -> ^CaptureManager { return msgSend(^CaptureManager, CaptureManager, "alloc") } @@ -1154,7 +1154,7 @@ CaptureManager_newCaptureScopeWithDevice :: #force_inline proc(self: ^CaptureMan CaptureManager_setDefaultCaptureScope :: #force_inline proc(self: ^CaptureManager, defaultCaptureScope: ^CaptureScope) { msgSend(nil, self, "setDefaultCaptureScope:", defaultCaptureScope) } -@(objc_type=CaptureManager, objc_class_name="sharedCaptureManager") +@(objc_type=CaptureManager, objc_name="sharedCaptureManager", objc_is_class_method=true) CaptureManager_sharedCaptureManager :: #force_inline proc() -> ^CaptureManager { return msgSend(^CaptureManager, CaptureManager, "sharedCaptureManager") } @@ -1201,7 +1201,7 @@ Methods: @(objc_class="MTLCommandBufferDescriptor") CommandBufferDescriptor :: struct { using _: NS.Copying(CommandBufferDescriptor) } -@(objc_type=CommandBufferDescriptor, objc_class_name="alloc") +@(objc_type=CommandBufferDescriptor, objc_name="alloc", objc_is_class_method=true) CommandBufferDescriptor_alloc :: #force_inline proc() -> ^CommandBufferDescriptor { return msgSend(^CommandBufferDescriptor, CommandBufferDescriptor, "alloc") } @@ -1253,7 +1253,7 @@ Methods: @(objc_class="MTLCompileOptions") CompileOptions :: struct { using _: NS.Copying(CompileOptions) } -@(objc_type=CompileOptions, objc_class_name="alloc") +@(objc_type=CompileOptions, objc_name="alloc", objc_is_class_method=true) CompileOptions_alloc :: #force_inline proc() -> ^CompileOptions { return msgSend(^CompileOptions, CompileOptions, "alloc") } @@ -1335,7 +1335,7 @@ Methods: @(objc_class="MTLComputePassDescriptor") ComputePassDescriptor :: struct { using _: NS.Copying(ComputePassDescriptor) } -@(objc_type=ComputePassDescriptor, objc_class_name="alloc") +@(objc_type=ComputePassDescriptor, objc_name="alloc", objc_is_class_method=true) ComputePassDescriptor_alloc :: #force_inline proc() -> ^ComputePassDescriptor { return msgSend(^ComputePassDescriptor, ComputePassDescriptor, "alloc") } @@ -1343,7 +1343,7 @@ ComputePassDescriptor_alloc :: #force_inline proc() -> ^ComputePassDescriptor { ComputePassDescriptor_init :: #force_inline proc(self: ^ComputePassDescriptor) -> ^ComputePassDescriptor { return msgSend(^ComputePassDescriptor, self, "init") } -@(objc_type=ComputePassDescriptor, objc_class_name="computePassDescriptor") +@(objc_type=ComputePassDescriptor, objc_name="computePassDescriptor", objc_is_class_method=true) ComputePassDescriptor_computePassDescriptor :: #force_inline proc() -> ^ComputePassDescriptor { return msgSend(^ComputePassDescriptor, ComputePassDescriptor, "computePassDescriptor") } @@ -1379,7 +1379,7 @@ Methods: @(objc_class="MTLComputePassSampleBufferAttachmentDescriptor") ComputePassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(ComputePassSampleBufferAttachmentDescriptor) } -@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=ComputePassSampleBufferAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) ComputePassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^ComputePassSampleBufferAttachmentDescriptor { return msgSend(^ComputePassSampleBufferAttachmentDescriptor, ComputePassSampleBufferAttachmentDescriptor, "alloc") } @@ -1427,7 +1427,7 @@ Methods: @(objc_class="MTLComputePassSampleBufferAttachmentDescriptorArray") ComputePassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } -@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +@(objc_type=ComputePassSampleBufferAttachmentDescriptorArray, objc_name="alloc", objc_is_class_method=true) ComputePassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^ComputePassSampleBufferAttachmentDescriptorArray { return msgSend(^ComputePassSampleBufferAttachmentDescriptorArray, ComputePassSampleBufferAttachmentDescriptorArray, "alloc") } @@ -1481,7 +1481,7 @@ Methods: @(objc_class="MTLComputePipelineDescriptor") ComputePipelineDescriptor :: struct { using _: NS.Copying(ComputePipelineDescriptor) } -@(objc_type=ComputePipelineDescriptor, objc_class_name="alloc") +@(objc_type=ComputePipelineDescriptor, objc_name="alloc", objc_is_class_method=true) ComputePipelineDescriptor_alloc :: #force_inline proc() -> ^ComputePipelineDescriptor { return msgSend(^ComputePipelineDescriptor, ComputePipelineDescriptor, "alloc") } @@ -1600,7 +1600,7 @@ Methods: @(objc_class="MTLComputePipelineReflection") ComputePipelineReflection :: struct { using _: NS.Object } -@(objc_type=ComputePipelineReflection, objc_class_name="alloc") +@(objc_type=ComputePipelineReflection, objc_name="alloc", objc_is_class_method=true) ComputePipelineReflection_alloc :: #force_inline proc() -> ^ComputePipelineReflection { return msgSend(^ComputePipelineReflection, ComputePipelineReflection, "alloc") } @@ -1634,7 +1634,7 @@ Methods: @(objc_class="MTLCounterSampleBufferDescriptor") CounterSampleBufferDescriptor :: struct { using _: NS.Copying(CounterSampleBufferDescriptor) } -@(objc_type=CounterSampleBufferDescriptor, objc_class_name="alloc") +@(objc_type=CounterSampleBufferDescriptor, objc_name="alloc", objc_is_class_method=true) CounterSampleBufferDescriptor_alloc :: #force_inline proc() -> ^CounterSampleBufferDescriptor { return msgSend(^CounterSampleBufferDescriptor, CounterSampleBufferDescriptor, "alloc") } @@ -1698,7 +1698,7 @@ Methods: @(objc_class="MTLDepthStencilDescriptor") DepthStencilDescriptor :: struct { using _: NS.Copying(DepthStencilDescriptor) } -@(objc_type=DepthStencilDescriptor, objc_class_name="alloc") +@(objc_type=DepthStencilDescriptor, objc_name="alloc", objc_is_class_method=true) DepthStencilDescriptor_alloc :: #force_inline proc() -> ^DepthStencilDescriptor { return msgSend(^DepthStencilDescriptor, DepthStencilDescriptor, "alloc") } @@ -1764,7 +1764,7 @@ Methods: @(objc_class="MTLFunctionConstant") FunctionConstant :: struct { using _: NS.Copying(FunctionConstant) } -@(objc_type=FunctionConstant, objc_class_name="alloc") +@(objc_type=FunctionConstant, objc_name="alloc", objc_is_class_method=true) FunctionConstant_alloc :: #force_inline proc() -> ^FunctionConstant { return msgSend(^FunctionConstant, FunctionConstant, "alloc") } @@ -1806,7 +1806,7 @@ Methods: @(objc_class="MTLFunctionConstantValues") FunctionConstantValues :: struct { using _: NS.Copying(FunctionConstantValues) } -@(objc_type=FunctionConstantValues, objc_class_name="alloc") +@(objc_type=FunctionConstantValues, objc_name="alloc", objc_is_class_method=true) FunctionConstantValues_alloc :: #force_inline proc() -> ^FunctionConstantValues { return msgSend(^FunctionConstantValues, FunctionConstantValues, "alloc") } @@ -1853,7 +1853,7 @@ Methods: @(objc_class="MTLFunctionDescriptor") FunctionDescriptor :: struct { using _: NS.Copying(FunctionDescriptor) } -@(objc_type=FunctionDescriptor, objc_class_name="alloc") +@(objc_type=FunctionDescriptor, objc_name="alloc", objc_is_class_method=true) FunctionDescriptor_alloc :: #force_inline proc() -> ^FunctionDescriptor { return msgSend(^FunctionDescriptor, FunctionDescriptor, "alloc") } @@ -1865,7 +1865,7 @@ FunctionDescriptor_init :: #force_inline proc(self: ^FunctionDescriptor) -> ^Fun FunctionDescriptor_constantValues :: #force_inline proc(self: ^FunctionDescriptor) -> ^FunctionConstantValues { return msgSend(^FunctionConstantValues, self, "constantValues") } -@(objc_type=FunctionDescriptor, objc_class_name="functionDescriptor") +@(objc_type=FunctionDescriptor, objc_name="functionDescriptor", objc_is_class_method=true) FunctionDescriptor_functionDescriptor :: #force_inline proc() -> ^FunctionDescriptor { return msgSend(^FunctionDescriptor, FunctionDescriptor, "functionDescriptor") } @@ -1911,7 +1911,7 @@ Methods: @(objc_class="MTLIntersectionFunctionDescriptor") IntersectionFunctionDescriptor :: struct { using _: NS.Copying(IntersectionFunctionDescriptor) } -@(objc_type=IntersectionFunctionDescriptor, objc_class_name="alloc") +@(objc_type=IntersectionFunctionDescriptor, objc_name="alloc", objc_is_class_method=true) IntersectionFunctionDescriptor_alloc :: #force_inline proc() -> ^IntersectionFunctionDescriptor { return msgSend(^IntersectionFunctionDescriptor, IntersectionFunctionDescriptor, "alloc") } @@ -1945,7 +1945,7 @@ Methods: @(objc_class="MTLHeapDescriptor") HeapDescriptor :: struct { using _: NS.Copying(HeapDescriptor) } -@(objc_type=HeapDescriptor, objc_class_name="alloc") +@(objc_type=HeapDescriptor, objc_name="alloc", objc_is_class_method=true) HeapDescriptor_alloc :: #force_inline proc() -> ^HeapDescriptor { return msgSend(^HeapDescriptor, HeapDescriptor, "alloc") } @@ -2027,7 +2027,7 @@ Methods: @(objc_class="MTLIndirectCommandBufferDescriptor") IndirectCommandBufferDescriptor :: struct { using _: NS.Copying(IndirectCommandBufferDescriptor) } -@(objc_type=IndirectCommandBufferDescriptor, objc_class_name="alloc") +@(objc_type=IndirectCommandBufferDescriptor, objc_name="alloc", objc_is_class_method=true) IndirectCommandBufferDescriptor_alloc :: #force_inline proc() -> ^IndirectCommandBufferDescriptor { return msgSend(^IndirectCommandBufferDescriptor, IndirectCommandBufferDescriptor, "alloc") } @@ -2108,7 +2108,7 @@ Methods: @(objc_class="MTLInstanceAccelerationStructureDescriptor") InstanceAccelerationStructureDescriptor :: struct { using _: NS.Copying(InstanceAccelerationStructureDescriptor), using _: AccelerationStructureDescriptor } -@(objc_type=InstanceAccelerationStructureDescriptor, objc_class_name="alloc") +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="alloc", objc_is_class_method=true) InstanceAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, InstanceAccelerationStructureDescriptor, "alloc") } @@ -2116,7 +2116,7 @@ InstanceAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^Instan InstanceAccelerationStructureDescriptor_init :: #force_inline proc(self: ^InstanceAccelerationStructureDescriptor) -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, self, "init") } -@(objc_type=InstanceAccelerationStructureDescriptor, objc_class_name="descriptor") +@(objc_type=InstanceAccelerationStructureDescriptor, objc_name="descriptor", objc_is_class_method=true) InstanceAccelerationStructureDescriptor_descriptor :: #force_inline proc() -> ^InstanceAccelerationStructureDescriptor { return msgSend(^InstanceAccelerationStructureDescriptor, InstanceAccelerationStructureDescriptor, "descriptor") } @@ -2217,7 +2217,7 @@ Methods: @(objc_class="MTLIntersectionFunctionTableDescriptor") IntersectionFunctionTableDescriptor :: struct { using _: NS.Copying(IntersectionFunctionTableDescriptor) } -@(objc_type=IntersectionFunctionTableDescriptor, objc_class_name="alloc") +@(objc_type=IntersectionFunctionTableDescriptor, objc_name="alloc", objc_is_class_method=true) IntersectionFunctionTableDescriptor_alloc :: #force_inline proc() -> ^IntersectionFunctionTableDescriptor { return msgSend(^IntersectionFunctionTableDescriptor, IntersectionFunctionTableDescriptor, "alloc") } @@ -2229,7 +2229,7 @@ IntersectionFunctionTableDescriptor_init :: #force_inline proc(self: ^Intersecti IntersectionFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^IntersectionFunctionTableDescriptor) -> NS.UInteger { return msgSend(NS.UInteger, self, "functionCount") } -@(objc_type=IntersectionFunctionTableDescriptor, objc_class_name="intersectionFunctionTableDescriptor") +@(objc_type=IntersectionFunctionTableDescriptor, objc_name="intersectionFunctionTableDescriptor", objc_is_class_method=true) IntersectionFunctionTableDescriptor_intersectionFunctionTableDescriptor :: #force_inline proc() -> ^IntersectionFunctionTableDescriptor { return msgSend(^IntersectionFunctionTableDescriptor, IntersectionFunctionTableDescriptor, "intersectionFunctionTableDescriptor") } @@ -2258,7 +2258,7 @@ Methods: @(objc_class="MTLLinkedFunctions") LinkedFunctions :: struct { using _: NS.Copying(LinkedFunctions) } -@(objc_type=LinkedFunctions, objc_class_name="alloc") +@(objc_type=LinkedFunctions, objc_name="alloc", objc_is_class_method=true) LinkedFunctions_alloc :: #force_inline proc() -> ^LinkedFunctions { return msgSend(^LinkedFunctions, LinkedFunctions, "alloc") } @@ -2278,7 +2278,7 @@ LinkedFunctions_functions :: #force_inline proc(self: ^LinkedFunctions) -> ^NS.A LinkedFunctions_groups :: #force_inline proc(self: ^LinkedFunctions) -> ^NS.Dictionary { return msgSend(^NS.Dictionary, self, "groups") } -@(objc_type=LinkedFunctions, objc_class_name="linkedFunctions") +@(objc_type=LinkedFunctions, objc_name="linkedFunctions", objc_is_class_method=true) LinkedFunctions_linkedFunctions :: #force_inline proc() -> ^LinkedFunctions { return msgSend(^LinkedFunctions, LinkedFunctions, "linkedFunctions") } @@ -2310,7 +2310,7 @@ Methods: @(objc_class="MTLPipelineBufferDescriptor") PipelineBufferDescriptor :: struct { using _: NS.Copying(PipelineBufferDescriptor) } -@(objc_type=PipelineBufferDescriptor, objc_class_name="alloc") +@(objc_type=PipelineBufferDescriptor, objc_name="alloc", objc_is_class_method=true) PipelineBufferDescriptor_alloc :: #force_inline proc() -> ^PipelineBufferDescriptor { return msgSend(^PipelineBufferDescriptor, PipelineBufferDescriptor, "alloc") } @@ -2342,7 +2342,7 @@ Methods: @(objc_class="MTLPipelineBufferDescriptorArray") PipelineBufferDescriptorArray :: struct { using _: NS.Object } -@(objc_type=PipelineBufferDescriptorArray, objc_class_name="alloc") +@(objc_type=PipelineBufferDescriptorArray, objc_name="alloc", objc_is_class_method=true) PipelineBufferDescriptorArray_alloc :: #force_inline proc() -> ^PipelineBufferDescriptorArray { return msgSend(^PipelineBufferDescriptorArray, PipelineBufferDescriptorArray, "alloc") } @@ -2379,7 +2379,7 @@ Methods: @(objc_class="MTLPointerType") PointerType :: struct { using _: Type } -@(objc_type=PointerType, objc_class_name="alloc") +@(objc_type=PointerType, objc_name="alloc", objc_is_class_method=true) PointerType_alloc :: #force_inline proc() -> ^PointerType { return msgSend(^PointerType, PointerType, "alloc") } @@ -2432,7 +2432,7 @@ Methods: @(objc_class="MTLPrimitiveAccelerationStructureDescriptor") PrimitiveAccelerationStructureDescriptor :: struct { using _: NS.Copying(PrimitiveAccelerationStructureDescriptor), using _: AccelerationStructureDescriptor } -@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_class_name="alloc") +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="alloc", objc_is_class_method=true) PrimitiveAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^PrimitiveAccelerationStructureDescriptor { return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "alloc") } @@ -2440,7 +2440,7 @@ PrimitiveAccelerationStructureDescriptor_alloc :: #force_inline proc() -> ^Primi PrimitiveAccelerationStructureDescriptor_init :: #force_inline proc(self: ^PrimitiveAccelerationStructureDescriptor) -> ^PrimitiveAccelerationStructureDescriptor { return msgSend(^PrimitiveAccelerationStructureDescriptor, self, "init") } -@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_class_name="descriptor") +@(objc_type=PrimitiveAccelerationStructureDescriptor, objc_name="descriptor", objc_is_class_method=true) PrimitiveAccelerationStructureDescriptor_descriptor :: #force_inline proc() -> ^PrimitiveAccelerationStructureDescriptor { return msgSend(^PrimitiveAccelerationStructureDescriptor, PrimitiveAccelerationStructureDescriptor, "descriptor") } @@ -2516,7 +2516,7 @@ Methods: @(objc_class="MTLRasterizationRateLayerArray") RasterizationRateLayerArray :: struct { using _: NS.Object } -@(objc_type=RasterizationRateLayerArray, objc_class_name="alloc") +@(objc_type=RasterizationRateLayerArray, objc_name="alloc", objc_is_class_method=true) RasterizationRateLayerArray_alloc :: #force_inline proc() -> ^RasterizationRateLayerArray { return msgSend(^RasterizationRateLayerArray, RasterizationRateLayerArray, "alloc") } @@ -2553,7 +2553,7 @@ Methods: @(objc_class="MTLRasterizationRateLayerDescriptor") RasterizationRateLayerDescriptor :: struct { using _: NS.Copying(RasterizationRateLayerDescriptor) } -@(objc_type=RasterizationRateLayerDescriptor, objc_class_name="alloc") +@(objc_type=RasterizationRateLayerDescriptor, objc_name="alloc", objc_is_class_method=true) RasterizationRateLayerDescriptor_alloc :: #force_inline proc() -> ^RasterizationRateLayerDescriptor { return msgSend(^RasterizationRateLayerDescriptor, RasterizationRateLayerDescriptor, "alloc") } @@ -2614,7 +2614,7 @@ Methods: @(objc_class="MTLRasterizationRateMapDescriptor") RasterizationRateMapDescriptor :: struct { using _: NS.Copying(RasterizationRateMapDescriptor) } -@(objc_type=RasterizationRateMapDescriptor, objc_class_name="alloc") +@(objc_type=RasterizationRateMapDescriptor, objc_name="alloc", objc_is_class_method=true) RasterizationRateMapDescriptor_alloc :: #force_inline proc() -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "alloc") } @@ -2638,15 +2638,15 @@ RasterizationRateMapDescriptor_layerCount :: #force_inline proc(self: ^Rasteriza RasterizationRateMapDescriptor_layers :: #force_inline proc(self: ^RasterizationRateMapDescriptor) -> ^RasterizationRateLayerArray { return msgSend(^RasterizationRateLayerArray, self, "layers") } -@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSize") +@(objc_type=RasterizationRateMapDescriptor, objc_name="rasterizationRateMapDescriptorWithScreenSize", objc_is_class_method=true) RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSize :: #force_inline proc(screenSize: Size) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:", screenSize) } -@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSizeWithLayer") +@(objc_type=RasterizationRateMapDescriptor, objc_name="rasterizationRateMapDescriptorWithScreenSizeWithLayer", objc_is_class_method=true) RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSizeWithLayer :: #force_inline proc(screenSize: Size, layer: ^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layer:", screenSize, layer) } -@(objc_type=RasterizationRateMapDescriptor, objc_class_name="rasterizationRateMapDescriptorWithScreenSizeWithLayers") +@(objc_type=RasterizationRateMapDescriptor, objc_name="rasterizationRateMapDescriptorWithScreenSizeWithLayers", objc_is_class_method=true) RasterizationRateMapDescriptor_rasterizationRateMapDescriptorWithScreenSizeWithLayers :: #force_inline proc(screenSize: Size, layers: []^RasterizationRateLayerDescriptor) -> ^RasterizationRateMapDescriptor { return msgSend(^RasterizationRateMapDescriptor, RasterizationRateMapDescriptor, "rasterizationRateMapDescriptorWithScreenSize:layerCount:layers:", screenSize, NS.UInteger(len(layers)), layers) } @@ -2682,7 +2682,7 @@ Methods: @(objc_class="MTLRasterizationRateSampleArray") RasterizationRateSampleArray :: struct { using _: NS.Object } -@(objc_type=RasterizationRateSampleArray, objc_class_name="alloc") +@(objc_type=RasterizationRateSampleArray, objc_name="alloc", objc_is_class_method=true) RasterizationRateSampleArray_alloc :: #force_inline proc() -> ^RasterizationRateSampleArray { return msgSend(^RasterizationRateSampleArray, RasterizationRateSampleArray, "alloc") } @@ -2734,7 +2734,7 @@ Methods: @(objc_class="MTLRenderPassAttachmentDescriptor") RenderPassAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassAttachmentDescriptor) } -@(objc_type=RenderPassAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=RenderPassAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPassAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassAttachmentDescriptor { return msgSend(^RenderPassAttachmentDescriptor, RenderPassAttachmentDescriptor, "alloc") } @@ -2846,7 +2846,7 @@ Methods: @(objc_class="MTLRenderPassColorAttachmentDescriptor") RenderPassColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassColorAttachmentDescriptor), using _: RenderPassAttachmentDescriptor } -@(objc_type=RenderPassColorAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=RenderPassColorAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPassColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassColorAttachmentDescriptor { return msgSend(^RenderPassColorAttachmentDescriptor, RenderPassColorAttachmentDescriptor, "alloc") } @@ -2878,7 +2878,7 @@ Methods: @(objc_class="MTLRenderPassColorAttachmentDescriptorArray") RenderPassColorAttachmentDescriptorArray :: struct { using _: NS.Object } -@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_class_name="alloc") +@(objc_type=RenderPassColorAttachmentDescriptorArray, objc_name="alloc", objc_is_class_method=true) RenderPassColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^RenderPassColorAttachmentDescriptorArray { return msgSend(^RenderPassColorAttachmentDescriptorArray, RenderPassColorAttachmentDescriptorArray, "alloc") } @@ -2912,7 +2912,7 @@ Methods: @(objc_class="MTLRenderPassDepthAttachmentDescriptor") RenderPassDepthAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassDepthAttachmentDescriptor), using _: RenderPassAttachmentDescriptor } -@(objc_type=RenderPassDepthAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=RenderPassDepthAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPassDepthAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassDepthAttachmentDescriptor { return msgSend(^RenderPassDepthAttachmentDescriptor, RenderPassDepthAttachmentDescriptor, "alloc") } @@ -2979,7 +2979,7 @@ Methods: @(objc_class="MTLRenderPassDescriptor") RenderPassDescriptor :: struct { using _: NS.Copying(RenderPassDescriptor), using _: AccelerationStructureDescriptor } -@(objc_type=RenderPassDescriptor, objc_class_name="alloc") +@(objc_type=RenderPassDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPassDescriptor_alloc :: #force_inline proc() -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, RenderPassDescriptor, "alloc") } @@ -3011,7 +3011,7 @@ RenderPassDescriptor_imageblockSampleLength :: #force_inline proc(self: ^RenderP RenderPassDescriptor_rasterizationRateMap :: #force_inline proc(self: ^RenderPassDescriptor) -> ^RasterizationRateMap { return msgSend(^RasterizationRateMap, self, "rasterizationRateMap") } -@(objc_type=RenderPassDescriptor, objc_class_name="renderPassDescriptor") +@(objc_type=RenderPassDescriptor, objc_name="renderPassDescriptor", objc_is_class_method=true) RenderPassDescriptor_renderPassDescriptor :: #force_inline proc() -> ^RenderPassDescriptor { return msgSend(^RenderPassDescriptor, RenderPassDescriptor, "renderPassDescriptor") } @@ -3127,7 +3127,7 @@ Methods: @(objc_class="MTLRenderPassSampleBufferAttachmentDescriptor") RenderPassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassSampleBufferAttachmentDescriptor) } -@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=RenderPassSampleBufferAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassSampleBufferAttachmentDescriptor { return msgSend(^RenderPassSampleBufferAttachmentDescriptor, RenderPassSampleBufferAttachmentDescriptor, "alloc") } @@ -3191,7 +3191,7 @@ Methods: @(objc_class="MTLRenderPassSampleBufferAttachmentDescriptorArray") RenderPassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } -@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +@(objc_type=RenderPassSampleBufferAttachmentDescriptorArray, objc_name="alloc", objc_is_class_method=true) RenderPassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^RenderPassSampleBufferAttachmentDescriptorArray { return msgSend(^RenderPassSampleBufferAttachmentDescriptorArray, RenderPassSampleBufferAttachmentDescriptorArray, "alloc") } @@ -3225,7 +3225,7 @@ Methods: @(objc_class="MTLRenderPassStencilAttachmentDescriptor") RenderPassStencilAttachmentDescriptor :: struct { using _: NS.Copying(RenderPassStencilAttachmentDescriptor) } -@(objc_type=RenderPassStencilAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=RenderPassStencilAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPassStencilAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPassStencilAttachmentDescriptor { return msgSend(^RenderPassStencilAttachmentDescriptor, RenderPassStencilAttachmentDescriptor, "alloc") } @@ -3281,7 +3281,7 @@ Methods: @(objc_class="MTLRenderPipelineColorAttachmentDescriptor") RenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(RenderPipelineColorAttachmentDescriptor), using _: RenderPassAttachmentDescriptor } -@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=RenderPipelineColorAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPipelineColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^RenderPipelineColorAttachmentDescriptor { return msgSend(^RenderPipelineColorAttachmentDescriptor, RenderPipelineColorAttachmentDescriptor, "alloc") } @@ -3377,7 +3377,7 @@ Methods: @(objc_class="MTLRenderPipelineColorAttachmentDescriptorArray") RenderPipelineColorAttachmentDescriptorArray :: struct { using _: NS.Object } -@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_class_name="alloc") +@(objc_type=RenderPipelineColorAttachmentDescriptorArray, objc_name="alloc", objc_is_class_method=true) RenderPipelineColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^RenderPipelineColorAttachmentDescriptorArray { return msgSend(^RenderPipelineColorAttachmentDescriptorArray, RenderPipelineColorAttachmentDescriptorArray, "alloc") } @@ -3455,7 +3455,7 @@ Methods: @(objc_class="MTLRenderPipelineDescriptor") RenderPipelineDescriptor :: struct { using _: NS.Copying(RenderPipelineDescriptor) } -@(objc_type=RenderPipelineDescriptor, objc_class_name="alloc") +@(objc_type=RenderPipelineDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPipelineDescriptor_alloc :: #force_inline proc() -> ^RenderPipelineDescriptor { return msgSend(^RenderPipelineDescriptor, RenderPipelineDescriptor, "alloc") } @@ -3672,7 +3672,7 @@ Methods: @(objc_class="MTLRenderPipelineReflection") RenderPipelineReflection :: struct { using _: NS.Object } -@(objc_type=RenderPipelineReflection, objc_class_name="alloc") +@(objc_type=RenderPipelineReflection, objc_name="alloc", objc_is_class_method=true) RenderPipelineReflection_alloc :: #force_inline proc() -> ^RenderPipelineReflection { return msgSend(^RenderPipelineReflection, RenderPipelineReflection, "alloc") } @@ -3708,7 +3708,7 @@ Methods: @(objc_class="MTLResourceStatePassDescriptor") ResourceStatePassDescriptor :: struct { using _: NS.Copying(ResourceStatePassDescriptor) } -@(objc_type=ResourceStatePassDescriptor, objc_class_name="alloc") +@(objc_type=ResourceStatePassDescriptor, objc_name="alloc", objc_is_class_method=true) ResourceStatePassDescriptor_alloc :: #force_inline proc() -> ^ResourceStatePassDescriptor { return msgSend(^ResourceStatePassDescriptor, ResourceStatePassDescriptor, "alloc") } @@ -3716,7 +3716,7 @@ ResourceStatePassDescriptor_alloc :: #force_inline proc() -> ^ResourceStatePassD ResourceStatePassDescriptor_init :: #force_inline proc(self: ^ResourceStatePassDescriptor) -> ^ResourceStatePassDescriptor { return msgSend(^ResourceStatePassDescriptor, self, "init") } -@(objc_type=ResourceStatePassDescriptor, objc_class_name="resourceStatePassDescriptor") +@(objc_type=ResourceStatePassDescriptor, objc_name="resourceStatePassDescriptor", objc_is_class_method=true) ResourceStatePassDescriptor_resourceStatePassDescriptor :: #force_inline proc() -> ^ResourceStatePassDescriptor { return msgSend(^ResourceStatePassDescriptor, ResourceStatePassDescriptor, "resourceStatePassDescriptor") } @@ -3744,7 +3744,7 @@ Methods: @(objc_class="MTLResourceStatePassSampleBufferAttachmentDescriptor") ResourceStatePassSampleBufferAttachmentDescriptor :: struct { using _: NS.Copying(ResourceStatePassSampleBufferAttachmentDescriptor) } -@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) ResourceStatePassSampleBufferAttachmentDescriptor_alloc :: #force_inline proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptor { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptor, ResourceStatePassSampleBufferAttachmentDescriptor, "alloc") } @@ -3792,7 +3792,7 @@ Methods: @(objc_class="MTLResourceStatePassSampleBufferAttachmentDescriptorArray") ResourceStatePassSampleBufferAttachmentDescriptorArray :: struct { using _: NS.Object } -@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_class_name="alloc") +@(objc_type=ResourceStatePassSampleBufferAttachmentDescriptorArray, objc_name="alloc", objc_is_class_method=true) ResourceStatePassSampleBufferAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^ResourceStatePassSampleBufferAttachmentDescriptorArray { return msgSend(^ResourceStatePassSampleBufferAttachmentDescriptorArray, ResourceStatePassSampleBufferAttachmentDescriptorArray, "alloc") } @@ -3852,7 +3852,7 @@ Methods: @(objc_class="MTLSamplerDescriptor") SamplerDescriptor :: struct { using _: NS.Copying(SamplerDescriptor) } -@(objc_type=SamplerDescriptor, objc_class_name="alloc") +@(objc_type=SamplerDescriptor, objc_name="alloc", objc_is_class_method=true) SamplerDescriptor_alloc :: #force_inline proc() -> ^SamplerDescriptor { return msgSend(^SamplerDescriptor, SamplerDescriptor, "alloc") } @@ -3995,7 +3995,7 @@ Methods: @(objc_class="MTLSharedEventHandle") SharedEventHandle :: struct { using _: NS.Object } -@(objc_type=SharedEventHandle, objc_class_name="alloc") +@(objc_type=SharedEventHandle, objc_name="alloc", objc_is_class_method=true) SharedEventHandle_alloc :: #force_inline proc() -> ^SharedEventHandle { return msgSend(^SharedEventHandle, SharedEventHandle, "alloc") } @@ -4023,7 +4023,7 @@ Methods: @(objc_class="MTLSharedEventListener") SharedEventListener :: struct { using _: NS.Object } -@(objc_type=SharedEventListener, objc_class_name="alloc") +@(objc_type=SharedEventListener, objc_name="alloc", objc_is_class_method=true) SharedEventListener_alloc :: #force_inline proc() -> ^SharedEventListener { return msgSend(^SharedEventListener, SharedEventListener, "alloc") } @@ -4055,7 +4055,7 @@ Methods: @(objc_class="MTLSharedTextureHandle") SharedTextureHandle :: struct { using _: NS.Object } -@(objc_type=SharedTextureHandle, objc_class_name="alloc") +@(objc_type=SharedTextureHandle, objc_name="alloc", objc_is_class_method=true) SharedTextureHandle_alloc :: #force_inline proc() -> ^SharedTextureHandle { return msgSend(^SharedTextureHandle, SharedTextureHandle, "alloc") } @@ -4093,7 +4093,7 @@ Methods: @(objc_class="MTLStageInputOutputDescriptor") StageInputOutputDescriptor :: struct { using _: NS.Copying(StageInputOutputDescriptor) } -@(objc_type=StageInputOutputDescriptor, objc_class_name="alloc") +@(objc_type=StageInputOutputDescriptor, objc_name="alloc", objc_is_class_method=true) StageInputOutputDescriptor_alloc :: #force_inline proc() -> ^StageInputOutputDescriptor { return msgSend(^StageInputOutputDescriptor, StageInputOutputDescriptor, "alloc") } @@ -4129,7 +4129,7 @@ StageInputOutputDescriptor_setIndexBufferIndex :: #force_inline proc(self: ^Stag StageInputOutputDescriptor_setIndexType :: #force_inline proc(self: ^StageInputOutputDescriptor, indexType: IndexType) { msgSend(nil, self, "setIndexType:", indexType) } -@(objc_type=StageInputOutputDescriptor, objc_class_name="stageInputOutputDescriptor") +@(objc_type=StageInputOutputDescriptor, objc_name="stageInputOutputDescriptor", objc_is_class_method=true) StageInputOutputDescriptor_stageInputOutputDescriptor :: #force_inline proc() -> ^StageInputOutputDescriptor { return msgSend(^StageInputOutputDescriptor, StageInputOutputDescriptor, "stageInputOutputDescriptor") } @@ -4159,7 +4159,7 @@ Methods: @(objc_class="MTLStencilDescriptor") StencilDescriptor :: struct { using _: NS.Copying(StencilDescriptor) } -@(objc_type=StencilDescriptor, objc_class_name="alloc") +@(objc_type=StencilDescriptor, objc_name="alloc", objc_is_class_method=true) StencilDescriptor_alloc :: #force_inline proc() -> ^StencilDescriptor { return msgSend(^StencilDescriptor, StencilDescriptor, "alloc") } @@ -4237,7 +4237,7 @@ Methods: @(objc_class="MTLStructMember") StructMember :: struct { using _: NS.Object } -@(objc_type=StructMember, objc_class_name="alloc") +@(objc_type=StructMember, objc_name="alloc", objc_is_class_method=true) StructMember_alloc :: #force_inline proc() -> ^StructMember { return msgSend(^StructMember, StructMember, "alloc") } @@ -4293,7 +4293,7 @@ Methods: @(objc_class="MTLStructType") StructType :: struct { using _: Type } -@(objc_type=StructType, objc_class_name="alloc") +@(objc_type=StructType, objc_name="alloc", objc_is_class_method=true) StructType_alloc :: #force_inline proc() -> ^StructType { return msgSend(^StructType, StructType, "alloc") } @@ -4356,7 +4356,7 @@ Methods: @(objc_class="MTLTextureDescriptor") TextureDescriptor :: struct { using _: NS.Copying(TextureDescriptor) } -@(objc_type=TextureDescriptor, objc_class_name="alloc") +@(objc_type=TextureDescriptor, objc_name="alloc", objc_is_class_method=true) TextureDescriptor_alloc :: #force_inline proc() -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "alloc") } @@ -4472,15 +4472,15 @@ TextureDescriptor_storageMode :: #force_inline proc(self: ^TextureDescriptor) -> TextureDescriptor_swizzle :: #force_inline proc(self: ^TextureDescriptor) -> TextureSwizzleChannels { return msgSend(TextureSwizzleChannels, self, "swizzle") } -@(objc_type=TextureDescriptor, objc_class_name="texture2DDescriptor") +@(objc_type=TextureDescriptor, objc_name="texture2DDescriptor", objc_is_class_method=true) TextureDescriptor_texture2DDescriptor :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, height: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "texture2DDescriptorWithPixelFormat:width:height:mipmapped:", pixelFormat, width, height, mipmapped) } -@(objc_type=TextureDescriptor, objc_class_name="textureBufferDescriptor") +@(objc_type=TextureDescriptor, objc_name="textureBufferDescriptor", objc_is_class_method=true) TextureDescriptor_textureBufferDescriptor :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureBufferDescriptorWithPixelFormat:width:resourceOptions:usage:", pixelFormat, width, resourceOptions, usage) } -@(objc_type=TextureDescriptor, objc_class_name="textureCubeDescriptor") +@(objc_type=TextureDescriptor, objc_name="textureCubeDescriptor", objc_is_class_method=true) TextureDescriptor_textureCubeDescriptor :: #force_inline proc(pixelFormat: PixelFormat, size: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureCubeDescriptorWithPixelFormat:size:mipmapped:", pixelFormat, size, mipmapped) } @@ -4514,7 +4514,7 @@ Methods: @(objc_class="MTLTextureReferenceType") TextureReferenceType :: struct { using _: Type } -@(objc_type=TextureReferenceType, objc_class_name="alloc") +@(objc_type=TextureReferenceType, objc_name="alloc", objc_is_class_method=true) TextureReferenceType_alloc :: #force_inline proc() -> ^TextureReferenceType { return msgSend(^TextureReferenceType, TextureReferenceType, "alloc") } @@ -4554,7 +4554,7 @@ Methods: @(objc_class="MTLTileRenderPipelineColorAttachmentDescriptor") TileRenderPipelineColorAttachmentDescriptor :: struct { using _: NS.Copying(TileRenderPipelineColorAttachmentDescriptor) } -@(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_class_name="alloc") +@(objc_type=TileRenderPipelineColorAttachmentDescriptor, objc_name="alloc", objc_is_class_method=true) TileRenderPipelineColorAttachmentDescriptor_alloc :: #force_inline proc() -> ^TileRenderPipelineColorAttachmentDescriptor { return msgSend(^TileRenderPipelineColorAttachmentDescriptor, TileRenderPipelineColorAttachmentDescriptor, "alloc") } @@ -4586,7 +4586,7 @@ Methods: @(objc_class="MTLTileRenderPipelineColorAttachmentDescriptorArray") TileRenderPipelineColorAttachmentDescriptorArray :: struct { using _: NS.Object } -@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_class_name="alloc") +@(objc_type=TileRenderPipelineColorAttachmentDescriptorArray, objc_name="alloc", objc_is_class_method=true) TileRenderPipelineColorAttachmentDescriptorArray_alloc :: #force_inline proc() -> ^TileRenderPipelineColorAttachmentDescriptorArray { return msgSend(^TileRenderPipelineColorAttachmentDescriptorArray, TileRenderPipelineColorAttachmentDescriptorArray, "alloc") } @@ -4631,7 +4631,7 @@ Methods: @(objc_class="MTLTileRenderPipelineDescriptor") TileRenderPipelineDescriptor :: struct { using _: NS.Copying(TileRenderPipelineDescriptor) } -@(objc_type=TileRenderPipelineDescriptor, objc_class_name="alloc") +@(objc_type=TileRenderPipelineDescriptor, objc_name="alloc", objc_is_class_method=true) TileRenderPipelineDescriptor_alloc :: #force_inline proc() -> ^TileRenderPipelineDescriptor { return msgSend(^TileRenderPipelineDescriptor, TileRenderPipelineDescriptor, "alloc") } @@ -4714,7 +4714,7 @@ Methods: @(objc_class="MTLType") Type :: struct { using _: NS.Object } -@(objc_type=Type, objc_class_name="alloc") +@(objc_type=Type, objc_name="alloc", objc_is_class_method=true) Type_alloc :: #force_inline proc() -> ^Type { return msgSend(^Type, Type, "alloc") } @@ -4746,7 +4746,7 @@ Methods: @(objc_class="MTLVertexAttribute") VertexAttribute :: struct { using _: NS.Object } -@(objc_type=VertexAttribute, objc_class_name="alloc") +@(objc_type=VertexAttribute, objc_name="alloc", objc_is_class_method=true) VertexAttribute_alloc :: #force_inline proc() -> ^VertexAttribute { return msgSend(^VertexAttribute, VertexAttribute, "alloc") } @@ -4798,7 +4798,7 @@ Methods: @(objc_class="MTLVertexAttributeDescriptor") VertexAttributeDescriptor :: struct { using _: NS.Copying(VertexAttributeDescriptor) } -@(objc_type=VertexAttributeDescriptor, objc_class_name="alloc") +@(objc_type=VertexAttributeDescriptor, objc_name="alloc", objc_is_class_method=true) VertexAttributeDescriptor_alloc :: #force_inline proc() -> ^VertexAttributeDescriptor { return msgSend(^VertexAttributeDescriptor, VertexAttributeDescriptor, "alloc") } @@ -4846,7 +4846,7 @@ Methods: @(objc_class="MTLVertexAttributeDescriptorArray") VertexAttributeDescriptorArray :: struct { using _: NS.Object } -@(objc_type=VertexAttributeDescriptorArray, objc_class_name="alloc") +@(objc_type=VertexAttributeDescriptorArray, objc_name="alloc", objc_is_class_method=true) VertexAttributeDescriptorArray_alloc :: #force_inline proc() -> ^VertexAttributeDescriptorArray { return msgSend(^VertexAttributeDescriptorArray, VertexAttributeDescriptorArray, "alloc") } @@ -4882,7 +4882,7 @@ Methods: @(objc_class="MTLVertexBufferLayoutDescriptor") VertexBufferLayoutDescriptor :: struct { using _: NS.Copying(VertexBufferLayoutDescriptor) } -@(objc_type=VertexBufferLayoutDescriptor, objc_class_name="alloc") +@(objc_type=VertexBufferLayoutDescriptor, objc_name="alloc", objc_is_class_method=true) VertexBufferLayoutDescriptor_alloc :: #force_inline proc() -> ^VertexBufferLayoutDescriptor { return msgSend(^VertexBufferLayoutDescriptor, VertexBufferLayoutDescriptor, "alloc") } @@ -4930,7 +4930,7 @@ Methods: @(objc_class="MTLVertexBufferLayoutDescriptorArray") VertexBufferLayoutDescriptorArray :: struct { using _: NS.Object } -@(objc_type=VertexBufferLayoutDescriptorArray, objc_class_name="alloc") +@(objc_type=VertexBufferLayoutDescriptorArray, objc_name="alloc", objc_is_class_method=true) VertexBufferLayoutDescriptorArray_alloc :: #force_inline proc() -> ^VertexBufferLayoutDescriptorArray { return msgSend(^VertexBufferLayoutDescriptorArray, VertexBufferLayoutDescriptorArray, "alloc") } @@ -4964,7 +4964,7 @@ Methods: @(objc_class="MTLVertexDescriptor") VertexDescriptor :: struct { using _: NS.Copying(VertexDescriptor) } -@(objc_type=VertexDescriptor, objc_class_name="alloc") +@(objc_type=VertexDescriptor, objc_name="alloc", objc_is_class_method=true) VertexDescriptor_alloc :: #force_inline proc() -> ^VertexDescriptor { return msgSend(^VertexDescriptor, VertexDescriptor, "alloc") } @@ -4984,7 +4984,7 @@ VertexDescriptor_layouts :: #force_inline proc(self: ^VertexDescriptor) -> ^Vert VertexDescriptor_reset :: #force_inline proc(self: ^VertexDescriptor) { msgSend(nil, self, "reset") } -@(objc_type=VertexDescriptor, objc_class_name="vertexDescriptor") +@(objc_type=VertexDescriptor, objc_name="vertexDescriptor", objc_is_class_method=true) VertexDescriptor_vertexDescriptor :: #force_inline proc() -> ^VertexDescriptor { return msgSend(^VertexDescriptor, VertexDescriptor, "vertexDescriptor") } @@ -5005,7 +5005,7 @@ Methods: @(objc_class="MTLVisibleFunctionTableDescriptor") VisibleFunctionTableDescriptor :: struct { using _: NS.Copying(VisibleFunctionTableDescriptor) } -@(objc_type=VisibleFunctionTableDescriptor, objc_class_name="alloc") +@(objc_type=VisibleFunctionTableDescriptor, objc_name="alloc", objc_is_class_method=true) VisibleFunctionTableDescriptor_alloc :: #force_inline proc() -> ^VisibleFunctionTableDescriptor { return msgSend(^VisibleFunctionTableDescriptor, VisibleFunctionTableDescriptor, "alloc") } @@ -5021,7 +5021,7 @@ VisibleFunctionTableDescriptor_functionCount :: #force_inline proc(self: ^Visibl VisibleFunctionTableDescriptor_setFunctionCount :: #force_inline proc(self: ^VisibleFunctionTableDescriptor, functionCount: NS.UInteger) { msgSend(nil, self, "setFunctionCount:", functionCount) } -@(objc_type=VisibleFunctionTableDescriptor, objc_class_name="visibleFunctionTableDescriptor") +@(objc_type=VisibleFunctionTableDescriptor, objc_name="visibleFunctionTableDescriptor", objc_is_class_method=true) VisibleFunctionTableDescriptor_visibleFunctionTableDescriptor :: #force_inline proc() -> ^VisibleFunctionTableDescriptor { return msgSend(^VisibleFunctionTableDescriptor, VisibleFunctionTableDescriptor, "visibleFunctionTableDescriptor") } @@ -7976,7 +7976,7 @@ Class: @(objc_class="MTLRenderPipelineFunctionsDescriptor") RenderPipelineFunctionsDescriptor :: struct { using _: NS.Copying(RenderPipelineFunctionsDescriptor) } -@(objc_type=RenderPipelineFunctionsDescriptor, objc_class_name="alloc") +@(objc_type=RenderPipelineFunctionsDescriptor, objc_name="alloc", objc_is_class_method=true) RenderPipelineFunctionsDescriptor_alloc :: #force_inline proc() -> ^RenderPipelineFunctionsDescriptor { return msgSend(^RenderPipelineFunctionsDescriptor, RenderPipelineFunctionsDescriptor, "alloc") } diff --git a/core/sys/darwin/QuartzCore/QuartzCore.odin b/core/sys/darwin/QuartzCore/QuartzCore.odin index 0afb8aa37..c35453efc 100644 --- a/core/sys/darwin/QuartzCore/QuartzCore.odin +++ b/core/sys/darwin/QuartzCore/QuartzCore.odin @@ -10,7 +10,7 @@ msgSend :: intrinsics.objc_send @(objc_class="CAMetalLayer") MetalLayer :: struct{ using _: NS.Layer} -@(objc_type=MetalLayer, objc_class_name="layer") +@(objc_type=MetalLayer, objc_name="layer", objc_is_class_method=true) MetalLayer_layer :: proc() -> ^MetalLayer { return msgSend(^MetalLayer, MetalLayer, "layer") } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1d30088d6..45d741532 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -826,15 +826,13 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } e->Procedure.optimization_mode = cast(ProcedureOptimizationMode)ac.optimization_mode; - if (ac.objc_name.len || ac.objc_class_name.len || ac.objc_type) { - if (ac.objc_class_name.len && ac.objc_name.len) { - error(e->token, "@(objc_class_name) and @(objc_name) may not be allowed at the same time"); + if (ac.objc_name.len || ac.objc_is_class_method || ac.objc_type) { + if (ac.objc_name.len == 0 && ac.objc_is_class_method) { + error(e->token, "@(objc_name) is required with @(objc_is_class_method)"); } else if (ac.objc_type == nullptr) { - if (ac.objc_name.len) { - error(e->token, "@(objc_name) requires that @(objc_type) to be set"); - } else { - error(e->token, "@(objc_class_name) requires that @(objc_type) to be set"); - } + error(e->token, "@(objc_name) requires that @(objc_type) to be set"); + } else if (ac.objc_name.len == 0 && ac.objc_type) { + error(e->token, "@(objc_name) is required with @(objc_type)"); } else { Type *t = ac.objc_type; if (t->kind == Type_Named) { @@ -843,7 +841,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { GB_ASSERT(tn->kind == Entity_TypeName); if (tn->scope != e->scope) { - error(e->token, "@(objc_name) and @(objc_class_name) attributes may only be applied to procedures and types within the same scope"); + error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope"); } else { mutex_lock(&global_type_name_objc_metadata_mutex); defer (mutex_unlock(&global_type_name_objc_metadata_mutex)); @@ -855,7 +853,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { mutex_lock(md->mutex); defer (mutex_unlock(md->mutex)); - if (ac.objc_name.len) { + if (!ac.objc_is_class_method) { bool ok = true; for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { if (entry.name == ac.objc_name) { @@ -870,14 +868,14 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } else { bool ok = true; for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { - if (entry.name == ac.objc_class_name) { - error(e->token, "Previous declaration of @(objc_class_name=\"%.*s\")", LIT(ac.objc_class_name)); + if (entry.name == ac.objc_name) { + error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); ok = false; break; } } if (ok) { - array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_class_name, e}); + array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); } } } diff --git a/src/checker.cpp b/src/checker.cpp index 0dd36987e..dac4dd79f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3059,16 +3059,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { error(elem, "Expected a string value for '%.*s'", LIT(name)); } return true; - } else if (name == "objc_class_name") { + } else if (name == "objc_is_class_method") { ExactValue ev = check_decl_attribute_value(c, value); - if (ev.kind == ExactValue_String) { - if (string_is_valid_identifier(ev.value_string)) { - ac->objc_class_name = ev.value_string; - } else { - error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string)); - } + if (ev.kind == ExactValue_Bool) { + ac->objc_is_class_method = ev.value_bool; } else { - error(elem, "Expected a string value for '%.*s'", LIT(name)); + error(elem, "Expected a boolean value for '%.*s'", LIT(name)); } return true; } else if (name == "objc_type") { diff --git a/src/checker.hpp b/src/checker.hpp index 38c8d32f6..552e6aca7 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -121,7 +121,7 @@ struct AttributeContext { String objc_class; String objc_name; - String objc_class_name; + bool objc_is_class_method; Type * objc_type; }; From 32c7e817450e8f089eec81a147d20b919db088ff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 18:32:10 +0000 Subject: [PATCH 0184/1052] Use `objc_allocateClassPair` for `intrinsics.objc_register_class` --- core/runtime/procs_darwin.odin | 1 + src/check_builtin.cpp | 1 + src/llvm_backend_utility.cpp | 8 +++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/runtime/procs_darwin.odin b/core/runtime/procs_darwin.odin index 79fd777d7..b54a28dcc 100644 --- a/core/runtime/procs_darwin.odin +++ b/core/runtime/procs_darwin.odin @@ -12,6 +12,7 @@ objc_SEL :: ^intrinsics.objc_selector foreign Foundation { objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class --- sel_registerName :: proc "c" (name: cstring) -> objc_SEL --- + objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) --- objc_msgSend :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) --- objc_msgSend_fpret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a6b1759f5..c7ada8e03 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -225,6 +225,7 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice(permanent_allocator(), 1); - args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); - lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); + auto args = array_make(permanent_allocator(), 3); + args[0] = lb_const_nil(m, t_objc_Class); + args[1] = lb_const_nil(m, t_objc_Class); + args[2] = lb_const_int(m, t_uint, 0); + lbValue ptr = lb_emit_runtime_call(p, "objc_allocateClassPair", args); lb_addr_store(p, dst, ptr); return lb_addr_load(p, dst); From 753cceea82b99c3dbf0f6adc286469123d5bd076 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 18:34:55 +0000 Subject: [PATCH 0185/1052] Minor changes to method names on NS.String --- core/sys/darwin/Foundation/NSString.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin index 66442383a..ae1d6d43f 100644 --- a/core/sys/darwin/Foundation/NSString.odin +++ b/core/sys/darwin/Foundation/NSString.odin @@ -100,8 +100,8 @@ String_length :: proc(self: ^String) -> UInteger { return msgSend(UInteger, self, "length") } -@(objc_type=String, objc_name="cStringUsingEncoding") -String_cStringUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> cstring { +@(objc_type=String, objc_name="cstringUsingEncoding") +String_cstringUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> cstring { return msgSend(cstring, self, "cStringUsingEncoding:", encoding) } @@ -110,8 +110,8 @@ String_UTF8String :: proc(self: ^String) -> cstring { return msgSend(cstring, self, "UTF8String") } -@(objc_type=String, objc_name="OdinString") -String_OdinString :: proc(self: ^String) -> string { +@(objc_type=String, objc_name="odinString") +String_odinString :: proc(self: ^String) -> string { return string(String_UTF8String(self)) } From e6e04fc6c888b9acdb0058f7050a53b0bc7d4465 Mon Sep 17 00:00:00 2001 From: Phil H Date: Mon, 14 Feb 2022 22:15:45 -0800 Subject: [PATCH 0186/1052] Add 'odin run -help' info for specifying args --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 27c71c8eb..efb0f584e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1851,6 +1851,7 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); } else if (command == "run") { print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); + print_usage_line(1, " append an empty flag and then the args, '-- ', to specify args for the output."); } else if (command == "check") { print_usage_line(1, "check parse and type check .odin file(s)"); } else if (command == "test") { From 0e5928ff39653d3a1de3e071afbcc1b29f5fe9f7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 15:16:30 +0000 Subject: [PATCH 0187/1052] Correct pseudo selector code generation --- src/check_expr.cpp | 6 +++--- src/llvm_backend_expr.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6db17a316..7fb0e44f2 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6396,10 +6396,10 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr return builtin_procs[id].kind; } - Entity *e = entity_of_node(operand->expr); + Entity *initial_entity = entity_of_node(operand->expr); - if (e != nullptr && e->kind == Entity_Procedure) { - if (e->Procedure.deferred_procedure.entity != nullptr) { + if (initial_entity != nullptr && initial_entity->kind == Entity_Procedure) { + if (initial_entity->Procedure.deferred_procedure.entity != nullptr) { call->viral_state_flags |= ViralStateFlag_ContainsDeferredProcedure; } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index b2f430cd2..844deb43c 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3303,9 +3303,9 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(se, SelectorExpr, expr); - Ast *sel = unparen_expr(se->selector); - if (sel->kind == Ast_Ident) { - String selector = sel->Ident.token.string; + Ast *sel_node = unparen_expr(se->selector); + if (sel_node->kind == Ast_Ident) { + String selector = sel_node->Ident.token.string; TypeAndValue tav = type_and_value_of_expr(se->expr); if (tav.mode == Addressing_Invalid) { @@ -3354,7 +3354,8 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { GB_ASSERT(sel.entity != nullptr); if (sel.pseudo_field) { GB_ASSERT(sel.entity->kind == Entity_Procedure); - return lb_addr(lb_find_value_from_entity(p->module, sel.entity)); + Entity *e = entity_of_node(sel_node); + return lb_addr(lb_find_value_from_entity(p->module, e)); } { From 3380ece4a1003a068377e0a9c884d6e177a23d63 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 15:16:48 +0000 Subject: [PATCH 0188/1052] Add utility calls for creating buffers from slices --- core/sys/darwin/Metal/MetalClasses.odin | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/core/sys/darwin/Metal/MetalClasses.odin index 2686ce2ae..e5b6d0849 100644 --- a/core/sys/darwin/Metal/MetalClasses.odin +++ b/core/sys/darwin/Metal/MetalClasses.odin @@ -1,6 +1,7 @@ package objc_Metal import NS "core:sys/darwin/Foundation" +import "core:mem" //////////////////////////////////////////////////////////////////////////////// @@ -6465,6 +6466,16 @@ Device_newBufferWithBytes :: #force_inline proc(self: ^Device, bytes: []byte, op Device_newBufferWithBytesNoCopy :: #force_inline proc(self: ^Device, bytes: []byte, options: ResourceOptions, deallocator: rawptr) -> ^Buffer { return msgSend(^Buffer, self, "newBufferWithBytesNoCopy:length:options:deallocator:", raw_data(bytes), NS.UInteger(len(bytes)), options, deallocator) } + +@(objc_type=Device, objc_name="newBufferWithSlice") +Device_newBufferWithSlice :: #force_inline proc(self: ^Device, slice: $S/[]$E, options: ResourceOptions) -> ^Buffer { + return Device_newBufferWithBytes(self, mem.slice_to_bytes(slice), options) +} +@(objc_type=Device, objc_name="newBufferWithSliceNoCopy") +Device_newBufferWithSliceNoCopy :: #force_inline proc(self: ^Device, slice: $S/[]$E, options: ResourceOptions, deallocator: rawptr) -> ^Buffer { + return Device_newBufferWithBytesNotCopy(self, mem.slice_to_bytes(slice), options, deallocator) +} + @(objc_type=Device, objc_name="newBuffer") Device_newBuffer :: #force_inline proc(self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { return msgSend(^Buffer, self, "newBufferWithLength:options:", length, options) @@ -7263,7 +7274,7 @@ IndirectRenderCommand_drawPatches :: #force_inline proc(self: ^IndirectRenderCom msgSend(nil, self, "drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:tessellationFactorBuffer:tessellationFactorBufferOffset:tessellationFactorBufferInstanceStride:", numberOfPatchControlPoints, patchStart, patchCount, patchIndexBuffer, patchIndexBufferOffset, instanceCount, baseInstance, buffer, offset, instanceStride) } @(objc_type=IndirectRenderCommand, objc_name="drawPrimitives") -IndirectRenderCommand_drawPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger = 0, baseInstance: NS.UInteger = 0) { +IndirectRenderCommand_drawPrimitives :: #force_inline proc(self: ^IndirectRenderCommand, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger = 0) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } @(objc_type=IndirectRenderCommand, objc_name="reset") From 3ab5db82975f20190c4f1ffc2a06d02c5b8d98c4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 15:17:21 +0000 Subject: [PATCH 0189/1052] Add README.md --- core/sys/darwin/Metal/README.md | 155 ++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 core/sys/darwin/Metal/README.md diff --git a/core/sys/darwin/Metal/README.md b/core/sys/darwin/Metal/README.md new file mode 100644 index 000000000..e61d7f7aa --- /dev/null +++ b/core/sys/darwin/Metal/README.md @@ -0,0 +1,155 @@ +## About + +**metal-odin** is a low overhead Odin interface for Metal that helps developers add Metal functionality to graphics applications that are written in Odin. **metal-odin** removes the need to create a shim and allows developers to call Metal functions directly from anywhere in their existing Odin code. + +## Highlights + +- Drop in Odin alternative interface to the Metal Objective-C headers. +- Direct mapping of all Metal Objective-C classes, constants, enums and bit_sets to Odin +- No measurable overhead compared to calling Metal Objective-C headers, due to inlining of Odin procedure calls. +- No usage of wrapper containers that require additional allocations. +- Identical header files and procedure/constant/enum availability for iOS, macOS and tvOS. +- Backwards compatibility: All `MTL.Device.supports...()` procedure check if their required selectors exist and automatically return `false` if not. +- String (`ErrorDomain`) constants are `@(linkage="weak")` and automatically set to `nil` if not available. + +## Memory Allocation Policy + +**metal-odin** follows the object allocation policies of Cocoa and Cocoa Touch. Understanding those rules is especially important when using `metal-odin`, as Odin values are not eligible for automatic reference counting (ARC). + +**metal-odin** objects are reference counted. To help convey and manage object lifecycles, the following conventions are observed: + +### AutoreleasePools and Objects + +Several methods that create temporary objects in **metal-odin** add them to an `AutoreleasePool` to help manage their lifetimes. In these situations, after **metal-odin** creates the object, it adds it to an `AutoreleasePool`, which will release its objects when you release (or drain) it. + +By adding temporary objects to an AutoreleasePool, you do not need to explicitly call `release()` to deallocate them. Instead, you can rely on the `AutoreleasePool` to implicitly manage those lifetimes. + +If you create an object with a method that does not begin with `alloc`, or `copy`, the creating method adds the object to an autorelease pool. + +The typical scope of an `AutoreleasePool` is one frame of rendering for the main thread of the program. When the thread returns control to the RunLoop (an object responsible for receiving input and events from the windowing system), the pool is *drained*, releasing its objects. + +You can create and manage additional `AutoreleasePool`s at smaller scopes to reduce your program's working set, and you are required to do so for any additional threads your program creates. + +If an object's lifecycle needs to be extended beyond the `AutoreleasePool`'s scope, you can claim ownership of it (avoiding its release beyond the pool's scope) by calling its `retain()` method before its pool is drained. In these cases, you will be responsible for making the appropriate `release()` call on the object after you no longer need it. + +You can find a more-detailed introduction to the memory management rules here: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html. + +For more details about the application's RunLoop, please find its documentation here: https://developer.apple.com/documentation/foundation/nsrunloop + +### Use and debug AutoreleasePools + +When you create an autoreleased object and there is no enclosing `AutoreleasePool`, the object is leaked. + +To prevent this, you normally create an `AutoreleasePool` in your program's `main` procedure, and in the entry procedure for every thread you create. You may also create additional `AutoreleasePool`s to avoid growing your program's high memory watermark when you create several autoreleased objects, such as when rendering. + +Use the Environment Variable `OBJC_DEBUG_MISSING_POOLS=YES` to print a runtime warning when an autoreleased object is leaked because no enclosing `AutoreleasePool` is available for its thread. + +You can also run `leaks --autoreleasePools` on a memgraph file or a process ID (macOS only) to view a listing of your program's `AutoreleasePool`s and all objects they contain. + +### nil + +Similar to Objective-C, it is legal to call any method, including `retain()` and `release()`, on `nil` "objects". While calling methods on `nil` still does incur in procedure call overhead, the effective result is equivalent of a NOP. + +Conversely, do not assume that because calling a method on a pointer did not result in a crash, that the pointed-to object is valid. + +## Adding `metal-odin` to a Project + +Simply `import MTL "core:sys/darwin/Metal"`. To ensure that the selector and class symbols are linked. + +```odin +import MTL "core:sys/darwin/Metal" +``` + +## Examples + +#### Creating the device + +###### Objective-C (with automatic reference counting) + +```objc +id< MTLDevice > device = MTLCreateSystemDefaultDevice(); + +// ... +``` + +###### Objective-C + +```objc +id< MTLDevice > device = MTLCreateSystemDefaultDevice(); + +// ... + +[device release]; +``` + +###### Odin + +```odin +device := MTL.CreateSystemDefaultDevice() + +// ... + +device->release() +``` + +#### Metal function calls map directly to Odin + +###### Objective-C (with automatic reference counting) + +```objc +MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init]; + +[samplerDescriptor setSAddressMode: MTLSamplerAddressModeRepeat]; +[samplerDescriptor setTAddressMode: MTLSamplerAddressModeRepeat]; +[samplerDescriptor setRAddressMode: MTLSamplerAddressModeRepeat]; +[samplerDescriptor setMagFilter: MTLSamplerMinMagFilterLinear]; +[samplerDescriptor setMinFilter: MTLSamplerMinMagFilterLinear]; +[samplerDescriptor setMipFilter: MTLSamplerMipFilterLinear]; +[samplerDescriptor setSupportArgumentBuffers: YES]; + +id< MTLSamplerState > samplerState = [device newSamplerStateWithDescriptor:samplerDescriptor]; +``` + +###### Objective-C + +```objc +MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init]; + +[samplerDescriptor setSAddressMode: MTLSamplerAddressModeRepeat]; +[samplerDescriptor setTAddressMode: MTLSamplerAddressModeRepeat]; +[samplerDescriptor setRAddressMode: MTLSamplerAddressModeRepeat]; +[samplerDescriptor setMagFilter: MTLSamplerMinMagFilterLinear]; +[samplerDescriptor setMinFilter: MTLSamplerMinMagFilterLinear]; +[samplerDescriptor setMipFilter: MTLSamplerMipFilterLinear]; +[samplerDescriptor setSupportArgumentBuffers: YES]; + +id< MTLSamplerState > samplerState = [device newSamplerStateWithDescriptor:samplerDescriptor]; + +[samplerDescriptor release]; + +// ... + +[samplerState release]; +``` + +###### Odin + +```odin +samplerDescriptor := MTL.SamplerDescriptor.alloc()->init() + +samplerDescriptor->setSAddressMode(.Repeat) +samplerDescriptor->setTAddressMode(.Repeat) +samplerDescriptor->setRAddressMode(.Repeat) +samplerDescriptor->setMagFilter(.Linear) +samplerDescriptor->setMinFilter(.Linear) +samplerDescriptor->setMipFilter(.Linear) +samplerDescriptor->setSupportArgumentBuffers(true) + +samplerState := device->newSamplerState(samplerDescriptor) + +samplerDescriptor->release() + +// ... + +samplerState->release() +``` From 803648be894659409beb3c2b5e76b7b491ddf7c5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 15:34:07 +0000 Subject: [PATCH 0190/1052] Minor aesthetic clean ups of Foundation --- core/sys/darwin/Foundation/NSBundle.odin | 6 ------ core/sys/darwin/Foundation/NSDate.odin | 1 - core/sys/darwin/Foundation/NSDictionary.odin | 1 - core/sys/darwin/Foundation/NSNotification.odin | 1 - core/sys/darwin/Foundation/NSNumber.odin | 1 - core/sys/darwin/Foundation/NSString.odin | 6 +++--- core/sys/darwin/Foundation/NSURL.odin | 5 ++++- core/sys/darwin/Foundation/NSWindow.odin | 7 ------- 8 files changed, 7 insertions(+), 21 deletions(-) diff --git a/core/sys/darwin/Foundation/NSBundle.odin b/core/sys/darwin/Foundation/NSBundle.odin index 4f5a8e928..5e136378b 100644 --- a/core/sys/darwin/Foundation/NSBundle.odin +++ b/core/sys/darwin/Foundation/NSBundle.odin @@ -105,7 +105,6 @@ Bundle_sharedFrameworksURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "sharedFrameworksURL") } - @(objc_type=Bundle, objc_name="sharedSupportURL") Bundle_sharedSupportURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "sharedSupportURL") @@ -121,9 +120,6 @@ Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL { return msgSend(^URL, self, "appStoreReceiptURL") } - - - @(objc_type=Bundle, objc_name="bundlePath") Bundle_bundlePath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "bundlePath") @@ -154,7 +150,6 @@ Bundle_sharedFrameworksPath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "sharedFrameworksPath") } - @(objc_type=Bundle, objc_name="sharedSupportPath") Bundle_sharedSupportPath :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "sharedSupportPath") @@ -175,7 +170,6 @@ Bundle_bundleIdentifier :: proc(self: ^Bundle) -> ^String { return msgSend(^String, self, "bundleIdentifier") } - @(objc_type=Bundle, objc_name="infoDictionary") Bundle_infoDictionary :: proc(self: ^Bundle) -> ^Dictionary { return msgSend(^Dictionary, self, "infoDictionary") diff --git a/core/sys/darwin/Foundation/NSDate.odin b/core/sys/darwin/Foundation/NSDate.odin index cd63d313a..e30cb07d0 100644 --- a/core/sys/darwin/Foundation/NSDate.odin +++ b/core/sys/darwin/Foundation/NSDate.odin @@ -13,7 +13,6 @@ Date_init :: proc(self: ^Date) -> ^Date { return msgSend(^Date, self, "init") } - @(objc_type=Date, objc_name="dateWithTimeIntervalSinceNow") Date_dateWithTimeIntervalSinceNow :: proc(secs: TimeInterval) -> ^Date { return msgSend(^Date, Date, "dateWithTimeIntervalSinceNow:", secs) diff --git a/core/sys/darwin/Foundation/NSDictionary.odin b/core/sys/darwin/Foundation/NSDictionary.odin index 1f009841a..3832c05f1 100644 --- a/core/sys/darwin/Foundation/NSDictionary.odin +++ b/core/sys/darwin/Foundation/NSDictionary.odin @@ -29,7 +29,6 @@ Dictionary_init :: proc(self: ^Dictionary) -> ^Dictionary { return msgSend(^Dictionary, self, "init") } - @(objc_type=Dictionary, objc_name="initWithObjects") Dictionary_initWithObjects :: proc(self: ^Dictionary, objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { return msgSend(^Dictionary, self, "initWithObjects:forKeys:count", objects, forKeys, count) diff --git a/core/sys/darwin/Foundation/NSNotification.odin b/core/sys/darwin/Foundation/NSNotification.odin index 182d33896..ec8dddab7 100644 --- a/core/sys/darwin/Foundation/NSNotification.odin +++ b/core/sys/darwin/Foundation/NSNotification.odin @@ -14,7 +14,6 @@ Notification_init :: proc(self: ^Notification) -> ^Notification { return msgSend(^Notification, self, "init") } - @(objc_type=Notification, objc_name="name") Notification_name :: proc(self: ^Notification) -> ^String { return msgSend(^String, self, "name") diff --git a/core/sys/darwin/Foundation/NSNumber.odin b/core/sys/darwin/Foundation/NSNumber.odin index 4f7ef311b..016698805 100644 --- a/core/sys/darwin/Foundation/NSNumber.odin +++ b/core/sys/darwin/Foundation/NSNumber.odin @@ -63,7 +63,6 @@ Value_pointerValue :: proc(self: ^Value) -> rawptr { @(objc_class="NSNumber") Number :: struct{using _: Copying(Number), using _: Value} - @(objc_type=Number, objc_name="alloc", objc_is_class_method=true) Number_alloc :: proc() -> ^Number { return msgSend(^Number, Number, "alloc") diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin index ae1d6d43f..45b5df37b 100644 --- a/core/sys/darwin/Foundation/NSString.odin +++ b/core/sys/darwin/Foundation/NSString.odin @@ -49,12 +49,12 @@ StringCompareOption :: enum UInteger { unichar :: distinct u16 -foreign Foundation { - __CFStringMakeConstantString :: proc "c" (c: cstring) -> ^String --- -} AT :: MakeConstantString MakeConstantString :: proc "c" (#const c: cstring) -> ^String { + foreign Foundation { + __CFStringMakeConstantString :: proc "c" (c: cstring) -> ^String --- + } return __CFStringMakeConstantString(c) } diff --git a/core/sys/darwin/Foundation/NSURL.odin b/core/sys/darwin/Foundation/NSURL.odin index 9813b6e59..72e5fc906 100644 --- a/core/sys/darwin/Foundation/NSURL.odin +++ b/core/sys/darwin/Foundation/NSURL.odin @@ -14,14 +14,17 @@ URL_init :: proc(self: ^URL) -> ^URL { return msgSend(^URL, self, "init") } - +@(objc_type=URL, objc_name="initWithString") URL_initWithString :: proc(self: ^URL, value: ^String) -> ^URL { return msgSend(^URL, self, "initWithString:", value) } + +@(objc_type=URL, objc_name="initFileURLWithPath") URL_initFileURLWithPath :: proc(self: ^URL, path: ^String) -> ^URL { return msgSend(^URL, self, "initFileURLWithPath:", path) } +@(objc_type=URL, objc_name="fileSystemRepresentation") URL_fileSystemRepresentation :: proc(self: ^URL) -> ^String { return msgSend(^String, self, "fileSystemRepresentation") } \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin index e109284d1..df675cfeb 100644 --- a/core/sys/darwin/Foundation/NSWindow.odin +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -23,7 +23,6 @@ View :: struct {using _: Responder} View_layer :: proc(self: ^View) -> ^Layer { return msgSend(^Layer, self, "layer") } - @(objc_type=View, objc_name="setLayer") View_setLayer :: proc(self: ^View, layer: ^Layer) { msgSend(nil, self, "setLayer:", layer) @@ -32,13 +31,10 @@ View_setLayer :: proc(self: ^View, layer: ^Layer) { View_setSubLayer :: proc(self: ^View, layer: ^Layer) { msgSend(nil, self, "setSubLayer:", layer) } - - @(objc_type=View, objc_name="wantsLayer") View_wantsLayer :: proc(self: ^View) -> BOOL { return msgSend(BOOL, self, "wantsLayer") } - @(objc_type=View, objc_name="setWantsLayer") View_setWantsLayer :: proc(self: ^View, wantsLayer: BOOL) { msgSend(nil, self, "setWantsLayer:", wantsLayer) @@ -52,7 +48,6 @@ Window :: struct {using _: Responder} Window_contentView :: proc(self: ^Window) -> ^View { return msgSend(^View, self, "contentView") } - @(objc_type=Window, objc_name="frame") Window_frame :: proc(self: ^Window) -> Rect { return msgSend(Rect, self, "frame") @@ -61,7 +56,6 @@ Window_frame :: proc(self: ^Window) -> Rect { Window_setFrame :: proc(self: ^Window, frame: Rect) { msgSend(nil, self, "setFrame:", frame) } - @(objc_type=Window, objc_name="opaque") Window_opaque :: proc(self: ^Window) -> NS.BOOL { return msgSend(NS.BOOL, self, "opaque") @@ -70,7 +64,6 @@ Window_opaque :: proc(self: ^Window) -> NS.BOOL { Window_setOpaque :: proc(self: ^Window, ok: NS.BOOL) { msgSend(nil, self, "setOpaque:", ok) } - @(objc_type=Window, objc_name="backgroundColor") Window_backgroundColor :: proc(self: ^Window) -> ^NS.Color { return msgSend(^NS.Color, self, "backgroundColor") From 1d4d0a3e1a86c02d4da5708c8b4b96c31cce20c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 15:56:11 +0000 Subject: [PATCH 0191/1052] Strip unneeded semicolons --- core/sys/darwin/xnu_system_call_helpers.odin | 10 +-- core/sys/darwin/xnu_system_call_wrappers.odin | 66 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin index f9844a73f..5b060cfd3 100644 --- a/core/sys/darwin/xnu_system_call_helpers.odin +++ b/core/sys/darwin/xnu_system_call_helpers.odin @@ -72,7 +72,7 @@ PERMISSION_OTHER_ALL :: Permission{.PERMISSION_OTHER_READ, .PERMISSION_OTHER_WRI PERMISSION_ALL_ALL :: PERMISSION_OWNER_ALL | PERMISSION_GROUP_ALL | PERMISSION_OTHER_ALL _sys_permission_mode :: #force_inline proc (mode: Permission) -> u32 { - cflags: u32 = 0; + cflags: u32 = 0 cflags |= PERMISSION_MASK_IRUSR * u32(Permission.PERMISSION_OWNER_READ in mode) cflags |= PERMISSION_MASK_IWUSR * u32(Permission.PERMISSION_OWNER_WRITE in mode) @@ -89,9 +89,9 @@ _sys_permission_mode :: #force_inline proc (mode: Permission) -> u32 { sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, bool) { - cmode: u32 = 0; - cflags: u32 = 0; - cpath: cstring = strings.clone_to_cstring(path); + cmode: u32 = 0 + cflags: u32 = 0 + cpath: cstring = strings.clone_to_cstring(path) defer delete(cpath) cflags = _sys_permission_mode(mode) @@ -167,7 +167,7 @@ sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 { sys_chmod :: proc(path: string, mode: Permission) -> bool { cpath: cstring = strings.clone_to_cstring(path) defer delete(cpath) - cmode := _sys_permission_mode(mode); + cmode := _sys_permission_mode(mode) return syscall_chmod(cpath, cmode) != -1 } diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index 4cf86862f..4e4227f1f 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -10,10 +10,10 @@ LOCK_NB :: 4 /* don't block when locking */ LOCK_UN :: 8 /* unlock */ /* sys/unistd.h for access */ -F_OK :: c.int(0); /* test for existence of file */ -X_OK :: c.int((1 << 0)); /* test for execute or search permission */ -W_OK :: c.int((1 << 1)); /* test for write permission */ -R_OK :: c.int((1 << 2)); /* test for read permission */ +F_OK :: c.int(0) /* test for existence of file */ +X_OK :: c.int((1 << 0)) /* test for execute or search permission */ +W_OK :: c.int((1 << 1)) /* test for write permission */ +R_OK :: c.int((1 << 2)) /* test for read permission */ /* copyfile flags */ COPYFILE_ACL :: (1 << 0) @@ -26,37 +26,37 @@ COPYFILE_METADATA :: (COPYFILE_SECURITY | COPYFILE_XATTR) COPYFILE_ALL :: (COPYFILE_METADATA | COPYFILE_DATA) /* syslimits.h */ -PATH_MAX :: 1024; /* max bytes in pathname */ +PATH_MAX :: 1024 /* max bytes in pathname */ /* param.h */ -MAXPATHLEN :: PATH_MAX; +MAXPATHLEN :: PATH_MAX /* proc_info.h */ -DARWIN_PROC_PIDPATHINFO_SIZE :: MAXPATHLEN; -DARWIN_PROC_PIDPATHINFO :: 11; +DARWIN_PROC_PIDPATHINFO_SIZE :: MAXPATHLEN +DARWIN_PROC_PIDPATHINFO :: 11 -DARWIN_PROC_ALL_PIDS :: c.int(1); -DARWIN_PROC_PGRP_ONLY :: c.int(2); -DARWIN_PROC_TTY_ONLY :: c.int(3); -DARWIN_PROC_UID_ONLY :: c.int(4); -DARWIN_PROC_RUID_ONLY :: c.int(5); -DARWIN_PROC_PPID_ONLY :: c.int(6); -DARWIN_PROC_KDBG_ONLY :: c.int(7); +DARWIN_PROC_ALL_PIDS :: c.int(1) +DARWIN_PROC_PGRP_ONLY :: c.int(2) +DARWIN_PROC_TTY_ONLY :: c.int(3) +DARWIN_PROC_UID_ONLY :: c.int(4) +DARWIN_PROC_RUID_ONLY :: c.int(5) +DARWIN_PROC_PPID_ONLY :: c.int(6) +DARWIN_PROC_KDBG_ONLY :: c.int(7) -DARWIN_PROC_INFO_CALL_LISTPIDS :: c.int(0x1); -DARWIN_PROC_INFO_CALL_PIDINFO :: c.int(0x2); -DARWIN_PROC_INFO_CALL_PIDFDINFO :: c.int(0x3); -DARWIN_PROC_INFO_CALL_KERNMSGBUF :: c.int(0x4); -DARWIN_PROC_INFO_CALL_SETCONTROL :: c.int(0x5); -DARWIN_PROC_INFO_CALL_PIDFILEPORTINFO :: c.int(0x6); -DARWIN_PROC_INFO_CALL_TERMINATE :: c.int(0x7); -DARWIN_PROC_INFO_CALL_DIRTYCONTROL :: c.int(0x8); -DARWIN_PROC_INFO_CALL_PIDRUSAGE :: c.int(0x9); -DARWIN_PROC_INFO_CALL_PIDORIGINATORINFO :: c.int(0xa); -DARWIN_PROC_INFO_CALL_LISTCOALITIONS :: c.int(0xb); -DARWIN_PROC_INFO_CALL_CANUSEFGHW :: c.int(0xc); -DARWIN_PROC_INFO_CALL_PIDDYNKQUEUEINFO :: c.int(0xd); -DARWIN_PROC_INFO_CALL_UDATA_INFO :: c.int(0xe); +DARWIN_PROC_INFO_CALL_LISTPIDS :: c.int(0x1) +DARWIN_PROC_INFO_CALL_PIDINFO :: c.int(0x2) +DARWIN_PROC_INFO_CALL_PIDFDINFO :: c.int(0x3) +DARWIN_PROC_INFO_CALL_KERNMSGBUF :: c.int(0x4) +DARWIN_PROC_INFO_CALL_SETCONTROL :: c.int(0x5) +DARWIN_PROC_INFO_CALL_PIDFILEPORTINFO :: c.int(0x6) +DARWIN_PROC_INFO_CALL_TERMINATE :: c.int(0x7) +DARWIN_PROC_INFO_CALL_DIRTYCONTROL :: c.int(0x8) +DARWIN_PROC_INFO_CALL_PIDRUSAGE :: c.int(0x9) +DARWIN_PROC_INFO_CALL_PIDORIGINATORINFO :: c.int(0xa) +DARWIN_PROC_INFO_CALL_LISTCOALITIONS :: c.int(0xb) +DARWIN_PROC_INFO_CALL_CANUSEFGHW :: c.int(0xc) +DARWIN_PROC_INFO_CALL_PIDDYNKQUEUEINFO :: c.int(0xd) +DARWIN_PROC_INFO_CALL_UDATA_INFO :: c.int(0xe) /* mmap flags */ MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */ @@ -120,7 +120,7 @@ OPEN_FLAG_CLOEXEC :: 0x01000000 /* causes the descriptor to be closed if yo OPEN_FLAG_NOFOLLOW_ANY :: 0x20000000 /* no symlinks allowed in path */ /* bsd/sys/param.h */ -DARWIN_MAXCOMLEN :: 16; +DARWIN_MAXCOMLEN :: 16 /*--==========================================================================--*/ @@ -184,7 +184,7 @@ __DARWIN_STRUCT_STAT64 :: struct { _STRUCT_TIMEVAL :: struct { tv_sec: __darwin_time_t, /* seconds */ tv_usec: __darwin_suseconds_t, /* microseconds */ -}; +} /* pwd.h */ _Password_Entry :: struct { @@ -199,7 +199,7 @@ _Password_Entry :: struct { pw_shell: cstring, /* shell program */ pw_expire: u64, /* account expiration */ pw_fields: i32, /* filled fields */ -}; +} /* processinfo.h */ _Proc_Bsdinfo :: struct { @@ -225,7 +225,7 @@ _Proc_Bsdinfo :: struct { pbi_nice: i32, pbi_start_tvsec: u64, pbi_start_tvusec: u64, -}; +} /*--==========================================================================--*/ From 0380a288a9e7d5bb775abec00900488659d1c784 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 15:58:44 +0000 Subject: [PATCH 0192/1052] Minor fix for -vet --- examples/all/all_main.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index e38dd5150..e694060d2 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -119,6 +119,7 @@ _ :: bit_array _ :: priority_queue _ :: queue _ :: small_array +_ :: lru _ :: crypto _ :: blake _ :: blake2b From d695a8a52631aafcedeb2472c4d405c51547c651 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 16:02:14 +0000 Subject: [PATCH 0193/1052] Update os_darwin.odin --- core/os/os_darwin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 71c9fac38..a011fa58a 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -320,7 +320,7 @@ foreign libc { @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } -when ODIN_ARCH != "arm64" { +when ODIN_ARCH != .arm64 { _unix_fdopendir :: proc {_unix_fdopendir_amd64} _unix_readdir_r :: proc {_unix_readdir_r_amd64} } else { From 21864d8d51872b98dbb1ca3dd3d86d2cb0d8a364 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Feb 2022 16:25:28 +0000 Subject: [PATCH 0194/1052] Improve BAD ENUM VALUE message in fmt #1496 --- core/fmt/fmt.odin | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 932fc0bb8..360a00b32 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1065,11 +1065,13 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) { case 'i', 'd', 'f': fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, verb) case 's', 'v': - str, ok := enum_value_to_string(v) - if !ok { - str = "%!(BAD ENUM VALUE)" + if str, ok := enum_value_to_string(v); ok { + io.write_string(fi.writer, str) + } else { + io.write_string(fi.writer, "%!(BAD ENUM VALUE=") + fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, 'i') + io.write_string(fi.writer, ")") } - io.write_string(fi.writer, str) } } } From a3bcacee273f935350de9fa7ecb575c7e8356b99 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 00:06:25 +0000 Subject: [PATCH 0195/1052] Move Objective-C libraries located in `core:sys/darwin/*` to `vendor:darwin/*` --- {core/sys => vendor}/darwin/Foundation/NSArray.odin | 0 {core/sys => vendor}/darwin/Foundation/NSAutoreleasePool.odin | 0 {core/sys => vendor}/darwin/Foundation/NSBundle.odin | 0 {core/sys => vendor}/darwin/Foundation/NSData.odin | 0 {core/sys => vendor}/darwin/Foundation/NSDate.odin | 0 {core/sys => vendor}/darwin/Foundation/NSDictionary.odin | 0 {core/sys => vendor}/darwin/Foundation/NSEnumerator.odin | 0 {core/sys => vendor}/darwin/Foundation/NSError.odin | 0 {core/sys => vendor}/darwin/Foundation/NSLock.odin | 0 {core/sys => vendor}/darwin/Foundation/NSNotification.odin | 0 {core/sys => vendor}/darwin/Foundation/NSNumber.odin | 0 {core/sys => vendor}/darwin/Foundation/NSObject.odin | 0 {core/sys => vendor}/darwin/Foundation/NSRange.odin | 0 {core/sys => vendor}/darwin/Foundation/NSString.odin | 0 {core/sys => vendor}/darwin/Foundation/NSTypes.odin | 0 {core/sys => vendor}/darwin/Foundation/NSURL.odin | 0 {core/sys => vendor}/darwin/Foundation/NSWindow.odin | 0 {core/sys => vendor}/darwin/Metal/MetalClasses.odin | 0 {core/sys => vendor}/darwin/Metal/MetalEnums.odin | 0 {core/sys => vendor}/darwin/Metal/MetalErrors.odin | 0 {core/sys => vendor}/darwin/Metal/MetalProcedures.odin | 0 {core/sys => vendor}/darwin/Metal/MetalTypes.odin | 0 {core/sys => vendor}/darwin/Metal/README.md | 0 {core/sys => vendor}/darwin/QuartzCore/QuartzCore.odin | 0 24 files changed, 0 insertions(+), 0 deletions(-) rename {core/sys => vendor}/darwin/Foundation/NSArray.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSAutoreleasePool.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSBundle.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSData.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSDate.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSDictionary.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSEnumerator.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSError.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSLock.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSNotification.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSNumber.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSObject.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSRange.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSString.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSTypes.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSURL.odin (100%) rename {core/sys => vendor}/darwin/Foundation/NSWindow.odin (100%) rename {core/sys => vendor}/darwin/Metal/MetalClasses.odin (100%) rename {core/sys => vendor}/darwin/Metal/MetalEnums.odin (100%) rename {core/sys => vendor}/darwin/Metal/MetalErrors.odin (100%) rename {core/sys => vendor}/darwin/Metal/MetalProcedures.odin (100%) rename {core/sys => vendor}/darwin/Metal/MetalTypes.odin (100%) rename {core/sys => vendor}/darwin/Metal/README.md (100%) rename {core/sys => vendor}/darwin/QuartzCore/QuartzCore.odin (100%) diff --git a/core/sys/darwin/Foundation/NSArray.odin b/vendor/darwin/Foundation/NSArray.odin similarity index 100% rename from core/sys/darwin/Foundation/NSArray.odin rename to vendor/darwin/Foundation/NSArray.odin diff --git a/core/sys/darwin/Foundation/NSAutoreleasePool.odin b/vendor/darwin/Foundation/NSAutoreleasePool.odin similarity index 100% rename from core/sys/darwin/Foundation/NSAutoreleasePool.odin rename to vendor/darwin/Foundation/NSAutoreleasePool.odin diff --git a/core/sys/darwin/Foundation/NSBundle.odin b/vendor/darwin/Foundation/NSBundle.odin similarity index 100% rename from core/sys/darwin/Foundation/NSBundle.odin rename to vendor/darwin/Foundation/NSBundle.odin diff --git a/core/sys/darwin/Foundation/NSData.odin b/vendor/darwin/Foundation/NSData.odin similarity index 100% rename from core/sys/darwin/Foundation/NSData.odin rename to vendor/darwin/Foundation/NSData.odin diff --git a/core/sys/darwin/Foundation/NSDate.odin b/vendor/darwin/Foundation/NSDate.odin similarity index 100% rename from core/sys/darwin/Foundation/NSDate.odin rename to vendor/darwin/Foundation/NSDate.odin diff --git a/core/sys/darwin/Foundation/NSDictionary.odin b/vendor/darwin/Foundation/NSDictionary.odin similarity index 100% rename from core/sys/darwin/Foundation/NSDictionary.odin rename to vendor/darwin/Foundation/NSDictionary.odin diff --git a/core/sys/darwin/Foundation/NSEnumerator.odin b/vendor/darwin/Foundation/NSEnumerator.odin similarity index 100% rename from core/sys/darwin/Foundation/NSEnumerator.odin rename to vendor/darwin/Foundation/NSEnumerator.odin diff --git a/core/sys/darwin/Foundation/NSError.odin b/vendor/darwin/Foundation/NSError.odin similarity index 100% rename from core/sys/darwin/Foundation/NSError.odin rename to vendor/darwin/Foundation/NSError.odin diff --git a/core/sys/darwin/Foundation/NSLock.odin b/vendor/darwin/Foundation/NSLock.odin similarity index 100% rename from core/sys/darwin/Foundation/NSLock.odin rename to vendor/darwin/Foundation/NSLock.odin diff --git a/core/sys/darwin/Foundation/NSNotification.odin b/vendor/darwin/Foundation/NSNotification.odin similarity index 100% rename from core/sys/darwin/Foundation/NSNotification.odin rename to vendor/darwin/Foundation/NSNotification.odin diff --git a/core/sys/darwin/Foundation/NSNumber.odin b/vendor/darwin/Foundation/NSNumber.odin similarity index 100% rename from core/sys/darwin/Foundation/NSNumber.odin rename to vendor/darwin/Foundation/NSNumber.odin diff --git a/core/sys/darwin/Foundation/NSObject.odin b/vendor/darwin/Foundation/NSObject.odin similarity index 100% rename from core/sys/darwin/Foundation/NSObject.odin rename to vendor/darwin/Foundation/NSObject.odin diff --git a/core/sys/darwin/Foundation/NSRange.odin b/vendor/darwin/Foundation/NSRange.odin similarity index 100% rename from core/sys/darwin/Foundation/NSRange.odin rename to vendor/darwin/Foundation/NSRange.odin diff --git a/core/sys/darwin/Foundation/NSString.odin b/vendor/darwin/Foundation/NSString.odin similarity index 100% rename from core/sys/darwin/Foundation/NSString.odin rename to vendor/darwin/Foundation/NSString.odin diff --git a/core/sys/darwin/Foundation/NSTypes.odin b/vendor/darwin/Foundation/NSTypes.odin similarity index 100% rename from core/sys/darwin/Foundation/NSTypes.odin rename to vendor/darwin/Foundation/NSTypes.odin diff --git a/core/sys/darwin/Foundation/NSURL.odin b/vendor/darwin/Foundation/NSURL.odin similarity index 100% rename from core/sys/darwin/Foundation/NSURL.odin rename to vendor/darwin/Foundation/NSURL.odin diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/vendor/darwin/Foundation/NSWindow.odin similarity index 100% rename from core/sys/darwin/Foundation/NSWindow.odin rename to vendor/darwin/Foundation/NSWindow.odin diff --git a/core/sys/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin similarity index 100% rename from core/sys/darwin/Metal/MetalClasses.odin rename to vendor/darwin/Metal/MetalClasses.odin diff --git a/core/sys/darwin/Metal/MetalEnums.odin b/vendor/darwin/Metal/MetalEnums.odin similarity index 100% rename from core/sys/darwin/Metal/MetalEnums.odin rename to vendor/darwin/Metal/MetalEnums.odin diff --git a/core/sys/darwin/Metal/MetalErrors.odin b/vendor/darwin/Metal/MetalErrors.odin similarity index 100% rename from core/sys/darwin/Metal/MetalErrors.odin rename to vendor/darwin/Metal/MetalErrors.odin diff --git a/core/sys/darwin/Metal/MetalProcedures.odin b/vendor/darwin/Metal/MetalProcedures.odin similarity index 100% rename from core/sys/darwin/Metal/MetalProcedures.odin rename to vendor/darwin/Metal/MetalProcedures.odin diff --git a/core/sys/darwin/Metal/MetalTypes.odin b/vendor/darwin/Metal/MetalTypes.odin similarity index 100% rename from core/sys/darwin/Metal/MetalTypes.odin rename to vendor/darwin/Metal/MetalTypes.odin diff --git a/core/sys/darwin/Metal/README.md b/vendor/darwin/Metal/README.md similarity index 100% rename from core/sys/darwin/Metal/README.md rename to vendor/darwin/Metal/README.md diff --git a/core/sys/darwin/QuartzCore/QuartzCore.odin b/vendor/darwin/QuartzCore/QuartzCore.odin similarity index 100% rename from core/sys/darwin/QuartzCore/QuartzCore.odin rename to vendor/darwin/QuartzCore/QuartzCore.odin From d64e3b672ccd4f93162c0880fc59fcb9d5609bc8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 00:12:31 +0000 Subject: [PATCH 0196/1052] Add darwin build tags --- vendor/darwin/Foundation/NSArray.odin | 1 + vendor/darwin/Foundation/NSAutoreleasePool.odin | 1 + vendor/darwin/Foundation/NSBundle.odin | 1 + vendor/darwin/Foundation/NSData.odin | 1 + vendor/darwin/Foundation/NSDate.odin | 1 + vendor/darwin/Foundation/NSDictionary.odin | 1 + vendor/darwin/Foundation/NSEnumerator.odin | 1 + vendor/darwin/Foundation/NSError.odin | 1 + vendor/darwin/Foundation/NSLock.odin | 1 + vendor/darwin/Foundation/NSNotification.odin | 1 + vendor/darwin/Foundation/NSNumber.odin | 1 + vendor/darwin/Foundation/NSObject.odin | 1 + vendor/darwin/Foundation/NSRange.odin | 1 + vendor/darwin/Foundation/NSString.odin | 1 + vendor/darwin/Foundation/NSTypes.odin | 1 + vendor/darwin/Foundation/NSURL.odin | 1 + vendor/darwin/Foundation/NSWindow.odin | 1 + vendor/darwin/Metal/MetalClasses.odin | 1 + vendor/darwin/Metal/MetalEnums.odin | 1 + vendor/darwin/Metal/MetalErrors.odin | 1 + vendor/darwin/Metal/MetalProcedures.odin | 1 + vendor/darwin/Metal/MetalTypes.odin | 1 + vendor/darwin/QuartzCore/QuartzCore.odin | 1 + 23 files changed, 23 insertions(+) diff --git a/vendor/darwin/Foundation/NSArray.odin b/vendor/darwin/Foundation/NSArray.odin index d6021838b..4392c2791 100644 --- a/vendor/darwin/Foundation/NSArray.odin +++ b/vendor/darwin/Foundation/NSArray.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSAutoreleasePool.odin b/vendor/darwin/Foundation/NSAutoreleasePool.odin index a388a7146..f0157107e 100644 --- a/vendor/darwin/Foundation/NSAutoreleasePool.odin +++ b/vendor/darwin/Foundation/NSAutoreleasePool.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation @(objc_class="NSAutoreleasePool") diff --git a/vendor/darwin/Foundation/NSBundle.odin b/vendor/darwin/Foundation/NSBundle.odin index 5e136378b..2e9d0df83 100644 --- a/vendor/darwin/Foundation/NSBundle.odin +++ b/vendor/darwin/Foundation/NSBundle.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation @(objc_class="NSBundle") diff --git a/vendor/darwin/Foundation/NSData.odin b/vendor/darwin/Foundation/NSData.odin index 3c6369e86..b5367af07 100644 --- a/vendor/darwin/Foundation/NSData.odin +++ b/vendor/darwin/Foundation/NSData.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation @(objc_class="NSData") diff --git a/vendor/darwin/Foundation/NSDate.odin b/vendor/darwin/Foundation/NSDate.odin index e30cb07d0..5aef42c13 100644 --- a/vendor/darwin/Foundation/NSDate.odin +++ b/vendor/darwin/Foundation/NSDate.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation @(objc_class="NSDate") diff --git a/vendor/darwin/Foundation/NSDictionary.odin b/vendor/darwin/Foundation/NSDictionary.odin index 3832c05f1..54f2e3446 100644 --- a/vendor/darwin/Foundation/NSDictionary.odin +++ b/vendor/darwin/Foundation/NSDictionary.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation @(objc_class="NSDictionary") diff --git a/vendor/darwin/Foundation/NSEnumerator.odin b/vendor/darwin/Foundation/NSEnumerator.odin index 1c7ddeed2..0f1bdc482 100644 --- a/vendor/darwin/Foundation/NSEnumerator.odin +++ b/vendor/darwin/Foundation/NSEnumerator.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation import "core:c" diff --git a/vendor/darwin/Foundation/NSError.odin b/vendor/darwin/Foundation/NSError.odin index 23e6eaba7..868e6acc6 100644 --- a/vendor/darwin/Foundation/NSError.odin +++ b/vendor/darwin/Foundation/NSError.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation foreign import "system:Foundation.framework" diff --git a/vendor/darwin/Foundation/NSLock.odin b/vendor/darwin/Foundation/NSLock.odin index c48b5dbad..48c3a0e23 100644 --- a/vendor/darwin/Foundation/NSLock.odin +++ b/vendor/darwin/Foundation/NSLock.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation Locking :: struct($T: typeid) {using _: Object} diff --git a/vendor/darwin/Foundation/NSNotification.odin b/vendor/darwin/Foundation/NSNotification.odin index ec8dddab7..da9874bbc 100644 --- a/vendor/darwin/Foundation/NSNotification.odin +++ b/vendor/darwin/Foundation/NSNotification.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation @(objc_class="NSNotification") diff --git a/vendor/darwin/Foundation/NSNumber.odin b/vendor/darwin/Foundation/NSNumber.odin index 016698805..eb28b7099 100644 --- a/vendor/darwin/Foundation/NSNumber.odin +++ b/vendor/darwin/Foundation/NSNumber.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation import "core:c" diff --git a/vendor/darwin/Foundation/NSObject.odin b/vendor/darwin/Foundation/NSObject.odin index 55d87a14b..66cd5d617 100644 --- a/vendor/darwin/Foundation/NSObject.odin +++ b/vendor/darwin/Foundation/NSObject.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSRange.odin b/vendor/darwin/Foundation/NSRange.odin index 74ce595a3..48bce5f38 100644 --- a/vendor/darwin/Foundation/NSRange.odin +++ b/vendor/darwin/Foundation/NSRange.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation Range :: struct { diff --git a/vendor/darwin/Foundation/NSString.odin b/vendor/darwin/Foundation/NSString.odin index 45b5df37b..5807db2db 100644 --- a/vendor/darwin/Foundation/NSString.odin +++ b/vendor/darwin/Foundation/NSString.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation foreign import "system:Foundation.framework" diff --git a/vendor/darwin/Foundation/NSTypes.odin b/vendor/darwin/Foundation/NSTypes.odin index 47f75630f..2cb9000e9 100644 --- a/vendor/darwin/Foundation/NSTypes.odin +++ b/vendor/darwin/Foundation/NSTypes.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSURL.odin b/vendor/darwin/Foundation/NSURL.odin index 72e5fc906..995117a65 100644 --- a/vendor/darwin/Foundation/NSURL.odin +++ b/vendor/darwin/Foundation/NSURL.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation @(objc_class="NSURL") diff --git a/vendor/darwin/Foundation/NSWindow.odin b/vendor/darwin/Foundation/NSWindow.odin index df675cfeb..a2d043c49 100644 --- a/vendor/darwin/Foundation/NSWindow.odin +++ b/vendor/darwin/Foundation/NSWindow.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Foundation import NS "core:sys/darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index e5b6d0849..d931f7e4f 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Metal import NS "core:sys/darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalEnums.odin b/vendor/darwin/Metal/MetalEnums.odin index 47059ee66..cb0e4b415 100644 --- a/vendor/darwin/Metal/MetalEnums.odin +++ b/vendor/darwin/Metal/MetalEnums.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Metal import NS "core:sys/darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalErrors.odin b/vendor/darwin/Metal/MetalErrors.odin index 5909b35e4..c1b71cf2e 100644 --- a/vendor/darwin/Metal/MetalErrors.odin +++ b/vendor/darwin/Metal/MetalErrors.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Metal import NS "core:sys/darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalProcedures.odin b/vendor/darwin/Metal/MetalProcedures.odin index 6db5fe316..a8f29e4ac 100644 --- a/vendor/darwin/Metal/MetalProcedures.odin +++ b/vendor/darwin/Metal/MetalProcedures.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Metal import NS "core:sys/darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalTypes.odin b/vendor/darwin/Metal/MetalTypes.odin index 4928847a9..b1fef9fc1 100644 --- a/vendor/darwin/Metal/MetalTypes.odin +++ b/vendor/darwin/Metal/MetalTypes.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_Metal import NS "core:sys/darwin/Foundation" diff --git a/vendor/darwin/QuartzCore/QuartzCore.odin b/vendor/darwin/QuartzCore/QuartzCore.odin index c35453efc..a31c57fb6 100644 --- a/vendor/darwin/QuartzCore/QuartzCore.odin +++ b/vendor/darwin/QuartzCore/QuartzCore.odin @@ -1,3 +1,4 @@ +//+build darwin package objc_QuartzCore import NS "core:sys/darwin/Foundation" From 135091ddbee9f5df9c546c5331d85c90001b06df Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 00:14:16 +0000 Subject: [PATCH 0197/1052] Correct import paths --- vendor/darwin/Foundation/NSWindow.odin | 2 +- vendor/darwin/Metal/MetalClasses.odin | 3 ++- vendor/darwin/Metal/MetalEnums.odin | 2 +- vendor/darwin/Metal/MetalErrors.odin | 2 +- vendor/darwin/Metal/MetalProcedures.odin | 2 +- vendor/darwin/Metal/MetalTypes.odin | 2 +- vendor/darwin/QuartzCore/QuartzCore.odin | 4 ++-- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/vendor/darwin/Foundation/NSWindow.odin b/vendor/darwin/Foundation/NSWindow.odin index a2d043c49..654009bda 100644 --- a/vendor/darwin/Foundation/NSWindow.odin +++ b/vendor/darwin/Foundation/NSWindow.odin @@ -1,7 +1,7 @@ //+build darwin package objc_Foundation -import NS "core:sys/darwin/Foundation" +import NS "vendor:darwin/Foundation" Rect :: struct { x, y: f64, diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index d931f7e4f..4bc43002d 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -1,8 +1,9 @@ //+build darwin package objc_Metal -import NS "core:sys/darwin/Foundation" +import NS "vendor:darwin/Foundation" import "core:mem" +_ :: mem //////////////////////////////////////////////////////////////////////////////// diff --git a/vendor/darwin/Metal/MetalEnums.odin b/vendor/darwin/Metal/MetalEnums.odin index cb0e4b415..5cfa33558 100644 --- a/vendor/darwin/Metal/MetalEnums.odin +++ b/vendor/darwin/Metal/MetalEnums.odin @@ -1,7 +1,7 @@ //+build darwin package objc_Metal -import NS "core:sys/darwin/Foundation" +import NS "vendor:darwin/Foundation" AccelerationStructureUsage :: distinct bit_set[AccelerationStructureUsageFlag; NS.UInteger] AccelerationStructureUsageFlag :: enum NS.UInteger { diff --git a/vendor/darwin/Metal/MetalErrors.odin b/vendor/darwin/Metal/MetalErrors.odin index c1b71cf2e..da37b59ff 100644 --- a/vendor/darwin/Metal/MetalErrors.odin +++ b/vendor/darwin/Metal/MetalErrors.odin @@ -1,7 +1,7 @@ //+build darwin package objc_Metal -import NS "core:sys/darwin/Foundation" +import NS "vendor:darwin/Foundation" foreign import "system:Metal.framework" diff --git a/vendor/darwin/Metal/MetalProcedures.odin b/vendor/darwin/Metal/MetalProcedures.odin index a8f29e4ac..24ec2f8dd 100644 --- a/vendor/darwin/Metal/MetalProcedures.odin +++ b/vendor/darwin/Metal/MetalProcedures.odin @@ -1,7 +1,7 @@ //+build darwin package objc_Metal -import NS "core:sys/darwin/Foundation" +import NS "vendor:darwin/Foundation" @(require) foreign import "system:Metal.framework" diff --git a/vendor/darwin/Metal/MetalTypes.odin b/vendor/darwin/Metal/MetalTypes.odin index b1fef9fc1..1aabfa83e 100644 --- a/vendor/darwin/Metal/MetalTypes.odin +++ b/vendor/darwin/Metal/MetalTypes.odin @@ -1,7 +1,7 @@ //+build darwin package objc_Metal -import NS "core:sys/darwin/Foundation" +import NS "vendor:darwin/Foundation" import "core:intrinsics" BOOL :: NS.BOOL diff --git a/vendor/darwin/QuartzCore/QuartzCore.odin b/vendor/darwin/QuartzCore/QuartzCore.odin index a31c57fb6..7bcf216f1 100644 --- a/vendor/darwin/QuartzCore/QuartzCore.odin +++ b/vendor/darwin/QuartzCore/QuartzCore.odin @@ -1,8 +1,8 @@ //+build darwin package objc_QuartzCore -import NS "core:sys/darwin/Foundation" -import MTL "core:sys/darwin/Metal" +import NS "vendor:darwin/Foundation" +import MTL "vendor:darwin/Metal" import "core:intrinsics" @(private) From 0e69993d39e367a67911f361fde0ad2b58f6d4ea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 00:17:07 +0000 Subject: [PATCH 0198/1052] Add `init` and `copy` to all `Object`s --- vendor/darwin/Foundation/NSObject.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vendor/darwin/Foundation/NSObject.odin b/vendor/darwin/Foundation/NSObject.odin index 66cd5d617..33ef26a23 100644 --- a/vendor/darwin/Foundation/NSObject.odin +++ b/vendor/darwin/Foundation/NSObject.odin @@ -25,9 +25,11 @@ Copying :: struct($T: typeid) {using _: Object} alloc :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, T, "alloc") } +@(objc_type=Object, objc_name="init") init :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, self, "init") } +@(objc_type=Object, objc_name="copy") copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Object) { return msgSend(^T, self, "copy") } From 65dedbb1caaa785a444d32a7a15adaf6c396b07f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 11:54:15 +0000 Subject: [PATCH 0199/1052] Add `#subtype` struct field prefix, required to have a COM interface hierarchy --- src/check_expr.cpp | 3 +++ src/check_type.cpp | 18 ++++++++++++++++++ src/entity.cpp | 5 +++++ src/parser.cpp | 4 +++- src/parser.hpp | 3 ++- src/types.cpp | 12 ++++++------ 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7fb0e44f2..884f1bb9f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9774,6 +9774,9 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { if (f->flags&FieldFlag_const) { str = gb_string_appendc(str, "#const "); } + if (f->flags&FieldFlag_subtype) { + str = gb_string_appendc(str, "#subtype "); + } for_array(i, f->names) { Ast *name = f->names[i]; diff --git a/src/check_type.cpp b/src/check_type.cpp index 32340070e..7e0ad2bd9 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -144,6 +144,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice *fields } bool is_using = (p->flags&FieldFlag_using) != 0; + bool is_subtype = (p->flags&FieldFlag_subtype) != 0; for_array(j, p->names) { Ast *name = p->names[j]; @@ -158,6 +159,9 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice *fields Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index); add_entity(ctx, ctx->scope, name, field); field->Variable.field_group_index = field_group_index; + if (is_subtype) { + field->flags |= EntityFlag_Subtype; + } if (j == 0) { field->Variable.docs = docs; @@ -194,6 +198,20 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice *fields populate_using_entity_scope(ctx, node, p, type); } + + if (is_subtype && p->names.count > 0) { + Type *first_type = fields_array[fields_array.count-1]->type; + Type *t = base_type(type_deref(first_type)); + + if (!does_field_type_allow_using(t) && + p->names.count >= 1 && + p->names[0]->kind == Ast_Ident) { + Token name_token = p->names[0]->Ident.token; + gbString type_str = type_to_string(first_type); + error(name_token, "'subtype' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str); + gb_string_free(type_str); + } + } } *fields = slice_from_array(fields_array); diff --git a/src/entity.cpp b/src/entity.cpp index df8ee3faa..f5720293f 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -74,6 +74,7 @@ enum EntityFlag : u64 { EntityFlag_Test = 1ull<<30, EntityFlag_Init = 1ull<<31, + EntityFlag_Subtype = 1ull<<32, EntityFlag_CustomLinkName = 1ull<<40, EntityFlag_CustomLinkage_Internal = 1ull<<41, @@ -86,6 +87,10 @@ enum EntityFlag : u64 { EntityFlag_Overridden = 1ull<<63, }; +enum : u64 { + EntityFlags_IsSubtype = EntityFlag_Using|EntityFlag_Subtype, +}; + enum EntityState : u32 { EntityState_Unresolved = 0, EntityState_InProgress = 1, diff --git a/src/parser.cpp b/src/parser.cpp index 0914c77ca..b55d745f1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3504,12 +3504,13 @@ enum FieldPrefixKind : i32 { FieldPrefix_Unknown = -1, FieldPrefix_Invalid = 0, - FieldPrefix_using, + FieldPrefix_using, // implies #subtype FieldPrefix_const, FieldPrefix_no_alias, FieldPrefix_c_vararg, FieldPrefix_auto_cast, FieldPrefix_any_int, + FieldPrefix_subtype, // does not imply `using` semantics }; struct ParseFieldPrefixMapping { @@ -3526,6 +3527,7 @@ gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = { {str_lit("c_vararg"), Token_Hash, FieldPrefix_c_vararg, FieldFlag_c_vararg}, {str_lit("const"), Token_Hash, FieldPrefix_const, FieldFlag_const}, {str_lit("any_int"), Token_Hash, FieldPrefix_any_int, FieldFlag_any_int}, + {str_lit("subtype"), Token_Hash, FieldPrefix_subtype, FieldFlag_subtype}, }; diff --git a/src/parser.hpp b/src/parser.hpp index ff0df0382..fb84210b3 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -282,6 +282,7 @@ enum FieldFlag : u32 { FieldFlag_auto_cast = 1<<4, FieldFlag_const = 1<<5, FieldFlag_any_int = 1<<6, + FieldFlag_subtype = 1<<7, // Internal use by the parser only FieldFlag_Tags = 1<<10, @@ -289,7 +290,7 @@ enum FieldFlag : u32 { // Parameter List Restrictions FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int, - FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags, + FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags, }; enum StmtAllowFlag { diff --git a/src/types.cpp b/src/types.cpp index 78958146b..2c1e6162f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2334,7 +2334,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) { GB_ASSERT(is_type_struct(src) || is_type_union(src)); for_array(i, src->Struct.fields) { Entity *f = src->Struct.fields[i]; - if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) { + if (f->kind == Entity_Variable && f->flags & EntityFlags_IsSubtype) { if (are_types_identical(dst, f->type)) { return f->token.string; } @@ -2343,7 +2343,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) { return f->token.string; } } - if (is_type_struct(f->type)) { + if ((f->flags & EntityFlag_Using) != 0 && is_type_struct(f->type)) { String name = lookup_subtype_polymorphic_field(dst, f->type); if (name.len > 0) { return name; @@ -2489,9 +2489,9 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) { if (xf->token.string != yf->token.string) { return false; } - bool xf_is_using = (xf->flags&EntityFlag_Using) != 0; - bool yf_is_using = (yf->flags&EntityFlag_Using) != 0; - if (xf_is_using ^ yf_is_using) { + u64 xf_flags = (xf->flags&EntityFlags_IsSubtype); + u64 yf_flags = (yf->flags&EntityFlags_IsSubtype); + if (xf_flags != yf_flags) { return false; } } @@ -3813,7 +3813,7 @@ isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0 for_array(i, src->Struct.fields) { Entity *f = src->Struct.fields[i]; - if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) { + if (f->kind != Entity_Variable || (f->flags&EntityFlags_IsSubtype) == 0) { continue; } From 2213722776ae6f10bd4b11bee7d9d23f0a772458 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 12:37:22 +0000 Subject: [PATCH 0200/1052] Change debug declare to value --- src/llvm_backend_debug.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index f60096aad..1a2705988 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -962,7 +962,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); - LLVMDIBuilderInsertDeclareBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); + LLVMDIBuilderInsertDbgValueBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); } @@ -1026,12 +1026,12 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); if (LLVMIsAAllocaInst(instr)) { - LLVMDIBuilderInsertDeclareBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); + LLVMDIBuilderInsertDbgValueBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); } else { // NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block // The reason is that if the parameter is at index 0 and a pointer, there is not such things as an // instruction "before" it. - LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); + LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); } } From 0738822dda2a863322b752b91ce7a4e0ac95e6e7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 13:25:31 +0000 Subject: [PATCH 0201/1052] Change how parameter and variables are given debug values --- src/llvm_backend_debug.cpp | 18 +++++++----------- src/llvm_backend_opt.cpp | 2 +- src/llvm_backend_proc.cpp | 3 ++- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 1a2705988..88974bd24 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -958,11 +958,11 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T ); LLVMValueRef storage = ptr; - LLVMValueRef instr = ptr; + LLVMBasicBlockRef block = p->decl_block->block; LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); - LLVMDIBuilderInsertDbgValueBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); + LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); } @@ -1020,19 +1020,15 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T ); LLVMValueRef storage = ptr; - LLVMValueRef instr = ptr; LLVMBasicBlockRef block = p->decl_block->block; LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); - if (LLVMIsAAllocaInst(instr)) { - LLVMDIBuilderInsertDbgValueBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); - } else { - // NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block - // The reason is that if the parameter is at index 0 and a pointer, there is not such things as an - // instruction "before" it. - LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); - } + + // NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block + // The reason is that if the parameter is at index 0 and a pointer, there is not such things as an + // instruction "before" it. + LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); } diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 8f1c7ad59..d36bdec0b 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -56,7 +56,7 @@ LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data #endif void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) { - if (optimization_level == 0 && build_context.ODIN_DEBUG) { + if (false && optimization_level == 0 && build_context.ODIN_DEBUG) { LLVMAddMergedLoadStoreMotionPass(fpm); } else { LLVMAddPromoteMemoryToRegisterPass(fpm); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 2a0380605..61cba53bd 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -491,7 +491,8 @@ void lb_begin_procedure_body(lbProcedure *p) { lbValue ptr = lb_address_from_load_or_generate_local(p, param); GB_ASSERT(LLVMIsAAllocaInst(ptr.value)); lb_add_entity(p->module, e, ptr); - lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1); + // lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1); + lb_add_debug_param_variable(p, value, e->type, e->token, param_index+1); } } else if (arg_type->kind == lbArg_Indirect) { if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { From e011d812ca5df522f937a4e3866310c6a24fd6c4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 14:39:08 +0000 Subject: [PATCH 0202/1052] Improve debug information for direct procedure parmaters --- src/llvm_backend_debug.cpp | 5 ++--- src/llvm_backend_proc.cpp | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 88974bd24..0e86fbb59 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -966,7 +966,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T } -void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number) { +void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block) { if (p->debug_info == nullptr) { return; } @@ -1020,7 +1020,6 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T ); LLVMValueRef storage = ptr; - LLVMBasicBlockRef block = p->decl_block->block; LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); @@ -1028,7 +1027,7 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T // NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block // The reason is that if the parameter is at index 0 and a pointer, there is not such things as an // instruction "before" it. - LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); + LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 61cba53bd..ccb16ebe0 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -480,9 +480,8 @@ void lb_begin_procedure_body(lbProcedure *p) { } else if (arg_type->kind == lbArg_Direct) { if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { LLVMTypeRef param_type = lb_type(p->module, e->type); - LLVMValueRef value = LLVMGetParam(p->value, param_offset+param_index); - - value = OdinLLVMBuildTransmute(p, value, param_type); + LLVMValueRef original_value = LLVMGetParam(p->value, param_offset+param_index); + LLVMValueRef value = OdinLLVMBuildTransmute(p, original_value, param_type); lbValue param = {}; param.value = value; @@ -491,8 +490,16 @@ void lb_begin_procedure_body(lbProcedure *p) { lbValue ptr = lb_address_from_load_or_generate_local(p, param); GB_ASSERT(LLVMIsAAllocaInst(ptr.value)); lb_add_entity(p->module, e, ptr); - // lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1); - lb_add_debug_param_variable(p, value, e->type, e->token, param_index+1); + + lbBlock *block = p->decl_block; + if (original_value != value) { + block = p->curr_block; + } + LLVMValueRef debug_storage_value = value; + if (original_value != value && LLVMIsALoadInst(value)) { + debug_storage_value = ptr.value; + } + lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block); } } else if (arg_type->kind == lbArg_Indirect) { if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { @@ -500,7 +507,7 @@ void lb_begin_procedure_body(lbProcedure *p) { ptr.value = LLVMGetParam(p->value, param_offset+param_index); ptr.type = alloc_type_pointer(e->type); lb_add_entity(p->module, e, ptr); - lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1); + lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block); } } } From 1857bc7b02eec221bc0d89a4702b9c8c5e003e3f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 14:51:54 +0000 Subject: [PATCH 0203/1052] Improve slice bounds checking runtime error messages --- core/runtime/error_checks.odin | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index ed75cbea6..14d55c64c 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -25,7 +25,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Index ") print_i64(i64(index)) - print_string(" is out of bounds range 0:") + print_string(" is out of range 0..<") print_i64(i64(count)) print_byte('\n') bounds_trap() @@ -35,11 +35,11 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid slice indices: ") + print_string(" Invalid slice indices ") print_i64(i64(lo)) print_string(":") print_i64(i64(hi)) - print_string(":") + print_string(" is out of range 0..<") print_i64(i64(len)) print_byte('\n') bounds_trap() @@ -47,7 +47,7 @@ slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, h multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid slice indices: ") + print_string(" Invalid slice indices ") print_i64(i64(lo)) print_string(":") print_i64(i64(hi)) @@ -83,11 +83,11 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, } handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid dynamic array values: ") + print_string(" Invalid dynamic array indices ") print_i64(i64(low)) print_string(":") print_i64(i64(high)) - print_string(":") + print_string(" is out of range 0..<") print_i64(i64(max)) print_byte('\n') bounds_trap() @@ -107,7 +107,7 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32 print_i64(i64(row_index)) print_string(", ") print_i64(i64(column_index)) - print_string(" is out of bounds range [0..<") + print_string(" is out of range [0..<") print_i64(i64(row_count)) print_string(", 0..<") print_i64(i64(column_count)) From 42ad54c28ee013618c7ee0039bbe1ce5dd1f0ba6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 15:18:22 +0000 Subject: [PATCH 0204/1052] Improve metadata for `context` --- src/llvm_backend_debug.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 0e86fbb59..ff1c5c7dc 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -1050,5 +1050,10 @@ void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) { token.string = str_lit("context"); token.pos = pos; - lb_add_debug_local_variable(p, ctx.addr.value, t_context, token); + LLVMValueRef ptr = ctx.addr.value; + while (LLVMIsABitCastInst(ptr)) { + ptr = LLVMGetOperand(ptr, 0); + } + + lb_add_debug_local_variable(p, ptr, t_context, token); } From db6bd9b358f17c0259ff5fe6411ce93407613338 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 16:03:49 +0000 Subject: [PATCH 0205/1052] Allow sysv and win64 calling conventions to be used on any platform on amd64 --- core/runtime/core.odin | 5 +++++ src/check_type.cpp | 19 +++++++++++++++++++ src/docs_writer.cpp | 35 +---------------------------------- src/llvm_abi.cpp | 6 ++++++ src/llvm_backend.hpp | 4 ++++ src/llvm_backend_proc.cpp | 2 +- src/parser.cpp | 6 ++++++ src/parser.hpp | 18 ++++++++++++++++++ 8 files changed, 60 insertions(+), 35 deletions(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index fec51f236..229d70417 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -33,6 +33,11 @@ Calling_Convention :: enum u8 { None = 6, Naked = 7, + + _ = 8, // reserved + + Win64 = 9, + SysV = 10, } Type_Info_Enum_Value :: distinct i64 diff --git a/src/check_type.cpp b/src/check_type.cpp index 32340070e..a11f5234b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1910,6 +1910,25 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, c->scope->flags &= ~ScopeFlag_ContextDefined; } + TargetArchKind arch = build_context.metrics.arch; + switch (cc) { + case ProcCC_StdCall: + case ProcCC_FastCall: + if (arch != TargetArch_i386 || arch != TargetArch_amd64) { + error(proc_type_node, "Invalid procedure calling convention \"%s\" for target architecture, expected either i386 or amd64, got %.*s", + proc_calling_convention_strings[cc], LIT(target_arch_names[arch])); + } + break; + case ProcCC_Win64: + case ProcCC_SysV: + if (arch != TargetArch_amd64) { + error(proc_type_node, "Invalid procedure calling convention \"%s\" for target architecture, expected amd64, got %.*s", + proc_calling_convention_strings[cc], LIT(target_arch_names[arch])); + } + break; + } + + bool variadic = false; isize variadic_index = -1; bool success = true; diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 0474ce8ff..2c5186c39 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -683,40 +683,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { types[1] = odin_doc_type(w, type->Proc.results); doc_type.types = odin_write_slice(w, types, gb_count_of(types)); - String calling_convention = {}; - switch (type->Proc.calling_convention) { - case ProcCC_Invalid: - // no need - break; - case ProcCC_Odin: - if (default_calling_convention() != ProcCC_Odin) { - calling_convention = str_lit("odin"); - } - break; - case ProcCC_Contextless: - if (default_calling_convention() != ProcCC_Contextless) { - calling_convention = str_lit("contextless"); - } - break; - case ProcCC_CDecl: - calling_convention = str_lit("cdecl"); - break; - case ProcCC_StdCall: - calling_convention = str_lit("stdcall"); - break; - case ProcCC_FastCall: - calling_convention = str_lit("fastcall"); - break; - case ProcCC_None: - calling_convention = str_lit("none"); - break; - case ProcCC_Naked: - calling_convention = str_lit("naked"); - break; - case ProcCC_InlineAsm: - calling_convention = str_lit("inline-assembly"); - break; - } + String calling_convention = make_string_c(proc_calling_convention_strings[type->Proc.calling_convention]); doc_type.calling_convention = odin_doc_write_string(w, calling_convention); } break; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 310df6639..0244b73d6 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1184,6 +1184,12 @@ LB_ABI_INFO(lb_get_abi_info) { ft->calling_convention = calling_convention; return ft; } + case ProcCC_Win64: + GB_ASSERT(build_context.metrics.arch == TargetArch_amd64); + return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + case ProcCC_SysV: + GB_ASSERT(build_context.metrics.arch == TargetArch_amd64); + return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } switch (build_context.metrics.arch) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 087cda22a..f2bcfaff6 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -548,6 +548,10 @@ lbCallingConventionKind const lb_calling_convention_map[ProcCC_MAX] = { lbCallingConvention_C, // ProcCC_None, lbCallingConvention_C, // ProcCC_Naked, lbCallingConvention_C, // ProcCC_InlineAsm, + + lbCallingConvention_Win64, // ProcCC_Win64, + lbCallingConvention_X86_64_SysV, // ProcCC_SysV, + }; enum : LLVMDWARFTypeEncoding { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ccb16ebe0..261e2819c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -497,7 +497,7 @@ void lb_begin_procedure_body(lbProcedure *p) { } LLVMValueRef debug_storage_value = value; if (original_value != value && LLVMIsALoadInst(value)) { - debug_storage_value = ptr.value; + debug_storage_value = LLVMGetOperand(value, 0); } lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block); } diff --git a/src/parser.cpp b/src/parser.cpp index 0914c77ca..bd0e55b7f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3412,12 +3412,18 @@ ProcCallingConvention string_to_calling_convention(String s) { if (s == "fast") return ProcCC_FastCall; if (s == "none") return ProcCC_None; if (s == "naked") return ProcCC_Naked; + + if (s == "win64") return ProcCC_Win64; + if (s == "sysv") return ProcCC_SysV; + if (s == "system") { if (build_context.metrics.os == TargetOs_windows) { return ProcCC_StdCall; } return ProcCC_CDecl; } + + return ProcCC_Invalid; } diff --git a/src/parser.hpp b/src/parser.hpp index ff0df0382..9e93f4b26 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -249,12 +249,30 @@ enum ProcCallingConvention : i32 { ProcCC_InlineAsm = 8, + ProcCC_Win64 = 9, + ProcCC_SysV = 10, + + ProcCC_MAX, ProcCC_ForeignBlockDefault = -1, }; +char const *proc_calling_convention_strings[ProcCC_MAX] = { + "", + "odin", + "contextless", + "cdecl", + "stdcall", + "fastcall", + "none", + "naked", + "inlineasm", + "win64", + "sysv", +}; + ProcCallingConvention default_calling_convention(void) { return ProcCC_Odin; } From 459ea5f4f6bbd30b02eacb330d2e6c72392c69a6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 16:05:28 +0000 Subject: [PATCH 0206/1052] Fix typo --- src/check_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index a11f5234b..976bb7f42 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1914,7 +1914,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, switch (cc) { case ProcCC_StdCall: case ProcCC_FastCall: - if (arch != TargetArch_i386 || arch != TargetArch_amd64) { + if (arch != TargetArch_i386 && arch != TargetArch_amd64) { error(proc_type_node, "Invalid procedure calling convention \"%s\" for target architecture, expected either i386 or amd64, got %.*s", proc_calling_convention_strings[cc], LIT(target_arch_names[arch])); } From 536bf61323230eddbeb4f36266b24e4b29425d1d Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 16 Feb 2022 08:14:11 -0800 Subject: [PATCH 0207/1052] avoid memset on stats --- core/os/os_linux.odin | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index dfb4b7948..140b84d8a 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -611,7 +611,8 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { cstr := strings.clone_to_cstring(path) defer delete(cstr) - s: OS_Stat + // deliberately uninitialized; the syscall fills this buffer for us + s: OS_Stat = --- result := _unix_stat(cstr, &s) if result < 0 { return s, _get_errno(result) @@ -624,7 +625,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { cstr := strings.clone_to_cstring(path) defer delete(cstr) - s: OS_Stat + // deliberately uninitialized; the syscall fills this buffer for us + s: OS_Stat = --- result := _unix_lstat(cstr, &s) if result < 0 { return s, _get_errno(result) @@ -634,7 +636,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { @private _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { - s: OS_Stat + // deliberately uninitialized; the syscall fills this buffer for us + s: OS_Stat = --- result := _unix_fstat(fd, &s) if result < 0 { return s, _get_errno(result) From 002ac6a1b793c44f0459b2be0851b29ddabc8df3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Feb 2022 21:26:34 +0000 Subject: [PATCH 0208/1052] Add `vendor:directx` packages: `dxgi`, `d3d11`, and `d3d12` TODO: enums marked with `bit_set` may need conversions --- core/sys/windows/types.odin | 3 + vendor/directx/d3d11/d3d11.odin | 3584 ++++++++++++ vendor/directx/d3d12/d3d12.odin | 5102 +++++++++++++++++ vendor/directx/d3d12/d3d12_constants.odin | 531 ++ vendor/directx/d3d_compiler/d3d_compiler.odin | 224 + .../directx/d3d_compiler/d3dcompiler_47.dll | Bin 0 -> 4410176 bytes .../directx/d3d_compiler/d3dcompiler_47.lib | Bin 0 -> 8512 bytes vendor/directx/dxgi/dxgi.odin | 1125 ++++ 8 files changed, 10569 insertions(+) create mode 100644 vendor/directx/d3d11/d3d11.odin create mode 100644 vendor/directx/d3d12/d3d12.odin create mode 100644 vendor/directx/d3d12/d3d12_constants.odin create mode 100644 vendor/directx/d3d_compiler/d3d_compiler.odin create mode 100644 vendor/directx/d3d_compiler/d3dcompiler_47.dll create mode 100644 vendor/directx/d3d_compiler/d3dcompiler_47.lib create mode 100644 vendor/directx/dxgi/dxgi.odin diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 3e25a4c18..1407201d6 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -376,6 +376,9 @@ FILE_TYPE_DISK :: 0x0001 FILE_TYPE_CHAR :: 0x0002 FILE_TYPE_PIPE :: 0x0003 +RECT :: struct {left, top, right, bottom: LONG} +POINT :: struct {x, y: LONG} + when size_of(uintptr) == 4 { WSADATA :: struct { diff --git a/vendor/directx/d3d11/d3d11.odin b/vendor/directx/d3d11/d3d11.odin new file mode 100644 index 000000000..668d8b9cb --- /dev/null +++ b/vendor/directx/d3d11/d3d11.odin @@ -0,0 +1,3584 @@ +package directx_d3d11 + +foreign import "system:d3d11.lib" + +import "../dxgi" +import "../d3d_compiler" + +IUnknown :: dxgi.IUnknown +IUnknown_VTable :: dxgi.IUnknown_VTable + +HANDLE :: dxgi.HANDLE +HMODULE :: dxgi.HMODULE +HRESULT :: dxgi.HRESULT +GUID :: dxgi.GUID +IID :: dxgi.IID +SIZE_T :: dxgi.SIZE_T +BOOL :: dxgi.BOOL + +RECT :: dxgi.RECT +SIZE :: dxgi.SIZE + +IModuleInstance :: d3d_compiler.ID3D11ModuleInstance +IBlob :: d3d_compiler.ID3DBlob +IModule :: d3d_compiler.ID3D11Module + +@(default_calling_convention="stdcall", link_prefix="D3D11") +foreign d3d11 { + CreateDevice :: proc( + pAdapter: ^dxgi.IAdapter, + DriverType: DRIVER_TYPE, + Software: HMODULE, + Flags: CREATE_DEVICE_FLAG, + pFeatureLevels: ^FEATURE_LEVEL, + FeatureLevels: u32, + SDKVersion: u32, + ppDevice: ^^IDevice, + pFeatureLevel: ^FEATURE_LEVEL, + ppImmediateContext: ^^IDeviceContext, + ) -> HRESULT --- + CreateDeviceAndSwapChain :: proc( + pAdapter: ^dxgi.IAdapter, + DriverType: DRIVER_TYPE, + Software: HMODULE, + Flags: u32, + pFeatureLevels: ^FEATURE_LEVEL, + FeatureLevels: u32, + SDKVersion: u32, + pSwapChainDesc: ^dxgi.SWAP_CHAIN_DESC, + ppSwapChain: ^^dxgi.ISwapChain, + ppDevice: ^^IDevice, + pFeatureLevel: ^FEATURE_LEVEL, + ppImmediateContext: ^^IDeviceContext, + ) -> HRESULT --- +} + +foreign d3d11 { + WKPDID_D3DDebugObjectNameW: GUID + WKPDID_CommentStringW: GUID +} + +@(link_prefix="D3D_") +foreign d3d11 { + TEXTURE_LAYOUT_ROW_MAJOR: GUID + TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE: GUID +} + +@(link_prefix="D3D11_") +foreign d3d11 { + DECODER_PROFILE_MPEG2_MOCOMP: GUID + DECODER_PROFILE_MPEG2_IDCT: GUID + DECODER_PROFILE_MPEG2_VLD: GUID + DECODER_PROFILE_MPEG1_VLD: GUID + DECODER_PROFILE_MPEG2and1_VLD: GUID + DECODER_PROFILE_H264_MOCOMP_NOFGT: GUID + DECODER_PROFILE_H264_MOCOMP_FGT: GUID + DECODER_PROFILE_H264_IDCT_NOFGT: GUID + DECODER_PROFILE_H264_IDCT_FGT: GUID + DECODER_PROFILE_H264_VLD_NOFGT: GUID + DECODER_PROFILE_H264_VLD_FGT: GUID + DECODER_PROFILE_H264_VLD_WITHFMOASO_NOFGT: GUID + DECODER_PROFILE_H264_VLD_STEREO_PROGRESSIVE_NOFGT: GUID + DECODER_PROFILE_H264_VLD_STEREO_NOFGT: GUID + DECODER_PROFILE_H264_VLD_MULTIVIEW_NOFGT: GUID + DECODER_PROFILE_WMV8_POSTPROC: GUID + DECODER_PROFILE_WMV8_MOCOMP: GUID + DECODER_PROFILE_WMV9_POSTPROC: GUID + DECODER_PROFILE_WMV9_MOCOMP: GUID + DECODER_PROFILE_WMV9_IDCT: GUID + DECODER_PROFILE_VC1_POSTPROC: GUID + DECODER_PROFILE_VC1_MOCOMP: GUID + DECODER_PROFILE_VC1_IDCT: GUID + DECODER_PROFILE_VC1_VLD: GUID + DECODER_PROFILE_VC1_D2010: GUID + DECODER_PROFILE_MPEG4PT2_VLD_SIMPLE: GUID + DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_NOGMC: GUID + DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_GMC: GUID + DECODER_PROFILE_HEVC_VLD_MAIN: GUID + DECODER_PROFILE_HEVC_VLD_MAIN10: GUID + DECODER_PROFILE_VP9_VLD_PROFILE0: GUID + DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2: GUID + DECODER_PROFILE_VP8_VLD: GUID + + CRYPTO_TYPE_AES128_CTR: GUID + DECODER_ENCRYPTION_HW_CENC: GUID + DECODER_BITSTREAM_ENCRYPTION_TYPE_CENC: GUID + DECODER_BITSTREAM_ENCRYPTION_TYPE_CBCS: GUID + KEY_EXCHANGE_HW_PROTECTION: GUID + + AUTHENTICATED_QUERY_PROTECTION: GUID + AUTHENTICATED_QUERY_CHANNEL_TYPE: GUID + AUTHENTICATED_QUERY_DEVICE_HANDLE: GUID + AUTHENTICATED_QUERY_CRYPTO_SESSION: GUID + AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_COUNT: GUID + AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS: GUID + AUTHENTICATED_QUERY_UNRESTRICTED_PROTECTED_SHARED_RESOURCE_COUNT: GUID + AUTHENTICATED_QUERY_OUTPUT_ID_COUNT: GUID + AUTHENTICATED_QUERY_OUTPUT_ID: GUID + AUTHENTICATED_QUERY_ACCESSIBILITY_ATTRIBUTES: GUID + AUTHENTICATED_QUERY_ENCRYPTION_WHEN_ACCESSIBLE_GUID_COUNT: GUID + AUTHENTICATED_QUERY_ENCRYPTION_WHEN_ACCESSIBLE_GUID: GUID + AUTHENTICATED_QUERY_CURRENT_ENCRYPTION_WHEN_ACCESSIBLE: GUID + AUTHENTICATED_CONFIGURE_INITIALIZE: GUID + AUTHENTICATED_CONFIGURE_PROTECTION: GUID + AUTHENTICATED_CONFIGURE_CRYPTO_SESSION: GUID + AUTHENTICATED_CONFIGURE_SHARED_RESOURCE: GUID + AUTHENTICATED_CONFIGURE_ENCRYPTION_WHEN_ACCESSIBLE: GUID + + KEY_EXCHANGE_RSAES_OAEP: GUID +} + +FL9_1_REQ_TEXTURE1D_U_DIMENSION :: 2048 +FL9_3_REQ_TEXTURE1D_U_DIMENSION :: 4096 +FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 2048 +FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 4096 +FL9_1_REQ_TEXTURECUBE_DIMENSION :: 512 +FL9_3_REQ_TEXTURECUBE_DIMENSION :: 4096 +FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 256 +FL9_1_DEFAULT_MAX_ANISOTROPY :: 2 +FL9_1_IA_PRIMITIVE_MAX_COUNT :: 65535 +FL9_2_IA_PRIMITIVE_MAX_COUNT :: 1048575 +FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT :: 1 +FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT :: 4 +FL9_1_MAX_TEXTURE_REPEAT :: 128 +FL9_2_MAX_TEXTURE_REPEAT :: 2048 +FL9_3_MAX_TEXTURE_REPEAT :: 8192 + +_8BIT_INDEX_STRIP_CUT_VALUE :: 0xff +_16BIT_INDEX_STRIP_CUT_VALUE :: 0xffff +_32BIT_INDEX_STRIP_CUT_VALUE :: 0xffffffff + +ARRAY_AXIS_ADDRESS_RANGE_BIT_COUNT :: 9 + +CLIP_OR_CULL_DISTANCE_COUNT :: 8 +CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT :: 2 + +COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT :: 14 +COMMONSHADER_CONSTANT_BUFFER_COMPONENTS :: 4 +COMMONSHADER_CONSTANT_BUFFER_COMPONENT_BIT_COUNT :: 32 +COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT :: 15 +COMMONSHADER_CONSTANT_BUFFER_PARTIAL_UPDATE_EXTENTS_BYTE_ALIGNMENT :: 16 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT :: 15 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 +COMMONSHADER_FLOWCONTROL_NESTING_LIMIT :: 64 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COUNT :: 1 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 +COMMONSHADER_IMMEDIATE_VALUE_COMPONENT_BIT_COUNT :: 32 +COMMONSHADER_INPUT_RESOURCE_REGISTER_COMPONENTS :: 1 +COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT :: 128 +COMMONSHADER_INPUT_RESOURCE_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_INPUT_RESOURCE_REGISTER_READ_PORTS :: 1 +COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT :: 128 +COMMONSHADER_SAMPLER_REGISTER_COMPONENTS :: 1 +COMMONSHADER_SAMPLER_REGISTER_COUNT :: 16 +COMMONSHADER_SAMPLER_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_SAMPLER_REGISTER_READ_PORTS :: 1 +COMMONSHADER_SAMPLER_SLOT_COUNT :: 16 +COMMONSHADER_SUBROUTINE_NESTING_LIMIT :: 32 +COMMONSHADER_TEMP_REGISTER_COMPONENTS :: 4 +COMMONSHADER_TEMP_REGISTER_COMPONENT_BIT_COUNT :: 32 +COMMONSHADER_TEMP_REGISTER_COUNT :: 4096 +COMMONSHADER_TEMP_REGISTER_READS_PER_INST :: 3 +COMMONSHADER_TEMP_REGISTER_READ_PORTS :: 3 +COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MAX :: 10 +COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MIN :: -10 +COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE :: -8 +COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE :: 7 + +CS_4_X_BUCKET00_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 256 +CS_4_X_BUCKET00_MAX_NUM_THREADS_PER_GROUP :: 64 +CS_4_X_BUCKET01_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 240 +CS_4_X_BUCKET01_MAX_NUM_THREADS_PER_GROUP :: 68 +CS_4_X_BUCKET02_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 224 +CS_4_X_BUCKET02_MAX_NUM_THREADS_PER_GROUP :: 72 +CS_4_X_BUCKET03_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 208 +CS_4_X_BUCKET03_MAX_NUM_THREADS_PER_GROUP :: 76 +CS_4_X_BUCKET04_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 192 +CS_4_X_BUCKET04_MAX_NUM_THREADS_PER_GROUP :: 84 +CS_4_X_BUCKET05_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 176 +CS_4_X_BUCKET05_MAX_NUM_THREADS_PER_GROUP :: 92 +CS_4_X_BUCKET06_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 160 +CS_4_X_BUCKET06_MAX_NUM_THREADS_PER_GROUP :: 100 +CS_4_X_BUCKET07_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 144 +CS_4_X_BUCKET07_MAX_NUM_THREADS_PER_GROUP :: 112 +CS_4_X_BUCKET08_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 128 +CS_4_X_BUCKET08_MAX_NUM_THREADS_PER_GROUP :: 128 +CS_4_X_BUCKET09_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 112 +CS_4_X_BUCKET09_MAX_NUM_THREADS_PER_GROUP :: 144 +CS_4_X_BUCKET10_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 96 +CS_4_X_BUCKET10_MAX_NUM_THREADS_PER_GROUP :: 168 +CS_4_X_BUCKET11_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 80 +CS_4_X_BUCKET11_MAX_NUM_THREADS_PER_GROUP :: 204 +CS_4_X_BUCKET12_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 64 +CS_4_X_BUCKET12_MAX_NUM_THREADS_PER_GROUP :: 256 +CS_4_X_BUCKET13_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 48 +CS_4_X_BUCKET13_MAX_NUM_THREADS_PER_GROUP :: 340 +CS_4_X_BUCKET14_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 32 +CS_4_X_BUCKET14_MAX_NUM_THREADS_PER_GROUP :: 512 +CS_4_X_BUCKET15_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 16 +CS_4_X_BUCKET15_MAX_NUM_THREADS_PER_GROUP :: 768 +CS_4_X_DISPATCH_MAX_THREAD_GROUPS_IN_Z_DIMENSION :: 1 +CS_4_X_RAW_UAV_BYTE_ALIGNMENT :: 256 +CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 768 +CS_4_X_THREAD_GROUP_MAX_X :: 768 +CS_4_X_THREAD_GROUP_MAX_Y :: 768 +CS_4_X_UAV_REGISTER_COUNT :: 1 + +CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION :: 65535 +CS_TGSM_REGISTER_COUNT :: 8192 +CS_TGSM_REGISTER_READS_PER_INST :: 1 +CS_TGSM_RESOURCE_REGISTER_COMPONENTS :: 1 +CS_TGSM_RESOURCE_REGISTER_READ_PORTS :: 1 +CS_THREADGROUPID_REGISTER_COMPONENTS :: 3 +CS_THREADGROUPID_REGISTER_COUNT :: 1 +CS_THREADIDINGROUPFLATTENED_REGISTER_COMPONENTS :: 1 +CS_THREADIDINGROUPFLATTENED_REGISTER_COUNT :: 1 +CS_THREADIDINGROUP_REGISTER_COMPONENTS :: 3 +CS_THREADIDINGROUP_REGISTER_COUNT :: 1 +CS_THREADID_REGISTER_COMPONENTS :: 3 +CS_THREADID_REGISTER_COUNT :: 1 +CS_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 1024 +CS_THREAD_GROUP_MAX_X :: 1024 +CS_THREAD_GROUP_MAX_Y :: 1024 +CS_THREAD_GROUP_MAX_Z :: 64 +CS_THREAD_GROUP_MIN_X :: 1 +CS_THREAD_GROUP_MIN_Y :: 1 +CS_THREAD_GROUP_MIN_Z :: 1 +CS_THREAD_LOCAL_TEMP_REGISTER_POOL :: 16384 + +DEFAULT_BLEND_FACTOR_ALPHA :: 1.0 +DEFAULT_BLEND_FACTOR_BLUE :: 1.0 +DEFAULT_BLEND_FACTOR_GREEN :: 1.0 +DEFAULT_BLEND_FACTOR_RED :: 1.0 +DEFAULT_BORDER_COLOR_COMPONENT :: 0.0 +DEFAULT_DEPTH_BIAS :: 0 +DEFAULT_DEPTH_BIAS_CLAMP :: 0.0 +DEFAULT_MAX_ANISOTROPY :: 16 +DEFAULT_MIP_LOD_BIAS :: 0.0 +DEFAULT_RENDER_TARGET_ARRAY_INDEX :: 0 +DEFAULT_SAMPLE_MASK :: 0xffffffff +DEFAULT_SCISSOR_ENDX :: 0 +DEFAULT_SCISSOR_ENDY :: 0 +DEFAULT_SCISSOR_STARTX :: 0 +DEFAULT_SCISSOR_STARTY :: 0 +DEFAULT_SLOPE_SCALED_DEPTH_BIAS :: 0.0 +DEFAULT_STENCIL_READ_MASK :: 0xff +DEFAULT_STENCIL_REFERENCE :: 0 +DEFAULT_STENCIL_WRITE_MASK :: 0xff +DEFAULT_VIEWPORT_AND_SCISSORRECT_INDEX :: 0 +DEFAULT_VIEWPORT_HEIGHT :: 0 +DEFAULT_VIEWPORT_MAX_DEPTH :: 0.0 +DEFAULT_VIEWPORT_MIN_DEPTH :: 0.0 +DEFAULT_VIEWPORT_TOPLEFTX :: 0 +DEFAULT_VIEWPORT_TOPLEFTY :: 0 +DEFAULT_VIEWPORT_WIDTH :: 0 + +DS_INPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 +DS_INPUT_CONTROL_POINT_REGISTER_COMPONENTS :: 4 +DS_INPUT_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_CONTROL_POINT_REGISTER_COUNT :: 32 +DS_INPUT_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 +DS_INPUT_CONTROL_POINT_REGISTER_READ_PORTS :: 1 +DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENTS :: 3 +DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_DOMAIN_POINT_REGISTER_COUNT :: 1 +DS_INPUT_DOMAIN_POINT_REGISTER_READS_PER_INST :: 2 +DS_INPUT_DOMAIN_POINT_REGISTER_READ_PORTS :: 1 +DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 +DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 +DS_INPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 +DS_INPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 +DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 +DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 +DS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 +DS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 +DS_OUTPUT_REGISTER_COMPONENTS :: 4 +DS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_OUTPUT_REGISTER_COUNT :: 32 + +FLOAT16_FUSED_TOLERANCE_IN_ULP :: 0.6 +FLOAT32_MAX :: 3.402823466e+38 +FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP :: 0.6 +FLOAT_TO_SRGB_EXPONENT_DENOMINATOR :: 2.4 +FLOAT_TO_SRGB_EXPONENT_NUMERATOR :: 1.0 +FLOAT_TO_SRGB_OFFSET :: 0.055 +FLOAT_TO_SRGB_SCALE_1 :: 12.92 +FLOAT_TO_SRGB_SCALE_2 :: 1.055 +FLOAT_TO_SRGB_THRESHOLD :: 0.0031308 +FTOI_INSTRUCTION_MAX_INPUT :: 2147483647.999 +FTOI_INSTRUCTION_MIN_INPUT :: -2147483648.999 +FTOU_INSTRUCTION_MAX_INPUT :: 4294967295.999 +FTOU_INSTRUCTION_MIN_INPUT :: 0.0 +GS_INPUT_INSTANCE_ID_READS_PER_INST :: 2 +GS_INPUT_INSTANCE_ID_READ_PORTS :: 1 +GS_INPUT_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +GS_INPUT_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_INPUT_INSTANCE_ID_REGISTER_COUNT :: 1 +GS_INPUT_PRIM_CONST_REGISTER_COMPONENTS :: 1 +GS_INPUT_PRIM_CONST_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_INPUT_PRIM_CONST_REGISTER_COUNT :: 1 +GS_INPUT_PRIM_CONST_REGISTER_READS_PER_INST :: 2 +GS_INPUT_PRIM_CONST_REGISTER_READ_PORTS :: 1 +GS_INPUT_REGISTER_COMPONENTS :: 4 +GS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_INPUT_REGISTER_COUNT :: 32 +GS_INPUT_REGISTER_READS_PER_INST :: 2 +GS_INPUT_REGISTER_READ_PORTS :: 1 +GS_INPUT_REGISTER_VERTICES :: 32 +GS_MAX_INSTANCE_COUNT :: 32 +GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES :: 1024 +GS_OUTPUT_ELEMENTS :: 32 +GS_OUTPUT_REGISTER_COMPONENTS :: 4 +GS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_OUTPUT_REGISTER_COUNT :: 32 +HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT :: 32 +HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT :: 32 +HS_CONTROL_POINT_REGISTER_COMPONENTS :: 4 +HS_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 +HS_CONTROL_POINT_REGISTER_READ_PORTS :: 1 +HS_FORK_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff +HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_COUNT :: 1 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_READ_PORTS :: 1 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COUNT :: 1 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READ_PORTS :: 1 +HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 +HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 +HS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 +HS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 +HS_JOIN_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff +HS_MAXTESSFACTOR_LOWER_BOUND :: 1.0 +HS_MAXTESSFACTOR_UPPER_BOUND :: 64.0 +HS_OUTPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENTS :: 1 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COUNT :: 1 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READS_PER_INST :: 2 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READ_PORTS :: 1 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_SCALAR_COMPONENTS :: 128 +IA_DEFAULT_INDEX_BUFFER_OFFSET_IN_BYTES :: 0 +IA_DEFAULT_PRIMITIVE_TOPOLOGY :: 0 +IA_DEFAULT_VERTEX_BUFFER_OFFSET_IN_BYTES :: 0 +IA_INDEX_INPUT_RESOURCE_SLOT_COUNT :: 1 +IA_INSTANCE_ID_BIT_COUNT :: 32 +IA_INTEGER_ARITHMETIC_BIT_COUNT :: 32 +IA_PATCH_MAX_CONTROL_POINT_COUNT :: 32 +IA_PRIMITIVE_ID_BIT_COUNT :: 32 +IA_VERTEX_ID_BIT_COUNT :: 32 +IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT :: 32 +IA_VERTEX_INPUT_STRUCTURE_ELEMENTS_COMPONENTS :: 128 +IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT :: 32 +INTEGER_DIVIDE_BY_ZERO_QUOTIENT :: 0xffffffff +INTEGER_DIVIDE_BY_ZERO_REMAINDER :: 0xffffffff +KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL :: 0xffffffff +KEEP_UNORDERED_ACCESS_VIEWS :: 0xffffffff +LINEAR_GAMMA :: 1.0 +MAJOR_VERSION :: 11 +MAX_BORDER_COLOR_COMPONENT :: 1.0 +MAX_DEPTH :: 1.0 +MAX_MAXANISOTROPY :: 16 +MAX_MULTISAMPLE_SAMPLE_COUNT :: 32 +MAX_POSITION_VALUE :: 3.402823466e+34 +MAX_TEXTURE_DIMENSION_2_TO_EXP :: 17 +MINOR_VERSION :: 0 +MIN_BORDER_COLOR_COMPONENT :: 0.0 +MIN_DEPTH :: 0.0 +MIN_MAXANISOTROPY :: 0 +MIP_LOD_BIAS_MAX :: 15.99 +MIP_LOD_BIAS_MIN :: -16.0 +MIP_LOD_FRACTIONAL_BIT_COUNT :: 8 +MIP_LOD_RANGE_BIT_COUNT :: 8 +MULTISAMPLE_ANTIALIAS_LINE_WIDTH :: 1.4 +NONSAMPLE_FETCH_OUT_OF_RANGE_ACCESS_RESULT :: 0 +PIXEL_ADDRESS_RANGE_BIT_COUNT :: 15 +PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT :: 16 +PS_CS_UAV_REGISTER_COMPONENTS :: 1 +PS_CS_UAV_REGISTER_COUNT :: 8 +PS_CS_UAV_REGISTER_READS_PER_INST :: 1 +PS_CS_UAV_REGISTER_READ_PORTS :: 1 +PS_FRONTFACING_DEFAULT_VALUE :: 0xffffffff +PS_FRONTFACING_FALSE_VALUE :: 0 +PS_FRONTFACING_TRUE_VALUE :: 0xffffffff +PS_INPUT_REGISTER_COMPONENTS :: 4 +PS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_INPUT_REGISTER_COUNT :: 32 +PS_INPUT_REGISTER_READS_PER_INST :: 2 +PS_INPUT_REGISTER_READ_PORTS :: 1 +PS_LEGACY_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.0 +PS_OUTPUT_DEPTH_REGISTER_COMPONENTS :: 1 +PS_OUTPUT_DEPTH_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_OUTPUT_DEPTH_REGISTER_COUNT :: 1 +PS_OUTPUT_MASK_REGISTER_COMPONENTS :: 1 +PS_OUTPUT_MASK_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_OUTPUT_MASK_REGISTER_COUNT :: 1 +PS_OUTPUT_REGISTER_COMPONENTS :: 4 +PS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_OUTPUT_REGISTER_COUNT :: 8 +PS_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.5 +RAW_UAV_SRV_BYTE_ALIGNMENT :: 16 +REQ_BLEND_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP :: 27 +REQ_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 +REQ_DEPTH_STENCIL_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 32 +REQ_DRAW_VERTEX_COUNT_2_TO_EXP :: 32 +REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION :: 16384 +REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT :: 1024 +REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 +REQ_MAXANISOTROPY :: 16 +REQ_MIP_LEVELS :: 15 +REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES :: 2048 +REQ_RASTERIZER_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_RENDER_TO_BUFFER_WINDOW_WIDTH :: 16384 +REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM :: 128 +REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_B_TERM :: 0.25 +REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM :: 2048 +REQ_RESOURCE_VIEW_COUNT_PER_DEVICE_2_TO_EXP :: 20 +REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION :: 2048 +REQ_TEXTURE1D_U_DIMENSION :: 16384 +REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION :: 2048 +REQ_TEXTURE2D_U_OR_V_DIMENSION :: 16384 +REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 2048 +REQ_TEXTURECUBE_DIMENSION :: 16384 +RESINFO_INSTRUCTION_MISSING_COMPONENT_RETVAL :: 0 +SHADER_MAJOR_VERSION :: 5 +SHADER_MAX_INSTANCES :: 65535 +SHADER_MAX_INTERFACES :: 253 +SHADER_MAX_INTERFACE_CALL_SITES :: 4096 +SHADER_MAX_TYPES :: 65535 +SHADER_MINOR_VERSION :: 0 +SHIFT_INSTRUCTION_PAD_VALUE :: 0 +SHIFT_INSTRUCTION_SHIFT_VALUE_BIT_COUNT :: 5 +SIMULTANEOUS_RENDER_TARGET_COUNT :: 8 +SO_BUFFER_MAX_STRIDE_IN_BYTES :: 2048 +SO_BUFFER_MAX_WRITE_WINDOW_IN_BYTES :: 512 +SO_BUFFER_SLOT_COUNT :: 4 +SO_DDI_REGISTER_INDEX_DENOTING_GAP :: 0xffffffff +SO_NO_RASTERIZED_STREAM :: 0xffffffff +SO_OUTPUT_COMPONENT_COUNT :: 128 +SO_STREAM_COUNT :: 4 +SPEC_DATE_DAY :: 16 +SPEC_DATE_YEAR :: 2011 +SPEC_VERSION :: 1.07 +SRGB_GAMMA :: 2.2 +SRGB_TO_FLOAT_DENOMINATOR_1 :: 12.92 +SRGB_TO_FLOAT_DENOMINATOR_2 :: 1.055 +SRGB_TO_FLOAT_EXPONENT :: 2.4 +SRGB_TO_FLOAT_OFFSET :: 0.055 +SRGB_TO_FLOAT_THRESHOLD :: 0.04045 +SRGB_TO_FLOAT_TOLERANCE_IN_ULP :: 0.5 +STANDARD_COMPONENT_BIT_COUNT :: 32 +STANDARD_COMPONENT_BIT_COUNT_DOUBLED :: 64 +STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE :: 4 +STANDARD_PIXEL_COMPONENT_COUNT :: 128 +STANDARD_PIXEL_ELEMENT_COUNT :: 32 +STANDARD_VECTOR_SIZE :: 4 +STANDARD_VERTEX_ELEMENT_COUNT :: 32 +STANDARD_VERTEX_TOTAL_COMPONENT_COUNT :: 64 +SUBPIXEL_FRACTIONAL_BIT_COUNT :: 8 +SUBTEXEL_FRACTIONAL_BIT_COUNT :: 8 +TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR :: 64 +TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 64 +TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR :: 63 +TESSELLATOR_MAX_TESSELLATION_FACTOR :: 64 +TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR :: 2 +TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 1 +TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR :: 1 +TEXEL_ADDRESS_RANGE_BIT_COUNT :: 16 +UNBOUND_MEMORY_ACCESS_RESULT :: 0 +VIEWPORT_AND_SCISSORRECT_MAX_INDEX :: 15 +VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE :: 16 +VIEWPORT_BOUNDS_MAX :: 32767 +VIEWPORT_BOUNDS_MIN :: -32768 +VS_INPUT_REGISTER_COMPONENTS :: 4 +VS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +VS_INPUT_REGISTER_COUNT :: 32 +VS_INPUT_REGISTER_READS_PER_INST :: 2 +VS_INPUT_REGISTER_READ_PORTS :: 1 +VS_OUTPUT_REGISTER_COMPONENTS :: 4 +VS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +VS_OUTPUT_REGISTER_COUNT :: 32 +WHQL_CONTEXT_COUNT_FOR_RESOURCE_LIMIT :: 10 +WHQL_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 25 +WHQL_DRAW_VERTEX_COUNT_2_TO_EXP :: 25 +_1_UAV_SLOT_COUNT :: 64 +_2_TILED_RESOURCE_TILE_SIZE_IN_BYTES :: 65536 +_4_VIDEO_DECODER_MAX_HISTOGRAM_COMPONENTS :: 4 +_4_VIDEO_DECODER_HISTOGRAM_OFFSET_ALIGNMENT :: 256 + +_FACD3D11 :: 0x87c + +APPEND_ALIGNED_ELEMENT :: 0xffffffff +FILTER_REDUCTION_TYPE_MASK :: 0x3 +FILTER_REDUCTION_TYPE_SHIFT :: 7 +FILTER_TYPE_MASK :: 0x3 +MIN_FILTER_SHIFT :: 4 +MAG_FILTER_SHIFT :: 2 +MIP_FILTER_SHIFT :: 0 +COMPARISON_FILTERING_BIT :: 0x80 +ANISOTROPIC_FILTERING_BIT :: 0x40 +SDK_VERSION :: 7 +RETURN_PARAMETER_INDEX :: -1 + +COMPONENT_MASK :: enum u32 { // TODO: make bit_set + X = 1, + Y = 2, + Z = 4, + W = 8, +} + +SHADER_REQUIRES :: enum u32 { // TODO: make bit_set + DOUBLES = 0x00000001, + EARLY_DEPTH_STENCIL = 0x00000002, + UAVS_AT_EVERY_STAGE = 0x00000004, + _64_UAVS = 0x00000008, + MINIMUM_PRECISION = 0x00000010, + _11_1_DOUBLE_EXTENSIONS = 0x00000020, + _11_1_SHADER_EXTENSIONS = 0x00000040, + LEVEL_9_COMPARISON_FILTERING = 0x00000080, + TILED_RESOURCES = 0x00000100, +} + +DRIVER_TYPE :: enum i32 { + UNKNOWN = 0, + HARDWARE = 1, + REFERENCE = 2, + NULL = 3, + SOFTWARE = 4, + WARP = 5, +} + +FEATURE_LEVEL :: enum i32 { + _1_0_CORE = 4096, + _9_1 = 37120, + _9_2 = 37376, + _9_3 = 37632, + _10_0 = 40960, + _10_1 = 41216, + _11_0 = 45056, + _11_1 = 45312, + _12_0 = 49152, + _12_1 = 49408, +} + +PRIMITIVE_TOPOLOGY :: enum i32 { + UNDEFINED = 0, + POINTLIST = 1, + LINELIST = 2, + LINESTRIP = 3, + TRIANGLELIST = 4, + TRIANGLESTRIP = 5, + LINELIST_ADJ = 10, + LINESTRIP_ADJ = 11, + TRIANGLELIST_ADJ = 12, + TRIANGLESTRIP_ADJ = 13, + _1_CONTROL_POINT_PATCHLIST = 33, + _2_CONTROL_POINT_PATCHLIST = 34, + _3_CONTROL_POINT_PATCHLIST = 35, + _4_CONTROL_POINT_PATCHLIST = 36, + _5_CONTROL_POINT_PATCHLIST = 37, + _6_CONTROL_POINT_PATCHLIST = 38, + _7_CONTROL_POINT_PATCHLIST = 39, + _8_CONTROL_POINT_PATCHLIST = 40, + _9_CONTROL_POINT_PATCHLIST = 41, + _10_CONTROL_POINT_PATCHLIST = 42, + _11_CONTROL_POINT_PATCHLIST = 43, + _12_CONTROL_POINT_PATCHLIST = 44, + _13_CONTROL_POINT_PATCHLIST = 45, + _14_CONTROL_POINT_PATCHLIST = 46, + _15_CONTROL_POINT_PATCHLIST = 47, + _16_CONTROL_POINT_PATCHLIST = 48, + _17_CONTROL_POINT_PATCHLIST = 49, + _18_CONTROL_POINT_PATCHLIST = 50, + _19_CONTROL_POINT_PATCHLIST = 51, + _20_CONTROL_POINT_PATCHLIST = 52, + _21_CONTROL_POINT_PATCHLIST = 53, + _22_CONTROL_POINT_PATCHLIST = 54, + _23_CONTROL_POINT_PATCHLIST = 55, + _24_CONTROL_POINT_PATCHLIST = 56, + _25_CONTROL_POINT_PATCHLIST = 57, + _26_CONTROL_POINT_PATCHLIST = 58, + _27_CONTROL_POINT_PATCHLIST = 59, + _28_CONTROL_POINT_PATCHLIST = 60, + _29_CONTROL_POINT_PATCHLIST = 61, + _30_CONTROL_POINT_PATCHLIST = 62, + _31_CONTROL_POINT_PATCHLIST = 63, + _32_CONTROL_POINT_PATCHLIST = 64, +} + +PRIMITIVE :: enum i32 { + UNDEFINED = 0, + POINT = 1, + LINE = 2, + TRIANGLE = 3, + LINE_ADJ = 6, + TRIANGLE_ADJ = 7, + _1_CONTROL_POINT_PATCH = 8, + _2_CONTROL_POINT_PATCH = 9, + _3_CONTROL_POINT_PATCH = 10, + _4_CONTROL_POINT_PATCH = 11, + _5_CONTROL_POINT_PATCH = 12, + _6_CONTROL_POINT_PATCH = 13, + _7_CONTROL_POINT_PATCH = 14, + _8_CONTROL_POINT_PATCH = 15, + _9_CONTROL_POINT_PATCH = 16, + _10_CONTROL_POINT_PATCH = 17, + _11_CONTROL_POINT_PATCH = 18, + _12_CONTROL_POINT_PATCH = 19, + _13_CONTROL_POINT_PATCH = 20, + _14_CONTROL_POINT_PATCH = 21, + _15_CONTROL_POINT_PATCH = 22, + _16_CONTROL_POINT_PATCH = 23, + _17_CONTROL_POINT_PATCH = 24, + _18_CONTROL_POINT_PATCH = 25, + _19_CONTROL_POINT_PATCH = 26, + _20_CONTROL_POINT_PATCH = 27, + _21_CONTROL_POINT_PATCH = 28, + _22_CONTROL_POINT_PATCH = 29, + _23_CONTROL_POINT_PATCH = 30, + _24_CONTROL_POINT_PATCH = 31, + _25_CONTROL_POINT_PATCH = 32, + _26_CONTROL_POINT_PATCH = 33, + _27_CONTROL_POINT_PATCH = 34, + _28_CONTROL_POINT_PATCH = 35, + _29_CONTROL_POINT_PATCH = 36, + _30_CONTROL_POINT_PATCH = 37, + _31_CONTROL_POINT_PATCH = 38, + _32_CONTROL_POINT_PATCH = 39, +} + +SRV_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE2DMS = 6, + TEXTURE2DMSARRAY = 7, + TEXTURE3D = 8, + TEXTURECUBE = 9, + TEXTURECUBEARRAY = 10, + BUFFEREX = 11, +} + +PFN_DESTRUCTION_CALLBACK :: #type proc "c" (a0: rawptr) + + +ID3DDestructionNotifier_UUID :: "A06EB39A-50DA-425B-8C31-4EECD6C270F3" +ID3DDestructionNotifier :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3ddestructionnotifier_vtable: ^ID3DDestructionNotifier_VTable, +} +ID3DDestructionNotifier_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + RegisterDestructionCallback: proc "stdcall" (this: ^ID3DDestructionNotifier, callbackFn: PFN_DESTRUCTION_CALLBACK, pData: rawptr, pCallbackID: ^u32) -> HRESULT, + UnregisterDestructionCallback: proc "stdcall" (this: ^ID3DDestructionNotifier, callbackID: u32) -> HRESULT, +} + + +SHADER_VARIABLE_CLASS :: enum i32 { + SCALAR = 0, + VECTOR = 1, + MATRIX_ROWS = 2, + MATRIX_COLUMNS = 3, + OBJECT = 4, + STRUCT = 5, + INTERFACE_CLASS = 6, + INTERFACE_POINTER = 7, +} + +SHADER_VARIABLE_FLAGS :: enum u32 { // TODO: make bit_set + USERPACKED = 0x1, + USED = 0x2, + INTERFACE_POINTER = 0x4, + INTERFACE_PARAMETER = 0x8, +} + +SHADER_VARIABLE_TYPE :: enum i32 { + VOID = 0, + BOOL = 1, + INT = 2, + FLOAT = 3, + STRING = 4, + TEXTURE = 5, + TEXTURE1D = 6, + TEXTURE2D = 7, + TEXTURE3D = 8, + TEXTURECUBE = 9, + SAMPLER = 10, + SAMPLER1D = 11, + SAMPLER2D = 12, + SAMPLER3D = 13, + SAMPLERCUBE = 14, + PIXELSHADER = 15, + VERTEXSHADER = 16, + PIXELFRAGMENT = 17, + VERTEXFRAGMENT = 18, + UINT = 19, + UINT8 = 20, + GEOMETRYSHADER = 21, + RASTERIZER = 22, + DEPTHSTENCIL = 23, + BLEND = 24, + BUFFER = 25, + CBUFFER = 26, + TBUFFER = 27, + TEXTURE1DARRAY = 28, + TEXTURE2DARRAY = 29, + RENDERTARGETVIEW = 30, + DEPTHSTENCILVIEW = 31, + TEXTURE2DMS = 32, + TEXTURE2DMSARRAY = 33, + TEXTURECUBEARRAY = 34, + HULLSHADER = 35, + DOMAINSHADER = 36, + INTERFACE_POINTER = 37, + COMPUTESHADER = 38, + DOUBLE = 39, + RWTEXTURE1D = 40, + RWTEXTURE1DARRAY = 41, + RWTEXTURE2D = 42, + RWTEXTURE2DARRAY = 43, + RWTEXTURE3D = 44, + RWBUFFER = 45, + BYTEADDRESS_BUFFER = 46, + RWBYTEADDRESS_BUFFER = 47, + STRUCTURED_BUFFER = 48, + RWSTRUCTURED_BUFFER = 49, + APPEND_STRUCTURED_BUFFER = 50, + CONSUME_STRUCTURED_BUFFER = 51, + MIN8FLOAT = 52, + MIN10FLOAT = 53, + MIN16FLOAT = 54, + MIN12INT = 55, + MIN16INT = 56, + MIN16UINT = 57, +} + +SHADER_INPUT_FLAGS :: enum u32 { // TODO: make bit_set + USERPACKED = 0x1, + COMPARISON_SAMPLER = 0x2, + TEXTURE_COMPONENT_0 = 0x4, + TEXTURE_COMPONENT_1 = 0x8, + TEXTURE_COMPONENTS = 0xc, + UNUSED = 0x10, +} + +SHADER_INPUT_TYPE :: enum i32 { + CBUFFER = 0, + TBUFFER = 1, + TEXTURE = 2, + SAMPLER = 3, + UAV_RWTYPED = 4, + STRUCTURED = 5, + UAV_RWSTRUCTURED = 6, + BYTEADDRESS = 7, + UAV_RWBYTEADDRESS = 8, + UAV_APPEND_STRUCTURED = 9, + UAV_CONSUME_STRUCTURED = 10, + UAV_RWSTRUCTURED_WITH_COUNTER = 11, + RTACCELERATIONSTRUCTURE = 12, + UAV_FEEDBACKTEXTURE = 13, +} + +SHADER_CBUFFER_FLAGS :: enum u32 { // TODO: make bit_set + USERPACKED = 0x1, +} + +CBUFFER_TYPE :: enum i32 { + CBUFFER = 0, + TBUFFER = 1, + INTERFACE_POINTERS = 2, + RESOURCE_BIND_INFO = 3, +} + +NAME :: enum i32 { + UNDEFINED = 0, + POSITION = 1, + CLIP_DISTANCE = 2, + CULL_DISTANCE = 3, + RENDER_TARGET_ARRAY_INDEX = 4, + VIEWPORT_ARRAY_INDEX = 5, + VERTEX_ID = 6, + PRIMITIVE_ID = 7, + INSTANCE_ID = 8, + IS_FRONT_FACE = 9, + SAMPLE_INDEX = 10, + FINAL_QUAD_EDGE_TESSFACTOR = 11, + FINAL_QUAD_INSIDE_TESSFACTOR = 12, + FINAL_TRI_EDGE_TESSFACTOR = 13, + FINAL_TRI_INSIDE_TESSFACTOR = 14, + FINAL_LINE_DETAIL_TESSFACTOR = 15, + FINAL_LINE_DENSITY_TESSFACTOR = 16, + BARYCENTRICS = 23, + SHADINGRATE = 24, + CULLPRIMITIVE = 25, + TARGET = 64, + DEPTH = 65, + COVERAGE = 66, + DEPTH_GREATER_EQUAL = 67, + DEPTH_LESS_EQUAL = 68, + STENCIL_REF = 69, + INNER_COVERAGE = 70, +} + +RESOURCE_RETURN_TYPE :: enum i32 { + UNORM = 1, + SNORM = 2, + SINT = 3, + UINT = 4, + FLOAT = 5, + MIXED = 6, + DOUBLE = 7, + CONTINUED = 8, +} + +REGISTER_COMPONENT_TYPE :: enum i32 { + UNKNOWN = 0, + UINT32 = 1, + SINT32 = 2, + FLOAT32 = 3, +} + +TESSELLATOR_DOMAIN :: enum i32 { + UNDEFINED = 0, + ISOLINE = 1, + TRI = 2, + QUAD = 3, +} + +TESSELLATOR_PARTITIONING :: enum i32 { + UNDEFINED = 0, + INTEGER = 1, + POW2 = 2, + FRACTIONAL_ODD = 3, + FRACTIONAL_EVEN = 4, +} + +TESSELLATOR_OUTPUT_PRIMITIVE :: enum i32 { + UNDEFINED = 0, + POINT = 1, + LINE = 2, + TRIANGLE_CW = 3, + TRIANGLE_CCW = 4, +} + +MIN_PRECISION :: enum i32 { + DEFAULT = 0, + FLOAT_16 = 1, + FLOAT_2_8 = 2, + RESERVED = 3, + SINT_16 = 4, + UINT_16 = 5, + ANY_16 = 240, + ANY_10 = 241, +} + +INTERPOLATION_MODE :: enum i32 { + UNDEFINED = 0, + CONSTANT = 1, + LINEAR = 2, + LINEAR_CENTROID = 3, + LINEAR_NOPERSPECTIVE = 4, + LINEAR_NOPERSPECTIVE_CENTROID = 5, + LINEAR_SAMPLE = 6, + LINEAR_NOPERSPECTIVE_SAMPLE = 7, +} + +PARAMETER_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + IN = 0x1, + OUT = 0x2, +} + +CDEFAULT :: struct { + _: u8, +} + +INPUT_CLASSIFICATION :: enum i32 { + VERTEX_DATA = 0, + INSTANCE_DATA = 1, +} + +INPUT_ELEMENT_DESC :: struct { + SemanticName: cstring, + SemanticIndex: u32, + Format: dxgi.FORMAT, + InputSlot: u32, + AlignedByteOffset: u32, + InputSlotClass: INPUT_CLASSIFICATION, + InstanceDataStepRate: u32, +} + +FILL_MODE :: enum i32 { + WIREFRAME = 2, + SOLID = 3, +} + +CULL_MODE :: enum i32 { + NONE = 1, + FRONT = 2, + BACK = 3, +} + +SO_DECLARATION_ENTRY :: struct { + Stream: u32, + SemanticName: cstring, + SemanticIndex: u32, + StartComponent: u8, + ComponentCount: u8, + OutputSlot: u8, +} + +VIEWPORT :: struct { + TopLeftX: f32, + TopLeftY: f32, + Width: f32, + Height: f32, + MinDepth: f32, + MaxDepth: f32, +} + +DRAW_INSTANCED_INDIRECT_ARGS :: struct { + VertexCountPerInstance: u32, + InstanceCount: u32, + StartVertexLocation: u32, + StartInstanceLocation: u32, +} + +DRAW_INDEXED_INSTANCED_INDIRECT_ARGS :: struct { + IndexCountPerInstance: u32, + InstanceCount: u32, + StartIndexLocation: u32, + BaseVertexLocation: i32, + StartInstanceLocation: u32, +} + +RESOURCE_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE2D = 3, + TEXTURE3D = 4, +} + +DSV_DIMENSION :: enum i32 { + UNKNOWN = 0, + TEXTURE1D = 1, + TEXTURE1DARRAY = 2, + TEXTURE2D = 3, + TEXTURE2DARRAY = 4, + TEXTURE2DMS = 5, + TEXTURE2DMSARRAY = 6, +} + +RTV_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE2DMS = 6, + TEXTURE2DMSARRAY = 7, + TEXTURE3D = 8, +} + +UAV_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE3D = 8, +} + +USAGE :: enum i32 { + DEFAULT = 0, + IMMUTABLE = 1, + DYNAMIC = 2, + STAGING = 3, +} + +BIND_FLAG :: enum u32 { // TODO: make bit_set + VERTEX_BUFFER = 0x1, + INDEX_BUFFER = 0x2, + CONSTANT_BUFFER = 0x4, + SHADER_RESOURCE = 0x8, + STREAM_OUTPUT = 0x10, + RENDER_TARGET = 0x20, + DEPTH_STENCIL = 0x40, + UNORDERED_ACCESS = 0x80, + DECODER = 0x200, + VIDEO_ENCODER = 0x400, +} + +CPU_ACCESS_FLAG :: enum u32 { // TODO: make bit_set + WRITE = 0x10000, + READ = 0x20000, + +} + +RESOURCE_MISC_FLAG :: enum u32 { // TODO: make bit_set + GENERATE_MIPS = 0x1, + SHARED = 0x2, + TEXTURECUBE = 0x4, + DRAWINDIRECT_ARGS = 0x10, + BUFFER_ALLOW_RAW_VIEWS = 0x20, + BUFFER_STRUCTURED = 0x40, + RESOURCE_CLAMP = 0x80, + SHARED_KEYEDMUTEX = 0x100, + GDI_COMPATIBLE = 0x200, + SHARED_NTHANDLE = 0x800, + RESTRICTED_CONTENT = 0x1000, + RESTRICT_SHARED_RESOURCE = 0x2000, + RESTRICT_SHARED_RESOURCE_DRIVER = 0x4000, + GUARDED = 0x8000, + TILE_POOL = 0x20000, + TILED = 0x40000, + HW_PROTECTED = 0x80000, +} + +MAP :: enum i32 { + READ = 1, + WRITE = 2, + READ_WRITE = 3, + WRITE_DISCARD = 4, + WRITE_NO_OVERWRITE = 5, +} + +MAP_FLAG :: enum u32 { // TODO: make bit_set + DO_NOT_WAIT = 0x100000, +} + +RAISE_FLAG :: enum u32 { // TODO: make bit_set + DRIVER_INTERNAL_ERROR = 0x1, +} + +CLEAR_FLAG :: enum u32 { // TODO: make bit_set + DEPTH = 0x1, + STENCIL = 0x2, +} + + +CRECT :: struct { + using d3d11_rect: RECT, +} + +BOX :: struct { + left: u32, + top: u32, + front: u32, + right: u32, + bottom: u32, + back: u32, +} + +CBOX :: struct { + using d3d11_box: BOX, +} + + +IDeviceChild_UUID :: "1841E5C8-16B0-489B-BCC8-44CFB0D5DEAE" +IDeviceChild :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11devicechild_vtable: ^IDeviceChild_VTable, +} +IDeviceChild_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetDevice: proc "stdcall" (this: ^IDeviceChild, ppDevice: ^^IDevice), + GetPrivateData: proc "stdcall" (this: ^IDeviceChild, guid: ^GUID, pDataSize: ^u32, pData: rawptr) -> HRESULT, + SetPrivateData: proc "stdcall" (this: ^IDeviceChild, guid: ^GUID, DataSize: u32, pData: rawptr) -> HRESULT, + SetPrivateDataInterface: proc "stdcall" (this: ^IDeviceChild, guid: ^GUID, pData: ^IUnknown) -> HRESULT, +} + + +COMPARISON_FUNC :: enum i32 { + NEVER = 1, + LESS = 2, + EQUAL = 3, + LESS_EQUAL = 4, + GREATER = 5, + NOT_EQUAL = 6, + GREATER_EQUAL = 7, + ALWAYS = 8, +} + +DEPTH_WRITE_MASK :: enum i32 { + ZERO = 0, + ALL = 1, +} + +STENCIL_OP :: enum i32 { + KEEP = 1, + ZERO = 2, + REPLACE = 3, + INCR_SAT = 4, + DECR_SAT = 5, + INVERT = 6, + INCR = 7, + DECR = 8, +} + +DEPTH_STENCILOP_DESC :: struct { + StencilFailOp: STENCIL_OP, + StencilDepthFailOp: STENCIL_OP, + StencilPassOp: STENCIL_OP, + StencilFunc: COMPARISON_FUNC, +} + +DEPTH_STENCIL_DESC :: struct { + DepthEnable: BOOL, + DepthWriteMask: DEPTH_WRITE_MASK, + DepthFunc: COMPARISON_FUNC, + StencilEnable: BOOL, + StencilReadMask: u8, + StencilWriteMask: u8, + FrontFace: DEPTH_STENCILOP_DESC, + BackFace: DEPTH_STENCILOP_DESC, +} + +CDEPTH_STENCIL_DESC :: struct { + using d3d11_depth_stencil_desc: DEPTH_STENCIL_DESC, +} + + +IDepthStencilState_UUID :: "03823EFB-8D8F-4E1C-9AA2-F64BB2CBFDF1" +IDepthStencilState :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11depthstencilstate_vtable: ^IDepthStencilState_VTable, +} +IDepthStencilState_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetDesc: proc "stdcall" (this: ^IDepthStencilState, pDesc: ^DEPTH_STENCIL_DESC), +} + + +BLEND :: enum i32 { + ZERO = 1, + ONE = 2, + SRC_COLOR = 3, + INV_SRC_COLOR = 4, + SRC_ALPHA = 5, + INV_SRC_ALPHA = 6, + DEST_ALPHA = 7, + INV_DEST_ALPHA = 8, + DEST_COLOR = 9, + INV_DEST_COLOR = 10, + SRC_ALPHA_SAT = 11, + BLEND_FACTOR = 14, + INV_BLEND_FACTOR = 15, + SRC1_COLOR = 16, + INV_SRC1_COLOR = 17, + SRC1_ALPHA = 18, + INV_SRC1_ALPHA = 19, +} + +BLEND_OP :: enum i32 { + ADD = 1, + SUBTRACT = 2, + REV_SUBTRACT = 3, + MIN = 4, + MAX = 5, +} + +COLOR_WRITE_ENABLE :: enum i32 { // TODO: make bit_set + RED = 1, + GREEN = 2, + BLUE = 4, + ALPHA = 8, + ALL = 15, +} + +RENDER_TARGET_BLEND_DESC :: struct { + BlendEnable: BOOL, + SrcBlend: BLEND, + DestBlend: BLEND, + BlendOp: BLEND_OP, + SrcBlendAlpha: BLEND, + DestBlendAlpha: BLEND, + BlendOpAlpha: BLEND_OP, + RenderTargetWriteMask: u8, +} + +BLEND_DESC :: struct { + AlphaToCoverageEnable: BOOL, + IndependentBlendEnable: BOOL, + RenderTarget: [8]RENDER_TARGET_BLEND_DESC, +} + +CBLEND_DESC :: struct { + using d3d11_blend_desc: BLEND_DESC, +} + + +IBlendState_UUID :: "75B68FAA-347D-4159-8F45-A0640F01CD9A" +IBlendState :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11blendstate_vtable: ^IBlendState_VTable, +} +IBlendState_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetDesc: proc "stdcall" (this: ^IBlendState, pDesc: ^BLEND_DESC), +} + + +RASTERIZER_DESC :: struct { + FillMode: FILL_MODE, + CullMode: CULL_MODE, + FrontCounterClockwise: BOOL, + DepthBias: i32, + DepthBiasClamp: f32, + SlopeScaledDepthBias: f32, + DepthClipEnable: BOOL, + ScissorEnable: BOOL, + MultisampleEnable: BOOL, + AntialiasedLineEnable: BOOL, +} + +CRASTERIZER_DESC :: struct { + using d3d11_rasterizer_desc: RASTERIZER_DESC, +} + + +IRasterizerState_UUID :: "9BB4AB81-AB1A-4D8F-B506-FC04200B6EE7" +IRasterizerState :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11rasterizerstate_vtable: ^IRasterizerState_VTable, +} +IRasterizerState_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetDesc: proc "stdcall" (this: ^IRasterizerState, pDesc: ^RASTERIZER_DESC), +} + + +SUBRESOURCE_DATA :: struct { + pSysMem: rawptr, + SysMemPitch: u32, + SysMemSlicePitch: u32, +} + +MAPPED_SUBRESOURCE :: struct { + pData: rawptr, + RowPitch: u32, + DepthPitch: u32, +} + + +IResource_UUID :: "DC8E63F3-D12B-4952-B47B-5E45026A862D" +IResource :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11resource_vtable: ^IResource_VTable, +} +IResource_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetType: proc "stdcall" (this: ^IResource, pResourceDimension: ^RESOURCE_DIMENSION), + SetEvictionPriority: proc "stdcall" (this: ^IResource, EvictionPriority: u32), + GetEvictionPriority: proc "stdcall" (this: ^IResource) -> u32, +} + + +BUFFER_DESC :: struct { + ByteWidth: u32, + Usage: USAGE, + BindFlags: BIND_FLAG, + CPUAccessFlags: CPU_ACCESS_FLAG, + MiscFlags: RESOURCE_MISC_FLAG, + StructureByteStride: u32, +} + +CBUFFER_DESC :: struct { + using d3d11_buffer_desc: BUFFER_DESC, +} + + +IBuffer_UUID :: "48570B85-D1EE-4FCD-A250-EB350722B037" +IBuffer :: struct #raw_union { + #subtype id3d11resource: IResource, + using id3d11buffer_vtable: ^IBuffer_VTable, +} +IBuffer_VTable :: struct { + using id3d11resource_vtable: IResource_VTable, + GetDesc: proc "stdcall" (this: ^IBuffer, pDesc: ^BUFFER_DESC), +} + + +TEXTURE1D_DESC :: struct { + Width: u32, + MipLevels: u32, + ArraySize: u32, + Format: dxgi.FORMAT, + Usage: USAGE, + BindFlags: BIND_FLAG, + CPUAccessFlags: CPU_ACCESS_FLAG, + MiscFlags: RESOURCE_MISC_FLAG, +} + +CTEXTURE1D_DESC :: struct { + using d3d11_texture1d_desc: TEXTURE1D_DESC, +} + + +ITexture1D_UUID :: "F8FB5C27-C6B3-4F75-A4C8-439AF2EF564C" +ITexture1D :: struct #raw_union { + #subtype id3d11resource: IResource, + using id3d11texture1d_vtable: ^ITexture1D_VTable, +} +ITexture1D_VTable :: struct { + using id3d11resource_vtable: IResource_VTable, + GetDesc: proc "stdcall" (this: ^ITexture1D, pDesc: ^TEXTURE1D_DESC), +} + + +TEXTURE2D_DESC :: struct { + Width: u32, + Height: u32, + MipLevels: u32, + ArraySize: u32, + Format: dxgi.FORMAT, + SampleDesc: dxgi.SAMPLE_DESC, + Usage: USAGE, + BindFlags: BIND_FLAG, + CPUAccessFlags: CPU_ACCESS_FLAG, + MiscFlags: RESOURCE_MISC_FLAG, +} + +CTEXTURE2D_DESC :: struct { + using d3d11_texture2d_desc: TEXTURE2D_DESC, +} + + +ITexture2D_UUID :: "6F15AAF2-D208-4E89-9AB4-489535D34F9C" +ITexture2D :: struct #raw_union { + #subtype id3d11resource: IResource, + using id3d11texture2d_vtable: ^ITexture2D_VTable, +} +ITexture2D_VTable :: struct { + using id3d11resource_vtable: IResource_VTable, + GetDesc: proc "stdcall" (this: ^ITexture2D, pDesc: ^TEXTURE2D_DESC), +} + + +TEXTURE3D_DESC :: struct { + Width: u32, + Height: u32, + Depth: u32, + MipLevels: u32, + Format: dxgi.FORMAT, + Usage: USAGE, + BindFlags: BIND_FLAG, + CPUAccessFlags: CPU_ACCESS_FLAG, + MiscFlags: RESOURCE_MISC_FLAG, +} + +CTEXTURE3D_DESC :: struct { + using d3d11_texture3d_desc: TEXTURE3D_DESC, +} + + +ITexture3D_UUID :: "037E866E-F56D-4357-A8AF-9DABBE6E250E" +ITexture3D :: struct #raw_union { + #subtype id3d11resource: IResource, + using id3d11texture3d_vtable: ^ITexture3D_VTable, +} +ITexture3D_VTable :: struct { + using id3d11resource_vtable: IResource_VTable, + GetDesc: proc "stdcall" (this: ^ITexture3D, pDesc: ^TEXTURE3D_DESC), +} + + +TEXTURECUBE_FACE :: enum i32 { + POSITIVE_X = 0, + NEGATIVE_X = 1, + POSITIVE_Y = 2, + NEGATIVE_Y = 3, + POSITIVE_Z = 4, + NEGATIVE_Z = 5, +} + + +IView_UUID :: "839D1216-BB2E-412B-B7F4-A9DBEBE08ED1" +IView :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11view_vtable: ^IView_VTable, +} +IView_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetResource: proc "stdcall" (this: ^IView, ppResource: ^^IResource), +} + + +BUFFER_SRV :: struct { + using _: struct #raw_union { + FirstElement: u32, + ElementOffset: u32, + }, + using _: struct #raw_union { + NumElements: u32, + ElementWidth: u32, + }, +} + +BUFFEREX_SRV_FLAG :: enum u32 { // TODO: make bit_set + RAW = 0x1, +} + +BUFFEREX_SRV :: struct { + FirstElement: u32, + NumElements: u32, + Flags: u32, +} + +TEX1D_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, +} + +TEX1D_ARRAY_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2D_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, +} + +TEX2D_ARRAY_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX3D_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, +} + +TEXCUBE_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, +} + +TEXCUBE_ARRAY_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + First2DArrayFace: u32, + NumCubes: u32, +} + +TEX2DMS_SRV :: struct { + UnusedField_NothingToDefine: u32, +} + +TEX2DMS_ARRAY_SRV :: struct { + FirstArraySlice: u32, + ArraySize: u32, +} + +SHADER_RESOURCE_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: SRV_DIMENSION, + using _: struct #raw_union { + Buffer: BUFFER_SRV, + Texture1D: TEX1D_SRV, + Texture1DArray: TEX1D_ARRAY_SRV, + Texture2D: TEX2D_SRV, + Texture2DArray: TEX2D_ARRAY_SRV, + Texture2DMS: TEX2DMS_SRV, + Texture2DMSArray: TEX2DMS_ARRAY_SRV, + Texture3D: TEX3D_SRV, + TextureCube: TEXCUBE_SRV, + TextureCubeArray: TEXCUBE_ARRAY_SRV, + BufferEx: BUFFEREX_SRV, + }, +} + +CSHADER_RESOURCE_VIEW_DESC :: struct { + using d3d11_shader_resource_view_desc: SHADER_RESOURCE_VIEW_DESC, +} + + +IShaderResourceView_UUID :: "B0E06FE0-8192-4E1A-B1CA-36D7414710B2" +IShaderResourceView :: struct #raw_union { + #subtype id3d11view: IView, + using id3d11shaderresourceview_vtable: ^IShaderResourceView_VTable, +} +IShaderResourceView_VTable :: struct { + using id3d11view_vtable: IView_VTable, + GetDesc: proc "stdcall" (this: ^IShaderResourceView, pDesc: ^SHADER_RESOURCE_VIEW_DESC), +} + + +BUFFER_RTV :: struct { + using _: struct #raw_union { + FirstElement: u32, + ElementOffset: u32, + }, + using _: struct #raw_union { + NumElements: u32, + ElementWidth: u32, + }, +} + +TEX1D_RTV :: struct { + MipSlice: u32, +} + +TEX1D_ARRAY_RTV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2D_RTV :: struct { + MipSlice: u32, +} + +TEX2DMS_RTV :: struct { + UnusedField_NothingToDefine: u32, +} + +TEX2D_ARRAY_RTV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2DMS_ARRAY_RTV :: struct { + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX3D_RTV :: struct { + MipSlice: u32, + FirstWSlice: u32, + WSize: u32, +} + +RENDER_TARGET_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: RTV_DIMENSION, + using _: struct #raw_union { + Buffer: BUFFER_RTV, + Texture1D: TEX1D_RTV, + Texture1DArray: TEX1D_ARRAY_RTV, + Texture2D: TEX2D_RTV, + Texture2DArray: TEX2D_ARRAY_RTV, + Texture2DMS: TEX2DMS_RTV, + Texture2DMSArray: TEX2DMS_ARRAY_RTV, + Texture3D: TEX3D_RTV, + }, +} + +CRENDER_TARGET_VIEW_DESC :: struct { + using d3d11_render_target_view_desc: RENDER_TARGET_VIEW_DESC, +} + + +IRenderTargetView_UUID :: "DFDBA067-0B8D-4865-875B-D7B4516CC164" +IRenderTargetView :: struct #raw_union { + #subtype id3d11view: IView, + using id3d11rendertargetview_vtable: ^IRenderTargetView_VTable, +} +IRenderTargetView_VTable :: struct { + using id3d11view_vtable: IView_VTable, + GetDesc: proc "stdcall" (this: ^IRenderTargetView, pDesc: ^RENDER_TARGET_VIEW_DESC), +} + + +CVIEWPORT :: struct { + using d3d11_viewport: VIEWPORT, +} + +TEX1D_DSV :: struct { + MipSlice: u32, +} + +TEX1D_ARRAY_DSV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2D_DSV :: struct { + MipSlice: u32, +} + +TEX2D_ARRAY_DSV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2DMS_DSV :: struct { + UnusedField_NothingToDefine: u32, +} + +TEX2DMS_ARRAY_DSV :: struct { + FirstArraySlice: u32, + ArraySize: u32, +} + +DSV_FLAG :: enum u32 { // TODO: make bit_set + DEPTH = 0x1, + STENCIL = 0x2, +} + +DEPTH_STENCIL_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: DSV_DIMENSION, + Flags: u32, + using _: struct #raw_union { + Texture1D: TEX1D_DSV, + Texture1DArray: TEX1D_ARRAY_DSV, + Texture2D: TEX2D_DSV, + Texture2DArray: TEX2D_ARRAY_DSV, + Texture2DMS: TEX2DMS_DSV, + Texture2DMSArray: TEX2DMS_ARRAY_DSV, + }, +} + +CDEPTH_STENCIL_VIEW_DESC :: struct { + using d3d11_depth_stencil_view_desc: DEPTH_STENCIL_VIEW_DESC, +} + + +IDepthStencilView_UUID :: "9FDAC92A-1876-48C3-AFAD-25B94F84A9B6" +IDepthStencilView :: struct #raw_union { + #subtype id3d11view: IView, + using id3d11depthstencilview_vtable: ^IDepthStencilView_VTable, +} +IDepthStencilView_VTable :: struct { + using id3d11view_vtable: IView_VTable, + GetDesc: proc "stdcall" (this: ^IDepthStencilView, pDesc: ^DEPTH_STENCIL_VIEW_DESC), +} + + +BUFFER_UAV_FLAG :: enum u32 { // TODO: make bit_set + RAW = 0x1, + APPEND = 0x2, + COUNTER = 0x4, +} + +BUFFER_UAV :: struct { + FirstElement: u32, + NumElements: u32, + Flags: u32, +} + +TEX1D_UAV :: struct { + MipSlice: u32, +} + +TEX1D_ARRAY_UAV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2D_UAV :: struct { + MipSlice: u32, +} + +TEX2D_ARRAY_UAV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX3D_UAV :: struct { + MipSlice: u32, + FirstWSlice: u32, + WSize: u32, +} + +UNORDERED_ACCESS_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: UAV_DIMENSION, + using _: struct #raw_union { + Buffer: BUFFER_UAV, + Texture1D: TEX1D_UAV, + Texture1DArray: TEX1D_ARRAY_UAV, + Texture2D: TEX2D_UAV, + Texture2DArray: TEX2D_ARRAY_UAV, + Texture3D: TEX3D_UAV, + }, +} + +CUNORDERED_ACCESS_VIEW_DESC :: struct { + using d3d11_unordered_access_view_desc: UNORDERED_ACCESS_VIEW_DESC, +} + + +IUnorderedAccessView_UUID :: "28ACF509-7F5C-48F6-8611-F316010A6380" +IUnorderedAccessView :: struct #raw_union { + #subtype id3d11view: IView, + using id3d11unorderedaccessview_vtable: ^IUnorderedAccessView_VTable, +} +IUnorderedAccessView_VTable :: struct { + using id3d11view_vtable: IView_VTable, + GetDesc: proc "stdcall" (this: ^IUnorderedAccessView, pDesc: ^UNORDERED_ACCESS_VIEW_DESC), +} + + + +IVertexShader_UUID :: "3B301D64-D678-4289-8897-22F8928B72F3" +IVertexShader :: struct { + using id3d11devicechild: IDeviceChild, +} + + +IHullShader_UUID :: "8E5C6061-628A-4C8E-8264-BBE45CB3D5DD" +IHullShader :: struct { + using id3d11devicechild: IDeviceChild, +} + + +IDomainShader_UUID :: "F582C508-0F36-490C-9977-31EECE268CFA" +IDomainShader :: struct { + using id3d11devicechild: IDeviceChild, +} + + +IGeometryShader_UUID :: "38325B96-EFFB-4022-BA02-2E795B70275C" +IGeometryShader :: struct { + using id3d11devicechild: IDeviceChild, +} + + +IPixelShader_UUID :: "EA82E40D-51DC-4F33-93D4-DB7C9125AE8C" +IPixelShader :: struct { + using id3d11devicechild: IDeviceChild, +} + + +IComputeShader_UUID :: "4F5B196E-C2BD-495E-BD01-1FDED38E4969" +IComputeShader :: struct { + using id3d11devicechild: IDeviceChild, +} + + +IInputLayout_UUID :: "E4819DDC-4CF0-4025-BD26-5DE82A3E07B7" +IInputLayout :: struct { + using id3d11devicechild: IDeviceChild, +} + +FILTER :: enum i32 { + MIN_MAG_MIP_POINT = 0, + MIN_MAG_POINT_MIP_LINEAR = 1, + MIN_POINT_MAG_LINEAR_MIP_POINT = 4, + MIN_POINT_MAG_MIP_LINEAR = 5, + MIN_LINEAR_MAG_MIP_POINT = 16, + MIN_LINEAR_MAG_POINT_MIP_LINEAR = 17, + MIN_MAG_LINEAR_MIP_POINT = 20, + MIN_MAG_MIP_LINEAR = 21, + ANISOTROPIC = 85, + COMPARISON_MIN_MAG_MIP_POINT = 128, + COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 129, + COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 132, + COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 133, + COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 144, + COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 145, + COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 148, + COMPARISON_MIN_MAG_MIP_LINEAR = 149, + COMPARISON_ANISOTROPIC = 213, + MINIMUM_MIN_MAG_MIP_POINT = 256, + MINIMUM_MIN_MAG_POINT_MIP_LINEAR = 257, + MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 260, + MINIMUM_MIN_POINT_MAG_MIP_LINEAR = 261, + MINIMUM_MIN_LINEAR_MAG_MIP_POINT = 272, + MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 273, + MINIMUM_MIN_MAG_LINEAR_MIP_POINT = 276, + MINIMUM_MIN_MAG_MIP_LINEAR = 277, + MINIMUM_ANISOTROPIC = 341, + MAXIMUM_MIN_MAG_MIP_POINT = 384, + MAXIMUM_MIN_MAG_POINT_MIP_LINEAR = 385, + MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 388, + MAXIMUM_MIN_POINT_MAG_MIP_LINEAR = 389, + MAXIMUM_MIN_LINEAR_MAG_MIP_POINT = 400, + MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 401, + MAXIMUM_MIN_MAG_LINEAR_MIP_POINT = 404, + MAXIMUM_MIN_MAG_MIP_LINEAR = 405, + MAXIMUM_ANISOTROPIC = 469, +} + +FILTER_TYPE :: enum i32 { + POINT = 0, + LINEAR = 1, +} + +FILTER_REDUCTION_TYPE :: enum i32 { + STANDARD = 0, + COMPARISON = 1, + MINIMUM = 2, + MAXIMUM = 3, +} + +TEXTURE_ADDRESS_MODE :: enum i32 { + WRAP = 1, + MIRROR = 2, + CLAMP = 3, + BORDER = 4, + MIRROR_ONCE = 5, +} + +SAMPLER_DESC :: struct { + Filter: FILTER, + AddressU: TEXTURE_ADDRESS_MODE, + AddressV: TEXTURE_ADDRESS_MODE, + AddressW: TEXTURE_ADDRESS_MODE, + MipLODBias: f32, + MaxAnisotropy: u32, + ComparisonFunc: COMPARISON_FUNC, + BorderColor: [4]f32, + MinLOD: f32, + MaxLOD: f32, +} + +CSAMPLER_DESC :: struct { + using d3d11_sampler_desc: SAMPLER_DESC, +} + + +ISamplerState_UUID :: "DA6FEA51-564C-4487-9810-F0D0F9B4E3A5" +ISamplerState :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11samplerstate_vtable: ^ISamplerState_VTable, +} +ISamplerState_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetDesc: proc "stdcall" (this: ^ISamplerState, pDesc: ^SAMPLER_DESC), +} + + +FORMAT_SUPPORT :: enum i32 { // TODO: make bit_set + BUFFER = 1, + IA_VERTEX_BUFFER = 2, + IA_INDEX_BUFFER = 4, + SO_BUFFER = 8, + TEXTURE1D = 16, + TEXTURE2D = 32, + TEXTURE3D = 64, + TEXTURECUBE = 128, + SHADER_LOAD = 256, + SHADER_SAMPLE = 512, + SHADER_SAMPLE_COMPARISON = 1024, + SHADER_SAMPLE_MONO_TEXT = 2048, + MIP = 4096, + MIP_AUTOGEN = 8192, + RENDER_TARGET = 16384, + BLENDABLE = 32768, + DEPTH_STENCIL = 65536, + CPU_LOCKABLE = 131072, + MULTISAMPLE_RESOLVE = 262144, + DISPLAY = 524288, + CAST_WITHIN_BIT_LAYOUT = 1048576, + MULTISAMPLE_RENDERTARGET = 2097152, + MULTISAMPLE_LOAD = 4194304, + SHADER_GATHER = 8388608, + BACK_BUFFER_CAST = 16777216, + TYPED_UNORDERED_ACCESS_VIEW = 33554432, + SHADER_GATHER_COMPARISON = 67108864, + DECODER_OUTPUT = 134217728, + VIDEO_PROCESSOR_OUTPUT = 268435456, + VIDEO_PROCESSOR_INPUT = 536870912, + VIDEO_ENCODER = 1073741824, +} + +FORMAT_SUPPORT2 :: enum i32 { // TODO: make bit_set + UAV_ATOMIC_ADD = 1, + UAV_ATOMIC_BITWISE_OPS = 2, + UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 4, + UAV_ATOMIC_EXCHANGE = 8, + UAV_ATOMIC_SIGNED_MIN_OR_MAX = 16, + UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 32, + UAV_TYPED_LOAD = 64, + UAV_TYPED_STORE = 128, + OUTPUT_MERGER_LOGIC_OP = 256, + TILED = 512, + SHAREABLE = 1024, + MULTIPLANE_OVERLAY = 16384, +} + + +IAsynchronous_UUID :: "4B35D0CD-1E15-4258-9C98-1B1333F6DD3B" +IAsynchronous :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11asynchronous_vtable: ^IAsynchronous_VTable, +} +IAsynchronous_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetDataSize: proc "stdcall" (this: ^IAsynchronous) -> u32, +} + + +ASYNC_GETDATA_FLAG :: enum u32 { // TODO: make bit_set + DONOTFLUSH = 0x1, +} + +QUERY :: enum i32 { + EVENT = 0, + OCCLUSION = 1, + TIMESTAMP = 2, + TIMESTAMP_DISJOINT = 3, + PIPELINE_STATISTICS = 4, + OCCLUSION_PREDICATE = 5, + SO_STATISTICS = 6, + SO_OVERFLOW_PREDICATE = 7, + SO_STATISTICS_STREAM0 = 8, + SO_OVERFLOW_PREDICATE_STREAM0 = 9, + SO_STATISTICS_STREAM1 = 10, + SO_OVERFLOW_PREDICATE_STREAM1 = 11, + SO_STATISTICS_STREAM2 = 12, + SO_OVERFLOW_PREDICATE_STREAM2 = 13, + SO_STATISTICS_STREAM3 = 14, + SO_OVERFLOW_PREDICATE_STREAM3 = 15, +} + +QUERY_MISC_FLAG :: enum u32 { // TODO: make bit_set + QUERY_MISC_PREDICATEHINT = 0x1, +} + +QUERY_DESC :: struct { + Query: QUERY, + MiscFlags: RESOURCE_MISC_FLAG, +} + +CQUERY_DESC :: struct { + using d3d11_query_desc: QUERY_DESC, +} + + +IQuery_UUID :: "D6C00747-87B7-425E-B84D-44D108560AFD" +IQuery :: struct #raw_union { + #subtype id3d11asynchronous: IAsynchronous, + using id3d11query_vtable: ^IQuery_VTable, +} +IQuery_VTable :: struct { + using id3d11asynchronous_vtable: IAsynchronous_VTable, + GetDesc: proc "stdcall" (this: ^IQuery, pDesc: ^QUERY_DESC), +} + + + +IPredicate_UUID :: "9EB576DD-9F77-4D86-81AA-8BAB5FE490E2" +IPredicate :: struct { + using id3d11query: IQuery, +} + +QUERY_DATA_TIMESTAMP_DISJOINT :: struct { + Frequency: u64, + Disjoint: BOOL, +} + +QUERY_DATA_PIPELINE_STATISTICS :: struct { + IAVertices: u64, + IAPrimitives: u64, + VSInvocations: u64, + GSInvocations: u64, + GSPrimitives: u64, + CInvocations: u64, + CPrimitives: u64, + PSInvocations: u64, + HSInvocations: u64, + DSInvocations: u64, + CSInvocations: u64, +} + +QUERY_DATA_SO_STATISTICS :: struct { + NumPrimitivesWritten: u64, + PrimitivesStorageNeeded: u64, +} + +COUNTER :: enum i32 { + DEVICE_DEPENDENT_0 = 1073741824, +} + +COUNTER_TYPE :: enum i32 { + FLOAT32 = 0, + UINT16 = 1, + UINT32 = 2, + UINT64 = 3, +} + +COUNTER_DESC :: struct { + Counter: COUNTER, + MiscFlags: RESOURCE_MISC_FLAG, +} + +CCOUNTER_DESC :: struct { + using d3d11_counter_desc: COUNTER_DESC, +} + +COUNTER_INFO :: struct { + LastDeviceDependentCounter: COUNTER, + NumSimultaneousCounters: u32, + NumDetectableParallelUnits: u8, +} + + +ICounter_UUID :: "6E8C49FB-A371-4770-B440-29086022B741" +ICounter :: struct #raw_union { + #subtype id3d11asynchronous: IAsynchronous, + using id3d11counter_vtable: ^ICounter_VTable, +} +ICounter_VTable :: struct { + using id3d11asynchronous_vtable: IAsynchronous_VTable, + GetDesc: proc "stdcall" (this: ^ICounter, pDesc: ^COUNTER_DESC), +} + + +STANDARD_MULTISAMPLE_QUALITY_LEVELS :: enum i32 { + STANDARD_MULTISAMPLE_PATTERN = -1, + CENTER_MULTISAMPLE_PATTERN = -2, +} + +DEVICE_CONTEXT_TYPE :: enum i32 { + IMMEDIATE = 0, + DEFERRED = 1, +} + +CLASS_INSTANCE_DESC :: struct { + InstanceId: u32, + InstanceIndex: u32, + TypeId: u32, + ConstantBuffer: u32, + BaseConstantBufferOffset: u32, + BaseTexture: u32, + BaseSampler: u32, + Created: BOOL, +} + + +IClassInstance_UUID :: "A6CD7FAA-B0B7-4A2F-9436-8662A65797CB" +IClassInstance :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11classinstance_vtable: ^IClassInstance_VTable, +} +IClassInstance_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetClassLinkage: proc "stdcall" (this: ^IClassInstance, ppLinkage: ^^IClassLinkage), + GetDesc: proc "stdcall" (this: ^IClassInstance, pDesc: ^CLASS_INSTANCE_DESC), + GetInstanceName: proc "stdcall" (this: ^IClassInstance, pInstanceName: cstring, pBufferLength: ^SIZE_T), + GetTypeName: proc "stdcall" (this: ^IClassInstance, pTypeName: cstring, pBufferLength: ^SIZE_T), +} + + + +IClassLinkage_UUID :: "DDF57CBA-9543-46E4-A12B-F207A0FE7FED" +IClassLinkage :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11classlinkage_vtable: ^IClassLinkage_VTable, +} +IClassLinkage_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetClassInstance: proc "stdcall" (this: ^IClassLinkage, pClassInstanceName: cstring, InstanceIndex: u32, ppInstance: ^^IClassInstance) -> HRESULT, + CreateClassInstance: proc "stdcall" (this: ^IClassLinkage, pClassTypeName: cstring, ConstantBufferOffset: u32, ConstantVectorOffset: u32, TextureOffset: u32, SamplerOffset: u32, ppInstance: ^^IClassInstance) -> HRESULT, +} + + + +ICommandList_UUID :: "A24BC4D1-769E-43F7-8013-98FF566C18E2" +ICommandList :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11commandlist_vtable: ^ICommandList_VTable, +} +ICommandList_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetContextFlags: proc "stdcall" (this: ^ICommandList) -> u32, +} + + +FEATURE :: enum i32 { + THREADING = 0, + DOUBLES = 1, + FORMAT_SUPPORT = 2, + FORMAT_SUPPORT2 = 3, + D3D10_X_HARDWARE_OPTIONS = 4, + OPTIONS = 5, + ARCHITECTURE_INFO = 6, + D3D9_OPTIONS = 7, + SHADER_MIN_PRECISION_SUPPORT = 8, + D3D9_SHADOW_SUPPORT = 9, + OPTIONS1 = 10, + D3D9_SIMPLE_INSTANCING_SUPPORT = 11, + MARKER_SUPPORT = 12, + D3D9_OPTIONS1 = 13, + OPTIONS2 = 14, + OPTIONS3 = 15, + GPU_VIRTUAL_ADDRESS_SUPPORT = 16, + OPTIONS4 = 17, + SHADER_CACHE = 18, + OPTIONS5 = 19, +} + +FEATURE_DATA_THREADING :: struct { + DriverConcurrentCreates: BOOL, + DriverCommandLists: BOOL, +} + +FEATURE_DATA_DOUBLES :: struct { + DoublePrecisionFloatShaderOps: BOOL, +} + +FEATURE_DATA_FORMAT_SUPPORT :: struct { + InFormat: dxgi.FORMAT, + OutFormatSupport: u32, +} + +FEATURE_DATA_FORMAT_SUPPORT2 :: struct { + InFormat: dxgi.FORMAT, + OutFormatSupport2: u32, +} + +FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS :: struct { + ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x: BOOL, +} + +FEATURE_DATA_OPTIONS :: struct { + OutputMergerLogicOp: BOOL, + UAVOnlyRenderingForcedSampleCount: BOOL, + DiscardAPIsSeenByDriver: BOOL, + FlagsForUpdateAndCopySeenByDriver: BOOL, + ClearView: BOOL, + CopyWithOverlap: BOOL, + ConstantBufferPartialUpdate: BOOL, + ConstantBufferOffsetting: BOOL, + MapNoOverwriteOnDynamicConstantBuffer: BOOL, + MapNoOverwriteOnDynamicBufferSRV: BOOL, + MultisampleRTVWithForcedSampleCountOne: BOOL, + SAD4ShaderInstructions: BOOL, + ExtendedDoublesShaderInstructions: BOOL, + ExtendedResourceSharing: BOOL, +} + +FEATURE_DATA_ARCHITECTURE_INFO :: struct { + TileBasedDeferredRenderer: BOOL, +} + +FEATURE_DATA_D3D9_OPTIONS :: struct { + FullNonPow2TextureSupport: BOOL, +} + +FEATURE_DATA_D3D9_SHADOW_SUPPORT :: struct { + SupportsDepthAsTextureWithLessEqualComparisonFilter: BOOL, +} + +SHADER_MIN_PRECISION_SUPPORT :: enum i32 { + _10_BIT = 1, + _16_BIT = 2, +} + +FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT :: struct { + PixelShaderMinPrecision: u32, + AllOtherShaderStagesMinPrecision: u32, +} + +TILED_RESOURCES_TIER :: enum i32 { + TILED_RESOURCES_NOT_SUPPORTED = 0, + _1 = 1, + _2 = 2, + _3 = 3, +} + +FEATURE_DATA_OPTIONS1 :: struct { + TiledResourcesTier: TILED_RESOURCES_TIER, + MinMaxFiltering: BOOL, + ClearViewAlsoSupportsDepthOnlyFormats: BOOL, + MapOnDefaultBuffers: BOOL, +} + +FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT :: struct { + SimpleInstancingSupported: BOOL, +} + +FEATURE_DATA_MARKER_SUPPORT :: struct { + Profile: BOOL, +} + +FEATURE_DATA_D3D9_OPTIONS1 :: struct { + FullNonPow2TextureSupported: BOOL, + DepthAsTextureWithLessEqualComparisonFilterSupported: BOOL, + SimpleInstancingSupported: BOOL, + TextureCubeFaceRenderTargetWithNonCubeDepthStencilSupported: BOOL, +} + +CONSERVATIVE_RASTERIZATION_TIER :: enum i32 { + CONSERVATIVE_RASTERIZATION_NOT_SUPPORTED = 0, + _1 = 1, + _2 = 2, + _3 = 3, +} + +FEATURE_DATA_OPTIONS2 :: struct { + PSSpecifiedStencilRefSupported: BOOL, + TypedUAVLoadAdditionalFormats: BOOL, + ROVsSupported: BOOL, + ConservativeRasterizationTier: CONSERVATIVE_RASTERIZATION_TIER, + TiledResourcesTier: TILED_RESOURCES_TIER, + MapOnDefaultTextures: BOOL, + StandardSwizzle: BOOL, + UnifiedMemoryArchitecture: BOOL, +} + +FEATURE_DATA_OPTIONS3 :: struct { + VPAndRTArrayIndexFromAnyShaderFeedingRasterizer: BOOL, +} + +FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT :: struct { + MaxGPUVirtualAddressBitsPerResource: u32, + MaxGPUVirtualAddressBitsPerProcess: u32, +} + +SHADER_CACHE_SUPPORT_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + AUTOMATIC_INPROC_CACHE = 0x1, + AUTOMATIC_DISK_CACHE = 0x2, +} + +FEATURE_DATA_SHADER_CACHE :: struct { + SupportFlags: u32, +} + +SHARED_RESOURCE_TIER :: enum i32 { + _0 = 0, + _1 = 1, + _2 = 2, + _3 = 3, +} + +FEATURE_DATA_OPTIONS5 :: struct { + SharedResourceTier: SHARED_RESOURCE_TIER, +} + + +IDeviceContext_UUID :: "C0BFA96C-E089-44FB-8EAF-26F8796190DA" +IDeviceContext :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11devicecontext_vtable: ^IDeviceContext_VTable, +} +IDeviceContext_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + VSSetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + PSSetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + PSSetShader: proc "stdcall" (this: ^IDeviceContext, pPixelShader: ^IPixelShader, ppClassInstances: ^^IClassInstance, NumClassInstances: u32), + PSSetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + VSSetShader: proc "stdcall" (this: ^IDeviceContext, pVertexShader: ^IVertexShader, ppClassInstances: ^^IClassInstance, NumClassInstances: u32), + DrawIndexed: proc "stdcall" (this: ^IDeviceContext, IndexCount: u32, StartIndexLocation: u32, BaseVertexLocation: i32), + Draw: proc "stdcall" (this: ^IDeviceContext, VertexCount: u32, StartVertexLocation: u32), + Map: proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource, Subresource: u32, MapType: MAP, MapFlags: u32, pMappedResource: ^MAPPED_SUBRESOURCE) -> HRESULT, + Unmap: proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource, Subresource: u32), + PSSetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + IASetInputLayout: proc "stdcall" (this: ^IDeviceContext, pInputLayout: ^IInputLayout), + IASetVertexBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppVertexBuffers: ^^IBuffer, pStrides: ^u32, pOffsets: ^u32), + IASetIndexBuffer: proc "stdcall" (this: ^IDeviceContext, pIndexBuffer: ^IBuffer, Format: dxgi.FORMAT, Offset: u32), + DrawIndexedInstanced: proc "stdcall" (this: ^IDeviceContext, IndexCountPerInstance: u32, InstanceCount: u32, StartIndexLocation: u32, BaseVertexLocation: i32, StartInstanceLocation: u32), + DrawInstanced: proc "stdcall" (this: ^IDeviceContext, VertexCountPerInstance: u32, InstanceCount: u32, StartVertexLocation: u32, StartInstanceLocation: u32), + GSSetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + GSSetShader: proc "stdcall" (this: ^IDeviceContext, pShader: ^IGeometryShader, ppClassInstances: ^^IClassInstance, NumClassInstances: u32), + IASetPrimitiveTopology: proc "stdcall" (this: ^IDeviceContext, Topology: PRIMITIVE_TOPOLOGY), + VSSetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + VSSetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + Begin: proc "stdcall" (this: ^IDeviceContext, pAsync: ^IAsynchronous), + End: proc "stdcall" (this: ^IDeviceContext, pAsync: ^IAsynchronous), + GetData: proc "stdcall" (this: ^IDeviceContext, pAsync: ^IAsynchronous, pData: rawptr, DataSize: u32, GetDataFlags: u32) -> HRESULT, + SetPredication: proc "stdcall" (this: ^IDeviceContext, pPredicate: ^IPredicate, PredicateValue: BOOL), + GSSetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + GSSetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + OMSetRenderTargets: proc "stdcall" (this: ^IDeviceContext, NumViews: u32, ppRenderTargetViews: ^^IRenderTargetView, pDepthStencilView: ^IDepthStencilView), + OMSetRenderTargetsAndUnorderedAccessViews: proc "stdcall" (this: ^IDeviceContext, NumRTVs: u32, ppRenderTargetViews: ^^IRenderTargetView, pDepthStencilView: ^IDepthStencilView, UAVStartSlot: u32, NumUAVs: u32, ppUnorderedAccessViews: ^^IUnorderedAccessView, pUAVInitialCounts: ^u32), + OMSetBlendState: proc "stdcall" (this: ^IDeviceContext, pBlendState: ^IBlendState, BlendFactor: ^[4]f32, SampleMask: u32), + OMSetDepthStencilState: proc "stdcall" (this: ^IDeviceContext, pDepthStencilState: ^IDepthStencilState, StencilRef: u32), + SOSetTargets: proc "stdcall" (this: ^IDeviceContext, NumBuffers: u32, ppSOTargets: ^^IBuffer, pOffsets: ^u32), + DrawAuto: proc "stdcall" (this: ^IDeviceContext), + DrawIndexedInstancedIndirect: proc "stdcall" (this: ^IDeviceContext, pBufferForArgs: ^IBuffer, AlignedByteOffsetForArgs: u32), + DrawInstancedIndirect: proc "stdcall" (this: ^IDeviceContext, pBufferForArgs: ^IBuffer, AlignedByteOffsetForArgs: u32), + Dispatch: proc "stdcall" (this: ^IDeviceContext, ThreadGroupCountX: u32, ThreadGroupCountY: u32, ThreadGroupCountZ: u32), + DispatchIndirect: proc "stdcall" (this: ^IDeviceContext, pBufferForArgs: ^IBuffer, AlignedByteOffsetForArgs: u32), + RSSetState: proc "stdcall" (this: ^IDeviceContext, pRasterizerState: ^IRasterizerState), + RSSetViewports: proc "stdcall" (this: ^IDeviceContext, NumViewports: u32, pViewports: ^VIEWPORT), + RSSetScissorRects: proc "stdcall" (this: ^IDeviceContext, NumRects: u32, pRects: ^RECT), + CopySubresourceRegion: proc "stdcall" (this: ^IDeviceContext, pDstResource: ^IResource, DstSubresource: u32, DstX: u32, DstY: u32, DstZ: u32, pSrcResource: ^IResource, SrcSubresource: u32, pSrcBox: ^BOX), + CopyResource: proc "stdcall" (this: ^IDeviceContext, pDstResource: ^IResource, pSrcResource: ^IResource), + UpdateSubresource: proc "stdcall" (this: ^IDeviceContext, pDstResource: ^IResource, DstSubresource: u32, pDstBox: ^BOX, pSrcData: rawptr, SrcRowPitch: u32, SrcDepthPitch: u32), + CopyStructureCount: proc "stdcall" (this: ^IDeviceContext, pDstBuffer: ^IBuffer, DstAlignedByteOffset: u32, pSrcView: ^IUnorderedAccessView), + ClearRenderTargetView: proc "stdcall" (this: ^IDeviceContext, pRenderTargetView: ^IRenderTargetView, ColorRGBA: ^[4]f32), + ClearUnorderedAccessViewUint: proc "stdcall" (this: ^IDeviceContext, pUnorderedAccessView: ^IUnorderedAccessView, Values: ^[4]u32), + ClearUnorderedAccessViewFloat: proc "stdcall" (this: ^IDeviceContext, pUnorderedAccessView: ^IUnorderedAccessView, Values: ^[4]f32), + ClearDepthStencilView: proc "stdcall" (this: ^IDeviceContext, pDepthStencilView: ^IDepthStencilView, ClearFlags: u32, Depth: f32, Stencil: u8), + GenerateMips: proc "stdcall" (this: ^IDeviceContext, pShaderResourceView: ^IShaderResourceView), + SetResourceMinLOD: proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource, MinLOD: f32), + GetResourceMinLOD: proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource) -> f32, + ResolveSubresource: proc "stdcall" (this: ^IDeviceContext, pDstResource: ^IResource, DstSubresource: u32, pSrcResource: ^IResource, SrcSubresource: u32, Format: dxgi.FORMAT), + ExecuteCommandList: proc "stdcall" (this: ^IDeviceContext, pCommandList: ^ICommandList, RestoreContextState: BOOL), + HSSetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + HSSetShader: proc "stdcall" (this: ^IDeviceContext, pHullShader: ^IHullShader, ppClassInstances: ^^IClassInstance, NumClassInstances: u32), + HSSetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + HSSetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + DSSetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + DSSetShader: proc "stdcall" (this: ^IDeviceContext, pDomainShader: ^IDomainShader, ppClassInstances: ^^IClassInstance, NumClassInstances: u32), + DSSetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + DSSetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + CSSetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + CSSetUnorderedAccessViews: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumUAVs: u32, ppUnorderedAccessViews: ^^IUnorderedAccessView, pUAVInitialCounts: ^u32), + CSSetShader: proc "stdcall" (this: ^IDeviceContext, pComputeShader: ^IComputeShader, ppClassInstances: ^^IClassInstance, NumClassInstances: u32), + CSSetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + CSSetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + VSGetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + PSGetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + PSGetShader: proc "stdcall" (this: ^IDeviceContext, ppPixelShader: ^^IPixelShader, ppClassInstances: ^^IClassInstance, pNumClassInstances: ^u32), + PSGetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + VSGetShader: proc "stdcall" (this: ^IDeviceContext, ppVertexShader: ^^IVertexShader, ppClassInstances: ^^IClassInstance, pNumClassInstances: ^u32), + PSGetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + IAGetInputLayout: proc "stdcall" (this: ^IDeviceContext, ppInputLayout: ^^IInputLayout), + IAGetVertexBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppVertexBuffers: ^^IBuffer, pStrides: ^u32, pOffsets: ^u32), + IAGetIndexBuffer: proc "stdcall" (this: ^IDeviceContext, pIndexBuffer: ^^IBuffer, Format: ^dxgi.FORMAT, Offset: ^u32), + GSGetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + GSGetShader: proc "stdcall" (this: ^IDeviceContext, ppGeometryShader: ^^IGeometryShader, ppClassInstances: ^^IClassInstance, pNumClassInstances: ^u32), + IAGetPrimitiveTopology: proc "stdcall" (this: ^IDeviceContext, pTopology: ^PRIMITIVE_TOPOLOGY), + VSGetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + VSGetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + GetPredication: proc "stdcall" (this: ^IDeviceContext, ppPredicate: ^^IPredicate, pPredicateValue: ^BOOL), + GSGetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + GSGetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + OMGetRenderTargets: proc "stdcall" (this: ^IDeviceContext, NumViews: u32, ppRenderTargetViews: ^^IRenderTargetView, ppDepthStencilView: ^^IDepthStencilView), + OMGetRenderTargetsAndUnorderedAccessViews: proc "stdcall" (this: ^IDeviceContext, NumRTVs: u32, ppRenderTargetViews: ^^IRenderTargetView, ppDepthStencilView: ^^IDepthStencilView, UAVStartSlot: u32, NumUAVs: u32, ppUnorderedAccessViews: ^^IUnorderedAccessView), + OMGetBlendState: proc "stdcall" (this: ^IDeviceContext, ppBlendState: ^^IBlendState, BlendFactor: ^[4]f32, pSampleMask: ^u32), + OMGetDepthStencilState: proc "stdcall" (this: ^IDeviceContext, ppDepthStencilState: ^^IDepthStencilState, pStencilRef: ^u32), + SOGetTargets: proc "stdcall" (this: ^IDeviceContext, NumBuffers: u32, ppSOTargets: ^^IBuffer), + RSGetState: proc "stdcall" (this: ^IDeviceContext, ppRasterizerState: ^^IRasterizerState), + RSGetViewports: proc "stdcall" (this: ^IDeviceContext, pNumViewports: ^u32, pViewports: ^VIEWPORT), + RSGetScissorRects: proc "stdcall" (this: ^IDeviceContext, pNumRects: ^u32, pRects: ^RECT), + HSGetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + HSGetShader: proc "stdcall" (this: ^IDeviceContext, ppHullShader: ^^IHullShader, ppClassInstances: ^^IClassInstance, pNumClassInstances: ^u32), + HSGetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + HSGetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + DSGetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + DSGetShader: proc "stdcall" (this: ^IDeviceContext, ppDomainShader: ^^IDomainShader, ppClassInstances: ^^IClassInstance, pNumClassInstances: ^u32), + DSGetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + DSGetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + CSGetShaderResources: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumViews: u32, ppShaderResourceViews: ^^IShaderResourceView), + CSGetUnorderedAccessViews: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumUAVs: u32, ppUnorderedAccessViews: ^^IUnorderedAccessView), + CSGetShader: proc "stdcall" (this: ^IDeviceContext, ppComputeShader: ^^IComputeShader, ppClassInstances: ^^IClassInstance, pNumClassInstances: ^u32), + CSGetSamplers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState), + CSGetConstantBuffers: proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer), + ClearState: proc "stdcall" (this: ^IDeviceContext), + Flush: proc "stdcall" (this: ^IDeviceContext), + GetType: proc "stdcall" (this: ^IDeviceContext) -> DEVICE_CONTEXT_TYPE, + GetContextFlags: proc "stdcall" (this: ^IDeviceContext) -> u32, + FinishCommandList: proc "stdcall" (this: ^IDeviceContext, RestoreDeferredContextState: BOOL, ppCommandList: ^^ICommandList) -> HRESULT, +} + + +CVIDEO_DEFAULT :: struct { + _: u8, +} + +APP_DEPRECATED_HRESULT :: HRESULT + + +VIDEO_DECODER_DESC :: struct { + Guid: GUID, + SampleWidth: u32, + SampleHeight: u32, + OutputFormat: dxgi.FORMAT, +} + +VIDEO_DECODER_CONFIG :: struct { + guidConfigBitstreamEncryption: GUID, + guidConfigMBcontrolEncryption: GUID, + guidConfigResidDiffEncryption: GUID, + ConfigBitstreamRaw: u32, + ConfigMBcontrolRasterOrder: u32, + ConfigResidDiffHost: u32, + ConfigSpatialResid8: u32, + ConfigResid8Subtraction: u32, + ConfigSpatialHost8or9Clipping: u32, + ConfigSpatialResidInterleaved: u32, + ConfigIntraResidUnsigned: u32, + ConfigResidDiffAccelerator: u32, + ConfigHostInverseScan: u32, + ConfigSpecificIDCT: u32, + Config4GroupedCoefs: u32, + ConfigMinRenderTargetBuffCount: u16, + ConfigDecoderSpecific: u16, +} + +VIDEO_DECODER_BUFFER_TYPE :: enum i32 { + PICTURE_PARAMETERS = 0, + MACROBLOCK_CONTROL = 1, + RESIDUAL_DIFFERENCE = 2, + DEBLOCKING_CONTROL = 3, + INVERSE_QUANTIZATION_MATRIX = 4, + SLICE_CONTROL = 5, + BITSTREAM = 6, + MOTION_VECTOR = 7, + FILM_GRAIN = 8, +} + +AES_CTR_IV :: struct { + IV: u64, + Count: u64, +} + +ENCRYPTED_BLOCK_INFO :: struct { + NumEncryptedBytesAtBeginning: u32, + NumBytesInSkipPattern: u32, + NumBytesInEncryptPattern: u32, +} + +VIDEO_DECODER_BUFFER_DESC :: struct { + BufferType: VIDEO_DECODER_BUFFER_TYPE, + BufferIndex: u32, + DataOffset: u32, + DataSize: u32, + FirstMBaddress: u32, + NumMBsInBuffer: u32, + Width: u32, + Height: u32, + Stride: u32, + ReservedBits: u32, + + pIV: rawptr, + IVSize: u32, + PartialEncryption: BOOL, + EncryptedBlockInfo: ENCRYPTED_BLOCK_INFO, +} + +VIDEO_DECODER_EXTENSION :: struct { + Function: u32, + + pPrivateInputData: rawptr, + PrivateInputDataSize: u32, + + pPrivateOutputData: rawptr, + PrivateOutputDataSize: u32, + ResourceCount: u32, + + ppResourceList: ^^IResource, +} + + +IVideoDecoder_UUID :: "3C9C5B51-995D-48D1-9B8D-FA5CAEDED65C" +IVideoDecoder :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11videodecoder_vtable: ^IVideoDecoder_VTable, +} +IVideoDecoder_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetCreationParameters: proc "stdcall" (this: ^IVideoDecoder, pVideoDesc: ^VIDEO_DECODER_DESC, pConfig: ^VIDEO_DECODER_CONFIG) -> HRESULT, + GetDriverHandle: proc "stdcall" (this: ^IVideoDecoder, pDriverHandle: ^HANDLE) -> HRESULT, +} + + +VIDEO_PROCESSOR_FORMAT_SUPPORT :: enum i32 { + INPUT = 1, + OUTPUT = 2, +} + +VIDEO_PROCESSOR_DEVICE_CAPS :: enum i32 { // TODO: make bit_set + LINEAR_SPACE = 1, + xvYCC = 2, + RGB_RANGE_CONVERSION = 4, + YCbCr_MATRIX_CONVERSION = 8, + NOMINAL_RANGE = 16, +} + +VIDEO_PROCESSOR_FEATURE_CAPS :: enum i32 { // TODO: make bit_set + ALPHA_FILL = 1, + CONSTRICTION = 2, + LUMA_KEY = 4, + ALPHA_PALETTE = 8, + LEGACY = 16, + STEREO = 32, + ROTATION = 64, + ALPHA_STREAM = 128, + PIXEL_ASPECT_RATIO = 256, + MIRROR = 512, + SHADER_USAGE = 1024, + METADATA_HDR10 = 2048, +} + +VIDEO_PROCESSOR_FILTER_CAPS :: enum i32 { // TODO: make bit_set + BRIGHTNESS = 1, + CONTRAST = 2, + HUE = 4, + SATURATION = 8, + NOISE_REDUCTION = 16, + EDGE_ENHANCEMENT = 32, + ANAMORPHIC_SCALING = 64, + STEREO_ADJUSTMENT = 128, +} + +VIDEO_PROCESSOR_FORMAT_CAPS :: enum i32 { // TODO: make bit_set + RGB_INTERLACED = 1, + RGB_PROCAMP = 2, + RGB_LUMA_KEY = 4, + PALETTE_INTERLACED = 8, +} + +VIDEO_PROCESSOR_AUTO_STREAM_CAPS :: enum i32 { // TODO: make bit_set + DENOISE = 1, + DERINGING = 2, + EDGE_ENHANCEMENT = 4, + COLOR_CORRECTION = 8, + FLESH_TONE_MAPPING = 16, + IMAGE_STABILIZATION = 32, + SUPER_RESOLUTION = 64, + ANAMORPHIC_SCALING = 128, +} + +VIDEO_PROCESSOR_STEREO_CAPS :: enum i32 { // TODO: make bit_set + MONO_OFFSET = 1, + ROW_INTERLEAVED = 2, + COLUMN_INTERLEAVED = 4, + CHECKERBOARD = 8, + FLIP_MODE = 16, +} + +VIDEO_PROCESSOR_CAPS :: struct { + DeviceCaps: u32, + FeatureCaps: u32, + FilterCaps: u32, + InputFormatCaps: u32, + AutoStreamCaps: u32, + StereoCaps: u32, + RateConversionCapsCount: u32, + MaxInputStreams: u32, + MaxStreamStates: u32, +} + +VIDEO_PROCESSOR_PROCESSOR_CAPS :: enum i32 { // TODO: make bit_set + DEINTERLACE_BLEND = 1, + DEINTERLACE_BOB = 2, + DEINTERLACE_ADAPTIVE = 4, + DEINTERLACE_MOTION_COMPENSATION = 8, + INVERSE_TELECINE = 16, + FRAME_RATE_CONVERSION = 32, +} + +VIDEO_PROCESSOR_ITELECINE_CAPS :: enum i32 { + _32 = 1, + _22 = 2, + _2224 = 4, + _2332 = 8, + _32322 = 16, + _55 = 32, + _64 = 64, + _87 = 128, + _222222222223 = 256, + OTHER = -2147483648, +} + +VIDEO_PROCESSOR_RATE_CONVERSION_CAPS :: struct { + PastFrames: u32, + FutureFrames: u32, + ProcessorCaps: u32, + ITelecineCaps: u32, + CustomRateCount: u32, +} + +CONTENT_PROTECTION_CAPS :: enum i32 { + SOFTWARE = 1, + HARDWARE = 2, + PROTECTION_ALWAYS_ON = 4, + PARTIAL_DECRYPTION = 8, + CONTENT_KEY = 16, + FRESHEN_SESSION_KEY = 32, + ENCRYPTED_READ_BACK = 64, + ENCRYPTED_READ_BACK_KEY = 128, + SEQUENTIAL_CTR_IV = 256, + ENCRYPT_SLICEDATA_ONLY = 512, + DECRYPTION_BLT = 1024, + HARDWARE_PROTECT_UNCOMPRESSED = 2048, + HARDWARE_PROTECTED_MEMORY_PAGEABLE = 4096, + HARDWARE_TEARDOWN = 8192, + HARDWARE_DRM_COMMUNICATION = 16384, + HARDWARE_DRM_COMMUNICATION_MULTI_THREADED = 32768, +} + + +VIDEO_CONTENT_PROTECTION_CAPS :: struct { + Caps: u32, + KeyExchangeTypeCount: u32, + BlockAlignmentSize: u32, + ProtectedMemorySize: u64, +} + +VIDEO_PROCESSOR_CUSTOM_RATE :: struct { + CustomRate: dxgi.RATIONAL, + OutputFrames: u32, + InputInterlaced: BOOL, + InputFramesOrFields: u32, +} + +VIDEO_PROCESSOR_FILTER :: enum i32 { + BRIGHTNESS = 0, + CONTRAST = 1, + HUE = 2, + SATURATION = 3, + NOISE_REDUCTION = 4, + EDGE_ENHANCEMENT = 5, + ANAMORPHIC_SCALING = 6, + STEREO_ADJUSTMENT = 7, +} + +VIDEO_PROCESSOR_FILTER_RANGE :: struct { + Minimum: i32, + Maximum: i32, + Default: i32, + Multiplier: f32, +} + +VIDEO_FRAME_FORMAT :: enum i32 { + PROGRESSIVE = 0, + INTERLACED_TOP_FIELD_FIRST = 1, + INTERLACED_BOTTOM_FIELD_FIRST = 2, +} + +VIDEO_USAGE :: enum i32 { + PLAYBACK_NORMAL = 0, + OPTIMAL_SPEED = 1, + OPTIMAL_QUALITY = 2, +} + +VIDEO_PROCESSOR_CONTENT_DESC :: struct { + InputFrameFormat: VIDEO_FRAME_FORMAT, + InputFrameRate: dxgi.RATIONAL, + InputWidth: u32, + InputHeight: u32, + OutputFrameRate: dxgi.RATIONAL, + OutputWidth: u32, + OutputHeight: u32, + Usage: VIDEO_USAGE, +} + + +IVideoProcessorEnumerator_UUID :: "31627037-53AB-4200-9061-05FAA9AB45F9" +IVideoProcessorEnumerator :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11videoprocessorenumerator_vtable: ^IVideoProcessorEnumerator_VTable, +} +IVideoProcessorEnumerator_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetVideoProcessorContentDesc: proc "stdcall" (this: ^IVideoProcessorEnumerator, pContentDesc: ^VIDEO_PROCESSOR_CONTENT_DESC) -> HRESULT, + CheckVideoProcessorFormat: proc "stdcall" (this: ^IVideoProcessorEnumerator, Format: dxgi.FORMAT, pFlags: ^u32) -> HRESULT, + GetVideoProcessorCaps: proc "stdcall" (this: ^IVideoProcessorEnumerator, pCaps: ^VIDEO_PROCESSOR_CAPS) -> HRESULT, + GetVideoProcessorRateConversionCaps: proc "stdcall" (this: ^IVideoProcessorEnumerator, TypeIndex: u32, pCaps: ^VIDEO_PROCESSOR_RATE_CONVERSION_CAPS) -> HRESULT, + GetVideoProcessorCustomRate: proc "stdcall" (this: ^IVideoProcessorEnumerator, TypeIndex: u32, CustomRateIndex: u32, pRate: ^VIDEO_PROCESSOR_CUSTOM_RATE) -> HRESULT, + GetVideoProcessorFilterRange: proc "stdcall" (this: ^IVideoProcessorEnumerator, Filter: VIDEO_PROCESSOR_FILTER, pRange: ^VIDEO_PROCESSOR_FILTER_RANGE) -> HRESULT, +} + + +VIDEO_COLOR_RGBA :: struct { + R: f32, + G: f32, + B: f32, + A: f32, +} + +VIDEO_COLOR_YCbCrA :: struct { + Y: f32, + Cb: f32, + Cr: f32, + A: f32, +} + +VIDEO_COLOR :: struct { + using _: struct #raw_union { + YCbCr: VIDEO_COLOR_YCbCrA, + RGBA: VIDEO_COLOR_RGBA, + }, +} + +VIDEO_PROCESSOR_NOMINAL_RANGE :: enum i32 { + UNDEFINED = 0, + _16_235 = 1, + _0_255 = 2, +} + +VIDEO_PROCESSOR_COLOR_SPACE_FLAG :: enum u32 { + Usage = 0, + RGB_Range = 1, + YCbCr_Matrix = 2, + YCbCr_xvYCC = 3, + Nominal_Range = 4, + Reserved = 6, +} + +VIDEO_PROCESSOR_COLOR_SPACE :: distinct bit_set[VIDEO_PROCESSOR_COLOR_SPACE_FLAG; u32] + +VIDEO_PROCESSOR_ALPHA_FILL_MODE :: enum i32 { + OPAQUE = 0, + BACKGROUND = 1, + DESTINATION = 2, + SOURCE_STREAM = 3, +} + +VIDEO_PROCESSOR_OUTPUT_RATE :: enum i32 { + NORMAL = 0, + HALF = 1, + CUSTOM = 2, +} + +VIDEO_PROCESSOR_STEREO_FORMAT :: enum i32 { + MONO = 0, + HORIZONTAL = 1, + VERTICAL = 2, + SEPARATE = 3, + MONO_OFFSET = 4, + ROW_INTERLEAVED = 5, + COLUMN_INTERLEAVED = 6, + CHECKERBOARD = 7, +} + +VIDEO_PROCESSOR_STEREO_FLIP_MODE :: enum i32 { + NONE = 0, + FRAME0 = 1, + FRAME1 = 2, +} + +VIDEO_PROCESSOR_ROTATION :: enum i32 { + IDENTITY = 0, + _90 = 1, + _180 = 2, + _270 = 3, +} + +VIDEO_PROCESSOR_STREAM :: struct { + Enable: BOOL, + OutputIndex: u32, + InputFrameOrField: u32, + PastFrames: u32, + FutureFrames: u32, + + ppPastSurfaces: ^^IVideoProcessorInputView, + pInputSurface: ^IVideoProcessorInputView, + + ppFutureSurfaces: ^^IVideoProcessorInputView, + + ppPastSurfacesRight: ^^IVideoProcessorInputView, + pInputSurfaceRight: ^IVideoProcessorInputView, + + ppFutureSurfacesRight: ^^IVideoProcessorInputView, +} + + +IVideoProcessor_UUID :: "1D7B0652-185F-41C6-85CE-0C5BE3D4AE6C" +IVideoProcessor :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11videoprocessor_vtable: ^IVideoProcessor_VTable, +} +IVideoProcessor_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetContentDesc: proc "stdcall" (this: ^IVideoProcessor, pDesc: ^VIDEO_PROCESSOR_CONTENT_DESC), + GetRateConversionCaps: proc "stdcall" (this: ^IVideoProcessor, pCaps: ^VIDEO_PROCESSOR_RATE_CONVERSION_CAPS), +} + + +OMAC :: struct { + Omac: [16]u8, +} + +AUTHENTICATED_CHANNEL_TYPE :: enum i32 { + D3D11 = 1, + DRIVER_SOFTWARE = 2, + DRIVER_HARDWARE = 3, +} + + +IAuthenticatedChannel_UUID :: "3015A308-DCBD-47AA-A747-192486D14D4A" +IAuthenticatedChannel :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11authenticatedchannel_vtable: ^IAuthenticatedChannel_VTable, +} +IAuthenticatedChannel_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetCertificateSize: proc "stdcall" (this: ^IAuthenticatedChannel, pCertificateSize: ^u32) -> HRESULT, + GetCertificate: proc "stdcall" (this: ^IAuthenticatedChannel, CertificateSize: u32, pCertificate: cstring) -> HRESULT, + GetChannelHandle: proc "stdcall" (this: ^IAuthenticatedChannel, pChannelHandle: ^HANDLE), +} + + +AUTHENTICATED_QUERY_INPUT :: struct { + QueryType: GUID, + hChannel: HANDLE, + SequenceNumber: u32, +} + +AUTHENTICATED_QUERY_OUTPUT :: struct { + omac: OMAC, + QueryType: GUID, + hChannel: HANDLE, + SequenceNumber: u32, + ReturnCode: HRESULT, +} + +AUTHENTICATED_PROTECTION_FLAG :: enum u32 { + ProtectionEnabled = 0, + OverlayOrFullscreenRequired = 1, + Reserved = 2, +} +AUTHENTICATED_PROTECTION_FLAGS :: distinct bit_set[AUTHENTICATED_PROTECTION_FLAG; u32] + +AUTHENTICATED_QUERY_PROTECTION_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + ProtectionFlags: AUTHENTICATED_PROTECTION_FLAGS, +} + +AUTHENTICATED_QUERY_CHANNEL_TYPE_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + ChannelType: AUTHENTICATED_CHANNEL_TYPE, +} + +AUTHENTICATED_QUERY_DEVICE_HANDLE_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + DeviceHandle: HANDLE, +} + +AUTHENTICATED_QUERY_CRYPTO_SESSION_INPUT :: struct { + Input: AUTHENTICATED_QUERY_INPUT, + DecoderHandle: HANDLE, +} + +AUTHENTICATED_QUERY_CRYPTO_SESSION_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + DecoderHandle: HANDLE, + CryptoSessionHandle: HANDLE, + DeviceHandle: HANDLE, +} + +AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_COUNT_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + RestrictedSharedResourceProcessCount: u32, +} + +AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_INPUT :: struct { + Input: AUTHENTICATED_QUERY_INPUT, + ProcessIndex: u32, +} + +AUTHENTICATED_PROCESS_IDENTIFIER_TYPE :: enum i32 { + UNKNOWN = 0, + DWM = 1, + HANDLE = 2, +} + +AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + ProcessIndex: u32, + ProcessIdentifier: AUTHENTICATED_PROCESS_IDENTIFIER_TYPE, + ProcessHandle: HANDLE, +} + +AUTHENTICATED_QUERY_UNRESTRICTED_PROTECTED_SHARED_RESOURCE_COUNT_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + UnrestrictedProtectedSharedResourceCount: u32, +} + +AUTHENTICATED_QUERY_OUTPUT_ID_COUNT_INPUT :: struct { + Input: AUTHENTICATED_QUERY_INPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, +} + +AUTHENTICATED_QUERY_OUTPUT_ID_COUNT_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDCount: u32, +} + +AUTHENTICATED_QUERY_OUTPUT_ID_INPUT :: struct { + Input: AUTHENTICATED_QUERY_INPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDIndex: u32, +} + +AUTHENTICATED_QUERY_OUTPUT_ID_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDIndex: u32, + OutputID: u64, +} + +BUS_TYPE :: enum i32 { + OTHER = 0, + PCI = 1, + PCIX = 2, + PCIEXPRESS = 3, + AGP = 4, + NSIDE_OF_CHIPSET = 65536, + RACKS_ON_MOTHER_BOARD_TO_CHIP = 131072, + RACKS_ON_MOTHER_BOARD_TO_SOCKET = 196608, + AUGHTER_BOARD_CONNECTOR = 262144, + AUGHTER_BOARD_CONNECTOR_INSIDE_OF_NUAE = 327680, + ON_STANDARD = -2147483648, +} + +AUTHENTICATED_QUERY_ACESSIBILITY_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + BusType: BUS_TYPE, + AccessibleInContiguousBlocks: BOOL, + AccessibleInNonContiguousBlocks: BOOL, +} + +AUTHENTICATED_QUERY_ACCESSIBILITY_OUTPUT :: AUTHENTICATED_QUERY_ACESSIBILITY_OUTPUT + +AUTHENTICATED_QUERY_ACCESSIBILITY_ENCRYPTION_GUID_COUNT_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + EncryptionGuidCount: u32, +} + +AUTHENTICATED_QUERY_ACCESSIBILITY_ENCRYPTION_GUID_INPUT :: struct { + Input: AUTHENTICATED_QUERY_INPUT, + EncryptionGuidIndex: u32, +} + +AUTHENTICATED_QUERY_ACCESSIBILITY_ENCRYPTION_GUID_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + EncryptionGuidIndex: u32, + EncryptionGuid: GUID, +} + +AUTHENTICATED_QUERY_CURRENT_ACCESSIBILITY_ENCRYPTION_OUTPUT :: struct { + Output: AUTHENTICATED_QUERY_OUTPUT, + EncryptionGuid: GUID, +} + +AUTHENTICATED_CONFIGURE_INPUT :: struct { + omac: OMAC, + ConfigureType: GUID, + hChannel: HANDLE, + SequenceNumber: u32, +} + +AUTHENTICATED_CONFIGURE_OUTPUT :: struct { + omac: OMAC, + ConfigureType: GUID, + hChannel: HANDLE, + SequenceNumber: u32, + ReturnCode: HRESULT, +} + +AUTHENTICATED_CONFIGURE_INITIALIZE_INPUT :: struct { + Parameters: AUTHENTICATED_CONFIGURE_INPUT, + StartSequenceQuery: u32, + StartSequenceConfigure: u32, +} + +AUTHENTICATED_CONFIGURE_PROTECTION_INPUT :: struct { + Parameters: AUTHENTICATED_CONFIGURE_INPUT, + Protections: AUTHENTICATED_PROTECTION_FLAGS, +} + +AUTHENTICATED_CONFIGURE_CRYPTO_SESSION_INPUT :: struct { + Parameters: AUTHENTICATED_CONFIGURE_INPUT, + DecoderHandle: HANDLE, + CryptoSessionHandle: HANDLE, + DeviceHandle: HANDLE, +} + +AUTHENTICATED_CONFIGURE_SHARED_RESOURCE_INPUT :: struct { + Parameters: AUTHENTICATED_CONFIGURE_INPUT, + ProcessType: AUTHENTICATED_PROCESS_IDENTIFIER_TYPE, + ProcessHandle: HANDLE, + AllowAccess: BOOL, +} + +AUTHENTICATED_CONFIGURE_ACCESSIBLE_ENCRYPTION_INPUT :: struct { + Parameters: AUTHENTICATED_CONFIGURE_INPUT, + EncryptionGuid: GUID, +} + + + +ICryptoSession_UUID :: "9B32F9AD-BDCC-40A6-A39D-D5C865845720" +ICryptoSession :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11cryptosession_vtable: ^ICryptoSession_VTable, +} +ICryptoSession_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetCryptoType: proc "stdcall" (this: ^ICryptoSession, pCryptoType: ^GUID), + GetDecoderProfile: proc "stdcall" (this: ^ICryptoSession, pDecoderProfile: ^GUID), + GetCertificateSize: proc "stdcall" (this: ^ICryptoSession, pCertificateSize: ^u32) -> HRESULT, + GetCertificate: proc "stdcall" (this: ^ICryptoSession, CertificateSize: u32, pCertificate: cstring) -> HRESULT, + GetCryptoSessionHandle: proc "stdcall" (this: ^ICryptoSession, pCryptoSessionHandle: ^HANDLE), +} + + +VDOV_DIMENSION :: enum i32 { + UNKNOWN = 0, + TEXTURE2D = 1, +} + +TEX2D_VDOV :: struct { + ArraySlice: u32, +} + +VIDEO_DECODER_OUTPUT_VIEW_DESC :: struct { + DecodeProfile: GUID, + ViewDimension: VDOV_DIMENSION, + using _: struct #raw_union { + Texture2D: TEX2D_VDOV, + }, +} + + +IVideoDecoderOutputView_UUID :: "C2931AEA-2A85-4F20-860F-FBA1FD256E18" +IVideoDecoderOutputView :: struct #raw_union { + #subtype id3d11view: IView, + using id3d11videodecoderoutputview_vtable: ^IVideoDecoderOutputView_VTable, +} +IVideoDecoderOutputView_VTable :: struct { + using id3d11view_vtable: IView_VTable, + GetDesc: proc "stdcall" (this: ^IVideoDecoderOutputView, pDesc: ^VIDEO_DECODER_OUTPUT_VIEW_DESC), +} + + +VPIV_DIMENSION :: enum i32 { + UNKNOWN = 0, + TEXTURE2D = 1, +} + +TEX2D_VPIV :: struct { + MipSlice: u32, + ArraySlice: u32, +} + +VIDEO_PROCESSOR_INPUT_VIEW_DESC :: struct { + FourCC: u32, + ViewDimension: VPIV_DIMENSION, + using _: struct #raw_union { + Texture2D: TEX2D_VPIV, + }, +} + + +IVideoProcessorInputView_UUID :: "11EC5A5F-51DC-4945-AB34-6E8C21300EA5" +IVideoProcessorInputView :: struct #raw_union { + #subtype id3d11view: IView, + using id3d11videoprocessorinputview_vtable: ^IVideoProcessorInputView_VTable, +} +IVideoProcessorInputView_VTable :: struct { + using id3d11view_vtable: IView_VTable, + GetDesc: proc "stdcall" (this: ^IVideoProcessorInputView, pDesc: ^VIDEO_PROCESSOR_INPUT_VIEW_DESC), +} + + +VPOV_DIMENSION :: enum i32 { + UNKNOWN = 0, + TEXTURE2D = 1, + TEXTURE2DARRAY = 2, +} + +TEX2D_VPOV :: struct { + MipSlice: u32, +} + +TEX2D_ARRAY_VPOV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +VIDEO_PROCESSOR_OUTPUT_VIEW_DESC :: struct { + ViewDimension: VPOV_DIMENSION, + using _: struct #raw_union { + Texture2D: TEX2D_VPOV, + Texture2DArray: TEX2D_ARRAY_VPOV, + }, +} + + +IVideoProcessorOutputView_UUID :: "A048285E-25A9-4527-BD93-D68B68C44254" +IVideoProcessorOutputView :: struct #raw_union { + #subtype id3d11view: IView, + using id3d11videoprocessoroutputview_vtable: ^IVideoProcessorOutputView_VTable, +} +IVideoProcessorOutputView_VTable :: struct { + using id3d11view_vtable: IView_VTable, + GetDesc: proc "stdcall" (this: ^IVideoProcessorOutputView, pDesc: ^VIDEO_PROCESSOR_OUTPUT_VIEW_DESC), +} + + + +IVideoContext_UUID :: "61F21C45-3C0E-4A74-9CEA-67100D9AD5E4" +IVideoContext :: struct #raw_union { + #subtype id3d11devicechild: IDeviceChild, + using id3d11videocontext_vtable: ^IVideoContext_VTable, +} +IVideoContext_VTable :: struct { + using id3d11devicechild_vtable: IDeviceChild_VTable, + GetDecoderBuffer: proc "stdcall" (this: ^IVideoContext, pDecoder: ^IVideoDecoder, Type: VIDEO_DECODER_BUFFER_TYPE, pBufferSize: ^u32, ppBuffer: ^rawptr) -> HRESULT, + ReleaseDecoderBuffer: proc "stdcall" (this: ^IVideoContext, pDecoder: ^IVideoDecoder, Type: VIDEO_DECODER_BUFFER_TYPE) -> HRESULT, + DecoderBeginFrame: proc "stdcall" (this: ^IVideoContext, pDecoder: ^IVideoDecoder, pView: ^IVideoDecoderOutputView, ContentKeySize: u32, pContentKey: rawptr) -> HRESULT, + DecoderEndFrame: proc "stdcall" (this: ^IVideoContext, pDecoder: ^IVideoDecoder) -> HRESULT, + SubmitDecoderBuffers: proc "stdcall" (this: ^IVideoContext, pDecoder: ^IVideoDecoder, NumBuffers: u32, pBufferDesc: ^VIDEO_DECODER_BUFFER_DESC) -> HRESULT, + DecoderExtension: proc "stdcall" (this: ^IVideoContext, pDecoder: ^IVideoDecoder, pExtensionData: ^VIDEO_DECODER_EXTENSION) -> APP_DEPRECATED_HRESULT, + VideoProcessorSetOutputTargetRect: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, Enable: BOOL, pRect: ^RECT), + VideoProcessorSetOutputBackgroundColor: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, YCbCr: BOOL, pColor: ^VIDEO_COLOR), + VideoProcessorSetOutputColorSpace: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pColorSpace: ^VIDEO_PROCESSOR_COLOR_SPACE), + VideoProcessorSetOutputAlphaFillMode: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, AlphaFillMode: VIDEO_PROCESSOR_ALPHA_FILL_MODE, StreamIndex: u32), + VideoProcessorSetOutputConstriction: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, Enable: BOOL, Size: SIZE), + VideoProcessorSetOutputStereoMode: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, Enable: BOOL), + VideoProcessorSetOutputExtension: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pExtensionGuid: ^GUID, DataSize: u32, pData: rawptr) -> APP_DEPRECATED_HRESULT, + VideoProcessorGetOutputTargetRect: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, Enabled: ^BOOL, pRect: ^RECT), + VideoProcessorGetOutputBackgroundColor: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pYCbCr: ^BOOL, pColor: ^VIDEO_COLOR), + VideoProcessorGetOutputColorSpace: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pColorSpace: ^VIDEO_PROCESSOR_COLOR_SPACE), + VideoProcessorGetOutputAlphaFillMode: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pAlphaFillMode: ^VIDEO_PROCESSOR_ALPHA_FILL_MODE, pStreamIndex: ^u32), + VideoProcessorGetOutputConstriction: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pEnabled: ^BOOL, pSize: ^SIZE), + VideoProcessorGetOutputStereoMode: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pEnabled: ^BOOL), + VideoProcessorGetOutputExtension: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pExtensionGuid: ^GUID, DataSize: u32, pData: rawptr) -> APP_DEPRECATED_HRESULT, + VideoProcessorSetStreamFrameFormat: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, FrameFormat: VIDEO_FRAME_FORMAT), + VideoProcessorSetStreamColorSpace: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pColorSpace: ^VIDEO_PROCESSOR_COLOR_SPACE), + VideoProcessorSetStreamOutputRate: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, OutputRate: VIDEO_PROCESSOR_OUTPUT_RATE, RepeatFrame: BOOL, pCustomRate: ^dxgi.RATIONAL), + VideoProcessorSetStreamSourceRect: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL, pRect: ^RECT), + VideoProcessorSetStreamDestRect: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL, pRect: ^RECT), + VideoProcessorSetStreamAlpha: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL, Alpha: f32), + VideoProcessorSetStreamPalette: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Count: u32, pEntries: ^u32), + VideoProcessorSetStreamPixelAspectRatio: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL, pSourceAspectRatio: ^dxgi.RATIONAL, pDestinationAspectRatio: ^dxgi.RATIONAL), + VideoProcessorSetStreamLumaKey: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL, Lower: f32, Upper: f32), + VideoProcessorSetStreamStereoFormat: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL, Format: VIDEO_PROCESSOR_STEREO_FORMAT, LeftViewFrame0: BOOL, BaseViewFrame0: BOOL, FlipMode: VIDEO_PROCESSOR_STEREO_FLIP_MODE, MonoOffset: i32), + VideoProcessorSetStreamAutoProcessingMode: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL), + VideoProcessorSetStreamFilter: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Filter: VIDEO_PROCESSOR_FILTER, Enable: BOOL, Level: i32), + VideoProcessorSetStreamExtension: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pExtensionGuid: ^GUID, DataSize: u32, pData: rawptr) -> APP_DEPRECATED_HRESULT, + VideoProcessorGetStreamFrameFormat: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pFrameFormat: ^VIDEO_FRAME_FORMAT), + VideoProcessorGetStreamColorSpace: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pColorSpace: ^VIDEO_PROCESSOR_COLOR_SPACE), + VideoProcessorGetStreamOutputRate: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pOutputRate: ^VIDEO_PROCESSOR_OUTPUT_RATE, pRepeatFrame: ^BOOL, pCustomRate: ^dxgi.RATIONAL), + VideoProcessorGetStreamSourceRect: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnabled: ^BOOL, pRect: ^RECT), + VideoProcessorGetStreamDestRect: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnabled: ^BOOL, pRect: ^RECT), + VideoProcessorGetStreamAlpha: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnabled: ^BOOL, pAlpha: ^f32), + VideoProcessorGetStreamPalette: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Count: u32, pEntries: ^u32), + VideoProcessorGetStreamPixelAspectRatio: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnabled: ^BOOL, pSourceAspectRatio: ^dxgi.RATIONAL, pDestinationAspectRatio: ^dxgi.RATIONAL), + VideoProcessorGetStreamLumaKey: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnabled: ^BOOL, pLower: ^f32, pUpper: ^f32), + VideoProcessorGetStreamStereoFormat: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnable: ^BOOL, pFormat: ^VIDEO_PROCESSOR_STEREO_FORMAT, pLeftViewFrame0: ^BOOL, pBaseViewFrame0: ^BOOL, pFlipMode: ^VIDEO_PROCESSOR_STEREO_FLIP_MODE, MonoOffset: ^i32), + VideoProcessorGetStreamAutoProcessingMode: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnabled: ^BOOL), + VideoProcessorGetStreamFilter: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Filter: VIDEO_PROCESSOR_FILTER, pEnabled: ^BOOL, pLevel: ^i32), + VideoProcessorGetStreamExtension: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pExtensionGuid: ^GUID, DataSize: u32, pData: rawptr) -> APP_DEPRECATED_HRESULT, + VideoProcessorBlt: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, pView: ^IVideoProcessorOutputView, OutputFrame: u32, StreamCount: u32, pStreams: ^VIDEO_PROCESSOR_STREAM) -> HRESULT, + NegotiateCryptoSessionKeyExchange: proc "stdcall" (this: ^IVideoContext, pCryptoSession: ^ICryptoSession, DataSize: u32, pData: rawptr) -> HRESULT, + EncryptionBlt: proc "stdcall" (this: ^IVideoContext, pCryptoSession: ^ICryptoSession, pSrcSurface: ^ITexture2D, pDstSurface: ^ITexture2D, IVSize: u32, pIV: rawptr), + DecryptionBlt: proc "stdcall" (this: ^IVideoContext, pCryptoSession: ^ICryptoSession, pSrcSurface: ^ITexture2D, pDstSurface: ^ITexture2D, pEncryptedBlockInfo: ^ENCRYPTED_BLOCK_INFO, ContentKeySize: u32, pContentKey: rawptr, IVSize: u32, pIV: rawptr), + StartSessionKeyRefresh: proc "stdcall" (this: ^IVideoContext, pCryptoSession: ^ICryptoSession, RandomNumberSize: u32, pRandomNumber: rawptr), + FinishSessionKeyRefresh: proc "stdcall" (this: ^IVideoContext, pCryptoSession: ^ICryptoSession), + GetEncryptionBltKey: proc "stdcall" (this: ^IVideoContext, pCryptoSession: ^ICryptoSession, KeySize: u32, pReadbackKey: rawptr) -> HRESULT, + NegotiateAuthenticatedChannelKeyExchange: proc "stdcall" (this: ^IVideoContext, pChannel: ^IAuthenticatedChannel, DataSize: u32, pData: rawptr) -> HRESULT, + QueryAuthenticatedChannel: proc "stdcall" (this: ^IVideoContext, pChannel: ^IAuthenticatedChannel, InputSize: u32, pInput: rawptr, OutputSize: u32, pOutput: rawptr) -> HRESULT, + ConfigureAuthenticatedChannel: proc "stdcall" (this: ^IVideoContext, pChannel: ^IAuthenticatedChannel, InputSize: u32, pInput: rawptr, pOutput: ^AUTHENTICATED_CONFIGURE_OUTPUT) -> HRESULT, + VideoProcessorSetStreamRotation: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, Enable: BOOL, Rotation: VIDEO_PROCESSOR_ROTATION), + VideoProcessorGetStreamRotation: proc "stdcall" (this: ^IVideoContext, pVideoProcessor: ^IVideoProcessor, StreamIndex: u32, pEnable: ^BOOL, pRotation: ^VIDEO_PROCESSOR_ROTATION), +} + + + +IVideoDevice_UUID :: "10EC4D5B-975A-4689-B9E4-D0AAC30FE333" +IVideoDevice :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11videodevice_vtable: ^IVideoDevice_VTable, +} +IVideoDevice_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + CreateVideoDecoder: proc "stdcall" (this: ^IVideoDevice, pVideoDesc: ^VIDEO_DECODER_DESC, pConfig: ^VIDEO_DECODER_CONFIG, ppDecoder: ^^IVideoDecoder) -> HRESULT, + CreateVideoProcessor: proc "stdcall" (this: ^IVideoDevice, pEnum: ^IVideoProcessorEnumerator, RateConversionIndex: u32, ppVideoProcessor: ^^IVideoProcessor) -> HRESULT, + CreateAuthenticatedChannel: proc "stdcall" (this: ^IVideoDevice, ChannelType: AUTHENTICATED_CHANNEL_TYPE, ppAuthenticatedChannel: ^^IAuthenticatedChannel) -> HRESULT, + CreateCryptoSession: proc "stdcall" (this: ^IVideoDevice, pCryptoType: ^GUID, pDecoderProfile: ^GUID, pKeyExchangeType: ^GUID, ppCryptoSession: ^^ICryptoSession) -> HRESULT, + CreateVideoDecoderOutputView: proc "stdcall" (this: ^IVideoDevice, pResource: ^IResource, pDesc: ^VIDEO_DECODER_OUTPUT_VIEW_DESC, ppVDOVView: ^^IVideoDecoderOutputView) -> HRESULT, + CreateVideoProcessorInputView: proc "stdcall" (this: ^IVideoDevice, pResource: ^IResource, pEnum: ^IVideoProcessorEnumerator, pDesc: ^VIDEO_PROCESSOR_INPUT_VIEW_DESC, ppVPIView: ^^IVideoProcessorInputView) -> HRESULT, + CreateVideoProcessorOutputView: proc "stdcall" (this: ^IVideoDevice, pResource: ^IResource, pEnum: ^IVideoProcessorEnumerator, pDesc: ^VIDEO_PROCESSOR_OUTPUT_VIEW_DESC, ppVPOView: ^^IVideoProcessorOutputView) -> HRESULT, + CreateVideoProcessorEnumerator: proc "stdcall" (this: ^IVideoDevice, pDesc: ^VIDEO_PROCESSOR_CONTENT_DESC, ppEnum: ^^IVideoProcessorEnumerator) -> HRESULT, + GetVideoDecoderProfileCount: proc "stdcall" (this: ^IVideoDevice) -> u32, + GetVideoDecoderProfile: proc "stdcall" (this: ^IVideoDevice, Index: u32, pDecoderProfile: ^GUID) -> HRESULT, + CheckVideoDecoderFormat: proc "stdcall" (this: ^IVideoDevice, pDecoderProfile: ^GUID, Format: dxgi.FORMAT, pSupported: ^BOOL) -> HRESULT, + GetVideoDecoderConfigCount: proc "stdcall" (this: ^IVideoDevice, pDesc: ^VIDEO_DECODER_DESC, pCount: ^u32) -> HRESULT, + GetVideoDecoderConfig: proc "stdcall" (this: ^IVideoDevice, pDesc: ^VIDEO_DECODER_DESC, Index: u32, pConfig: ^VIDEO_DECODER_CONFIG) -> HRESULT, + GetContentProtectionCaps: proc "stdcall" (this: ^IVideoDevice, pCryptoType: ^GUID, pDecoderProfile: ^GUID, pCaps: ^VIDEO_CONTENT_PROTECTION_CAPS) -> HRESULT, + CheckCryptoKeyExchange: proc "stdcall" (this: ^IVideoDevice, pCryptoType: ^GUID, pDecoderProfile: ^GUID, Index: u32, pKeyExchangeType: ^GUID) -> HRESULT, + SetPrivateData: proc "stdcall" (this: ^IVideoDevice, guid: ^GUID, DataSize: u32, pData: rawptr) -> HRESULT, + SetPrivateDataInterface: proc "stdcall" (this: ^IVideoDevice, guid: ^GUID, pData: ^IUnknown) -> HRESULT, +} + + + +IDevice_UUID :: "DB6F6DDB-AC77-4E88-8253-819DF9BBF140" +IDevice :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11device_vtable: ^IDevice_VTable, +} +IDevice_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + CreateBuffer: proc "stdcall" (this: ^IDevice, pDesc: ^BUFFER_DESC, pInitialData: ^SUBRESOURCE_DATA, ppBuffer: ^^IBuffer) -> HRESULT, + CreateTexture1D: proc "stdcall" (this: ^IDevice, pDesc: ^TEXTURE1D_DESC, pInitialData: ^SUBRESOURCE_DATA, ppTexture1D: ^^ITexture1D) -> HRESULT, + CreateTexture2D: proc "stdcall" (this: ^IDevice, pDesc: ^TEXTURE2D_DESC, pInitialData: ^SUBRESOURCE_DATA, ppTexture2D: ^^ITexture2D) -> HRESULT, + CreateTexture3D: proc "stdcall" (this: ^IDevice, pDesc: ^TEXTURE3D_DESC, pInitialData: ^SUBRESOURCE_DATA, ppTexture3D: ^^ITexture3D) -> HRESULT, + CreateShaderResourceView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pDesc: ^SHADER_RESOURCE_VIEW_DESC, ppSRView: ^^IShaderResourceView) -> HRESULT, + CreateUnorderedAccessView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pDesc: ^UNORDERED_ACCESS_VIEW_DESC, ppUAView: ^^IUnorderedAccessView) -> HRESULT, + CreateRenderTargetView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pDesc: ^RENDER_TARGET_VIEW_DESC, ppRTView: ^^IRenderTargetView) -> HRESULT, + CreateDepthStencilView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pDesc: ^DEPTH_STENCIL_VIEW_DESC, ppDepthStencilView: ^^IDepthStencilView) -> HRESULT, + CreateInputLayout: proc "stdcall" (this: ^IDevice, pInputElementDescs: ^INPUT_ELEMENT_DESC, NumElements: u32, pShaderBytecodeWithInputSignature: rawptr, BytecodeLength: SIZE_T, ppInputLayout: ^^IInputLayout) -> HRESULT, + CreateVertexShader: proc "stdcall" (this: ^IDevice, pShaderBytecode: rawptr, BytecodeLength: SIZE_T, pClassLinkage: ^IClassLinkage, ppVertexShader: ^^IVertexShader) -> HRESULT, + CreateGeometryShader: proc "stdcall" (this: ^IDevice, pShaderBytecode: rawptr, BytecodeLength: SIZE_T, pClassLinkage: ^IClassLinkage, ppGeometryShader: ^^IGeometryShader) -> HRESULT, + CreateGeometryShaderWithStreamOutput: proc "stdcall" (this: ^IDevice, pShaderBytecode: rawptr, BytecodeLength: SIZE_T, pSODeclaration: ^SO_DECLARATION_ENTRY, NumEntries: u32, pBufferStrides: ^u32, NumStrides: u32, RasterizedStream: u32, pClassLinkage: ^IClassLinkage, ppGeometryShader: ^^IGeometryShader) -> HRESULT, + CreatePixelShader: proc "stdcall" (this: ^IDevice, pShaderBytecode: rawptr, BytecodeLength: SIZE_T, pClassLinkage: ^IClassLinkage, ppPixelShader: ^^IPixelShader) -> HRESULT, + CreateHullShader: proc "stdcall" (this: ^IDevice, pShaderBytecode: rawptr, BytecodeLength: SIZE_T, pClassLinkage: ^IClassLinkage, ppHullShader: ^^IHullShader) -> HRESULT, + CreateDomainShader: proc "stdcall" (this: ^IDevice, pShaderBytecode: rawptr, BytecodeLength: SIZE_T, pClassLinkage: ^IClassLinkage, ppDomainShader: ^^IDomainShader) -> HRESULT, + CreateComputeShader: proc "stdcall" (this: ^IDevice, pShaderBytecode: rawptr, BytecodeLength: SIZE_T, pClassLinkage: ^IClassLinkage, ppComputeShader: ^^IComputeShader) -> HRESULT, + CreateClassLinkage: proc "stdcall" (this: ^IDevice, ppLinkage: ^^IClassLinkage) -> HRESULT, + CreateBlendState: proc "stdcall" (this: ^IDevice, pBlendStateDesc: ^BLEND_DESC, ppBlendState: ^^IBlendState) -> HRESULT, + CreateDepthStencilState: proc "stdcall" (this: ^IDevice, pDepthStencilDesc: ^DEPTH_STENCIL_DESC, ppDepthStencilState: ^^IDepthStencilState) -> HRESULT, + CreateRasterizerState: proc "stdcall" (this: ^IDevice, pRasterizerDesc: ^RASTERIZER_DESC, ppRasterizerState: ^^IRasterizerState) -> HRESULT, + CreateSamplerState: proc "stdcall" (this: ^IDevice, pSamplerDesc: ^SAMPLER_DESC, ppSamplerState: ^^ISamplerState) -> HRESULT, + CreateQuery: proc "stdcall" (this: ^IDevice, pQueryDesc: ^QUERY_DESC, ppQuery: ^^IQuery) -> HRESULT, + CreatePredicate: proc "stdcall" (this: ^IDevice, pPredicateDesc: ^QUERY_DESC, ppPredicate: ^^IPredicate) -> HRESULT, + CreateCounter: proc "stdcall" (this: ^IDevice, pCounterDesc: ^COUNTER_DESC, ppCounter: ^^ICounter) -> HRESULT, + CreateDeferredContext: proc "stdcall" (this: ^IDevice, ContextFlags: u32, ppDeferredContext: ^^IDeviceContext) -> HRESULT, + OpenSharedResource: proc "stdcall" (this: ^IDevice, hResource: HANDLE, ReturnedInterface: ^IID, ppResource: ^rawptr) -> HRESULT, + CheckFormatSupport: proc "stdcall" (this: ^IDevice, Format: dxgi.FORMAT, pFormatSupport: ^u32) -> HRESULT, + CheckMultisampleQualityLevels: proc "stdcall" (this: ^IDevice, Format: dxgi.FORMAT, SampleCount: u32, pNumQualityLevels: ^u32) -> HRESULT, + CheckCounterInfo: proc "stdcall" (this: ^IDevice, pCounterInfo: ^COUNTER_INFO), + CheckCounter: proc "stdcall" (this: ^IDevice, pDesc: ^COUNTER_DESC, pType: ^COUNTER_TYPE, pActiveCounters: ^u32, szName: cstring, pNameLength: ^u32, szUnits: ^u8, pUnitsLength: ^u32, szDescription: cstring, pDescriptionLength: ^u32) -> HRESULT, + CheckFeatureSupport: proc "stdcall" (this: ^IDevice, Feature: FEATURE, pFeatureSupportData: rawptr, FeatureSupportDataSize: u32) -> HRESULT, + GetPrivateData: proc "stdcall" (this: ^IDevice, guid: ^GUID, pDataSize: ^u32, pData: rawptr) -> HRESULT, + SetPrivateData: proc "stdcall" (this: ^IDevice, guid: ^GUID, DataSize: u32, pData: rawptr) -> HRESULT, + SetPrivateDataInterface: proc "stdcall" (this: ^IDevice, guid: ^GUID, pData: ^IUnknown) -> HRESULT, + GetFeatureLevel: proc "stdcall" (this: ^IDevice) -> FEATURE_LEVEL, + GetCreationFlags: proc "stdcall" (this: ^IDevice) -> u32, + GetDeviceRemovedReason: proc "stdcall" (this: ^IDevice) -> HRESULT, + GetImmediateContext: proc "stdcall" (this: ^IDevice, ppImmediateContext: ^^IDeviceContext), + SetExceptionMode: proc "stdcall" (this: ^IDevice, RaiseFlags: u32) -> HRESULT, + GetExceptionMode: proc "stdcall" (this: ^IDevice) -> u32, +} + + +CREATE_DEVICE_FLAG :: enum u32 { // TODO: make bit_set + SINGLETHREADED = 0x1, + DEBUG = 0x2, + SWITCH_TO_REF = 0x4, + PREVENT_INTERNAL_THREADING_OPTIMIZATIONS = 0x8, + BGRA_SUPPORT = 0x20, + DEBUGGABLE = 0x40, + PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY = 0x80, + DISABLE_GPU_TIMEOUT = 0x100, + VIDEO_SUPPORT = 0x800, +} + +PFN_CREATE_DEVICE :: #type proc "c" (a0: ^dxgi.IAdapter, a1: DRIVER_TYPE, a2: HMODULE, a3: u32, a4: ^FEATURE_LEVEL, a5: u32, a6: u32, a7: ^^IDevice, a8: ^FEATURE_LEVEL, a9: ^^IDeviceContext) -> HRESULT +PFN_CREATE_DEVICE_AND_SWAP_CHAIN :: #type proc "c" (a0: ^dxgi.IAdapter, a1: DRIVER_TYPE, a2: HMODULE, a3: u32, a4: ^FEATURE_LEVEL, a5: u32, a6: u32, a7: ^dxgi.SWAP_CHAIN_DESC, a8: ^^dxgi.ISwapChain, a9: ^^IDevice, a10: ^FEATURE_LEVEL, a11: ^^IDeviceContext) -> HRESULT + +SHADER_VERSION_TYPE :: enum i32 { + PIXEL_SHADER = 0, + VERTEX_SHADER = 1, + GEOMETRY_SHADER = 2, + + HULL_SHADER = 3, + DOMAIN_SHADER = 4, + COMPUTE_SHADER = 5, + + RESERVED0 = 65520, +} + +SIGNATURE_PARAMETER_DESC :: struct { + SemanticName: cstring, + SemanticIndex: u32, + Register: u32, + SystemValueType: NAME, + ComponentType: REGISTER_COMPONENT_TYPE, + Mask: u8, + + ReadWriteMask: u8, + + Stream: u32, + MinPrecision: MIN_PRECISION, +} + +SHADER_BUFFER_DESC :: struct { + Name: cstring, + Type: CBUFFER_TYPE, + Variables: u32, + Size: u32, + uFlags: u32, +} + +SHADER_VARIABLE_DESC :: struct { + Name: cstring, + StartOffset: u32, + Size: u32, + uFlags: u32, + DefaultValue: rawptr, + StartTexture: u32, + TextureSize: u32, + StartSampler: u32, + SamplerSize: u32, +} + +SHADER_TYPE_DESC :: struct { + Class: SHADER_VARIABLE_CLASS, + Type: SHADER_VARIABLE_TYPE, + Rows: u32, + Columns: u32, + Elements: u32, + Members: u32, + Offset: u32, + Name: cstring, +} + +SHADER_DESC :: struct { + Version: u32, + Creator: cstring, + Flags: u32, + + ConstantBuffers: u32, + BoundResources: u32, + InputParameters: u32, + OutputParameters: u32, + + InstructionCount: u32, + TempRegisterCount: u32, + TempArrayCount: u32, + DefCount: u32, + DclCount: u32, + TextureNormalInstructions: u32, + TextureLoadInstructions: u32, + TextureCompInstructions: u32, + TextureBiasInstructions: u32, + TextureGradientInstructions: u32, + FloatInstructionCount: u32, + IntInstructionCount: u32, + UintInstructionCount: u32, + StaticFlowControlCount: u32, + DynamicFlowControlCount: u32, + MacroInstructionCount: u32, + ArrayInstructionCount: u32, + CutInstructionCount: u32, + EmitInstructionCount: u32, + GSOutputTopology: PRIMITIVE_TOPOLOGY, + GSMaxOutputVertexCount: u32, + InputPrimitive: PRIMITIVE, + PatchConstantParameters: u32, + cGSInstanceCount: u32, + cControlPoints: u32, + HSOutputPrimitive: TESSELLATOR_OUTPUT_PRIMITIVE, + HSPartitioning: TESSELLATOR_PARTITIONING, + TessellatorDomain: TESSELLATOR_DOMAIN, + + cBarrierInstructions: u32, + cInterlockedInstructions: u32, + cTextureStoreInstructions: u32, +} + +SHADER_INPUT_BIND_DESC :: struct { + Name: cstring, + Type: SHADER_INPUT_TYPE, + BindPoint: u32, + BindCount: u32, + + uFlags: u32, + ReturnType: RESOURCE_RETURN_TYPE, + Dimension: SRV_DIMENSION, + NumSamples: u32, +} + +LIBRARY_DESC :: struct { + Creator: cstring, + Flags: u32, + FunctionCount: u32, +} + +FUNCTION_DESC :: struct { + Version: u32, + Creator: cstring, + Flags: u32, + + ConstantBuffers: u32, + BoundResources: u32, + + InstructionCount: u32, + TempRegisterCount: u32, + TempArrayCount: u32, + DefCount: u32, + DclCount: u32, + TextureNormalInstructions: u32, + TextureLoadInstructions: u32, + TextureCompInstructions: u32, + TextureBiasInstructions: u32, + TextureGradientInstructions: u32, + FloatInstructionCount: u32, + IntInstructionCount: u32, + UintInstructionCount: u32, + StaticFlowControlCount: u32, + DynamicFlowControlCount: u32, + MacroInstructionCount: u32, + ArrayInstructionCount: u32, + MovInstructionCount: u32, + MovcInstructionCount: u32, + ConversionInstructionCount: u32, + BitwiseInstructionCount: u32, + MinFeatureLevel: FEATURE_LEVEL, + RequiredFeatureFlags: u64, + + Name: cstring, + FunctionParameterCount: i32, + HasReturn: BOOL, + Has10Level9VertexShader: BOOL, + Has10Level9PixelShader: BOOL, +} + +PARAMETER_DESC :: struct { + Name: cstring, + SemanticName: cstring, + Type: SHADER_VARIABLE_TYPE, + Class: SHADER_VARIABLE_CLASS, + Rows: u32, + Columns: u32, + InterpolationMode: INTERPOLATION_MODE, + Flags: PARAMETER_FLAGS, + + FirstInRegister: u32, + FirstInComponent: u32, + FirstOutRegister: u32, + FirstOutComponent: u32, +} + +IShaderReflectionType :: struct { + using vtable: ^IShaderReflectionType_VTable, +} +IShaderReflectionType_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IShaderReflectionType, pDesc: ^SHADER_TYPE_DESC) -> HRESULT, + GetMemberTypeByIndex: proc "stdcall" (this: ^IShaderReflectionType, Index: u32) -> ^IShaderReflectionType, + GetMemberTypeByName: proc "stdcall" (this: ^IShaderReflectionType, Name: cstring) -> ^IShaderReflectionType, + GetMemberTypeName: proc "stdcall" (this: ^IShaderReflectionType, Index: u32) -> cstring, + IsEqual: proc "stdcall" (this: ^IShaderReflectionType, pType: ^IShaderReflectionType) -> HRESULT, + GetSubType: proc "stdcall" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, + GetBaseClass: proc "stdcall" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, + GetNumInterfaces: proc "stdcall" (this: ^IShaderReflectionType) -> u32, + GetInterfaceByIndex: proc "stdcall" (this: ^IShaderReflectionType, uIndex: u32) -> ^IShaderReflectionType, + IsOfType: proc "stdcall" (this: ^IShaderReflectionType, pType: ^IShaderReflectionType) -> HRESULT, + ImplementsInterface: proc "stdcall" (this: ^IShaderReflectionType, pBase: ^IShaderReflectionType) -> HRESULT, +} + +IShaderReflectionVariable :: struct { + using vtable: ^IShaderReflectionVariable_VTable, +} +IShaderReflectionVariable_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IShaderReflectionVariable, pDesc: ^SHADER_VARIABLE_DESC) -> HRESULT, + GetType: proc "stdcall" (this: ^IShaderReflectionVariable) -> ^IShaderReflectionType, + GetBuffer: proc "stdcall" (this: ^IShaderReflectionVariable) -> ^IShaderReflectionConstantBuffer, + GetInterfaceSlot: proc "stdcall" (this: ^IShaderReflectionVariable, uArrayIndex: u32) -> u32, +} + +IShaderReflectionConstantBuffer :: struct { + using vtable: ^IShaderReflectionConstantBuffer_VTable, +} +IShaderReflectionConstantBuffer_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, pDesc: ^SHADER_BUFFER_DESC) -> HRESULT, + GetVariableByIndex: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, Index: u32) -> ^IShaderReflectionVariable, + GetVariableByName: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, Name: cstring) -> ^IShaderReflectionVariable, +} + + +IShaderReflection :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11shaderreflection_vtable: ^IShaderReflection_VTable, +} +IShaderReflection_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetDesc: proc "stdcall" (this: ^IShaderReflection, pDesc: ^SHADER_DESC) -> HRESULT, + GetConstantBufferByIndex: proc "stdcall" (this: ^IShaderReflection, Index: u32) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "stdcall" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetResourceBindingDesc: proc "stdcall" (this: ^IShaderReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetInputParameterDesc: proc "stdcall" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, + GetOutputParameterDesc: proc "stdcall" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, + GetPatchConstantParameterDesc: proc "stdcall" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, + GetVariableByName: proc "stdcall" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "stdcall" (this: ^IShaderReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetMovInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetMovcInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetConversionInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetBitwiseInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetGSInputPrimitive: proc "stdcall" (this: ^IShaderReflection) -> PRIMITIVE, + IsSampleFrequencyShader: proc "stdcall" (this: ^IShaderReflection) -> BOOL, + GetNumInterfaceSlots: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetMinFeatureLevel: proc "stdcall" (this: ^IShaderReflection, pLevel: ^FEATURE_LEVEL) -> HRESULT, + GetThreadGroupSize: proc "stdcall" (this: ^IShaderReflection, pSizeX: ^u32, pSizeY: ^u32, pSizeZ: ^u32) -> u32, + GetRequiresFlags: proc "stdcall" (this: ^IShaderReflection) -> u64, +} + + +ILibraryReflection :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11libraryreflection_vtable: ^ILibraryReflection_VTable, +} +ILibraryReflection_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetDesc: proc "stdcall" (this: ^ILibraryReflection, pDesc: ^LIBRARY_DESC) -> HRESULT, + GetFunctionByIndex: proc "stdcall" (this: ^ILibraryReflection, FunctionIndex: i32) -> ^IFunctionReflection, +} + +IFunctionReflection :: struct { + using vtable: ^IFunctionReflection_VTable, +} +IFunctionReflection_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IFunctionReflection, pDesc: ^FUNCTION_DESC) -> HRESULT, + GetConstantBufferByIndex: proc "stdcall" (this: ^IFunctionReflection, BufferIndex: u32) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "stdcall" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetResourceBindingDesc: proc "stdcall" (this: ^IFunctionReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetVariableByName: proc "stdcall" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "stdcall" (this: ^IFunctionReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetFunctionParameter: proc "stdcall" (this: ^IFunctionReflection, ParameterIndex: i32) -> ^IFunctionParameterReflection, +} + +IFunctionParameterReflection :: struct { + using vtable: ^IFunctionParameterReflection_VTable, +} +IFunctionParameterReflection_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IFunctionParameterReflection, pDesc: ^PARAMETER_DESC) -> HRESULT, +} + + +ILinkingNode :: struct { + using iunknown: IUnknown, +} + +IFunctionLinkingGraph :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11functionlinkinggraph_vtable: ^IFunctionLinkingGraph_VTable, +} +IFunctionLinkingGraph_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + CreateModuleInstance: proc "stdcall" (this: ^IFunctionLinkingGraph, ppModuleInstance: ^^IModuleInstance, ppErrorBuffer: ^^IBlob) -> HRESULT, + SetInputSignature: proc "stdcall" (this: ^IFunctionLinkingGraph, pInputParameters: ^PARAMETER_DESC, cInputParameters: u32, ppInputNode: ^^ILinkingNode) -> HRESULT, + SetOutputSignature: proc "stdcall" (this: ^IFunctionLinkingGraph, pOutputParameters: ^PARAMETER_DESC, cOutputParameters: u32, ppOutputNode: ^^ILinkingNode) -> HRESULT, + CallFunction: proc "stdcall" (this: ^IFunctionLinkingGraph, pModuleInstanceNamespace: cstring, pModuleWithFunctionPrototype: ^IModule, pFunctionName: cstring, ppCallNode: ^^ILinkingNode) -> HRESULT, + PassValue: proc "stdcall" (this: ^IFunctionLinkingGraph, pSrcNode: ^ILinkingNode, SrcParameterIndex: i32, pDstNode: ^ILinkingNode, DstParameterIndex: i32) -> HRESULT, + PassValueWithSwizzle: proc "stdcall" (this: ^IFunctionLinkingGraph, pSrcNode: ^ILinkingNode, SrcParameterIndex: i32, pSrcSwizzle: ^u8, pDstNode: ^ILinkingNode, DstParameterIndex: i32, pDstSwizzle: ^u8) -> HRESULT, + GetLastError: proc "stdcall" (this: ^IFunctionLinkingGraph, ppErrorBuffer: ^^IBlob) -> HRESULT, + GenerateHlsl: proc "stdcall" (this: ^IFunctionLinkingGraph, uFlags: u32, ppBuffer: ^^IBlob) -> HRESULT, +} diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin new file mode 100644 index 000000000..f3885ed63 --- /dev/null +++ b/vendor/directx/d3d12/d3d12.odin @@ -0,0 +1,5102 @@ +package directx_d3d12 + +foreign import "system:d3d12.lib" + +import "../dxgi" +import "../d3d_compiler" +import win32 "core:sys/windows" + +IUnknown :: dxgi.IUnknown +IUnknown_VTable :: dxgi.IUnknown_VTable + +HANDLE :: dxgi.HANDLE +HMODULE :: dxgi.HMODULE +HRESULT :: dxgi.HRESULT +HWND :: dxgi.HWND +LUID :: dxgi.LUID +UUID :: dxgi.UUID +GUID :: dxgi.GUID +IID :: dxgi.IID +SIZE_T :: dxgi.SIZE_T +BOOL :: dxgi.BOOL + +RECT :: dxgi.RECT + +IModuleInstance :: d3d_compiler.ID3D11ModuleInstance +IBlob :: d3d_compiler.ID3DBlob +IModule :: d3d_compiler.ID3D11Module + +@(default_calling_convention="stdcall", link_prefix="D3D12") +foreign d3d12 { + CreateDevice :: proc(pAdapter: ^IUnknown, MinimumFeatureLevel: FEATURE_LEVEL, riid: ^IID, ppDevice: ^rawptr) -> HRESULT --- + CreateRootSignatureDeserializer :: proc(pSrcData: rawptr, SrcDataSizeInBytes: SIZE_T, pRootSignatureDeserializerInterface: ^IID, ppRootSignatureDeserializer: ^rawptr) -> HRESULT --- + CreateVersionedRootSignatureDeserializer :: proc(pSrcData: rawptr, SrcDataSizeInBytes: SIZE_T, pRootSignatureDeserializerInterface: ^IID, ppRootSignatureDeserializer: ^rawptr) -> HRESULT --- + EnableExperimentalFeatures :: proc(NumFeatures: u32, pIIDs: ^IID, pConfigurationStructs: rawptr, pConfigurationStructSizes: ^u32) -> HRESULT --- + GetDebugInterface :: proc(riid: ^IID, ppvDebug: ^rawptr) -> HRESULT --- + SerializeRootSignature :: proc(pRootSignature: ^ROOT_SIGNATURE_DESC, Version: ROOT_SIGNATURE_VERSION, ppBlob: ^^IBlob, ppErrorBlob: ^^IBlob) -> HRESULT --- + SerializeVersionedRootSignature :: proc(pRootSignature: ^VERSIONED_ROOT_SIGNATURE_DESC, ppBlob: ^^IBlob, ppErrorBlob: ^^IBlob) -> HRESULT --- +} + +foreign d3d12 { + WKPDID_D3DDebugObjectNameW: GUID + WKPDID_CommentStringW: GUID + + @(link_name="DXGI_DEBUG_D3D12") + DEBUG_D3D12: GUID + + @(link_name="D3D12_PROTECTED_RESOURCES_SESSION_HARDWARE_PROTECTED") + PROTECTED_RESOURCES_SESSION_HARDWARE_PROTECTED: GUID +} + +@(link_prefix="D3D_") +foreign d3d12 { + TEXTURE_LAYOUT_ROW_MAJOR: GUID + TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE: GUID +} + +@(link_prefix="D3D12") +foreign d3d12 { + ExperimentalShaderModels: UUID + TiledResourceTier4: UUID + MetaCommand: UUID +} + + +DRIVER_TYPE :: enum i32 { + UNKNOWN = 0, + HARDWARE = 1, + REFERENCE = 2, + NULL = 3, + SOFTWARE = 4, + WARP = 5, +} + +FEATURE_LEVEL :: enum i32 { + _1_0_CORE = 4096, + _9_1 = 37120, + _9_2 = 37376, + _9_3 = 37632, + _10_0 = 40960, + _10_1 = 41216, + _11_0 = 45056, + _11_1 = 45312, + _12_0 = 49152, + _12_1 = 49408, +} + +PRIMITIVE_TOPOLOGY :: enum i32 { + UNDEFINED = 0, + POINTLIST = 1, + LINELIST = 2, + LINESTRIP = 3, + TRIANGLELIST = 4, + TRIANGLESTRIP = 5, + LINELIST_ADJ = 10, + LINESTRIP_ADJ = 11, + TRIANGLELIST_ADJ = 12, + TRIANGLESTRIP_ADJ = 13, + _1_CONTROL_POINT_PATCHLIST = 33, + _2_CONTROL_POINT_PATCHLIST = 34, + _3_CONTROL_POINT_PATCHLIST = 35, + _4_CONTROL_POINT_PATCHLIST = 36, + _5_CONTROL_POINT_PATCHLIST = 37, + _6_CONTROL_POINT_PATCHLIST = 38, + _7_CONTROL_POINT_PATCHLIST = 39, + _8_CONTROL_POINT_PATCHLIST = 40, + _9_CONTROL_POINT_PATCHLIST = 41, + _10_CONTROL_POINT_PATCHLIST = 42, + _11_CONTROL_POINT_PATCHLIST = 43, + _12_CONTROL_POINT_PATCHLIST = 44, + _13_CONTROL_POINT_PATCHLIST = 45, + _14_CONTROL_POINT_PATCHLIST = 46, + _15_CONTROL_POINT_PATCHLIST = 47, + _16_CONTROL_POINT_PATCHLIST = 48, + _17_CONTROL_POINT_PATCHLIST = 49, + _18_CONTROL_POINT_PATCHLIST = 50, + _19_CONTROL_POINT_PATCHLIST = 51, + _20_CONTROL_POINT_PATCHLIST = 52, + _21_CONTROL_POINT_PATCHLIST = 53, + _22_CONTROL_POINT_PATCHLIST = 54, + _23_CONTROL_POINT_PATCHLIST = 55, + _24_CONTROL_POINT_PATCHLIST = 56, + _25_CONTROL_POINT_PATCHLIST = 57, + _26_CONTROL_POINT_PATCHLIST = 58, + _27_CONTROL_POINT_PATCHLIST = 59, + _28_CONTROL_POINT_PATCHLIST = 60, + _29_CONTROL_POINT_PATCHLIST = 61, + _30_CONTROL_POINT_PATCHLIST = 62, + _31_CONTROL_POINT_PATCHLIST = 63, + _32_CONTROL_POINT_PATCHLIST = 64, +} + +PRIMITIVE :: enum i32 { + UNDEFINED = 0, + POINT = 1, + LINE = 2, + TRIANGLE = 3, + LINE_ADJ = 6, + TRIANGLE_ADJ = 7, + _1_CONTROL_POINT_PATCH = 8, + _2_CONTROL_POINT_PATCH = 9, + _3_CONTROL_POINT_PATCH = 10, + _4_CONTROL_POINT_PATCH = 11, + _5_CONTROL_POINT_PATCH = 12, + _6_CONTROL_POINT_PATCH = 13, + _7_CONTROL_POINT_PATCH = 14, + _8_CONTROL_POINT_PATCH = 15, + _9_CONTROL_POINT_PATCH = 16, + _10_CONTROL_POINT_PATCH = 17, + _11_CONTROL_POINT_PATCH = 18, + _12_CONTROL_POINT_PATCH = 19, + _13_CONTROL_POINT_PATCH = 20, + _14_CONTROL_POINT_PATCH = 21, + _15_CONTROL_POINT_PATCH = 22, + _16_CONTROL_POINT_PATCH = 23, + _17_CONTROL_POINT_PATCH = 24, + _18_CONTROL_POINT_PATCH = 25, + _19_CONTROL_POINT_PATCH = 26, + _20_CONTROL_POINT_PATCH = 27, + _21_CONTROL_POINT_PATCH = 28, + _22_CONTROL_POINT_PATCH = 29, + _23_CONTROL_POINT_PATCH = 30, + _24_CONTROL_POINT_PATCH = 31, + _25_CONTROL_POINT_PATCH = 32, + _26_CONTROL_POINT_PATCH = 33, + _27_CONTROL_POINT_PATCH = 34, + _28_CONTROL_POINT_PATCH = 35, + _29_CONTROL_POINT_PATCH = 36, + _30_CONTROL_POINT_PATCH = 37, + _31_CONTROL_POINT_PATCH = 38, + _32_CONTROL_POINT_PATCH = 39, +} + +SRV_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE2DMS = 6, + TEXTURE2DMSARRAY = 7, + TEXTURE3D = 8, + TEXTURECUBE = 9, + TEXTURECUBEARRAY = 10, + BUFFEREX = 11, + RAYTRACING_ACCELERATION_STRUCTURE = 11, +} + +PFN_DESTRUCTION_CALLBACK :: #type proc "c" (a0: rawptr) + + +ID3DDestructionNotifier_UUID :: "a06eb39a-50da-425b-8c31-4eecd6c270f3" +ID3DDestructionNotifier :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3ddestructionnotifier_vtable: ^ID3DDestructionNotifier_VTable, +} +ID3DDestructionNotifier_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + RegisterDestructionCallback: proc "stdcall" (this: ^ID3DDestructionNotifier, callbackFn: PFN_DESTRUCTION_CALLBACK, pData: rawptr, pCallbackID: ^u32) -> HRESULT, + UnregisterDestructionCallback: proc "stdcall" (this: ^ID3DDestructionNotifier, callbackID: u32) -> HRESULT, +} + +SHADER_VARIABLE_CLASS :: enum i32 { + SCALAR = 0, + VECTOR = 1, + MATRIX_ROWS = 2, + MATRIX_COLUMNS = 3, + OBJECT = 4, + STRUCT = 5, + INTERFACE_CLASS = 6, + INTERFACE_POINTER = 7, +} + +SHADER_VARIABLE_FLAGS :: enum u32 { // TODO: make bit_set + USERPACKED = 0x1, + USED = 0x2, + INTERFACE_POINTER = 0x4, + INTERFACE_PARAMETER = 0x8, +} + +SHADER_VARIABLE_TYPE :: enum i32 { + VOID = 0, + BOOL = 1, + INT = 2, + FLOAT = 3, + STRING = 4, + TEXTURE = 5, + TEXTURE1D = 6, + TEXTURE2D = 7, + TEXTURE3D = 8, + TEXTURECUBE = 9, + SAMPLER = 10, + SAMPLER1D = 11, + SAMPLER2D = 12, + SAMPLER3D = 13, + SAMPLERCUBE = 14, + PIXELSHADER = 15, + VERTEXSHADER = 16, + PIXELFRAGMENT = 17, + VERTEXFRAGMENT = 18, + UINT = 19, + UINT8 = 20, + GEOMETRYSHADER = 21, + RASTERIZER = 22, + DEPTHSTENCIL = 23, + BLEND = 24, + BUFFER = 25, + CBUFFER = 26, + TBUFFER = 27, + TEXTURE1DARRAY = 28, + TEXTURE2DARRAY = 29, + RENDERTARGETVIEW = 30, + DEPTHSTENCILVIEW = 31, + TEXTURE2DMS = 32, + TEXTURE2DMSARRAY = 33, + TEXTURECUBEARRAY = 34, + HULLSHADER = 35, + DOMAINSHADER = 36, + INTERFACE_POINTER = 37, + COMPUTESHADER = 38, + DOUBLE = 39, + RWTEXTURE1D = 40, + RWTEXTURE1DARRAY = 41, + RWTEXTURE2D = 42, + RWTEXTURE2DARRAY = 43, + RWTEXTURE3D = 44, + RWBUFFER = 45, + BYTEADDRESS_BUFFER = 46, + RWBYTEADDRESS_BUFFER = 47, + STRUCTURED_BUFFER = 48, + RWSTRUCTURED_BUFFER = 49, + APPEND_STRUCTURED_BUFFER = 50, + CONSUME_STRUCTURED_BUFFER = 51, + MIN8FLOAT = 52, + MIN10FLOAT = 53, + MIN16FLOAT = 54, + MIN12INT = 55, + MIN16INT = 56, + MIN16UINT = 57, +} + +SHADER_INPUT_FLAGS :: enum u32 { // TODO: make bit_set + USERPACKED = 0x1, + COMPARISON_SAMPLER = 0x2, + TEXTURE_COMPONENT_0 = 0x4, + TEXTURE_COMPONENT_1 = 0x8, + TEXTURE_COMPONENTS = 0xc, + UNUSED = 0x10, +} + +SHADER_INPUT_TYPE :: enum i32 { + CBUFFER = 0, + TBUFFER = 1, + TEXTURE = 2, + SAMPLER = 3, + UAV_RWTYPED = 4, + STRUCTURED = 5, + UAV_RWSTRUCTURED = 6, + BYTEADDRESS = 7, + UAV_RWBYTEADDRESS = 8, + UAV_APPEND_STRUCTURED = 9, + UAV_CONSUME_STRUCTURED = 10, + UAV_RWSTRUCTURED_WITH_COUNTER = 11, + RTACCELERATIONSTRUCTURE = 12, + UAV_FEEDBACKTEXTURE = 13, +} + +SHADER_CBUFFER_FLAGS :: enum u32 { // TODO: make bit_set + USERPACKED = 0x1, +} + +CBUFFER_TYPE :: enum i32 { + CBUFFER = 0, + TBUFFER = 1, + INTERFACE_POINTERS = 2, + RESOURCE_BIND_INFO = 3, +} + +NAME :: enum i32 { + UNDEFINED = 0, + POSITION = 1, + CLIP_DISTANCE = 2, + CULL_DISTANCE = 3, + RENDER_TARGET_ARRAY_INDEX = 4, + VIEWPORT_ARRAY_INDEX = 5, + VERTEX_ID = 6, + PRIMITIVE_ID = 7, + INSTANCE_ID = 8, + IS_FRONT_FACE = 9, + SAMPLE_INDEX = 10, + FINAL_QUAD_EDGE_TESSFACTOR = 11, + FINAL_QUAD_INSIDE_TESSFACTOR = 12, + FINAL_TRI_EDGE_TESSFACTOR = 13, + FINAL_TRI_INSIDE_TESSFACTOR = 14, + FINAL_LINE_DETAIL_TESSFACTOR = 15, + FINAL_LINE_DENSITY_TESSFACTOR = 16, + BARYCENTRICS = 23, + SHADINGRATE = 24, + CULLPRIMITIVE = 25, + TARGET = 64, + DEPTH = 65, + COVERAGE = 66, + DEPTH_GREATER_EQUAL = 67, + DEPTH_LESS_EQUAL = 68, + STENCIL_REF = 69, + INNER_COVERAGE = 70, +} + +RESOURCE_RETURN_TYPE :: enum i32 { + UNORM = 1, + SNORM = 2, + SINT = 3, + UINT = 4, + FLOAT = 5, + MIXED = 6, + DOUBLE = 7, + CONTINUED = 8, +} + +REGISTER_COMPONENT_TYPE :: enum i32 { + UNKNOWN = 0, + UINT32 = 1, + SINT32 = 2, + FLOAT32 = 3, +} + +TESSELLATOR_DOMAIN :: enum i32 { + UNDEFINED = 0, + ISOLINE = 1, + TRI = 2, + QUAD = 3, +} + +TESSELLATOR_PARTITIONING :: enum i32 { + UNDEFINED = 0, + INTEGER = 1, + POW2 = 2, + FRACTIONAL_ODD = 3, + FRACTIONAL_EVEN = 4, +} + +TESSELLATOR_OUTPUT_PRIMITIVE :: enum i32 { + UNDEFINED = 0, + POINT = 1, + LINE = 2, + TRIANGLE_CW = 3, + TRIANGLE_CCW = 4, +} + +MIN_PRECISION :: enum i32 { + DEFAULT = 0, + FLOAT_16 = 1, + FLOAT_2_8 = 2, + RESERVED = 3, + SINT_16 = 4, + UINT_16 = 5, + ANY_16 = 240, + ANY_10 = 241, +} + +INTERPOLATION_MODE :: enum i32 { + UNDEFINED = 0, + CONSTANT = 1, + LINEAR = 2, + LINEAR_CENTROID = 3, + LINEAR_NOPERSPECTIVE = 4, + LINEAR_NOPERSPECTIVE_CENTROID = 5, + LINEAR_SAMPLE = 6, + LINEAR_NOPERSPECTIVE_SAMPLE = 7, +} + +PARAMETER_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + IN = 0x1, + OUT = 0x2, +} + + +GPU_VIRTUAL_ADDRESS :: u64 + +COMMAND_LIST_TYPE :: enum i32 { + DIRECT = 0, + BUNDLE = 1, + COMPUTE = 2, + COPY = 3, + VIDEO_DECODE = 4, + VIDEO_PROCESS = 5, + VIDEO_ENCODE = 6, +} + +COMMAND_QUEUE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + DISABLE_GPU_TIMEOUT = 0x1, +} + +COMMAND_QUEUE_PRIORITY :: enum i32 { + NORMAL = 0, + HIGH = 100, + GLOBAL_REALTIME = 10000, +} + +COMMAND_QUEUE_DESC :: struct { + Type: COMMAND_LIST_TYPE, + Priority: i32, + Flags: COMMAND_QUEUE_FLAGS, + NodeMask: u32, +} + +PRIMITIVE_TOPOLOGY_TYPE :: enum i32 { + UNDEFINED = 0, + POINT = 1, + LINE = 2, + TRIANGLE = 3, + PATCH = 4, +} + +INPUT_CLASSIFICATION :: enum i32 { + PER_VERTEX_DATA = 0, + PER_INSTANCE_DATA = 1, +} + +INPUT_ELEMENT_DESC :: struct { + SemanticName: cstring, + SemanticIndex: u32, + Format: dxgi.FORMAT, + InputSlot: u32, + AlignedByteOffset: u32, + InputSlotClass: INPUT_CLASSIFICATION, + InstanceDataStepRate: u32, +} + +FILL_MODE :: enum i32 { + WIREFRAME = 2, + SOLID = 3, +} + +CULL_MODE :: enum i32 { + NONE = 1, + FRONT = 2, + BACK = 3, +} + +SO_DECLARATION_ENTRY :: struct { + Stream: u32, + SemanticName: cstring, + SemanticIndex: u32, + StartComponent: u8, + ComponentCount: u8, + OutputSlot: u8, +} + +VIEWPORT :: struct { + TopLeftX: f32, + TopLeftY: f32, + Width: f32, + Height: f32, + MinDepth: f32, + MaxDepth: f32, +} + +BOX :: struct { + left: u32, + top: u32, + front: u32, + right: u32, + bottom: u32, + back: u32, +} + +COMPARISON_FUNC :: enum i32 { + NEVER = 1, + LESS = 2, + EQUAL = 3, + LESS_EQUAL = 4, + GREATER = 5, + NOT_EQUAL = 6, + GREATER_EQUAL = 7, + ALWAYS = 8, +} + +DEPTH_WRITE_MASK :: enum i32 { + ZERO = 0, + ALL = 1, +} + +STENCIL_OP :: enum i32 { + KEEP = 1, + ZERO = 2, + REPLACE = 3, + INCR_SAT = 4, + DECR_SAT = 5, + INVERT = 6, + INCR = 7, + DECR = 8, +} + +DEPTH_STENCILOP_DESC :: struct { + StencilFailOp: STENCIL_OP, + StencilDepthFailOp: STENCIL_OP, + StencilPassOp: STENCIL_OP, + StencilFunc: COMPARISON_FUNC, +} + +DEPTH_STENCIL_DESC :: struct { + DepthEnable: BOOL, + DepthWriteMask: DEPTH_WRITE_MASK, + DepthFunc: COMPARISON_FUNC, + StencilEnable: BOOL, + StencilReadMask: u8, + StencilWriteMask: u8, + FrontFace: DEPTH_STENCILOP_DESC, + BackFace: DEPTH_STENCILOP_DESC, +} + +DEPTH_STENCIL_DESC1 :: struct { + DepthEnable: BOOL, + DepthWriteMask: DEPTH_WRITE_MASK, + DepthFunc: COMPARISON_FUNC, + StencilEnable: BOOL, + StencilReadMask: u8, + StencilWriteMask: u8, + FrontFace: DEPTH_STENCILOP_DESC, + BackFace: DEPTH_STENCILOP_DESC, + DepthBoundsTestEnable: BOOL, +} + +BLEND :: enum i32 { + ZERO = 1, + ONE = 2, + SRC_COLOR = 3, + INV_SRC_COLOR = 4, + SRC_ALPHA = 5, + INV_SRC_ALPHA = 6, + DEST_ALPHA = 7, + INV_DEST_ALPHA = 8, + DEST_COLOR = 9, + INV_DEST_COLOR = 10, + SRC_ALPHA_SAT = 11, + BLEND_FACTOR = 14, + INV_BLEND_FACTOR = 15, + SRC1_COLOR = 16, + INV_SRC1_COLOR = 17, + SRC1_ALPHA = 18, + INV_SRC1_ALPHA = 19, +} + +BLEND_OP :: enum i32 { + ADD = 1, + SUBTRACT = 2, + REV_SUBTRACT = 3, + MIN = 4, + MAX = 5, +} + +COLOR_WRITE_ENABLE :: enum i32 { // TODO: make bit_set + RED = 1, + GREEN = 2, + BLUE = 4, + ALPHA = 8, + ALL = 15, +} + +LOGIC_OP :: enum i32 { + CLEAR = 0, + SET = 1, + COPY = 2, + COPY_INVERTED = 3, + NOOP = 4, + INVERT = 5, + AND = 6, + NAND = 7, + OR = 8, + NOR = 9, + XOR = 10, + EQUIV = 11, + AND_REVERSE = 12, + AND_INVERTED = 13, + OR_REVERSE = 14, + OR_INVERTED = 15, +} + +RENDER_TARGET_BLEND_DESC :: struct { + BlendEnable: BOOL, + LogicOpEnable: BOOL, + SrcBlend: BLEND, + DestBlend: BLEND, + BlendOp: BLEND_OP, + SrcBlendAlpha: BLEND, + DestBlendAlpha: BLEND, + BlendOpAlpha: BLEND_OP, + LogicOp: LOGIC_OP, + RenderTargetWriteMask: u8, +} + +BLEND_DESC :: struct { + AlphaToCoverageEnable: BOOL, + IndependentBlendEnable: BOOL, + RenderTarget: [8]RENDER_TARGET_BLEND_DESC, +} + +CONSERVATIVE_RASTERIZATION_MODE :: enum i32 { + OFF = 0, + ON = 1, +} + +RASTERIZER_DESC :: struct { + FillMode: FILL_MODE, + CullMode: CULL_MODE, + FrontCounterClockwise: BOOL, + DepthBias: i32, + DepthBiasClamp: f32, + SlopeScaledDepthBias: f32, + DepthClipEnable: BOOL, + MultisampleEnable: BOOL, + AntialiasedLineEnable: BOOL, + ForcedSampleCount: u32, + ConservativeRaster: CONSERVATIVE_RASTERIZATION_MODE, +} + + +IObject_UUID :: "c4fec28f-7966-4e95-9f94-f431cb56c3b8" +IObject :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12object_vtable: ^IObject_VTable, +} +IObject_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetPrivateData: proc "stdcall" (this: ^IObject, guid: ^GUID, pDataSize: ^u32, pData: rawptr) -> HRESULT, + SetPrivateData: proc "stdcall" (this: ^IObject, guid: ^GUID, DataSize: u32, pData: rawptr) -> HRESULT, + SetPrivateDataInterface: proc "stdcall" (this: ^IObject, guid: ^GUID, pData: ^IUnknown) -> HRESULT, + SetName: proc "stdcall" (this: ^IObject, Name: [^]u16) -> HRESULT, +} + + +IDeviceChild_UUID :: "905db94b-a00c-4140-9df5-2b64ca9ea357" +IDeviceChild :: struct #raw_union { + #subtype id3d12object: IObject, + using id3d12devicechild_vtable: ^IDeviceChild_VTable, +} +IDeviceChild_VTable :: struct { + using id3d12object_vtable: IObject_VTable, + GetDevice: proc "stdcall" (this: ^IDeviceChild, riid: ^IID, ppvDevice: ^rawptr) -> HRESULT, +} + + +IRootSignature_UUID :: "c54a6b66-72df-4ee8-8be5-a946a1429214" +IRootSignature :: struct { + using id3d12devicechild: IDeviceChild, +} + +SHADER_BYTECODE :: struct { + pShaderBytecode: rawptr, + BytecodeLength: SIZE_T, +} + +STREAM_OUTPUT_DESC :: struct { + pSODeclaration: ^SO_DECLARATION_ENTRY, + NumEntries: u32, + pBufferStrides: ^u32, + NumStrides: u32, + RasterizedStream: u32, +} + +INPUT_LAYOUT_DESC :: struct { + pInputElementDescs: ^INPUT_ELEMENT_DESC, + NumElements: u32, +} + +INDEX_BUFFER_STRIP_CUT_VALUE :: enum i32 { + DISABLED = 0, + _0xFFFF = 1, + _0xFFFFFFFF = 2, +} + +CACHED_PIPELINE_STATE :: struct { + pCachedBlob: rawptr, + CachedBlobSizeInBytes: SIZE_T, +} + +PIPELINE_STATE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + TOOL_DEBUG = 0x1, +} + +GRAPHICS_PIPELINE_STATE_DESC :: struct { + pRootSignature: ^IRootSignature, + VS: SHADER_BYTECODE, + PS: SHADER_BYTECODE, + DS: SHADER_BYTECODE, + HS: SHADER_BYTECODE, + GS: SHADER_BYTECODE, + StreamOutput: STREAM_OUTPUT_DESC, + BlendState: BLEND_DESC, + SampleMask: u32, + RasterizerState: RASTERIZER_DESC, + DepthStencilState: DEPTH_STENCIL_DESC, + InputLayout: INPUT_LAYOUT_DESC, + IBStripCutValue: INDEX_BUFFER_STRIP_CUT_VALUE, + PrimitiveTopologyType: PRIMITIVE_TOPOLOGY_TYPE, + NumRenderTargets: u32, + RTVFormats: [8]dxgi.FORMAT, + DSVFormat: dxgi.FORMAT, + SampleDesc: dxgi.SAMPLE_DESC, + NodeMask: u32, + CachedPSO: CACHED_PIPELINE_STATE, + Flags: PIPELINE_STATE_FLAGS, +} + +COMPUTE_PIPELINE_STATE_DESC :: struct { + pRootSignature: ^IRootSignature, + CS: SHADER_BYTECODE, + NodeMask: u32, + CachedPSO: CACHED_PIPELINE_STATE, + Flags: PIPELINE_STATE_FLAGS, +} + +RT_FORMAT_ARRAY :: struct { + RTFormats: [8]dxgi.FORMAT, + NumRenderTargets: u32, +} + +PIPELINE_STATE_STREAM_DESC :: struct { + SizeInBytes: SIZE_T, + pPipelineStateSubobjectStream: rawptr, +} + +PIPELINE_STATE_SUBOBJECT_TYPE :: enum i32 { + ROOT_SIGNATURE = 0, + VS = 1, + PS = 2, + DS = 3, + HS = 4, + GS = 5, + CS = 6, + STREAM_OUTPUT = 7, + BLEND = 8, + SAMPLE_MASK = 9, + RASTERIZER = 10, + DEPTH_STENCIL = 11, + INPUT_LAYOUT = 12, + IB_STRIP_CUT_VALUE = 13, + PRIMITIVE_TOPOLOGY = 14, + RENDER_TARGET_FORMATS = 15, + DEPTH_STENCIL_FORMAT = 16, + SAMPLE_DESC = 17, + NODE_MASK = 18, + CACHED_PSO = 19, + FLAGS = 20, + DEPTH_STENCIL1 = 21, + VIEW_INSTANCING = 22, + AS = 24, + MS = 25, + MAX_VALID = 26, +} + +FEATURE :: enum i32 { + OPTIONS = 0, + ARCHITECTURE = 1, + FEATURE_LEVELS = 2, + FORMAT_SUPPORT = 3, + MULTISAMPLE_QUALITY_LEVELS = 4, + FORMAT_INFO = 5, + GPU_VIRTUAL_ADDRESS_SUPPORT = 6, + SHADER_MODEL = 7, + OPTIONS1 = 8, + PROTECTED_RESOURCE_SESSION_SUPPORT = 10, + ROOT_SIGNATURE = 12, + ARCHITECTURE1 = 16, + OPTIONS2 = 18, + SHADER_CACHE = 19, + COMMAND_QUEUE_PRIORITY = 20, + OPTIONS3 = 21, + EXISTING_HEAPS = 22, + OPTIONS4 = 23, + SERIALIZATION = 24, + CROSS_NODE = 25, + OPTIONS5 = 27, + OPTIONS6 = 30, + QUERY_META_COMMAND = 31, + OPTIONS7 = 32, + PROTECTED_RESOURCE_SESSION_TYPE_COUNT = 33, + PROTECTED_RESOURCE_SESSION_TYPES = 34, +} + +SHADER_MIN_PRECISION_SUPPORT :: enum i32 { + NONE = 0, + _10_BIT = 1, + _16_BIT = 2, +} + +TILED_RESOURCES_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1 = 1, + _2 = 2, + _3 = 3, + _4 = 4, +} + +RESOURCE_BINDING_TIER :: enum i32 { + _1 = 1, + _2 = 2, + _3 = 3, +} + +CONSERVATIVE_RASTERIZATION_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1 = 1, + _2 = 2, + _3 = 3, +} + +FORMAT_SUPPORT1 :: enum i32 { // TODO: make bit_set + NONE = 0, + BUFFER = 1, + IA_VERTEX_BUFFER = 2, + IA_INDEX_BUFFER = 4, + SO_BUFFER = 8, + TEXTURE1D = 16, + TEXTURE2D = 32, + TEXTURE3D = 64, + TEXTURECUBE = 128, + SHADER_LOAD = 256, + SHADER_SAMPLE = 512, + SHADER_SAMPLE_COMPARISON = 1024, + SHADER_SAMPLE_MONO_TEXT = 2048, + MIP = 4096, + RENDER_TARGET = 16384, + BLENDABLE = 32768, + DEPTH_STENCIL = 65536, + MULTISAMPLE_RESOLVE = 262144, + DISPLAY = 524288, + CAST_WITHIN_BIT_LAYOUT = 1048576, + MULTISAMPLE_RENDERTARGET = 2097152, + MULTISAMPLE_LOAD = 4194304, + SHADER_GATHER = 8388608, + BACK_BUFFER_CAST = 16777216, + TYPED_UNORDERED_ACCESS_VIEW = 33554432, + SHADER_GATHER_COMPARISON = 67108864, + DECODER_OUTPUT = 134217728, + VIDEO_PROCESSOR_OUTPUT = 268435456, + VIDEO_PROCESSOR_INPUT = 536870912, + VIDEO_ENCODER = 1073741824, +} + +FORMAT_SUPPORT2 :: enum i32 { // TODO: make bit_set + NONE = 0, + UAV_ATOMIC_ADD = 1, + UAV_ATOMIC_BITWISE_OPS = 2, + UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 4, + UAV_ATOMIC_EXCHANGE = 8, + UAV_ATOMIC_SIGNED_MIN_OR_MAX = 16, + UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 32, + UAV_TYPED_LOAD = 64, + UAV_TYPED_STORE = 128, + OUTPUT_MERGER_LOGIC_OP = 256, + TILED = 512, + MULTIPLANE_OVERLAY = 16384, + SAMPLER_FEEDBACK = 32768, +} + +MULTISAMPLE_QUALITY_LEVEL_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + TILED_RESOURCE = 0x1, +} + +CROSS_NODE_SHARING_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1_EMULATED = 1, + _1 = 2, + _2 = 3, + _3 = 4, +} + +RESOURCE_HEAP_TIER :: enum i32 { + _1 = 1, + _2 = 2, +} + +PROGRAMMABLE_SAMPLE_POSITIONS_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1 = 1, + _2 = 2, +} + +VIEW_INSTANCING_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1 = 1, + _2 = 2, + _3 = 3, +} + +FEATURE_DATA_OPTIONS :: struct { + DoublePrecisionFloatShaderOps: BOOL, + OutputMergerLogicOp: BOOL, + MinPrecisionSupport: SHADER_MIN_PRECISION_SUPPORT, + TiledResourcesTier: TILED_RESOURCES_TIER, + ResourceBindingTier: RESOURCE_BINDING_TIER, + PSSpecifiedStencilRefSupported: BOOL, + TypedUAVLoadAdditionalFormats: BOOL, + ROVsSupported: BOOL, + ConservativeRasterizationTier: CONSERVATIVE_RASTERIZATION_TIER, + MaxGPUVirtualAddressBitsPerResource: u32, + StandardSwizzle64KBSupported: BOOL, + CrossNodeSharingTier: CROSS_NODE_SHARING_TIER, + CrossAdapterRowMajorTextureSupported: BOOL, + VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation: BOOL, + ResourceHeapTier: RESOURCE_HEAP_TIER, +} + +FEATURE_DATA_OPTIONS1 :: struct { + WaveOps: BOOL, + WaveLaneCountMin: u32, + WaveLaneCountMax: u32, + TotalLaneCount: u32, + ExpandedComputeResourceStates: BOOL, + Int64ShaderOps: BOOL, +} + +FEATURE_DATA_OPTIONS2 :: struct { + DepthBoundsTestSupported: BOOL, + ProgrammableSamplePositionsTier: PROGRAMMABLE_SAMPLE_POSITIONS_TIER, +} + +ROOT_SIGNATURE_VERSION :: enum i32 { + _1 = 1, + _1_0 = 1, + _1_1 = 2, +} + +FEATURE_DATA_ROOT_SIGNATURE :: struct { + HighestVersion: ROOT_SIGNATURE_VERSION, +} + +FEATURE_DATA_ARCHITECTURE :: struct { + NodeIndex: u32, + TileBasedRenderer: BOOL, + UMA: BOOL, + CacheCoherentUMA: BOOL, +} + +FEATURE_DATA_ARCHITECTURE1 :: struct { + NodeIndex: u32, + TileBasedRenderer: BOOL, + UMA: BOOL, + CacheCoherentUMA: BOOL, + IsolatedMMU: BOOL, +} + +FEATURE_DATA_FEATURE_LEVELS :: struct { + NumFeatureLevels: u32, + pFeatureLevelsRequested: ^FEATURE_LEVEL, + MaxSupportedFeatureLevel: FEATURE_LEVEL, +} + +SHADER_MODEL :: enum i32 { + _5_1 = 81, + _6_0 = 96, + _6_1 = 97, + _6_2 = 98, + _6_3 = 99, + _6_4 = 100, + _6_5 = 101, + _6_6 = 102, +} + +FEATURE_DATA_SHADER_MODEL :: struct { + HighestShaderModel: SHADER_MODEL, +} + +FEATURE_DATA_FORMAT_SUPPORT :: struct { + Format: dxgi.FORMAT, + Support1: FORMAT_SUPPORT1, + Support2: FORMAT_SUPPORT2, +} + +FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS :: struct { + Format: dxgi.FORMAT, + SampleCount: u32, + Flags: MULTISAMPLE_QUALITY_LEVEL_FLAGS, + NumQualityLevels: u32, +} + +FEATURE_DATA_FORMAT_INFO :: struct { + Format: dxgi.FORMAT, + PlaneCount: u8, +} + +FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT :: struct { + MaxGPUVirtualAddressBitsPerResource: u32, + MaxGPUVirtualAddressBitsPerProcess: u32, +} + +SHADER_CACHE_SUPPORT_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + SINGLE_PSO = 0x1, + LIBRARY = 0x2, + AUTOMATIC_INPROC_CACHE = 0x4, + AUTOMATIC_DISK_CACHE = 0x8, +} + +FEATURE_DATA_SHADER_CACHE :: struct { + SupportFlags: SHADER_CACHE_SUPPORT_FLAGS, +} + +FEATURE_DATA_COMMAND_QUEUE_PRIORITY :: struct { + CommandListType: COMMAND_LIST_TYPE, + Priority: u32, + PriorityForTypeIsSupported: BOOL, +} + +COMMAND_LIST_SUPPORT_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + DIRECT = 0x1, + BUNDLE = 0x2, + COMPUTE = 0x4, + COPY = 0x8, + VIDEO_DECODE = 0x10, + VIDEO_PROCESS = 0x20, + VIDEO_ENCODE = 0x40, +} + +FEATURE_DATA_OPTIONS3 :: struct { + CopyQueueTimestampQueriesSupported: BOOL, + CastingFullyTypedFormatSupported: BOOL, + WriteBufferImmediateSupportFlags: COMMAND_LIST_SUPPORT_FLAGS, + ViewInstancingTier: VIEW_INSTANCING_TIER, + BarycentricsSupported: BOOL, +} + +FEATURE_DATA_EXISTING_HEAPS :: struct { + Supported: BOOL, +} + +SHARED_RESOURCE_COMPATIBILITY_TIER :: enum i32 { + _0 = 0, + _1 = 1, + _2 = 2, +} + +FEATURE_DATA_OPTIONS4 :: struct { + MSAA64KBAlignedTextureSupported: BOOL, + SharedResourceCompatibilityTier: SHARED_RESOURCE_COMPATIBILITY_TIER, + Native16BitShaderOpsSupported: BOOL, +} + +HEAP_SERIALIZATION_TIER :: enum i32 { + _0 = 0, + _10 = 10, +} + +FEATURE_DATA_SERIALIZATION :: struct { + NodeIndex: u32, + HeapSerializationTier: HEAP_SERIALIZATION_TIER, +} + +FEATURE_DATA_CROSS_NODE :: struct { + SharingTier: CROSS_NODE_SHARING_TIER, + AtomicShaderInstructions: BOOL, +} + +RENDER_PASS_TIER :: enum i32 { + _0 = 0, + _1 = 1, + _2 = 2, +} + +RAYTRACING_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1_0 = 10, + _1_1 = 11, +} + +FEATURE_DATA_OPTIONS5 :: struct { + SRVOnlyTiledResourceTier3: BOOL, + RenderPassesTier: RENDER_PASS_TIER, + RaytracingTier: RAYTRACING_TIER, +} + +VARIABLE_SHADING_RATE_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1 = 1, + _2 = 2, +} + +FEATURE_DATA_OPTIONS6 :: struct { + AdditionalShadingRatesSupported: BOOL, + PerPrimitiveShadingRateSupportedWithViewportIndexing: BOOL, + VariableShadingRateTier: VARIABLE_SHADING_RATE_TIER, + ShadingRateImageTileSize: u32, + BackgroundProcessingSupported: BOOL, +} + +MESH_SHADER_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _1 = 10, +} + +SAMPLER_FEEDBACK_TIER :: enum i32 { + NOT_SUPPORTED = 0, + _0_9 = 90, + _1_0 = 100, +} + +FEATURE_DATA_OPTIONS7 :: struct { + MeshShaderTier: MESH_SHADER_TIER, + SamplerFeedbackTier: SAMPLER_FEEDBACK_TIER, +} + +FEATURE_DATA_QUERY_META_COMMAND :: struct { + CommandId: GUID, + NodeMask: u32, + pQueryInputData: rawptr, + QueryInputDataSizeInBytes: SIZE_T, + pQueryOutputData: rawptr, + QueryOutputDataSizeInBytes: SIZE_T, +} + +RESOURCE_ALLOCATION_INFO :: struct { + SizeInBytes: u64, + Alignment: u64, +} + +RESOURCE_ALLOCATION_INFO1 :: struct { + Offset: u64, + Alignment: u64, + SizeInBytes: u64, +} + +HEAP_TYPE :: enum i32 { + DEFAULT = 1, + UPLOAD = 2, + READBACK = 3, + CUSTOM = 4, +} + +CPU_PAGE_PROPERTY :: enum i32 { + UNKNOWN = 0, + NOT_AVAILABLE = 1, + WRITE_COMBINE = 2, + WRITE_BACK = 3, +} + +MEMORY_POOL :: enum i32 { + UNKNOWN = 0, + L0 = 1, + L1 = 2, +} + +HEAP_PROPERTIES :: struct { + Type: HEAP_TYPE, + CPUPageProperty: CPU_PAGE_PROPERTY, + MemoryPoolPreference: MEMORY_POOL, + CreationNodeMask: u32, + VisibleNodeMask: u32, +} + +HEAP_FLAGS :: enum u32 { // TODO: make bit_set ??? + NONE = 0x0, + SHARED = 0x1, + DENY_BUFFERS = 0x4, + ALLOW_DISPLAY = 0x8, + SHARED_CROSS_ADAPTER = 0x20, + DENY_RT_DS_TEXTURES = 0x40, + DENY_NON_RT_DS_TEXTURES = 0x80, + HARDWARE_PROTECTED = 0x100, + ALLOW_WRITE_WATCH = 0x200, + ALLOW_SHADER_ATOMICS = 0x400, + CREATE_NOT_RESIDENT = 0x800, + CREATE_NOT_ZEROED = 0x1000, + ALLOW_ALL_BUFFERS_AND_TEXTURES = 0x0, + ALLOW_ONLY_BUFFERS = 0xc0, + ALLOW_ONLY_NON_RT_DS_TEXTURES = 0x44, + ALLOW_ONLY_RT_DS_TEXTURES = 0x84, +} + +HEAP_DESC :: struct { + SizeInBytes: u64, + Properties: HEAP_PROPERTIES, + Alignment: u64, + Flags: HEAP_FLAGS, +} + +RESOURCE_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE2D = 3, + TEXTURE3D = 4, +} + +TEXTURE_LAYOUT :: enum i32 { + UNKNOWN = 0, + ROW_MAJOR = 1, + _64KB_UNDEFINED_SWIZZLE = 2, + _64KB_STANDARD_SWIZZLE = 3, +} + +RESOURCE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + ALLOW_RENDER_TARGET = 0x1, + ALLOW_DEPTH_STENCIL = 0x2, + ALLOW_UNORDERED_ACCESS = 0x4, + DENY_SHADER_RESOURCE = 0x8, + ALLOW_CROSS_ADAPTER = 0x10, + ALLOW_SIMULTANEOUS_ACCESS = 0x20, + VIDEO_DECODE_REFERENCE_ONLY = 0x40, +} + +MIP_REGION :: struct { + Width: u32, + Height: u32, + Depth: u32, +} + +RESOURCE_DESC :: struct { + Dimension: RESOURCE_DIMENSION, + Alignment: u64, + Width: u64, + Height: u32, + DepthOrArraySize: u16, + MipLevels: u16, + Format: dxgi.FORMAT, + SampleDesc: dxgi.SAMPLE_DESC, + Layout: TEXTURE_LAYOUT, + Flags: RESOURCE_FLAGS, +} + +RESOURCE_DESC1 :: struct { + Dimension: RESOURCE_DIMENSION, + Alignment: u64, + Width: u64, + Height: u32, + DepthOrArraySize: u16, + MipLevels: u16, + Format: dxgi.FORMAT, + SampleDesc: dxgi.SAMPLE_DESC, + Layout: TEXTURE_LAYOUT, + Flags: RESOURCE_FLAGS, + SamplerFeedbackMipRegion: MIP_REGION, +} + +DEPTH_STENCIL_VALUE :: struct { + Depth: f32, + Stencil: u8, +} + +CLEAR_VALUE :: struct { + Format: dxgi.FORMAT, + using _: struct #raw_union { + Color: [4]f32, + DepthStencil: DEPTH_STENCIL_VALUE, + }, +} + +RANGE :: struct { + Begin: SIZE_T, + End: SIZE_T, +} + +RANGE_UINT64 :: struct { + Begin: u64, + End: u64, +} + +SUBRESOURCE_RANGE_UINT64 :: struct { + Subresource: u32, + Range: RANGE_UINT64, +} + +SUBRESOURCE_INFO :: struct { + Offset: u64, + RowPitch: u32, + DepthPitch: u32, +} + +TILED_RESOURCE_COORDINATE :: struct { + X: u32, + Y: u32, + Z: u32, + Subresource: u32, +} + +TILE_REGION_SIZE :: struct { + NumTiles: u32, + UseBox: BOOL, + Width: u32, + Height: u16, + Depth: u16, +} + +TILE_RANGE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + NULL = 0x1, + SKIP = 0x2, + REUSE_SINGLE_TILE = 0x4, +} + +SUBRESOURCE_TILING :: struct { + WidthInTiles: u32, + HeightInTiles: u16, + DepthInTiles: u16, + StartTileIndexInOverallResource: u32, +} + +TILE_SHAPE :: struct { + WidthInTexels: u32, + HeightInTexels: u32, + DepthInTexels: u32, +} + +PACKED_MIP_INFO :: struct { + NumStandardMips: u8, + NumPackedMips: u8, + NumTilesForPackedMips: u32, + StartTileIndexInOverallResource: u32, +} + +TILE_MAPPING_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + NO_HAZARD = 0x1, +} + +TILE_COPY_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + NO_HAZARD = 0x1, + LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE = 0x2, + SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER = 0x4, +} + +RESOURCE_STATES :: enum i32 { // TODO: make bit_set + COMMON = 0, + VERTEX_AND_CONSTANT_BUFFER = 1, + INDEX_BUFFER = 2, + RENDER_TARGET = 4, + UNORDERED_ACCESS = 8, + DEPTH_WRITE = 16, + DEPTH_READ = 32, + NON_PIXEL_SHADER_RESOURCE = 64, + PIXEL_SHADER_RESOURCE = 128, + STREAM_OUT = 256, + INDIRECT_ARGUMENT = 512, + COPY_DEST = 1024, + COPY_SOURCE = 2048, + RESOLVE_DEST = 4096, + RESOLVE_SOURCE = 8192, + RAYTRACING_ACCELERATION_STRUCTURE = 4194304, + SHADING_RATE_SOURCE = 16777216, + GENERIC_READ = 2755, + PRESENT = 0, + PREDICATION = 512, + VIDEO_DECODE_READ = 65536, + VIDEO_DECODE_WRITE = 131072, + VIDEO_PROCESS_READ = 262144, + VIDEO_PROCESS_WRITE = 524288, + VIDEO_ENCODE_READ = 2097152, + VIDEO_ENCODE_WRITE = 8388608, +} + +RESOURCE_BARRIER_TYPE :: enum i32 { + TRANSITION = 0, + ALIASING = 1, + UAV = 2, +} + +RESOURCE_TRANSITION_BARRIER :: struct { + pResource: ^IResource, + Subresource: u32, + StateBefore: RESOURCE_STATES, + StateAfter: RESOURCE_STATES, +} + +RESOURCE_ALIASING_BARRIER :: struct { + pResourceBefore: ^IResource, + pResourceAfter: ^IResource, +} + +RESOURCE_UAV_BARRIER :: struct { + pResource: ^IResource, +} + +RESOURCE_BARRIER_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + BEGIN_ONLY = 0x1, + END_ONLY = 0x2, +} + +RESOURCE_BARRIER :: struct { + Type: RESOURCE_BARRIER_TYPE, + Flags: RESOURCE_BARRIER_FLAGS, + using _: struct #raw_union { + Transition: RESOURCE_TRANSITION_BARRIER, + Aliasing: RESOURCE_ALIASING_BARRIER, + UAV: RESOURCE_UAV_BARRIER, + }, +} + +SUBRESOURCE_FOOTPRINT :: struct { + Format: dxgi.FORMAT, + Width: u32, + Height: u32, + Depth: u32, + RowPitch: u32, +} + +PLACED_SUBRESOURCE_FOOTPRINT :: struct { + Offset: u64, + Footprint: SUBRESOURCE_FOOTPRINT, +} + +TEXTURE_COPY_TYPE :: enum i32 { + SUBRESOURCE_INDEX = 0, + PLACED_FOOTPRINT = 1, +} + +TEXTURE_COPY_LOCATION :: struct { + pResource: ^IResource, + Type: TEXTURE_COPY_TYPE, +} + +RESOLVE_MODE :: enum i32 { + DECOMPRESS = 0, + MIN = 1, + MAX = 2, + AVERAGE = 3, + ENCODE_SAMPLER_FEEDBACK = 4, + DECODE_SAMPLER_FEEDBACK = 5, +} + +SAMPLE_POSITION :: struct { + X: i8, + Y: i8, +} + +VIEW_INSTANCE_LOCATION :: struct { + ViewportArrayIndex: u32, + RenderTargetArrayIndex: u32, +} + +VIEW_INSTANCING_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + ENABLE_VIEW_INSTANCE_MASKING = 0x1, +} + +VIEW_INSTANCING_DESC :: struct { + ViewInstanceCount: u32, + pViewInstanceLocations: ^VIEW_INSTANCE_LOCATION, + Flags: VIEW_INSTANCING_FLAGS, +} + +SHADER_COMPONENT_MAPPING :: enum i32 { + FROM_MEMORY_COMPONENT_0 = 0, + FROM_MEMORY_COMPONENT_1 = 1, + FROM_MEMORY_COMPONENT_2 = 2, + FROM_MEMORY_COMPONENT_3 = 3, + FORCE_VALUE_0 = 4, + FORCE_VALUE_1 = 5, +} + +BUFFER_SRV_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + RAW = 0x1, +} + +BUFFER_SRV :: struct { + FirstElement: u64, + NumElements: u32, + StructureByteStride: u32, + Flags: BUFFER_SRV_FLAGS, +} + +TEX1D_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + ResourceMinLODClamp: f32, +} + +TEX1D_ARRAY_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + FirstArraySlice: u32, + ArraySize: u32, + ResourceMinLODClamp: f32, +} + +TEX2D_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + PlaneSlice: u32, + ResourceMinLODClamp: f32, +} + +TEX2D_ARRAY_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + FirstArraySlice: u32, + ArraySize: u32, + PlaneSlice: u32, + ResourceMinLODClamp: f32, +} + +TEX3D_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + ResourceMinLODClamp: f32, +} + +TEXCUBE_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + ResourceMinLODClamp: f32, +} + +TEXCUBE_ARRAY_SRV :: struct { + MostDetailedMip: u32, + MipLevels: u32, + First2DArrayFace: u32, + NumCubes: u32, + ResourceMinLODClamp: f32, +} + +TEX2DMS_SRV :: struct { + UnusedField_NothingToDefine: u32, +} + +TEX2DMS_ARRAY_SRV :: struct { + FirstArraySlice: u32, + ArraySize: u32, +} + +RAYTRACING_ACCELERATION_STRUCTURE_SRV :: struct { + Location: GPU_VIRTUAL_ADDRESS, +} + +SHADER_RESOURCE_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: SRV_DIMENSION, + Shader4ComponentMapping: u32, + using _: struct #raw_union { + Buffer: BUFFER_SRV, + Texture1D: TEX1D_SRV, + Texture1DArray: TEX1D_ARRAY_SRV, + Texture2D: TEX2D_SRV, + Texture2DArray: TEX2D_ARRAY_SRV, + Texture2DMS: TEX2DMS_SRV, + Texture2DMSArray: TEX2DMS_ARRAY_SRV, + Texture3D: TEX3D_SRV, + TextureCube: TEXCUBE_SRV, + TextureCubeArray: TEXCUBE_ARRAY_SRV, + RaytracingAccelerationStructure: RAYTRACING_ACCELERATION_STRUCTURE_SRV, + }, +} + +CONSTANT_BUFFER_VIEW_DESC :: struct { + BufferLocation: GPU_VIRTUAL_ADDRESS, + SizeInBytes: u32, +} + +FILTER :: enum i32 { + MIN_MAG_MIP_POINT = 0, + MIN_MAG_POINT_MIP_LINEAR = 1, + MIN_POINT_MAG_LINEAR_MIP_POINT = 4, + MIN_POINT_MAG_MIP_LINEAR = 5, + MIN_LINEAR_MAG_MIP_POINT = 16, + MIN_LINEAR_MAG_POINT_MIP_LINEAR = 17, + MIN_MAG_LINEAR_MIP_POINT = 20, + MIN_MAG_MIP_LINEAR = 21, + ANISOTROPIC = 85, + COMPARISON_MIN_MAG_MIP_POINT = 128, + COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 129, + COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 132, + COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 133, + COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 144, + COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 145, + COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 148, + COMPARISON_MIN_MAG_MIP_LINEAR = 149, + COMPARISON_ANISOTROPIC = 213, + MINIMUM_MIN_MAG_MIP_POINT = 256, + MINIMUM_MIN_MAG_POINT_MIP_LINEAR = 257, + MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 260, + MINIMUM_MIN_POINT_MAG_MIP_LINEAR = 261, + MINIMUM_MIN_LINEAR_MAG_MIP_POINT = 272, + MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 273, + MINIMUM_MIN_MAG_LINEAR_MIP_POINT = 276, + MINIMUM_MIN_MAG_MIP_LINEAR = 277, + MINIMUM_ANISOTROPIC = 341, + MAXIMUM_MIN_MAG_MIP_POINT = 384, + MAXIMUM_MIN_MAG_POINT_MIP_LINEAR = 385, + MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 388, + MAXIMUM_MIN_POINT_MAG_MIP_LINEAR = 389, + MAXIMUM_MIN_LINEAR_MAG_MIP_POINT = 400, + MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 401, + MAXIMUM_MIN_MAG_LINEAR_MIP_POINT = 404, + MAXIMUM_MIN_MAG_MIP_LINEAR = 405, + MAXIMUM_ANISOTROPIC = 469, +} + +FILTER_TYPE :: enum i32 { + POINT = 0, + LINEAR = 1, +} + +FILTER_REDUCTION_TYPE :: enum i32 { + STANDARD = 0, + COMPARISON = 1, + MINIMUM = 2, + MAXIMUM = 3, +} + +TEXTURE_ADDRESS_MODE :: enum i32 { + WRAP = 1, + MIRROR = 2, + CLAMP = 3, + BORDER = 4, + MIRROR_ONCE = 5, +} + +SAMPLER_DESC :: struct { + Filter: FILTER, + AddressU: TEXTURE_ADDRESS_MODE, + AddressV: TEXTURE_ADDRESS_MODE, + AddressW: TEXTURE_ADDRESS_MODE, + MipLODBias: f32, + MaxAnisotropy: u32, + ComparisonFunc: COMPARISON_FUNC, + BorderColor: [4]f32, + MinLOD: f32, + MaxLOD: f32, +} + +BUFFER_UAV_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + RAW = 0x1, +} + +BUFFER_UAV :: struct { + FirstElement: u64, + NumElements: u32, + StructureByteStride: u32, + CounterOffsetInBytes: u64, + Flags: BUFFER_UAV_FLAGS, +} + +TEX1D_UAV :: struct { + MipSlice: u32, +} + +TEX1D_ARRAY_UAV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2D_UAV :: struct { + MipSlice: u32, + PlaneSlice: u32, +} + +TEX2D_ARRAY_UAV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, + PlaneSlice: u32, +} + +TEX3D_UAV :: struct { + MipSlice: u32, + FirstWSlice: u32, + WSize: u32, +} + +UAV_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE3D = 8, +} + +UNORDERED_ACCESS_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: UAV_DIMENSION, + using _: struct #raw_union { + Buffer: BUFFER_UAV, + Texture1D: TEX1D_UAV, + Texture1DArray: TEX1D_ARRAY_UAV, + Texture2D: TEX2D_UAV, + Texture2DArray: TEX2D_ARRAY_UAV, + Texture3D: TEX3D_UAV, + }, +} + +BUFFER_RTV :: struct { + FirstElement: u64, + NumElements: u32, +} + +TEX1D_RTV :: struct { + MipSlice: u32, +} + +TEX1D_ARRAY_RTV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2D_RTV :: struct { + MipSlice: u32, + PlaneSlice: u32, +} + +TEX2DMS_RTV :: struct { + UnusedField_NothingToDefine: u32, +} + +TEX2D_ARRAY_RTV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, + PlaneSlice: u32, +} + +TEX2DMS_ARRAY_RTV :: struct { + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX3D_RTV :: struct { + MipSlice: u32, + FirstWSlice: u32, + WSize: u32, +} + +RTV_DIMENSION :: enum i32 { + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE2DMS = 6, + TEXTURE2DMSARRAY = 7, + TEXTURE3D = 8, +} + +RENDER_TARGET_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: RTV_DIMENSION, + using _: struct #raw_union { + Buffer: BUFFER_RTV, + Texture1D: TEX1D_RTV, + Texture1DArray: TEX1D_ARRAY_RTV, + Texture2D: TEX2D_RTV, + Texture2DArray: TEX2D_ARRAY_RTV, + Texture2DMS: TEX2DMS_RTV, + Texture2DMSArray: TEX2DMS_ARRAY_RTV, + Texture3D: TEX3D_RTV, + }, +} + +TEX1D_DSV :: struct { + MipSlice: u32, +} + +TEX1D_ARRAY_DSV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2D_DSV :: struct { + MipSlice: u32, +} + +TEX2D_ARRAY_DSV :: struct { + MipSlice: u32, + FirstArraySlice: u32, + ArraySize: u32, +} + +TEX2DMS_DSV :: struct { + UnusedField_NothingToDefine: u32, +} + +TEX2DMS_ARRAY_DSV :: struct { + FirstArraySlice: u32, + ArraySize: u32, +} + +DSV_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + READ_ONLY_DEPTH = 0x1, + READ_ONLY_STENCIL = 0x2, +} + +DSV_DIMENSION :: enum i32 { + UNKNOWN = 0, + TEXTURE1D = 1, + TEXTURE1DARRAY = 2, + TEXTURE2D = 3, + TEXTURE2DARRAY = 4, + TEXTURE2DMS = 5, + TEXTURE2DMSARRAY = 6, +} + +DEPTH_STENCIL_VIEW_DESC :: struct { + Format: dxgi.FORMAT, + ViewDimension: DSV_DIMENSION, + Flags: DSV_FLAGS, + using _: struct #raw_union { + Texture1D: TEX1D_DSV, + Texture1DArray: TEX1D_ARRAY_DSV, + Texture2D: TEX2D_DSV, + Texture2DArray: TEX2D_ARRAY_DSV, + Texture2DMS: TEX2DMS_DSV, + Texture2DMSArray: TEX2DMS_ARRAY_DSV, + }, +} + +CLEAR_FLAGS :: enum u32 { // TODO: make bit_set + DEPTH = 0x1, + STENCIL = 0x2, +} + +FENCE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + SHARED = 0x1, + SHARED_CROSS_ADAPTER = 0x2, + NON_MONITORED = 0x4, +} + +DESCRIPTOR_HEAP_TYPE :: enum i32 { + CBV_SRV_UAV = 0, + SAMPLER = 1, + RTV = 2, + DSV = 3, + NUM_TYPES = 4, +} + +DESCRIPTOR_HEAP_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + SHADER_VISIBLE = 0x1, +} + +DESCRIPTOR_HEAP_DESC :: struct { + Type: DESCRIPTOR_HEAP_TYPE, + NumDescriptors: u32, + Flags: DESCRIPTOR_HEAP_FLAGS, + NodeMask: u32, +} + +DESCRIPTOR_RANGE_TYPE :: enum i32 { + SRV = 0, + UAV = 1, + CBV = 2, + SAMPLER = 3, +} + +DESCRIPTOR_RANGE :: struct { + RangeType: DESCRIPTOR_RANGE_TYPE, + NumDescriptors: u32, + BaseShaderRegister: u32, + RegisterSpace: u32, + OffsetInDescriptorsFromTableStart: u32, +} + +ROOT_DESCRIPTOR_TABLE :: struct { + NumDescriptorRanges: u32, + pDescriptorRanges: ^DESCRIPTOR_RANGE, +} + +ROOT_CONSTANTS :: struct { + ShaderRegister: u32, + RegisterSpace: u32, + Num32BitValues: u32, +} + +ROOT_DESCRIPTOR :: struct { + ShaderRegister: u32, + RegisterSpace: u32, +} + +SHADER_VISIBILITY :: enum i32 { + ALL = 0, + VERTEX = 1, + HULL = 2, + DOMAIN = 3, + GEOMETRY = 4, + PIXEL = 5, + AMPLIFICATION = 6, + MESH = 7, +} + +ROOT_PARAMETER_TYPE :: enum i32 { + DESCRIPTOR_TABLE = 0, + _32BIT_CONSTANTS = 1, + CBV = 2, + SRV = 3, + UAV = 4, +} + +ROOT_PARAMETER :: struct { + ParameterType: ROOT_PARAMETER_TYPE, + using _: struct #raw_union { + DescriptorTable: ROOT_DESCRIPTOR_TABLE, + Constants: ROOT_CONSTANTS, + Descriptor: ROOT_DESCRIPTOR, + }, + ShaderVisibility: SHADER_VISIBILITY, +} + +ROOT_SIGNATURE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT = 0x1, + DENY_VERTEX_SHADER_ROOT_ACCESS = 0x2, + DENY_HULL_SHADER_ROOT_ACCESS = 0x4, + DENY_DOMAIN_SHADER_ROOT_ACCESS = 0x8, + DENY_GEOMETRY_SHADER_ROOT_ACCESS = 0x10, + DENY_PIXEL_SHADER_ROOT_ACCESS = 0x20, + ALLOW_STREAM_OUTPUT = 0x40, + LOCAL_ROOT_SIGNATURE = 0x80, + DENY_AMPLIFICATION_SHADER_ROOT_ACCESS = 0x100, + DENY_MESH_SHADER_ROOT_ACCESS = 0x200, +} + +STATIC_BORDER_COLOR :: enum i32 { + TRANSPARENT_BLACK = 0, + OPAQUE_BLACK = 1, + OPAQUE_WHITE = 2, +} + +STATIC_SAMPLER_DESC :: struct { + Filter: FILTER, + AddressU: TEXTURE_ADDRESS_MODE, + AddressV: TEXTURE_ADDRESS_MODE, + AddressW: TEXTURE_ADDRESS_MODE, + MipLODBias: f32, + MaxAnisotropy: u32, + ComparisonFunc: COMPARISON_FUNC, + BorderColor: STATIC_BORDER_COLOR, + MinLOD: f32, + MaxLOD: f32, + ShaderRegister: u32, + RegisterSpace: u32, + ShaderVisibility: SHADER_VISIBILITY, +} + +ROOT_SIGNATURE_DESC :: struct { + NumParameters: u32, + pParameters: ^ROOT_PARAMETER, + NumStaticSamplers: u32, + pStaticSamplers: ^STATIC_SAMPLER_DESC, + Flags: ROOT_SIGNATURE_FLAGS, +} + +DESCRIPTOR_RANGE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + DESCRIPTORS_VOLATILE = 0x1, + DATA_VOLATILE = 0x2, + DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4, + DATA_STATIC = 0x8, + DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS = 0x10000, +} + +DESCRIPTOR_RANGE1 :: struct { + RangeType: DESCRIPTOR_RANGE_TYPE, + NumDescriptors: u32, + BaseShaderRegister: u32, + RegisterSpace: u32, + Flags: DESCRIPTOR_RANGE_FLAGS, + OffsetInDescriptorsFromTableStart: u32, +} + +ROOT_DESCRIPTOR_TABLE1 :: struct { + NumDescriptorRanges: u32, + pDescriptorRanges: ^DESCRIPTOR_RANGE1, +} + +ROOT_DESCRIPTOR_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + DATA_VOLATILE = 0x2, + DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4, + DATA_STATIC = 0x8, +} + +ROOT_DESCRIPTOR1 :: struct { + ShaderRegister: u32, + RegisterSpace: u32, + Flags: ROOT_DESCRIPTOR_FLAGS, +} + +ROOT_PARAMETER1 :: struct { + ParameterType: ROOT_PARAMETER_TYPE, + using _: struct #raw_union { + DescriptorTable: ROOT_DESCRIPTOR_TABLE1, + Constants: ROOT_CONSTANTS, + Descriptor: ROOT_DESCRIPTOR1, + }, + ShaderVisibility: SHADER_VISIBILITY, +} + +ROOT_SIGNATURE_DESC1 :: struct { + NumParameters: u32, + pParameters: ^ROOT_PARAMETER1, + NumStaticSamplers: u32, + pStaticSamplers: ^STATIC_SAMPLER_DESC, + Flags: ROOT_SIGNATURE_FLAGS, +} + +VERSIONED_ROOT_SIGNATURE_DESC :: struct { + Version: ROOT_SIGNATURE_VERSION, + using _: struct #raw_union { + Desc_1_0: ROOT_SIGNATURE_DESC, + Desc_1_1: ROOT_SIGNATURE_DESC1, + }, +} + + +IRootSignatureDeserializer_UUID :: "34AB647B-3CC8-46AC-841B-C0965645C046" +IRootSignatureDeserializer :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12rootsignaturedeserializer_vtable: ^IRootSignatureDeserializer_VTable, +} +IRootSignatureDeserializer_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetRootSignatureDesc: proc "stdcall" (this: ^IRootSignatureDeserializer) -> ^ROOT_SIGNATURE_DESC, +} + + +IVersionedRootSignatureDeserializer_UUID :: "7F91CE67-090C-4BB7-B78E-ED8FF2E31DA0" +IVersionedRootSignatureDeserializer :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12versionedrootsignaturedeserializer_vtable: ^IVersionedRootSignatureDeserializer_VTable, +} +IVersionedRootSignatureDeserializer_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetRootSignatureDescAtVersion: proc "stdcall" (this: ^IVersionedRootSignatureDeserializer, convertToVersion: ROOT_SIGNATURE_VERSION, ppDesc: ^^VERSIONED_ROOT_SIGNATURE_DESC) -> HRESULT, + GetUnconvertedRootSignatureDesc: proc "stdcall" (this: ^IVersionedRootSignatureDeserializer) -> ^VERSIONED_ROOT_SIGNATURE_DESC, +} + +PFN_SERIALIZE_ROOT_SIGNATURE :: #type proc "c" (a0: ^ROOT_SIGNATURE_DESC, a1: ROOT_SIGNATURE_VERSION, a2: ^^IBlob, a3: ^^IBlob) -> HRESULT +PFN_CREATE_ROOT_SIGNATURE_DESERIALIZER :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: ^IID, a3: ^rawptr) -> HRESULT +PFN_SERIALIZE_VERSIONED_ROOT_SIGNATURE :: #type proc "c" (a0: ^VERSIONED_ROOT_SIGNATURE_DESC, a1: ^^IBlob, a2: ^^IBlob) -> HRESULT +PFN_CREATE_VERSIONED_ROOT_SIGNATURE_DESERIALIZER :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: ^IID, a3: ^rawptr) -> HRESULT + + +CPU_DESCRIPTOR_HANDLE :: struct { + ptr: SIZE_T, +} + +GPU_DESCRIPTOR_HANDLE :: struct { + ptr: u64, +} + +DISCARD_REGION :: struct { + NumRects: u32, + pRects: ^RECT, + FirstSubresource: u32, + NumSubresources: u32, +} + +QUERY_HEAP_TYPE :: enum i32 { + OCCLUSION = 0, + TIMESTAMP = 1, + PIPELINE_STATISTICS = 2, + SO_STATISTICS = 3, + VIDEO_DECODE_STATISTICS = 4, + COPY_QUEUE_TIMESTAMP = 5, +} + +QUERY_HEAP_DESC :: struct { + Type: QUERY_HEAP_TYPE, + Count: u32, + NodeMask: u32, +} + +QUERY_TYPE :: enum i32 { + OCCLUSION = 0, + BINARY_OCCLUSION = 1, + TIMESTAMP = 2, + PIPELINE_STATISTICS = 3, + SO_STATISTICS_STREAM0 = 4, + SO_STATISTICS_STREAM1 = 5, + SO_STATISTICS_STREAM2 = 6, + SO_STATISTICS_STREAM3 = 7, + VIDEO_DECODE_STATISTICS = 8, +} + +PREDICATION_OP :: enum i32 { + EQUAL_ZERO = 0, + NOT_EQUAL_ZERO = 1, +} + +QUERY_DATA_PIPELINE_STATISTICS :: struct { + IAVertices: u64, + IAPrimitives: u64, + VSInvocations: u64, + GSInvocations: u64, + GSPrimitives: u64, + CInvocations: u64, + CPrimitives: u64, + PSInvocations: u64, + HSInvocations: u64, + DSInvocations: u64, + CSInvocations: u64, +} + +QUERY_DATA_SO_STATISTICS :: struct { + NumPrimitivesWritten: u64, + PrimitivesStorageNeeded: u64, +} + +STREAM_OUTPUT_BUFFER_VIEW :: struct { + BufferLocation: GPU_VIRTUAL_ADDRESS, + SizeInBytes: u64, + BufferFilledSizeLocation: GPU_VIRTUAL_ADDRESS, +} + +DRAW_ARGUMENTS :: struct { + VertexCountPerInstance: u32, + InstanceCount: u32, + StartVertexLocation: u32, + StartInstanceLocation: u32, +} + +DRAW_INDEXED_ARGUMENTS :: struct { + IndexCountPerInstance: u32, + InstanceCount: u32, + StartIndexLocation: u32, + BaseVertexLocation: i32, + StartInstanceLocation: u32, +} + +DISPATCH_ARGUMENTS :: struct { + ThreadGroupCountX: u32, + ThreadGroupCountY: u32, + ThreadGroupCountZ: u32, +} + +VERTEX_BUFFER_VIEW :: struct { + BufferLocation: GPU_VIRTUAL_ADDRESS, + SizeInBytes: u32, + StrideInBytes: u32, +} + +INDEX_BUFFER_VIEW :: struct { + BufferLocation: GPU_VIRTUAL_ADDRESS, + SizeInBytes: u32, + Format: dxgi.FORMAT, +} + +INDIRECT_ARGUMENT_TYPE :: enum i32 { + DRAW = 0, + DRAW_INDEXED = 1, + DISPATCH = 2, + VERTEX_BUFFER_VIEW = 3, + INDEX_BUFFER_VIEW = 4, + CONSTANT = 5, + CONSTANT_BUFFER_VIEW = 6, + SHADER_RESOURCE_VIEW = 7, + UNORDERED_ACCESS_VIEW = 8, + DISPATCH_RAYS = 9, + DISPATCH_MESH = 10, +} + +INDIRECT_ARGUMENT_DESC :: struct { + Type: INDIRECT_ARGUMENT_TYPE, + using _: struct #raw_union { + VertexBuffer: struct { + Slot: u32, + }, + Constant: struct { + RootParameterIndex: u32, + DestOffsetIn32BitValues: u32, + Num32BitValuesToSet: u32, + }, + ConstantBufferView: struct { + RootParameterIndex: u32, + }, + ShaderResourceView: struct { + RootParameterIndex: u32, + }, + UnorderedAccessView: struct { + RootParameterIndex: u32, + }, + }, +} + +COMMAND_SIGNATURE_DESC :: struct { + ByteStride: u32, + NumArgumentDescs: u32, + pArgumentDescs: ^INDIRECT_ARGUMENT_DESC, + NodeMask: u32, +} + + +IPageable_UUID :: "63ee58fb-1268-4835-86da-f008ce62f0d6" +IPageable :: struct { + using id3d12devicechild: IDeviceChild, +} + + +IHeap_UUID :: "6b3b2502-6e51-45b3-90ee-9884265e8df3" +IHeap :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12heap_vtable: ^IHeap_VTable, +} +IHeap_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + GetDesc: proc "stdcall" (this: ^IHeap) -> HEAP_DESC, +} + + +IResource_UUID :: "696442be-a72e-4059-bc79-5b5c98040fad" +IResource :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12resource_vtable: ^IResource_VTable, +} +IResource_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + Map: proc "stdcall" (this: ^IResource, Subresource: u32, pReadRange: ^RANGE, ppData: ^rawptr) -> HRESULT, + Unmap: proc "stdcall" (this: ^IResource, Subresource: u32, pWrittenRange: ^RANGE), + GetDesc: proc "stdcall" (this: ^IResource) -> RESOURCE_DESC, + GetGPUVirtualAddress: proc "stdcall" (this: ^IResource) -> GPU_VIRTUAL_ADDRESS, + WriteToSubresource: proc "stdcall" (this: ^IResource, DstSubresource: u32, pDstBox: ^BOX, pSrcData: rawptr, SrcRowPitch: u32, SrcDepthPitch: u32) -> HRESULT, + ReadFromSubresource: proc "stdcall" (this: ^IResource, pDstData: rawptr, DstRowPitch: u32, DstDepthPitch: u32, SrcSubresource: u32, pSrcBox: ^BOX) -> HRESULT, + GetHeapProperties: proc "stdcall" (this: ^IResource, pHeapProperties: ^HEAP_PROPERTIES, pHeapFlags: ^HEAP_FLAGS) -> HRESULT, +} + + +ICommandAllocator_UUID :: "6102dee4-af59-4b09-b999-b44d73f09b24" +ICommandAllocator :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12commandallocator_vtable: ^ICommandAllocator_VTable, +} +ICommandAllocator_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + Reset: proc "stdcall" (this: ^ICommandAllocator) -> HRESULT, +} + + +IFence_UUID :: "0a753dcf-c4d8-4b91-adf6-be5a60d95a76" +IFence :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12fence_vtable: ^IFence_VTable, +} +IFence_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + GetCompletedValue: proc "stdcall" (this: ^IFence) -> u64, + SetEventOnCompletion: proc "stdcall" (this: ^IFence, Value: u64, hEvent: HANDLE) -> HRESULT, + Signal: proc "stdcall" (this: ^IFence, Value: u64) -> HRESULT, +} + + +IFence1_UUID :: "433685fe-e22b-4ca0-a8db-b5b4f4dd0e4a" +IFence1 :: struct #raw_union { + #subtype id3d12fence: IFence, + using id3d12fence1_vtable: ^IFence1_VTable, +} +IFence1_VTable :: struct { + #subtype id3d12fence_vtable: IFence_VTable, + GetCreationFlags: proc "stdcall" (this: ^IFence1) -> FENCE_FLAGS, +} + + +IPipelineState_UUID :: "765a30f3-f624-4c6f-a828-ace948622445" +IPipelineState :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12pipelinestate_vtable: ^IPipelineState_VTable, +} +IPipelineState_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + GetCachedBlob: proc "stdcall" (this: ^IPipelineState, ppBlob: ^^IBlob) -> HRESULT, +} + + +IDescriptorHeap_UUID :: "8efb471d-616c-4f49-90f7-127bb763fa51" +IDescriptorHeap :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12descriptorheap_vtable: ^IDescriptorHeap_VTable, +} +IDescriptorHeap_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + GetDesc: proc "stdcall" (this: ^IDescriptorHeap) -> DESCRIPTOR_HEAP_DESC, + GetCPUDescriptorHandleForHeapStart: proc "stdcall" (this: ^IDescriptorHeap) -> CPU_DESCRIPTOR_HANDLE, + GetGPUDescriptorHandleForHeapStart: proc "stdcall" (this: ^IDescriptorHeap) -> GPU_DESCRIPTOR_HANDLE, +} + + +IQueryHeap_UUID :: "0d9658ae-ed45-469e-a61d-970ec583cab4" +IQueryHeap :: struct { + #subtype id3d12pageable: IPageable, +} + + +ICommandSignature_UUID :: "c36a797c-ec80-4f0a-8985-a7b2475082d1" +ICommandSignature :: struct { + #subtype id3d12pageable: IPageable, +} + + +ICommandList_UUID :: "7116d91c-e7e4-47ce-b8c6-ec8168f437e5" +ICommandList :: struct #raw_union { + #subtype id3d12devicechild: IDeviceChild, + using id3d12commandlist_vtable: ^ICommandList_VTable, +} +ICommandList_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + GetType: proc "stdcall" (this: ^ICommandList) -> COMMAND_LIST_TYPE, +} + + +IGraphicsCommandList_UUID :: "5b160d0f-ac1b-4185-8ba8-b3ae42a5a455" +IGraphicsCommandList :: struct #raw_union { + #subtype id3d12commandlist: ICommandList, + using id3d12graphicscommandlist_vtable: ^IGraphicsCommandList_VTable, +} +IGraphicsCommandList_VTable :: struct { + using id3d12commandlist_vtable: ICommandList_VTable, + Close: proc "stdcall" (this: ^IGraphicsCommandList) -> HRESULT, + Reset: proc "stdcall" (this: ^IGraphicsCommandList, pAllocator: ^ICommandAllocator, pInitialState: ^IPipelineState) -> HRESULT, + ClearState: proc "stdcall" (this: ^IGraphicsCommandList, pPipelineState: ^IPipelineState), + DrawInstanced: proc "stdcall" (this: ^IGraphicsCommandList, VertexCountPerInstance: u32, InstanceCount: u32, StartVertexLocation: u32, StartInstanceLocation: u32), + DrawIndexedInstanced: proc "stdcall" (this: ^IGraphicsCommandList, IndexCountPerInstance: u32, InstanceCount: u32, StartIndexLocation: u32, BaseVertexLocation: i32, StartInstanceLocation: u32), + Dispatch: proc "stdcall" (this: ^IGraphicsCommandList, ThreadGroupCountX: u32, ThreadGroupCountY: u32, ThreadGroupCountZ: u32), + CopyBufferRegion: proc "stdcall" (this: ^IGraphicsCommandList, pDstBuffer: ^IResource, DstOffset: u64, pSrcBuffer: ^IResource, SrcOffset: u64, NumBytes: u64), + CopyTextureRegion: proc "stdcall" (this: ^IGraphicsCommandList, pDst: ^TEXTURE_COPY_LOCATION, DstX: u32, DstY: u32, DstZ: u32, pSrc: ^TEXTURE_COPY_LOCATION, pSrcBox: ^BOX), + CopyResource: proc "stdcall" (this: ^IGraphicsCommandList, pDstResource: ^IResource, pSrcResource: ^IResource), + CopyTiles: proc "stdcall" (this: ^IGraphicsCommandList, pTiledResource: ^IResource, pTileRegionStartCoordinate: ^TILED_RESOURCE_COORDINATE, pTileRegionSize: ^TILE_REGION_SIZE, pBuffer: ^IResource, BufferStartOffsetInBytes: u64, Flags: TILE_COPY_FLAGS), + ResolveSubresource: proc "stdcall" (this: ^IGraphicsCommandList, pDstResource: ^IResource, DstSubresource: u32, pSrcResource: ^IResource, SrcSubresource: u32, Format: dxgi.FORMAT), + IASetPrimitiveTopology: proc "stdcall" (this: ^IGraphicsCommandList, PrimitiveTopology: PRIMITIVE_TOPOLOGY), + RSSetViewports: proc "stdcall" (this: ^IGraphicsCommandList, NumViewports: u32, pViewports: ^VIEWPORT), + RSSetScissorRects: proc "stdcall" (this: ^IGraphicsCommandList, NumRects: u32, pRects: ^RECT), + OMSetBlendFactor: proc "stdcall" (this: ^IGraphicsCommandList, BlendFactor: ^[4]f32), + OMSetStencilRef: proc "stdcall" (this: ^IGraphicsCommandList, StencilRef: u32), + SetPipelineState: proc "stdcall" (this: ^IGraphicsCommandList, pPipelineState: ^IPipelineState), + ResourceBarrier: proc "stdcall" (this: ^IGraphicsCommandList, NumBarriers: u32, pBarriers: ^RESOURCE_BARRIER), + ExecuteBundle: proc "stdcall" (this: ^IGraphicsCommandList, pCommandList: ^IGraphicsCommandList), + SetDescriptorHeaps: proc "stdcall" (this: ^IGraphicsCommandList, NumDescriptorHeaps: u32, ppDescriptorHeaps: ^^IDescriptorHeap), + SetComputeRootSignature: proc "stdcall" (this: ^IGraphicsCommandList, pRootSignature: ^IRootSignature), + SetGraphicsRootSignature: proc "stdcall" (this: ^IGraphicsCommandList, pRootSignature: ^IRootSignature), + SetComputeRootDescriptorTable: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BaseDescriptor: GPU_DESCRIPTOR_HANDLE), + SetGraphicsRootDescriptorTable: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BaseDescriptor: GPU_DESCRIPTOR_HANDLE), + SetComputeRoot32BitConstant: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, SrcData: u32, DestOffsetIn32BitValues: u32), + SetGraphicsRoot32BitConstant: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, SrcData: u32, DestOffsetIn32BitValues: u32), + SetComputeRoot32BitConstants: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, Num32BitValuesToSet: u32, pSrcData: rawptr, DestOffsetIn32BitValues: u32), + SetGraphicsRoot32BitConstants: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, Num32BitValuesToSet: u32, pSrcData: rawptr, DestOffsetIn32BitValues: u32), + SetComputeRootConstantBufferView: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BufferLocation: GPU_VIRTUAL_ADDRESS), + SetGraphicsRootConstantBufferView: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BufferLocation: GPU_VIRTUAL_ADDRESS), + SetComputeRootShaderResourceView: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BufferLocation: GPU_VIRTUAL_ADDRESS), + SetGraphicsRootShaderResourceView: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BufferLocation: GPU_VIRTUAL_ADDRESS), + SetComputeRootUnorderedAccessView: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BufferLocation: GPU_VIRTUAL_ADDRESS), + SetGraphicsRootUnorderedAccessView: proc "stdcall" (this: ^IGraphicsCommandList, RootParameterIndex: u32, BufferLocation: GPU_VIRTUAL_ADDRESS), + IASetIndexBuffer: proc "stdcall" (this: ^IGraphicsCommandList, pView: ^INDEX_BUFFER_VIEW), + IASetVertexBuffers: proc "stdcall" (this: ^IGraphicsCommandList, StartSlot: u32, NumViews: u32, pViews: ^VERTEX_BUFFER_VIEW), + SOSetTargets: proc "stdcall" (this: ^IGraphicsCommandList, StartSlot: u32, NumViews: u32, pViews: ^STREAM_OUTPUT_BUFFER_VIEW), + OMSetRenderTargets: proc "stdcall" (this: ^IGraphicsCommandList, NumRenderTargetDescriptors: u32, pRenderTargetDescriptors: ^CPU_DESCRIPTOR_HANDLE, RTsSingleHandleToDescriptorRange: BOOL, pDepthStencilDescriptor: ^CPU_DESCRIPTOR_HANDLE), + ClearDepthStencilView: proc "stdcall" (this: ^IGraphicsCommandList, DepthStencilView: CPU_DESCRIPTOR_HANDLE, ClearFlags: CLEAR_FLAGS, Depth: f32, Stencil: u8, NumRects: u32, pRects: ^RECT), + ClearRenderTargetView: proc "stdcall" (this: ^IGraphicsCommandList, RenderTargetView: CPU_DESCRIPTOR_HANDLE, ColorRGBA: ^[4]f32, NumRects: u32, pRects: ^RECT), + ClearUnorderedAccessViewUint: proc "stdcall" (this: ^IGraphicsCommandList, ViewGPUHandleInCurrentHeap: GPU_DESCRIPTOR_HANDLE, ViewCPUHandle: CPU_DESCRIPTOR_HANDLE, pResource: ^IResource, Values: ^[4]u32, NumRects: u32, pRects: ^RECT), + ClearUnorderedAccessViewFloat: proc "stdcall" (this: ^IGraphicsCommandList, ViewGPUHandleInCurrentHeap: GPU_DESCRIPTOR_HANDLE, ViewCPUHandle: CPU_DESCRIPTOR_HANDLE, pResource: ^IResource, Values: ^[4]f32, NumRects: u32, pRects: ^RECT), + DiscardResource: proc "stdcall" (this: ^IGraphicsCommandList, pResource: ^IResource, pRegion: ^DISCARD_REGION), + BeginQuery: proc "stdcall" (this: ^IGraphicsCommandList, pQueryHeap: ^IQueryHeap, Type: QUERY_TYPE, Index: u32), + EndQuery: proc "stdcall" (this: ^IGraphicsCommandList, pQueryHeap: ^IQueryHeap, Type: QUERY_TYPE, Index: u32), + ResolveQueryData: proc "stdcall" (this: ^IGraphicsCommandList, pQueryHeap: ^IQueryHeap, Type: QUERY_TYPE, StartIndex: u32, NumQueries: u32, pDestinationBuffer: ^IResource, AlignedDestinationBufferOffset: u64), + SetPredication: proc "stdcall" (this: ^IGraphicsCommandList, pBuffer: ^IResource, AlignedBufferOffset: u64, Operation: PREDICATION_OP), + SetMarker: proc "stdcall" (this: ^IGraphicsCommandList, Metadata: u32, pData: rawptr, Size: u32), + BeginEvent: proc "stdcall" (this: ^IGraphicsCommandList, Metadata: u32, pData: rawptr, Size: u32), + EndEvent: proc "stdcall" (this: ^IGraphicsCommandList), + ExecuteIndirect: proc "stdcall" (this: ^IGraphicsCommandList, pCommandSignature: ^ICommandSignature, MaxCommandCount: u32, pArgumentBuffer: ^IResource, ArgumentBufferOffset: u64, pCountBuffer: ^IResource, CountBufferOffset: u64), +} + + +IGraphicsCommandList1_UUID :: "553103fb-1fe7-4557-bb38-946d7d0e7ca7" +IGraphicsCommandList1 :: struct #raw_union { + #subtype id3d12graphicscommandlist: IGraphicsCommandList, + using id3d12graphicscommandlist1_vtable: ^IGraphicsCommandList1_VTable, +} +IGraphicsCommandList1_VTable :: struct { + using id3d12graphicscommandlist_vtable: IGraphicsCommandList_VTable, + AtomicCopyBufferUINT: proc "stdcall" (this: ^IGraphicsCommandList1, pDstBuffer: ^IResource, DstOffset: u64, pSrcBuffer: ^IResource, SrcOffset: u64, Dependencies: u32, ppDependentResources: ^^IResource, pDependentSubresourceRanges: ^SUBRESOURCE_RANGE_UINT64), + AtomicCopyBufferUINT64: proc "stdcall" (this: ^IGraphicsCommandList1, pDstBuffer: ^IResource, DstOffset: u64, pSrcBuffer: ^IResource, SrcOffset: u64, Dependencies: u32, ppDependentResources: ^^IResource, pDependentSubresourceRanges: ^SUBRESOURCE_RANGE_UINT64), + OMSetDepthBounds: proc "stdcall" (this: ^IGraphicsCommandList1, Min: f32, Max: f32), + SetSamplePositions: proc "stdcall" (this: ^IGraphicsCommandList1, NumSamplesPerPixel: u32, NumPixels: u32, pSamplePositions: ^SAMPLE_POSITION), + ResolveSubresourceRegion: proc "stdcall" (this: ^IGraphicsCommandList1, pDstResource: ^IResource, DstSubresource: u32, DstX: u32, DstY: u32, pSrcResource: ^IResource, SrcSubresource: u32, pSrcRect: ^RECT, Format: dxgi.FORMAT, ResolveMode: RESOLVE_MODE), + SetViewInstanceMask: proc "stdcall" (this: ^IGraphicsCommandList1, Mask: u32), +} + +WRITEBUFFERIMMEDIATE_PARAMETER :: struct { + Dest: GPU_VIRTUAL_ADDRESS, + Value: u32, +} + +WRITEBUFFERIMMEDIATE_MODE :: enum i32 { + DEFAULT = 0, + MARKER_IN = 1, + MARKER_OUT = 2, +} + + +IGraphicsCommandList2_UUID :: "38C3E585-FF17-412C-9150-4FC6F9D72A28" +IGraphicsCommandList2 :: struct #raw_union { + #subtype id3d12graphicscommandlist1: IGraphicsCommandList1, + using id3d12graphicscommandlist2_vtable: ^IGraphicsCommandList2_VTable, +} +IGraphicsCommandList2_VTable :: struct { + using id3d12graphicscommandlist1_vtable: IGraphicsCommandList1_VTable, + WriteBufferImmediate: proc "stdcall" (this: ^IGraphicsCommandList2, Count: u32, pParams: ^WRITEBUFFERIMMEDIATE_PARAMETER, pModes: ^WRITEBUFFERIMMEDIATE_MODE), +} + + +ICommandQueue_UUID :: "0ec870a6-5d7e-4c22-8cfc-5baae07616ed" +ICommandQueue :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12commandqueue_vtable: ^ICommandQueue_VTable, +} +ICommandQueue_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + UpdateTileMappings: proc "stdcall" (this: ^ICommandQueue, pResource: ^IResource, NumResourceRegions: u32, pResourceRegionStartCoordinates: ^TILED_RESOURCE_COORDINATE, pResourceRegionSizes: ^TILE_REGION_SIZE, pHeap: ^IHeap, NumRanges: u32, pRangeFlags: ^TILE_RANGE_FLAGS, pHeapRangeStartOffsets: ^u32, pRangeTileCounts: ^u32, Flags: TILE_MAPPING_FLAGS), + CopyTileMappings: proc "stdcall" (this: ^ICommandQueue, pDstResource: ^IResource, pDstRegionStartCoordinate: ^TILED_RESOURCE_COORDINATE, pSrcResource: ^IResource, pSrcRegionStartCoordinate: ^TILED_RESOURCE_COORDINATE, pRegionSize: ^TILE_REGION_SIZE, Flags: TILE_MAPPING_FLAGS), + ExecuteCommandLists: proc "stdcall" (this: ^ICommandQueue, NumCommandLists: u32, ppCommandLists: ^^ICommandList), + SetMarker: proc "stdcall" (this: ^ICommandQueue, Metadata: u32, pData: rawptr, Size: u32), + BeginEvent: proc "stdcall" (this: ^ICommandQueue, Metadata: u32, pData: rawptr, Size: u32), + EndEvent: proc "stdcall" (this: ^ICommandQueue), + Signal: proc "stdcall" (this: ^ICommandQueue, pFence: ^IFence, Value: u64) -> HRESULT, + Wait: proc "stdcall" (this: ^ICommandQueue, pFence: ^IFence, Value: u64) -> HRESULT, + GetTimestampFrequency: proc "stdcall" (this: ^ICommandQueue, pFrequency: ^u64) -> HRESULT, + GetClockCalibration: proc "stdcall" (this: ^ICommandQueue, pGpuTimestamp: ^u64, pCpuTimestamp: ^u64) -> HRESULT, + GetDesc: proc "stdcall" (this: ^ICommandQueue) -> COMMAND_QUEUE_DESC, +} + + +IDevice_UUID :: "189819f1-1db6-4b57-be54-1821339b85f7" +IDevice :: struct #raw_union { + #subtype id3d12object: IObject, + using id3d12device_vtable: ^IDevice_VTable, +} +IDevice_VTable :: struct { + using id3d12object_vtable: IObject_VTable, + GetNodeCount: proc "stdcall" (this: ^IDevice) -> u32, + CreateCommandQueue: proc "stdcall" (this: ^IDevice, pDesc: ^COMMAND_QUEUE_DESC, riid: ^IID, ppCommandQueue: ^rawptr) -> HRESULT, + CreateCommandAllocator: proc "stdcall" (this: ^IDevice, type: COMMAND_LIST_TYPE, riid: ^IID, ppCommandAllocator: ^rawptr) -> HRESULT, + CreateGraphicsPipelineState: proc "stdcall" (this: ^IDevice, pDesc: ^GRAPHICS_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, + CreateComputePipelineState: proc "stdcall" (this: ^IDevice, pDesc: ^COMPUTE_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, + CreateCommandList: proc "stdcall" (this: ^IDevice, nodeMask: u32, type: COMMAND_LIST_TYPE, pCommandAllocator: ^ICommandAllocator, pInitialState: ^IPipelineState, riid: ^IID, ppCommandList: ^rawptr) -> HRESULT, + CheckFeatureSupport: proc "stdcall" (this: ^IDevice, Feature: FEATURE, pFeatureSupportData: rawptr, FeatureSupportDataSize: u32) -> HRESULT, + CreateDescriptorHeap: proc "stdcall" (this: ^IDevice, pDescriptorHeapDesc: ^DESCRIPTOR_HEAP_DESC, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, + GetDescriptorHandleIncrementSize: proc "stdcall" (this: ^IDevice, DescriptorHeapType: DESCRIPTOR_HEAP_TYPE) -> u32, + CreateRootSignature: proc "stdcall" (this: ^IDevice, nodeMask: u32, pBlobWithRootSignature: rawptr, blobLengthInBytes: SIZE_T, riid: ^IID, ppvRootSignature: ^rawptr) -> HRESULT, + CreateConstantBufferView: proc "stdcall" (this: ^IDevice, pDesc: ^CONSTANT_BUFFER_VIEW_DESC, DestDescriptor: CPU_DESCRIPTOR_HANDLE), + CreateShaderResourceView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pDesc: ^SHADER_RESOURCE_VIEW_DESC, DestDescriptor: CPU_DESCRIPTOR_HANDLE), + CreateUnorderedAccessView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pCounterResource: ^IResource, pDesc: ^UNORDERED_ACCESS_VIEW_DESC, DestDescriptor: CPU_DESCRIPTOR_HANDLE), + CreateRenderTargetView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pDesc: ^RENDER_TARGET_VIEW_DESC, DestDescriptor: CPU_DESCRIPTOR_HANDLE), + CreateDepthStencilView: proc "stdcall" (this: ^IDevice, pResource: ^IResource, pDesc: ^DEPTH_STENCIL_VIEW_DESC, DestDescriptor: CPU_DESCRIPTOR_HANDLE), + CreateSampler: proc "stdcall" (this: ^IDevice, pDesc: ^SAMPLER_DESC, DestDescriptor: CPU_DESCRIPTOR_HANDLE), + CopyDescriptors: proc "stdcall" (this: ^IDevice, NumDestDescriptorRanges: u32, pDestDescriptorRangeStarts: ^CPU_DESCRIPTOR_HANDLE, pDestDescriptorRangeSizes: ^u32, NumSrcDescriptorRanges: u32, pSrcDescriptorRangeStarts: ^CPU_DESCRIPTOR_HANDLE, pSrcDescriptorRangeSizes: ^u32, DescriptorHeapsType: DESCRIPTOR_HEAP_TYPE), + CopyDescriptorsSimple: proc "stdcall" (this: ^IDevice, NumDescriptors: u32, DestDescriptorRangeStart: CPU_DESCRIPTOR_HANDLE, SrcDescriptorRangeStart: CPU_DESCRIPTOR_HANDLE, DescriptorHeapsType: DESCRIPTOR_HEAP_TYPE), + GetResourceAllocationInfo: proc "stdcall" (this: ^IDevice, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC) -> RESOURCE_ALLOCATION_INFO, + GetCustomHeapProperties: proc "stdcall" (this: ^IDevice, nodeMask: u32, heapType: HEAP_TYPE) -> HEAP_PROPERTIES, + CreateCommittedResource: proc "stdcall" (this: ^IDevice, pHeapProperties: ^HEAP_PROPERTIES, HeapFlags: HEAP_FLAGS, pDesc: ^RESOURCE_DESC, InitialResourceState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riidResource: ^IID, ppvResource: ^rawptr) -> HRESULT, + CreateHeap: proc "stdcall" (this: ^IDevice, pDesc: ^HEAP_DESC, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, + CreatePlacedResource: proc "stdcall" (this: ^IDevice, pHeap: ^IHeap, HeapOffset: u64, pDesc: ^RESOURCE_DESC, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, + CreateReservedResource: proc "stdcall" (this: ^IDevice, pDesc: ^RESOURCE_DESC, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, + CreateSharedHandle: proc "stdcall" (this: ^IDevice, pObject: ^IDeviceChild, pAttributes: ^win32.SECURITY_ATTRIBUTES, Access: u32, Name: [^]u16, pHandle: ^HANDLE) -> HRESULT, + OpenSharedHandle: proc "stdcall" (this: ^IDevice, NTHandle: HANDLE, riid: ^IID, ppvObj: ^rawptr) -> HRESULT, + OpenSharedHandleByName: proc "stdcall" (this: ^IDevice, Name: [^]u16, Access: u32, pNTHandle: ^HANDLE) -> HRESULT, + MakeResident: proc "stdcall" (this: ^IDevice, NumObjects: u32, ppObjects: ^^IPageable) -> HRESULT, + Evict: proc "stdcall" (this: ^IDevice, NumObjects: u32, ppObjects: ^^IPageable) -> HRESULT, + CreateFence: proc "stdcall" (this: ^IDevice, InitialValue: u64, Flags: FENCE_FLAGS, riid: ^IID, ppFence: ^rawptr) -> HRESULT, + GetDeviceRemovedReason: proc "stdcall" (this: ^IDevice) -> HRESULT, + GetCopyableFootprints: proc "stdcall" (this: ^IDevice, pResourceDesc: ^RESOURCE_DESC, FirstSubresource: u32, NumSubresources: u32, BaseOffset: u64, pLayouts: ^PLACED_SUBRESOURCE_FOOTPRINT, pNumRows: ^u32, pRowSizeInBytes: ^u64, pTotalBytes: ^u64), + CreateQueryHeap: proc "stdcall" (this: ^IDevice, pDesc: ^QUERY_HEAP_DESC, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, + SetStablePowerState: proc "stdcall" (this: ^IDevice, Enable: BOOL) -> HRESULT, + CreateCommandSignature: proc "stdcall" (this: ^IDevice, pDesc: ^COMMAND_SIGNATURE_DESC, pRootSignature: ^IRootSignature, riid: ^IID, ppvCommandSignature: ^rawptr) -> HRESULT, + GetResourceTiling: proc "stdcall" (this: ^IDevice, pTiledResource: ^IResource, pNumTilesForEntireResource: ^u32, pPackedMipDesc: ^PACKED_MIP_INFO, pStandardTileShapeForNonPackedMips: ^TILE_SHAPE, pNumSubresourceTilings: ^u32, FirstSubresourceTilingToGet: u32, pSubresourceTilingsForNonPackedMips: ^SUBRESOURCE_TILING), + GetAdapterLuid: proc "stdcall" (this: ^IDevice) -> LUID, +} + + +IPipelineLibrary_UUID :: "c64226a8-9201-46af-b4cc-53fb9ff7414f" +IPipelineLibrary :: struct #raw_union { + #subtype id3d12devicechild: IDeviceChild, + using id3d12pipelinelibrary_vtable: ^IPipelineLibrary_VTable, +} +IPipelineLibrary_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + StorePipeline: proc "stdcall" (this: ^IPipelineLibrary, pName: [^]u16, pPipeline: ^IPipelineState) -> HRESULT, + LoadGraphicsPipeline: proc "stdcall" (this: ^IPipelineLibrary, pName: [^]u16, pDesc: ^GRAPHICS_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, + LoadComputePipeline: proc "stdcall" (this: ^IPipelineLibrary, pName: [^]u16, pDesc: ^COMPUTE_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, + GetSerializedSize: proc "stdcall" (this: ^IPipelineLibrary) -> SIZE_T, + Serialize: proc "stdcall" (this: ^IPipelineLibrary, pData: rawptr, DataSizeInBytes: SIZE_T) -> HRESULT, +} + + +IPipelineLibrary1_UUID :: "80eabf42-2568-4e5e-bd82-c37f86961dc3" +IPipelineLibrary1 :: struct #raw_union { + #subtype id3d12pipelinelibrary: IPipelineLibrary, + using id3d12pipelinelibrary1_vtable: ^IPipelineLibrary1_VTable, +} +IPipelineLibrary1_VTable :: struct { + using id3d12pipelinelibrary_vtable: IPipelineLibrary_VTable, + LoadPipeline: proc "stdcall" (this: ^IPipelineLibrary1, pName: [^]u16, pDesc: ^PIPELINE_STATE_STREAM_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, +} + +MULTIPLE_FENCE_WAIT_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + ANY = 0x1, + ALL = 0x0, +} + +RESIDENCY_PRIORITY :: enum i32 { + MINIMUM = 671088640, + LOW = 1342177280, + NORMAL = 2013265920, + HIGH = -1610547200, + MAXIMUM = -939524096, +} + + +IDevice1_UUID :: "77acce80-638e-4e65-8895-c1f23386863e" +IDevice1 :: struct #raw_union { + #subtype id3d12device: IDevice, + using id3d12device1_vtable: ^IDevice1_VTable, +} +IDevice1_VTable :: struct { + using id3d12device_vtable: IDevice_VTable, + CreatePipelineLibrary: proc "stdcall" (this: ^IDevice1, pLibraryBlob: rawptr, BlobLength: SIZE_T, riid: ^IID, ppPipelineLibrary: ^rawptr) -> HRESULT, + SetEventOnMultipleFenceCompletion: proc "stdcall" (this: ^IDevice1, ppFences: ^^IFence, pFenceValues: ^u64, NumFences: u32, Flags: MULTIPLE_FENCE_WAIT_FLAGS, hEvent: HANDLE) -> HRESULT, + SetResidencyPriority: proc "stdcall" (this: ^IDevice1, NumObjects: u32, ppObjects: ^^IPageable, pPriorities: ^RESIDENCY_PRIORITY) -> HRESULT, +} + + +IDevice2_UUID :: "30baa41e-b15b-475c-a0bb-1af5c5b64328" +IDevice2 :: struct #raw_union { + #subtype id3d12device1: IDevice1, + using id3d12device2_vtable: ^IDevice2_VTable, +} +IDevice2_VTable :: struct { + using id3d12device1_vtable: IDevice1_VTable, + CreatePipelineState: proc "stdcall" (this: ^IDevice2, pDesc: ^PIPELINE_STATE_STREAM_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, +} + +RESIDENCY_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + DENY_OVERBUDGET = 0x1, +} + + +IDevice3_UUID :: "81dadc15-2bad-4392-93c5-101345c4aa98" +IDevice3 :: struct #raw_union { + #subtype id3d12device2: IDevice2, + using id3d12device3_vtable: ^IDevice3_VTable, +} +IDevice3_VTable :: struct { + using id3d12device2_vtable: IDevice2_VTable, + OpenExistingHeapFromAddress: proc "stdcall" (this: ^IDevice3, pAddress: rawptr, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, + OpenExistingHeapFromFileMapping: proc "stdcall" (this: ^IDevice3, hFileMapping: HANDLE, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, + EnqueueMakeResident: proc "stdcall" (this: ^IDevice3, Flags: RESIDENCY_FLAGS, NumObjects: u32, ppObjects: ^^IPageable, pFenceToSignal: ^IFence, FenceValueToSignal: u64) -> HRESULT, +} + +COMMAND_LIST_FLAGS :: enum u32 { // TODO: make bit_set + COMMAND_LIST_FLAG_NONE = 0x0, +} + +COMMAND_POOL_FLAGS :: enum u32 { // TODO: make bit_set + COMMAND_POOL_FLAG_NONE = 0x0, +} + +COMMAND_RECORDER_FLAGS :: enum u32 { // TODO: make bit_set + COMMAND_RECORDER_FLAG_NONE = 0x0, +} + +PROTECTED_SESSION_STATUS :: enum i32 { + OK = 0, + INVALID = 1, +} + + +IProtectedSession_UUID :: "A1533D18-0AC1-4084-85B9-89A96116806B" +IProtectedSession :: struct #raw_union { + #subtype id3d12devicechild: IDeviceChild, + using id3d12protectedsession_vtable: ^IProtectedSession_VTable, +} +IProtectedSession_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + GetStatusFence: proc "stdcall" (this: ^IProtectedSession, riid: ^IID, ppFence: ^rawptr) -> HRESULT, + GetSessionStatus: proc "stdcall" (this: ^IProtectedSession) -> PROTECTED_SESSION_STATUS, +} + +PROTECTED_RESOURCE_SESSION_SUPPORT_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + SUPPORTED = 0x1, +} + +FEATURE_DATA_PROTECTED_RESOURCE_SESSION_SUPPORT :: struct { + NodeIndex: u32, + Support: PROTECTED_RESOURCE_SESSION_SUPPORT_FLAGS, +} + +PROTECTED_RESOURCE_SESSION_FLAGS :: enum u32 { // TODO: make bit_set + PROTECTED_RESOURCE_SESSION_FLAG_NONE = 0x0, +} + +PROTECTED_RESOURCE_SESSION_DESC :: struct { + NodeMask: u32, + Flags: PROTECTED_RESOURCE_SESSION_FLAGS, +} + + +IProtectedResourceSession_UUID :: "6CD696F4-F289-40CC-8091-5A6C0A099C3D" +IProtectedResourceSession :: struct #raw_union { + #subtype id3d12protectedsession: IProtectedSession, + using id3d12protectedresourcesession_vtable: ^IProtectedResourceSession_VTable, +} +IProtectedResourceSession_VTable :: struct { + using id3d12protectedsession_vtable: IProtectedSession_VTable, + GetDesc: proc "stdcall" (this: ^IProtectedResourceSession) -> PROTECTED_RESOURCE_SESSION_DESC, +} + + +IDevice4_UUID :: "e865df17-a9ee-46f9-a463-3098315aa2e5" +IDevice4 :: struct #raw_union { + #subtype id3d12device3: IDevice3, + using id3d12device4_vtable: ^IDevice4_VTable, +} +IDevice4_VTable :: struct { + using id3d12device3_vtable: IDevice3_VTable, + CreateCommandList1: proc "stdcall" (this: ^IDevice4, nodeMask: u32, type: COMMAND_LIST_TYPE, flags: COMMAND_LIST_FLAGS, riid: ^IID, ppCommandList: ^rawptr) -> HRESULT, + CreateProtectedResourceSession: proc "stdcall" (this: ^IDevice4, pDesc: ^PROTECTED_RESOURCE_SESSION_DESC, riid: ^IID, ppSession: ^rawptr) -> HRESULT, + CreateCommittedResource1: proc "stdcall" (this: ^IDevice4, pHeapProperties: ^HEAP_PROPERTIES, HeapFlags: HEAP_FLAGS, pDesc: ^RESOURCE_DESC, InitialResourceState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, pProtectedSession: ^IProtectedResourceSession, riidResource: ^IID, ppvResource: ^rawptr) -> HRESULT, + CreateHeap1: proc "stdcall" (this: ^IDevice4, pDesc: ^HEAP_DESC, pProtectedSession: ^IProtectedResourceSession, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, + CreateReservedResource1: proc "stdcall" (this: ^IDevice4, pDesc: ^RESOURCE_DESC, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, pProtectedSession: ^IProtectedResourceSession, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, + GetResourceAllocationInfo1: proc "stdcall" (this: ^IDevice4, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC, pResourceAllocationInfo1: ^RESOURCE_ALLOCATION_INFO1) -> RESOURCE_ALLOCATION_INFO, +} + +LIFETIME_STATE :: enum i32 { + IN_USE = 0, + NOT_IN_USE = 1, +} + + +ILifetimeOwner_UUID :: "e667af9f-cd56-4f46-83ce-032e595d70a8" +ILifetimeOwner :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12lifetimeowner_vtable: ^ILifetimeOwner_VTable, +} +ILifetimeOwner_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + LifetimeStateUpdated: proc "stdcall" (this: ^ILifetimeOwner, NewState: LIFETIME_STATE), +} + + +ISwapChainAssistant_UUID :: "f1df64b6-57fd-49cd-8807-c0eb88b45c8f" +ISwapChainAssistant :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12swapchainassistant_vtable: ^ISwapChainAssistant_VTable, +} +ISwapChainAssistant_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetLUID: proc "stdcall" (this: ^ISwapChainAssistant) -> LUID, + GetSwapChainObject: proc "stdcall" (this: ^ISwapChainAssistant, riid: ^IID, ppv: ^rawptr) -> HRESULT, + GetCurrentResourceAndCommandQueue: proc "stdcall" (this: ^ISwapChainAssistant, riidResource: ^IID, ppvResource: ^rawptr, riidQueue: ^IID, ppvQueue: ^rawptr) -> HRESULT, + InsertImplicitSync: proc "stdcall" (this: ^ISwapChainAssistant) -> HRESULT, +} + + +ILifetimeTracker_UUID :: "3fd03d36-4eb1-424a-a582-494ecb8ba813" +ILifetimeTracker :: struct #raw_union { + #subtype id3d12devicechild: IDeviceChild, + using id3d12lifetimetracker_vtable: ^ILifetimeTracker_VTable, +} +ILifetimeTracker_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + DestroyOwnedObject: proc "stdcall" (this: ^ILifetimeTracker, pObject: ^IDeviceChild) -> HRESULT, +} + +META_COMMAND_PARAMETER_TYPE :: enum i32 { + FLOAT = 0, + UINT64 = 1, + GPU_VIRTUAL_ADDRESS = 2, + CPU_DESCRIPTOR_HANDLE_HEAP_TYPE_CBV_SRV_UAV = 3, + GPU_DESCRIPTOR_HANDLE_HEAP_TYPE_CBV_SRV_UAV = 4, +} + +META_COMMAND_PARAMETER_FLAGS :: enum u32 { // TODO: make bit_set + INPUT = 0x1, + OUTPUT = 0x2, +} + +META_COMMAND_PARAMETER_STAGE :: enum i32 { + CREATION = 0, + INITIALIZATION = 1, + EXECUTION = 2, +} + +META_COMMAND_PARAMETER_DESC :: struct { + Name: [^]u16, + Type: META_COMMAND_PARAMETER_TYPE, + Flags: META_COMMAND_PARAMETER_FLAGS, + RequiredResourceState: RESOURCE_STATES, + StructureOffset: u32, +} + +GRAPHICS_STATES :: enum i32 { + NONE = 0, + IA_VERTEX_BUFFERS = 1, + IA_INDEX_BUFFER = 2, + IA_PRIMITIVE_TOPOLOGY = 4, + DESCRIPTOR_HEAP = 8, + GRAPHICS_ROOT_SIGNATURE = 16, + COMPUTE_ROOT_SIGNATURE = 32, + RS_VIEWPORTS = 64, + RS_SCISSOR_RECTS = 128, + PREDICATION = 256, + OM_RENDER_TARGETS = 512, + OM_STENCIL_REF = 1024, + OM_BLEND_FACTOR = 2048, + PIPELINE_STATE = 4096, + SO_TARGETS = 8192, + OM_DEPTH_BOUNDS = 16384, + SAMPLE_POSITIONS = 32768, + VIEW_INSTANCE_MASK = 65536, +} + +META_COMMAND_DESC :: struct { + Id: GUID, + Name: [^]u16, + InitializationDirtyState: GRAPHICS_STATES, + ExecutionDirtyState: GRAPHICS_STATES, +} + + +IStateObject_UUID :: "47016943-fca8-4594-93ea-af258b55346d" +IStateObject :: struct #raw_union { + #subtype id3d12pageable: IPageable, +} + + +IStateObjectProperties_UUID :: "de5fa827-9bf9-4f26-89ff-d7f56fde3860" +IStateObjectProperties :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12stateobjectproperties_vtable: ^IStateObjectProperties_VTable, +} +IStateObjectProperties_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetShaderIdentifier: proc "stdcall" (this: ^IStateObjectProperties, pExportName: [^]u16) -> rawptr, + GetShaderStackSize: proc "stdcall" (this: ^IStateObjectProperties, pExportName: [^]u16) -> u64, + GetPipelineStackSize: proc "stdcall" (this: ^IStateObjectProperties) -> u64, + SetPipelineStackSize: proc "stdcall" (this: ^IStateObjectProperties, PipelineStackSizeInBytes: u64), +} + +STATE_SUBOBJECT_TYPE :: enum i32 { + STATE_OBJECT_CONFIG = 0, + GLOBAL_ROOT_SIGNATURE = 1, + LOCAL_ROOT_SIGNATURE = 2, + NODE_MASK = 3, + DXIL_LIBRARY = 5, + EXISTING_COLLECTION = 6, + SUBOBJECT_TO_EXPORTS_ASSOCIATION = 7, + DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION = 8, + RAYTRACING_SHADER_CONFIG = 9, + RAYTRACING_PIPELINE_CONFIG = 10, + HIT_GROUP = 11, + RAYTRACING_PIPELINE_CONFIG1 = 12, + MAX_VALID = 13, +} + +STATE_SUBOBJECT :: struct { + Type: STATE_SUBOBJECT_TYPE, + pDesc: rawptr, +} + +STATE_OBJECT_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + ALLOW_LOCAL_DEPENDENCIES_ON_EXTERNAL_DEFINITIONS = 0x1, + ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL_DEFINITIONS = 0x2, + ALLOW_STATE_OBJECT_ADDITIONS = 0x4, +} + +STATE_OBJECT_CONFIG :: struct { + Flags: STATE_OBJECT_FLAGS, +} + +GLOBAL_ROOT_SIGNATURE :: struct { + pGlobalRootSignature: ^IRootSignature, +} + +LOCAL_ROOT_SIGNATURE :: struct { + pLocalRootSignature: ^IRootSignature, +} + +NODE_MASK :: struct { + NodeMask: u32, +} + +EXPORT_FLAGS :: enum u32 { // TODO: make bit_set + EXPORT_FLAG_NONE = 0x0, +} + +EXPORT_DESC :: struct { + Name: [^]u16, + ExportToRename: [^]u16, + Flags: EXPORT_FLAGS, +} + +DXIL_LIBRARY_DESC :: struct { + DXILLibrary: SHADER_BYTECODE, + NumExports: u32, + pExports: ^EXPORT_DESC, +} + +EXISTING_COLLECTION_DESC :: struct { + pExistingCollection: ^IStateObject, + NumExports: u32, + pExports: ^EXPORT_DESC, +} + +SUBOBJECT_TO_EXPORTS_ASSOCIATION :: struct { + pSubobjectToAssociate: ^STATE_SUBOBJECT, + NumExports: u32, + pExports: [^]^i16, +} + +DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION :: struct { + SubobjectToAssociate: ^i16, + NumExports: u32, + pExports: [^]^i16, +} + +HIT_GROUP_TYPE :: enum i32 { + TRIANGLES = 0, + PROCEDURAL_PRIMITIVE = 1, +} + +HIT_GROUP_DESC :: struct { + HitGroupExport: ^i16, + Type: HIT_GROUP_TYPE, + AnyHitShaderImport: ^i16, + ClosestHitShaderImport: ^i16, + IntersectionShaderImport: ^i16, +} + +RAYTRACING_SHADER_CONFIG :: struct { + MaxPayloadSizeInBytes: u32, + MaxAttributeSizeInBytes: u32, +} + +RAYTRACING_PIPELINE_CONFIG :: struct { + MaxTraceRecursionDepth: u32, +} + +RAYTRACING_PIPELINE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + SKIP_TRIANGLES = 0x100, + SKIP_PROCEDURAL_PRIMITIVES = 0x200, +} + +RAYTRACING_PIPELINE_CONFIG1 :: struct { + MaxTraceRecursionDepth: u32, + Flags: RAYTRACING_PIPELINE_FLAGS, +} + +STATE_OBJECT_TYPE :: enum i32 { + COLLECTION = 0, + RAYTRACING_PIPELINE = 3, +} + +STATE_OBJECT_DESC :: struct { + Type: STATE_OBJECT_TYPE, + NumSubobjects: u32, + pSubobjects: ^STATE_SUBOBJECT, +} + +RAYTRACING_GEOMETRY_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + OPAQUE = 0x1, + NO_DUPLICATE_ANYHIT_INVOCATION = 0x2, +} + +RAYTRACING_GEOMETRY_TYPE :: enum i32 { + TRIANGLES = 0, + PROCEDURAL_PRIMITIVE_AABBS = 1, +} + +RAYTRACING_INSTANCE_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + TRIANGLE_CULL_DISABLE = 0x1, + TRIANGLE_FRONT_COUNTERCLOCKWISE = 0x2, + FORCE_OPAQUE = 0x4, + FORCE_NON_OPAQUE = 0x8, +} + +GPU_VIRTUAL_ADDRESS_AND_STRIDE :: struct { + StartAddress: GPU_VIRTUAL_ADDRESS, + StrideInBytes: u64, +} + +GPU_VIRTUAL_ADDRESS_RANGE :: struct { + StartAddress: GPU_VIRTUAL_ADDRESS, + SizeInBytes: u64, +} + +GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE :: struct { + StartAddress: GPU_VIRTUAL_ADDRESS, + SizeInBytes: u64, + StrideInBytes: u64, +} + +RAYTRACING_GEOMETRY_TRIANGLES_DESC :: struct { + Transform3x4: GPU_VIRTUAL_ADDRESS, + IndexFormat: dxgi.FORMAT, + VertexFormat: dxgi.FORMAT, + IndexCount: u32, + VertexCount: u32, + IndexBuffer: GPU_VIRTUAL_ADDRESS, + VertexBuffer: GPU_VIRTUAL_ADDRESS_AND_STRIDE, +} + +RAYTRACING_AABB :: struct { + MinX: f32, + MinY: f32, + MinZ: f32, + MaxX: f32, + MaxY: f32, + MaxZ: f32, +} + +RAYTRACING_GEOMETRY_AABBS_DESC :: struct { + AABBCount: u64, + AABBs: GPU_VIRTUAL_ADDRESS_AND_STRIDE, +} + +RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + ALLOW_UPDATE = 0x1, + ALLOW_COMPACTION = 0x2, + PREFER_FAST_TRACE = 0x4, + PREFER_FAST_BUILD = 0x8, + MINIMIZE_MEMORY = 0x10, + PERFORM_UPDATE = 0x20, +} + +RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE :: enum i32 { + CLONE = 0, + COMPACT = 1, + VISUALIZATION_DECODE_FOR_TOOLS = 2, + SERIALIZE = 3, + DESERIALIZE = 4, +} + +RAYTRACING_ACCELERATION_STRUCTURE_TYPE :: enum i32 { + TOP_LEVEL = 0, + BOTTOM_LEVEL = 1, +} + +ELEMENTS_LAYOUT :: enum i32 { + ARRAY = 0, + ARRAY_OF_POINTERS = 1, +} + +RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_TYPE :: enum i32 { + COMPACTED_SIZE = 0, + TOOLS_VISUALIZATION = 1, + SERIALIZATION = 2, + CURRENT_SIZE = 3, +} + +RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC :: struct { + DestBuffer: GPU_VIRTUAL_ADDRESS, + InfoType: RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_TYPE, +} + +RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC :: struct { + CompactedSizeInBytes: u64, +} + +RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_TOOLS_VISUALIZATION_DESC :: struct { + DecodedSizeInBytes: u64, +} + +BUILD_RAYTRACING_ACCELERATION_STRUCTURE_TOOLS_VISUALIZATION_HEADER :: struct { + Type: RAYTRACING_ACCELERATION_STRUCTURE_TYPE, + NumDescs: u32, +} + +RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_SERIALIZATION_DESC :: struct { + SerializedSizeInBytes: u64, + NumBottomLevelAccelerationStructurePointers: u64, +} + +SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER :: struct { + DriverOpaqueGUID: GUID, + DriverOpaqueVersioningData: [16]u8, +} + +SERIALIZED_DATA_TYPE :: enum i32 { + SERIALIZED_DATA_RAYTRACING_ACCELERATION_STRUCTURE = 0, +} + +DRIVER_MATCHING_IDENTIFIER_STATUS :: enum i32 { + COMPATIBLE_WITH_DEVICE = 0, + UNSUPPORTED_TYPE = 1, + UNRECOGNIZED = 2, + INCOMPATIBLE_VERSION = 3, + INCOMPATIBLE_TYPE = 4, +} + +SERIALIZED_RAYTRACING_ACCELERATION_STRUCTURE_HEADER :: struct { + DriverMatchingIdentifier: SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER, + SerializedSizeInBytesIncludingHeader: u64, + DeserializedSizeInBytes: u64, + NumBottomLevelAccelerationStructurePointersAfterHeader: u64, +} + +RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_CURRENT_SIZE_DESC :: struct { + CurrentSizeInBytes: u64, +} + +RAYTRACING_INSTANCE_DESC :: struct { + Transform: [3][4]f32, + InstanceID: u32, + InstanceContributionToHitGroupIndex: u32, + AccelerationStructure: GPU_VIRTUAL_ADDRESS, +} + +RAYTRACING_GEOMETRY_DESC :: struct { + Type: RAYTRACING_GEOMETRY_TYPE, + Flags: RAYTRACING_GEOMETRY_FLAGS, + using _: struct #raw_union { + Triangles: RAYTRACING_GEOMETRY_TRIANGLES_DESC, + AABBs: RAYTRACING_GEOMETRY_AABBS_DESC, + }, +} + +BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS :: struct { + Type: RAYTRACING_ACCELERATION_STRUCTURE_TYPE, + Flags: RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS, + NumDescs: u32, + DescsLayout: ELEMENTS_LAYOUT, + using _: struct #raw_union { + InstanceDescs: GPU_VIRTUAL_ADDRESS, + pGeometryDescs: ^RAYTRACING_GEOMETRY_DESC, + ppGeometryDescs: ^^RAYTRACING_GEOMETRY_DESC, + }, +} + +BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC :: struct { + DestAccelerationStructureData: GPU_VIRTUAL_ADDRESS, + Inputs: BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS, + SourceAccelerationStructureData: GPU_VIRTUAL_ADDRESS, + ScratchAccelerationStructureData: GPU_VIRTUAL_ADDRESS, +} + +RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO :: struct { + ResultDataMaxSizeInBytes: u64, + ScratchDataSizeInBytes: u64, + UpdateScratchDataSizeInBytes: u64, +} + +RAY_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + FORCE_OPAQUE = 0x1, + FORCE_NON_OPAQUE = 0x2, + ACCEPT_FIRST_HIT_AND_END_SEARCH = 0x4, + SKIP_CLOSEST_HIT_SHADER = 0x8, + CULL_BACK_FACING_TRIANGLES = 0x10, + CULL_FRONT_FACING_TRIANGLES = 0x20, + CULL_OPAQUE = 0x40, + CULL_NON_OPAQUE = 0x80, + SKIP_TRIANGLES = 0x100, + SKIP_PROCEDURAL_PRIMITIVES = 0x200, +} + +HIT_KIND :: enum i32 { + TRIANGLE_FRONT_FACE = 254, + TRIANGLE_BACK_FACE = 255, +} + + +IDevice5_UUID :: "8b4f173b-2fea-4b80-8f58-4307191ab95d" +IDevice5 :: struct #raw_union { + #subtype id3d12device4: IDevice4, + using id3d12device5_vtable: ^IDevice5_VTable, +} +IDevice5_VTable :: struct { + using id3d12device4_vtable: IDevice4_VTable, + CreateLifetimeTracker: proc "stdcall" (this: ^IDevice5, pOwner: ^ILifetimeOwner, riid: ^IID, ppvTracker: ^rawptr) -> HRESULT, + RemoveDevice: proc "stdcall" (this: ^IDevice5), + EnumerateMetaCommands: proc "stdcall" (this: ^IDevice5, pNumMetaCommands: ^u32, pDescs: ^META_COMMAND_DESC) -> HRESULT, + EnumerateMetaCommandParameters: proc "stdcall" (this: ^IDevice5, CommandId: ^GUID, Stage: META_COMMAND_PARAMETER_STAGE, pTotalStructureSizeInBytes: ^u32, pParameterCount: ^u32, pParameterDescs: ^META_COMMAND_PARAMETER_DESC) -> HRESULT, + CreateMetaCommand: proc "stdcall" (this: ^IDevice5, CommandId: ^GUID, NodeMask: u32, pCreationParametersData: rawptr, CreationParametersDataSizeInBytes: SIZE_T, riid: ^IID, ppMetaCommand: ^rawptr) -> HRESULT, + CreateStateObject: proc "stdcall" (this: ^IDevice5, pDesc: ^STATE_OBJECT_DESC, riid: ^IID, ppStateObject: ^rawptr) -> HRESULT, + GetRaytracingAccelerationStructurePrebuildInfo: proc "stdcall" (this: ^IDevice5, pDesc: ^BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS, pInfo: ^RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO), + CheckDriverMatchingIdentifier: proc "stdcall" (this: ^IDevice5, SerializedDataType: SERIALIZED_DATA_TYPE, pIdentifierToCheck: ^SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER) -> DRIVER_MATCHING_IDENTIFIER_STATUS, +} + +AUTO_BREADCRUMB_OP :: enum i32 { + SETMARKER = 0, + BEGINEVENT = 1, + ENDEVENT = 2, + DRAWINSTANCED = 3, + DRAWINDEXEDINSTANCED = 4, + EXECUTEINDIRECT = 5, + DISPATCH = 6, + COPYBUFFERREGION = 7, + COPYTEXTUREREGION = 8, + COPYRESOURCE = 9, + COPYTILES = 10, + RESOLVESUBRESOURCE = 11, + CLEARRENDERTARGETVIEW = 12, + CLEARUNORDEREDACCESSVIEW = 13, + CLEARDEPTHSTENCILVIEW = 14, + RESOURCEBARRIER = 15, + EXECUTEBUNDLE = 16, + PRESENT = 17, + RESOLVEQUERYDATA = 18, + BEGINSUBMISSION = 19, + ENDSUBMISSION = 20, + DECODEFRAME = 21, + PROCESSFRAMES = 22, + ATOMICCOPYBUFFERUINT = 23, + ATOMICCOPYBUFFERUINT64 = 24, + RESOLVESUBRESOURCEREGION = 25, + WRITEBUFFERIMMEDIATE = 26, + DECODEFRAME1 = 27, + SETPROTECTEDRESOURCESESSION = 28, + DECODEFRAME2 = 29, + PROCESSFRAMES1 = 30, + BUILDRAYTRACINGACCELERATIONSTRUCTURE = 31, + EMITRAYTRACINGACCELERATIONSTRUCTUREPOSTBUILDINFO = 32, + COPYRAYTRACINGACCELERATIONSTRUCTURE = 33, + DISPATCHRAYS = 34, + INITIALIZEMETACOMMAND = 35, + EXECUTEMETACOMMAND = 36, + ESTIMATEMOTION = 37, + RESOLVEMOTIONVECTORHEAP = 38, + SETPIPELINESTATE1 = 39, + INITIALIZEEXTENSIONCOMMAND = 40, + EXECUTEEXTENSIONCOMMAND = 41, + DISPATCHMESH = 42, +} + +AUTO_BREADCRUMB_NODE :: struct { + pCommandListDebugNameA: cstring, + pCommandListDebugNameW: [^]u16, + pCommandQueueDebugNameA: cstring, + pCommandQueueDebugNameW: [^]u16, + pCommandList: ^IGraphicsCommandList, + pCommandQueue: ^ICommandQueue, + BreadcrumbCount: u32, + pLastBreadcrumbValue: ^u32, + pCommandHistory: ^AUTO_BREADCRUMB_OP, + pNext: ^AUTO_BREADCRUMB_NODE, +} + +DRED_BREADCRUMB_CONTEXT :: struct { + BreadcrumbIndex: u32, + pContextString: [^]u16, +} + +AUTO_BREADCRUMB_NODE1 :: struct { + pCommandListDebugNameA: cstring, + pCommandListDebugNameW: [^]u16, + pCommandQueueDebugNameA: cstring, + pCommandQueueDebugNameW: [^]u16, + pCommandList: ^IGraphicsCommandList, + pCommandQueue: ^ICommandQueue, + BreadcrumbCount: u32, + pLastBreadcrumbValue: ^u32, + pCommandHistory: ^AUTO_BREADCRUMB_OP, + pNext: ^AUTO_BREADCRUMB_NODE1, + BreadcrumbContextsCount: u32, + pBreadcrumbContexts: ^DRED_BREADCRUMB_CONTEXT, +} + +DRED_VERSION :: enum i32 { + _1_0 = 1, + _1_1 = 2, + _1_2 = 3, +} + +DRED_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + FORCE_ENABLE = 0x1, + DISABLE_AUTOBREADCRUMBS = 0x2, +} + +DRED_ENABLEMENT :: enum i32 { + SYSTEM_CONTROLLED = 0, + FORCED_OFF = 1, + FORCED_ON = 2, +} + +DEVICE_REMOVED_EXTENDED_DATA :: struct { + Flags: DRED_FLAGS, + pHeadAutoBreadcrumbNode: ^AUTO_BREADCRUMB_NODE, +} + +DRED_ALLOCATION_TYPE :: enum i32 { + COMMAND_QUEUE = 19, + COMMAND_ALLOCATOR = 20, + PIPELINE_STATE = 21, + COMMAND_LIST = 22, + FENCE = 23, + DESCRIPTOR_HEAP = 24, + HEAP = 25, + QUERY_HEAP = 27, + COMMAND_SIGNATURE = 28, + PIPELINE_LIBRARY = 29, + VIDEO_DECODER = 30, + VIDEO_PROCESSOR = 32, + RESOURCE = 34, + PASS = 35, + CRYPTOSESSION = 36, + CRYPTOSESSIONPOLICY = 37, + PROTECTEDRESOURCESESSION = 38, + VIDEO_DECODER_HEAP = 39, + COMMAND_POOL = 40, + COMMAND_RECORDER = 41, + STATE_OBJECT = 42, + METACOMMAND = 43, + SCHEDULINGGROUP = 44, + VIDEO_MOTION_ESTIMATOR = 45, + VIDEO_MOTION_VECTOR_HEAP = 46, + VIDEO_EXTENSION_COMMAND = 47, + INVALID = -1, +} + +DRED_ALLOCATION_NODE :: struct { + ObjectNameA: cstring, + ObjectNameW: ^i16, + AllocationType: DRED_ALLOCATION_TYPE, + pNext: ^DRED_ALLOCATION_NODE, +} + +DRED_ALLOCATION_NODE1 :: struct { + ObjectNameA: cstring, + ObjectNameW: ^i16, + AllocationType: DRED_ALLOCATION_TYPE, + pNext: ^DRED_ALLOCATION_NODE1, + pObject: ^IUnknown, +} + +DRED_AUTO_BREADCRUMBS_OUTPUT :: struct { + pHeadAutoBreadcrumbNode: ^AUTO_BREADCRUMB_NODE, +} + +DRED_AUTO_BREADCRUMBS_OUTPUT1 :: struct { + pHeadAutoBreadcrumbNode: ^AUTO_BREADCRUMB_NODE1, +} + +DRED_PAGE_FAULT_OUTPUT :: struct { + PageFaultVA: GPU_VIRTUAL_ADDRESS, + pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE, + pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE, +} + +DRED_PAGE_FAULT_OUTPUT1 :: struct { + PageFaultVA: GPU_VIRTUAL_ADDRESS, + pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE1, + pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE1, +} + +DEVICE_REMOVED_EXTENDED_DATA1 :: struct { + DeviceRemovedReason: HRESULT, + AutoBreadcrumbsOutput: DRED_AUTO_BREADCRUMBS_OUTPUT, + PageFaultOutput: DRED_PAGE_FAULT_OUTPUT, +} + +DEVICE_REMOVED_EXTENDED_DATA2 :: struct { + DeviceRemovedReason: HRESULT, + AutoBreadcrumbsOutput: DRED_AUTO_BREADCRUMBS_OUTPUT1, + PageFaultOutput: DRED_PAGE_FAULT_OUTPUT1, +} + +VERSIONED_DEVICE_REMOVED_EXTENDED_DATA :: struct { + Version: DRED_VERSION, + using _: struct #raw_union { + Dred_1_0: DEVICE_REMOVED_EXTENDED_DATA, + Dred_1_1: DEVICE_REMOVED_EXTENDED_DATA1, + Dred_1_2: DEVICE_REMOVED_EXTENDED_DATA2, + }, +} + + +IDeviceRemovedExtendedDataSettings_UUID :: "82BC481C-6B9B-4030-AEDB-7EE3D1DF1E63" +IDeviceRemovedExtendedDataSettings :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12deviceremovedextendeddatasettings_vtable: ^IDeviceRemovedExtendedDataSettings_VTable, +} +IDeviceRemovedExtendedDataSettings_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetAutoBreadcrumbsEnablement: proc "stdcall" (this: ^IDeviceRemovedExtendedDataSettings, Enablement: DRED_ENABLEMENT), + SetPageFaultEnablement: proc "stdcall" (this: ^IDeviceRemovedExtendedDataSettings, Enablement: DRED_ENABLEMENT), + SetWatsonDumpEnablement: proc "stdcall" (this: ^IDeviceRemovedExtendedDataSettings, Enablement: DRED_ENABLEMENT), +} + + +IDeviceRemovedExtendedDataSettings1_UUID :: "DBD5AE51-3317-4F0A-ADF9-1D7CEDCAAE0B" +IDeviceRemovedExtendedDataSettings1 :: struct #raw_union { + #subtype id3d12deviceremovedextendeddatasettings: IDeviceRemovedExtendedDataSettings, + using id3d12deviceremovedextendeddatasettings1_vtable: ^IDeviceRemovedExtendedDataSettings1_VTable, +} +IDeviceRemovedExtendedDataSettings1_VTable :: struct { + using id3d12deviceremovedextendeddatasettings_vtable: IDeviceRemovedExtendedDataSettings_VTable, + SetBreadcrumbContextEnablement: proc "stdcall" (this: ^IDeviceRemovedExtendedDataSettings1, Enablement: DRED_ENABLEMENT), +} + + +IDeviceRemovedExtendedData_UUID :: "98931D33-5AE8-4791-AA3C-1A73A2934E71" +IDeviceRemovedExtendedData :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12deviceremovedextendeddata_vtable: ^IDeviceRemovedExtendedData_VTable, +} +IDeviceRemovedExtendedData_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetAutoBreadcrumbsOutput: proc "stdcall" (this: ^IDeviceRemovedExtendedData, pOutput: ^DRED_AUTO_BREADCRUMBS_OUTPUT) -> HRESULT, + GetPageFaultAllocationOutput: proc "stdcall" (this: ^IDeviceRemovedExtendedData, pOutput: ^DRED_PAGE_FAULT_OUTPUT) -> HRESULT, +} + + +IDeviceRemovedExtendedData1_UUID :: "9727A022-CF1D-4DDA-9EBA-EFFA653FC506" +IDeviceRemovedExtendedData1 :: struct #raw_union { + #subtype id3d12deviceremovedextendeddata: IDeviceRemovedExtendedData, + using id3d12deviceremovedextendeddata1_vtable: ^IDeviceRemovedExtendedData1_VTable, +} +IDeviceRemovedExtendedData1_VTable :: struct { + using id3d12deviceremovedextendeddata_vtable: IDeviceRemovedExtendedData_VTable, + GetAutoBreadcrumbsOutput1: proc "stdcall" (this: ^IDeviceRemovedExtendedData1, pOutput: ^DRED_AUTO_BREADCRUMBS_OUTPUT1) -> HRESULT, + GetPageFaultAllocationOutput1: proc "stdcall" (this: ^IDeviceRemovedExtendedData1, pOutput: ^DRED_PAGE_FAULT_OUTPUT1) -> HRESULT, +} + +BACKGROUND_PROCESSING_MODE :: enum i32 { + ALLOWED = 0, + ALLOW_INTRUSIVE_MEASUREMENTS = 1, + DISABLE_BACKGROUND_WORK = 2, + DISABLE_PROFILING_BY_SYSTEM = 3, +} + +MEASUREMENTS_ACTION :: enum i32 { + KEEP_ALL = 0, + COMMIT_RESULTS = 1, + COMMIT_RESULTS_HIGH_PRIORITY = 2, + DISCARD_PREVIOUS = 3, +} + + +IDevice6_UUID :: "c70b221b-40e4-4a17-89af-025a0727a6dc" +IDevice6 :: struct #raw_union { + #subtype id3d12device5: IDevice5, + using id3d12device6_vtable: ^IDevice6_VTable, +} +IDevice6_VTable :: struct { + using id3d12device5_vtable: IDevice5_VTable, + SetBackgroundProcessingMode: proc "stdcall" (this: ^IDevice6, Mode: BACKGROUND_PROCESSING_MODE, MeasurementsAction: MEASUREMENTS_ACTION, hEventToSignalUponCompletion: HANDLE, pbFurtherMeasurementsDesired: ^BOOL) -> HRESULT, +} + +FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPE_COUNT :: struct { + NodeIndex: u32, + Count: u32, +} + +FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPES :: struct { + NodeIndex: u32, + Count: u32, + pTypes: ^GUID, +} + +PROTECTED_RESOURCE_SESSION_DESC1 :: struct { + NodeMask: u32, + Flags: PROTECTED_RESOURCE_SESSION_FLAGS, + ProtectionType: GUID, +} + + +IProtectedResourceSession1_UUID :: "D6F12DD6-76FB-406E-8961-4296EEFC0409" +IProtectedResourceSession1 :: struct #raw_union { + #subtype id3d12protectedresourcesession: IProtectedResourceSession, + using id3d12protectedresourcesession1_vtable: ^IProtectedResourceSession1_VTable, +} +IProtectedResourceSession1_VTable :: struct { + using id3d12protectedresourcesession_vtable: IProtectedResourceSession_VTable, + GetDesc1: proc "stdcall" (this: ^IProtectedResourceSession1) -> PROTECTED_RESOURCE_SESSION_DESC1, +} + + +IDevice7_UUID :: "5c014b53-68a1-4b9b-8bd1-dd6046b9358b" +IDevice7 :: struct #raw_union { + #subtype id3d12device6: IDevice6, + using id3d12device7_vtable: ^IDevice7_VTable, +} +IDevice7_VTable :: struct { + using id3d12device6_vtable: IDevice6_VTable, + AddToStateObject: proc "stdcall" (this: ^IDevice7, pAddition: ^STATE_OBJECT_DESC, pStateObjectToGrowFrom: ^IStateObject, riid: ^IID, ppNewStateObject: ^rawptr) -> HRESULT, + CreateProtectedResourceSession1: proc "stdcall" (this: ^IDevice7, pDesc: ^PROTECTED_RESOURCE_SESSION_DESC1, riid: ^IID, ppSession: ^rawptr) -> HRESULT, +} + + +IDevice8_UUID :: "9218E6BB-F944-4F7E-A75C-B1B2C7B701F3" +IDevice8 :: struct #raw_union { + #subtype id3d12device7: IDevice7, + using id3d12device8_vtable: ^IDevice8_VTable, +} +IDevice8_VTable :: struct { + using id3d12device7_vtable: IDevice7_VTable, + GetResourceAllocationInfo2: proc "stdcall" (this: ^IDevice8, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC1, pResourceAllocationInfo1: ^RESOURCE_ALLOCATION_INFO1) -> RESOURCE_ALLOCATION_INFO, + CreateCommittedResource2: proc "stdcall" (this: ^IDevice8, pHeapProperties: ^HEAP_PROPERTIES, HeapFlags: HEAP_FLAGS, pDesc: ^RESOURCE_DESC1, InitialResourceState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, pProtectedSession: ^IProtectedResourceSession, riidResource: ^IID, ppvResource: ^rawptr) -> HRESULT, + CreatePlacedResource1: proc "stdcall" (this: ^IDevice8, pHeap: ^IHeap, HeapOffset: u64, pDesc: ^RESOURCE_DESC1, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, + CreateSamplerFeedbackUnorderedAccessView: proc "stdcall" (this: ^IDevice8, pTargetedResource: ^IResource, pFeedbackResource: ^IResource, DestDescriptor: CPU_DESCRIPTOR_HANDLE), + GetCopyableFootprints1: proc "stdcall" (this: ^IDevice8, pResourceDesc: ^RESOURCE_DESC1, FirstSubresource: u32, NumSubresources: u32, BaseOffset: u64, pLayouts: ^PLACED_SUBRESOURCE_FOOTPRINT, pNumRows: ^u32, pRowSizeInBytes: ^u64, pTotalBytes: ^u64), +} + + +IResource1_UUID :: "9D5E227A-4430-4161-88B3-3ECA6BB16E19" +IResource1 :: struct #raw_union { + #subtype id3d12resource: IResource, + using id3d12resource1_vtable: ^IResource1_VTable, +} +IResource1_VTable :: struct { + using id3d12resource_vtable: IResource_VTable, + GetProtectedResourceSession: proc "stdcall" (this: ^IResource1, riid: ^IID, ppProtectedSession: ^rawptr) -> HRESULT, +} + + +IResource2_UUID :: "BE36EC3B-EA85-4AEB-A45A-E9D76404A495" +IResource2 :: struct #raw_union { + #subtype id3d12resource1: IResource1, + using id3d12resource2_vtable: ^IResource2_VTable, +} +IResource2_VTable :: struct { + using id3d12resource1_vtable: IResource1_VTable, + GetDesc1: proc "stdcall" (this: ^IResource2) -> RESOURCE_DESC1, +} + + +IHeap1_UUID :: "572F7389-2168-49E3-9693-D6DF5871BF6D" +IHeap1 :: struct #raw_union { + #subtype id3d12heap: IHeap, + using id3d12heap1_vtable: ^IHeap1_VTable, +} +IHeap1_VTable :: struct { + using id3d12heap_vtable: IHeap_VTable, + GetProtectedResourceSession: proc "stdcall" (this: ^IHeap1, riid: ^IID, ppProtectedSession: ^rawptr) -> HRESULT, +} + + +IGraphicsCommandList3_UUID :: "6FDA83A7-B84C-4E38-9AC8-C7BD22016B3D" +IGraphicsCommandList3 :: struct #raw_union { + #subtype id3d12graphicscommandlist2: IGraphicsCommandList2, + using id3d12graphicscommandlist3_vtable: ^IGraphicsCommandList3_VTable, +} +IGraphicsCommandList3_VTable :: struct { + using id3d12graphicscommandlist2_vtable: IGraphicsCommandList2_VTable, + SetProtectedResourceSession: proc "stdcall" (this: ^IGraphicsCommandList3, pProtectedResourceSession: ^IProtectedResourceSession), +} + +RENDER_PASS_BEGINNING_ACCESS_TYPE :: enum i32 { + DISCARD = 0, + PRESERVE = 1, + CLEAR = 2, + NO_ACCESS = 3, +} + +RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS :: struct { + ClearValue: CLEAR_VALUE, +} + +RENDER_PASS_BEGINNING_ACCESS :: struct { + Type: RENDER_PASS_BEGINNING_ACCESS_TYPE, + using _: struct #raw_union { + Clear: RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS, + }, +} + +RENDER_PASS_ENDING_ACCESS_TYPE :: enum i32 { + DISCARD = 0, + PRESERVE = 1, + RESOLVE = 2, + NO_ACCESS = 3, +} + +RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS :: struct { + SrcSubresource: u32, + DstSubresource: u32, + DstX: u32, + DstY: u32, + SrcRect: RECT, +} + +RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS :: struct { + pSrcResource: ^IResource, + pDstResource: ^IResource, + SubresourceCount: u32, + pSubresourceParameters: ^RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS, + Format: dxgi.FORMAT, + ResolveMode: RESOLVE_MODE, + PreserveResolveSource: BOOL, +} + +RENDER_PASS_ENDING_ACCESS :: struct { + Type: RENDER_PASS_ENDING_ACCESS_TYPE, + using _: struct #raw_union { + Resolve: RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS, + }, +} + +RENDER_PASS_RENDER_TARGET_DESC :: struct { + cpuDescriptor: CPU_DESCRIPTOR_HANDLE, + BeginningAccess: RENDER_PASS_BEGINNING_ACCESS, + EndingAccess: RENDER_PASS_ENDING_ACCESS, +} + +RENDER_PASS_DEPTH_STENCIL_DESC :: struct { + cpuDescriptor: CPU_DESCRIPTOR_HANDLE, + DepthBeginningAccess: RENDER_PASS_BEGINNING_ACCESS, + StencilBeginningAccess: RENDER_PASS_BEGINNING_ACCESS, + DepthEndingAccess: RENDER_PASS_ENDING_ACCESS, + StencilEndingAccess: RENDER_PASS_ENDING_ACCESS, +} + +RENDER_PASS_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + ALLOW_UAV_WRITES = 0x1, + SUSPENDING_PASS = 0x2, + RESUMING_PASS = 0x4, +} + + +IMetaCommand_UUID :: "DBB84C27-36CE-4FC9-B801-F048C46AC570" +IMetaCommand :: struct #raw_union { + #subtype id3d12pageable: IPageable, + using id3d12metacommand_vtable: ^IMetaCommand_VTable, +} +IMetaCommand_VTable :: struct { + using id3d12devicechild_vtable: IDeviceChild_VTable, + GetRequiredParameterResourceSize: proc "stdcall" (this: ^IMetaCommand, Stage: META_COMMAND_PARAMETER_STAGE, ParameterIndex: u32) -> u64, +} + +DISPATCH_RAYS_DESC :: struct { + RayGenerationShaderRecord: GPU_VIRTUAL_ADDRESS_RANGE, + MissShaderTable: GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE, + HitGroupTable: GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE, + CallableShaderTable: GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE, + Width: u32, + Height: u32, + Depth: u32, +} + + +IGraphicsCommandList4_UUID :: "8754318e-d3a9-4541-98cf-645b50dc4874" +IGraphicsCommandList4 :: struct #raw_union { + #subtype id3d12graphicscommandlist3: IGraphicsCommandList3, + using id3d12graphicscommandlist4_vtable: ^IGraphicsCommandList4_VTable, +} +IGraphicsCommandList4_VTable :: struct { + using id3d12graphicscommandlist3_vtable: IGraphicsCommandList3_VTable, + BeginRenderPass: proc "stdcall" (this: ^IGraphicsCommandList4, NumRenderTargets: u32, pRenderTargets: ^RENDER_PASS_RENDER_TARGET_DESC, pDepthStencil: ^RENDER_PASS_DEPTH_STENCIL_DESC, Flags: RENDER_PASS_FLAGS), + EndRenderPass: proc "stdcall" (this: ^IGraphicsCommandList4), + InitializeMetaCommand: proc "stdcall" (this: ^IGraphicsCommandList4, pMetaCommand: ^IMetaCommand, pInitializationParametersData: rawptr, InitializationParametersDataSizeInBytes: SIZE_T), + ExecuteMetaCommand: proc "stdcall" (this: ^IGraphicsCommandList4, pMetaCommand: ^IMetaCommand, pExecutionParametersData: rawptr, ExecutionParametersDataSizeInBytes: SIZE_T), + BuildRaytracingAccelerationStructure: proc "stdcall" (this: ^IGraphicsCommandList4, pDesc: ^BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC, NumPostbuildInfoDescs: u32, pPostbuildInfoDescs: ^RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC), + EmitRaytracingAccelerationStructurePostbuildInfo: proc "stdcall" (this: ^IGraphicsCommandList4, pDesc: ^RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC, NumSourceAccelerationStructures: u32, pSourceAccelerationStructureData: ^GPU_VIRTUAL_ADDRESS), + CopyRaytracingAccelerationStructure: proc "stdcall" (this: ^IGraphicsCommandList4, DestAccelerationStructureData: GPU_VIRTUAL_ADDRESS, SourceAccelerationStructureData: GPU_VIRTUAL_ADDRESS, Mode: RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE), + SetPipelineState1: proc "stdcall" (this: ^IGraphicsCommandList4, pStateObject: ^IStateObject), + DispatchRays: proc "stdcall" (this: ^IGraphicsCommandList4, pDesc: ^DISPATCH_RAYS_DESC), +} + + +ITools_UUID :: "7071e1f0-e84b-4b33-974f-12fa49de65c5" +ITools :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12tools_vtable: ^ITools_VTable, +} +ITools_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + EnableShaderInstrumentation: proc "stdcall" (this: ^ITools, bEnable: BOOL), + ShaderInstrumentationEnabled: proc "stdcall" (this: ^ITools) -> BOOL, +} + +SUBRESOURCE_DATA :: struct { + pData: rawptr, + RowPitch: i64, + SlicePitch: i64, +} + +MEMCPY_DEST :: struct { + pData: rawptr, + RowPitch: SIZE_T, + SlicePitch: SIZE_T, +} + + +IDebug_UUID :: "344488b7-6846-474b-b989-f027448245e0" +IDebug :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debug_vtable: ^IDebug_VTable, +} +IDebug_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + EnableDebugLayer: proc "stdcall" (this: ^IDebug), +} + +GPU_BASED_VALIDATION_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + DISABLE_STATE_TRACKING = 0x1, +} + + +IDebug1_UUID :: "affaa4ca-63fe-4d8e-b8ad-159000af4304" +IDebug1 :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debug1_vtable: ^IDebug1_VTable, +} +IDebug1_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + EnableDebugLayer: proc "stdcall" (this: ^IDebug1), + SetEnableGPUBasedValidation: proc "stdcall" (this: ^IDebug1, Enable: BOOL), + SetEnableSynchronizedCommandQueueValidation: proc "stdcall" (this: ^IDebug1, Enable: BOOL), +} + + +IDebug2_UUID :: "93a665c4-a3b2-4e5d-b692-a26ae14e3374" +IDebug2 :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debug2_vtable: ^IDebug2_VTable, +} +IDebug2_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetGPUBasedValidationFlags: proc "stdcall" (this: ^IDebug2, Flags: GPU_BASED_VALIDATION_FLAGS), +} + + +IDebug3_UUID :: "5cf4e58f-f671-4ff1-a542-3686e3d153d1" +IDebug3 :: struct #raw_union { + #subtype id3d12debug: IDebug, + using id3d12debug3_vtable: ^IDebug3_VTable, +} +IDebug3_VTable :: struct { + using id3d12debug_vtable: IDebug_VTable, + SetEnableGPUBasedValidation: proc "stdcall" (this: ^IDebug3, Enable: BOOL), + SetEnableSynchronizedCommandQueueValidation: proc "stdcall" (this: ^IDebug3, Enable: BOOL), + SetGPUBasedValidationFlags: proc "stdcall" (this: ^IDebug3, Flags: GPU_BASED_VALIDATION_FLAGS), +} + +RLDO_FLAGS :: enum u32 { // TODO: make bit_set + NONE = 0x0, + SUMMARY = 0x1, + DETAIL = 0x2, + IGNORE_INTERNAL = 0x4, +} + +DEBUG_DEVICE_PARAMETER_TYPE :: enum i32 { + FEATURE_FLAGS = 0, + GPU_BASED_VALIDATION_SETTINGS = 1, + GPU_SLOWDOWN_PERFORMANCE_FACTOR = 2, +} + +DEBUG_FEATURE :: enum i32 { // TODO: make bit_set + NONE = 0, + ALLOW_BEHAVIOR_CHANGING_DEBUG_AIDS = 1, + CONSERVATIVE_RESOURCE_STATE_TRACKING = 2, + DISABLE_VIRTUALIZED_BUNDLES_VALIDATION = 4, + EMULATE_WINDOWS7 = 8, +} + +GPU_BASED_VALIDATION_SHADER_PATCH_MODE :: enum i32 { + NONE = 0, + STATE_TRACKING_ONLY = 1, + UNGUARDED_VALIDATION = 2, + GUARDED_VALIDATION = 3, + NUM_GPU_BASED_VALIDATION_SHADER_PATCH_MODES = 4, +} + +GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAGS :: enum u32 { // TODO: make bit_set + GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_NONE = 0x0, + GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_FRONT_LOAD_CREATE_TRACKING_ONLY_SHADERS = 0x1, + GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_FRONT_LOAD_CREATE_UNGUARDED_VALIDATION_SHADERS = 0x2, + GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_FRONT_LOAD_CREATE_GUARDED_VALIDATION_SHADERS = 0x4, + VALID_MASK = 0x7, +} + +DEBUG_DEVICE_GPU_BASED_VALIDATION_SETTINGS :: struct { + MaxMessagesPerCommandList: u32, + DefaultShaderPatchMode: GPU_BASED_VALIDATION_SHADER_PATCH_MODE, + PipelineStateCreateFlags: GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAGS, +} + +DEBUG_DEVICE_GPU_SLOWDOWN_PERFORMANCE_FACTOR :: struct { + SlowdownFactor: f32, +} + + +IDebugDevice1_UUID :: "a9b71770-d099-4a65-a698-3dee10020f88" +IDebugDevice1 :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debugdevice1_vtable: ^IDebugDevice1_VTable, +} +IDebugDevice1_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetDebugParameter: proc "stdcall" (this: ^IDebugDevice1, Type: DEBUG_DEVICE_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, + GetDebugParameter: proc "stdcall" (this: ^IDebugDevice1, Type: DEBUG_DEVICE_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, + ReportLiveDeviceObjects: proc "stdcall" (this: ^IDebugDevice1, Flags: RLDO_FLAGS) -> HRESULT, +} + + +IDebugDevice_UUID :: "3febd6dd-4973-4787-8194-e45f9e28923e" +IDebugDevice :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debugdevice_vtable: ^IDebugDevice_VTable, +} +IDebugDevice_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetFeatureMask: proc "stdcall" (this: ^IDebugDevice, Mask: DEBUG_FEATURE) -> HRESULT, + GetFeatureMask: proc "stdcall" (this: ^IDebugDevice) -> DEBUG_FEATURE, + ReportLiveDeviceObjects: proc "stdcall" (this: ^IDebugDevice, Flags: RLDO_FLAGS) -> HRESULT, +} + + +IDebugDevice2_UUID :: "60eccbc1-378d-4df1-894c-f8ac5ce4d7dd" +IDebugDevice2 :: struct #raw_union { + #subtype id3d12debugdevice: IDebugDevice, + using id3d12debugdevice2_vtable: ^IDebugDevice2_VTable, +} +IDebugDevice2_VTable :: struct { + using id3d12debugdevice_vtable: IDebugDevice_VTable, + SetDebugParameter: proc "stdcall" (this: ^IDebugDevice2, Type: DEBUG_DEVICE_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, + GetDebugParameter: proc "stdcall" (this: ^IDebugDevice2, Type: DEBUG_DEVICE_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, +} + + + +IDebugCommandQueue_UUID :: "09e0bf36-54ac-484f-8847-4baeeab6053a" +IDebugCommandQueue :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debugcommandqueue_vtable: ^IDebugCommandQueue_VTable, +} +IDebugCommandQueue_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + AssertResourceState: proc "stdcall" (this: ^IDebugCommandQueue, pResource: ^IResource, Subresource: u32, State: u32) -> BOOL, +} + +DEBUG_COMMAND_LIST_PARAMETER_TYPE :: enum i32 { + DEBUG_COMMAND_LIST_PARAMETER_GPU_BASED_VALIDATION_SETTINGS = 0, +} + +DEBUG_COMMAND_LIST_GPU_BASED_VALIDATION_SETTINGS :: struct { + ShaderPatchMode: GPU_BASED_VALIDATION_SHADER_PATCH_MODE, +} + + +IDebugCommandList1_UUID :: "102ca951-311b-4b01-b11f-ecb83e061b37" +IDebugCommandList1 :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debugcommandlist1_vtable: ^IDebugCommandList1_VTable, +} +IDebugCommandList1_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + AssertResourceState: proc "stdcall" (this: ^IDebugCommandList1, pResource: ^IResource, Subresource: u32, State: u32) -> BOOL, + SetDebugParameter: proc "stdcall" (this: ^IDebugCommandList1, Type: DEBUG_COMMAND_LIST_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, + GetDebugParameter: proc "stdcall" (this: ^IDebugCommandList1, Type: DEBUG_COMMAND_LIST_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, +} + + +IDebugCommandList_UUID :: "09e0bf36-54ac-484f-8847-4baeeab6053f" +IDebugCommandList :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12debugcommandlist_vtable: ^IDebugCommandList_VTable, +} +IDebugCommandList_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + AssertResourceState: proc "stdcall" (this: ^IDebugCommandList, pResource: ^IResource, Subresource: u32, State: u32) -> BOOL, + SetFeatureMask: proc "stdcall" (this: ^IDebugCommandList, Mask: DEBUG_FEATURE) -> HRESULT, + GetFeatureMask: proc "stdcall" (this: ^IDebugCommandList) -> DEBUG_FEATURE, +} + + +IDebugCommandList2_UUID :: "aeb575cf-4e06-48be-ba3b-c450fc96652e" +IDebugCommandList2 :: struct #raw_union { + #subtype id3d12debugcommandlist: IDebugCommandList, + using id3d12debugcommandlist2_vtable: ^IDebugCommandList2_VTable, +} +IDebugCommandList2_VTable :: struct { + using id3d12debugcommandlist_vtable: IDebugCommandList_VTable, + SetDebugParameter: proc "stdcall" (this: ^IDebugCommandList2, Type: DEBUG_COMMAND_LIST_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, + GetDebugParameter: proc "stdcall" (this: ^IDebugCommandList2, Type: DEBUG_COMMAND_LIST_PARAMETER_TYPE, pData: rawptr, DataSize: u32) -> HRESULT, +} + + +ISharingContract_UUID :: "0adf7d52-929c-4e61-addb-ffed30de66ef" +ISharingContract :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12sharingcontract_vtable: ^ISharingContract_VTable, +} +ISharingContract_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Present: proc "stdcall" (this: ^ISharingContract, pResource: ^IResource, Subresource: u32, window: HWND), + SharedFenceSignal: proc "stdcall" (this: ^ISharingContract, pFence: ^IFence, FenceValue: u64), + BeginCapturableWork: proc "stdcall" (this: ^ISharingContract, guid: ^GUID), + EndCapturableWork: proc "stdcall" (this: ^ISharingContract, guid: ^GUID), +} + +MESSAGE_CATEGORY :: enum i32 { + APPLICATION_DEFINED = 0, + MISCELLANEOUS = 1, + INITIALIZATION = 2, + CLEANUP = 3, + COMPILATION = 4, + STATE_CREATION = 5, + STATE_SETTING = 6, + STATE_GETTING = 7, + RESOURCE_MANIPULATION = 8, + EXECUTION = 9, + SHADER = 10, +} + +MESSAGE_SEVERITY :: enum i32 { + CORRUPTION = 0, + ERROR = 1, + WARNING = 2, + INFO = 3, + MESSAGE = 4, +} + +MESSAGE_ID :: enum i32 { + UNKNOWN = 0, + STRING_FROM_APPLICATION = 1, + CORRUPTED_THIS = 2, + CORRUPTED_PARAMETER1 = 3, + CORRUPTED_PARAMETER2 = 4, + CORRUPTED_PARAMETER3 = 5, + CORRUPTED_PARAMETER4 = 6, + CORRUPTED_PARAMETER5 = 7, + CORRUPTED_PARAMETER6 = 8, + CORRUPTED_PARAMETER7 = 9, + CORRUPTED_PARAMETER8 = 10, + CORRUPTED_PARAMETER9 = 11, + CORRUPTED_PARAMETER10 = 12, + CORRUPTED_PARAMETER11 = 13, + CORRUPTED_PARAMETER12 = 14, + CORRUPTED_PARAMETER13 = 15, + CORRUPTED_PARAMETER14 = 16, + CORRUPTED_PARAMETER15 = 17, + CORRUPTED_MULTITHREADING = 18, + MESSAGE_REPORTING_OUTOFMEMORY = 19, + GETPRIVATEDATA_MOREDATA = 20, + SETPRIVATEDATA_INVALIDFREEDATA = 21, + SETPRIVATEDATA_CHANGINGPARAMS = 24, + SETPRIVATEDATA_OUTOFMEMORY = 25, + CREATESHADERRESOURCEVIEW_UNRECOGNIZEDFORMAT = 26, + CREATESHADERRESOURCEVIEW_INVALIDDESC = 27, + CREATESHADERRESOURCEVIEW_INVALIDFORMAT = 28, + CREATESHADERRESOURCEVIEW_INVALIDVIDEOPLANESLICE = 29, + CREATESHADERRESOURCEVIEW_INVALIDPLANESLICE = 30, + CREATESHADERRESOURCEVIEW_INVALIDDIMENSIONS = 31, + CREATESHADERRESOURCEVIEW_INVALIDRESOURCE = 32, + CREATERENDERTARGETVIEW_UNRECOGNIZEDFORMAT = 35, + CREATERENDERTARGETVIEW_UNSUPPORTEDFORMAT = 36, + CREATERENDERTARGETVIEW_INVALIDDESC = 37, + CREATERENDERTARGETVIEW_INVALIDFORMAT = 38, + CREATERENDERTARGETVIEW_INVALIDVIDEOPLANESLICE = 39, + CREATERENDERTARGETVIEW_INVALIDPLANESLICE = 40, + CREATERENDERTARGETVIEW_INVALIDDIMENSIONS = 41, + CREATERENDERTARGETVIEW_INVALIDRESOURCE = 42, + CREATEDEPTHSTENCILVIEW_UNRECOGNIZEDFORMAT = 45, + CREATEDEPTHSTENCILVIEW_INVALIDDESC = 46, + CREATEDEPTHSTENCILVIEW_INVALIDFORMAT = 47, + CREATEDEPTHSTENCILVIEW_INVALIDDIMENSIONS = 48, + CREATEDEPTHSTENCILVIEW_INVALIDRESOURCE = 49, + CREATEINPUTLAYOUT_OUTOFMEMORY = 52, + CREATEINPUTLAYOUT_TOOMANYELEMENTS = 53, + CREATEINPUTLAYOUT_INVALIDFORMAT = 54, + CREATEINPUTLAYOUT_INCOMPATIBLEFORMAT = 55, + CREATEINPUTLAYOUT_INVALIDSLOT = 56, + CREATEINPUTLAYOUT_INVALIDINPUTSLOTCLASS = 57, + CREATEINPUTLAYOUT_STEPRATESLOTCLASSMISMATCH = 58, + CREATEINPUTLAYOUT_INVALIDSLOTCLASSCHANGE = 59, + CREATEINPUTLAYOUT_INVALIDSTEPRATECHANGE = 60, + CREATEINPUTLAYOUT_INVALIDALIGNMENT = 61, + CREATEINPUTLAYOUT_DUPLICATESEMANTIC = 62, + CREATEINPUTLAYOUT_UNPARSEABLEINPUTSIGNATURE = 63, + CREATEINPUTLAYOUT_NULLSEMANTIC = 64, + CREATEINPUTLAYOUT_MISSINGELEMENT = 65, + CREATEVERTEXSHADER_OUTOFMEMORY = 66, + CREATEVERTEXSHADER_INVALIDSHADERBYTECODE = 67, + CREATEVERTEXSHADER_INVALIDSHADERTYPE = 68, + CREATEGEOMETRYSHADER_OUTOFMEMORY = 69, + CREATEGEOMETRYSHADER_INVALIDSHADERBYTECODE = 70, + CREATEGEOMETRYSHADER_INVALIDSHADERTYPE = 71, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTOFMEMORY = 72, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERBYTECODE = 73, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERTYPE = 74, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMENTRIES = 75, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSTREAMSTRIDEUNUSED = 76, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSLOT0EXPECTED = 79, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSLOT = 80, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_ONLYONEELEMENTPERSLOT = 81, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDCOMPONENTCOUNT = 82, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTARTCOMPONENTANDCOMPONENTCOUNT = 83, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDGAPDEFINITION = 84, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_REPEATEDOUTPUT = 85, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSTREAMSTRIDE = 86, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGSEMANTIC = 87, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MASKMISMATCH = 88, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_CANTHAVEONLYGAPS = 89, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DECLTOOCOMPLEX = 90, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGOUTPUTSIGNATURE = 91, + CREATEPIXELSHADER_OUTOFMEMORY = 92, + CREATEPIXELSHADER_INVALIDSHADERBYTECODE = 93, + CREATEPIXELSHADER_INVALIDSHADERTYPE = 94, + CREATERASTERIZERSTATE_INVALIDFILLMODE = 95, + CREATERASTERIZERSTATE_INVALIDCULLMODE = 96, + CREATERASTERIZERSTATE_INVALIDDEPTHBIASCLAMP = 97, + CREATERASTERIZERSTATE_INVALIDSLOPESCALEDDEPTHBIAS = 98, + CREATEDEPTHSTENCILSTATE_INVALIDDEPTHWRITEMASK = 100, + CREATEDEPTHSTENCILSTATE_INVALIDDEPTHFUNC = 101, + CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFAILOP = 102, + CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILZFAILOP = 103, + CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILPASSOP = 104, + CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFUNC = 105, + CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFAILOP = 106, + CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILZFAILOP = 107, + CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILPASSOP = 108, + CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFUNC = 109, + CREATEBLENDSTATE_INVALIDSRCBLEND = 111, + CREATEBLENDSTATE_INVALIDDESTBLEND = 112, + CREATEBLENDSTATE_INVALIDBLENDOP = 113, + CREATEBLENDSTATE_INVALIDSRCBLENDALPHA = 114, + CREATEBLENDSTATE_INVALIDDESTBLENDALPHA = 115, + CREATEBLENDSTATE_INVALIDBLENDOPALPHA = 116, + CREATEBLENDSTATE_INVALIDRENDERTARGETWRITEMASK = 117, + CLEARDEPTHSTENCILVIEW_INVALID = 135, + COMMAND_LIST_DRAW_ROOT_SIGNATURE_NOT_SET = 200, + COMMAND_LIST_DRAW_ROOT_SIGNATURE_MISMATCH = 201, + COMMAND_LIST_DRAW_VERTEX_BUFFER_NOT_SET = 202, + COMMAND_LIST_DRAW_VERTEX_BUFFER_STRIDE_TOO_SMALL = 209, + COMMAND_LIST_DRAW_VERTEX_BUFFER_TOO_SMALL = 210, + COMMAND_LIST_DRAW_INDEX_BUFFER_NOT_SET = 211, + COMMAND_LIST_DRAW_INDEX_BUFFER_FORMAT_INVALID = 212, + COMMAND_LIST_DRAW_INDEX_BUFFER_TOO_SMALL = 213, + COMMAND_LIST_DRAW_INVALID_PRIMITIVETOPOLOGY = 219, + COMMAND_LIST_DRAW_VERTEX_STRIDE_UNALIGNED = 221, + COMMAND_LIST_DRAW_INDEX_OFFSET_UNALIGNED = 222, + DEVICE_REMOVAL_PROCESS_AT_FAULT = 232, + DEVICE_REMOVAL_PROCESS_POSSIBLY_AT_FAULT = 233, + DEVICE_REMOVAL_PROCESS_NOT_AT_FAULT = 234, + CREATEINPUTLAYOUT_TRAILING_DIGIT_IN_SEMANTIC = 239, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_TRAILING_DIGIT_IN_SEMANTIC = 240, + CREATEINPUTLAYOUT_TYPE_MISMATCH = 245, + CREATEINPUTLAYOUT_EMPTY_LAYOUT = 253, + LIVE_OBJECT_SUMMARY = 255, + LIVE_DEVICE = 274, + LIVE_SWAPCHAIN = 275, + CREATEDEPTHSTENCILVIEW_INVALIDFLAGS = 276, + CREATEVERTEXSHADER_INVALIDCLASSLINKAGE = 277, + CREATEGEOMETRYSHADER_INVALIDCLASSLINKAGE = 278, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAMTORASTERIZER = 280, + CREATEPIXELSHADER_INVALIDCLASSLINKAGE = 283, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAM = 284, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDENTRIES = 285, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDSTRIDES = 286, + CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMSTRIDES = 287, + CREATEHULLSHADER_OUTOFMEMORY = 289, + CREATEHULLSHADER_INVALIDSHADERBYTECODE = 290, + CREATEHULLSHADER_INVALIDSHADERTYPE = 291, + CREATEHULLSHADER_INVALIDCLASSLINKAGE = 292, + CREATEDOMAINSHADER_OUTOFMEMORY = 294, + CREATEDOMAINSHADER_INVALIDSHADERBYTECODE = 295, + CREATEDOMAINSHADER_INVALIDSHADERTYPE = 296, + CREATEDOMAINSHADER_INVALIDCLASSLINKAGE = 297, + RESOURCE_UNMAP_NOTMAPPED = 310, + DEVICE_CHECKFEATURESUPPORT_MISMATCHED_DATA_SIZE = 318, + CREATECOMPUTESHADER_OUTOFMEMORY = 321, + CREATECOMPUTESHADER_INVALIDSHADERBYTECODE = 322, + CREATECOMPUTESHADER_INVALIDCLASSLINKAGE = 323, + DEVICE_CREATEVERTEXSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 331, + DEVICE_CREATEHULLSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 332, + DEVICE_CREATEDOMAINSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 333, + DEVICE_CREATEGEOMETRYSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 334, + DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEFLOATOPSNOTSUPPORTED = 335, + DEVICE_CREATEPIXELSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 336, + DEVICE_CREATECOMPUTESHADER_DOUBLEFLOATOPSNOTSUPPORTED = 337, + CREATEUNORDEREDACCESSVIEW_INVALIDRESOURCE = 340, + CREATEUNORDEREDACCESSVIEW_INVALIDDESC = 341, + CREATEUNORDEREDACCESSVIEW_INVALIDFORMAT = 342, + CREATEUNORDEREDACCESSVIEW_INVALIDVIDEOPLANESLICE = 343, + CREATEUNORDEREDACCESSVIEW_INVALIDPLANESLICE = 344, + CREATEUNORDEREDACCESSVIEW_INVALIDDIMENSIONS = 345, + CREATEUNORDEREDACCESSVIEW_UNRECOGNIZEDFORMAT = 346, + CREATEUNORDEREDACCESSVIEW_INVALIDFLAGS = 354, + CREATERASTERIZERSTATE_INVALIDFORCEDSAMPLECOUNT = 401, + CREATEBLENDSTATE_INVALIDLOGICOPS = 403, + DEVICE_CREATEVERTEXSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 410, + DEVICE_CREATEHULLSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 412, + DEVICE_CREATEDOMAINSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 414, + DEVICE_CREATEGEOMETRYSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 416, + DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEEXTENSIONSNOTSUPPORTED = 418, + DEVICE_CREATEPIXELSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 420, + DEVICE_CREATECOMPUTESHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 422, + DEVICE_CREATEVERTEXSHADER_UAVSNOTSUPPORTED = 425, + DEVICE_CREATEHULLSHADER_UAVSNOTSUPPORTED = 426, + DEVICE_CREATEDOMAINSHADER_UAVSNOTSUPPORTED = 427, + DEVICE_CREATEGEOMETRYSHADER_UAVSNOTSUPPORTED = 428, + DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UAVSNOTSUPPORTED = 429, + DEVICE_CREATEPIXELSHADER_UAVSNOTSUPPORTED = 430, + DEVICE_CREATECOMPUTESHADER_UAVSNOTSUPPORTED = 431, + DEVICE_CLEARVIEW_INVALIDSOURCERECT = 447, + DEVICE_CLEARVIEW_EMPTYRECT = 448, + UPDATETILEMAPPINGS_INVALID_PARAMETER = 493, + COPYTILEMAPPINGS_INVALID_PARAMETER = 494, + CREATEDEVICE_INVALIDARGS = 506, + CREATEDEVICE_WARNING = 507, + RESOURCE_BARRIER_INVALID_TYPE = 519, + RESOURCE_BARRIER_NULL_POINTER = 520, + RESOURCE_BARRIER_INVALID_SUBRESOURCE = 521, + RESOURCE_BARRIER_RESERVED_BITS = 522, + RESOURCE_BARRIER_MISSING_BIND_FLAGS = 523, + RESOURCE_BARRIER_MISMATCHING_MISC_FLAGS = 524, + RESOURCE_BARRIER_MATCHING_STATES = 525, + RESOURCE_BARRIER_INVALID_COMBINATION = 526, + RESOURCE_BARRIER_BEFORE_AFTER_MISMATCH = 527, + RESOURCE_BARRIER_INVALID_RESOURCE = 528, + RESOURCE_BARRIER_SAMPLE_COUNT = 529, + RESOURCE_BARRIER_INVALID_FLAGS = 530, + RESOURCE_BARRIER_INVALID_COMBINED_FLAGS = 531, + RESOURCE_BARRIER_INVALID_FLAGS_FOR_FORMAT = 532, + RESOURCE_BARRIER_INVALID_SPLIT_BARRIER = 533, + RESOURCE_BARRIER_UNMATCHED_END = 534, + RESOURCE_BARRIER_UNMATCHED_BEGIN = 535, + RESOURCE_BARRIER_INVALID_FLAG = 536, + RESOURCE_BARRIER_INVALID_COMMAND_LIST_TYPE = 537, + INVALID_SUBRESOURCE_STATE = 538, + COMMAND_ALLOCATOR_CONTENTION = 540, + COMMAND_ALLOCATOR_RESET = 541, + COMMAND_ALLOCATOR_RESET_BUNDLE = 542, + COMMAND_ALLOCATOR_CANNOT_RESET = 543, + COMMAND_LIST_OPEN = 544, + INVALID_BUNDLE_API = 546, + COMMAND_LIST_CLOSED = 547, + WRONG_COMMAND_ALLOCATOR_TYPE = 549, + COMMAND_ALLOCATOR_SYNC = 552, + COMMAND_LIST_SYNC = 553, + SET_DESCRIPTOR_HEAP_INVALID = 554, + CREATE_COMMANDQUEUE = 557, + CREATE_COMMANDALLOCATOR = 558, + CREATE_PIPELINESTATE = 559, + CREATE_COMMANDLIST12 = 560, + CREATE_RESOURCE = 562, + CREATE_DESCRIPTORHEAP = 563, + CREATE_ROOTSIGNATURE = 564, + CREATE_LIBRARY = 565, + CREATE_HEAP = 566, + CREATE_MONITOREDFENCE = 567, + CREATE_QUERYHEAP = 568, + CREATE_COMMANDSIGNATURE = 569, + LIVE_COMMANDQUEUE = 570, + LIVE_COMMANDALLOCATOR = 571, + LIVE_PIPELINESTATE = 572, + LIVE_COMMANDLIST12 = 573, + LIVE_RESOURCE = 575, + LIVE_DESCRIPTORHEAP = 576, + LIVE_ROOTSIGNATURE = 577, + LIVE_LIBRARY = 578, + LIVE_HEAP = 579, + LIVE_MONITOREDFENCE = 580, + LIVE_QUERYHEAP = 581, + LIVE_COMMANDSIGNATURE = 582, + DESTROY_COMMANDQUEUE = 583, + DESTROY_COMMANDALLOCATOR = 584, + DESTROY_PIPELINESTATE = 585, + DESTROY_COMMANDLIST12 = 586, + DESTROY_RESOURCE = 588, + DESTROY_DESCRIPTORHEAP = 589, + DESTROY_ROOTSIGNATURE = 590, + DESTROY_LIBRARY = 591, + DESTROY_HEAP = 592, + DESTROY_MONITOREDFENCE = 593, + DESTROY_QUERYHEAP = 594, + DESTROY_COMMANDSIGNATURE = 595, + CREATERESOURCE_INVALIDDIMENSIONS = 597, + CREATERESOURCE_INVALIDMISCFLAGS = 599, + CREATERESOURCE_INVALIDARG_RETURN = 602, + CREATERESOURCE_OUTOFMEMORY_RETURN = 603, + CREATERESOURCE_INVALIDDESC = 604, + POSSIBLY_INVALID_SUBRESOURCE_STATE = 607, + INVALID_USE_OF_NON_RESIDENT_RESOURCE = 608, + POSSIBLE_INVALID_USE_OF_NON_RESIDENT_RESOURCE = 609, + BUNDLE_PIPELINE_STATE_MISMATCH = 610, + PRIMITIVE_TOPOLOGY_MISMATCH_PIPELINE_STATE = 611, + RENDER_TARGET_FORMAT_MISMATCH_PIPELINE_STATE = 613, + RENDER_TARGET_SAMPLE_DESC_MISMATCH_PIPELINE_STATE = 614, + DEPTH_STENCIL_FORMAT_MISMATCH_PIPELINE_STATE = 615, + DEPTH_STENCIL_SAMPLE_DESC_MISMATCH_PIPELINE_STATE = 616, + CREATESHADER_INVALIDBYTECODE = 622, + CREATEHEAP_NULLDESC = 623, + CREATEHEAP_INVALIDSIZE = 624, + CREATEHEAP_UNRECOGNIZEDHEAPTYPE = 625, + CREATEHEAP_UNRECOGNIZEDCPUPAGEPROPERTIES = 626, + CREATEHEAP_UNRECOGNIZEDMEMORYPOOL = 627, + CREATEHEAP_INVALIDPROPERTIES = 628, + CREATEHEAP_INVALIDALIGNMENT = 629, + CREATEHEAP_UNRECOGNIZEDMISCFLAGS = 630, + CREATEHEAP_INVALIDMISCFLAGS = 631, + CREATEHEAP_INVALIDARG_RETURN = 632, + CREATEHEAP_OUTOFMEMORY_RETURN = 633, + CREATERESOURCEANDHEAP_NULLHEAPPROPERTIES = 634, + CREATERESOURCEANDHEAP_UNRECOGNIZEDHEAPTYPE = 635, + CREATERESOURCEANDHEAP_UNRECOGNIZEDCPUPAGEPROPERTIES = 636, + CREATERESOURCEANDHEAP_UNRECOGNIZEDMEMORYPOOL = 637, + CREATERESOURCEANDHEAP_INVALIDHEAPPROPERTIES = 638, + CREATERESOURCEANDHEAP_UNRECOGNIZEDHEAPMISCFLAGS = 639, + CREATERESOURCEANDHEAP_INVALIDHEAPMISCFLAGS = 640, + CREATERESOURCEANDHEAP_INVALIDARG_RETURN = 641, + CREATERESOURCEANDHEAP_OUTOFMEMORY_RETURN = 642, + GETCUSTOMHEAPPROPERTIES_UNRECOGNIZEDHEAPTYPE = 643, + GETCUSTOMHEAPPROPERTIES_INVALIDHEAPTYPE = 644, + CREATE_DESCRIPTOR_HEAP_INVALID_DESC = 645, + INVALID_DESCRIPTOR_HANDLE = 646, + CREATERASTERIZERSTATE_INVALID_CONSERVATIVERASTERMODE = 647, + CREATE_CONSTANT_BUFFER_VIEW_INVALID_RESOURCE = 649, + CREATE_CONSTANT_BUFFER_VIEW_INVALID_DESC = 650, + CREATE_UNORDEREDACCESS_VIEW_INVALID_COUNTER_USAGE = 652, + COPY_DESCRIPTORS_INVALID_RANGES = 653, + COPY_DESCRIPTORS_WRITE_ONLY_DESCRIPTOR = 654, + CREATEGRAPHICSPIPELINESTATE_RTV_FORMAT_NOT_UNKNOWN = 655, + CREATEGRAPHICSPIPELINESTATE_INVALID_RENDER_TARGET_COUNT = 656, + CREATEGRAPHICSPIPELINESTATE_VERTEX_SHADER_NOT_SET = 657, + CREATEGRAPHICSPIPELINESTATE_INPUTLAYOUT_NOT_SET = 658, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_HS_DS_SIGNATURE_MISMATCH = 659, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_REGISTERINDEX = 660, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_COMPONENTTYPE = 661, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_REGISTERMASK = 662, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_SYSTEMVALUE = 663, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_NEVERWRITTEN_ALWAYSREADS = 664, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_MINPRECISION = 665, + CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND = 666, + CREATEGRAPHICSPIPELINESTATE_HS_XOR_DS_MISMATCH = 667, + CREATEGRAPHICSPIPELINESTATE_HULL_SHADER_INPUT_TOPOLOGY_MISMATCH = 668, + CREATEGRAPHICSPIPELINESTATE_HS_DS_CONTROL_POINT_COUNT_MISMATCH = 669, + CREATEGRAPHICSPIPELINESTATE_HS_DS_TESSELLATOR_DOMAIN_MISMATCH = 670, + CREATEGRAPHICSPIPELINESTATE_INVALID_USE_OF_CENTER_MULTISAMPLE_PATTERN = 671, + CREATEGRAPHICSPIPELINESTATE_INVALID_USE_OF_FORCED_SAMPLE_COUNT = 672, + CREATEGRAPHICSPIPELINESTATE_INVALID_PRIMITIVETOPOLOGY = 673, + CREATEGRAPHICSPIPELINESTATE_INVALID_SYSTEMVALUE = 674, + CREATEGRAPHICSPIPELINESTATE_OM_DUAL_SOURCE_BLENDING_CAN_ONLY_HAVE_RENDER_TARGET_0 = 675, + CREATEGRAPHICSPIPELINESTATE_OM_RENDER_TARGET_DOES_NOT_SUPPORT_BLENDING = 676, + CREATEGRAPHICSPIPELINESTATE_PS_OUTPUT_TYPE_MISMATCH = 677, + CREATEGRAPHICSPIPELINESTATE_OM_RENDER_TARGET_DOES_NOT_SUPPORT_LOGIC_OPS = 678, + CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET = 679, + CREATEGRAPHICSPIPELINESTATE_DEPTHSTENCILVIEW_NOT_SET = 680, + CREATEGRAPHICSPIPELINESTATE_GS_INPUT_PRIMITIVE_MISMATCH = 681, + CREATEGRAPHICSPIPELINESTATE_POSITION_NOT_PRESENT = 682, + CREATEGRAPHICSPIPELINESTATE_MISSING_ROOT_SIGNATURE_FLAGS = 683, + CREATEGRAPHICSPIPELINESTATE_INVALID_INDEX_BUFFER_PROPERTIES = 684, + CREATEGRAPHICSPIPELINESTATE_INVALID_SAMPLE_DESC = 685, + CREATEGRAPHICSPIPELINESTATE_HS_ROOT_SIGNATURE_MISMATCH = 686, + CREATEGRAPHICSPIPELINESTATE_DS_ROOT_SIGNATURE_MISMATCH = 687, + CREATEGRAPHICSPIPELINESTATE_VS_ROOT_SIGNATURE_MISMATCH = 688, + CREATEGRAPHICSPIPELINESTATE_GS_ROOT_SIGNATURE_MISMATCH = 689, + CREATEGRAPHICSPIPELINESTATE_PS_ROOT_SIGNATURE_MISMATCH = 690, + CREATEGRAPHICSPIPELINESTATE_MISSING_ROOT_SIGNATURE = 691, + EXECUTE_BUNDLE_OPEN_BUNDLE = 692, + EXECUTE_BUNDLE_DESCRIPTOR_HEAP_MISMATCH = 693, + EXECUTE_BUNDLE_TYPE = 694, + DRAW_EMPTY_SCISSOR_RECTANGLE = 695, + CREATE_ROOT_SIGNATURE_BLOB_NOT_FOUND = 696, + CREATE_ROOT_SIGNATURE_DESERIALIZE_FAILED = 697, + CREATE_ROOT_SIGNATURE_INVALID_CONFIGURATION = 698, + CREATE_ROOT_SIGNATURE_NOT_SUPPORTED_ON_DEVICE = 699, + CREATERESOURCEANDHEAP_NULLRESOURCEPROPERTIES = 700, + CREATERESOURCEANDHEAP_NULLHEAP = 701, + GETRESOURCEALLOCATIONINFO_INVALIDRDESCS = 702, + MAKERESIDENT_NULLOBJECTARRAY = 703, + EVICT_NULLOBJECTARRAY = 705, + SET_DESCRIPTOR_TABLE_INVALID = 708, + SET_ROOT_CONSTANT_INVALID = 709, + SET_ROOT_CONSTANT_BUFFER_VIEW_INVALID = 710, + SET_ROOT_SHADER_RESOURCE_VIEW_INVALID = 711, + SET_ROOT_UNORDERED_ACCESS_VIEW_INVALID = 712, + SET_VERTEX_BUFFERS_INVALID_DESC = 713, + SET_INDEX_BUFFER_INVALID_DESC = 715, + SET_STREAM_OUTPUT_BUFFERS_INVALID_DESC = 717, + CREATERESOURCE_UNRECOGNIZEDDIMENSIONALITY = 718, + CREATERESOURCE_UNRECOGNIZEDLAYOUT = 719, + CREATERESOURCE_INVALIDDIMENSIONALITY = 720, + CREATERESOURCE_INVALIDALIGNMENT = 721, + CREATERESOURCE_INVALIDMIPLEVELS = 722, + CREATERESOURCE_INVALIDSAMPLEDESC = 723, + CREATERESOURCE_INVALIDLAYOUT = 724, + SET_INDEX_BUFFER_INVALID = 725, + SET_VERTEX_BUFFERS_INVALID = 726, + SET_STREAM_OUTPUT_BUFFERS_INVALID = 727, + SET_RENDER_TARGETS_INVALID = 728, + CREATEQUERY_HEAP_INVALID_PARAMETERS = 729, + BEGIN_END_QUERY_INVALID_PARAMETERS = 731, + CLOSE_COMMAND_LIST_OPEN_QUERY = 732, + RESOLVE_QUERY_DATA_INVALID_PARAMETERS = 733, + SET_PREDICATION_INVALID_PARAMETERS = 734, + TIMESTAMPS_NOT_SUPPORTED = 735, + CREATERESOURCE_UNRECOGNIZEDFORMAT = 737, + CREATERESOURCE_INVALIDFORMAT = 738, + GETCOPYABLEFOOTPRINTS_INVALIDSUBRESOURCERANGE = 739, + GETCOPYABLEFOOTPRINTS_INVALIDBASEOFFSET = 740, + GETCOPYABLELAYOUT_INVALIDSUBRESOURCERANGE = 739, + GETCOPYABLELAYOUT_INVALIDBASEOFFSET = 740, + RESOURCE_BARRIER_INVALID_HEAP = 741, + CREATE_SAMPLER_INVALID = 742, + CREATECOMMANDSIGNATURE_INVALID = 743, + EXECUTE_INDIRECT_INVALID_PARAMETERS = 744, + GETGPUVIRTUALADDRESS_INVALID_RESOURCE_DIMENSION = 745, + CREATERESOURCE_INVALIDCLEARVALUE = 815, + CREATERESOURCE_UNRECOGNIZEDCLEARVALUEFORMAT = 816, + CREATERESOURCE_INVALIDCLEARVALUEFORMAT = 817, + CREATERESOURCE_CLEARVALUEDENORMFLUSH = 818, + CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE = 820, + CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE = 821, + MAP_INVALIDHEAP = 822, + UNMAP_INVALIDHEAP = 823, + MAP_INVALIDRESOURCE = 824, + UNMAP_INVALIDRESOURCE = 825, + MAP_INVALIDSUBRESOURCE = 826, + UNMAP_INVALIDSUBRESOURCE = 827, + MAP_INVALIDRANGE = 828, + UNMAP_INVALIDRANGE = 829, + MAP_INVALIDDATAPOINTER = 832, + MAP_INVALIDARG_RETURN = 833, + MAP_OUTOFMEMORY_RETURN = 834, + EXECUTECOMMANDLISTS_BUNDLENOTSUPPORTED = 835, + EXECUTECOMMANDLISTS_COMMANDLISTMISMATCH = 836, + EXECUTECOMMANDLISTS_OPENCOMMANDLIST = 837, + EXECUTECOMMANDLISTS_FAILEDCOMMANDLIST = 838, + COPYBUFFERREGION_NULLDST = 839, + COPYBUFFERREGION_INVALIDDSTRESOURCEDIMENSION = 840, + COPYBUFFERREGION_DSTRANGEOUTOFBOUNDS = 841, + COPYBUFFERREGION_NULLSRC = 842, + COPYBUFFERREGION_INVALIDSRCRESOURCEDIMENSION = 843, + COPYBUFFERREGION_SRCRANGEOUTOFBOUNDS = 844, + COPYBUFFERREGION_INVALIDCOPYFLAGS = 845, + COPYTEXTUREREGION_NULLDST = 846, + COPYTEXTUREREGION_UNRECOGNIZEDDSTTYPE = 847, + COPYTEXTUREREGION_INVALIDDSTRESOURCEDIMENSION = 848, + COPYTEXTUREREGION_INVALIDDSTRESOURCE = 849, + COPYTEXTUREREGION_INVALIDDSTSUBRESOURCE = 850, + COPYTEXTUREREGION_INVALIDDSTOFFSET = 851, + COPYTEXTUREREGION_UNRECOGNIZEDDSTFORMAT = 852, + COPYTEXTUREREGION_INVALIDDSTFORMAT = 853, + COPYTEXTUREREGION_INVALIDDSTDIMENSIONS = 854, + COPYTEXTUREREGION_INVALIDDSTROWPITCH = 855, + COPYTEXTUREREGION_INVALIDDSTPLACEMENT = 856, + COPYTEXTUREREGION_INVALIDDSTDSPLACEDFOOTPRINTFORMAT = 857, + COPYTEXTUREREGION_DSTREGIONOUTOFBOUNDS = 858, + COPYTEXTUREREGION_NULLSRC = 859, + COPYTEXTUREREGION_UNRECOGNIZEDSRCTYPE = 860, + COPYTEXTUREREGION_INVALIDSRCRESOURCEDIMENSION = 861, + COPYTEXTUREREGION_INVALIDSRCRESOURCE = 862, + COPYTEXTUREREGION_INVALIDSRCSUBRESOURCE = 863, + COPYTEXTUREREGION_INVALIDSRCOFFSET = 864, + COPYTEXTUREREGION_UNRECOGNIZEDSRCFORMAT = 865, + COPYTEXTUREREGION_INVALIDSRCFORMAT = 866, + COPYTEXTUREREGION_INVALIDSRCDIMENSIONS = 867, + COPYTEXTUREREGION_INVALIDSRCROWPITCH = 868, + COPYTEXTUREREGION_INVALIDSRCPLACEMENT = 869, + COPYTEXTUREREGION_INVALIDSRCDSPLACEDFOOTPRINTFORMAT = 870, + COPYTEXTUREREGION_SRCREGIONOUTOFBOUNDS = 871, + COPYTEXTUREREGION_INVALIDDSTCOORDINATES = 872, + COPYTEXTUREREGION_INVALIDSRCBOX = 873, + COPYTEXTUREREGION_FORMATMISMATCH = 874, + COPYTEXTUREREGION_EMPTYBOX = 875, + COPYTEXTUREREGION_INVALIDCOPYFLAGS = 876, + RESOLVESUBRESOURCE_INVALID_SUBRESOURCE_INDEX = 877, + RESOLVESUBRESOURCE_INVALID_FORMAT = 878, + RESOLVESUBRESOURCE_RESOURCE_MISMATCH = 879, + RESOLVESUBRESOURCE_INVALID_SAMPLE_COUNT = 880, + CREATECOMPUTEPIPELINESTATE_INVALID_SHADER = 881, + CREATECOMPUTEPIPELINESTATE_CS_ROOT_SIGNATURE_MISMATCH = 882, + CREATECOMPUTEPIPELINESTATE_MISSING_ROOT_SIGNATURE = 883, + CREATEPIPELINESTATE_INVALIDCACHEDBLOB = 884, + CREATEPIPELINESTATE_CACHEDBLOBADAPTERMISMATCH = 885, + CREATEPIPELINESTATE_CACHEDBLOBDRIVERVERSIONMISMATCH = 886, + CREATEPIPELINESTATE_CACHEDBLOBDESCMISMATCH = 887, + CREATEPIPELINESTATE_CACHEDBLOBIGNORED = 888, + WRITETOSUBRESOURCE_INVALIDHEAP = 889, + WRITETOSUBRESOURCE_INVALIDRESOURCE = 890, + WRITETOSUBRESOURCE_INVALIDBOX = 891, + WRITETOSUBRESOURCE_INVALIDSUBRESOURCE = 892, + WRITETOSUBRESOURCE_EMPTYBOX = 893, + READFROMSUBRESOURCE_INVALIDHEAP = 894, + READFROMSUBRESOURCE_INVALIDRESOURCE = 895, + READFROMSUBRESOURCE_INVALIDBOX = 896, + READFROMSUBRESOURCE_INVALIDSUBRESOURCE = 897, + READFROMSUBRESOURCE_EMPTYBOX = 898, + TOO_MANY_NODES_SPECIFIED = 899, + INVALID_NODE_INDEX = 900, + GETHEAPPROPERTIES_INVALIDRESOURCE = 901, + NODE_MASK_MISMATCH = 902, + COMMAND_LIST_OUTOFMEMORY = 903, + COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES = 904, + COMMAND_LIST_TOO_MANY_SWAPCHAIN_REFERENCES = 905, + COMMAND_QUEUE_TOO_MANY_SWAPCHAIN_REFERENCES = 906, + EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE = 907, + COMMAND_LIST_SETRENDERTARGETS_INVALIDNUMRENDERTARGETS = 908, + CREATE_QUEUE_INVALID_TYPE = 909, + CREATE_QUEUE_INVALID_FLAGS = 910, + CREATESHAREDRESOURCE_INVALIDFLAGS = 911, + CREATESHAREDRESOURCE_INVALIDFORMAT = 912, + CREATESHAREDHEAP_INVALIDFLAGS = 913, + REFLECTSHAREDPROPERTIES_UNRECOGNIZEDPROPERTIES = 914, + REFLECTSHAREDPROPERTIES_INVALIDSIZE = 915, + REFLECTSHAREDPROPERTIES_INVALIDOBJECT = 916, + KEYEDMUTEX_INVALIDOBJECT = 917, + KEYEDMUTEX_INVALIDKEY = 918, + KEYEDMUTEX_WRONGSTATE = 919, + CREATE_QUEUE_INVALID_PRIORITY = 920, + OBJECT_DELETED_WHILE_STILL_IN_USE = 921, + CREATEPIPELINESTATE_INVALID_FLAGS = 922, + HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE = 923, + COMMAND_LIST_DRAW_RENDER_TARGET_DELETED = 924, + CREATEGRAPHICSPIPELINESTATE_ALL_RENDER_TARGETS_HAVE_UNKNOWN_FORMAT = 925, + HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS = 926, + EXECUTECOMMANDLISTS_GPU_WRITTEN_READBACK_RESOURCE_MAPPED = 927, + UNMAP_RANGE_NOT_EMPTY = 929, + MAP_INVALID_NULLRANGE = 930, + UNMAP_INVALID_NULLRANGE = 931, + NO_GRAPHICS_API_SUPPORT = 932, + NO_COMPUTE_API_SUPPORT = 933, + RESOLVESUBRESOURCE_RESOURCE_FLAGS_NOT_SUPPORTED = 934, + GPU_BASED_VALIDATION_ROOT_ARGUMENT_UNINITIALIZED = 935, + GPU_BASED_VALIDATION_DESCRIPTOR_HEAP_INDEX_OUT_OF_BOUNDS = 936, + GPU_BASED_VALIDATION_DESCRIPTOR_TABLE_REGISTER_INDEX_OUT_OF_BOUNDS = 937, + GPU_BASED_VALIDATION_DESCRIPTOR_UNINITIALIZED = 938, + GPU_BASED_VALIDATION_DESCRIPTOR_TYPE_MISMATCH = 939, + GPU_BASED_VALIDATION_SRV_RESOURCE_DIMENSION_MISMATCH = 940, + GPU_BASED_VALIDATION_UAV_RESOURCE_DIMENSION_MISMATCH = 941, + GPU_BASED_VALIDATION_INCOMPATIBLE_RESOURCE_STATE = 942, + COPYRESOURCE_NULLDST = 943, + COPYRESOURCE_INVALIDDSTRESOURCE = 944, + COPYRESOURCE_NULLSRC = 945, + COPYRESOURCE_INVALIDSRCRESOURCE = 946, + RESOLVESUBRESOURCE_NULLDST = 947, + RESOLVESUBRESOURCE_INVALIDDSTRESOURCE = 948, + RESOLVESUBRESOURCE_NULLSRC = 949, + RESOLVESUBRESOURCE_INVALIDSRCRESOURCE = 950, + PIPELINE_STATE_TYPE_MISMATCH = 951, + COMMAND_LIST_DISPATCH_ROOT_SIGNATURE_NOT_SET = 952, + COMMAND_LIST_DISPATCH_ROOT_SIGNATURE_MISMATCH = 953, + RESOURCE_BARRIER_ZERO_BARRIERS = 954, + BEGIN_END_EVENT_MISMATCH = 955, + RESOURCE_BARRIER_POSSIBLE_BEFORE_AFTER_MISMATCH = 956, + RESOURCE_BARRIER_MISMATCHING_BEGIN_END = 957, + GPU_BASED_VALIDATION_INVALID_RESOURCE = 958, + USE_OF_ZERO_REFCOUNT_OBJECT = 959, + OBJECT_EVICTED_WHILE_STILL_IN_USE = 960, + GPU_BASED_VALIDATION_ROOT_DESCRIPTOR_ACCESS_OUT_OF_BOUNDS = 961, + CREATEPIPELINELIBRARY_INVALIDLIBRARYBLOB = 962, + CREATEPIPELINELIBRARY_DRIVERVERSIONMISMATCH = 963, + CREATEPIPELINELIBRARY_ADAPTERVERSIONMISMATCH = 964, + CREATEPIPELINELIBRARY_UNSUPPORTED = 965, + CREATE_PIPELINELIBRARY = 966, + LIVE_PIPELINELIBRARY = 967, + DESTROY_PIPELINELIBRARY = 968, + STOREPIPELINE_NONAME = 969, + STOREPIPELINE_DUPLICATENAME = 970, + LOADPIPELINE_NAMENOTFOUND = 971, + LOADPIPELINE_INVALIDDESC = 972, + PIPELINELIBRARY_SERIALIZE_NOTENOUGHMEMORY = 973, + CREATEGRAPHICSPIPELINESTATE_PS_OUTPUT_RT_OUTPUT_MISMATCH = 974, + SETEVENTONMULTIPLEFENCECOMPLETION_INVALIDFLAGS = 975, + CREATE_QUEUE_VIDEO_NOT_SUPPORTED = 976, + CREATE_COMMAND_ALLOCATOR_VIDEO_NOT_SUPPORTED = 977, + CREATEQUERY_HEAP_VIDEO_DECODE_STATISTICS_NOT_SUPPORTED = 978, + CREATE_VIDEODECODECOMMANDLIST = 979, + CREATE_VIDEODECODER = 980, + CREATE_VIDEODECODESTREAM = 981, + LIVE_VIDEODECODECOMMANDLIST = 982, + LIVE_VIDEODECODER = 983, + LIVE_VIDEODECODESTREAM = 984, + DESTROY_VIDEODECODECOMMANDLIST = 985, + DESTROY_VIDEODECODER = 986, + DESTROY_VIDEODECODESTREAM = 987, + DECODE_FRAME_INVALID_PARAMETERS = 988, + DEPRECATED_API = 989, + RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE = 990, + COMMAND_LIST_DESCRIPTOR_TABLE_NOT_SET = 991, + COMMAND_LIST_ROOT_CONSTANT_BUFFER_VIEW_NOT_SET = 992, + COMMAND_LIST_ROOT_SHADER_RESOURCE_VIEW_NOT_SET = 993, + COMMAND_LIST_ROOT_UNORDERED_ACCESS_VIEW_NOT_SET = 994, + DISCARD_INVALID_SUBRESOURCE_RANGE = 995, + DISCARD_ONE_SUBRESOURCE_FOR_MIPS_WITH_RECTS = 996, + DISCARD_NO_RECTS_FOR_NON_TEXTURE2D = 997, + COPY_ON_SAME_SUBRESOURCE = 998, + SETRESIDENCYPRIORITY_INVALID_PAGEABLE = 999, + GPU_BASED_VALIDATION_UNSUPPORTED = 1000, + STATIC_DESCRIPTOR_INVALID_DESCRIPTOR_CHANGE = 1001, + DATA_STATIC_DESCRIPTOR_INVALID_DATA_CHANGE = 1002, + DATA_STATIC_WHILE_SET_AT_EXECUTE_DESCRIPTOR_INVALID_DATA_CHANGE = 1003, + EXECUTE_BUNDLE_STATIC_DESCRIPTOR_DATA_STATIC_NOT_SET = 1004, + GPU_BASED_VALIDATION_RESOURCE_ACCESS_OUT_OF_BOUNDS = 1005, + GPU_BASED_VALIDATION_SAMPLER_MODE_MISMATCH = 1006, + CREATE_FENCE_INVALID_FLAGS = 1007, + RESOURCE_BARRIER_DUPLICATE_SUBRESOURCE_TRANSITIONS = 1008, + SETRESIDENCYPRIORITY_INVALID_PRIORITY = 1009, + CREATE_DESCRIPTOR_HEAP_LARGE_NUM_DESCRIPTORS = 1013, + BEGIN_EVENT = 1014, + END_EVENT = 1015, + CREATEDEVICE_DEBUG_LAYER_STARTUP_OPTIONS = 1016, + CREATEDEPTHSTENCILSTATE_DEPTHBOUNDSTEST_UNSUPPORTED = 1017, + CREATEPIPELINESTATE_DUPLICATE_SUBOBJECT = 1018, + CREATEPIPELINESTATE_UNKNOWN_SUBOBJECT = 1019, + CREATEPIPELINESTATE_ZERO_SIZE_STREAM = 1020, + CREATEPIPELINESTATE_INVALID_STREAM = 1021, + CREATEPIPELINESTATE_CANNOT_DEDUCE_TYPE = 1022, + COMMAND_LIST_STATIC_DESCRIPTOR_RESOURCE_DIMENSION_MISMATCH = 1023, + CREATE_COMMAND_QUEUE_INSUFFICIENT_PRIVILEGE_FOR_GLOBAL_REALTIME = 1024, + CREATE_COMMAND_QUEUE_INSUFFICIENT_HARDWARE_SUPPORT_FOR_GLOBAL_REALTIME = 1025, + ATOMICCOPYBUFFER_INVALID_ARCHITECTURE = 1026, + ATOMICCOPYBUFFER_NULL_DST = 1027, + ATOMICCOPYBUFFER_INVALID_DST_RESOURCE_DIMENSION = 1028, + ATOMICCOPYBUFFER_DST_RANGE_OUT_OF_BOUNDS = 1029, + ATOMICCOPYBUFFER_NULL_SRC = 1030, + ATOMICCOPYBUFFER_INVALID_SRC_RESOURCE_DIMENSION = 1031, + ATOMICCOPYBUFFER_SRC_RANGE_OUT_OF_BOUNDS = 1032, + ATOMICCOPYBUFFER_INVALID_OFFSET_ALIGNMENT = 1033, + ATOMICCOPYBUFFER_NULL_DEPENDENT_RESOURCES = 1034, + ATOMICCOPYBUFFER_NULL_DEPENDENT_SUBRESOURCE_RANGES = 1035, + ATOMICCOPYBUFFER_INVALID_DEPENDENT_RESOURCE = 1036, + ATOMICCOPYBUFFER_INVALID_DEPENDENT_SUBRESOURCE_RANGE = 1037, + ATOMICCOPYBUFFER_DEPENDENT_SUBRESOURCE_OUT_OF_BOUNDS = 1038, + ATOMICCOPYBUFFER_DEPENDENT_RANGE_OUT_OF_BOUNDS = 1039, + ATOMICCOPYBUFFER_ZERO_DEPENDENCIES = 1040, + DEVICE_CREATE_SHARED_HANDLE_INVALIDARG = 1041, + DESCRIPTOR_HANDLE_WITH_INVALID_RESOURCE = 1042, + SETDEPTHBOUNDS_INVALIDARGS = 1043, + GPU_BASED_VALIDATION_RESOURCE_STATE_IMPRECISE = 1044, + COMMAND_LIST_PIPELINE_STATE_NOT_SET = 1045, + CREATEGRAPHICSPIPELINESTATE_SHADER_MODEL_MISMATCH = 1046, + OBJECT_ACCESSED_WHILE_STILL_IN_USE = 1047, + PROGRAMMABLE_MSAA_UNSUPPORTED = 1048, + SETSAMPLEPOSITIONS_INVALIDARGS = 1049, + RESOLVESUBRESOURCEREGION_INVALID_RECT = 1050, + CREATE_VIDEODECODECOMMANDQUEUE = 1051, + CREATE_VIDEOPROCESSCOMMANDLIST = 1052, + CREATE_VIDEOPROCESSCOMMANDQUEUE = 1053, + LIVE_VIDEODECODECOMMANDQUEUE = 1054, + LIVE_VIDEOPROCESSCOMMANDLIST = 1055, + LIVE_VIDEOPROCESSCOMMANDQUEUE = 1056, + DESTROY_VIDEODECODECOMMANDQUEUE = 1057, + DESTROY_VIDEOPROCESSCOMMANDLIST = 1058, + DESTROY_VIDEOPROCESSCOMMANDQUEUE = 1059, + CREATE_VIDEOPROCESSOR = 1060, + CREATE_VIDEOPROCESSSTREAM = 1061, + LIVE_VIDEOPROCESSOR = 1062, + LIVE_VIDEOPROCESSSTREAM = 1063, + DESTROY_VIDEOPROCESSOR = 1064, + DESTROY_VIDEOPROCESSSTREAM = 1065, + PROCESS_FRAME_INVALID_PARAMETERS = 1066, + COPY_INVALIDLAYOUT = 1067, + CREATE_CRYPTO_SESSION = 1068, + CREATE_CRYPTO_SESSION_POLICY = 1069, + CREATE_PROTECTED_RESOURCE_SESSION = 1070, + LIVE_CRYPTO_SESSION = 1071, + LIVE_CRYPTO_SESSION_POLICY = 1072, + LIVE_PROTECTED_RESOURCE_SESSION = 1073, + DESTROY_CRYPTO_SESSION = 1074, + DESTROY_CRYPTO_SESSION_POLICY = 1075, + DESTROY_PROTECTED_RESOURCE_SESSION = 1076, + PROTECTED_RESOURCE_SESSION_UNSUPPORTED = 1077, + FENCE_INVALIDOPERATION = 1078, + CREATEQUERY_HEAP_COPY_QUEUE_TIMESTAMPS_NOT_SUPPORTED = 1079, + SAMPLEPOSITIONS_MISMATCH_DEFERRED = 1080, + SAMPLEPOSITIONS_MISMATCH_RECORDTIME_ASSUMEDFROMFIRSTUSE = 1081, + SAMPLEPOSITIONS_MISMATCH_RECORDTIME_ASSUMEDFROMCLEAR = 1082, + CREATE_VIDEODECODERHEAP = 1083, + LIVE_VIDEODECODERHEAP = 1084, + DESTROY_VIDEODECODERHEAP = 1085, + OPENEXISTINGHEAP_INVALIDARG_RETURN = 1086, + OPENEXISTINGHEAP_OUTOFMEMORY_RETURN = 1087, + OPENEXISTINGHEAP_INVALIDADDRESS = 1088, + OPENEXISTINGHEAP_INVALIDHANDLE = 1089, + WRITEBUFFERIMMEDIATE_INVALID_DEST = 1090, + WRITEBUFFERIMMEDIATE_INVALID_MODE = 1091, + WRITEBUFFERIMMEDIATE_INVALID_ALIGNMENT = 1092, + WRITEBUFFERIMMEDIATE_NOT_SUPPORTED = 1093, + SETVIEWINSTANCEMASK_INVALIDARGS = 1094, + VIEW_INSTANCING_UNSUPPORTED = 1095, + VIEW_INSTANCING_INVALIDARGS = 1096, + COPYTEXTUREREGION_MISMATCH_DECODE_REFERENCE_ONLY_FLAG = 1097, + COPYRESOURCE_MISMATCH_DECODE_REFERENCE_ONLY_FLAG = 1098, + CREATE_VIDEO_DECODE_HEAP_CAPS_FAILURE = 1099, + CREATE_VIDEO_DECODE_HEAP_CAPS_UNSUPPORTED = 1100, + VIDEO_DECODE_SUPPORT_INVALID_INPUT = 1101, + CREATE_VIDEO_DECODER_UNSUPPORTED = 1102, + CREATEGRAPHICSPIPELINESTATE_METADATA_ERROR = 1103, + CREATEGRAPHICSPIPELINESTATE_VIEW_INSTANCING_VERTEX_SIZE_EXCEEDED = 1104, + CREATEGRAPHICSPIPELINESTATE_RUNTIME_INTERNAL_ERROR = 1105, + NO_VIDEO_API_SUPPORT = 1106, + VIDEO_PROCESS_SUPPORT_INVALID_INPUT = 1107, + CREATE_VIDEO_PROCESSOR_CAPS_FAILURE = 1108, + VIDEO_PROCESS_SUPPORT_UNSUPPORTED_FORMAT = 1109, + VIDEO_DECODE_FRAME_INVALID_ARGUMENT = 1110, + ENQUEUE_MAKE_RESIDENT_INVALID_FLAGS = 1111, + OPENEXISTINGHEAP_UNSUPPORTED = 1112, + VIDEO_PROCESS_FRAMES_INVALID_ARGUMENT = 1113, + VIDEO_DECODE_SUPPORT_UNSUPPORTED = 1114, + CREATE_COMMANDRECORDER = 1115, + LIVE_COMMANDRECORDER = 1116, + DESTROY_COMMANDRECORDER = 1117, + CREATE_COMMAND_RECORDER_VIDEO_NOT_SUPPORTED = 1118, + CREATE_COMMAND_RECORDER_INVALID_SUPPORT_FLAGS = 1119, + CREATE_COMMAND_RECORDER_INVALID_FLAGS = 1120, + CREATE_COMMAND_RECORDER_MORE_RECORDERS_THAN_LOGICAL_PROCESSORS = 1121, + CREATE_COMMANDPOOL = 1122, + LIVE_COMMANDPOOL = 1123, + DESTROY_COMMANDPOOL = 1124, + CREATE_COMMAND_POOL_INVALID_FLAGS = 1125, + CREATE_COMMAND_LIST_VIDEO_NOT_SUPPORTED = 1126, + COMMAND_RECORDER_SUPPORT_FLAGS_MISMATCH = 1127, + COMMAND_RECORDER_CONTENTION = 1128, + COMMAND_RECORDER_USAGE_WITH_CREATECOMMANDLIST_COMMAND_LIST = 1129, + COMMAND_ALLOCATOR_USAGE_WITH_CREATECOMMANDLIST1_COMMAND_LIST = 1130, + CANNOT_EXECUTE_EMPTY_COMMAND_LIST = 1131, + CANNOT_RESET_COMMAND_POOL_WITH_OPEN_COMMAND_LISTS = 1132, + CANNOT_USE_COMMAND_RECORDER_WITHOUT_CURRENT_TARGET = 1133, + CANNOT_CHANGE_COMMAND_RECORDER_TARGET_WHILE_RECORDING = 1134, + COMMAND_POOL_SYNC = 1135, + EVICT_UNDERFLOW = 1136, + CREATE_META_COMMAND = 1137, + LIVE_META_COMMAND = 1138, + DESTROY_META_COMMAND = 1139, + COPYBUFFERREGION_INVALID_DST_RESOURCE = 1140, + COPYBUFFERREGION_INVALID_SRC_RESOURCE = 1141, + ATOMICCOPYBUFFER_INVALID_DST_RESOURCE = 1142, + ATOMICCOPYBUFFER_INVALID_SRC_RESOURCE = 1143, + CREATEPLACEDRESOURCEONBUFFER_NULL_BUFFER = 1144, + CREATEPLACEDRESOURCEONBUFFER_NULL_RESOURCE_DESC = 1145, + CREATEPLACEDRESOURCEONBUFFER_UNSUPPORTED = 1146, + CREATEPLACEDRESOURCEONBUFFER_INVALID_BUFFER_DIMENSION = 1147, + CREATEPLACEDRESOURCEONBUFFER_INVALID_BUFFER_FLAGS = 1148, + CREATEPLACEDRESOURCEONBUFFER_INVALID_BUFFER_OFFSET = 1149, + CREATEPLACEDRESOURCEONBUFFER_INVALID_RESOURCE_DIMENSION = 1150, + CREATEPLACEDRESOURCEONBUFFER_INVALID_RESOURCE_FLAGS = 1151, + CREATEPLACEDRESOURCEONBUFFER_OUTOFMEMORY_RETURN = 1152, + CANNOT_CREATE_GRAPHICS_AND_VIDEO_COMMAND_RECORDER = 1153, + UPDATETILEMAPPINGS_POSSIBLY_MISMATCHING_PROPERTIES = 1154, + CREATE_COMMAND_LIST_INVALID_COMMAND_LIST_TYPE = 1155, + CLEARUNORDEREDACCESSVIEW_INCOMPATIBLE_WITH_STRUCTURED_BUFFERS = 1156, + COMPUTE_ONLY_DEVICE_OPERATION_UNSUPPORTED = 1157, + BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INVALID = 1158, + EMIT_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_INVALID = 1159, + COPY_RAYTRACING_ACCELERATION_STRUCTURE_INVALID = 1160, + DISPATCH_RAYS_INVALID = 1161, + GET_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO_INVALID = 1162, + CREATE_LIFETIMETRACKER = 1163, + LIVE_LIFETIMETRACKER = 1164, + DESTROY_LIFETIMETRACKER = 1165, + DESTROYOWNEDOBJECT_OBJECTNOTOWNED = 1166, + CREATE_TRACKEDWORKLOAD = 1167, + LIVE_TRACKEDWORKLOAD = 1168, + DESTROY_TRACKEDWORKLOAD = 1169, + RENDER_PASS_ERROR = 1170, + META_COMMAND_ID_INVALID = 1171, + META_COMMAND_UNSUPPORTED_PARAMS = 1172, + META_COMMAND_FAILED_ENUMERATION = 1173, + META_COMMAND_PARAMETER_SIZE_MISMATCH = 1174, + UNINITIALIZED_META_COMMAND = 1175, + META_COMMAND_INVALID_GPU_VIRTUAL_ADDRESS = 1176, + CREATE_VIDEOENCODECOMMANDLIST = 1177, + LIVE_VIDEOENCODECOMMANDLIST = 1178, + DESTROY_VIDEOENCODECOMMANDLIST = 1179, + CREATE_VIDEOENCODECOMMANDQUEUE = 1180, + LIVE_VIDEOENCODECOMMANDQUEUE = 1181, + DESTROY_VIDEOENCODECOMMANDQUEUE = 1182, + CREATE_VIDEOMOTIONESTIMATOR = 1183, + LIVE_VIDEOMOTIONESTIMATOR = 1184, + DESTROY_VIDEOMOTIONESTIMATOR = 1185, + CREATE_VIDEOMOTIONVECTORHEAP = 1186, + LIVE_VIDEOMOTIONVECTORHEAP = 1187, + DESTROY_VIDEOMOTIONVECTORHEAP = 1188, + MULTIPLE_TRACKED_WORKLOADS = 1189, + MULTIPLE_TRACKED_WORKLOAD_PAIRS = 1190, + OUT_OF_ORDER_TRACKED_WORKLOAD_PAIR = 1191, + CANNOT_ADD_TRACKED_WORKLOAD = 1192, + INCOMPLETE_TRACKED_WORKLOAD_PAIR = 1193, + CREATE_STATE_OBJECT_ERROR = 1194, + GET_SHADER_IDENTIFIER_ERROR = 1195, + GET_SHADER_STACK_SIZE_ERROR = 1196, + GET_PIPELINE_STACK_SIZE_ERROR = 1197, + SET_PIPELINE_STACK_SIZE_ERROR = 1198, + GET_SHADER_IDENTIFIER_SIZE_INVALID = 1199, + CHECK_DRIVER_MATCHING_IDENTIFIER_INVALID = 1200, + CHECK_DRIVER_MATCHING_IDENTIFIER_DRIVER_REPORTED_ISSUE = 1201, + RENDER_PASS_INVALID_RESOURCE_BARRIER = 1202, + RENDER_PASS_DISALLOWED_API_CALLED = 1203, + RENDER_PASS_CANNOT_NEST_RENDER_PASSES = 1204, + RENDER_PASS_CANNOT_END_WITHOUT_BEGIN = 1205, + RENDER_PASS_CANNOT_CLOSE_COMMAND_LIST = 1206, + RENDER_PASS_GPU_WORK_WHILE_SUSPENDED = 1207, + RENDER_PASS_MISMATCHING_SUSPEND_RESUME = 1208, + RENDER_PASS_NO_PRIOR_SUSPEND_WITHIN_EXECUTECOMMANDLISTS = 1209, + RENDER_PASS_NO_SUBSEQUENT_RESUME_WITHIN_EXECUTECOMMANDLISTS = 1210, + TRACKED_WORKLOAD_COMMAND_QUEUE_MISMATCH = 1211, + TRACKED_WORKLOAD_NOT_SUPPORTED = 1212, + RENDER_PASS_MISMATCHING_NO_ACCESS = 1213, + RENDER_PASS_UNSUPPORTED_RESOLVE = 1214, + CLEARUNORDEREDACCESSVIEW_INVALID_RESOURCE_PTR = 1215, + WINDOWS7_FENCE_OUTOFORDER_SIGNAL = 1216, + WINDOWS7_FENCE_OUTOFORDER_WAIT = 1217, + VIDEO_CREATE_MOTION_ESTIMATOR_INVALID_ARGUMENT = 1218, + VIDEO_CREATE_MOTION_VECTOR_HEAP_INVALID_ARGUMENT = 1219, + ESTIMATE_MOTION_INVALID_ARGUMENT = 1220, + RESOLVE_MOTION_VECTOR_HEAP_INVALID_ARGUMENT = 1221, + GETGPUVIRTUALADDRESS_INVALID_HEAP_TYPE = 1222, + SET_BACKGROUND_PROCESSING_MODE_INVALID_ARGUMENT = 1223, + CREATE_COMMAND_LIST_INVALID_COMMAND_LIST_TYPE_FOR_FEATURE_LEVEL = 1224, + CREATE_VIDEOEXTENSIONCOMMAND = 1225, + LIVE_VIDEOEXTENSIONCOMMAND = 1226, + DESTROY_VIDEOEXTENSIONCOMMAND = 1227, + INVALID_VIDEO_EXTENSION_COMMAND_ID = 1228, + VIDEO_EXTENSION_COMMAND_INVALID_ARGUMENT = 1229, + CREATE_ROOT_SIGNATURE_NOT_UNIQUE_IN_DXIL_LIBRARY = 1230, + VARIABLE_SHADING_RATE_NOT_ALLOWED_WITH_TIR = 1231, + GEOMETRY_SHADER_OUTPUTTING_BOTH_VIEWPORT_ARRAY_INDEX_AND_SHADING_RATE_NOT_SUPPORTED_ON_DEVICE = 1232, + RSSETSHADING_RATE_INVALID_SHADING_RATE = 1233, + RSSETSHADING_RATE_SHADING_RATE_NOT_PERMITTED_BY_CAP = 1234, + RSSETSHADING_RATE_INVALID_COMBINER = 1235, + RSSETSHADINGRATEIMAGE_REQUIRES_TIER_2 = 1236, + RSSETSHADINGRATE_REQUIRES_TIER_1 = 1237, + SHADING_RATE_IMAGE_INCORRECT_FORMAT = 1238, + SHADING_RATE_IMAGE_INCORRECT_ARRAY_SIZE = 1239, + SHADING_RATE_IMAGE_INCORRECT_MIP_LEVEL = 1240, + SHADING_RATE_IMAGE_INCORRECT_SAMPLE_COUNT = 1241, + SHADING_RATE_IMAGE_INCORRECT_SAMPLE_QUALITY = 1242, + NON_RETAIL_SHADER_MODEL_WONT_VALIDATE = 1243, + CREATEGRAPHICSPIPELINESTATE_AS_ROOT_SIGNATURE_MISMATCH = 1244, + CREATEGRAPHICSPIPELINESTATE_MS_ROOT_SIGNATURE_MISMATCH = 1245, + ADD_TO_STATE_OBJECT_ERROR = 1246, + CREATE_PROTECTED_RESOURCE_SESSION_INVALID_ARGUMENT = 1247, + CREATEGRAPHICSPIPELINESTATE_MS_PSO_DESC_MISMATCH = 1248, + CREATEPIPELINESTATE_MS_INCOMPLETE_TYPE = 1249, + CREATEGRAPHICSPIPELINESTATE_AS_NOT_MS_MISMATCH = 1250, + CREATEGRAPHICSPIPELINESTATE_MS_NOT_PS_MISMATCH = 1251, + NONZERO_SAMPLER_FEEDBACK_MIP_REGION_WITH_INCOMPATIBLE_FORMAT = 1252, + CREATEGRAPHICSPIPELINESTATE_INPUTLAYOUT_SHADER_MISMATCH = 1253, + EMPTY_DISPATCH = 1254, + RESOURCE_FORMAT_REQUIRES_SAMPLER_FEEDBACK_CAPABILITY = 1255, + SAMPLER_FEEDBACK_MAP_INVALID_MIP_REGION = 1256, + SAMPLER_FEEDBACK_MAP_INVALID_DIMENSION = 1257, + SAMPLER_FEEDBACK_MAP_INVALID_SAMPLE_COUNT = 1258, + SAMPLER_FEEDBACK_MAP_INVALID_SAMPLE_QUALITY = 1259, + SAMPLER_FEEDBACK_MAP_INVALID_LAYOUT = 1260, + SAMPLER_FEEDBACK_MAP_REQUIRES_UNORDERED_ACCESS_FLAG = 1261, + SAMPLER_FEEDBACK_CREATE_UAV_NULL_ARGUMENTS = 1262, + SAMPLER_FEEDBACK_UAV_REQUIRES_SAMPLER_FEEDBACK_CAPABILITY = 1263, + SAMPLER_FEEDBACK_CREATE_UAV_REQUIRES_FEEDBACK_MAP_FORMAT = 1264, + CREATEMESHSHADER_INVALIDSHADERBYTECODE = 1265, + CREATEMESHSHADER_OUTOFMEMORY = 1266, + CREATEMESHSHADERWITHSTREAMOUTPUT_INVALIDSHADERTYPE = 1267, + RESOLVESUBRESOURCE_SAMPLER_FEEDBACK_TRANSCODE_INVALID_FORMAT = 1268, + RESOLVESUBRESOURCE_SAMPLER_FEEDBACK_INVALID_MIP_LEVEL_COUNT = 1269, + RESOLVESUBRESOURCE_SAMPLER_FEEDBACK_TRANSCODE_ARRAY_SIZE_MISMATCH = 1270, + SAMPLER_FEEDBACK_CREATE_UAV_MISMATCHING_TARGETED_RESOURCE = 1271, + CREATEMESHSHADER_OUTPUTEXCEEDSMAXSIZE = 1272, + CREATEMESHSHADER_GROUPSHAREDEXCEEDSMAXSIZE = 1273, + VERTEX_SHADER_OUTPUTTING_BOTH_VIEWPORT_ARRAY_INDEX_AND_SHADING_RATE_NOT_SUPPORTED_ON_DEVICE = 1274, + MESH_SHADER_OUTPUTTING_BOTH_VIEWPORT_ARRAY_INDEX_AND_SHADING_RATE_NOT_SUPPORTED_ON_DEVICE = 1275, + CREATEMESHSHADER_MISMATCHEDASMSPAYLOADSIZE = 1276, + CREATE_ROOT_SIGNATURE_UNBOUNDED_STATIC_DESCRIPTORS = 1277, + CREATEAMPLIFICATIONSHADER_INVALIDSHADERBYTECODE = 1278, + CREATEAMPLIFICATIONSHADER_OUTOFMEMORY = 1279, + MESSAGES_END = 1280, +} + +MESSAGE :: struct { + Category: MESSAGE_CATEGORY, + Severity: MESSAGE_SEVERITY, + ID: MESSAGE_ID, + pDescription: cstring, + DescriptionByteLength: SIZE_T, +} + +INFO_QUEUE_FILTER_DESC :: struct { + NumCategories: u32, + pCategoryList: ^MESSAGE_CATEGORY, + NumSeverities: u32, + pSeverityList: ^MESSAGE_SEVERITY, + NumIDs: u32, + pIDList: ^MESSAGE_ID, +} + +INFO_QUEUE_FILTER :: struct { + AllowList: INFO_QUEUE_FILTER_DESC, + DenyList: INFO_QUEUE_FILTER_DESC, +} + + +IInfoQueue_UUID :: "0742a90b-c387-483f-b946-30a7e4e61458" +IInfoQueue :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12infoqueue_vtable: ^IInfoQueue_VTable, +} +IInfoQueue_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetMessageCountLimit: proc "stdcall" (this: ^IInfoQueue, MessageCountLimit: u64) -> HRESULT, + ClearStoredMessages: proc "stdcall" (this: ^IInfoQueue), + GetMessageA: proc "stdcall" (this: ^IInfoQueue, MessageIndex: u64, pMessage: ^MESSAGE, pMessageByteLength: ^SIZE_T) -> HRESULT, + GetNumMessagesAllowedByStorageFilter: proc "stdcall" (this: ^IInfoQueue) -> u64, + GetNumMessagesDeniedByStorageFilter: proc "stdcall" (this: ^IInfoQueue) -> u64, + GetNumStoredMessages: proc "stdcall" (this: ^IInfoQueue) -> u64, + GetNumStoredMessagesAllowedByRetrievalFilter: proc "stdcall" (this: ^IInfoQueue) -> u64, + GetNumMessagesDiscardedByMessageCountLimit: proc "stdcall" (this: ^IInfoQueue) -> u64, + GetMessageCountLimit: proc "stdcall" (this: ^IInfoQueue) -> u64, + AddStorageFilterEntries: proc "stdcall" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + GetStorageFilter: proc "stdcall" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER, pFilterByteLength: ^SIZE_T) -> HRESULT, + ClearStorageFilter: proc "stdcall" (this: ^IInfoQueue), + PushEmptyStorageFilter: proc "stdcall" (this: ^IInfoQueue) -> HRESULT, + PushCopyOfStorageFilter: proc "stdcall" (this: ^IInfoQueue) -> HRESULT, + PushStorageFilter: proc "stdcall" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + PopStorageFilter: proc "stdcall" (this: ^IInfoQueue), + GetStorageFilterStackSize: proc "stdcall" (this: ^IInfoQueue) -> u32, + AddRetrievalFilterEntries: proc "stdcall" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + GetRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER, pFilterByteLength: ^SIZE_T) -> HRESULT, + ClearRetrievalFilter: proc "stdcall" (this: ^IInfoQueue), + PushEmptyRetrievalFilter: proc "stdcall" (this: ^IInfoQueue) -> HRESULT, + PushCopyOfRetrievalFilter: proc "stdcall" (this: ^IInfoQueue) -> HRESULT, + PushRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + PopRetrievalFilter: proc "stdcall" (this: ^IInfoQueue), + GetRetrievalFilterStackSize: proc "stdcall" (this: ^IInfoQueue) -> u32, + AddMessage: proc "stdcall" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: cstring) -> HRESULT, + AddApplicationMessage: proc "stdcall" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, pDescription: cstring) -> HRESULT, + SetBreakOnCategory: proc "stdcall" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, bEnable: BOOL) -> HRESULT, + SetBreakOnSeverity: proc "stdcall" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, bEnable: BOOL) -> HRESULT, + SetBreakOnID: proc "stdcall" (this: ^IInfoQueue, ID: MESSAGE_ID, bEnable: BOOL) -> HRESULT, + GetBreakOnCategory: proc "stdcall" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY) -> BOOL, + GetBreakOnSeverity: proc "stdcall" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY) -> BOOL, + GetBreakOnID: proc "stdcall" (this: ^IInfoQueue, ID: MESSAGE_ID) -> BOOL, + SetMuteDebugOutput: proc "stdcall" (this: ^IInfoQueue, bMute: BOOL), + GetMuteDebugOutput: proc "stdcall" (this: ^IInfoQueue) -> BOOL, +} + +PFN_CREATE_DEVICE :: #type proc "c" (a0: ^IUnknown, a1: FEATURE_LEVEL, a2: ^IID, a3: ^rawptr) -> HRESULT +PFN_GET_DEBUG_INTERFACE :: #type proc "c" (a0: ^IID, a1: ^rawptr) -> HRESULT + +AXIS_SHADING_RATE :: enum i32 { + _1X = 0, + _2X = 1, + _4X = 2, +} + +SHADING_RATE :: enum i32 { + _1X1 = 0, + _1X2 = 1, + _2X1 = 4, + _2X2 = 5, + _2X4 = 6, + _4X2 = 9, + _4X4 = 10, +} + +SHADING_RATE_COMBINER :: enum i32 { + PASSTHROUGH = 0, + OVERRIDE = 1, + MIN = 2, + MAX = 3, + SUM = 4, +} + + +IGraphicsCommandList5_UUID :: "55050859-4024-474c-87f5-6472eaee44ea" +IGraphicsCommandList5 :: struct #raw_union { + #subtype id3d12graphicscommandlist4: IGraphicsCommandList4, + using id3d12graphicscommandlist5_vtable: ^IGraphicsCommandList5_VTable, +} +IGraphicsCommandList5_VTable :: struct { + using id3d12graphicscommandlist4_vtable: IGraphicsCommandList4_VTable, + RSSetShadingRate: proc "stdcall" (this: ^IGraphicsCommandList5, baseShadingRate: SHADING_RATE, combiners: ^SHADING_RATE_COMBINER), + RSSetShadingRateImage: proc "stdcall" (this: ^IGraphicsCommandList5, shadingRateImage: ^IResource), +} + +DISPATCH_MESH_ARGUMENTS :: struct { + ThreadGroupCountX: u32, + ThreadGroupCountY: u32, + ThreadGroupCountZ: u32, +} + + +IGraphicsCommandList6_UUID :: "c3827890-e548-4cfa-96cf-5689a9370f80" +IGraphicsCommandList6 :: struct #raw_union { + #subtype id3d12graphicscommandlist5: IGraphicsCommandList5, + using id3d12graphicscommandlist6_vtable: ^IGraphicsCommandList6_VTable, +} +IGraphicsCommandList6_VTable :: struct { + using id3d12graphicscommandlist5_vtable: IGraphicsCommandList5_VTable, + DispatchMesh: proc "stdcall" (this: ^IGraphicsCommandList6, ThreadGroupCountX: u32, ThreadGroupCountY: u32, ThreadGroupCountZ: u32), +} + +SHADER_VERSION_TYPE :: enum i32 { + PIXEL_SHADER = 0, + VERTEX_SHADER = 1, + GEOMETRY_SHADER = 2, + + HULL_SHADER = 3, + DOMAIN_SHADER = 4, + COMPUTE_SHADER = 5, + + RESERVED0 = 65520, +} + +SIGNATURE_PARAMETER_DESC :: struct { + SemanticName: cstring, + SemanticIndex: u32, + Register: u32, + SystemValueType: NAME, + ComponentType: REGISTER_COMPONENT_TYPE, + Mask: u8, + + ReadWriteMask: u8, + + Stream: u32, + MinPrecision: MIN_PRECISION, +} + +SHADER_BUFFER_DESC :: struct { + Name: cstring, + Type: CBUFFER_TYPE, + Variables: u32, + Size: u32, + uFlags: u32, +} + +SHADER_VARIABLE_DESC :: struct { + Name: cstring, + StartOffset: u32, + Size: u32, + uFlags: u32, + DefaultValue: rawptr, + StartTexture: u32, + TextureSize: u32, + StartSampler: u32, + SamplerSize: u32, +} + +SHADER_TYPE_DESC :: struct { + Class: SHADER_VARIABLE_CLASS, + Type: SHADER_VARIABLE_TYPE, + Rows: u32, + Columns: u32, + Elements: u32, + Members: u32, + Offset: u32, + Name: cstring, +} +SHADER_DESC :: struct { + Version: u32, + Creator: cstring, + Flags: u32, + + ConstantBuffers: u32, + BoundResources: u32, + InputParameters: u32, + OutputParameters: u32, + + InstructionCount: u32, + TempRegisterCount: u32, + TempArrayCount: u32, + DefCount: u32, + DclCount: u32, + TextureNormalInstructions: u32, + TextureLoadInstructions: u32, + TextureCompInstructions: u32, + TextureBiasInstructions: u32, + TextureGradientInstructions: u32, + FloatInstructionCount: u32, + IntInstructionCount: u32, + UintInstructionCount: u32, + StaticFlowControlCount: u32, + DynamicFlowControlCount: u32, + MacroInstructionCount: u32, + ArrayInstructionCount: u32, + CutInstructionCount: u32, + EmitInstructionCount: u32, + GSOutputTopology: PRIMITIVE_TOPOLOGY, + GSMaxOutputVertexCount: u32, + InputPrimitive: PRIMITIVE, + PatchConstantParameters: u32, + cGSInstanceCount: u32, + cControlPoints: u32, + HSOutputPrimitive: TESSELLATOR_OUTPUT_PRIMITIVE, + HSPartitioning: TESSELLATOR_PARTITIONING, + TessellatorDomain: TESSELLATOR_DOMAIN, + + cBarrierInstructions: u32, + cInterlockedInstructions: u32, + cTextureStoreInstructions: u32, +} + +SHADER_INPUT_BIND_DESC :: struct { + Name: cstring, + Type: SHADER_INPUT_TYPE, + BindPoint: u32, + BindCount: u32, + + uFlags: u32, + ReturnType: RESOURCE_RETURN_TYPE, + Dimension: SRV_DIMENSION, + NumSamples: u32, + Space: u32, + uID: u32, +} + +LIBRARY_DESC :: struct { + Creator: cstring, + Flags: u32, + FunctionCount: u32, +} + +FUNCTION_DESC :: struct { + Version: u32, + Creator: cstring, + Flags: u32, + + ConstantBuffers: u32, + BoundResources: u32, + + InstructionCount: u32, + TempRegisterCount: u32, + TempArrayCount: u32, + DefCount: u32, + DclCount: u32, + TextureNormalInstructions: u32, + TextureLoadInstructions: u32, + TextureCompInstructions: u32, + TextureBiasInstructions: u32, + TextureGradientInstructions: u32, + FloatInstructionCount: u32, + IntInstructionCount: u32, + UintInstructionCount: u32, + StaticFlowControlCount: u32, + DynamicFlowControlCount: u32, + MacroInstructionCount: u32, + ArrayInstructionCount: u32, + MovInstructionCount: u32, + MovcInstructionCount: u32, + ConversionInstructionCount: u32, + BitwiseInstructionCount: u32, + MinFeatureLevel: FEATURE_LEVEL, + RequiredFeatureFlags: u64, + + Name: cstring, + FunctionParameterCount: i32, + HasReturn: BOOL, + Has10Level9VertexShader: BOOL, + Has10Level9PixelShader: BOOL, +} + +PARAMETER_DESC :: struct { + Name: cstring, + SemanticName: cstring, + Type: SHADER_VARIABLE_TYPE, + Class: SHADER_VARIABLE_CLASS, + Rows: u32, + Columns: u32, + InterpolationMode: INTERPOLATION_MODE, + Flags: PARAMETER_FLAGS, + + FirstInRegister: u32, + FirstInComponent: u32, + FirstOutRegister: u32, + FirstOutComponent: u32, +} + +IShaderReflectionType :: struct { + vtable: ^IShaderReflectionType_VTable, +} +IShaderReflectionType_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IShaderReflectionType, pDesc: ^SHADER_TYPE_DESC) -> HRESULT, + GetMemberTypeByIndex: proc "stdcall" (this: ^IShaderReflectionType, Index: u32) -> ^IShaderReflectionType, + GetMemberTypeByName: proc "stdcall" (this: ^IShaderReflectionType, Name: cstring) -> ^IShaderReflectionType, + GetMemberTypeName: proc "stdcall" (this: ^IShaderReflectionType, Index: u32) -> cstring, + IsEqual: proc "stdcall" (this: ^IShaderReflectionType, pType: ^IShaderReflectionType) -> HRESULT, + GetSubType: proc "stdcall" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, + GetBaseClass: proc "stdcall" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, + GetNumInterfaces: proc "stdcall" (this: ^IShaderReflectionType) -> u32, + GetInterfaceByIndex: proc "stdcall" (this: ^IShaderReflectionType, uIndex: u32) -> ^IShaderReflectionType, + IsOfType: proc "stdcall" (this: ^IShaderReflectionType, pType: ^IShaderReflectionType) -> HRESULT, + ImplementsInterface: proc "stdcall" (this: ^IShaderReflectionType, pBase: ^IShaderReflectionType) -> HRESULT, +} + +IShaderReflectionVariable :: struct { + vtable: ^IShaderReflectionVariable_VTable, +} +IShaderReflectionVariable_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IShaderReflectionVariable, pDesc: ^SHADER_VARIABLE_DESC) -> HRESULT, + GetType: proc "stdcall" (this: ^IShaderReflectionVariable) -> ^IShaderReflectionType, + GetBuffer: proc "stdcall" (this: ^IShaderReflectionVariable) -> ^IShaderReflectionConstantBuffer, + GetInterfaceSlot: proc "stdcall" (this: ^IShaderReflectionVariable, uArrayIndex: u32) -> u32, +} + +IShaderReflectionConstantBuffer :: struct { + vtable: ^IShaderReflectionConstantBuffer_VTable, +} +IShaderReflectionConstantBuffer_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, pDesc: ^SHADER_BUFFER_DESC) -> HRESULT, + GetVariableByIndex: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, Index: u32) -> ^IShaderReflectionVariable, + GetVariableByName: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, Name: cstring) -> ^IShaderReflectionVariable, +} + +IShaderReflection :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12shaderreflection_vtable: ^IShaderReflection_VTable, +} +IShaderReflection_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetDesc: proc "stdcall" (this: ^IShaderReflection, pDesc: ^SHADER_DESC) -> HRESULT, + GetConstantBufferByIndex: proc "stdcall" (this: ^IShaderReflection, Index: u32) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "stdcall" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetResourceBindingDesc: proc "stdcall" (this: ^IShaderReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetInputParameterDesc: proc "stdcall" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, + GetOutputParameterDesc: proc "stdcall" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, + GetPatchConstantParameterDesc: proc "stdcall" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, + GetVariableByName: proc "stdcall" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "stdcall" (this: ^IShaderReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetMovInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetMovcInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetConversionInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetBitwiseInstructionCount: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetGSInputPrimitive: proc "stdcall" (this: ^IShaderReflection) -> PRIMITIVE, + IsSampleFrequencyShader: proc "stdcall" (this: ^IShaderReflection) -> BOOL, + GetNumInterfaceSlots: proc "stdcall" (this: ^IShaderReflection) -> u32, + GetMinFeatureLevel: proc "stdcall" (this: ^IShaderReflection, pLevel: ^FEATURE_LEVEL) -> HRESULT, + GetThreadGroupSize: proc "stdcall" (this: ^IShaderReflection, pSizeX: ^u32, pSizeY: ^u32, pSizeZ: ^u32) -> u32, + GetRequiresFlags: proc "stdcall" (this: ^IShaderReflection) -> u64, +} + +ILibraryReflection :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d12libraryreflection_vtable: ^ILibraryReflection_VTable, +} +ILibraryReflection_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetDesc: proc "stdcall" (this: ^ILibraryReflection, pDesc: ^LIBRARY_DESC) -> HRESULT, + GetFunctionByIndex: proc "stdcall" (this: ^ILibraryReflection, FunctionIndex: i32) -> ^IFunctionReflection, +} + +IFunctionReflection :: struct { + vtable: ^IFunctionReflection_VTable, +} +IFunctionReflection_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IFunctionReflection, pDesc: ^FUNCTION_DESC) -> HRESULT, + GetConstantBufferByIndex: proc "stdcall" (this: ^IFunctionReflection, BufferIndex: u32) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "stdcall" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetResourceBindingDesc: proc "stdcall" (this: ^IFunctionReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetVariableByName: proc "stdcall" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "stdcall" (this: ^IFunctionReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetFunctionParameter: proc "stdcall" (this: ^IFunctionReflection, ParameterIndex: i32) -> ^IFunctionParameterReflection, +} + +IFunctionParameterReflection :: struct { + vtable: ^IFunctionParameterReflection_VTable, +} +IFunctionParameterReflection_VTable :: struct { + GetDesc: proc "stdcall" (this: ^IFunctionParameterReflection, pDesc: ^PARAMETER_DESC) -> HRESULT, +} diff --git a/vendor/directx/d3d12/d3d12_constants.odin b/vendor/directx/d3d12/d3d12_constants.odin new file mode 100644 index 000000000..0fbda6b6a --- /dev/null +++ b/vendor/directx/d3d12/d3d12_constants.odin @@ -0,0 +1,531 @@ +package directx_d3d12 + +D3D_FL9_1_REQ_TEXTURE1D_U_DIMENSION :: 2048 +D3D_FL9_3_REQ_TEXTURE1D_U_DIMENSION :: 4096 +D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 2048 +D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 4096 +D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION :: 512 +D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION :: 4096 +D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 256 +D3D_FL9_1_DEFAULT_MAX_ANISOTROPY :: 2 +D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT :: 65535 +D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT :: 1048575 +D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT :: 1 +D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT :: 4 +D3D_FL9_1_MAX_TEXTURE_REPEAT :: 128 +D3D_FL9_2_MAX_TEXTURE_REPEAT :: 2048 +D3D_FL9_3_MAX_TEXTURE_REPEAT :: 8192 + +D3D_COMPONENT_MASK_X :: 1 +D3D_COMPONENT_MASK_Y :: 2 +D3D_COMPONENT_MASK_Z :: 4 +D3D_COMPONENT_MASK_W :: 8 + +D3D12_16BIT_INDEX_STRIP_CUT_VALUE :: 0xffff +D3D12_32BIT_INDEX_STRIP_CUT_VALUE :: 0xffffffff +D3D12_8BIT_INDEX_STRIP_CUT_VALUE :: 0xff + +D3D12_APPEND_ALIGNED_ELEMENT :: 0xffffffff +D3D12_ARRAY_AXIS_ADDRESS_RANGE_BIT_COUNT :: 9 + +D3D12_CLIP_OR_CULL_DISTANCE_COUNT :: 8 +D3D12_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT :: 2 + +D3D12_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT :: 14 +D3D12_COMMONSHADER_CONSTANT_BUFFER_COMPONENTS :: 4 +D3D12_COMMONSHADER_CONSTANT_BUFFER_COMPONENT_BIT_COUNT :: 32 +D3D12_COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT :: 15 +D3D12_COMMONSHADER_CONSTANT_BUFFER_PARTIAL_UPDATE_EXTENTS_BYTE_ALIGNMENT :: 16 +D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 +D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT :: 15 +D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 +D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 +D3D12_COMMONSHADER_FLOWCONTROL_NESTING_LIMIT :: 64 +D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 +D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COUNT :: 1 +D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 +D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 +D3D12_COMMONSHADER_IMMEDIATE_VALUE_COMPONENT_BIT_COUNT :: 32 +D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_COMPONENTS :: 1 +D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT :: 128 +D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_READS_PER_INST :: 1 +D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_READ_PORTS :: 1 +D3D12_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT :: 128 +D3D12_COMMONSHADER_SAMPLER_REGISTER_COMPONENTS :: 1 +D3D12_COMMONSHADER_SAMPLER_REGISTER_COUNT :: 16 +D3D12_COMMONSHADER_SAMPLER_REGISTER_READS_PER_INST :: 1 +D3D12_COMMONSHADER_SAMPLER_REGISTER_READ_PORTS :: 1 +D3D12_COMMONSHADER_SAMPLER_SLOT_COUNT :: 16 +D3D12_COMMONSHADER_SUBROUTINE_NESTING_LIMIT :: 32 +D3D12_COMMONSHADER_TEMP_REGISTER_COMPONENTS :: 4 +D3D12_COMMONSHADER_TEMP_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_COMMONSHADER_TEMP_REGISTER_COUNT :: 4096 +D3D12_COMMONSHADER_TEMP_REGISTER_READS_PER_INST :: 3 +D3D12_COMMONSHADER_TEMP_REGISTER_READ_PORTS :: 3 +D3D12_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MAX :: 10 +D3D12_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MIN :: -10 +D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE :: -8 +D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE :: 7 + +D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT :: 256 + +D3D12_CS_4_X_BUCKET00_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 256 +D3D12_CS_4_X_BUCKET00_MAX_NUM_THREADS_PER_GROUP :: 64 +D3D12_CS_4_X_BUCKET01_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 240 +D3D12_CS_4_X_BUCKET01_MAX_NUM_THREADS_PER_GROUP :: 68 +D3D12_CS_4_X_BUCKET02_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 224 +D3D12_CS_4_X_BUCKET02_MAX_NUM_THREADS_PER_GROUP :: 72 +D3D12_CS_4_X_BUCKET03_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 208 +D3D12_CS_4_X_BUCKET03_MAX_NUM_THREADS_PER_GROUP :: 76 +D3D12_CS_4_X_BUCKET04_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 192 +D3D12_CS_4_X_BUCKET04_MAX_NUM_THREADS_PER_GROUP :: 84 +D3D12_CS_4_X_BUCKET05_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 176 +D3D12_CS_4_X_BUCKET05_MAX_NUM_THREADS_PER_GROUP :: 92 +D3D12_CS_4_X_BUCKET06_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 160 +D3D12_CS_4_X_BUCKET06_MAX_NUM_THREADS_PER_GROUP :: 100 +D3D12_CS_4_X_BUCKET07_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 144 +D3D12_CS_4_X_BUCKET07_MAX_NUM_THREADS_PER_GROUP :: 112 +D3D12_CS_4_X_BUCKET08_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 128 +D3D12_CS_4_X_BUCKET08_MAX_NUM_THREADS_PER_GROUP :: 128 +D3D12_CS_4_X_BUCKET09_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 112 +D3D12_CS_4_X_BUCKET09_MAX_NUM_THREADS_PER_GROUP :: 144 +D3D12_CS_4_X_BUCKET10_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 96 +D3D12_CS_4_X_BUCKET10_MAX_NUM_THREADS_PER_GROUP :: 168 +D3D12_CS_4_X_BUCKET11_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 80 +D3D12_CS_4_X_BUCKET11_MAX_NUM_THREADS_PER_GROUP :: 204 +D3D12_CS_4_X_BUCKET12_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 64 +D3D12_CS_4_X_BUCKET12_MAX_NUM_THREADS_PER_GROUP :: 256 +D3D12_CS_4_X_BUCKET13_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 48 +D3D12_CS_4_X_BUCKET13_MAX_NUM_THREADS_PER_GROUP :: 340 +D3D12_CS_4_X_BUCKET14_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 32 +D3D12_CS_4_X_BUCKET14_MAX_NUM_THREADS_PER_GROUP :: 512 +D3D12_CS_4_X_BUCKET15_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 16 +D3D12_CS_4_X_BUCKET15_MAX_NUM_THREADS_PER_GROUP :: 768 +D3D12_CS_4_X_DISPATCH_MAX_THREAD_GROUPS_IN_Z_DIMENSION :: 1 +D3D12_CS_4_X_RAW_UAV_BYTE_ALIGNMENT :: 256 +D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 768 +D3D12_CS_4_X_THREAD_GROUP_MAX_X :: 768 +D3D12_CS_4_X_THREAD_GROUP_MAX_Y :: 768 +D3D12_CS_4_X_UAV_REGISTER_COUNT :: 1 + +D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION :: 65535 +D3D12_CS_TGSM_REGISTER_COUNT :: 8192 +D3D12_CS_TGSM_REGISTER_READS_PER_INST :: 1 +D3D12_CS_TGSM_RESOURCE_REGISTER_COMPONENTS :: 1 +D3D12_CS_TGSM_RESOURCE_REGISTER_READ_PORTS :: 1 +D3D12_CS_THREADGROUPID_REGISTER_COMPONENTS :: 3 +D3D12_CS_THREADGROUPID_REGISTER_COUNT :: 1 +D3D12_CS_THREADIDINGROUPFLATTENED_REGISTER_COMPONENTS :: 1 +D3D12_CS_THREADIDINGROUPFLATTENED_REGISTER_COUNT :: 1 +D3D12_CS_THREADIDINGROUP_REGISTER_COMPONENTS :: 3 +D3D12_CS_THREADIDINGROUP_REGISTER_COUNT :: 1 +D3D12_CS_THREADID_REGISTER_COMPONENTS :: 3 +D3D12_CS_THREADID_REGISTER_COUNT :: 1 +D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 1024 +D3D12_CS_THREAD_GROUP_MAX_X :: 1024 +D3D12_CS_THREAD_GROUP_MAX_Y :: 1024 +D3D12_CS_THREAD_GROUP_MAX_Z :: 64 +D3D12_CS_THREAD_GROUP_MIN_X :: 1 +D3D12_CS_THREAD_GROUP_MIN_Y :: 1 +D3D12_CS_THREAD_GROUP_MIN_Z :: 1 +D3D12_CS_THREAD_LOCAL_TEMP_REGISTER_POOL :: 16384 + +D3D12_DEFAULT_BLEND_FACTOR_ALPHA :: 1.0 +D3D12_DEFAULT_BLEND_FACTOR_BLUE :: 1.0 +D3D12_DEFAULT_BLEND_FACTOR_GREEN :: 1.0 +D3D12_DEFAULT_BLEND_FACTOR_RED :: 1.0 +D3D12_DEFAULT_BORDER_COLOR_COMPONENT :: 0.0 +D3D12_DEFAULT_DEPTH_BIAS :: 0 +D3D12_DEFAULT_DEPTH_BIAS_CLAMP :: 0.0 +D3D12_DEFAULT_MAX_ANISOTROPY :: 16 +D3D12_DEFAULT_MIP_LOD_BIAS :: 0.0 +D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 4194304 +D3D12_DEFAULT_RENDER_TARGET_ARRAY_INDEX :: 0 + +D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT :: 65536 +D3D12_DEFAULT_SAMPLE_MASK :: 0xffffffff +D3D12_DEFAULT_SCISSOR_ENDX :: 0 +D3D12_DEFAULT_SCISSOR_ENDY :: 0 +D3D12_DEFAULT_SCISSOR_STARTX :: 0 +D3D12_DEFAULT_SCISSOR_STARTY :: 0 +D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS :: 0.0 +D3D12_DEFAULT_STENCIL_READ_MASK :: 0xff +D3D12_DEFAULT_STENCIL_REFERENCE :: 0 +D3D12_DEFAULT_STENCIL_WRITE_MASK :: 0xff +D3D12_DEFAULT_VIEWPORT_AND_SCISSORRECT_INDEX :: 0 +D3D12_DEFAULT_VIEWPORT_HEIGHT :: 0 +D3D12_DEFAULT_VIEWPORT_MAX_DEPTH :: 0.0 +D3D12_DEFAULT_VIEWPORT_MIN_DEPTH :: 0.0 +D3D12_DEFAULT_VIEWPORT_TOPLEFTX :: 0 +D3D12_DEFAULT_VIEWPORT_TOPLEFTY :: 0 +D3D12_DEFAULT_VIEWPORT_WIDTH :: 0 + +D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND :: 0xffffffff + +D3D12_DRIVER_RESERVED_REGISTER_SPACE_VALUES_END :: 0xfffffff7 +D3D12_DRIVER_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0 + +D3D12_DS_INPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 +D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENTS :: 4 +D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COUNT :: 32 +D3D12_DS_INPUT_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 +D3D12_DS_INPUT_CONTROL_POINT_REGISTER_READ_PORTS :: 1 +D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENTS :: 3 +D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COUNT :: 1 +D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_READS_PER_INST :: 2 +D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_READ_PORTS :: 1 +D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 +D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 +D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 +D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 +D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 +D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 +D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 +D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 +D3D12_DS_OUTPUT_REGISTER_COMPONENTS :: 4 +D3D12_DS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_DS_OUTPUT_REGISTER_COUNT :: 32 + +D3D12_FLOAT16_FUSED_TOLERANCE_IN_ULP :: 0.6 +D3D12_FLOAT32_MAX :: 3.402823466e+38 +D3D12_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP :: 0.6 +D3D12_FLOAT_TO_SRGB_EXPONENT_DENOMINATOR :: 2.4 +D3D12_FLOAT_TO_SRGB_EXPONENT_NUMERATOR :: 1.0 +D3D12_FLOAT_TO_SRGB_OFFSET :: 0.055 +D3D12_FLOAT_TO_SRGB_SCALE_1 :: 12.92 +D3D12_FLOAT_TO_SRGB_SCALE_2 :: 1.055 +D3D12_FLOAT_TO_SRGB_THRESHOLD :: 0.0031308 +D3D12_FTOI_INSTRUCTION_MAX_INPUT :: 2147483647.999 +D3D12_FTOI_INSTRUCTION_MIN_INPUT :: -2147483648.999 +D3D12_FTOU_INSTRUCTION_MAX_INPUT :: 4294967295.999 +D3D12_FTOU_INSTRUCTION_MIN_INPUT :: 0.0 + +D3D12_GS_INPUT_INSTANCE_ID_READS_PER_INST :: 2 +D3D12_GS_INPUT_INSTANCE_ID_READ_PORTS :: 1 +D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COUNT :: 1 +D3D12_GS_INPUT_PRIM_CONST_REGISTER_COMPONENTS :: 1 +D3D12_GS_INPUT_PRIM_CONST_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_GS_INPUT_PRIM_CONST_REGISTER_COUNT :: 1 +D3D12_GS_INPUT_PRIM_CONST_REGISTER_READS_PER_INST :: 2 +D3D12_GS_INPUT_PRIM_CONST_REGISTER_READ_PORTS :: 1 +D3D12_GS_INPUT_REGISTER_COMPONENTS :: 4 +D3D12_GS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_GS_INPUT_REGISTER_COUNT :: 32 +D3D12_GS_INPUT_REGISTER_READS_PER_INST :: 2 +D3D12_GS_INPUT_REGISTER_READ_PORTS :: 1 +D3D12_GS_INPUT_REGISTER_VERTICES :: 32 +D3D12_GS_MAX_INSTANCE_COUNT :: 32 +D3D12_GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES :: 1024 +D3D12_GS_OUTPUT_ELEMENTS :: 32 +D3D12_GS_OUTPUT_REGISTER_COMPONENTS :: 4 +D3D12_GS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_GS_OUTPUT_REGISTER_COUNT :: 32 + +D3D12_HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT :: 32 +D3D12_HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT :: 32 +D3D12_HS_CONTROL_POINT_REGISTER_COMPONENTS :: 4 +D3D12_HS_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_HS_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 +D3D12_HS_CONTROL_POINT_REGISTER_READ_PORTS :: 1 +D3D12_HS_FORK_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff +D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COUNT :: 1 +D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 +D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READ_PORTS :: 1 +D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COUNT :: 1 +D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 +D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READ_PORTS :: 1 +D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 +D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 +D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 +D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 +D3D12_HS_JOIN_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff +D3D12_HS_MAXTESSFACTOR_LOWER_BOUND :: 1.0 +D3D12_HS_MAXTESSFACTOR_UPPER_BOUND :: 64.0 +D3D12_HS_OUTPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 +D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENTS :: 1 +D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COUNT :: 1 +D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READS_PER_INST :: 2 +D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READ_PORTS :: 1 +D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 +D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 +D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 +D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 +D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_SCALAR_COMPONENTS :: 128 + +D3D12_IA_DEFAULT_INDEX_BUFFER_OFFSET_IN_BYTES :: 0 +D3D12_IA_DEFAULT_PRIMITIVE_TOPOLOGY :: 0 +D3D12_IA_DEFAULT_VERTEX_BUFFER_OFFSET_IN_BYTES :: 0 +D3D12_IA_INDEX_INPUT_RESOURCE_SLOT_COUNT :: 1 +D3D12_IA_INSTANCE_ID_BIT_COUNT :: 32 +D3D12_IA_INTEGER_ARITHMETIC_BIT_COUNT :: 32 +D3D12_IA_PATCH_MAX_CONTROL_POINT_COUNT :: 32 +D3D12_IA_PRIMITIVE_ID_BIT_COUNT :: 32 +D3D12_IA_VERTEX_ID_BIT_COUNT :: 32 +D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT :: 32 +D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENTS_COMPONENTS :: 128 +D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT :: 32 + +D3D12_INTEGER_DIVIDE_BY_ZERO_QUOTIENT :: 0xffffffff +D3D12_INTEGER_DIVIDE_BY_ZERO_REMAINDER :: 0xffffffff + +D3D12_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL :: 0xffffffff +D3D12_KEEP_UNORDERED_ACCESS_VIEWS :: 0xffffffff + +D3D12_LINEAR_GAMMA :: 1.0 +D3D12_MAJOR_VERSION :: 12 + +D3D12_MAX_BORDER_COLOR_COMPONENT :: 1.0 +D3D12_MAX_DEPTH :: 1.0 +D3D12_MAX_LIVE_STATIC_SAMPLERS :: 2032 +D3D12_MAX_MAXANISOTROPY :: 16 +D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT :: 32 +D3D12_MAX_POSITION_VALUE :: 3.402823466e+34D3D12_MAX_ROOT_COST :: 64 +D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1 :: 1000000 +D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2 :: 1000000 +D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE :: 2048 +D3D12_MAX_TEXTURE_DIMENSION_2_TO_EXP :: 17 +D3D12_MAX_VIEW_INSTANCE_COUNT :: 4 + +D3D12_MINOR_VERSION :: 0 + +D3D12_MIN_BORDER_COLOR_COMPONENT :: 0.0 +D3D12_MIN_DEPTH :: 0.0 +D3D12_MIN_MAXANISOTROPY :: 0 + +D3D12_MIP_LOD_BIAS_MAX :: 15.99 +D3D12_MIP_LOD_BIAS_MIN :: -16.0 +D3D12_MIP_LOD_FRACTIONAL_BIT_COUNT :: 8 +D3D12_MIP_LOD_RANGE_BIT_COUNT :: 8 + +D3D12_MULTISAMPLE_ANTIALIAS_LINE_WIDTH :: 1.4 +D3D12_NONSAMPLE_FETCH_OUT_OF_RANGE_ACCESS_RESULT :: 0 + +D3D12_OS_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff +D3D12_OS_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff8 + +D3D12_PACKED_TILE :: 0xffffffff + +D3D12_PIXEL_ADDRESS_RANGE_BIT_COUNT :: 15 + +D3D12_PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT :: 16 + +D3D12_PS_CS_UAV_REGISTER_COMPONENTS :: 1 +D3D12_PS_CS_UAV_REGISTER_COUNT :: 8 +D3D12_PS_CS_UAV_REGISTER_READS_PER_INST :: 1 +D3D12_PS_CS_UAV_REGISTER_READ_PORTS :: 1 +D3D12_PS_FRONTFACING_DEFAULT_VALUE :: 0xffffffff +D3D12_PS_FRONTFACING_FALSE_VALUE :: 0 +D3D12_PS_FRONTFACING_TRUE_VALUE :: 0xffffffff +D3D12_PS_INPUT_REGISTER_COMPONENTS :: 4 +D3D12_PS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_PS_INPUT_REGISTER_COUNT :: 32 +D3D12_PS_INPUT_REGISTER_READS_PER_INST :: 2 +D3D12_PS_INPUT_REGISTER_READ_PORTS :: 1 +D3D12_PS_LEGACY_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.0 +D3D12_PS_OUTPUT_DEPTH_REGISTER_COMPONENTS :: 1 +D3D12_PS_OUTPUT_DEPTH_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_PS_OUTPUT_DEPTH_REGISTER_COUNT :: 1 +D3D12_PS_OUTPUT_MASK_REGISTER_COMPONENTS :: 1 +D3D12_PS_OUTPUT_MASK_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_PS_OUTPUT_MASK_REGISTER_COUNT :: 1 +D3D12_PS_OUTPUT_REGISTER_COMPONENTS :: 4 +D3D12_PS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_PS_OUTPUT_REGISTER_COUNT :: 8 +D3D12_PS_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.5 + +D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT :: 16 + +D3D12_RAYTRACING_AABB_BYTE_ALIGNMENT :: 8 +D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT :: 256 +D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT :: 16 +D3D12_RAYTRACING_MAX_ATTRIBUTE_SIZE_IN_BYTES :: 32 +D3D12_RAYTRACING_MAX_DECLARABLE_TRACE_RECURSION_DEPTH :: 31 +D3D12_RAYTRACING_MAX_GEOMETRIES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 16777216 +D3D12_RAYTRACING_MAX_INSTANCES_PER_TOP_LEVEL_ACCELERATION_STRUCTURE :: 16777216 +D3D12_RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 536870912 +D3D12_RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS :: 1073741824 +D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE :: 4096 +D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT :: 32 +D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT :: 64 +D3D12_RAYTRACING_TRANSFORM3X4_BYTE_ALIGNMENT :: 16 + +D3D12_REQ_BLEND_OBJECT_COUNT_PER_DEVICE :: 4096 +D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP :: 27 +D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 +D3D12_REQ_DEPTH_STENCIL_OBJECT_COUNT_PER_DEVICE :: 4096 +D3D12_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 32 +D3D12_REQ_DRAW_VERTEX_COUNT_2_TO_EXP :: 32 +D3D12_REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION :: 16384 +D3D12_REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT :: 1024 +D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 +D3D12_REQ_MAXANISOTROPY :: 16 +D3D12_REQ_MIP_LEVELS :: 15 +D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES :: 2048 +D3D12_REQ_RASTERIZER_OBJECT_COUNT_PER_DEVICE :: 4096 +D3D12_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH :: 16384 +D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM :: 128 +D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_B_TERM :: 0.25 +D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM :: 2048 +D3D12_REQ_RESOURCE_VIEW_COUNT_PER_DEVICE_2_TO_EXP :: 20 +D3D12_REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE :: 4096 +D3D12_REQ_SUBRESOURCES :: 30720 +D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION :: 2048 +D3D12_REQ_TEXTURE1D_U_DIMENSION :: 16384 +D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION :: 2048 +D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 16384 +D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 2048 +D3D12_REQ_TEXTURECUBE_DIMENSION :: 16384 + +D3D12_RESINFO_INSTRUCTION_MISSING_COMPONENT_RETVAL :: 0 + +D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES :: 0xffffffff + +D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT :: 2 + +D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES :: 32 +D3D12_SHADER_MAJOR_VERSION :: 5 +D3D12_SHADER_MAX_INSTANCES :: 65535 +D3D12_SHADER_MAX_INTERFACES :: 253 +D3D12_SHADER_MAX_INTERFACE_CALL_SITES :: 4096 +D3D12_SHADER_MAX_TYPES :: 65535 +D3D12_SHADER_MINOR_VERSION :: 1 + +D3D12_SHIFT_INSTRUCTION_PAD_VALUE :: 0 +D3D12_SHIFT_INSTRUCTION_SHIFT_VALUE_BIT_COUNT :: 5 + +D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT :: 8 + +D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 65536 +D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT :: 4096 + +D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES :: 2048 +D3D12_SO_BUFFER_MAX_WRITE_WINDOW_IN_BYTES :: 512 +D3D12_SO_BUFFER_SLOT_COUNT :: 4 +D3D12_SO_DDI_REGISTER_INDEX_DENOTING_GAP :: 0xffffffff +D3D12_SO_NO_RASTERIZED_STREAM :: 0xffffffff +D3D12_SO_OUTPUT_COMPONENT_COUNT :: 128 +D3D12_SO_STREAM_COUNT :: 4 + +D3D12_SPEC_DATE_DAY :: 14 +D3D12_SPEC_DATE_MONTH :: 11 +D3D12_SPEC_DATE_YEAR :: 2014 +D3D12_SPEC_VERSION :: 1.16 + +D3D12_SRGB_GAMMA :: 2.2 +D3D12_SRGB_TO_FLOAT_DENOMINATOR_1 :: 12.92 +D3D12_SRGB_TO_FLOAT_DENOMINATOR_2 :: 1.055 +D3D12_SRGB_TO_FLOAT_EXPONENT :: 2.4 +D3D12_SRGB_TO_FLOAT_OFFSET :: 0.055 +D3D12_SRGB_TO_FLOAT_THRESHOLD :: 0.04045 +D3D12_SRGB_TO_FLOAT_TOLERANCE_IN_ULP :: 0.5 + +D3D12_STANDARD_COMPONENT_BIT_COUNT :: 32 +D3D12_STANDARD_COMPONENT_BIT_COUNT_DOUBLED :: 64 +D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE :: 4 +D3D12_STANDARD_PIXEL_COMPONENT_COUNT :: 128 +D3D12_STANDARD_PIXEL_ELEMENT_COUNT :: 32 +D3D12_STANDARD_VECTOR_SIZE :: 4 +D3D12_STANDARD_VERTEX_ELEMENT_COUNT :: 32 +D3D12_STANDARD_VERTEX_TOTAL_COMPONENT_COUNT :: 64 + +D3D12_SUBPIXEL_FRACTIONAL_BIT_COUNT :: 8 +D3D12_SUBTEXEL_FRACTIONAL_BIT_COUNT :: 8 + +D3D12_SYSTEM_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff +D3D12_SYSTEM_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0 + +D3D12_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR :: 64 +D3D12_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 64 +D3D12_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR :: 63 +D3D12_TESSELLATOR_MAX_TESSELLATION_FACTOR :: 64 +D3D12_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR :: 2 +D3D12_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 1 +D3D12_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR :: 1 + +D3D12_TEXEL_ADDRESS_RANGE_BIT_COUNT :: 16 + +D3D12_TEXTURE_DATA_PITCH_ALIGNMENT :: 256 +D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT :: 512 + +D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES :: 65536 + +D3D12_TRACKED_WORKLOAD_MAX_INSTANCES :: 32 + +D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT :: 4096 +D3D12_UAV_SLOT_COUNT :: 64 + +D3D12_UNBOUND_MEMORY_ACCESS_RESULT :: 0 + +D3D12_VIDEO_DECODE_MAX_ARGUMENTS :: 10 +D3D12_VIDEO_DECODE_MAX_HISTOGRAM_COMPONENTS :: 4 +D3D12_VIDEO_DECODE_MIN_BITSTREAM_OFFSET_ALIGNMENT :: 256 +D3D12_VIDEO_DECODE_MIN_HISTOGRAM_OFFSET_ALIGNMENT :: 256 +D3D12_VIDEO_DECODE_STATUS_MACROBLOCKS_AFFECTED_UNKNOWN :: 0xffffffff +D3D12_VIDEO_PROCESS_MAX_FILTERS :: 32 +D3D12_VIDEO_PROCESS_STEREO_VIEWS :: 2 + +D3D12_VIEWPORT_AND_SCISSORRECT_MAX_INDEX :: 15 +D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE :: 16 +D3D12_VIEWPORT_BOUNDS_MAX :: 32767 +D3D12_VIEWPORT_BOUNDS_MIN :: -32768 + +D3D12_VS_INPUT_REGISTER_COMPONENTS :: 4 +D3D12_VS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_VS_INPUT_REGISTER_COUNT :: 32 +D3D12_VS_INPUT_REGISTER_READS_PER_INST :: 2 +D3D12_VS_INPUT_REGISTER_READ_PORTS :: 1 +D3D12_VS_OUTPUT_REGISTER_COMPONENTS :: 4 +D3D12_VS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +D3D12_VS_OUTPUT_REGISTER_COUNT :: 32 + +D3D12_WHQL_CONTEXT_COUNT_FOR_RESOURCE_LIMIT :: 10 +D3D12_WHQL_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 25 +D3D12_WHQL_DRAW_VERTEX_COUNT_2_TO_EXP :: 25 + +D3D12_SHADER_COMPONENT_MAPPING_MASK :: 0x7 +D3D12_SHADER_COMPONENT_MAPPING_SHIFT :: 3 + +D3D12_FILTER_REDUCTION_TYPE_MASK :: 0x3 +D3D12_FILTER_REDUCTION_TYPE_SHIFT :: 7 +D3D12_FILTER_TYPE_MASK :: 0x3 + +D3D12_MIN_FILTER_SHIFT :: 4 +D3D12_MAG_FILTER_SHIFT :: 2 +D3D12_MIP_FILTER_SHIFT :: 0 + +D3D12_ANISOTROPIC_FILTERING_BIT :: 0x40 + +D3D12_INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT :: 1024 + +D3D12_SHADING_RATE_X_AXIS_SHIFT :: 2 +D3D12_SHADING_RATE_VALID_MASK :: 3 + +D3D_RETURN_PARAMETER_INDEX :: -1 + +D3D_SHADER_REQUIRES_DOUBLES :: 0x00000001 +D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL :: 0x00000002 +D3D_SHADER_REQUIRES_UAVS_AT_EVERY_STAGE :: 0x00000004 +D3D_SHADER_REQUIRES_64_UAVS :: 0x00000008 +D3D_SHADER_REQUIRES_MINIMUM_PRECISION :: 0x00000010 +D3D_SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS :: 0x00000020 +D3D_SHADER_REQUIRES_11_1_SHADER_EXTENSIONS :: 0x00000040 +D3D_SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING :: 0x00000080 +D3D_SHADER_REQUIRES_TILED_RESOURCES :: 0x00000100 +D3D_SHADER_REQUIRES_STENCIL_REF :: 0x00000200 +D3D_SHADER_REQUIRES_INNER_COVERAGE :: 0x00000400 +D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS :: 0x00000800 +D3D_SHADER_REQUIRES_ROVS :: 0x00001000 +D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER :: 0x00002000 diff --git a/vendor/directx/d3d_compiler/d3d_compiler.odin b/vendor/directx/d3d_compiler/d3d_compiler.odin new file mode 100644 index 000000000..9157e3585 --- /dev/null +++ b/vendor/directx/d3d_compiler/d3d_compiler.odin @@ -0,0 +1,224 @@ +package directx_d3d_compiler + +foreign import d3dcompiler "d3dcompiler_47.lib" + +D3DCOMPILER_DLL_A :: "d3dcompiler_47.dll" +COMPILER_VERSION :: 47 + + +import "../dxgi" + +BOOL :: dxgi.BOOL +IID :: dxgi.IID +SIZE_T :: dxgi.SIZE_T +HRESULT :: dxgi.HRESULT +IUnknown :: dxgi.IUnknown +IUnknown_VTable :: dxgi.IUnknown_VTable + +@(default_calling_convention="stdcall", link_prefix="D3D") +foreign d3dcompiler { + ReadFileToBlob :: proc(pFileName: [^]u16, ppContents: ^^ID3DBlob) -> HRESULT --- + WriteBlobToFile :: proc(pBlob: ^ID3DBlob, pFileName: [^]u16, bOverwrite: BOOL) -> HRESULT --- + Compile :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + Compile2 :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, SecondaryDataFlags: u32, pSecondaryData: rawptr, SecondaryDataSize: SIZE_T, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + CompileFromFile :: proc(pFileName: [^]u16, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + Preprocess :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, ppCodeText: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + GetDebugInfo :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppDebugInfo: ^^ID3DBlob) -> HRESULT --- + Reflect :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pInterface: ^IID, ppReflector: ^rawptr) -> HRESULT --- + ReflectLibrary :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, riid: ^IID, ppReflector: ^rawptr) -> HRESULT --- + Disassemble :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: cstring, ppDisassembly: ^^ID3DBlob) -> HRESULT --- + DisassembleRegion :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: cstring, StartByteOffset: SIZE_T, NumInsts: SIZE_T, pFinishByteOffset: ^SIZE_T, ppDisassembly: ^^ID3DBlob) -> HRESULT --- + CreateLinker :: proc(ppLinker: ^^ID3D11Linker) -> HRESULT --- + LoadModule :: proc(pSrcData: rawptr, cbSrcDataSize: SIZE_T, ppModule: ^^ID3D11Module) -> HRESULT --- + GetTraceInstructionOffsets :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, StartInstIndex: SIZE_T, NumInsts: SIZE_T, pOffsets: ^SIZE_T, pTotalInsts: ^SIZE_T) -> HRESULT --- + GetInputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT --- + GetOutputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT --- + GetInputAndOutputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT --- + StripShader :: proc(pShaderBytecode: rawptr, BytecodeLength: SIZE_T, uStripFlags: u32, ppStrippedBlob: ^^ID3DBlob) -> HRESULT --- + GetBlobPart :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Part: BLOB_PART, Flags: u32, ppPart: ^^ID3DBlob) -> HRESULT --- + SetBlobPart :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Part: BLOB_PART, Flags: u32, pPart: rawptr, PartSize: SIZE_T, ppNewShader: ^^ID3DBlob) -> HRESULT --- + CreateBlob :: proc(Size: SIZE_T, ppBlob: ^^ID3DBlob) -> HRESULT --- + CompressShaders :: proc(uNumShaders: u32, pShaderData: ^SHADER_DATA, uFlags: u32, ppCompressedData: ^^ID3DBlob) -> HRESULT --- + DecompressShaders :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, uNumShaders: u32, uStartIndex: u32, pIndices: ^u32, uFlags: u32, ppShaders: ^^ID3DBlob, pTotalShaders: ^u32) -> HRESULT --- + Disassemble10Effect :: proc(pEffect: ^ID3D10Effect, Flags: u32, ppDisassembly: ^^ID3DBlob) -> HRESULT --- +} + + + +D3DCOMPILE :: enum u32 { // TODO: make bit_field + DEBUG = 1 << 0, + SKIP_VALIDATION = 1 << 1, + SKIP_OPTIMIZATION = 1 << 2, + PACK_MATRIX_ROW_MAJOR = 1 << 3, + PACK_MATRIX_COLUMN_MAJOR = 1 << 4, + PARTIAL_PRECISION = 1 << 5, + FORCE_VS_SOFTWARE_NO_OPT = 1 << 6, + FORCE_PS_SOFTWARE_NO_OPT = 1 << 7, + NO_PRESHADER = 1 << 8, + AVOID_FLOW_CONTROL = 1 << 9, + PREFER_FLOW_CONTROL = 1 << 10, + ENABLE_STRICTNESS = 1 << 11, + ENABLE_BACKWARDS_COMPATIBILITY = 1 << 12, + IEEE_STRICTNESS = 1 << 13, + OPTIMIZATION_LEVEL0 = 1 << 14, + OPTIMIZATION_LEVEL1 = 0, + OPTIMIZATION_LEVEL2 = (1 << 14)|(1 << 15), // Added manually + OPTIMIZATION_LEVEL3 = 1 << 15, + RESERVED16 = 1 << 16, + RESERVED17 = 1 << 17, + WARNINGS_ARE_ERRORS = 1 << 18, + RESOURCES_MAY_ALIAS = 1 << 19, + ENABLE_UNBOUNDED_DESCRIPTOR_TABLES = 1 << 20, + ALL_RESOURCES_BOUND = 1 << 21, + DEBUG_NAME_FOR_SOURCE = 1 << 22, + DEBUG_NAME_FOR_BINARY = 1 << 23, +} + +EFFECT :: enum u32 { // TODO: make bit_field + CHILD_EFFECT = 1 << 0, + ALLOW_SLOW_OPS = 1 << 1, +} + +FLAGS2 :: enum u32 { // TODO: make bit_field + FORCE_ROOT_SIGNATURE_LATEST = 0, + FORCE_ROOT_SIGNATURE_1_0 = 1 << 4, + FORCE_ROOT_SIGNATURE_1_1 = 1 << 5, +} + +SECDATA :: enum u32 { // TODO: make bit_field + MERGE_UAV_SLOTS = 0x00000001, + PRESERVE_TEMPLATE_SLOTS = 0x00000002, + REQUIRE_TEMPLATE_MATCH = 0x00000004, +} + +DISASM_ENABLE_COLOR_CODE :: 0x00000001 +DISASM_ENABLE_DEFAULT_VALUE_PRINTS :: 0x00000002 +DISASM_ENABLE_INSTRUCTION_NUMBERING :: 0x00000004 +DISASM_ENABLE_INSTRUCTION_CYCLE :: 0x00000008 +DISASM_DISABLE_DEBUG_INFO :: 0x00000010 +DISASM_ENABLE_INSTRUCTION_OFFSET :: 0x00000020 +DISASM_INSTRUCTION_ONLY :: 0x00000040 +DISASM_PRINT_HEX_LITERALS :: 0x00000080 + +GET_INST_OFFSETS_INCLUDE_NON_EXECUTABLE :: 0x00000001 + +COMPRESS_SHADER_KEEP_ALL_PARTS :: 0x00000001 + +SHADER_MACRO :: struct { + Name: cstring, + Definition: cstring, +} + +ID3D10Blob :: struct { + #subtype iunknown: IUnknown, + using id3d10blob_vtable: ^ID3D10Blob_VTable, +} +ID3D10Blob_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetBufferPointer: proc "stdcall" (this: ^ID3D10Blob), + GetBufferSize: proc "stdcall" (this: ^ID3D10Blob) -> SIZE_T, +} + + +ID3DBlob :: ID3D10Blob + +INCLUDE_TYPE :: enum i32 { + INCLUDE_LOCAL = 0, + INCLUDE_SYSTEM = 1, + _10_INCLUDE_LOCAL = 0, + _10_INCLUDE_SYSTEM = 1, + INCLUDE_FORCE_DWORD = 2147483647, +} + +ID3DInclude :: struct { + vtable: ^ID3DInclude_VTable, +} +ID3DInclude_VTable :: struct { + Open: proc "stdcall" (this: ^ID3DInclude, IncludeType: INCLUDE_TYPE, pFileName: cstring, pParentData: rawptr, ppData: ^rawptr, pBytes: ^u32) -> HRESULT, + Close: proc "stdcall" (this: ^ID3DInclude, pData: rawptr) -> HRESULT, +} + + +ID3D11Module :: struct { + #subtype iunknown: IUnknown, + using id3d11module_vtable: ^ID3D11Module_VTable, +} +ID3D11Module_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + CreateInstance: proc "stdcall" (this: ^ID3D11Module, pNamespace: cstring, ppModuleInstance: ^^ID3D11ModuleInstance) -> HRESULT, +} + + +ID3D11ModuleInstance :: struct { + #subtype iunknown: IUnknown, + using id3d11moduleinstance_vtable: ^ID3D11ModuleInstance_VTable, +} +ID3D11ModuleInstance_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + BindConstantBuffer: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, cbDstOffset: u32) -> HRESULT, + BindConstantBufferByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, cbDstOffset: u32) -> HRESULT, + BindResource: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, + BindResourceByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT, + BindSampler: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, + BindSamplerByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT, + BindUnorderedAccessView: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, + BindUnorderedAccessViewByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT, + BindResourceAsUnorderedAccessView: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSrvSlot: u32, uDstUavSlot: u32, uCount: u32) -> HRESULT, + BindResourceAsUnorderedAccessViewByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pSrvName: cstring, uDstUavSlot: u32, uCount: u32) -> HRESULT, +} + + +ID3D11Linker :: struct { + #subtype iunknown: IUnknown, + using id3d11linker_vtable: ^ID3D11Linker_VTable, +} +ID3D11Linker_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Link: proc "stdcall" (this: ^ID3D11Linker, pEntry: ^ID3D11ModuleInstance, pEntryName: cstring, pTargetName: cstring, uFlags: u32, ppShaderBlob: ^^ID3DBlob, ppErrorBuffer: ^^ID3DBlob) -> HRESULT, + UseLibrary: proc "stdcall" (this: ^ID3D11Linker, pLibraryMI: ^ID3D11ModuleInstance) -> HRESULT, + AddClipPlaneFromCBuffer: proc "stdcall" (this: ^ID3D11Linker, uCBufferSlot: u32, uCBufferEntry: u32) -> HRESULT, +} + + +pD3DCompile :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: cstring, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: cstring, a6: cstring, a7: u32, a8: u32, a9: ^^ID3DBlob, a10: ^^ID3DBlob) -> HRESULT +pD3DPreprocess :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: cstring, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: ^^ID3DBlob, a6: ^^ID3DBlob) -> HRESULT +pD3DDisassemble :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: u32, a3: cstring, a4: ^^ID3DBlob) -> HRESULT + +D3DCOMPILER_STRIP_FLAGS :: enum u32 { // TODO: make bit_field + REFLECTION_DATA = 0x1, + DEBUG_INFO = 0x2, + TEST_BLOBS = 0x4, + PRIVATE_DATA = 0x8, + ROOT_SIGNATURE = 0x10, + FORCE_DWORD = 0x7fffffff, +} + +BLOB_PART :: enum i32 { + INPUT_SIGNATURE_BLOB = 0, + OUTPUT_SIGNATURE_BLOB = 1, + INPUT_AND_OUTPUT_SIGNATURE_BLOB = 2, + PATCH_CONSTANT_SIGNATURE_BLOB = 3, + ALL_SIGNATURE_BLOB = 4, + DEBUG_INFO = 5, + LEGACY_SHADER = 6, + XNA_PREPASS_SHADER = 7, + XNA_SHADER = 8, + PDB = 9, + PRIVATE_DATA = 10, + ROOT_SIGNATURE = 11, + DEBUG_NAME = 12, + + TEST_ALTERNATE_SHADER = 32768, + TEST_COMPILE_DETAILS = 32769, + TEST_COMPILE_PERF = 32770, + TEST_COMPILE_REPORT = 32771, +} + +SHADER_DATA :: struct { + pBytecode: rawptr, + BytecodeLength: SIZE_T, +} + +ID3D10Effect :: struct { + // ???? +} diff --git a/vendor/directx/d3d_compiler/d3dcompiler_47.dll b/vendor/directx/d3d_compiler/d3dcompiler_47.dll new file mode 100644 index 0000000000000000000000000000000000000000..d30a176525c1cd465d90d4b6d43a8b5756505592 GIT binary patch literal 4410176 zcmd?Sd3+Pq_y30~fWti!}BK5T6; zL^5j*vVq%!4ThSq(p8OQ^mo1o%iN4MR^;<23(slDd0fAx!p*&=9#1vQK*6Y|QVnB? zWA0%vQz1oL3>O>VMz!HifjgszVQdbJ$5Rab;rw5J*Y_kEZVI02-b6!2g_44YW^L~n zH^Tw@V-F+Eq#LE3?l1gB8w{h`XN?{07;P{d`XmB6BFtKt?O_UkX85${!3;^QkXzSN z4Tfb1@I6f7&ulOhwx7xavNR&ChA5ggV;s>2b`wY#0{x)$U-$8{!kcY|!%{2Ys547*`ANG%L$9@&`Y-7hOUw;18E zxQJ2rp<2lvvr%?k4su?x zIsZ;`6~?6J?{~gKcjkY{o;cYP5n-?xyrwU|Mc#TMk{;>=efPwbPG8d6;0x#vKUntI zW1_vL3ka=PV`ALKYcH88!eC$-4`tYKGc{7#JrPBN(lk?PM60!x)`o|}5cMrntYg-~I-jnjThHIQ$J*BrK^9sotg=O79pl*c&rcA_EEo$@>davO)h@btZ} zZh56Oi$lcb9V!#80uhLGAc~9$5K=j5IvP8`4RA*o>I4DTA)zwPq{mfbxKIeGG@z6b z)=ehZGu_4@*gf)HwUI!K2uSj8zxtC51>5~g3Lb}$Izyj=N8pBnB{0+jZhv}PkEpER z20iYdJB0ff!s-IbZsfv}Oh1;`F%D4A&4s8t{BsSC8ZB6Yezu z_jEv7?_BVg#P(V|t@lahF}9|(CY~pU+js$n=Sib#5om`eR8H$bfd)c-rrZ_?!v*CE z;Ldc%Z-k-VSm00V_W>2}Jps23LmHwbt{|DmxWAkV!bJ|ZF%O0(Jw#n4(3ZtlR&KID z17RZwMaJO}))tg|25#JC2n={ zf9sFqXiW0;x75q7%@=#we*^l&$e(q2vHvEOzV~dZAsBk24jJITN$bS!K}?-ke=vPo z&j{$m&LNa9cXv=XQDiKENb9#(;09>X$0(57xQmE=!_;7b_~di?d~h2-7lt$BkgPi4ao1?JNHA9QQoo#u5(mfQsUOb7*B1)AY_1s8k7g#sZAcnCZ5q6J!UyTs7oL8ws(+a86q}NdyICL-uM&> z+(>UI47G)Tdo!T>D8*9BS0FoRyeTsN2oVj`pzr<@b1`?blaOS(o1LPt?q=V^@bonn z8IQq2?F_mfXCYEfz);uC^XJIdtt;oqCIs=_5OX(_;qlclW>s&ZbJZWh#pr9ICn}qgua@T#!9i8T7bM8SdK2R0EB}KJCijMqhLVhT2BJH3>-QF$58c;RS{( zgisuOw{qMz!kwP$Pi)fw+)6zzf#F_T%l`E&)Pu-0i?|9SK+VvOlpUv6V~Kq{qF?aG?;2L#~12f(ZAX zfIAw1`~8HjC{lrQC!T@Om(WwNqg20#p*|&`wvDN**>`$WDAVjS2^wua#nKOtPO zfSVtn*&;n|ZyC+;=0fPxY!*k&Ce+3`{yb9xP^0yzH-IWKW4Y0E;1&ho zI_Ysk8LlOS4Fy~?hD&KqxJClb6MzfR;UW&1Fx>G~Jk3grDd2dU=3P%eMw7y zwzT|awmAG513K@Yuz}@kb=vTE2qJCx+jf}^e@7^g+qeS;4SyrSq&T#++#OxH#6J~? z=uW=|qR6-mLUH(80yl<(r7+Y;0e3Q{GVUb-rws=aAfmw!^hHd;lt~oGZ5#muh26+Er$N{nuXD}qq0@4Go}58>ttxCAV+^tey;xFHO;3_`KKFJZXErG)D! z;8w*|#=WG+J;ZR&Lnv1DaU7RPxC_($iH!|NY#%-D3TusBArz~6XO4TEaBm2>)&aPt zdfc}RR|`UMZdje;!U)$xz*P@O>{X$!&^oho5YfyK1w93H)V}i+$Zb3ZgF3Unruoxr z3?P0d5P|3hgga#&guZ6|8SH@m2Zp*vK-CODE!LxgSX$>oC{7P&aolXe4H9s)9@E#8 z(R$p0QZ~LqC{7RU9G6bGFv5xbVy^&Zyq-DvcVae$P@E%1F=it5%jyOvF=;f^I&8`@7847PvQ_Olk1GhqESewDDW3xsNXs&WvL^eIrr8x>oH~* z2-yhhHg<(|6W{hTc7`1r@#+Y|YFcIm5To?O8jM&SLbk?q8^ef5%@G>_p^O-&h6_Y< zAAP#DBD(OWKRYq;s99SpqEbvB0?J3fzrHS8EUBnodcND(`idXTb`gt=4I$D>YW!c+ zEaMwdAh)q54BAN?0;Vqy8Uzq;midWV*tLvxv-}F~?O7T3rXF|lI^l956bFTuIc_fDUJ!8m0&rvX zxYZ2zG=$=y(3j&f2-ifwz1FI-c8Pl28McLRnxN5Ity!2N(ARP^*X21OCcaQh$>2Zdc6x0`V71>B8*;eM?ixBq8K z?As8sVZm)&2CHu-wFGvWNu8bQPwzro{IjaXp}l~{vNH>V(- zY_+2Z`@`)URMzogsjf)&vOGKip*S#g&w@fOkEvv8xQo1&Hm7-xt*%CJq&dmhIYjFc2WiR?1bYJJG^%-C;oCSTZf1CnMC-iGEG< z1GoutZep)4OjGku&&z&+5LSL`c zPh*j(4i{K017@j@>se7ux7HAf<3lTrN2VGf@RmPWIjz<8Je98p_v?3*Z@^6zoJ@7w z3;w(dBD-3HM~E+DO1H4Zvj!I1q+`fQmK_QeT0Lh8_1vBvU=~yg$Lq0$@G$ zuof%>6Co5whetUto=kOimAnRe-Y;yWWQ0)MTMpv96f)Iz0&hL`^7NJY_hNs6Ah91Z z-YE#h&E;coV;XuKhWhh(e{$p1AsmfE>*zY4ZuC4$JGQ5HKh-vzLM=lEXc@IZ#?Hu>OL&X^f}i~4?D~jnN1)R zx0f3d&z%xQxQ_+gmjSxnFVYpnTfkY}@z)^r=~f0i=|-kHP=I|M06VIOjb^&-fKc3E z{!ZhOsaC6!w?fZ*nDJhNP~2fwi06)9M7WKa{;c~ZK)o0BxS9+%3c@HfUSD#D5e~^E zQ+=*Vo<-05QKe~YM+h4UymlIoOtoQ^ygGW`XN+fnu(80qw~y;brdl+vs`Oq!5MQsi zqlwl*T_mB$I0jkpeMXBR(b&*9YX`pL_j9f;?Qnh(ALZEu{Gj+?0o8su#!j(;Ud#uICM6 zye}YZDeyk!yhJk9B~|iX)$>{~-W&*93A~w{mqMm$t&%rF&%4dGuhJoWNZ_Rr&mG^J zaQ{5(PwrO%+1Ejj+r)6qA&e1ljXACf;noPa!16WdaWfh2+MZNHtbi+n8`@ogp$-yo zf&I%d1o5>u6mD0BD}=DMfZIwq6fT)+^(uKE>3MY-Z!v^z1l}Uzxf4Bv+cesrd4cUC zOOHEoiMp%N5XK3(;e>;FWUAw<Ja@_w!p#(L-v-pZZv>pSGFk;uJHSxbr!KOU z(HaWmHogsmRz__EVqkrlClG=78i*p}R0!h*1s5@5vvDwR{3DaQo`X?jBw2d|MeUpn ztGaolKRcEN=>IfD_3z(Z< z+J|vh4H!j6l08b=<8~74>c1oW>Q4($|K={8`lo)Q%=!&NI@0eOynlfkyjU{T&#L6@ z(eqX_-Zu~?2)r+e=Z;@bxS;}WdVqRM^|;9lmj~fv0xpN+<`FJjz|9E2W$JNnGu!|O z69wE;9M_L<+lKoyZ)O1QaXoG-!?lL6vw&;GaSsu0vVeOj02ijmJ<4#mccvO17jS>W zjl8=FLv118W(DBRAc#;igBh+E!XyE=hvW7V?&vUoVrK{7KGWlV`;}_SatON!xTPHT z7UAXzxH$p1S$ft z)akqgyP7ZDZgfC)jHI~!K65R*-IEaF{hx~4^@f{xWU7f(@;c~wGZ?Qqgxv*RV~t0q zdg&Q|b_D9@-J#PjiShn~u!q3A3^(aVrnQa;+U$(eadhnA?zvOhH~66!hIs(#suIjdR!L6b%d~& zfNRHb@q`;J;Kl~v>gsU`3>QQ~0e62pOY8#}Y7GH5E&%r%f(Ui*<}Z|Y$01A;a7PG- zvL#d9JjkDUfxK_@ypxQ#62jgB?*rnwQ$8fz3j!`PK)pOYZZ*SYL)b^aO(7iABU5c$ zC9l7pH=OZ$Kxh|usTz+=^}s-Xas%~?(eq*%uO5Wy0#72IJ3f+dvjp680m=Pmo31n- zuqR*_A$(H6orfE^3oz7n0&aW&Zl4}k!f@Y0*jK=PML6Uhnd;dA{?rEY-qQ14W4wF_ zGX&l|&Wj~eT~sA6Q_ma3cmp7OO5i=E@yJxWRmtnD=e1zGSP1(Gyq27oLZ*79e^u$N zrsrK_Prv@znre7j;Qa+RUn(`FA>5)0`F1IizibZRwb{2 zp4Wl#j1UeMctM<(LZ%vCCGYp|bmejTEOmaTAbdvP9fO<7mrQkQzpC=DK+oIAc&i~C zBJe)acx0**tK`ks^X4+16T+ba??ujwB~xu$C2ydfH;D0U5DpV~7S2l{Q$6%lRq1W5 z=QU(J6NGpJwPNB@hj{Mzx`dk};GPfYu5NG9703CXs5pLyaD;&S6>i{ugQ2z;a4!Vl ziuJf-47U-&kpk`;j@v-EUo!lOoe+RquE)K@a0?+ECE)TnE}w9V1>D2{+zWb~!f?+( zI9k9B;JAT=vk16J0k~v6u0O*)0^zd)t~JNCA>56={=`lWz=i8^i41plbE;vCfV&Mh zilQ8b`munU5`g;|L4=O)!H-n3haem);EFkJKjHcdxTyiSb$VP0!@UpTI03hu zL->M#TgPzmUlQ&m0T;OcvP6&j`3zMQ7lac8++2>!AzWJl7r0+CPLEr|aQz{iDBvL5t_Z>@0&X|Q?IGN?KK{f8?w5S3$NhSmieedrQw7`-j$2B&6#_1B zzvLx7?mLEi9>Ny|+>QB-~R1E^xo3j~+Lh;krVYCEz-9+~b4`7I1<4B~A6XbcU-1 zVYYy)&T(Oc`=+-)?*jKrt`_Kuq5;F5h0r13PQ#6fMJ$=>m@0YO^t^LFP+5Eqp;O?k zC7wI}Q^M63aQ|h0Lyz0RaC0D>Cg5gr+)ISpo90jLynsGnq#n1H;huzWx`69VIHZOOF%L2|o zI83<7RQpuPyR<=97M&UIB!qJX-ch)TN2YqWr$4!Y`hBbCJvc?Vw+g}>fwzKq?)Z-g z_ql*u7?9lgdR!61IU$@U;9lgoEW!;JaP9!yAU$pw!}WwPSHN}WxE_S7E#O`Wz{Tlt z^BArngf0PBkK^hSZimgEcS->6&NsTUc!%Ls2=fHoMYxf7mtd$<1>B+l+yOlH++he`5perC?f~JI3b@w;a9`?in;7l`2o(YM4#&MqxSj&;jR0JZ z9ygESra-tzz)c_=Isr1(TiyMs4di9$c`q_vDuf<^m#p!~RM%9=i`Mg=VLS=KR|Q@z zjYpzNpA%sf>+*ZP&c*#`T zRLT2D&%4aBZ!v^#3A{xbk4*K4RDW^<^?OmzJI;8cAbeZk4bymJstc;*S@gVJjMovu zWdg4q@!aw8gi8`|O9Ha5t{(R;!v#UOT)^G`lHne}P)ncir#A3B!*2*8l*W4ucO1fZ z1l$phDc1)e zjt2jK?-Pttf~sza*e-CU)D?#v@a0TqW-@Jui{*9)j>=f!9Lgk*OX?t}4BudR_$M{ryF%VU@tU z1~-)lnd(bb@=hX%(A+K^qw?Ji;c9`mL*tRDK2jxbm7ezni6F5t2_E}L)-`R z+!hGe3%CM~+eo-wkNflPg8cgwh(?J@Y)d1of1d56P^9Z{V*W85qexThP(G!s$qkGD~FrbS1{B( z0kW>%fy4nz2@fZNY;2MCua;64h#eW}MqGTa9c76`a^IPP7-{hsJg?8*RK zjviNo;if>iQNT?g9Qt@N)winTW$1Z9jF$@GCV`hsJa>FI!u1kx9|x${Qjhz!ggTW- z2saD3aE^;0T=`@E)UFD^-S|{j7T+=41qinYxS!#McIRNIp9;9u0l3|I+!BWS8p7`c z+&Yf?l5j%=+?oK~580^ zcWW!*l%sexH-SQ}S<;41EB9i!SV*=DxRxB(iULm3a5ZJ6Se^Pt8w39`FC*2U0K+&b zk&*7MO*QNgNVnleDU`!d9}-DD^`u`YKwVBsW~5_~6bhunL_+N)Q$5{@r;#ajSC862 z0gB#a$ul$58c22usFfOuOw}Wzj_Ofv3NV|a#xc|^NOlRR=^PbLrrKRZ#Uh%JRU;_C zqa2mXP#KWy7EpGMN+DCd{iu+@A$qM6D8TQKq5P&WR4gQW1XN26MW*_>i0Yt6g;9Wa zIf~c&e?Lhz>=jVA;6{gg8;1IL?`p1kxc!ia$&NqeRls#k!o@ zKmn?A(k4b)14)rUTFFTtQ@|q~g^YSsPkMy{YF3vUsq0Ju9_FOpj1&jS0f7|5NwF00dIuqO-{?u< z6yO)=iE0qXNDtPe8V(Aif8j>sy9+~IBa+;D(ytU?DJQjOq?3>w5=cim=@2Y1CPRESWJeD z4GX) z@(X8FS0DUA7H4g>28p9{Lf~?=PAH^|*qwje*+dP`4KZwf;PrYJL`2j#8(eoDII4L~ zlaU9Tf{=|Ypg(un_kd6cc`-Tgv?Uyu-PRcMCPeqz-Tmp)d)AmZvPG*serK`i8}Q;E z^kwmB?}$Yv80}+{BZ(Zeq0TtI+mIt#{rl4Y;>lt_AgnPnC<=ZDz#21^N4|B9MV2cm z1I3_^K0ZaKR8VAg;~|&-S6oV$T{)ZP9vYVBo)DSl&W=iR&x&ThFC>%U-W}wP>57ynr5qN z<_XdbUy)YIxo#mo-44nMbXzlo=~fQi9?1DWk#6{6Km15HH#}L3r5{rujl_m4>PGn| zqZU@%G%;-2!ri5_C)E~OGWi}lRQm4wL87p<$p?D(UA>z%HSMP&@FNjtWRIy1UT;xz z5^EcBW|9M z7u@U!BdMSqhNB+BtFWlAgJxaGgm!lUi4gKS3ps77qp_?!Im4&Q7S;z)iEp4@k$oD5 zeUFBJnPzs3jOvD;#i*!mhs;l-MVaY$9y076D>`g^m3kC%adv8F#4n}%NlLh7hqNQQ z&VeL_eXzO#3#R-+X(5e;%J9LSC*za{>b1Dm_(_iISb0f#v`)oX7aE&jP)?+|tKmmF z(%jR~@TNuLM=p9s8GHMc6Z!R!Y<2B6WH zqrIjdnYXh)_qHVzDnBrPbDY<-okvBdVvj*Av`s3VB(G^T_h`X9WY1Do5X{r;H7$fE zHR_qh??@3lGOHuC1YnRYa{eu9FHjD@SVATJ41#kGYs4tdh>GG&A=GYa(?fY4o2hO? z^E);LKMJyl^_FSL`?G3o8f2)RgMb+$@hd32f0o?~awyj-de{YvH7Du zc&Xs?m=*9gFPs?DaUVKB)(JpOxe?GViCI1r>)(4@!r_ecf9Pj$KcmR1|dF%i0uf5aQ$OuuwvPV&P|=P z9gWP>YZ!}~VeRgVih9JNjzrR-@35F?#9?u*%0BgR#Ikourfe-yU%K!0Qcb!`iOIVv z<*}`>^>C>lwx)J;npW~HQJ0chC7_AT!l$gz_}n20$1R&yP_W`rk7Dwkru-tiN1`eG z3bFWeaRDC(Mf2fa;cQHrS6VPr!&QL`OoNBuKX z{i6W_b%gpZ`lGyz958SYzB@EfR<59OjY?CHNk8HTa%9hdleUD5X-YB11-pBkO38qE z9`(OJ>LtboX<_3K^li$k)YDj$lQz`ewpL~MNlWsvY$;8dPu+`h!0riMSQe75?6DsU~~UX*{F?Mxhq6W|6Z#7&y;U)xD@qm zZ)GzFt&^fmMr*Hy@X#y2K5mk>qv71im#38Nr=|SY{h^SP;OA@#rBG{mD5pla&i#s+-y-HG<-QH4E6zai) zI@Cr-JSK__KQoT9;it{O9^J1cBRpy*b^L)U%eI+~GqU^hU)KwlNxoRN8b~Fe^J?{crLSbnZ3@wRf zmPD$PoTn|;r!5Vw@0GB$4c9cTQIWRa5W2JlCW=bBoQ9df?F-7zH07S$ zc9(oil|y#PJJp)<^My22%596&JddGwoKLNmT5B^U-Hal%8Vp^+q`W&whD<-+WR8NT z^UCIE1XFjl;;W?;yL(h5!n?z8C$}7mBwUAyc8crJ;qDnWy zvV&TBnc3o*7L=SFHmwo?UxJVTm(r=CO=VT0&V)oN2+6~MO1s>di@Qb7 z4(&F~Ia5wPH!aGFp~hpHgRs`N`|LD6m8iWa#`X}G8s@OzN244G^e@(>hBz9!)V_`y zh%g=z%G$y*lq{`a=}neKu-M2F3Cm+-sSZmUScrSAE%o%-K~h1FAlbVc8s$$#?I1lG zwmpY{w{AfVWw)kAAq#H$8A6Kv6`VP9F`cXH?Mvy~RzNKTeI*6s(-ivlsW?-k-tN#L z*PSlXf;_6(V|Lm-#`j%buSHpuqs~EZ5mM~EfX@AW+ynU#U@q6>|F7mpTD(s+^DE8V zteHDC^O$Cy(aZ~E<{ig0=^AWM=sFpaZ6_&rQwwxYGeeQBBoEij`kL8PGh;Nfon}&b zQ21_|Y1PdBnmJ4}Cu-(w&CJuxMVh%pGvBLZuF~9}Yvu;c+^U&-H1iOdQVYXW9DkgF zD+kvyTq|&`$F&JpF)kI?bzF3=(S)lRu2@|0xDs)t;L6A4!L<fvy@GH-|vI2?258GKVN%olbqF6ELVgaM>i^K4L)$x#WpRFG}CaO== z4}Ad-_7ig0AJ`gG%%Wp7?N7r#nl1(^uN`0avBp?woKD9$P2FD2O-8dJr}POpF{!mD z99K*4QFn@a<;AFgBt<&wc3Bd09#%(B1d&~Lj7}?b+JA%JH<9k^F}2dvXwCI&B9nsT z5u|xUROqKsWMv7vgS4b@VX*5?b!mZvhV(Hz5vhI-MutVX>vJIpIpDouMV$VS7ym;u zEzAuMs@vMsHk5Wp3@pvbYcsqkSO)iJQ?KO|rnx`N7yl)UlfwLqF2D}Zc#vt21~WC& zLIhR^!56bIkLeY1rNISzXV^)Fu5h9(FzrWLbC5&iSx571Mq%kE{mLNhuL;8-Oz_eq zxy$UBVbc6i+?UGHHy@!n{84b|7Yu0z6XrFg^`RseQb}U&hH)zhGcd2I6U0=Itn;df zrEFkJfRGI_*GU^6!^jwU42_{u=^tZGBa{V`Qm}sSjf#O)iPe*in;vC9d&o;4sia9P zZGV_qj`qQH+E<5Yim)Y)-RGcMHx`o=)R~1m7be_9X@ulyY8+Ih*0l{Z=TttAIgJqB zBFckg%7ff6>gPSCG{m4xy#x@P$N%Qe@8LuqH>s%aUuhoOD4Z{UBelqDAuQ`?M>QCa zUov#mr@DZ#LyPhX`PSvKmo(Wl$n4OYH5iZSgeD#du@$KvY{6`38h+uyv`zD|!3WL) z&Dj}FgtO8>T}Wx4w`TvJCZ!w2e z`XrZD>Cqqe$6csju57lu&gFK^KU{Oipi#1ZT$5YLgdYFkUiWcDfNjEM#B~+!W-w!M z@zIda|D*W)pMQ7M^LflDDj#%6C~a9W*1d=4Z3%m1cm84|Gr?m-04r6^-dyE( zHD@w+F8+)Awu2MvBP^Cj8L(p5D$U;$O#2QtS_v_IsX4#Yi$a$R%^4FFuW1a#lz@}f zDVHTQO*Bu)`>^0>`dAZDFQ6PmWuqNQ?3dt1tZ`c1W3kNq>JDp}EE`@0rJ`ldXjvP1 zvME@x>k>(YT@UcKNcYnp%h=oq(UD6C&4VPeW4cR zh`jScFt}1~OEe4DoF#_oHC=PwGf4Bd;ieUN9?Fw*49$`lb%^Lp9dStIH zq!@SEt%bNodC?FfPY3dc$1cs|dw9@orZrG(@4>$={0cO`E%1ZXhg}A*kGYo(H?W2j ztIK@YdcczZyIRz_@PIQ^OXO5IE#5uWWK`SSH1zSC% zt6`G3)1&!545xP=HDXKhEh+a2OeN6ikF_e}R@m|{N_m%fcQ8T={%;GWL<38hoSqI)r0Um5`N8vl2*hY!dx zFso$UY4H|Pmp#7hG0Ux;!H7GK$L&XPCF?cl(+Acv!hV47Vd9p3$;*>yhvDh|!0w6d z2^;b<6^5(4hP2>u8XlG*V{+@`+&#+}#kR=SsnA;t|LHGqzivK1L=8jKvVO3HkR=V4 z2iIUR!}1SV9)smNS=z%=MwVDuE|aAxEPs&&Re*=73CkalSk?zA=?m3W<#+_8oVU@+ z_I>1?lD^oklx&HH71M$SY{HFwJ4C>K(|R=@y%y{JH~1vkkoX1_GrDoA3bJR;dZzGO zbnEW8<8rcefn^C<&?TqLf(5yghtF1)wSjv&cRR@45bkUWh=p%T7We221BDQ|FQ489 zfHubTxXy-j<%r#r@*F;xjQ6@xk0fh3Mx=xIL@aB?=^0Qh8qej-Bv^tZMDDZoMUQ-h z1;<`QL+Y^*Wf`LIu-y^1tP$*S5Z_0wq!8Sz4ZM)P9B_{Avq}7(v~?#T=&uOsHHA{_ z2snRY&VN!9S<_5c4g)iuX3kTcW2hf$M?1hWk!S}GWog>XT0lCsRPFRc5Kp*B30~J} z5-59Y2un};Zge{Dh9}j-ksF1B&V;)u0cIx>Bo0@7YEEj zYANUxg*Xzc57)pO$~ z;Bno9y%^W8f=PDY^##J5dc|NM(*<)8t`Bgn!?hh(5w4}U_QU@;t}xhtf>{UVMVO6Y zUWIuJmlv0BE=Z>N>49u3c-|GZ38fh8-O#3gn1y7zUW!Cj#m=jh7MV9_^@@iYXPmX+ z6J>B#hf&|)cm$a-5%piK)tF^W2ENHo`E;)lb3O$xa$bcK(+JtkR|vAUottUxGA+t6 z7Ytv#Jv`ov8s=L#rHzvtV=|ByawXH6JS{5Q;#*HCMbbw5-cV^{|GmLhvKsK;y0;n% zF%CDS=MEs#cjwhfjMFp9Ta;X$g=vIo6FzfFiuH#FX;I%X6Vd}{lq7wEYf+{-J8&%; z__e5?ot(M&|91adfT&laC>=fPSKL2IyZ=de(B^gy>JRA=DdjDvs^c-8Lp(e33zdQC z^cg}z+)&Gzci}{GC)Z66xnji-*3qW?ZpXtNGi6ewh`ME#{Tbi0$j$r6e_m z0>}^yA7M}l!$%!v#0N7YwiXOFd-Km1ElRI2PxyVh_X$-hP-%zV;JP15TbvoB`(UY; zO3zkCQL`M6?(zt3MD2Ado{7^uZy&i)J|8rsDXJ9@$2_K2@sUrGy#krH$mI>qdK=Oe zT1W?^R%L8VM++T$LqKd5VlHII(-AYz9-3fxMA<}Ilg~@Jr)h)OV_L336WNW%;@KD0 zwp0?Cu9u^+0HNbf$ex#J19TD(n;vpct%l%`wAF5Yy8(0BHJHksHqG}8ch1+G2jE10 zQt?G+50O3bm*7!p{+s3rUx1PdU66@k0BfCy*Ab>n%0$lz$0|7NlI<`Qvjjtp4H|hW z$Vgx`t9)DF@f|+gNm(`s9!OAA@|a%NLdJ7lvovCJ?#$MFCGK3L z`5L(MTg~~GiEjUL^R$qAl(?qZcp#nwJW@;RcPdkqYlHgZkfc3H|T9J=CGmj`|4gQ7Y^9Xg?0S za1&#q@eFJrf3|9DakZk)lU-Z#NG}ZF^O){GqE^4gY=2FUaBZO*q3p4u#zZog-}aiT zJY+iNFcH%cj_PhS4Nq|pOs0siW8x6O@(p%+D!eBesd$l5kEo~Wvl{Y-=G+ITRZ&O_ z1ft)Mu+uq_BkC7C9DOH~oF9;LjEgEHDnfV{7rk96cyKT*O&QuTO_`9Cru=3ZF;X~- zKn2WpSqD6g!X3aLZ(>XBM;qH?-H*>2vOU&2>a*5r&>CSh#b9 z=G%!oKh&HL!D-9C>TF?W4^WP3;&6zeuxrm$%kYsSh7QNGjP#6zLc4oa%nFo>a@yAE zBIV+Ew{0+@OL_h95Ypv!*NOY+ZII}-{S_zrqingxvleTLODW2XFFwDyPHKimKukiDkE zosnLTsV2+v618_-l#)_n%e&~HW$amad9jvKJCWRDy2}=mC9MCy4ZB^j6{-#3hp@%) zFXR4d2t-nW?eu2)0>j!M_i$M%aHdHGKUpN(IkawP@3k0gY`0;Z(`Rj{RkHoHHf+;$ z1ctTTHRq65%72AMKqb8pSo&Q^uW3jkdsh1p1RrYmdAANzYnkR;1ZU|Y#N!0nPoUrB zK)(42!?h^SaKg))vo{fXR}iZC2@@IN`^PGDXre`F$O&ULXBZK}DhPX!CM^~H7-5N@ za0XL%s%xhrSt`0~gne+9(%8aNfjvAQp(7*o^Aq0I2yb#iv_{Ay0`(t6a9Z&Q9P1I& z3kYnHwjaS&KQ+dGiLch?;eS97REI;9 zvbz#(U!cMn_d`nSM4PlAm@?JVtloGGvdg4`ypTh9b5mL5ng~M@irDlBF#y?~#Qz9^WMkZ9I~m zZ0Wh2EVS`RYc^yixmo$wMlPkFgvV=;xJrW@J?US(>rRlfA0A?pqahq@W0St;RMrh) zClDrF6##w)|u3x`oca zXV6@o!MBb|1q0-@G#1;^EUY0*1?jyl+h-sL(RRPL?4Yl;pdD|ac59PtMQcML-;W6C zeb$CSaDY|6=6Q6-t8A0Oc#bWZN@U4)R6Q4gwOVUbtew*K{ZyfB()MBu9nsJX6_O^K zb7@ggfN-!UpXNG$0w<1iQQzk+loh8Lov9^xuax@`7HV|rWfTIR!{^Z`fiEF29gG=| zZdKvEu+Tj>!3-e;mxQYgt^{1ExccB4gli10iMTf4+JHRtzmVh7IJWm1^5=p}6GV+4D-n#D7~TNdIvfG3sONmHEl zX#v%>CuJRlCuL#&6xk8qH9N){;t02*F37aQX)miuc01W+sI^?X@o?OjHa0LhGr2Wc z8tDdE5)!t$0S+tXQ@SQ_UrMFg1|br>x9~_Zi0?enwmNka{Se4ADAkH#HyT?M*u7cb z9-A=buJX9-Q3*fMw)itxC^Z@5^$O!XA`kP_Z{+$nG`pr$u&C2fS7$?6@K>p50s8@s z0F-U{(7tziblV?f99l390yw0chWv9`+i5v79%FhmvKqR&&`#9cnkXr6WOfV7CM^EY z<3$u>t!ZsbefTc6>O7*3Kp3779Oa`gBTzy{;hvu&fIcCA#QPF5h$jSVuEc)NA|ZApPr*{&l$iVHNrZYx;kHFes`1N-=gn9T97T+1ZqP z__d6(C~R%jKvL;EInb_OqLW_3dw>^PSb9((1DqK zWTExqVY1MHnWJQhgyjTTXq^5L7SeNj7}96Q!~Fe@Cuj(WrGG{m6rQ4zvLons2ujZ| zu{U!>eHG!$>XVba!dVY^M4bUCocE7&=<{$|ynC(5lfvfW?D4Resihw5;j=RWW%T4> z)%QH0nF1m){7I!dCU`crsNO80{DR(s4=tQK_NZB0=4ZSG_!-Khw6c~ehIy%G1usb@y z7-)CIk+8p`B@FLeM`IWdypDS0@;bs<4pN3j;ykYFa;WUuiHq)0h{XB#Kdg9S4{v&Q zx{!tlY_}9!=Hba6t=(wW2gd_AoQam5YNV{}vdla0oeM2@s=+oK%uL>ymBpS|8^gr>c9qx9 zY5=|KLqS}c{;u8_XV`&#Ep_QQ&W?I&!BOlG%GO%lp#$oW7ulOos0HFLlkn_dk$opn z%>xJFQ8VAqGJf)N#kzZZf|p)K!1FJZSrUrLcW}i(MTEW+r&G~YTQ*s{59nq0u$^XX zk*nd@tD(H4$)fCjFD8eX6Y+!x3$3Zx6LGeMQXcH|&>j-|CzFkB0S_kIs7-N*L!Mf&oDV|iiXGK|XG|EiH>gv) zp~d2$ARn@3qJ5d;*uhM%Y23qT-8j)pM=GCzJ)MrYoT3+@Y>z!ki$-_zGJfh19X%A7 zLHox!fYR&*!#IuMXlBj5&}QBq%06x3%W5y}XJAtU8xM3^ydxbcQtr4eg;?-tC}(!e zRD&aya<+cDQfxfLK;^LWrzP37O$e`SM2bgX&GDa@1m`M*ZtO4{8pFW zI@@n``mK}w*5@=U&NXboJ!ar?;d&LTGfB9_LtSN`?})QjN7MztTJpsXxQ^P9e)+$1*;l!x4*km+dj_ zKz?a&D;>q_NX3|=;}{V*nTyku&={qo>?#aRbBD&z!Hk=bCwR$5qaYp-E|2K!-#=#I z@j?m@Z^aoSSZ&HNif!3>IoRU55TY(XqwFDV4}W+|21Cd}*t^Y^;^;hsCog6_gi@Rx zZxrA>B2>c+6>~65KBR|zo_R4j6bSC4EO1`T3g%uEQ^?$l_>Lda8%KezYo6y}T4~Q; zU2+%?{2GHyPs9GeuK=(caK9Pw!#?N(DYrekE!qYiOv9#`r45HjdD{HBf>#2hyod0N z(57uc_h5tMLA6N`8hnYm43E=odAA%j;qNq>HwKl3m^1+Oy#``^wm%JI#}djze1hy_)@(*jsg9#^Hjcj1dik2S)D^6-Q{ z4k&Lw=kfV`$*! zkq0d055tpE-VCwQPVrbR5zAk{M&i5vt_L`0-w#16PIWB*h@I-_uJBVAe|jV6R7b*b zrRX;H`f+coa^r?YitK-i(%ct}%rxocqv~D+%-PE7r@_&Q@-*IcKWN%m&m7D*Z}dQf ze<(t0Uj$0U>xje7iv3d7jlE}*{O7a;+VjsyIF6$rmfJTG%73%VNIbvUVA5(|@;_NW zu$=PaOMF2H--%SBx5>1VBu~7;)6^L9ipIq1kUvv;17PtM*^>Ad0u}ILv7RHx+423nuIXP6$QPl|c+hVlSXKAnK$Nqih3ki^wtltimOeK}aq z^7OSrL@|9qh~?MK?9X%Pwh{?tdG0a&aiBuC^Y<$2whg@q@}-uh+YTN;%HIPv*X><| zp!N^lDxT+w`F|c8JzD!mWKqA-bl~TRdJTsr{;Qg}?*b%F>zlONkrJR{W3J-(BA$Is zeJZxBP_djUx+gZXI#aPy{+TQE`xUPzi~8+EG(L|<=N*YTOq^BOB^8+dEW>XuDTSDs z=ghUtD@P5;aXgNhOm)n>xIAH3+g&MOD@U&&9+! z?V-Z7?&#r58IH=PC+w^AXyHhrZYrS_^`-<*yc&d4FJ~ zY*4#zLb4Qgv;$iNraw?o)LVC`?`&*v467I!roYQZhPZs*i=IRXj0`!mno<#L!3Kt9 zb61czMdKfy2o&R;KTy@r8Oh%ZZ_4BGmoRx#gCo7-4kmtweOibteuuUb*#^)k+`&rE z)DEi8_>hnCmw(4;5iCAAz2j8)4pVog<`>Ihv~@&@tgE$#+P)~-7|~b@eycpffC(H; zdSuTMmSvWmf3~nGC6=7ugXjQD21W#`D$vQg5YMJ@v<;_P=$SN*#!SRy=7)dyB8LuQ z;`Av}t$`>UKrE<5TXW$&3&r_Zi?f^E*R=RBZ?of}4Z8`QPt6eH^Bm!kGquR`dE_0t zc;vQ}6x0=Jy4iSZaP&FH{37_GQ`kt~~f z*wgy+@aj7(B$gw1wUaiPa-n}&7t8`^R`mrOu=Wg6y|<{@T5(X4CUv+kb|Gj@)CXN1 z9d9!=X6Y_bzehl}d*HeoBw0`6i6YiBm>ywPO6!?XNUYhvo}sP?i|&4O+PN$JYeh$% z`AZ(u@z6rX3bHyE*n~o#D4s+Ub)p6&dPXPmVs@wY^ov;kr{y9vGTuI1v0gVTyA&*q z4PK<|FZ9M2v3)Uz(&;g7ra2;J=Fw0kWhd+&<7b*E4)&Fr9aDZIeUqAkCaFjNLA_Lp z*m9Y6J~r0{4Eq-$O3?`wh84YRl6RMDCtf6p%DPOiPvE5PS3xG;}d?W)W3PchexvF`9VH`Pjeip;H84+-R-&?nst^6 zWPI65R>LUEQ|VuO*X3YGGs=8=dF0edJX{JV6>zTjDC`DqKSlPNH<^4h*;Q`;mh5NA z4y}au`>=0?V^-L|npciZAcMnb!N|du2Gow}?LYR?U+cG6Bl}}6Uiy0r6!f0B@n9%H zomw6wNC~zJJJY{7S81@LF=kcpW80!}2uDXPO{vg=)y4K?q4CQ^7TSfZ4-2u9z?w(9 zQwB$~FpUNw6l;JwYE}W)kn!s%3VZtq_J`nE`X>USro&kbFZG8T5r!^L zNUmQXc0W;i8irDY)mAI&hp1{brbybtuo}@REt$QP5BlHGqh2epFgOZ<|Va%kZDnSTE(#a)DGSbUaEy3LOo}byUh<0Rw<*#{f7E zJ2BBDAzDwOT@bMhNun1~D{^HM`F+fzz6ZPd+F!^7JVK_3Z<63;65zBW39?8q34*d& za2;<|{6!VqIJ)G1z?|6cgJMU;uuIrBGk)?A)|kPDXjCK%Jf4OJHHshLfw5tfRXJ=+C}f*> zB(~Cw9b&T2_?I=WSS`kC#NcBD?R4p17v|q5vD20VtMt6Wqwl6p1$Q039mtUF(ZFpnY(-8O~p!`{Er0@KN`#mJYhgQSh=!RkkQpccLihsK2sDE<|L%|`g= zBpIBMuB|aEU^h5=WhSQ^oRs7lTR8aQHGn;)W81j%6r9kbF|U&sj= z_ry2}BE8H-6VJ@#otO-n4S2oKvJk6AqqLwd+8mZ#8+#%1cH*e|!c|+etv;GTV`Azt zjR9SK7UY)#LOYLC$xc_tY*(qs^flmcpF|Vc~=&` z^|N2o!j4IySxLX=E##kf3OPcxs3R6*FyiQAMQk$*m17C&C%p|w1;IX113T3Xym=tI z_J&!pP9U$%xR8pmeJyW#1WnWKVC%=wOR#n8!eH$NsRXY9S^kuPJcGF zLN@uIry$roEtrR5`SR<$CY%8wRhWg)17S~T;?WSJe8cF}oC+z#XJ*dtv zSD3ExOxF_C4JU16VM7y-I4ziehN7gKTat^i8(EdY^pHLH3MC zIPORR<$Q_Sm7I9qgI6kPV%bKE_7KFx4u_g~tE4=F;3%Qw=d{fHJfk45`J~T)6 z)SoXWe=p@uf~b!tv>Wvmqp%p3TtgvYXMgcw2)Sq{Du!2<%s7-*td^d~jxEf%^G@ZI%^f~J9rvPF8pg|>ra36kVIPE2$A*Vs zO89)cC)C|t+Gw30iqog3v!bR)FjuwAF4hmKW!2yxCplTxj=o~j#-{AFCLfsAi1kMn zZ*jV(-@P7ySlqost;xHlUr~0^4K3cCwq!eW$z>-oJf`P2C$g{Un2~dqZQ&>#JIeI- zWmZ5}*tS%Os&Z!v!cqpGfm2J-eni0Y^u1`6Io*}eS1E6gq5DADNv>j8l+$S;XQjMt zu%_dAN;JwOP1%>;cAr!b*&U~64Q-D(tIOU(>=ItZv}#Is#rkS^TF9QXyhwIox~EqhS(;Y0;o0eU zLg7LTA*e30r3*R;X+FKc&r*ynOY8?yYm`0h+)C&=s^DYbOL-}|o`FrP;ZMQ}4cAeY zHl^H@kegEeQ51&NGy2)G+Lo;>tEySHK8w6^&0ZI2kn%o|7%@F?-Og{YBgXjW3dRHS6K(6DAEQ zl!p9-eNAb|{u@#qv|rjrJj3=9;l`v;9S@4^+8vqZ+80^YPhlW4sfuq`VIxTiLD9u2 zJ;GRnPZk5mx{^^BjBO}aFs~&8IZP+{>hoZsVA4eCeXV`ozeHm!vI$kjN>4$~qr$MN zAQhmFuwe>=2znD%T~G~Bsm@|vk$0RO*lDzZm(I7~0NZsvcdmhxQP7O+W%TZm%y!^P z)I~lYHlz*F)R+e8cB9#l<2wOJXIE(K#8=-`=Z~=l+FX2(@6XZEZG2`_m{hy|eMDOD z9~6*0W*26b!&B%H@{%0;9-3Dk_5O++iN)>FJdG_ivzcaowTH{=XzmCyb7tawSL_p0 zqwyGbk%8wm6#WMD^?AR+y%+erwOH9)Jl-cptU`(fb898DP`mkt%5u%UM>C5x^N?m9 zt>pIk`@&bgpD*4?E#BGxi>W22keVOf)h9#CguPmHpLtkwpVG`rnn_~-CEFbLmzX7l7x*PH*a= zJHz)ES<8|N%wfuDeEG=PFX5-WLWf=?On2ji@ngMAf_uuW6{p`-(a}jpuBJ^OVm7 zIqF~;*c5ttdU+*lky2h}goE9z2D{lx+^hy}rhU_9G7vd)uq8&D^le>i&*lJ)W>W99KLopS zkZneu_%)9fpLu5?!m~4WXs`!0K-{DWkhV^@Y0eS(CTj%cO- zq9jb8cm5i!*z=O)TE{5rDopjg`%347DiuUjJBHs{+l>dvc}W)SahDZE*Ad%*2$19G zh&hM$%quo;ztifICnL1*%&Q%e+iM5*As#`X7VKdcc3Dkv5MfZjZP`emjy>6WoO=a*G|SVv-gL^n{u6k9c0`bbLYfP)^L|UwZ(^@)hVWi1-*%&2Hdck% zyHyq?hhB!a;AyQ?5FdRs6)yp#Ddl+ZkL`$0(bdyu*|4s_F0p##7YwrtD7Z@v#%sM7Ql5>apCzJ*D|?hM?pZ+(aBJ8dxz*8ZHW%xr#ld zK``fIuDOw+&h}Qk%;>sFUc;?(5UgQ!&Z^v^NzdzW zY(5f{lxd-7-mY9YEy|y+tzS~hHaOF9RM^=Vw{f(^b2l>K2zG?I3jcs(dIKhGKE1Z| z@y={|05J)-WqY=E+I^U?HwpTnDkX)fvv6xAk70S9N((}`W~a10o@Wq3o^X{%v3H21 z%&mcGJ~9{k`3Q@w!Y$f=j)cS`tZR0MC^|jhd>ppO5GOt%XYW8ScHcx1{(q#s31E~( z((pea2?-E*!Z8vQG-^~7l}JE|0hxgrm@E^BAc_YNMG-t$gbBn02}}Zsk0a=!pyG<> z;x4Xupoj+vH=&1g8P2&x8EP_Om|gvcXdB~R##V(Y0rG8 zC1j1K3tZaXUIXvzeD^W%_KF7hZu#UN0;UA|1k=Id2g0&z|xl>_r+n8;RZ zl?_I6(JBGYRq(hh=ZBBt^d1F&$k4x^fLDellTWRI*8^`Hqg(f+I;v^~0M)vq@6tl0 z4W8*N0Tzh7BwW0f#vd8atQU__^~LZKz^0+H9NgI0(U}6Ry=Vtif_@RSNN=R5gzZIj zc$_JGg76w9BcyhN69;;$XR3kq)@!wt{WKEN^7z9>T;c|jERR3YQ2y~@TQ;hDt*Uf5 zR^QF4`c=&$S~kSTtKs7%eLLB4GA1BZ+$z_ZbDi%{Scq;UPJ$bs=4Rgn&CUJf0XKBS zG<|f0nN*MU;zpLGC~oI1r6^*B`%t>QjdSFxEum}7_oc4KsL^k0d5$xZRP052AePFx z`BO68K-+hUfCnQl34#r`j7P<45xUhm5scSXRs9#pV;g1d%K$p{y{Jvhs$EuU)Ni|P^@oDGe=F?6mSS&RI zN~R>R2wD>b)aeGb?|s_zEC748l+^hMfT>=|CC_iSjOT!YZSuq>!`x&<1dXks!LMZt zTb&0;fiYBlnmJGD4n7xH)Ax81>NF)>*y`K>Cb^+jT&)|?MZo{u8?M^>pL)acTU2kj z(M0VcnW@9KMw3a#QJHi!l;7{6jU7F`{o8c+T_E+6PGqREQK?kFdX8eEjZbJ|zaIPl z$5`{W^4)FOlDv_xwufl8A!%4$JY$BRzT-8 z18o=3@y$TH1=OY)Xs3V2dh0-DUp?ovHo%lTscRsEJSB9I0n~S?2 zw;Zptme!tNCq7Zm25v*H9oLy~rV?G7jQ)&sc0h^RPjM?_+bss44XOWU# zY;_LqW|9_?a4bcAWK8|AT1n8aE2vZPj2;X6;G<9k_o%8)pDRz+$<9wJg7fl34yOjS z)An_9e;f}2aD!%5;(fJ2ioCW0|1Hilw->FP8{H$FY^#T&}98c3fX%ByT!>D1kS|dJ0|TP>zrt zU)~;ZvAV;6?Y=ji3>FSzeTz#M%kxBam1kW#@WHGN2?Sv=Ppqp9+>R*lsRE_@pX6Wn*u z+;26=8G;nMhTtwUX|lhO{600f#$Dj#JYDiD)%m?`aN7lUlF84++iq~r3r;ShqluAf zaO(_ik>I|eo7kI9F^Bu5L90skQT^rGl2x@#dq-bnRn=%O_m(O^vbUaiRFz&cMpvnq zRGX^wrD>``R2XEQAf-wv+7iP?c07Vr)$2G`3g#2Ji4yGs0McSe#nhKOM?9yfrl*=u zfF5Hz(b%zythHd}==^j%_9nLM+v}Z7J_)`$XW34s(T@Z6JDjui3!=frhOKr>>bpLBaBeX5-C*j*V68bLl>~#4PHTfS zI*Du#?kc#Y5}%`);z(MJv`3X5aH(DPENogPz`{T*v+S5a63Btynn36Ch^K^e*l-rb z3r4yfcY2JQPMhNT(_VWfcfejO7vn`S(G{<{3Oes>Ot-UOtA3Ew>%T`@yCF?1G2Yij za5G&O`A1(=Ug70#57H0mvhJzs3%z@}{(N(Gm@mZH-APBE2l!d3NDChWkv=~uiTKli zQ0HiLqE0&C#f|~QK>C7SWi4P zVG$nAR0m3T=2gNHpDM#=XU!&uVCpu<-IP$Gy1JQU4sR2o(@WS{>vqy<+?N$~U5<-} zv;a1NJ*rQ&k*E}3Ql$#&t*RdgSugFRDQ%7nY*Dm%Mz@H!1qb!V0NEKC*cwQih_^NM z7OsO7?vB4-m-h~`OKKGvx=eMK>KeL1u%?De5n)LUjc$sOsG%}L->(TLHMHfgs)nW- z?D6r`gmHK{#-!M?DORF7+L<`tyrrrGBM99(o~o+Dmp70~L0Cx>p>ZJG%Wc+P?IBsB zUZ7CZ5Np!RIEwG*wMV(?zd8QEuFB6-q`=3zxI9B$c*C&^XPhyJyvMQ!MT36b6u&gRgNR)zd7la{9==sS? z%JxRlQO@ua{_s zo`ha8Y(-5;b|>n zTV*%}FA7Yj7{>Y&MUM~OgMR2;p3vANww}9D)zf&BffZ+q6gry}e%tzIhEfgvr{Jm& zLgI*A&Noi!snAi8h2*A39TPHo57_y_$Zlpeok;pw%{Fo@x_ zm*BHFGA2{*eWc+@ zR#>==bP<2$co&aRH6n z|Ew&+mdmeG|oYQC2gZD8FwgM zm3@c7`4YHrU2610jeN-}t!?;Y`v(f*y{zfk+Ph~KaM_2PHwxB{2_ zE+t*nL{c!I%}i-k2RQwr##=|fVA?0;$DnN7jpy$s%Bg>f;?_}8qbrD_QcFvjT8d@M z`i5*44=JwD+2n<<1s8}(X(A~(pRUz4(|9wGVFGz84!IUcZ8$cBDa8@Y z2yP_%@MkEHwYBEmjUPVl@4_1G&O5qu$QxfVol0Vjyp7;KOFYx?^cK%`c#6bxC7$!e zBNl%O#WNg_M?8b^3=xl5{23;m-gridM=bt~7SBm|E)kDhpSf5(*?2A$k9@AhEa9aw zzFCJl0b0ozQE0H#na1G1Y0PtA61CQNlQ%Ntz3`zvGbRRJZcmx0U=(OL4Ib@fJ9eJLK{szE%$)raB{uHMBXT%Aka1jmz{SkUT=X#*D5 zR@E2Ow$~oRuEMH)4}ZY{`-rvri?-7`Pw>t@f)$$9$TrXk+mP0nz6Ksw*z2%LL&?Mr zV7nOsc&kX_?Rv>qYHWgdgtsfjBfMQ99^vg0@d$4t@Ca`YtU<+W^%tF{$=RIO0IN07 zt$@7^aEb;VqkyLw;N<{`xO|CDElAMYm-}u?q_V3_Z4$zN(Tnt+f@C<(Rm*x#{6mH7jI*T7FSu)PA-8sHWU?4W=Z z2Ka&oc2vM?4e()r_1ydaA{7B>jLjD_m!>_|eb5^ay3f1y=9T0VVb-1FEuN!nFCGEP<4 z2$Rr}*Af-x{wku&{Efi$4mBZd_%Wa}-qwT@X~X3@wKS93ig;?3{r5c0UXW6RI{0~d zg=!A+{hav_G#)GZkfQ`v%4uNYWOZ6o(uwlkYO=iqoD@%Xx>ogBj2^1kSg1S)rVI9Y z3vXltIhzH8)?ZD?nV%c0_rE3`E6yNNa`GRoWmf35z3u$`Dy6o|UA%C#`m459SR~H6 zk63daQoTs`ljyw?2*;R(R`J!S;oS?8>es6?{Bek`ufI#GxrW4#OVsIsp>{hb?R+JO3>4)euZUa67y9$ zyFMoBXRjof@3zHOS#f6IydmJD_}?{Hm-pXIIN`rYC%D&O7sM0vhG)tspFZm$^nI|| z$q#KMs0|cOsHLS`)09x6NH>~fioqosd-Mp)MLl$VGFz4d7S^>~u9nukIsAlXM8f>U zo}%1`%R4Jnh8nd;oAKoL)iS&wBuE}Dl*D_&Cgxd5D|5z;p;J{lMbG_17?s2?D!1|zq3SPGGSudaM~2#y@yL+TlfuYLO>a8Ub+K6eckQrX6aG#{9{zNk zeZ-7B@BA+#Pu2#+-+Fk_=L?BX@QqJ@=Z!B*t#x~zPo?_aowZ_9LY5tJj5bk;oNtj; ztZi=fh)UHY0Mc-}Au}JNkO&HUeHiGWRegi@9=SWNWcKwOp&+v{H}d(Fz9!*1^Shbf z;-ZaKSeA3%HA=Lf(C_x5GVQf_;^E-mRXE}wqh(51C)D3{Yoe}FL3nW39~8^p^jc` zj|OI1N{=0Km!%%d=5m+iWUZ0^l8OG9q$yMWzYX9X0HVQ8+Xuq)cG6B~N+xohe*1IO z8mj5xjaaMN$0&au6(zd-0mIfblgv;RgGR=%uScOo>kJOmwb)%qxaU7x7o>}d!Q%wz z@AH^|ItM}?j*uS_cfN&DjF&hI5{Y$?J9tYeV6e!s=Cu4ub2GF8k95y}9qpDl1`H=(824 zi19cNQO2Mr*$FbWJbLUB)w-@W*lfY- z*(m)6RP8WkfTf4e=ZRL}x}c>jJ!CU3$%omyQbfNYx3)=i22c!q2x2P;7%Mf5y-H9s zW>tMI(~04z&Z9Y60zSG01nZEiK5)6d!2K2HYVm*imy&W6_D_JL@GV-TOjvNo$LMV0 ze!#W;#N|32=f_=%n~A$0w-UD#w-49qQ{LUfUA-6kZ@9G$bZx?o{4OHg=`)w>99)0g zVB84YSlo5E>9|F>=W(}_pBHyCaqq)Dj~jz~6?Y+Nt$}7UZntqC^ZN&`%jf8|uj6+P?g89$xUS5Ny>UU@)wt2n+{W)h+y?mk4EG1_GI)3c z`j3Dw$Nh|3kIRC-3uWofZ*QCj7sUMrZ6DyD%P;Op{F8Ba;HG^=9=K}UUARTKrMRbX z&*5Idt;fBEdl&a9&cR*wHFlkGH{i-~x8vsFG99LJeh=V!;s4*<$gfklr(Y!_BZ_Gh`I_EdFIRW?f%H%l;YZ-UAdnq zF?Ydx^j{2;ST%A6Ed98KU(vk5Y+hAfB>`{bV$>-_qXOH=sn9c8dNFM~C8hj)dr_K6 zm~2Sb)oy_pl7xyoPjT5}v&1D{WgWT4 z+zX(`G$yQ75|-fyTcW~FcFY|DCpLx@#xUP}fEppOv6Z^sW0bX3HH!XAapYfn5UGeg z#0+5|eO9eegQ;#v7eIAsOQvX)VbCHMZJ3uC&tswwQxMbIFi(tzprrPCX8mshwf-8S zlmWrJ05!W>|I(m6uuN&ppf2OHSzcVTST=JL<@A>W0+>+EiC8=+7Nps*1W~yUTcXHEw(q?&vU~pkp`{`MVx$0fzU!hxF z^qv)72u4VD7?KWFwcHXPXjgRzN%}>e-cvf zv_Nc0lRz*sbBC4PvLGh6&?Xj#Uz2{|;@y-qV%3T5q0#bSX03k}uCA8XBWnH2oi(iV zq{WYrZ^cxIS?yq+RDVFUi#*;}$<+r3@ULnKUQYcx1MkG zpTTL3&z)?M>1ty9~P>Sm}9|C=c)tQsxr11Wcq$_q+mXbviP{}&FV)FV?7 zRbi*xRerV@X**q5_0VUms!N5vc+WZ(a?!H$NFv%gha$wp`|HvVYRfA%EthS++ohA< zYf26WqZnnRk4}lXcNpw*N!V94wtLL|oWWKmVe2%Oms%GZtlZVqj8e8TjixP>8}xAo zUFwW{memK0mMOziQh-t^KqAH<6XP9KR z`g~!<4E^D|KAogf__txInOxLYHxm~)-Au0IL|dB4cgr<(bhl3B4kQEuKc9Cfqh);i z;_%Eey2w&Eu>G%cd-jHqi~|GNO$uEHq3a7B!rCdZx*|UYeL-Jt&_7KF-9;s{Ic9G! zw(InIJyypxlYT>7<-c(CTgAB2#Hg1TU-N-h%cYQ_Ujx=at|oEWIlws9&AiWKy_7P+ zTbNOvR~+6X`;HdHJ$9FWV`ckSiA651=wGu~b@8ZNl<->v8+eg3)Bs;aCYQ@4m)X(` zkcXKbGelrFYFMMGh5~`fC1B_l8Q2K|^J~~p18XC&b2Kbws`g+xux=XmF9Z8RV68Ol z5(C>VuwN)FRb9#u@r`P0{-u;;Vz}>_<*maNS?#%XFKxgsukjXLU{!A>ATI(;#E^Eb zwks4pS5h-r7*x%mo{S9nU zVlmM(`$`HHaeoogd<~B$CHZd~s!B1>Bv+vGhq{X?#ffohqh@=Sp==e0ODcIRsk2X=SS#gnI%4qI4BL?VLTSp6wOsq7YD<$=33 z%X}p-iYL+3R!3e~i%&KFVGgm+8Fr57=kX=6#O275P^6GPx9izV>C*WcUcLJG>(^ z3s=pm_E3qD!TUrRd*1V4?ctf|T@`IEms5=T#kxZM#80S7?=Ds?VP=7@)YHK+tjT>F zVk|N-Is%OjB|Qd7WvDiMIA+b+P2pzG%BH!^x~=W(StuL1Dy_TvK}OWkChDGlBxQE3 z&Mezx_9{4?ndpO0o~zk=G9JTx@8^1H*6soh**|X6WV7OA(h}S0gkLhG;}Z#ssLO2< zE{Vr5314cc`{;z9WG@??PE8W!fkir#W8+aIlcxfzsz#V-N1lvxFI9DeiQxcEZmmC` zqq*M!9I_}MP&#&foJr?-EIV)QAK-YA_O)Y}d9pg6UuiQ$H_2k`K$T%Gja4e>E?Vqx`Oo%Aph;nycr z9guW|p>}{YD}TNzKX6@wayh)}W5{2QlS|?Oo%jzX%0oJFZZ};b6XCH$QMX*T$`z>{ z&h4P1FVf(pGBBfy57Hr>te)v>&hF=$(ScCLp0*ZHM*<<6y5okoV?S(&kEw?z*dV0lXbuJY?iE4)yrm64qLeSTGO15ECXkEvow za!BYuu2vHIPxzt98wvgTn;5~?L6_V}wx6xJ{}=G14G1Q0zVXZZNP!4f<7JUG``c{k zuXg$cw z(Z#91+JgfiU%l9Cdpgzn z?yTT9jn}?weUVkMwWOMd8PBQD$ZQ+%#@6}c5^wbc_&(~3{es;0&V*-Qo3G`9_kN)4 z9{c)gxF8^Z&hhoVUhnGm4pc4ki8FP}y6}W9IeLksq z*@UPWj)zK7&P2e9X0q4*3URNUfK)JJHT88rIti&yu2YVG8|;tXjn61nt}I$nq8)vM;)W zNw}oJXARsGNM#S{6l~9TDGFAp12>_Cg5V(hu4XHrrJ%oIqc6R|6}m>6!W2LE7G!xY zw##i#uGFvHX*N$6DVy|dKl&$w^Xplew4E7lx~EiOsi})A9_AR~?C{!D-mRcC-9h<5 zDJsg`U(j;O;4$=P0>I*ymy@sfXDm+LHrNjKU&T2P7s6MP86*TYJQgcHO zFig`1d3A{`R2tT-GOamJGCDO?^3SLV2s1+B)Or@UtRAJVSv~%+Sgjsq2$UC@D9FKyI-~LNjAT~*V1Vig51Pz|fYU84I-ixr z)r=X$e9go>Jvru59rH>Pvuz^gqPuiHzdfW2WK~@wW6w~j{8U5zDY)n`piZ|3PH7UM zs`ah5TA3S=hwLz89+j=VUTPy`;24nIEjQpi$QjzM)l$-m>qP3)o^`Cv7n62odp!`w z+>Q0JcW3P$aaU3xF?X@~+F0zBbdReNRUMkn=s;~tIVQRSX-gQJv{?94GE=444Uz{A zGRQ46=6;y8MBvFjLe}e8z&7%Sxq@h(gqfET>-8LwW92Gy@+{15$a{*}X{ihn_F-1= z1zU>6l4i+iH1C7_X5hZYiGKj)aQ1S{p~b;dG9}WOgNSm5&}!6ULzOk86m!SwR9VMS z)~su#tlOQ6C47Qe#zxBb{ne*lahkNN?ame8VngJkJgGhy@4v>WJH&cI!&ncPe!jrR+`kx@Mr=kf)I!m}>eBDOiU zzh}7aaQIL+YhFlpUA!s#6Jzg-RV_+8rSRg&oP2(?)|O4>L`HqBzkw&_Zb3qn%6#h} znK_@*>@?d&B*tsCU(2H`_Nc!)*Qn}@=1Cqpq0{8kpvJ!iO@5Kh^JOcS(V=4Qr`D)i z6-}gbO+C#`B>XvhNK)Xtm2~FYWhl{kLU1&hsJd{gp_7X(XiHUZp@W8Jc4nEdM!Kra z*N%)jPDi3f3KNm4i4>lBT)I_tmue}B@C40UrTXG+6>pq*Hzm|mBl}-BHDXntrtqV_ zhQ+U)#jM^mS9zNIugM>y3sPj=kX|IF?B(8*Y{!o}q3FlktbqMSVEo2FY6-6y)K8tH z*rpRSiTr0vcANZEsVdah(nXrE<2CkcgZ&>WtUpwWwc5A&LeVO=`&2-OP#;rE^abg1 zh$lP7DQm_-#J3eChY!@`z1^8}Khy1~6MFoZ^v$KkPgW(5o<$6(rx@y05yHQX@ti#FPZ$O+g&pK(Bl)xq%i)9v38HJfLEj4|MR?_y-bs zxk>1I{ekuaiMidRMN1zJ?oS`@@T-C=?+7lYq&*1!W~A4aeBXF7h5ij@H~GKUpJBW6 zDz7-|E|NpScFFfxkCc|a+mvZZ0)L2kgvWa}9^@r9_uabZ`)uBSUd+9AftP=8J>&nr z$Ns21|MaKQkB6(K?zw^F9Zw?dC8SNi)XnoSn-JYRs}=aqCG4z9XjLmk1lu2bnGCT? zxtWG(&C|zaYH*;U|DpVBZ&CfU z)8#?;ya4aFe}5##gEdu|`OotLS;XDKw3w3?F?osT6xdo*Q&X>u*W@;hm}C%_CJ-w% zBGVu|3B(dX9Nk{df#Iea`?qZ&_7mHxbghq-qbT);P}){z9uN^mo)RhneyeXu?dD;#ftf ztjMo3l~9D%if(|5no@7p)=zJW^ofboG7;%2BKhnwmKRI?Gsf}oG^V@`rOg;+T4cel z!chewH#-Y^hxJU!_dR})hKeHVW-&#ySvOb%+TkzSI<2c8ZJy44c6I2)n%sKd%hx_E zqZ;>}4XkQhob3jUcm*vs8Dg$aAU0{lRR%F4fe_p1B$Z+ig$cyHg3!%?S68Hd^HsH- z_Oj~jvWB_H%U{m(e_bHd#$2FN!I7H z;w;*44cRY^yPay>upSg@*$-Y~qCY&ALZ+}#f~kz=!}-Eh%?A6^nq#MH>}ljC1v+Xf z7_G7Kso-Gqwbc27wORGhN7J3Ii%wz5za(!dDT%$?%d?B^X}QJrt=)_5FUG7}aC%mX zYbx%Ib}6p=I;OZbTPdzzInGYOKL_W^$jC^+wMgYp^M5?etnD?k%Z|Snq84e&a&vyc zKEJ&m<3aLJ$ornYH|40O31023mQXhy&(j25|E8A8@)jhk_gzoRs3(`l?Koq>Q?3Ab8Qx-FPI%5mZ&n&@n0Or0<+t#xI+R*k|Ebi}KS4@>$N+ zp9NE1e-Q!VZ+tQ~RNdtS-g)#MT4Xh;VN}AZPM3~@>=25^%N67&P(Hi0EV8g&RmR9M zg&2)UM%?2G3A^I}KwCbL7o$vG5%)@Bu8W0(UKgF03& zrEFdB?uofatcZXWask1YD~n73cR-HS*hWdeQz5aC*^RjE1C8 z-)pF?ssa+y3-^Z%_08a-T>;CEMxFhNhRGg=ftY*e3ouZ!s=AJ6+usb&+{_YTl{z5I zQB}R&S$Y{uuur9NsmL#A^_0G9NLol_79b);Oo5N+zY=6CG}&TBcB3M*s%74>OIGko zoi*=f{PgWYQf1ZLVDDs6${t=A%T|&4Hl^KP(jKlO7nZzfRS(6_fcJt}z`oL7*s}a= zl4|F*2d5SI8=l%97~hL_1UFP>lEvXWb+rP@56m^%#u*fcc9lV;=btaNr1+dORO-{XXS5YE-;em@5p(r)TUn<|GpcMfnCCLx5>NPWzSJAcDE(_MXc~ZjS?$JyI0m9uNWuNg}4|N{T+YppqwTX zkO6zO3?cM@;!T4@U`Phv;LXeLgT@#ML$Vm- z7bC9*Lbm01h=8OoZ9gU+k9g=G<*j`7Yf`pGtW~@wx?EmLwyN{2$=~ezX7fl4?|bb{ zfgWoEJDmXH<$9-eU{YO%>wVTtC-WG>gY5Wnz^aW}sjb8tCgg zO%GM`&r(BGX=gno|8B=aZblDK0`+~^(6r^{d5n&+Ls;|)nfe3g_`8dO&%6WRgoF+1kYeMZ(?x`l(MBZ;uJ zSy%nz-;jix%*DMauOGLWF+DI|?4&-77A-QAJ!pTMn{VlxIekGinEs~u-EDq9GQWGx z@3-dnXY>2J`Awr>62FuA%`?Aen%{o%%e;Fdd6wg5;;L~G+`YJma8KZ##;wG?hTDLP zk0(Zc7GIx?6PXd(sufvsyl<`kJbT)p#5-Xv&rlt5 zO-EL%lZ6*`gz##WaJSXD0!Z@uY$9X=_W`$7f8BXnlM&F@PFD#{Hxwr&(yB0NWgnGR zS3`Mdo=U5IQd&3Zw9YUT??R#Z>TS|m4#|YWYPP@EK5Come-gWhtEFzE!f*S>V>7Ycg&l-<1j5;y`>_m-k3)va|`V-a^TZK$yKgEE&nk0yS3;{xRGtB()D`kn-rCJoem*B*<$a1H^Oi~;qFsq< zO>t!Y5`r?ZbuW%ATCDsCI@KKs^?2JI7%I`VEiXVu+;5me;S1)Jy-Y9FNA74Jo=qbEux>%vN_;+(RW*x6K;bi4 zv`=+Zxc09a-%_Rj(hgEoXUG>qriyE7tc9hk_>(ZBA7=GR<9 z5HZtGKN6=li9X#KH6Or(o+@~^|FtA3-) zOA8-Bb?ytDArEn=7f9Geq?F5B6V6pKAK>{=JkrXyiHGH+yB?2JP`V_yVdqBPt(p3K z@;H`h^4mK{mHfslHT^pT3-*zKZ@dPq2axCkgEX(dx77t)22Ofdq|dGoj+lO{d(}S; z#at+wnuj$vChcU6d~TQh%XE*uG5o4(Bb3K_ectE5$@;8HbPBE4=YJ+atS^IUz{?1d z>-3Q! zYQUP8+X0HjO7^m)ur}yU)?T^sd7z61(6Eb3q%UC z3gXH&?Gy0b2EJ6mC3D^T>I}R_;J4~c z)gPh+Y98;iyl%|0reGJFl6+}~L`QX?yS%lN>vDEJtXK8NbWHF;a&1gO*32S{wQ$^P zOCZu`=AjE*ueBlxd+?!Z#d7GhDiH35nJRZK3sPqYl$?3Q3uw#Sx8a3{@WyOq27P_i z7OQ#+DMI?Rj^41Fx-tuH>E|LQ{Rx*xy=%e3TD(?N_|3dp`>U5&J zb#SZ+ZqUJ5Cio&jQ`6*a;y54QPTos}a=a>0_|R$AJhA5@^1!NorcDx|)Fks)oocZO zmg(R?6TDCd2bthN9rT%Cfe!jjFi!^uo1j|~I30|p#BTaCG4qjw}gLH6| z3HH{(i%swp9lXQ@kI})=CYYgvmzvH#olAqd!UVVK;20BpRR`nk zf=dBHJkDTIn2=zZ2_lb@;FTswf0E!;CU}z$jyJ)pbnt2u9I1m{wEk$+C&BUaq>G0S zWy}allgjJg)TF*d2~k-rk@lf1mdN*0_BW)Q%KpYA@yJwHDIS^X=7~po+H*#S@z~q` z%Rc|{gSyY3L<Buj2cJHQ7F;Z;@~)N~uTIKw+09hLVyfXFwcR)$&k^y= z#gi_~aEnT|dF{nNS^K+*pW{w}pCkT@wZD(}|Dye4NH%(b_IEJ_dHELBGnH#H&(WhN zdYjpy^SFhDo{_r?ah=5wFtk)^JZE3Aa=8YbJ_Fos;M9|}zX^Nt-45V!uF+AXZ2;;y zR#(|@pz+y^H7kTN_DQ7ABvL-;I3rfo87Om;t4t*j?9s$d7Bo>yqtqvixVIS84>yB) zp>@)vc>Qr|Qp`)&lj05tSl8%b*cr?l>w3*_r%7N1_~fdm%U&^W(VQ0zY_Hj$#@#ebppPt#p9I#35gCRjkQDYf_{*F4G5l1ytI?{V=T z(Y07%()eBnFEqgh9X!JXcM@#M!6W>h8DC0a&_okIVTd2s!P`ynUL71~f^&7yV}dgX zq6)2tg^2rRz{&d7_s*bBM?;fXa9Lec+uGbhw~-J8v@PAbrM?E}gsrN#P|hPsrR zQo)n2*4!@Slk^@JY3?+{uR(18GC0z2C7qkyne=f|QN7L^$zm8ttMPKp>&3R4CJb<$ z0=u(B8ZuhWf(iULk4AMEMQdw%Gzu+E_fJT`l54pq+^BuvCm^IO#{-DJz0q>8hP4J} z9+DcV2eQ#VjoDu={Zx7!kM7hvJfyl`Ny@&h(D)q*yhd7cenf@}AKz<&=v2{#I)v<5 zsW61sbSEiRxie&U+3SEOE`sjVS$(OuT>8`BOtR|J%Ycxg*4odJU}GZ8ZfN?JS|>Up@pL%%uZ58AA*Pu z`$>K0K^hjlgLEqO*G+nasJ~9}z!6;;kLnaj>P(Z=0wBrNw!~0Y0N3pfVhdudbIg~G z7y08={ap>?!yz<SJN^3%sqO{zuQ|8>&w*m0Wilc%uqE_xT)KL zUhP%Ii>^^eS}F^mtD%)be>GJylAa*@@g3@GCB0{zm{srl5Bc38`8`1blAk1@^84AN z^BYcnWc0DwX3vC<-ih~Hc>5Zz+143)~UXj+Vus* z;Erl%G$M}(7yHJWOQM~)oZs)3aV?(db(%BhM;5QqZ*`^@m`pzbMtw9}rpb{CfTS&> zuLi+o4FXH&(Pk;vFq=wkE|!!Z)G6;BreRgU{+DEln#A-Fm9*LrQ-6gd9WMeooGUpL zl0%{^ujrtf_oUx-V{}8%v~;mC?V^`1JEv-Pewos|X{MNX9|N}+sg(-Z6!35fndh1^ z)PY2v5nrPGq7BBhFxW@I#+M8fC6vVqW$HjCu`7^!{4YgMD)(@%gha=(<7`@TFaMfR z>s~vN@e;zYRa>IVa(eTOt*ZWv(q#S%O*_0UA*$JeDj5fbiHdt7Q%UE)jEEC_L|N7_zQL^ z`Ky=5#jVHQQP%rJl7gA-_jvf?Elf(t0Bw3Hoi7mNh6TX}pu#U8PrQe!&dHew7gTn6 zYC?J4eKl9pgUasGo3AIBGc{j9(N~IX_7&|=XWIiV(3Lr8vYbYO5<3K0ey%)aFuQrI zg&Vywt|x);6)lo-S#yF+3-Qwugp&O?9wGQ@-YU3)?d9s=#kL~e@4|=9pK(E8bxN+w z11=4Fm20P+?TvBTauwCZn{B^DckmhT6YrPkdhHju3co-&eE72RK6;6Xpr%PKD~8M7 zyosq=_Nf07kBrUt;Gtri={GjDjL=9C1uhF8`pb-BBLrM>fffSR@T-J?G&7l!8@u3< z(XTPvG`vQR(bWou#BVf-cOh|gDic47Iaf|F&f#uHDbG%;V;OGFb4G(6hIG`{K@>0c zd_o^>x8r7> zn&N6WE5((DbI{Lx22Jk@tVI2cdmmSHW{T?=Tn%n$56)JhD}$y3xMzraU7r+}2e+el ziYp!0u4jtt3f$|s9MVt2!qkK3rnsh~1UeV@DYS)zF9m)UZYyb2^Xod zPk|GmxF^MUTIgtTaPn^|DtZ~2txj&;x=mJF{HVQ(;@CT>bGMjce{4Sbk6D0 zuHCW6b?tWi3Ara8MUfmlDLH_@)f?1J`_ofgxwxLVe$<<|3-FiVuE1T7y9HN^Ta5b$ z?nT@N+-}?#xF2yTXQa5YaVOx;#`VVqahKz+!`+Ol!7ai)iCc+Vk9!;UIqnCXi@Yt| z@wl^aSL1r}J#XZ9I&K!O26s2^0o?zFe}uUI#66FD6}K6;8`psQ7Po=#`3COiLh?R8 z#g&D7OTKY>;vasRt^tTI?oUvpryG)#L_|%e|APHL|N9eO0Lj3V{}?|dUHJ94rK8O2G z>gZaO3M0$&Jg9S{Sy;#5gJ$6zPyFuc3K?-PsY9jkCu^3>0JT@kMW+t}_76@@4;iwj zc~D4OD9d_YW+OV&(qLY}xE+B!*Q0p4Xs%2Rqm%ZV#j(vVv$i3lwQBzH)#e5wp1vX= zDE}!id#y}5qGI%(*l6Ioop+Uobe($_VH1e#J%0Ol`7I0BoBZ~vepDiR3xRC! zcMTQuSMMnXwNi_&pMR7^*EVM<6tThF*QsMPp0Bo_+Z`N4hmn9ZDeATysPo(fH@`feFPJ_k-6nkMt&yN5vzCiJubBNqAO> zM+BoUiAN@#*To}~&IUZ(Nc78_^4px>Cdd+(n)k{@AD+79x+10pUq}gT3NHr0+!@;x zUTS=SBJ50AVLC7Zf%yJIRJ4l1s;a{6!327UMJhDOri8!#UA{=5_7&0ba?TrO@)AXZ z@!_7c86A4Xs(mT94V}cid@C< zx)NiXm=`yuND`{5=Ad#B@t_ZRiQM#KkxgHIv7hP7Re5DVv<9t)zW&&cUNonymyfe-z6X8U+^S1W&cHddCe-< z#~P~xiNw}@kJvHV*)W}CWL-_u&^_jh@hP701;dR zu>>#I!GOUAb?{OX>`$fMEEiPryMQYa`vUb}r3F%d^4SwI zefH$6lGLwCQok#loMz3%5T;~Qy|4T%yQQBC@aU_!eUU)SpDKcq^Q1iQUP(pB`vAof z+AJYq`Em)ZCWMsK{@8o)6K#K%CN}Lvl##ics@cR~ewxp@8$udjBn{Qh%&8xM9;DIE z3^4Y`P0>y;(QIF}%ehQN!}dTyJlgIax@tTUZCF~wpIKCIN3DU5FZF`hhN7r7=S(VH z7Ual7sAzIJUEPh|?zELC)K*N_SrK(M=VL}Fk*7#q$u>#qPOjt19%+h#y^vSIudMVJ zs9)W2WZbDE%uJ>(;=a`=)82OHsWSN{Vsf!es2Qc&T&~oyml70(IQjZHEGI-IFh6LI z$StuC%X(n6*FL1T5%!O0#+9HfbVks=ta}Mocu$mvm+cWT zS-h13aB8DByg7zCyd*GMoiTM>MPq=YE9fBM_4(d$thz458bmG(Z*@F(2x}E5CbQMaSA^Ms8pr_H06W#)C$&jY7)rTZ2u5t5?D%ltbgQlSBQO) zN~!~8W2{slC$GHycnNqlI&NW0O_^aCNZ*wjtSZufCy;ii0 z%VO@;b5J2hEhjG-_=Er>?o*X|&o<;+&Iv?Q=K;rRnA1)tJKp3H8zVJTt@+YQK91^J z+nl|i4)}9YLT8a=fuY|Hkl^pvXeR4)&~32K64a%-jE#rpOqRcNLQiST-4gbKc7w2e zD~WtcM)KmVM~XXLr_^W?zLwxCs_{np50CV61?tx^hj8qx_1}VahUi^)Dz5%Wtw_H$ z(efpgoubN%B=cTTTc zK;OD&;Ou@WBYghBp;ocA-lCo8*Nq7O8Vi;9ir$zW5Q5@}Cldo2p`yemm=bfJG`lwi zZzuK#yc79aF?Ti)W?$@b`0P3<>IvKd5Iy-`e0kwT*eHmzaYhpxCnT>gH9w_;Mh*$J zHvEL&h`~^~@4tyZa>zMH#kZbCx@I^}~SePRfZw}ZQYr6K~VCU_W@nrI2gXAhMZT!x~kN&EEFV9T17 z?45a%vsqMrIz-n`2inkoSwF=ihYUNaeC3}1qJD^fbp3>;tGao(scu47t9lumR4*eE z^+L%{nDwWUX91$*T`BpMs1H(dE7qlS=;OU|n*#G774+te}`{&jm8 z{^#;q)nfKX%G@&^lMP?IX&*u)hGY1VU%-fM``Z^EI%LAPL0W$3jB1<0-+cEA?Rcx6x|sbWYX5DuRg^ z+)HzA>+M2)yeT7^(r#cTqv$}L(eI3kmA7Lm#O$6g{X%cG`;eR-d*!S;UK^ejBmw*2l<=o<8-NyJgJYix;{!7-*z^(ka=^Pv*$<6z^x=No5LxbD^1}mqj%AE za~WllMY?yD_pg(=GsuOTZO$+Mz-nu6J2mb(9)rU7{Y)ttTrs84ymmlaeLz)h z8+`$g9yo%Midk*B-E|3j%015cRrzRcZ%oT^HBL^D^^gj&+XThp5$Xj4b7SrtKq~cA zqB>3=l|e;+s5A+Q|571|^C~b`(;?d9d=gehydzj|k=#h_E>CHnTVqn-kFcAs-fV(giY0fe2R|2bSI!} zQ~%1(=Aivqpmt?nFi14QEq3;_}q298Iv;e&0C(mNDgiNU-ek zu|E9TX8gP(5wus<;VZG%%U}_(Uaa0vutr2hcJ&US2h5#G76q~!>Mox#*LgTsF2%~n zxs+B&B*`dXzvl2G2Hqyt49T-ztgn+cW>t#-=|Fv^RV{L_1NALr`FfG8Ds`oWZRoDyYRLf_14{Y$1-^}PgTx=6e;j(j0kgi%G zHlA}zSdw=1u{WFEc987IA_HaF*_axjJy2iD5OhZ&YNv=Yg~$%IPm}#*qU^_(NugDr z5(5?UE|*DYyAz|MHKxCEi7TU0eJf{eS1Ow>yd-Za4FrLjw3B3knrdhAVUCuEmoms8 zLtDW&qJlV-;^+OK{WQlkt^yPWSn$w@O6<>qwOn1U&Gg%ce6@Z|e*7TUp2~vu8~m_~ z`cWQRzpW;icYAF~WlafHS#k(hqa;Sm1>Fx)b3T&G<++()?Tw6F{stv#pU7XoRZ&UHoV~tNu(GQo)~KpgWqOwdT5*oFEOpYI>%8!- ziJYS%BiAMJKZq=LuA}s8#4hE0*-Dsu2>ek4Dqk}7K|byR(4#?XCgyfSEpQ7%>=YY}Oa30ZvVy__Lmr`uz5g}>#O}$3-g8*j0>B~$2@s1;kOGH)J zc#mPKRDI@HF+U}J<}6b$v-|f#wpc`M&EbY|Ot+Wi^sHirx!wb5E)NqBFpYFQl?d0g zs3nG?gHX&TpvE_`PuuLU&v~3FGv^AX%qy$alo_zo=jX+b{9KnyBY9{sKZtZ0<$|^T z6^vwo+A*tGa0F{-Ru=5?)y`b3=gbLsX_Aozl+9N&^Y1cj)c{-Sw?8BNIP^(A~ZsHVD2m_?q zz<}pT(Tht!eZ{B|X_Ct(A?YrEa-Gj|;&E-_Vm>UFR$AU#8OofHtg59I^@AR>0AaZYSW+%==jy@l)?VC6r{Wfy5H?m1O~*iYT?_u!~~^JLt#u(8*q8rQ|x%c{*FV_YHX=spJp>-11e8 ze-Sb6M1Rru)6T-4tJjVNChd_!U5*dDJ^qk6jh?pExyKFbv)2hGAQG>y{6hR5{nNRY z+Z%jW`%|nL*0f>{@boQT5;{e)?x3`7rw5X7pkY95U{a#kcGM8 ze%sYe>ek^`L=Vzjq;3&o3RR7O>f^;^CcV*(_cHvi;FFb7yL$D_*7@lh8ERDf6q6U& z3b{?N5qH~>GSrq-IyuF1Lb0+^I%w+8{-Up}@E+9(X!_E$B++0*twwpZMyKnExkn|^ zeFf_9Yd=e8v#R8ilZmWdd3bqRIp!2A_^jHDUu|_I=uQ4*{6%tbAcUdWthu$32B`f- z8>VHIOxi3pRg$`0Mr5qkNO^Q(h)QX=qZ(8rJhooSHRl{P7x7{bnCIm!oa9-*lO?A`)nN{3op)r1vH0P29G54hFm9Hk|9*0ksj1e^qa@cV^V=1c* z87`Yv8%fq@%=yPryOKJj1*{)Ea*k`K_c|dyxQZ?_TL@8E$$m3>o?9+c;it6N{nEz+;V*u7E07;`ul4xm@@tS1X=6m*c*$B)=zC;++%$)eXAAL5SV$n*p; zB2)^Lq39dD6UED7LuT+BR2!e1ket!XL+a(F3L#Q`V>IPp78WT`bc@7f4lu!Tia~#o z`)=i2cyF6g!lAY7dZhZUyO!#MwoOg?!GZx|Vn9Scjd)W;9a4?;h;`tHSxd=(e0h`b zY6*}p?>gld8IUjUdgT`>5G*S{av=OSDt}AmpX@ATd}4T-=n9Ee&yzvDdMl1(i00ke)WOom`Av%hv2F*%Pw1+~&yCU#gv{!8y0^9VWyVUt{AZv9cphQV%6kAcT zFqI#352MU_P$(o}u@55mf8~%}c2=ya)ms2EHi$KQ>92)PR8d>j+<$}jMnZXP7-&pP zERtd%=Kg(xG{QrAwG1@o{sssOtg4CX!y}aPGQ9)er6~8rDcN?^8Orn6`sp1BOHH8$ z_c%Ds>0dcqQued%T>vLKV|I_>1i>%}?2=a_-XG++zg76K+p2DacZnoyR!ThNUqnz+ zEizzT&nb?_KsjtsK(Jl8Qjb{&D zA)T6xJWOtCVJZV-Ux9QNU#>HVON6?DGDsslvyLVN|I;sk$>GBCcOF_5qk#VURE3;n zm5{TfETo9z{Sj}P^G<)&{LUa!V?Sb_Be7Tfr`Xnih`mV1P9u^^)tRnh>Z%tjQXgE+ z9+X!k;H2^R1fS&dK35KBh!WdJc$@)56E%~A)|}0Z98@g}$o63W309}vRZ@<)S0(^$ z04OUO0efZ*%LZSOZmn}JK^ebb3sRTD$emQHHTQQ}o=5sj&f*9r(r1SH>0inZjl|{^ zGHK0aG56W;|?~zeURa-U9w<9QB-=CRi%)NO0(S2+#5NR_zO&^Pl@+A7% zb>K9keKezw6vx^5@B+oCC(h_5sQ_sTPCXbHotq$CApkm1bJolFp1UnK06lQCJ;64ZnxHF;3&7+us$V$meZ;;~sCm;u}3_5h+yNOAk z6rtZ&0d7v*Nk7voi=fJ?o$6>8OZTSJ>z+0ykz03Y!ZRHNpLZyBbh4gI?4Ls;8-Div z=7SfDCA^aoQTM6Agt1^0;}dC1MWiLLvdIX~%+(c%a9~A=-Ew-4Js3fPdn|ma(c(&a zNz{>yIX4C9lnOx1otxgjN-_0+-TVEG@!sEx?8%XIPb6LaHGk?SAMdEHKjO-xyMC7Q zL7_B9v1{@B5EGdpA=6n49N>8w@f06XDK>TLbP|hqYOzwdf#`}0X-pxAy=-~H8?$A- z;|<4BtvLm<96*;fo{uw3l8p5EFjIBOz3Qj`Yy8le7pTrmADQzJf()X~PDJZWG`plS zR!{FPQoVcHNz(nJy@XPWnzw{FoG>5i@-lg3R?n4g9(0~UYTs{+Pn27VRF7aC4C8Dv zBHVk@Z?_+!UPXgSCPvYgQWGU7Rx&F}-Iif^FVq<&A+w+8I7T`t^W3rH#KVd;=C<&v z^;Cm=UDi|E`l$Vctckp1#>qxP7P*=Fj4P6!aVGP){eGY}MU1NzE8&+rQIfkQ;Z1{B z(?~N)e?y3CQ#}VZrRWWGmwZ{Qv3)^4k~l|VNgw_;7xD)aX&+dd5=wU(dur*`GnenmuN71vVWvt4j))1Yr;G8uhEw!#O6-71_+TKUN z2c77TBEHu3=-hO+d;yl>tXEgHT9($wHf<%>p zs|U#gfZp$@=Pk0%4y0~eoei96tG1F~E1M=#seJ9dl~#6Ofz`fvftBr9YPI(+CA@<0 z3c_`S>j>{4%nQ1n2Eq-5_Y>Y92!E4O{o<@>Pp~TLMUe zAd9pL;(~R%F)p~V2r~cAd(NH7gvBnuK7XEP$i4UM?|ILA-t%t9!+`u|59?Q?`pqxu zXXZHsfqPjKegZ&ZB}8AXn3+4>8Jn5AYD8W}S+l4KOC?xgdD@&PY|!WLyw3T%&nkvWUa#%hOd8yfw;s@29dO?;M%-kCb4&EzZi*(rF*}od` zwD`Jyjs}lmRYi1hdJ#EE74-SiCVvgAxp*Cl9rin^r3cJxpGKpffhSK6D~1awp1%9>M;s*{S$ zDO%m1PCoH7)ydB8Qywy?(sM|^?SS;BGP>3`c>nt2T{|RfQhEu~GbH`Bv%Px36q-D` zYm=$|)XT6)-}BQhT~4LDOG$jUYodaGay*5kzjQ!)doQX@8^5OC0)Q<-TuqZ zf@dZ`V6~7Dw|LVm=c~;BB~*JSX`0~nv-2lYZjlrv*p-yRv@%zcqH=Wshu)vW(l$?) zP=7^dmBDDCgpj)_Cw7WIKASV>SI<+IL+(#rvkbPA_0g)8fZH=%_wLC_IcYl&BvXv3Q{zvQtWCz%wDu8bxtZ>)f;|~G*)nC~U zTqIPYxNHY<`GjBGi042n%ypinqB8avm8*%cS*5lEaTA%~kN*tn1lzj_x!}dZdDb26 zzsv7hQJWt*+TAq7CEa500A|G)Bg>bUZlXIS$zyTX=bEXj1UUCD>FYgwPzgLf`c zjXzPof-8fGO$8fGqO7_id~m)jwodKuGZ-Ty{?&z z4-KB*Ia-Zxy{DvAwuWYF>0}IJMijb6od52_dsnG8XGj(!3cpg(7};dShql z&Co5-s z`Ao~|F!G?`g|wzfyUg&v+>fzf*Bdgtl$fL1yp){$*pI_E|Hxjvy!sur7vF%!sPx4D zU>^oWHV|50nwDej1sNf34cdGE3uqndyDRh@j}VY>kC|gU%JY z-kW}uYj$o;cR|-aqLwdtPjGdG)%!A>0%%w9J0g%$)g~L~?~)8?Q5q5M9KVX9y+v5R z^+eULvX)OQb+lH>Q3&j(BQlg&WgfLFVAyr~TP1@dRjtA=S(W`SV);UE@JIDRHPFQN z8LR-(U#LRiWh=PHgir#j!|gIwf~RjaZ_eXxQNMGKhx->L1t-g~-KIom?8}T4;3}2D zRXo+X#&e!bj}teP4b{gg;}}-_#_BCnH`PctlMS%-aIvPDbvsj*gFX!ZtpUy{(OI|W zpmjbrf)gPsWL2sa)AB?@OsYCd8_#)fM^#Ck-jWS=)?}(TmiJVKHiW~UPdqd{7YE{x zl~V~4^@lknAW?rSD=AU02S8XFZ0C=Ui$4g$uX21P?sAy#aLXww9ku2-{+e;MTcQzV zvqR2Eo~cR$CAr*y#b~^p4P0CW1F@N#L$ND2gksmVb;@Hhy=E~gl`MY@AQG0hp4^DE z)bnc9aJXo48o!$vUBj7x6R9fVHOoZ<%uCCcnI5^IG{zrh-~u6WA#TN0ljh~3+&nLL zNuVQ^*(z(62|FziAHjsxk^Kncxje7y^=iX-&Y$Ug)$7`5G&}$R@F1e{d>>cFaeL@G z>-u7jAn0p)B8cH!xvWZH6%UmL2{>xK$H|o|L0A#Ji-?Ax5J(3OmYI_g$pL8XT>8hQJ|=JLhA_X?kJJ=54Y3rAzd}Q7mHyPM*ffT#Y;y%<%?*btCXJgBctJ`BAH=D zPg6Q0cEjfWqlhHVsUMEB8{v`q92&8A9N=&N3iRhlp2wqu<@MxcT zvBdHS5BHgq@_gpHkn=scG*!*z>)}D%y3uXQLcRR@8PD}aHCWwCR-bdZ*VR^CqGqy% znOt7|7R3HfCrK|iYfCg>H=7GMv45_8Dx)KEFpvh~1G+=Gw%QPNKbH|cTLaTu(&mYK z*b{%KJyCg-0?&Eph;2T%7lld{7Fa7W6!FI=mag(GM0!%NyBqV#Ab)=fV!Jx#p-g*x zAaY!Yo~M}MvD(>^#rs%+c~g-M=1zcm0kU5KS^V6{M{b%kYwhB8e$;@8GLSrS#o1NXi)Z{iG#E7K&-dREg7sY>_K(Jv+Z6 z(PIv~6Dz-`aa2sr&NMwc*Rr%TjQL{s;)!3DKwq0~4nEbc+)L&3n-=}ij*Q5o9XBW!E3fOD=~tD#j(_C|bWNI)z9sz&c0aAh@{f~M zbIW(?=2r2V8uobI+&(+&qogrx-Q30!<{hWwcdPGCAH@T9-r2g^?lz{}D6g{2I_JOL z!Aj#|hDeprmOEOaFN#$qyE@Yp$pVox%bJ_yiVb|{vd+795Go^Dr3uob$&frKkg{AWv>w})NWf!Y z^TeUY!{s>UE%hEQ*$zt#qNBbW;)q{3M#!P{H1-$4_$^473Obw`W6YDp#z+PMp7qjG zZjZy;1dAYD7o5knQ4dC@O%29+_P7H_^1dtt_M<{ES<@FQOw(M0C@gyT%;Et1hFA-H z4lumtP`T(rT)!6qMX{r}O184bBGDp<0By2T$H_A4^gr{OXM4;ql!3uIajqkK8`+Iz zUkwzu#)o;H`w`|94(sC&a+Sj;etyb{^VC*_i61;AShU8v{X|e>L}3UE@OZ)OZv>at zSU2-A-5Ybho%ssBn>zfCKYoX5#mh>UmOXPn=Kp$uil0jqpbFe_z0yx^;mwiF^99BT zy}tNM$j~H|fvp657s4;bY%lS7zxqK0KVMnys!q=mz(5~$wQ|yvdef@RC4KgVu5$u)qU5XLUKu)7r2D>&*_{jkT1Qimg$Ds5{O@G8?&^_!L`HOBo!SKFkgk;a@;sR1{e-!!1ryW-yV+E!=z8r!%S~D0q z#>`q}bsVRcBV;XnhK^1D?O*ls-C!rFrCq6ekwY(J6+cTF9ihI9)ach(4@hp7pd;L$ zkjQd9qTeBKSz|Sk(tbREA!u9ldqTW$uOceu><4FXJ&Sqk!eZJd<( zf-wh3F6YL>M*}t5*McCaS{%Nqv%3>59i}{(af* zo$PST7Jc~>@MG3jh2$}%2I36Mhi!c5xTQ;Fzojx6!Yh(=Mf7`TmJEB)E@r;o8mRe#}lJ-vS=xLW~S)!vS;y!ii3u_Z|(|KzI8d-BxDPm zb-{^tyCJ@%6U(1Iron$E-_>!jtoh&qo@?h5hm7C7{J!8f5*W+hB>r{Edqm_1j*D4v z*@sG&lf=N?zSzmK^3AvQ(>G&>^SO|!_15D9>4&fv9mE#M@yjxiK$M&YZKu1vz&98l zj(Aa`GsG^+Q`+bt3~RrjtEIM2&^#;X{5lvL$)T1ToS<-1%@s*7gVVq>_JB7PRog5V$9x>qRCJO%sHSNt<6W84A=hgx0_LdiAhWqfPwx1ui zlDEj$W8y`bk|st(b?2woQwa0?zmG&0)n=+ZS_11HIR0Zrv5Gx+h zneXGfGXD+6O7T{aZCxgbT`4Jmnj``!bv_@jWNpcq5MP)()_j+! zyTa3^nvgTHCwg;MM#S)#&X#TcTXr4IhFRCqi+xpWy&XhV@|Zu*Z}~h^4#6wJGAx{P)0F})p2Y1!dNXSY^lg!5XnijxL&LNhBM#b1Q)+l!mP{E zI1SVj;rC#QiIj>_vysv8EWUc1u7V4Ud-_>-ieC`6ops}UjfqIl1XQp!%k^FLQmQz; z5F0nD_;LUXQ;fz|NsO8IdHazHN2&_35X=@yvTVg#k35x4m|z=9wy4ehZ2BIyg?#aR zxkH!+zrq)hUD&$xXi=z3yp*4Rs+Z9enpT*CVh~#ZOtfUA&339^QW-s$4B}@}a15Ol zEIdQ{i|xE@U$;bOW@Uzp6@d?h_a!8}Ms%B#J47J*+#GXj-iD~UE!!$($E)OcGr_Z@ zj$TEZcSd*hsVzZl4~?ay+1M}ys}a-$iEW-GVX}1e@hrJQ{&w>$5i@YPe3Lj^R3yE4 zjKQQRk*FV)WNP7VGsE$(ei^i5*uNh9P3GTkf4o>->{(K_28wF}-)?)NGcqBSPZ%*~X}Nq*@F)RSczl{pERhX>-qC(5=_KoNldNE4LHug*>cLK4mFu7v?DLGx|M#iNu3J^|Q_xzQKANuC-&Rp8InJEr1n} z64b1|PM}nKwTSxxkC~szet)ryMFv4H&KJikp`w*^ZGtU)SVCu$g0Uzk6AmLn&(mh> z=EK!&J!zkT7f`@PFTt$4i|WY^Ubz+7l<28loZ1Dy3irn^q8LU$n`SKb^j8F+N)}iX zevIaBz8%RSCuCaqueli+%tok+-v)0i^r^Qg^aX#n^Y_~(Upq%2-)4m)ry?{DxcuNq zp*$gdb$%U)`SUark*mI41kHevSZ+im5CZ{D1P8q3xk-w#j<0%QLNQ<{pco@TvMsU$ zi_IGrZX9#YO;+-pRMNGEKcv?H6D-MCeplI*{E}oZ@gk9v!aXIC%jdT3(d{dcOAuFT z1p68JF{jxvGCwQqB+eLKg)GaJnA}w`px z1&NHNS(J~?##kd4R}=Qa_144v6sEkxl9$(sRJg2ITH$3#zRhMyz=qbviZ5$gq*<*Y zWP~sCnPVj|+0RcEcTd8qQR*mC(wVc9>=K!LM{u)EY|_r^v`L$DmTEasFuxolxMPCm z)o#61%E4^?RFizd^muckU?Lec8nwU&k#WevwJs!uFAtMjUcI~`(-8})1hXXO=nH9`L(hXs z2qH%5ckw|u^?+XB`3lWnAa_8K!l!u(nPY@0r6=)S zZeVsVIUE=)luuDZ?O_la+)M4IqB^@C}|EaaoY^a>6i@7pO}4%Lo-0KOaFM2l(V6gEPT~ zT7yFd%BbWiqj!+)OKMQzN&PXKlp}4MFfUP85-`t){1G@X_bAz2sG+Ua2$-jcI?MT~ zRNQg6D%sJUT|h=8k}RnY#BR!Cl19ddsH;@~90qdM8F>h$Fi8^*8Yg>mlec_ie?NP! zlo1-{R)&CRS(mW0C5VgKEJO`qpeP*VQjJ+`z^<1eK)Zwh{YHw#3vRZf@_a${ewLrA zO@;Ch`~NeQ5wI@~1=L}G-t3(;0rng%v1GAoAs#LtJ4U8r;hy)jLUZen8qM#ZW`*Vj z$5TY|H}FN}wu8ysX6O8QdLIzEA@#G(a#s$KwGU_okCbpTwR75Yrr5EyZbfA-V#47) z;EX@@VG6#STXvx_)|ZIBW#nEK1K6K0#HmV-`4eQ-zX3epaCy?9P_9QUxzJ+<@6Dno zvtcgHv6>n1LBt4KU(73W@X}MV_MZBQTTbh#HZ1i>v zPvaHF;JM6-A;)J$Lj7P6)>-4pq=J{`8x6k@o`pL-x9IXi_bcCr@`Tg`D+<<7fs{Ui zER1!4E$s#cWQ2q0hsPXK$UWh5#5STMRmbvMg!PeA^~r+p#|O=m@t^m{U?`hAj#Z1K z{Y<)`pT1$3B7&W)US)Va zpyp#ACh$}t$PNO}x}P)9<(oAuPGjupu*?J}H7vKCkb-3o1t7#=VmBh^%BgSb(%Z?+ z>(b*j)ZXV+!F+(x5MaO}a7NZFqM<@{I90d^!6}yA4tp*Qk!zE%>DZvrQOh^g{^w;G z_TQhAi(g;VE}=sdB*)ic7l-~m(DFWVI?fJ1%L_Tzgj{QkhQDwnSI9LA2JLR10%oQ+ zK1`paohw4IQ4pFp*>GCRw&F~Gqt!iE4QBFIEgi^bFlDdD#@Cw5WzRg98qCl&?Cx_2 zr%(%r^)j(HE%pcf$#KonfaQjxD?<*O>v&!eMf|J2TZrXKABpXrPz zr7}w0&pxi|o@nRoVb^U-CFj4Z%X}?e>r(mN-|5b5CWT%EsJz41+2xR~wwqn;(^5Xw zGItN)cO~@)&^3NfXTHc^i*wxY)Q=3l31A|_r!NM7GwcKI?#9}f()*VZ}4(E zhTr*W;(fTi5Zk<7zVGAHCYx4(om{Qo0$IO#A#+es(Agdkv@6?cA3KCASxo)_LNXA? zN5S0Xia+|Je1#e;__azNQUn_#91?Xhr^T3A)%IMvuLViPpIWNBpVQOfbVSbglwa0g zO=IA%3e;c!RzvPyMkO$z^CbmZ#$?JTvKx)3bq4|TH2&Joe*=l_hs*b5h1O%L!u#zE zA-h5kBNr3*ki&ZEUAfMq8DOJ=%$P3jcPB#*tmDb5qVyKXTfW_FIEgs}?Hc#sA5D>O zZ7JGkybAX+(J}p87-Jz1uh~<%k))6*p>Ff{aU{&8MO;e@9o8`JpV9pMmG}+_Q*(=> z8bhCg(=CkzcT%$bJm3k+<%V2Lm=P@_YrxDcLKq){D&!5XM-Uk%8p$|fcZu}nFfynO zBtsZVXG=hG(I)kdcoTEZt(IG=waC^54c^L9XpoaagChkE@&o3uB3!2x8W7-SJ*a@` z(H5aqn45t5zYcRcIPwS;8m>0A$NO;zWF9@D)VX-4R=bZ<;Nt4CV@{&?(} z(!WJHda4y>oc^eq$j!gen9(R{V1~U2Gi);Ti)4}HG}YPp$C1FuU$G(To>XojLNE0VF&0WIQ!0$a%~b4LnqDbW_<*k>)R?M=NQxNWZ=@aRU(SK^yJi3< zlI7hXQDYH|Bztzb?pY`ONg`erhzI&YY1p4W(LM8hV)v}>46jM#1rnK>mq*2OdkUuv z>1wM5+lNq86CaB8Qbjtln7fw+W4{vy##k(@PUy}i-;+MGMP4z9exu3vl$HI@-VXxU5n&+-|DDg3Ih)4X0P>qvxEQKKkzO zCr5vhnwNr$HrS)@LBSsz{q77k`f5ZFGWxf&7(JRY8GS$|+mE?#T~`#uX7m6Gv(rYw zoyn0CrfCuZ!iXm*%s6|z3eJHntyDG^+3JkiLQcQ;Tq@g~Tvl}z`C|s zHOCwzl+NoB=*x_Cde9#^#pp?41#FeI41^E?V!XgQQscx*GIZ21HMZ#Z`f9QA_tm<5*VGIzd%ZoEvwhiW)pVlZ_hje@9i*~p z$;xU|mHk5U9%qNyS)`GrfTbmK`Z$2axAAw@zxhj+k-s+Ut^P>7a?$FRawUT}Znt~QebG-d z!zbdZ#(lNlXM~UTMC%Y9cY}i{2=`HZJbXP`ETjnPfGFzPsbZHjO{~+V_va|hMC?3* z({EX`)w(a2_}t(kM{pGnui%We0(xBXI2l=Y0VDHW{P4n)mBvt{7xiSuJxutEzfp^5 zD{c}{rpcnKl`Q&tTNZ8Crj2;KW>%))H3eOm)xQ$hc)R2c3qr&m4-PrRyFdDx6^^gv+{?z5Fn0IU@WB0Kf}#=%yuobTjG$# za+SblFLx*CR<|CmU?a!RhkwXbfT^Nj|1~&H%W0bg1yt*1N+Xw1rn3=XC^8*^jtwdf zj}o&<0Cg)>N_~Dx#C@MccV*Xx^j~Aa&6Ko(SETsZYvqHI^G#Bfb{8Fh6OF{!JT1I> zBNYtcC^9J9iZtjO4aKPnj+G~3u8UlZlQCLVz^|ma*8N1r)$8*gbXo4}xm7Se`a^f) zHt_|C{*Ysb(CnO8qd}QzsJ^XG1BDPMb%SWY!c)_nfqc-F7pBEi}qeknuuMr0_@VuCSI~ak&lk~`p-XXypa`?BU*ZB>ntK=rtXbG zXEFD)dOD5+jW|^myu~sx_YpP~IZe=Pw{8GMl}T;E!}(m+IB`M%(IGAb7xA6!kCB}( zRwb{oNV5pSCbP9G?tv34+n=w0(A?ML+b)mXel&_6MA|sQZl+PfQhhCdR{3^Nde>J0Qy9}ts&WNk(iRAl6)*=Bp=Ma=cfO^hXPTDBeQgR4VEiS16uldfWj+56 zSfJ!-;(1^?Wj|WNQwS}l+LKUZKCG%#3KPZY9~Ka)Mxmfqk_#LY&sPeQU~K#bbDu~6 z>!i97qBA)!SH^_o6g~Qq`bg!7O|0w8T`wFd_lR-&i5_-UIPQ-(Gt9Zh1S_*%QXJU_I1!sxj zl2@qqtZl^0=c#=m*@-!|LErw=4yNj-6QORZ3+JmY?1}DjPS1&tP&DDh1G=I5aF&WF z3azYfZ=_9CTAZgbYmOW(b4tHa4OzFPKroI*IxbNeKa~=DPOi=KFLUf$;aJ2gw?n>F zeU3_9t5OH4RG>C#pq)BUr9Poj`-S_uRvYu~S1skgW)Mtxek4&i>5d=PK1u??_**0E!np znWuNL(Ifz!MP!yua~Q9nZ>b2i?gFKSTDfJ9b9dVBD*X>ik8(gxS%`w@#P5-Xq=>K_ zbpqyjqWlVsMl!LQXpd{vW3AdP)DibZpXuwgih0yd z9jsD8D5acv&6@IFvYWRHme0v?7>%O#@tLweD8%qvXuw2Qo zb7WP4H(7i^O5Q01zS2(U*qO_1sjG5qyOGIsz7rzdY>2EPlU$Fa^d!ViQsU>=tS9-* z38_@wu2kx3v{hKMBxnJ4O3QWAG0COW{tIOcQG(c~=}XmC+CC%+vko>@SwBkuucESQ zUe*nlB*n%4XSdRF{1f|F@v}LfZA|nT)8d1ablCg{FQwK_A{o<(sVrnM;LMUvV4b+e zdY1$h7rNjoi9y5{YezC|xh_;@7g|pOJNgi5<|B|?-LOR`6jBDzl>6i7oUH;G*>)$- zkSU-HeIAh~^DK3mACsqUI%2aZSEjUCcPY`(i*rR)w8pxYRxqX2y>rt8SVMaLg^Iki z#&7uEv__I8-3;^syXa}sbBrFt7Y34wno`xU(kTRziWHTK%-V?_I&wB&VVn&Lp%% z)1{$xv^~^^=pb~sPD6}d$1lpT-gqksu?M6o;*-9t0W*W#>_k~)BCBX9i)9Bdv{p)B z9k#@}Fu9%fa7GJMsk~f;`vH~>FS1`kZAvxNjc*jx8*KyR0n!!dx>}M$Sdy}6YA{;9 zs;I6#z{1r0M7I=YaVjfMeN$JWNl&SJnrIwTHtcS-UNO?KeGF`V_j=)XQ}GVQ*;aaP zyitg3%m_YjvG=zv)_giC9vkt3Qk)D0>BG9)tH~p;SM!R;intSM{{wWmDSWYyDNGsL znAl$FbIwnA3MzXBIZUJw}``|GXJU%^OHr(7lUfSr3Nxf8E=T%Q>YA25q$&2p}tEVDLMc_^xL zBvjU(HCsz}CDW`=yBidJ?HbSj`l2nIRJN(v&;IjjE{iN%iR|(SuUVZVYQUjEWyr^; zJNez`jZY5p_aPjXO8NVw;Ba{`79k3$@Ai=ETcbf(6Nx8&_3hrcdopIP@z8VDw}quh z@ba+JuJrrkw>-!5*u0pJAsBsq&za+&^T&IyJ#Mh%sU&bt2>D*#SR&{6-uzlVxxeOd zC*MD*=o{`WKCCTy@WItzbzJJlp8pWkFwdr2m9o%P4d|AVi?m;cnxkU?a`+Kw_l%%eF#3HjCzZ7dcVTKoL&{>2R6#-3f=TbUdnvx^&_iWo6TGGR)WsX5|3<_wJOtLd#`2X{o@Ul^I)_ zv@Udnc#2-uUIg6l=7KIJe(uU`3?ZFAfu+~+0$M%dAqXMQzT=-~fI$%NEoFoeDfh=b zZhrnLt)41J22T_CP3CQ?dYi^u-IUnedMO;6`;`8(gg>#l&HUdwcP0Nz)iD(Yh&+l< zip>>nt7+~c{^#4n@&}Ah6x`EW5QS^+l2OSzrHCNSOQ#WD)C+T=@n|NDc723nv^v@z< zaHXZ?tF$+WXBQhxLiHM{AUORJS4~h=;Fb#PO#X_&VV7%WT0&>dsV=VWJA@X}@+1q# z1}9ocsD6}CBEaJJxeTS^83Aheq@=xt-;63Kn{9rx+&YQQav`(&GA|K0WM&X+gP-LFI+>un?u+T@hk=&Ze*3-CR{?pwpZ7&Su*Dj zs_Sy$@x}ObD#e1aLJz*AZfn`QGHQwbW;DLzr0Uj@N#fc1_8G|Yh{f4E^fhasb!09O zOyHvvicQJm*PmY@zv3yR5!PsmFE)j67`~tcTai_SoNdZE?xLKaDk zS(G?|3R3N(Xf}Q!M0%ZdDXAJ)RkT<8nq&?pxzh=@NKlCYZu;hD-q_?kZ^czbLyY;N z{0zqD*){Y})$j2}$N@k{~2(9l*nDlZ?RQ;`$gk0gD zJeA5rAlh0Ut1NO|5B4?O$}tVYZdgQ*IXzeW!z2Fb$NS2!K0nf3A$P}A(O4G2a#(^0<7#nx2@|nLc)(qP9?M2zLjsgLFVNh$wn(PjG;9qMMJt zrrG75`kfj4t-x_HmB**@{8inPt!R!A9QNFwsPB3Onkzc8Rfs0h@l6APM4Kg~K&)zo zwg`u{7a9m>CBz5LikPk|rYtPLqUzgb<^x+e1`h0+zCZrNlD#dePfM>&Hz z7_20=k+C>)*raf8<0Vl34>=N?E{uDtipR7*;ZL;I4?EWp*(tmeVOtUz(@*xtFU#s^x~$NIUbfqTsTuGVV!2TDksB2|^Nq`uH>=NDTs)Kx#!^}KwM zSv?3fnE9!kN$zJru6JvCs|(D>e?KB-!svJwvHSvKOhU1hiF}Ti@dls>3ZDB3{DbTu^B;t5pHr zbEz#}Qu2v^6W;ez<9_fKe)Ir%|6e-zZtaKvf`spD$C&RB@NSa=r`ZF!Bvqgn1v=p! z5kU4q^0sV{0J8MQp%3UQ!osu8)A5jS@7;un|lHXdZhSp;a5aOXKbsB_N=Fm}QCm}%U{OF*?Vd1`q=s)&zt z<5T4)zKxs+yB>u&3)pKXfF*&+7Cu$a-af$$nQvh&J@$=SM$<&85Katw3d!}B4=RrA zgd0uG_vv;CBUPe=5=-6E^Vn%t(XdggFm5A=1L0{}8K%J-@~+MK~?BywADm?rz(ulPKt%^4Sa#eps)K z0L$RN>x=vxq4;dK$8{qopa8dl;H@K6CmwN8yn`x64pMZpk>M;G1}I=!t=8U2Xvl#=P_^Rv zBIE~sc=N$W531?I9mK*Zg`6N(hcjfp=9&$XU^g0oiwFuA!AI`TbLV*~JbA{vKQm6= z@_EBxLA*eC>(5(%V_rj`RE99*(a#H~2%T&vTORZiHUmh&kU@wWhE*u!m z5qjy4Wp_t3_NIYjNp2Dxf1n0gdb5B= z!)~Tjlm#~+s*rfj9cZ;*P}I)D2AnJT=HyI2)>nRGUvAeC5h|AnuD3>w(zS7}7$fJ3 zIYg^}N9KZqMP+VH4>?$L55@;^uDF`nSQ{{fI?2Hz55g@{ghlj%1SA5TY2W@(#`gQ6WxCMI!Jbl!L=_yH)fw_F3*Vr+F&yC;5&f$0wqWLb*^a2e}EAP4E$P zn>(lZ?LrX}G`D!_cV$iQ>sglVcGP>YFN&_5z_~`5PS%MmS+*15ov^0R4x6n`Ipz79 z4iCWvdO(1~-1Ui!+FZ}7Zdu+~zxGSP+QH49rgL#uH5$k8Hl@>^qsi%yUy`w}**&zi z`kVGMNEBwY3V_ZCnJDWn?{~X$>SaRN%dLvT8;&E>RrV* zxAD>|s%!{33>%D0p?nX(`xPgvs>5f$Q3(g(B~JF#4;z>W7pmKf$=yJ1`k^YZzUyJP zUU!aXADegfhu;eYqz~?Wt9(sG1KsueP=68>FX5@@?1qjz`~RpQ)%|C61o0xUyW#Wh6w2ny%!03x87RRXe0idRHc8vM?#gzicLjLzG0+4Vqsk3W|1= ziH4g^*RN*R+$+)<5!Ca^t3H+gxt>>J-t9S1rSd<|RWA*^C~oC49%QjJ^I7fuAwHPy zTu;Tw+-l(*1U}0KD~k7;^$$r@8|FwUhk5N!WSxv*tpZxM*maa>mJ(jO#Gg_n@}&eT ze}if%Atl#a`KgjZPToi_d2OoXTivlP`MfSG@k&R(=nvdk=qsO69x?d8!ee+pLzwmy zbtWVAp~0=oMpNA}09{Rjdx-4OdCTj{BRTwE;WNCSP+vD_(x6!~#wVoRQoF}r(V8CP z6+BVf>^`z33V^(>%LmOmi30CPfivs^&8Y%s@RZCel?$c+JkatH^#2BRQvO_OsNpiy zmHHIvVT~ge>&O=MWtFddc6r3b{}qul5jU#MHBurKE~0UoT_w#9p;;@KYV*Zzoo#x{ zXOu^V@P9?*G!d;-?Qj=m$ki^X8oo`{&@)xTOln9qm!A1-q3)`=cgUh)GKMD!%~$2w z;h}EGS*q@-sq9arvJXsV_f_1I7w+b(n330|%pFqZOc~M5sWKffrMd~zm$!^_51x)g zW(|z)I%{?TQnT4TqPr?0dFJwt+$C@j*uF1u^2bA@sp#$@vyO=FKFhf6ekrxP+_>#F z^-vMcG&j1IhtsQg_G*3-ud#dz%l+p01;)zus$rg!EdgcMb7l{(cdODT)1fG!M`vwpk-Du2{qIT_m zfaey>FBS_+Ui=~$=Djc#-@s`4kXcno%x>Yz z>MCP#+Y+&p`{q$%D7%T2cNOQC+uxRrXfZOc>$AM7%k{I0>oQo0XnRhfsh4OfIre2E zP5?@`rrP@f99CthXrxrMuXUA|((a-AsvjjXfsi&fe_zG;>y7z~<;9$My$_+R&$UUk zWxmN{;#nI+RM*U*IbixZ&U)P5ifOr;N36KE+?ZEQxqw+!$ZZvF(~mw?Bdp7x8~K^H z;)?RfI2en%K@4J@bA5DomT|jymca;w%ZYl2OMhFi~9% zF?=KN^9;q6x>64K3EhS=56v09%66G3D!?bFQiiLQ7M%7&H)@DurM z+~=EBw%XjNs>U-PC$4eQzWAGA8k5@=j8%kUH*&zgrZ5m6+uzevJ4oyyNSnnHE7|BT z*&Qs|ojNaM^=!%jDGX1O*C>{`^+!L?h<;P_6My&;xjoI zh+JZYl9vl_=B6d|<(>D>$VF^bAiPkLIxmd1kR>r>VCUAhv{ug!Q z)|+}elyTFlXgz6i$5T~O`3aNPS-&vz`&Tcn|GN5v);%_igLJd7jHzS7LEup;l1%(M zfXT~TjD{afX5>hZ*#r15-i6HRO{UC=V)u;gWsVFdvpki3w01TssQZfcB}4(${I*g+ zE#!|PY*Goi?pxH#>(@MSq8XmMllA zGUWNlStr?El{2t)9fZvP!*7N&4zlHps<@XrB zRs1&db7W*Xdv*PnmEHCIz_)JQb9(gDCxnB{x0_BOOqKcOK!XF`P=W($!ShdCosWDC|29Y^hG;bw5&HpyG=j+RW!gxMo`qvF)$e8&pQ zaQd&*!EaDJ)&{_zNyihj@zw_SyPbG*w^Spj@R&RZDm*O@f(lFJK`L*P2SJ5ac@R{1 zg9o!$Y6cdl)}W=b+VD|gR?At_e5mIGZ>2KtB6gJdwk(9jGF_axl;4zuEahxIX$A7o zJ?~^V9_J^27xR0WUmL%T{NCcH)~7me%f;AQyF!qVjbgAMjmIzN0Jd966Rti2+wVld zqgELn<7J81#5tl->8Y(={D@Z3wq`i2p)ZNHl*-)P{&F69UjlpRA4*XEaw(S2{P-nRiEEWHKg2dIfnI#BYm`Mx zrJIQHA{7ya;Pa6A3n?Li@^AunZL7gNI6|z$NkN}$jTpd4cKj9DZZhS%05+yoA#-?M zs02pmAo{z=N$?x}$)V(I2g`wr0o_H-<%y3-$o&w%)BO*bA)GQQ9O0vxzcnSB7_o<- z^?oOVUDQ$LaBc>U82t}&Oh-bBT9M0aU`jEeo1a2k;l`kCCc*{;Kx*t2=NdNT)k+%Yz_qs_`|SmeHL)YFrYU z@36=HFj@4tP2V6q;$6Gaa;^EDovR_0OMC}!L7?V=$w)!*h;QwDKU4XbpFBn?vC=wQ z+$lkz1=43F>mnxKHG+hCazGJ~!)SO8C0eTDSCfS@R3ReB1eu$Vd80dpT1n6v^Cj5j zq2M|u-{gvykpoILg|3`Z7z=fe`Su7n%{BBX=G&=2>chl1lFu}r{41gA@pb`C`@>8Z z-_C=5NEFOa-xQkc?OrR!%by&xFEQM_^@0A|I|{pQ_yv<4wt9$eD`ZR&x7P~ZWf!W&gp92q7w1jPZTt&bWZ0sf`H!k@_96gMwja> zN$i-3h*eK3fflYYhj-Pr4R>Qipls`cW+7(Bh6gj?3Ww3ST9z$WLkvRV{-Szj&2T?* zvN>0>xvxKw9_y?ifH7ZOoqS69(I>U2P#6f7$f_D(zTq=($g^kPhvju@>WRG0D)Q~& zP9in;CAZ5w|4KE`{ue#>mD}apE$UnP+;<$U=e|5`?oTGKn)|clLFWD(d62pH%7e`P zh4LVCe}O#6++WUv9;TZ6!;(!gzg^~Do%TTpbs2-2`C8G7rp^4!MfR+&`}mMEzh|MH z=TY+PKl7{J?40>us&t}75!o6Agr*Oj^YK^`gRW5dlrf+Zx7RWMsag9QY?m6AtzVH8tEw7!2!Cds(uD{4qVM2EJ!cI z-Xu@x5VX8xlOjFJM^LQJX~Ls~H7G>b+}f!07heE3nd3x3CN*}P%d?nmUd?yO9Wn#b zIg&s4kmP|9?nYL4=lt|zYzo55$pFBU>*&t=?eCAO@17mrBC#qJM`(fJ98U%3Fk}7> z_H}(E>zz81C3opl>Bxh(bwS#RRQ5j@_H+rUugBF(#+4lQ4Ser9?9VcgP#wXvCR{YY`0et+t0f-8@rs{8mBHD3czLk6*zmovkCzsYYgM(SIGe`T!#_^} z>@d@=afYsOu-vX39u+* zKl3vUC_xvEO~ji~c=G%|0oXb6oovV2**ekaZb?2iWU76l6N_HE)$YDB!DDsc2__zyV~9h@FN zL@l0us}w!P2BcNfV?B?lHlJ8$w>g8{{~cAn@8d&Z@QKu!qRLHnwoVN0Cdmh4@YxIO zE`9uV3a&z$y{@|CK9>+zAP9029-Z**e*k=MNR9QRM!Vv;uDBDvd-Dzo-)v5aDfk{h zk1MI=K=`Iw%S9BY5O$zy&4#=08X>>e*i<=Jj)cOSjW-f4vRp>74A*kzE&0Y=qZrCR zd}Pn7kYnisf)`2Z|Q{V8wASLstUYgWmNmZIBbNcHU{9yze^)0>ypbIT6EJ z+9uQr-{8lJbY;oAyrsO7|0P}P20n_%j&iM&8%P3vu@oyv`K|S(Gu#jE7q&?1J0k~8 z&W_fMaE`qFk=pIMHLy7s(YI8;R*9}t(&g0sV8jzjHu~#Fl8w@2f9pb3&*(h-reZby zEibQ_zQt9f^2bW`=lzQW za;)}84_-z*{ifwmtonCE1R5j`mZJ-;e#aphtQmx-T&ePuE3_V=JZ^NQu^IyI)D)&9 z|MoR8YWQNWbIAE$G(2to|0pj9%>R~uHU9^h@85G!lNsqj{}l2Za=v#ylm_~8Yx5&A zg`@pk9T}Th9-HY_HiVt?PiII#iZ!~bYs${eDn(gBYcL1`_!B3-v8gPz68<$j>OE=j zm?@+6d0CD>J|-`*B6bO$2yGqbCXrf7=kgAVe3%dz@v^XOZ^T0q>he1^1?#Q(4+}&|r_-G|G$d?zAZ6~a zmIAlS5H3duMV`8UU4+fH5((cA=~tH(rEa;4z$WzbkxuAI+RCVWQa9D zT12OavbN1y4}YQEq#_k*myN5Qbk=TJ4@obTHx)wvHtQ}a7SC>f5bTJt!o+~uuOc#F zV>T^OkRv2hBGvU1S1YrZkSh=_QSjv(0#bRWdEVdS-CWfXOB=9^L+)=>ZUzX#(Mu`c ze4@tTqZf?L0KIner%GagiPG|G3F>txQh|qjkot3^t9YiRNx#=}qQ$j4Hpxvl*%BB5 za-DzB6Y)MdmsG}*jSV3t0TO{-I3KYJkl>-~{-$>hqiH_*h(&s*9JbGvNTTBNcAC#T zA4}o&a*Hvs)0ZRf_m~d39P&cHZ-UV%R}>~%0$fV!AglU#? zQFkZ6Mm;#vs|J^6st5g4ad@QYP2T&Ma`kn*u*Ea_wH3P5jhg^ zzitpe?78Y7IVj{~{{EnI5$avhAWi(EQmzC?V=a1lv*<$841met(v&Co>^Sa^D zSv|5aH9JvKbIg_#8A9S5ha($-i;JRj-``Gk(cM)>gIuPxs?y6nXY1vHOfCjA8bv9s z@0`5A>l+!)OS^NjeJ@zAy6_DTfPm4LX8daq%ov&k!TYqlR0eI0|FcHpo`R3Na&sMG zkPBU|gz}{H9#4}UbG={H!G&R+?vE2?f$Tp$Dp!=@M-ktDKRPw`?{E^aIaS{BTTV6_ zLu!$RPKTBmjc)alVF#x`GI#=c+fU`Ij)!-xZk{c%Iq9f&7HywM+q5Z7TYZaFyR3+@ zYUk{9N`Dh#LA!pX%8|yybWSy_Jl8uLeS(alL%zGH7$~H9?5D24*xz6Oh5H3J@Yup% z-=F5N&vO;O3ApM{R<8O}d7H*toxIJh2Xy=qo@Yv{^2t}9#qyoci}dG*`6CKvam>$J zCrdlcG2dR(ie4)EWxgf%zYU7t1_`Dx&O#*#Q|1z zy2JkcuhS$O5&MnX8m6im?dQXO+tSTCn_s)(T=iO+Bli4*^uk^KybK`RFX;%s`vKXn z)kl2hWvH>|7pebc9g}?_e^mB*9;{b&cKJwl`4oFz;1!!0c9+krQ%t~A>p_)kW*z;S z8k;#SHuF*vC#%FNYk^Lj9Ggklgqc<8a7dCwfycq(l}OM8znLlAShNLG+gD|KfKLwM zCl)XGow{!V1{NOi=8eMV?h+F6Q$_Dbl-JjJS(^zkXC9=sh@edBb8F1i2vv+>+7S%^pSeQIYv_gqSoOyFT7MX|GD3*a;Gj)os8#h zELm?7>Tjiv{wdYORNA2;QX z)lPry0f}4XG6(;WCKG18)|qy_e8%5E3>*kNH`%Y1s04q`5_@e<0FyVQAafp>xfUmM zO+_eb%pb>_ZC@g}&5hb>8>#D0C=%oXqxkp*ev?g&GX~!0M|4)SgJG!1Pgmc^z2>}d zK7$Ccrw~kv%(~@|*QZ*3g*G2_3{=ksBGjw1ZbVn| zzv{bsUGO(v?Y=MIv9tcDtiKvVh7gsk2XCcjylP>cJp!h%W{QRkkF}SSA+l@^pW$qC znX>w+Zlk^MscxeZ&?TCaKw&y+x~b~ctI$(SW#tZiE)lFHz0UEh`~fd7Jq=;_*+>rBKCpM-K}n8f^f@prP~?Zu{Xo9-Tqbmkl}cm zpS-94mFMIyoj&CFVG`NwiAR;XFA`d-O_V%lJB$(Tv;{Y{l{s9smsWSzMo=?}A8gco z*nJKI-fRmIsZyu%Lc!Q| zSseo<1It6|8?Zg7R>P;GrvRpp3cf8d zus2t?bYv@MRt=xKUeWz`%SuZ#ocj0iY4)MvQ=TX&ef7VEkHV*~RtkJ<^RjtDgu0?t zbf3Fss)mufc9LM!BrwYLq9#`WNOrjY8m*o?BwAfgzy8%SOp+Td4?5&}y!X)X^Ct?n zLxBDt*5m)JIK+B9INvVhzSf8tfw!slvpp@KX zS4bW)43lGpNY-9ZA;Bu}EH&moM4ps9nHnS>v4q2b9XeL^aF;YSS@T26imbb;y>5Eh z)(TvYrcX@s=fcWZQEzh-IW?Ky0^LxaS9LydFDS?FHgdf3cng}Z1WQoS_C<`Jl~J-m zB097HFNx^jO{{QHdG!;CRbm5TG+Y5kse;^!b-oH{hB#Lplh}1-eBzHLuweI1!YRuhxCAWt61q$9=gwVbAG@tROwFoMifKm;1y?zc3{Gbi|`;)*Q zp9H?dLXjc;cazYv_J0Kbc|vP}NV|aGU*Pw{pQ}jY0q{Oq)m~R?!}_wc`8o)^ zcS9yLyhkSC?fefA{P84=FHgewzk{tt@HF_s>{25!h5vgpa;%VK!2H#}0p_O!%nQ5X z^SjH1f*t_hRz6F$4HU6qeC?s}`S;}3@Exz=8xQQ=*#cjl2>0;B1G}QTowffyJ-Igt z?hF1G;Qn#>{;6s5>_5uO{_^aXTK;2swk?lte4(p6dKT}8l1F#91x!MZrzQ#lG^#`q z2NO!G{Vb`P`Q)}U9Ef#9ytLaI{zW2@lI%SGs{*BWkp32bZi(OU+KDb?LYf(6_*P#7?;E9S<5Qf?e5Pu@6iso2!t zo13YA!vMpV_H+7Qc~1Vi@?VoVJaU8-sTpijfvrcu%UX_}b%-D*i+%>)$@DAH@Vgx3 z?Zc)UhU|3uiV&f|W;6CLXP-fbrOu$7srJ687gKr*DQ237|7rhjr?LN}fAHj&{{Pv( zFNFyG2k-;rFHl5?(V^hy*0hKl*5Dd@=?PVmWMqtjQcIs=SqqR$t>fZaXW$kkz>v!j zrfHoPYP0T&d9}4v0o7!uma4+;f+*=!)oH3S_1<+p(bviOsIXIM_bG9H(Ay!)2lI*J zI6UD$hwW+3^dtg`A`b-g>*`f+RRjeLnM1KsPkhV->#AFYpeh~Q&ykEz{N)*r))B(S zLiGsQ5|c2Rk_2RifY*i)C*lh7W45HP(F}BEmYDV(y~n13(kGY@X6Ue>h@!NL z@Peh%Hj)JC{=t>A$@Q!C8{gBI>-?PQ1M6q>b#NvVLAoxju*5nJ5O8=o&b%;J-E-f| zx{vu|XUY{5lwQ_G#*ZoPOvFdhq(&_@o`17`#EjHGnEI*C^=8cpnA~qP*O$DCsFT6< z)coEmcb3B+ZPt?aPiRiI`Ba1dNqhRRpS^z->B~X!KOWZxBf3bS)zCCu`uGn=Sy34P#l!|4uRix6cvq;<=yKb95+EMS1evuKmM}n{w%DlSe z2oJ^AASh0=MUjEf_nN8Za_O{mGTJ=OV{SlM$_A?B-~PD&ud=L%wz^qdSdzxvpYi*a z-`**$fSNdR?p%KPybX{y`S7ea<}Tv*0>2IZs70SX&4@fh+r+CClMq26v9Z|_$z6ia z73nLBi5)3`a|_V?WjhF`(sB3xk78o7!JtoDK<%^ZoBtW)A2ZWrGR&4auR7u))31V`~9bogC#OSO9bGVha z)!Kq!T+HzX3(cy+6(ijq&u{j_DT<3N-mo$d)&l$bfWZF~At+UX{Bo5w*uM#isIJ@Y zI7PRAc&03$&i2iHUJT&H+NOu~7c%?JFY0IJImEiCmvznp!HbgE%$$muxzn9$5itnO z!TMK?$P>R<4ME}=s`aEmEILV+ssb?>V4LR92tz5AAhC)E1Hzl9pQh$p!FLgG`w{rA z0KS{0@a+QMH5el~tq11|e76gH3sRtkuB6&@O@b<{0IZd{qNpG=LYu(xpbNJh_(`TS z1sX7*7XX7`Ci=hN;9Y^Jl@V$0IBH1}e(8;f4)*JMg8B>846D0zDt2~kQclGrf!ZWy zm~m@@P`;{CK`m*irI)qVFAMAhIeR6M6B8ma@(`%0IHNC%pvBc%^AiQHH@d>BL*rwP zvzZ*(9dCn^!gz;gDO_|~b@Mu5r8;B-%nmxLP!S3WtVSqU`Na@~^5_-SiB?lLfb^*V z>D02*HuoN11jrO11%lE1C?#%fQJ>QB1< zOa-pjcVC*-xe_AL{N7mnbF^Js2;fki=QVH637W@yW7p<-%dgFoEvSd}QbUo$+jL!C zOmsiE|GJy5qX5pp!Pp62kO-zMPr6VQjGZ2g-N^fmdD4%R1~9ejL|fKIcW2j*^IzE# zjAzgO=m*T6Zmr*NlpOfl67R={uaUqhz0?V0MfCf#!rw)|cZRo@HS^*mz8ZhZ!|zAG z&kVn1-OJ<9L@_`SsM6@E#aRq?+(>ZZP?aYe@|Au_=$ijMa@ zm1qhU6=JS)f-`MB8H;;LG!Di?*+PT`ZujTcB_FV3%-^&gg+`|0AqV9W5rXME1q($cq*}C;s25F1i#1lJY`=)oR^qt=g(ZYZ2o@5;O^55wWhcZnZiw){VD_8}tAE?laFM zV6gA||G$4eOwPIIo_o%@`|{i+mfUOGKYmDuN4x#KV##XspnUeHpKCqeoH1@A6LW4d z@ZUQ$H-`+1Uk{A>*Qehfy|$zG@)!J9xV}6P&TRtZ*@*$+`YAo^mhzrC zU2=!~G4h-KujJb`kv_%Y`bZDErYRSQmO{IwERf3|PtE_U{JhbPM#J`|jBu{{Mv)Y7 z=}T3A&L=66WAzqgxGZnM=R3sCjUShBbQeFK#V&Buuxt9UdUaeT{bYM6;Vb!pBoFv< z3-U?7_g@eNt`0{IBTqdHQm9*4H(P|KIdQEnm&) z0~N=-AM4xnKS2f^ghq2Vvee}dx}t6Z}$=`tG9cPVOOQCB5TLL zJp?q*UR6e!4<-6@T^oMU9tHXJ)ARG~J~iK_mG{jxu_ab9X^`I%TGH1C(rZGR{Y)zx z+Erw)pdnpO8#yt_ohKxvJ0o zQOF;K$mLq3ZbKkt$YPA_PFiNuQ^93JX+581svJ@4xx&}cZ-u|3_llk!Jyuw}Jk=OI zfBndENn6jz?1^Hbq!V*@ZiIq!SvlubnZz;Hb%QC;N_;p?Q;@=#2*}inXbT+WA_G2kHv|u6k`)T9Z+)H6|&Zx7>&Scj)>zzn*%tLo#>xmy@%Dvm1xf zAUoKge4F`1nYA*|?^tg4|ITxZtU7a5iZva z_dR|k+gk&xfcmF?F7N~nUv5dfCGZfKzdrC9fNB}IQ(Q1K0@=eHct+5Sw|A1h5f7|d z2axn-K&6L~UL%K*z7P!Q_X8yTJfNiC0F?BEU}k>4lYAM1{96H%e;iO{$;gl4$jOoQ z<-+O%7Xu{!NI8*z5>WDI33e}kK3>Q_10eZ(1C_T%ei4owpXB!g^VJ7}0Ljml2l5X9 zO8&lr-OC?~7xE7UNd6~({#g#Qd{_R5I9&N}gCV~sT#~;*9?1U+DEa>q>|TD3EB{+K zB!4AP6~WlQ0!NNX|KEY-)(2h%NdB+of&AxzlK-?|_wrxD3;SCDlD`zlda*12Djcr; z3&61d9)RS}lLzvz14@3KVE6KG!wdO00VIDau%{%`;)Hx{cubEUV`1rAB7k44+cp7M}*{} zSvP&&lNeJzUl&#%@WUnf>oW2`14@3oVE6K8y7HASlK%vpy*>GlNQ{yH8)5Z<12gh( zm6P-tfLrqW3U)8Q7%%Ksx=6kZ?d!?kC^4q|w}6p8TL7}ZK_19|2PpY(33f04Q@oI` zbdh`+$~EI|`rL`bZ69s|qkUKnko;x9oYufY0*vyzHVHNR-wyQ$CLLQIhj~+L;7Z&U zB3JmZs2YclChl=>I2hoX@--tqcNqBe^|i)p*64%Xd!lB#h#$DVj$4JvjKmR0sirWzxh+f zfX_jU0Y$K5zyN>@@Bupw_zteojq{f8sQ*K#8U5=)xyMTSTS29NHSkCJzmfjD@q-`0 z(2a~*@p_N51b5;?EU0K_9UQW z+k)Mf&zX23e=0!odjolx#Fd|i!uAlK+5U_wrZah5RP~l7A79lLwi+#o@|7RTy~-ko@E1ME*jcZ^SZzALnPyS0dT=~te{LcZBzY-|x8_2N|H~nwJ;mW@O4Evt}Nd8iwuQ8Uk=>clRp86n?9q#NT1UH zl79eD@}~eLKP=e2{MmRR|2Tl;_XFc>Re*thmPyPisT={2!A^%2z``8B^d6fBSa3n2OX0VRJDQ1WfT?&Z(K3;9z4lHXg< zlb?sfwf|eH2lgKbLGnMtDft6%OMYL$?&TNbh5R7^$$y=Y`+M>?;&A1+xbn9EB)a8LeN9B%t?Fc|iq0FeB>fs$Vil>DOwyO%!=FXT@FNPZ9CL7w~^9IpLaX>hQA z7zD}xB-8%%!!7x}1iP0%6fflO29W$sggn@j{}K*YezPn8bAaTp1j_!mfs+54VE6J< zcp?7-faKo|9O22o4TqaPH-M2o&j2KUDNyo%2bBE#1iP32Bwol@126gK0Y`fB&%)uh zZzqA#zFiBD{HgNjUY^1rPwjk7-&6TpT=GLr-xERd3-SxfS_5N24?#nHU>q1FOiWT; z4D_*hqZOImz^T|op%5%LT^}d~N_8)B?NmmGLPKXcpr)^a8lC+?&{?v&HSp;pKg&7P z==>54onn&CH*xy>uFehMc}8a&m~?&tl+Gq`VasNqlJj*zZ#{D-TT=KbzW^q`fQNbM zc^i&Qet{{!04BeHCcl6tzXZEa-zV`>egRB=0Y`cA&%)u3Cr=VaegRB=$w>qj044uI z!S3bP;D!7v0Fr+s@NiH5C>(BiJ^+mRG6Nv_Lx7V1Goa*;6YO4o3@_wQ0!V%?aI`1? z`#&f*)SiC@Mti=Ge3AbVPRZ|$Tk->f-ODe+3;6>8lD~nFV?6n7l5hIc=fSYQ10eZN z044u*pya zOS+jCwt~3x!bV{w@%q5iAetVR?Jz$ktW*%T1)%sW1s>_e=PDd-d0GHQdAbKMn$Hk{ zc_0{e9YFD^6YM5F$iEFQjQltsVC0VmLH_Xo$)7IRz5KKA zLjI`$$sYnN_2du2;pRtgF!JLlfRVrb_eTDHxFvrt!S3ac!VCEa10??=0*>?KzlXz> z|2i1*{csui>s$WsRz--i-`M@5a3-uHvl2R8E8i2oG` z$@2_A;#UgpqP=Lt5Bbdi$zKc%diF2E;pXo}VC3%|0Hfdx5ELu}NWl`p?(M%BFXZ0< zko+mY37-5A4mW+qgONVx0F3-YL6CnOK=LaDyO%!~FXW#DsOftEe~aDmM_GKc{xBt5vjQ(#uz$my01jAPXq~LME?$hT5 zypaDqK=Q8umU;54aJcz<9vJEKD}a%IDhTqI0wn)x!S3ZR#|!z_0VIDC(Dvk);c(?2 z35NVL0Y?78AjqEzko>4%H}Z91O?}`XeEEvk)EXEBR*v+BiTojaAKZEwz3&K+mcaK9 zp(WMvF1z($hb#jcLhz)LGN?hAR`p9+4!^)Zmy zzu8v>$7Ovy4>;UMkcKI6<0$r}3Sk8^Qfs?NHLMMhEMMyVPQLmq-{XO-$Y_@Jxh|}4 z5g%AEw2Ssh9&1bBL`3UnX<^Z3inb>-09o{`?-{cabo32pE99##L7j2KToIaGf+dbKMR**7o2Xl)GC6Hd>TZ|k zDc5~U>IT=HcHO6@7Q1eBtV+x?B<8#fj}qiW5l(aoLkQGxk_Zu(pk|?Awg^YLgpsoC zbP*1436k4zmI#Agg2pWk=ZKK!5?&L>JQ232UYR1X2TWK$KlL6YQtAlTeQs)_>sB7i z+LIOR*=(@!F57vjhatIH;#V3gOD-1c;eYdTaJ5*;!HYy50+~W zxWC~-xZF~G4MoGNyTf3GYO1+mZMY!Ir}F6L@}qFMxqM0L@y%WgE3pd;iDY%^jx04H zYI54bRDG888<%uhsya*3BnYlWsWU`Un(ySFk)HW?FP~ z;?*Ml0V3&TlKX3@UK%Q0hc_&SMOZOyQmT+@;U)LB3~Q#v8SZP)VO;_j=cH2PpvU)p zmaj|uSCeIZPG!JU*EEbKrc3Zl4em5`0CU}jr6T5Z5)TqFE@H=9rcj0;s0h`Hb`*?m zQ+1;F>O>o6XlfX=JYX~}6a5c_mkSRq4m4aV;;o&;J4CD(aY-jp>k|zL5ifw~Hg)Tu zsd!!|@~kZRU9mc%*;(4xhBdF@dXWzn*(5;$t2V~4r04^nW7IH+5_^Mar$VbSt2>2w z70?2h!aVKLREUIxw7=VuEJ%%Y-L~tlOqICqIj*}ZHOO_}hxCSDO0?f4Xo0QaW)Z%k zJR|W95ws^K^}b8cYGcE#B5ZUCeOXLw_>~B&UBYk?ZWG}#moQO;+eNs`C7de4uSK}t zC1}aD;SLe5gy1IVFGSNRz|=V|(<36>CBpG8p;d&tMF_iu4@9^}gt0E+2NCWSVVFxO zQYE`jgaIyLj0nFG!3RM#L9vcPb!)=ox!Nu|yy1RW+~VDflH~DKWcbtoLZce|Hp}--LzeH^ zE_`#dd|hJmNS5^%U06@=WbL%_(Jbq{F05x{Sv@Ns%kurK3*WpS@%=H&w_6uJeRJ6{ zZ&qaaK6|4x)))PV@9`{OOBX(Um7)Giq$xsfC-Ov=_tze;ng+Mz{K@qkuJTf>zD6H> zQkQy+5UL@#yidYQTd1tel>`$c6^57L;~d!Ft^`0YHL5{I`5OLAFbNp$@(*_TPjvY& z{xSc`9r^$Hx{*K2!3|7Vwfy32pgkNH>a$Y1C3tNLO8nI6BrLJ`IMr#*JJ zVif13W)PyL?_@YNgjK{%jNPOe<;x_^@Z5$5g1V6|c9oR5N{;t}WLVMijHkur|Kc?h z=?NaAF{LvR6%N(o@ospQkf}zOztokVsqPBca`**;x9r_QzhPBXHQU%RR&6V7Bu9yP8 z2&Yy*F^5?id-zd*F|^)c@1xX!Fe;()Ey$c=@PU9B=xNb zZ@GkZBD6zrbM<41c^fYxnR;TQ+g7P_`W6qBR<9pnuAJMj8AcUsUut*KrKYb!tL|tg z4D`}GnA|qzZ!YKX%*>S#|3qg^-}f^iwq!yCvLXKNg^+@r)Jnttj@TtRV8q()h*6Yc zQbej>hoj*g!lr6Xh&M9|KFKIhNrioszq2~On~lYEg3#u@0xzQekqzRu8UBX%;54;0 z(`NWm`xqtKsUzio_d+zhpWz&Zx~wKQCZCdFD9P;2k-dsgwqf-*eBfzu`JZ+98(~Dn zCXb)!DjsssOj4Pr;K_j6QVOSJ|qNTyJW^}6XMBCh!&utS(?$|Z}_Jd zLMHiA2O0LqGwf@`p5Hfqn@Xk0@6v{k+yJA@n8W0cFSUi@RMYptOsJ=KR^nx5!^dt| z^fZ|e_hmx-35b45)#E)BbtV>)OoN=thPcs$&;}?)U2Rk*gqBviglP9dv;=BkV$tMk zfz+`k{I!|zYWr&X*6|merUPjBgn+5r|Kin``|+cyG<1l(6f(Qk*GE{(>O6m4ab{EW z{EZ`{{#PSs=GwugY96XBXw*@g^*ngK9D!M5ss(&mtW9c*0ince_g^3A81u;3=zW*%ZZncdT6IW;cY zdDO>X?s-NIcj?qm{%G;*SRbcc%OdfY)5|02)|v^t-k>k z!N*>%`wXfBHNn%W&(t9@4nJ}O_n56Z39A5yF1MZ^;ru1!{5w5(KbLucE)4x>kqOwN ztmcQ)s`pQ~M7S#B>jkf}1jL~+4s0Ss=VK!}q>LRhX>?=92bkAMa3f;Q7fNf9bQZe@ z*YpIkntR=O^%a*7MB?kc^+Pn(OxT0?B!+Nm@DN3mqr>dU&%B?JyfV$((MR#_fibbF zhx2Y-y1HF@N7=!>EBkZK(7(Y>?42Hb-(|e=psN#fh81heT$8cZ&RpJziJ9|t+}|iw zMfUNWZZ75!YRt8Y^u?Yb*n>4g*dLeGzXs`?-puIdt`V*P9#>j*gtM8;S~|-Ur|-No z`(#KDH&9`^m3v#aN0SBHBXQp1dRs0x=`hw!U!|&j>W}V|tm;x5QHIhjaF%U`lS zC(ZRGJ%HQO>85|=ryhQ9Uvo#=ag37KMDXSD}m}&J+mU zv$m4(9l1KH+0CP{JCx|M8TKrb$Ymkt+yb)S89?Dq4K@m`di9AasB=|h<||7si6zdW zw5c4JJJ!?Taf^p8JliV|&iOo<5O&U5mgl_q^+wJfa;RL#T|16SR{MgL`3v_9m0sDu zx~Dm!+p(W}&&0Ju(|T5MH?BP8L?jreBK@I6$wLr`c2E~xE*`qze%m>IXefAoK_!LA zKQ%ewA&&DGrJEC+8mw?$9VZT zj*H^fSPiLt#8T-b?)M-DD-h1{F6;mu4WPZ#wze_3k3QDQ0msh5YY?93iG}dXh$29Fv zz(r#=>KZ2%9*Hnz$L`a(fBG;LnS4`ZTuW0&cQv!|n5>!EI-arjhvA*}hMcUu6m4Uw z?6Q}v&1uXO@p%wB6Wx?;HC?K*VV*uMHTck{>9F)^8mbtEfjjE^T@P2EU4OIx_u#~j9sT|XLFo`$ zYW)uj8$Y-gA&tHRL8NaGP)&k~Uq2i^HUsnqO5b*pJAl4#fII42m(i!R-Qem|dagJ6 zl%9Wa^*u*Oqwi!+QAnQ-uIN*f(N~T``gDdx`gC|j`VIl^sPCdao$0v%Jd=MHgSz>5 zsj%^bzvN(m(RVGgN9n5qmf>aeX^XZ>%y~fR)81^Q=ZT{4kbk{8!<0P_&$yNWa7}sr%smd(pV7w3&>obZ@|MsZhhyJ;gjnzfDp!NZ zzDFd=v+sA3mn-}31Y?)L?SRpn&~&4Gs6%C4$KToVJ+tUIw=&HvI^NY;#5YEC7R^HE zbiyup6`dD@Nara)zo+wfNj5rTBG(6^0HgEg^4W#Hg`U1EGWsra^<9p>0O5?jVIb01 z2vqeldC*%@{fc9b$n}9A9?a<50@A&{n~Stw?zIfYLE&5i8ik8Nr0{&8 z>Y7n_w#51r*^|L2>9YYw;Z*r#GSnNNW%Kjqq7RVZss9K(qh2#&SH0$~N^8Uz^}|3+ zS_6CH<)*ci81*?|sQ=-2URs0f5Z@k*R6T{g!7~bbY5;2* zoGONDYRsVpeehrA?y8@`D#>DscQeyJ= zUNF?(1u)6|OZjxo-&?yV{B@_oUu6~E?kb#3Koj4EAX0cHus{mc0L+ot+>$LVff-;Z zoCYuoC&_2m`Kwzxz2ttrQ@yz--X!;PuKFJy$f(~Fc~YMb)KJ!_&y^CRej9wK|2M#> z?*Q2$zVCEV$dh(n{=O?UM&bLe!WEvv4IonZ46vURssa78#F_&22QUiMLja@jZu#sw zzPYq3x)gM>5>K{dnQNJEU>Q@2#d+MK%5~KbhFw{Q)FzWA+PuKWf)J5TfPK6g| z6<+EpoJ&BXa50D!o(~-0CGgo2YZ~X1!DyUk1B}9{Ai2BF-*d9GUhCOzqYE8TDI0c8KrFE(#ku6+V?!__V8V6#R<0v|7uqKYp!|~AfrAGBK4O5hk5GH!{H{kiXq882Vm6CkWbh6 zZtbG*+fIdFXBB?qDl8(PQFtVX6qYVKY-+SjqlHp=P4`)&nW!4 z)EI@fux7LTd<0^Q`afpIb{eQom3nm#w`y!>lKXlv)F%K&{WbFG8sA(xZBJnj@Qgyg z`f{T%AZ+~L5CM(CGe8vIV}Zwd3N==B6>6}G!U+JQaI}1O9p3}Gs6V(<{efBa2f6Co z8PFK@2WpD&y}K_{`^*aRh_B`iZvJYTLH_yxM*Y{W`pyaOd5jsn_+A8_iSPLuN|^Xw zC~W-TX9;K&?w3($0Z;Z6_QK)DHw_>0{T^TxekJ#=25oew^$=x-7zs)FA|GV8)sQ&jmqfq_t53a&f2x#K_$=z=L zz5(1r3RR$9!NIm*8pu{KW?(M>jKT(xpNQ`b%x{$3QhyUT$u0Fag1YnXUkDpN_)^3e z^*4g3cwGe?;;CPVgIg(3e*qZrJr`iqp9Vtn(V4$bWE85yU+F4ThyN#|P#ylCU4?mBwQ{vcWeKL!+}FF9`*x?fZ)DAV%Qg3Q1Q>HSgUH-A;9kfw%}p~7%%!^-AP^Ej`wc|0@Q zJf7_~kJU&p_Wlw?_SOIo^z6L?himU8!s-JT0< zz5w$fSZ3=YiEnWq0vCC=RZK8{22@wn4$O40-ITvm=}x@n@C@)wb9kD18Pgn|E{ydO zq?q*ioPJO3(cge4;bq$2*KxS*?@M5`ziR=eey#@Dp*?zn=EhUF5%USuwFcGz^JS3QtLJdI1G+zf zF`!!kFb4fjKD%z84`%k|nRh67#=H@rzMeAg5HOi{3UXZYD!_hh-bnal-pTmNya-TB zW5&F49Ikn#V3>CVz?e5eKFH55&`w2;XV7ur8H0`m^;t4#I+zUl{8rDP_rQK^&@}jD z(D8gkmq8POgFJ(d#^D+?1`LBn0aU|=1M|9=^ERV-&zyI_Gv;j8Am5aizY9anr$j{Q z^8_EhKU5^gH!mEPId8%G9G9!GLZ`LnJrvewjUU_q*MbiT`X-1hd=WU4<0Lb3GfqA>McR$SW>^-2<-eI!Rr0@P2d;glrZl&)_;JZ#=g_XU( zfy>z22qJqQ1@7+I`ydY2-n+oC_tyZ~dy|~Iw09E1Wv}}8Dd3a`_3x8qrCDE(3L||Z zi1E_547~gFC2SvsmA$*cW$YabB764*7J2sWiNm$GKN$A*1IXSUz}#Khdmh3)doKdd z*n7ULH1=L7411rwrPJOg!F{_d4+<-LuY=3jd%+#pOA~n_uw3?Ph&ls@Yi|?`dnW-* zm7gFV(;{`#J|9P$;gyHu!87%3hME#n9%cy}KltCjM!CMv{E-SP<#(zAd&+Oc;VQo# z4CM*=YCZcJ`4Hc1dozGVOHbi$;2DJjwU%iV4i?6IfPhBf86Z-4EO3mcFe-P7^F6zg3sy`~Lew?emomynnZ@%4C-v+cj_02fk;p!?d1~`8P81;XU zyK8(8?UKNwI}`Y@YyuzdCh#Q$Gzw3mCsceV1Lt@OZ5+Nl4N#8)3)Bb30*u0g<+JPf z?#&vam)!e-XOep#EiIbl-dEW8!SCOhQ9lfMQeOx>%~Ri7N=$O+fRWrkz;4uU0oftG z^SUTJuT$YUS%v4i3Rigw=Sd;8ZwBxzDOCSjfrFt4@tr7)@iBnXHwWO3j}3!9;QSoy zY{N{rafVEP2Za4NfCfbSiEIS#X&6erZVik8n@70%z(_E@9}|3UCa4|UWYuYR2A^H+ya@s8+O@7D+JntejiRy*iY-u9-3mOM z=6Gs!)hO1a*>U|ry%s!`MNW*r4fek+h6f~4GwCM-{d^yg#CGDbC zjnQ?W2kOtB@%D*T7HTHjdKxxw+J;yHous z->CUMJ&V0b8?@VneI>1};W8ip^ybq=EC|&$T6OxSyK7eSJd{{!8>@I_qFafiijg=p zBk@aG+Fh{vd@ie4eo~^(C|+mSth#%CLLxJ4MdzN3@~U04!f9BmGOX(Jc5SCIK&xg- zq`iNFm2x8kHe^`0>^kW&z_8w*VQt$rtHzCzx+ueX*REO7Z&)ibtXj_AMYIrVSoh1Y zPTn=EhO06_ET#aF^=<(|A8p~RGE=6+Qu1RKcy?g%!9v+nNoik6_?mD0R$Wwrx-U}X zl+nHx7N!5)KgH@ADwh97k-97+G4>M@GdU`jpOT2TqOS+eWaGEQZWqzHY{TCQ*Gk9cR^ilUqGwS28n}UP%CMVV}7xwv6hT8M%b&D5&|yS3OM4 z2E^{dDFuefkL`KWv@eYO zx{Q3fjPs%U|#;TT6egmlLPO zMr?_&Qz^o3TVFIeC}(p0(Bc*@w6B@4x39VnH}_jB{nj6v>U*ygCzc+EdT5 zd5+>3HcyEgU#H1<9?VeyT?)>=<``Qnn_^DO!4rKr4|kdlKE{9W#9X#;kBK;cfiya` z5HY$d;1!Dt=i{^&;O&%&FsUY;4UD8MzKXp zzpz8>C%16_x6A{OciII=1aIx3eJT9eYrs6N~lupg*eo9@_JiSiWV(0Gom;wptm{$OllJ38V z^TLed^`xkc6qjj_c1;#l(Z!dT*x_s0AymRR&=)Oji7{LoUiiWcF^ zNNd@%#gsYi|4z)$-(p=;)|MW8aYP$vA1S#PpNhJz)qC^A$e0tx<}`dk>&4FG)M8G* znFr_Fub`!gz|sqrGFUn`>t)~DOu!FK!1KBW3}*u#O~7bkWJyKczpC=0i3@Wg<1U_7 zB~7O*z?O`rK?LC88XkEqkR}??GkDD|l9)VKPbBS2t51k?x~ll#Po8b+K@_6!CUzVq zCeJ2>Roe*Byhs_M9w!I??IOJy$}`ox8M-LOYj#H0y(VM~j&bKk^w5=ET2?wgR9%3w z(I{&l!T2%aU_|0r68r+~GM+|reFCtI5$ohd;PVyOs(q2}+&Qi!lDzR=@-nrCuFq8x zG)gAVk0hVcJ?_r@lHf)83-=3^F79vD?t!QCnymi~Z$m2p&kfY)L+v=kIi7ve{erJm z7VFv5f>%Z~I~zH{z(YNOgpUUTc&fvFwe8cyMR1~_wMheBXIiNlDK~wP8~OT!h*icu z@wU|Hq3j+_TpM9g)FjY7*lPkMZ+w%5WM|sg)QxP_ac#b~(=(p{&a{!K1zFGYIz7KI zA%~}CWj(biAtScfgdCMB&3cY9o-e0XlE<#1y`elocky!SIOY{Dtv58iWc70DXIa`- zQcjc@t3EE*hZ#z5maJXMCQJ))RQ`=9V5XPMC&fn`cFDm1K+w5z&+i7qj&c;}>?{5z-U=y$# zhe(nw;HiZNx^^wzFo4=i#?@`Ue6RTGXT@2)CzbrJ8MHy$hq+~I`5)Ok?s_h? zNCNF8k2djJ}SZ;XT*d@wL8i-P%RVuenVY4z;a9ztw*tL(aluc*pCQqOZUv@`_jgiNk5Y z=m&|7qD)$H&ZVlPI6EeE?4dkn;!NT1x?t1QdBkAN;vVk%7q(Mg=u9aLHZ5qsjAyub zE^N7?5Os2~KIX;8Ht{i$;n@_YoXD)}CNgboxeaN#G=Iz{QZT=|j~k=UoaSr-E?Q#U z)9f^7jiU?Zy>v$Bk>mv>Pe;55s_khphUJNhdt%Of-kzHkfBskP9pp(^?l#4Z7Y&^(wzBW?|vllELS2>%pj!@ z6Lz-5AiXDa+?^#i<7F)y$lp+~vY^tk8Ka#0#UhFJkLmD7oh{*Db*!>))Crf_Gy=(? zy!0G(HbakOf0hcOgfb|;{6Adk&N z&fRF*LI151A&IYsf)htp_SLg{P4D-N_>UDdw8OJEFL54%S#=5RHA$Wj&WGFpVP0x zc`@qPRLMqbWg)M5737R~rMf32ic^ID;w9X3@GUjfIT8su(?^EuHdW1tI;RyyoXd-~ zqUFussJ}YDc5b67C{AsuhFB7t{r=vK_^M+$Z(W+dd17HMEaS3Jox2%1a>% zMMn?*DDF;=NW#wFRWin$3$ddml!y+uojT=1n#Ia5tfjTe8j~d%df53m-Nr(twM-rQ z@=)+hQ<7hZxg|NKl3d|ziPBD0IQ@8to0Ok4JmO4`M9ytfBE_65ierAB@xJzZlFA-u zkE}Y3)K-*FGf|EfHhk4J$`8|}X6oCy>`GO9;;R*w#&Cza3+#~8= zt(xq-V+SuCS=l?%^pBoV|B0rcQ=ujos_!p|#IMZHsTvDTgDkvyxac!tw5b&!Q+8EA zs(97hm|W1+WX*Q7IrY^;S+k#Do!gmMGH&w7sxcTyOv3~dw--}Mt8k(WQI*M0bq2jm zK_?H5Z}V3LoD)hq{LTr*uH#tZ;v8ENoH)p;TcVgwEF3qvsQU8YjG@(4!DEW5FLox5 z95;Dv^*PSOvEwFBs6H*-Vn1V&E%=m@&szF2nHx>srOKGeT|51PGX6bl>9CzM-gdsu zWc>S#_tbzz)P8MqYh$qEXg6k?D}E|we}B*|zW4G)-7UVif<>M0$P(I|NU1ZqYgvi- zrxZt=U*uyT?^9QC5O+x-xGHAySmsWrkXWDWQ{WYkDaeYEw-gcO-rX_hgrW+8F_A8f6oRpg zlv;yA!F3BQH{edTsB@!&ShZyYh{ms8lw;Mdq9{e2Hz@b1ch6MrUe4KPi!yG$)WD@L1X7~Qt6CEXVMqOu@U7uxq> z(Zs6|&dcexM8(&p#rq>41Q`oIbSbZXW!iT;m{e<7Ie>oP+(y-f3V)p{lv=?xQFp`> zON1YcBxZfQ zN?2_**w_NA?nQ&;Q)9miCFa~=E%Rel_B>M5saGc1@xP=)&KaEj)tHdd6iQt9dCdQw z?F=oknUmy2{BOm#^|7vPB=>mma>*sP>A}mj>Gwm+&mwV!9geWi;?ZdnF1@TCCgg+?6`yxJCx(vaqfS|Vn0W`qH*$&6fNGqlpvtXGR*(l+ z*qL>AB*Lqm@aKu}8r$ia2)C*r7bU{$l~J)o^~*FI-jVwgz03-gR%VafhuqAX$pV9$ zL5!DLvbi1}nSV0h=;Si(ETr+5|FfQI!?HN=M*>msBx0a?0jUF?mH# z9CG%tsUTJTY_Gc5e0=bSM{iPYg`&Z480oIu~DmBMhOvj&=6i8vManCfVQKyYX^y|Qjnn0`-pE!i zeW&VLxq6!`657?3X0mL5Q@?tfTN2uDfbQnn-CMo>t8OvG&T3}WU4;9;k$Gbp+kXz{ z&Us`i)^D-OiodqiR4h46#nJ@hzg4l0@hX1k zg?f1xbt!l9f2d0)(>}e+&9pyK5IgJAf37~Xc!bDlpH1SJ%1egRRUC32J!h*sj7?m9 zNAQY#YiX}<$c~Dyy?INM>92!r*3!8Y@UT;N6^&RXtK(M|CY?H zLE)$1$%!+ zsj94ir7EYwA_c|F@>SHoF*br1XLHNP=MB)JPBWjuzHnMHi#lq=k7lGij#+Xz_-@tV zCPC;C{Kq5+^=MR9dS8w7+~vfo9`KVW_hUVn$h7m=H}@4VVB>| zG|w&g2|qta=JcETi`<+CZ+7vnP`LNg`XjSM?h7)Xp3Ul(*@KgOq(t{>u*jvozg(H} z>yM6huS}`a;3YifLsq<&ufl$Y#AlVvWVa3@oY@WwE#KSDGIz?)_M~NhVm-kQ-q1O! zO}V4m$La~I?)Os)wicIc=daP$IxTbSpEeW4?BGU5!p+R|wc-@@C%qM?m*STf=Tz;# z)gI-m;zP7O-1eD}EE2tvdZ?2|FPNh#)5Zl)+s<8*Z3pMfUpU;Zx%yJ(8gW*-oL8gC zin%HOcSOY5hSok-{iV>`>&5L1 zFE@kq`kK8=Q7)89`KmugTd^5{++`=`T!8V4iXFVG2C#61UGrQ5geWu?W}>htRmK1< z8->T9w`hUE2;6HY?ve#67_H%vN+Ld3@(D70TP$(* zL#ZD&^ufBMnU^Li?sfREmAsr)!mHUYKXeJ>?1w@Q3%ShOrp~wH?^#Ws(yUxz5?%cUAFPrUD|ld> zu&LdGhtWLSPjXZ3StZk`U8h8X-&yga3yjzmaNd?WU`wAIC%huw*m3mJ2(hkRLrA_< z{`$-x(vjPE6Fc|KKbU8jmjlc*%+4*1)I59KteIB)R+uTbkyM}0yf`G5LX*U8M_6@L zQspGu2#_B9)S+W?;?F5?o>g}XYhL)IjL%*8w8x=1v*@O0U0_{%G(ytNsuFhM7FC#z zJB{Bh%0lbfy*=+mcq{VlSCF41|9mGY1;I#(72gx(RQVUEvs!&#rdGlupW$o#^e<$-t&mUVeFA`x;QE&P1`-vI+EB?T?F6(YWNB8tIM?LM$`&{9yg{xU;hY zPqHy$d~nf7EB*-!5y=yL_PARIA!k8=o2)u^k0x)>x6IVTpL;1*e;0gq@Od#+_Qz29 z)BjNoht@Ol++1^IUQX2^u2JJA=2z_(Vyi?l@YK)wYNVmPHu{{z<<6$oS@n&GBLfnC zH$-A$e#^u>U;8IW4G|Bnq01rptoSkTDI&~Ff|1VgvgvxZ*Ia|nnenSv%&wm5%AsSg zniy~Vw>tP>lv0ifH_HT#h<2KLn0e-KW)7NduD&^I+Wsel$H#*Zd7px6H_+*!0VZ za1FD|lDSMYOD>7F+C{QI@(jI|Ijs^+oS4tA&`w-h>{P6Xx6dXK+oM&(sk&AjDU(xr zY~CuS&^b@v%^xe=WG8%?@|UoOc2p~cR^2CmMq(NNj?+YqByUk6ep>cL-;2XnFAV(0mYt5y3X z!R%Efgw-e3xw^D!^O1*XvA*_pyj(j1gWh5b2Y0g`ohc46E8Ir$2>fg;*+TI&<>0BC zvgKeelBfMd!kc=$7r{g z3c-?g@F+Y zN#<~`6N^non(}M%l`N$UrvgW~xw;0fO#3o{-25ifzI@A=C)2*n#m07RW2QxRs<$oq zHiw4Qihobins#y8DQ51?SY*ORnlIBVhn(F*!D(Zy`0H?mSP>67lk@Ck9=A6(EnrGl z!SF3s!bhp>Dn^;RieXxkQm^-{#U!)zY39#b=SrR4X;>?=)w)pIKQzsS*WhYrNviad zYz*!eqnZn`Wox^*C~InRH`TDysH%|9w&Nz}Rp#3*%f=DJ=Ny~o-!N`UzBPGDe*6j+ z=%?gY_i{5SQC`qePAgkWTDYAY+i10;)p<^Ns-l}b&0iw^w->&HT<8LmO#k(ME+xA@HDt_T@GO&b zJ5l!qh0XTeEmwOAoXu0c%j&C2rnSF~D_r}bRr`uq;#ZGMTXii$-C=XQar-z%(pK#g z&{%++X(uX1rklv6ne8lDqZnT{_6GFi)3r@C^3w?I5x-^=+ zdep*UHP`gdv1&h7rGH&pW45i^&SI{Hx@GZDvN!oWlU;h*wWy7<2xb zk=Dv*M_u`LSx(v3R+`;?{1n)g*N>`(!np{uQc%0LD#m*JTV{OatcxYXt0Lz%Z6i)G zf1@2=^(0tM^?nHJ!@~2{+GW=eIJdgL?bN)457Fom;`+aIvj+OFE_kl2@$-P0mz33f z?6aHN^Ei3nV>#jt-P$|dn!J&@OJY`iXxsyfC?D1`hYFQl?~XaMmdBFSt8C{5W*x2( zUxuB#8_^VYrsjpYmy}YubQ;-8S9F7nt6OW;{s2_RQmZo?@o$LgqeM0AEZc~idoA-r zDbNN6v2=1nn z4vGHt_CUlmhU%k*p~Q(rHCN^5`KqQzlGF2q3^s${|hGK@#y7oCY)i#ni$JxP{ zQf(SC?Kr18l9RyXL1BF{0%LhFc5ngf+Ge6Q#h-UDiPu=OXkbnv-@2u#rEE7}eME`3 zHdJ3$n3zr4`A9oOQyQW`6>F3MeUe=j@WjmywlCP;g zqU7UF-*{_YG`^Cij|IsVovpPR>e=DS}=czj0@jp zEnTyPFFRMSIHG!=?705j{j%fw>ccZ*`i}jUT)pBKBt&(u3|~hf6h;6!)hu%)H&W)) zgC8IyP0MVmf;U;$Iu{fzbXD+G!;U}ySHe(s|7I;aokWf%SE`-1gLjK=#oyyE%Se1_ zi29ec;b>QLcC=Ji9eK3$S#`P~DXa5vbhhsfMX|6~2RH#_)y^hXp1}(;26Jz(SU*)8 z?oMZF4~NZ&u6`iP^!~muwW`(6%By~|y(gUZYHb`diFJSb*00=j^E7^hJEO7chD^$| zPgnD1Oma0=-_-s*d{O5Gr!?IHBQ z`s9!^iOrb1g@Ub>QPz|iDVW!>B{1GxV2@~9&RqMyv|dosQofB*cey^C=g@x%FA&ZG z!Jt^;jPLm|LToNEGtIS$#Z-y!wH>Ek_u6MNq0-tR1GE77f|DPdTA&eJ5Bek;8k%s( ze>L6ew9atrXCfrxI4r5?@XNku0QRien!&a6> zohu_z=O5ldf;nsEEx+NnxjAuuxAVLE{@k4LzzDz6yK{4v{U$f(QVt2Nd^k7fW`1un zbowuTSMl2o`f2>u-kY1V-vboNoSgpdKVJqKkjq~~@O#v}fQJcoW$w{4zgO?xz5Ddi zzk*)9`u4NBvhE5eNaw%8!ouFYd-T{9Z#VSb-p+6rmd!ez4QeN7gIW`7cgkMY?%vsy zS-T4#$o{)TMQbAb%<~jp{OtK`UQ1Me9xu(c>gpiHpMFSrRCQJSX|37iEaXD%U$|>^ z^w^9O?Qu_NAieNpJ7^GX3Tw)23XA%0VpPc8)MGY{URye4_`-vE93z%o`XNNEoT*25 zD898NQnE0RZnG0P+ndHu8NT3k^G)|UiC*xSw|k3er*_S$ALarD_P%Mv8%sP=l5gOX zC5`wbs#gbFtYuXCoaN!*vu4{@)l`8=2ovlTpCdJ!>-I{i{d5;RXW$yG6s2pm9_VjGdd(`l}P( zT;YG%?=PrRVAZ;0JvO&`H|>0EuA+G^J< zW*Aks95c;W*Vz(j`iLw$O67y^GpV9|eL1YPSasjiE{xeE(u*wAlSrJb+7@*#pYK?V zJr)E?Pl!~X5&wpYvlh-Le52R0AGc|ewK7y%#Ly*OwHve6UiSDl@4VIaCQhO**la+h z+4lznH(NB7*IZRvl-`l;L#+Z_g5aog0^eWC%h-`?2NPx?y)bg_S}mhT{fSJ;Uh9;X zX7a0$og>Pxn16|vS=72nvHi4e$zy|Raneo`!DM;bwkE9w1H2MkXVvM7Mebw?zpOkv zHaWC#^xBGKJf%=Ir9ORu<;zNw^@rx|P0@6t;_|Vwo-_E~`i6$34a#PaHru*?tyR8J zG=`P+GXpQ1aV7iZDq17)%eC9*8dz2OOjZ?`K8G={J=Yzz4Ta-8Vp4NWB&YfWB{1qy z7c!FmL;CKc@7KTgNnpoU2z;@f2kOGt+Ud{+hHgwP!rFXX$zx2r3%AEw$0jP;2Rx5G#_8tCB~V zYt4_B=2=VIu-T43TVjT3)-oNDitsr+_zeZ$ zwc@OP6GB5c_Uuk9Zr3z2rk$S{_LL0uQU>bT%z2IC-0FbcGHIZX)tXW4C*5FPcVi2% zJ|XH17DI{DgS0U;Es5PIMJ5>Y>k)^rrt$A#(#W}_NJ(nHnrstvJDU>Q+s&8Rvs>Fg z1R2v9oHn!a7_1Mmg`QRYP%vtC7;9LMwRW)zh@2H)jS2$aGpnrr^(q8W z=Vrs@rKFv1bC#-1Fho0xS??&4W4M-5i*r(mR>l5ucBheG#QgA)JH>oBg+9~x-ou#h z$BpmxG?8B8OHF^%{rGizrf1#kOynb%wvInU^BaP9^rre*PnFJ~?L89L|D?%XzRUKO zLh!BH+Gx|q0q{?v$!nD+5kGqf!(UqrfBQ!YL;myGkv*|YZGZ6LTKu)X@^9KxD)FU@ z)S#-drMG?Az1DzzMB&kEQR<=heq{?OX>|J2;eeM+AhRNppv|=@qHH&ziWr}GkuXjfR{j+W5_1-X`Yh#(+ z&i)H;+i#ac0-TXp0co84Z znYpn);NNsMc`^Se)7NO<)QLkf-AOy4wC+>)9*7P&txx^1hh7EwBIcA)aUx}<)5lr0 z&*RH7M5_~}xxdad_x&R0zT!6bH>tU|owCy4QgzgowDsoOXv}||*VeC%I#dq^?tRv8y zJDJD+q-zRtsw4C{^dnyXMqg4I8^!j@K@x1b^G|=u{+dPV!#+l{S=4_AL}lGtIqRvG z+Wzwq;&UdRWvz@JWG8srXkwL3f8$KN%62=OAn7@0RV+Dmcyz><;IC+K(XU8-j(Que zXAivW3+Jxky`-WG)ZcJte5S*B&Fye#Xw;NTp-SxbW;Hi77n$y4Jgvskb?j}_;Lhz~ zcI^BBLgKQGE56I0*4W1rJ-4 zO~K!prKE+d)G?!svKCR{@23`XE&F_k2H$fSgzRqD+xbp-A3lr~C}MlDe(8=SDenQs z&BTiWpPwhw{;7h^kpvaYrRT7&P;us+C67?(D(G`qiK|x%9h)3JE(_aI;OfY7+o%lgu<^RFe;dr(fAD-SqF-^kdG%^GiO zx++z6a80#^oa)}1*k)+y^$Y-uv|I7=UwHFcHW6_yLYs1f+pMLNzf7mible+bS#`V9 zDaIESu!hzb%nKGu&gW!#)q%-KI@nfO%wVlm`^4W<-%#PdUwuPIe|J-%9wU*zR`?hs zsz8EZ8mW9GsaA-6lrj&|h`w?l=hbT#m6GR6p_+lrRb|%7R{z8a`eFvHvM}VdxwYknH*uR9Lo>nF z)9HDd4pVj5LjSlgI-+T6vY=4w{m=GSNG^h6?y_ezd7WIUMG^mcYh^4ye|+!iyvKE; z!`d!O|81Nly~H#;(WImLAv+i%t7{H9p;1>wlFKE?G)WQv>#z=I@%}~A9;B{)Hrp1c zF=h;W$iA7TKn=4Q{tv6lwgtaNzKUwu_SUlT&-u_*{kd0Kt))|`)9TYy zoK=>X;WT4Hrp_=SdQvg#oDe-=Jl)ZK%_2>RehHqkZx@6-w& zRGE$Wy%?muozFzieAYA|VaGkz8FSvyT5k>h>_xeT9#&0ONR1h1rj=g)H8xM#(O_+j zCL?*y>%26_)r>hTB;=~WvXc|j<9wI(P8?odUzIz^PUrJgN4pNpuIabD1}oTFT_`zS z8>}>o)g81~pU_@mnzk)AVu#K==c8HM7jq1B*X79J1GQkg-}}RIB1>M-iX#iOr(|xq z(Kol^7#$b;3ukJlVXP$o1QsS$yT>$A4!@zz$9n>&ob@5P)E-x(mcUw8qiF$afAzQ` ztoYR!SXHt}57b=}<1&W%IxRg{_mj-FgCS2Lcwg(w(pS~B9! z8uLAJ0xL~feXqtwywZ)nLiF`D`cRiQwu`#AW7L`zs56O6G^d+r9z)}Js9J-Z>aqyq z0F7()k#m$eC=g2?!-`J$EbT!l<}`EaaR!N$R5nnwY2EZGxIMWYG>Yb^Sbojr<8rE| zAb8|_Blzb#3U(OXDIBtmlB|N%jIPob&G96A2}Rpzo3?RJ+QtyaX2_yvOI9I^58v7H zd}@J@8S_SK=@GP*EI&*zpXA9!w@xj6hjk=#!dUgjQ4Qkx#7lG*e^G?$U4ys?Iio74 zM-*pMpH)ITpYP=S`-~IJ{ZxEnc%-D%-67nTuW$iUE_smXjwGXkvQ3t5}xsatUI3kRM-q)OBt=AqY8ZC4P`2{PEF1fzRd1q+^L&R_nE8AyJtr zH(Q^sfZ`TLtmwMfZZh(?b9D5{f1FJc9mQ-8bq&t)&*_4sgnyI64(AV}wNq%&jCHb@ z-4`Qk5?lK=`r}uhnBHfMmEu&y@BOnTUQjv6Sf~cwPs`HQ>h{`&68y2}lgDJszMQfx zb;)>y)al6Sw&z0KgydNbnI24(`qRyG=t%EO3PUS);%@X}EkwSkWiLqn?ZHCE^_~*G z$xzNwRj9@mH3|}40GV1K>u<3PV@_A}Yl)$~Ly{4QUTk-RS)m$6D+Kw;1DRpvs zTk2cNU+rB_1<``${YF!>K#;VK(a(;2X>F$G3fvA1 zFUG}zwApU4wpUMi$&$t&p|}^Fn6iahJ#rtwrdj_jKc{ZMM1d~j*(?jD| z=~DdT+D)~2Lp>##?L8%CLl1YiTZ28V8U-i!6M8Fcm05Tn3ArL3Zc*rx8e|D&L0rT0 zGT8#Xzt!-J;0`-`ZE+p8;aTQVw6kTkF0er{Iqx^3pS?;$VPe+Z0)2CA6=|)i{UcPh z(Q1NBL02279iTDoidSUSr9bJXF8#WV%ojWQ((epChXv=XmNIkQc)F)YIQa!=(H`~7 zWfkB$WPzZo8jcOVwK)Or$3{#xr0jW4ayjt+?6X;T&+~uBhWD!dO*sPZ2zSt0aRKz| zBLVv=8|+=zUe?d9u;iJ&l84zn+^N2Q|Ftp+sCIP zr)tp0Gh`M@PP;kN4Z)`x#1CB%HT=!{!Q*K`<1WKG(0?&ZWJf&OVo2es`2S`xJWjss zVz7kNg#t`CVc+qcOD*rh4b$b9&Uy^aRmIQ3=_6gdqLtD>gw&5(rW} zu*|=5UT02MuIo#D7=FfeBKIf)4*Z9gP3J}Kzz=Ts5ij~Bz-_ndAX318aqZ(ee#D_fgR^X3e&DV)2-(qXe6a0_r`yLgM+3BNn5J->#zM`M8%c>ozJ7$NpcUl@S0J1 zzi4sRU1)msjcCxf?BWf3)b5P#pw>GXZi#y#X;oDL(XNw+Y#k7tt9FYnNmTIbyp)vD z#cwI#%@HLXBSlaWrCj}`Q;Jsc-=<3uC3IuuqjZasv_`tLNwm?ADCsseL{!307nSf) zB4xgbqQ}@p=YPt6GEc<)&nIs*UUa36l@Hmi&nQl}lpbvymZ%|)I`i4IJ#w6M z;4+$5O7o;2jL%#Dq#+mZAn$mt`k3dl2Xy3XTX`9BuNdw?3mlLs5Vf8AbsHP6qsf|K zh36F6Nn8+3LSNSnX1Mi{N2GI)>4RMC-x&T(I!Um~NwC@bCw&|mE<}}j^a z%prp6cP5~bV)GAoCJ(ij<>c;=*B^=$_>V$&su=;MH`Y7IXp#^%jHuBhD%twxV!8S3 zd>pLNTXm5Y>z!{j$&M83bsJ5xqGTHCByICAB}sK@tnK~Sfzy^w(6&5-9{8)+@~pgr zpMZN?dha?JwbbZ!f+bSL+8Qi1cpZIpX$hCQcs#S_fR>311z~%NQNMuLqIVe3bj!5> zM(;;LbR1sU8+K*g|9@0A?t{L{nvYgl$(y=o9)7-g&kpa>v;DdxI>JYEX{KF^@0-=a zaCK|fc7E{^_B^qw?UB3c-M-Gq(Dzkyl|42$bYkDk3xGF4?ee9il0mbIPj@TKxb zd}n1le4)G%PDZxF-a|kSD_jdJq$fMWB zfVWr;x%5&Q@K)$Qy>bS;?cgmcP5ld%eWCwQTsd%w*4wSRaX_oSa*66uX9XTH>O+|1 z)KvqEe#$QT;cr&7G@2cSA2uD02>LCTc7&y_aHCkdYR^Y@XPLD8XekJ;ex4Xlu2(GiC)HH&%*fV3wYT zx!o3oCv&Y|?Fu4itge5mRI_X%1;IpO?VxT_<@w8@R}!_6cLqrQb`3@LA|rkIJZq6YGSxBfcLWpwj_07TXJS z73z6_?s!w=B92mx-_chHWZ8yT+tYdUR1oUthin2dz~?u?QGE*Sg7{Ei89 zz!CFf5P&AS;eu0E|5PD%zcBdS9Ei}Nw7lDl#wZ)K@OA>6N{ptnz(=zEL8BhE_e1y| zWXb}8YpM!j2P~sy4>%3B{V`|aNe6a-%hh9_i{1u;?Q;<{ytBm_!tQrD2dKGD!T`TI zq41R+=6e>g{2MZGF?oN0mziDc-}MIUBm_TdzB~(@-L2(DvwlO)#aC*F1LMUmpv$$9zM&D)6FBgyc@HR!xR3b zf5J?c|K}(PWwXtenCWu-C1dlF28`D%;7z015sof zNa;L0pM3Zz3GeBjFw^DRkCO0*{S#)oJo_jK{rwW!T`oULs*_07uggm(IqNv&bhmvB)r-Tq-N&ViSO66dv_`ek~x zsa8pn#K>Rq*QMIWbzu9ogg^?NtfjNq9RB2C*Fs=&M|sgJ-(fqsN0MXcA(D0sHd?xQ zlr0254r~@tz^W5JMqbW(mr4}yHSbDnKj!VobzQ<0;F`^KEtkvlfB2UJrv<+F7ScY&^=Gb5t{1qz zY2NQ5Ezn3vy+pmFPjP+5mCy4x z&3h$j!(3CjW^!H4^-c3$Mp(y}h!$D!YOZVVYq_q^`TfVPT-O%fOT45({}2CMxo%G$ zbl4v#^9rtWxnf)|bA8kH-A`M>TxDE!T-{vXH1E&okB@6K*Y#Xaa(&ah&5X%Jt|44= zx&E8$o8~=6#*XVV^5pY7N}m4@OV#77)m5auoogvq3)ekd-z=~A>lS+`JFHmZ#IGt;Y?DbIVhkJYztR{?!RcB7j||8s94b=Y7IUTi0VQB zwVcuGE}1cHy2!z0=YO()JS=Ku4vUyS|8-@$x=R0EmD>W+*Pp8S`o|wf474@ zP#S{C(@NPbc=ZymVr}mBWUl!%6^Yz>vgPj4v0VJH2sxVhP}_UdpYZ1g65&7Z>jETAaLaHzmm*xbCS^MyRM-f4NCviijwk}6?IZ^FFD5ra1u9w}AvEeP_a^E&Xc#fOg)8^vN zMOvi-1@ViE)Fq|KwhPi}zHQsUVJj`h+VSdQt73WCxsj^_?(M4KZ3>#gr`rvy14iY9 zo$>0CfrfVY1FrhYESs`Jvnf%uY!^k#cdS+vKU=Gh6Tbyk<+7sarQyokmPIgyn5H$j zqo&n*>v1WsvMR3)C8jOPRG>>2ZfJYPR0kI57UPlbLmgtOL(%V2^8OtZEp0519%IG5 z(u*HcLcAKzcX*@k5H2vE@tw~|H$I4z6yuZ@GySYHUDyTlPSgehLEQ42Ds5FRFPm(v z#9YdSOm33aLn+Q%zfUAhZ!m-#^|YYPYYg*m42*j-=>BUUaj}Q`bMcho%ZdI=go&k= z70KK}gtn*y5!yb9rx8e&P>zVziupx1{Qdx1 zvQ2n1!u@%c{}MnC8EkjIsxErCAnJKICt4X$UWs>ct{Qs7eN%9Luxvzn)U!Pk#F4WQ zm+~7OlpZyKS4jWm=s~EV@jR)a=VvqAePo6louSjo@cAA}bQ;xMCkqUofgo3;1*oV9 z`lL^zMbP)~1}*3lyq=*D(LPIF_tdGb=g^fdMpBmD17h#9Vm}I~UJS#AXDnRDht!`m zf<9d}2;v^V{>nO{|Fez5Me^LVUu;q9r9zEf3AwWM02(ccZ#~D4Uws)c{JY?V38EL2 z=CAy38~c3-f=`_=V0`Tq#u{u?C8hT-l2UAHF<;fFk=;Y1MM!XQ@16V}aSs5vv%m=A zhv^gTWxiu*df9GJfT9UkZkqqlT!qtG; z^}O+IT8VZdp16Dt=w&Y7YLdUFMs>+tHG2#`Q&6#*Ha5N4-R+%TT2~F;CSBer-H1DM zXQ^KrQ=z7o@>4D)qP#NJZkx0+c}BK%Z^3hv>ab@RKjYy&M)RF?9?ujx<7dlLJx}$w zIlkX`U2%b?mlD)TpMFqS)as zv{JF3(I5So{7;gj(PY7=|5d?3(AyS4Q$^3ue;rYwJwBz$(ri7ubv&cra(ETlaSxU0uIX<5DUj*b zja1igTS&|_ql45`=6F1M3$CbNx)ZI;j_`Rh>LQ7cj+55y(5<`eB)oOpb__uSqNBQ| zjTgk6D#9vxe99?GkI7^;ZM=7CATr52HIyBSOAc?R11hD-QQ5W$F_WEahIu^Y>leBm zp={f#q(v9dB8gsbo>h4>VIQ0kulUMp{(D+x2(FiEWO%(+yAxA z;ksN8|5+i{1GyXf=l<8!Ov4`|cP3|cdQOFiJc$vHwH?&ZX~qAzh&cvEhRDX0dB}~P z5qnzpPFI}-V5^rJ2A4@|o=@JDtzo)uALLi%qJn6CApUd@8M5P^r>0IuWqGQvb=m@~ z7_bnlY@K#BKNYRhzR%COt<$b?keJbUBKmMR$q|eOQZ&8K8!It*I}FKbh25Zgjf3R& z`%wur)fbj`udUnT_x?_!#NmPw9b3q(b%2^W$6GzeXnuey5aFV1(nipwn)IlTUl*KU zG`H{pQ+Sr>T+4flwjmWC_E{TJ;iD@ zqnBo;3f%1AzS4kd?vajyBd`=W(-V=^e+$)b7{WBBBy8Poc`9%w^)FVY{#&S@oeyUv z&nJbxus4Tm(|dUHs9AI-5*E8m&OBt4gOCC?T_K7v;< z=hX-A%B$#ifi*Lh&aFE;fG)3Or>_^%SHFZ?>%aAFsm?U0nJ#3n zGlc%i>p8InOEKT#z=@)yzU zXv{ABw`V8pgq|D?$MYh5I@dpykorLE@<{?;9_kS4{|!in0uDKT_K_`U-p3AljCk=ac&sYVN5^}#F?ud7U<3BC6lNn7*Uq-t zy33_H-Sb-1OuwSno9XqRzOvV-s1YBFK5xcy?qE*T!_6SO#d`AeB+C3b{%uftn*|f6 zo~FaZ$-Bd0;@~hZq^@5!F%7}*3#fk*?aydJSP9>PfPs$5NJLCVP;6y%WHd*SfKx4EqM`)`Xz>J}nM_=705lPP$qTDvDVYDDR7jDVbC?4)I-W6W`&| zI{GQH1=SC3qIo)%-M5O@Fc(qgpv23RQopQ}(j!cqdrWXEfhIEvkBM>_CAL zn|fJ+*qe68$5brb=tDPX^YXinC)Dbs42kT>j`fx5e`aX zE-nX8@`0+FXoHY$Bh19qbj3_hP2_YY99nU@%wdF@99nT(GCy1JXrUAE9f$5+>`*~% zyXxxo@X8MVbdU;oVelfWAu9N^L=34)`!q!dDvFjHYwROuSnb0)q10%>O&0n(<~kR@ zn35#t^qkF1%q&}GOWm}eBnm`_)AVjOR*H8D$RCL}h});6=H9u*&E5y~E3N@&4QHO~ zSB&K@NP$heBd1GhU<*rCy`P5MLxK(MZ!;RH)6ujr*X!F8GG+Fq(sI3Eto>RQE=}${ zi=hxNh>&>L1~0%ixESw*#6{x0=tog?Z zw^>~`7mi?)v#Ips2T&>MjHdgg0MUEd-$c0Q?(kPkUTHLon#UpSa-dh6V|UiR(0hgq zwyjJ-z3rqx05|JQp~GZ{ZxNj*snk>-X?j7-fxUkiiBM!A;z4ahuumF;aiG z+$k9;?;kWpT!)^ECi`HrXYr2bg{E{4D*)u@^YWC<`t$Q4=^5#{ep&6{C0I*O8@}S ztfS_2AuIT;Jn`Gk{583r`P|kOc#Pkmwj!{l=O>u!SP?kOwC#ZqU)vg=s7(RV;RRH7 z$aH_Psp{CA`XA%5@_g~Wc~LQQ)LJ#dB5bBWwXt%Y%-tSrLUT2IZ#CW9G3M2?V>G`E zQZP4p?#yA0j5k{?eRH+kP@?uuQOq~7W@se98E}|3+V>HHX1_VNCCkr8i zulm*l4nwQN;bn2bp(=5BIaoUkt+E|n!gR)AXl6YaT0vM3dS-+(n`{O33<}g`d4{?~ zMobVf*YtzPXSu$^HI-{N*Ef|N2~xG~-2#Y?#GPJJDp7f>Vj0m9M?kdh6YEz)y4yiu zH>x?~z4Hs|&JwS?sAt*M_+NUq3E!W}@FO+!1MPjpIMS%?el6i#H5WkpH__jgbh~3mrYQ@{Ibohc>EHNe?OBS)= z(CtUpLid~VK@S-;wHH1|w(gw|>8)Fa+&0}HctlaXJjGTN;b%ZxSL>m%R1C96XJm4d z|MA+{)N7S3GS*HX;|1ugbku5!?K&ikX*qF+l~7JG{|Uud4}`ipw;~32h=WCw9zT zecqJqv?@1->wsaVcT+U4vepyH7sdKrwXf?kyst&i5SRj?ypRN)<&+8b3XD&FJV|aC zMl4TR4fJP#qh`BkD?Z^UZ{xKd>04Q@>Gg|i+-^*6K%=&2P@3-F0~W@&(W`NcndfyG zYkgz1TZ$g)!Qg(Q3O^$Ii343}aTFVVMEt})itUg;aWnCO7;e#Lj-H1+@KqD(kWfwK z;wWSvLx^N^EQ8`Q3wLNAVadA2Y-ir1j7-r0tS(!eJFFC2ZSY$LUXK-c)xnK3?i?8c ziAIZ>B4L zKwL8$Yo{Huyj9wJdQ}aM6WV0LxA@h`eQ$LzGMQ>pf0wDY+_j#CmiO}9CD=IPU&o>E z=>LlZveDhgWM-n8HYi9ib!rof^Rb#xUe=K9{rec?O7$M`tQmgM!n+m(SpL#%0&xe& z_gr9P1BJK%l>1;e&=U~gP1}t|FWV-Qw1*zfEj!*+2mQuciRKgQ^w_cqY|MxkMOJBM z!2N3(sQ&P;`(F(Y>WKdLy~=jpSbOmy+&s81!Vned_*%DL4HiO^slKO}f`wKV{G5EI zua5&Ae6TZU9PIm*K~ySC>Sy2}T^PSM%v9 zizx%{{Z`Vbeyachli+R%_hGCQ8&`3Gq4f#0!J|A$)1U&n zt@8VEQI6wG1Q%sEKUwaH(flTrnwq$3@6EM{eHjnGYkIruCILK`d(@VO-Y=1I5Rrad zcVx8uIU&|tP25QMDmg9!cOG0A87#^Lty&T}QNR<3z?Wb^OK&@-t%NLis7$ zc%A&@ZM>EritwwC;w#QD+y7C*DU5$+>>Y!;9_JcYH$@f=irsquhK6Im8ri}|2{SJ~ zvw4K2ZW>2y!pHsIXKVMW6=x9Lj^PZSic2p6L{p4Zo)52Y$;k6<_5I1$&tzGaod!6iOML~L0j zWn+no=#iV!t_9Xr$HqD%-oI=8c}XGd}AP^%22;w`<&bGJ~$d@ZkL;ko@nlRH;Pn zYX1=RqG!y8ce68S6&^4f-j)I9V*zSXpPHX`eF%CmnnlScb|^P`d}10#aGs^Z1J_^+ zU4+iXnx>x&cAIdNRmarCq*5>z-nzC4$S1BMWW~IKx-%RiQdI7V%?1UzDB(<@gl60D zF9z*bl0k*>aXicA-D<={&cLDU@bGLC_pioHf{xENFB_YUH=k$Yv$ZXZ*JAR%#n)P! z7mT%i9Iwp}jq8>GZLl3a)rXXU`-|B+$>nP;=Y*Bh=b-pK>Mqq@URSH=BgAVfLVo4< zzGJlfmWB!KK}Pcn+{Myxb{^#B({`6@pDSvZpLX(O5K9|> zb+BwEY=%@rf2utR<<(hcOg3N7xcW5poQMO&oE&RmlRkybm^!Ndj6v!(oz5uX_ zkA3EjUST?D!F%P6OVE9Y{$2ud+U;KeVzF8mk4fQJHTruV@HwKN$2*z)-g!k!{?;#3 z(Cr7t>`eJiCW`=?vW+!O*1=36N$sPdO>(>_#QSBUu&z&v;Y5?xr^%pQxGJ-Lj23zE ztD|-M0&H5T#1p060X&hjq!!@E z12>i&*Ti`qN;k@OTdN(`J|`NZj$iMD?v4oF`uuty>8e&$P4b%1d^Yfy3pf&Slu#Y@ z%Z|-~jmKfdB2=<%6LyVW?Ki!uiD;PKgj5izNg{9E>k|mK+_n#2Bi4ttizoE%#O!5+{Kj=sReFJ@${{);H{z>vtGb#&zRP93DJvuWo#h(4FL zT1Jyuo|!$Dj5pmX3zEvJ^|<4i4_^?-khCH+FEi(Q*J1l!cfWb?QD)e^cZ8!`&P#JJLO(Y!E#@ zcuk-rVQL!Y7zh~L&u8hEO;)0;#Pq&FR42+XH*jKc`4d-s?!EsB?!;r-R`Jvra<6)r zXK}2v4bO5Onj?s}aF`jN&DP^z1Wgnyu+S@Icc>KN8A}hX_4Ix~X~KFEMvl=eY;*7Z&mGp4Hff0Niro)?;V{4MhiUf% z5gL1aazDpe)onTr+M6HiDQVwpH>g`0w3jHYFPnv1%=mOqQY8DmvUA`@M5;5C4o(wr zuiB++<77=qGHO<)Hc_4m7C4o~k6IZU?%o2Yie3>(N!Q5Hdoq3X-anZ)vcy};o4ognLjawB!QuIr%a_*v`DM@s5jZtnwrYfy3!(FuMu@xyupcJbPoLU(k%bHb9JxbcI`psdebnsYXjGFtPQ#5azEd> zm*@Mry82xw_4}52pAk@se6m=()RTiu!R4G|gX%T4yb*@dq(%!JAsjdr+r*+!-mH$c zqtJ_{_CX-_Zgdoq;&tSR`g|;|28&pG?Z%ps$JHN%N#pOBiW|XFXy2gFzHge3LAc}e zIU~OsBE{pCTxv3^B)UYKCguN**d-(hA!z&fOQgyTlVP&hMei{D65OKQJk*{ja_xM} z8uGd+PDNnlB86>ummtuRth2qRxUh@GCnG(!pEErzUl7$~kuU5(zMz3o<(+dwM!uk- zHl*It&h$j4&7cuj;5i}89Unik-lk3wy-}mJnP94-nXIW8^|XiS7l}eKznnr)l`_Sz zXyn_L+Jj&H5rX)Nd_mQG0MO0wxlyxP=5a?+W^7M)cweoBUh*$eHIq?$t2+f&UnvyB z=`X^XE@I1(;SAHwgr4y)Dcg1M>C4;o_9RAPjFq_X~f@A+!3%2$=)yQB=aYy zrO!!!IMh{OEQtHxPJVl`JsM5yHhMIqA$D*AMr0BXUp*pY`8r@k@{Sl0U;hy~*%^^z zWJDrkG9xmWs{1Bas_ZuqQb+%R$ou-qJ<);NKf^@O-I3yI|0Mb|Pv}Dg#sCbHxvrjp z;Vvoe?iO%^&bl8~p)Ev8{(d9EFRh0o3>crO-t<>KeK$pkyP;-HNW%&3^4@FHpYKvw zzXUd=O@i&-f7hhuaMc;Qe#c_+hun5h2&4h8vXHCBHbMUXhV0?QPm=tAEOt%Ui8ev@ z{OYeLKU$caq`%@v!=v*!x|7oOKVhD-$;#C+bp9cxWM)uZ6i~qebKJJbd46RQ2JxcO zs)Ct$J+a=A!csgrV#v2)@(2DxS89kYOm=h1sft@o3)t^V!{gpGn*U93VrTCGA<>cO zC89ln1WGX)KhoksQXT%(SkVIuFEYkHe)k6gkCBH2E;Y$R$G zrt_=nBKVH($Vsu@TvXq@+t8L%+f&Dy>nXb=b&UQkB~Y9^gBfUc@-nA!*Hey$9o?G7 zTj_ho&z;()V;W9E)Ml*wF$AyB`w0OIv{BJU(c+}A+cE42D~S#uK80(71eXG{JxbAn zRtNDbA&kkW77L#`;06FAWdWlpK&fibX*9vn_B%SCT6k)-u*Fn0^4CaA;7{-5 z92}q3^YzT>lQ-DR=?yk>dc#77H&wLZI{C@la4kOwP2;l;z~IYrrr(7#z2b|y(=|sL zOt3>((#o?^*wNO{--e$A>#M8w9X0EKTG7+AJ35DB=43ze)AnSE8S61f2+!GJL7xW; zdJCtlBUsR5r2qX`(4WDnM^_~WCTA-5@f;b0SjW4ugW;to2CfkT{_3~CKnJTSH-!Hv zxX(U*0&cj^6L%9fF>;Q>UxF$pN-2o<6`9~)6D(3D_%x2;Rd2lJwDXse!DiCEz`17@ZKXs}Nl)svBhytUdQLtqN6>$rX z(o5Ctd3fI!;p)LU5zMqRG1s-3EEvo(=9@OW0RTjGb-|79)-trCmb^yF*_e&5}ax? z3C73*)J%e~+eXntZ6e~|S!KA+be5plmq;^WycLvXb0p8?sjtM*c8SGOVt;3*IGq!G zjuZ`XPk-G@apEiJJ?P%JnlIwqV8ZT-`Pi2}$)jfYX5_h0Z-KYmMf3zB>^%&`btR zS8xPBRNPQcW(b5ILs(sgGo0{T;JBiGJ}J&)nBpHD>O7xTH(t*C0YL10X@YR^>*$#p zjm0vvn=xHJAWJ(Q?pX&->RQO2+HhSD-#}wwtklBq$HSipxgv;lGpzw;7x68xz zKPS)yS8fg-4RQzm%Q@o3!0)+aI`UtJ{}57dgyYpE!T5|~b0%&v7f)>CXdpUGM7gvT z^305f`5C}gFn%R5;&0d&j4w$Bd%D}0!W87uXX(9uso#q3{p#GX*%aRKX)`=d}|@=0d>?LX$!-y!`|c%bid zl3xGR1#)tAMa^Ks506lL+QKt>m}}a#vR#%6)QljF;~8Dl(nVVfci%X(k~$bUS!h9J z`$wN&|J1RIbeXeId=F42B?#LgI)oiK8Gss0p%UC;x35#`)eAu?)fJk;-;8*q0m=WM zU|sRD1(|wu<-SADX6pBy&oDHKZm7kTTIoDxe$$7U_6mZ2$t9rjrbN%9ZnKRx2 zVqXx5dB3^QBV!f!cf;6XP3{QD-cI1ac(g}kKJjQ0el$P(IK_4OAEP_z)%BH}W`hzH z9AZ+3;QByx$=akObyJOydJ~Z3Jq9y)M`+wG*7#!s@EiEYGlE02HMXENSG(sYR^fXA zwPX?WFtLzB@rSgQb=<$ss;GnD5iSv}As=Vph~sLL$4A<rcT_z84zEcaA7w<+QO3XznVf4h2qgGhW`}= z#BZ3!hTfB62M0&WO~gH%-zdAyUszP8w#49my#@EHh%f1P_pQ==slqLqIkh>34)tbo zB-8gdZ03wtOqvTZ$CnbP=W3 zZ_4hzTg~bLzKsp3{IgL`&)@w2%Dmya0fIa zlea6``E6K&4IpU;(qx(}>AaqII}&Ic&h;|0{tiIF4!A|wAtD7Ulp&B14xzlqB=p<% z+P?#be-0(WPsv*5$n9?vXhi70F1i1bbb7+(*6M%kXKoQb7MaYq`TXJq&FOBGS&oS z0>=qA_eS|M%1T`3cA)B&)NwXc4M(Dxg(`D{Y>LS41fY@{pe(bYM*xbM1eV?^0i1xP zLQsTX7@QiAtU{Q4Jpx>2VR!0eN<`DjE(=)QnIf8UcYh!YDSu6WK-29!PnuXJe}-k- zc&gpTG5y<^I>sqqN@mMa;T}ufTqFx13;LaAVF3^)01vcvi@lg$1U)0|Y709A)Vgi* z8lt2h)mtePw&>5Ep!H|_sB0iPd0`+!U86D!ZH*`Ke8~8!_#}tA{;eztA+O(#Tw}w7 zS}N4_RJHuiZ;ad2ubv9j4ZfpZu7nta0GK$?yH7_Cd>gbJ3E)G$Kn_ zi!HkeU3YZCI{n}T2bQ6)#j}JZ3143K<=@w`!=&x>h*YHd|Kf=5f#pevS^|_4vL^J~9%h`#tju6<3V(+t$ z<#o)?Y()E59Luo7`%LRSgw%U10oYWtc3>&8ko`#GRaSUTYW7(6M z_h&GhwJSADo`g_9j=3x4wotniE-j4LHQmYY|ML*S`dyIV0(`u;;ZLKwWBw;61APvz z(};B-u0xG=7qt6vx*QtbdlIGhP)d*MQFJ)l-zqMA!N!r`(r?i>+CG)7D{{8{Dfx>m z)>wK-;k9a6SUXaqn)h#%KB!l94#RpSHDuyWeNR@_kJQZ2 zKhwYcnbsd=?SM6R==Ht%kX;lry|~N2gIlQl6__aK+4_hRfEbgyWD|_9 zNHSx}FVhFp@qO7gnXWIkljsde#H1DZy8J?Y5!Az;JFN6J({JXiRQ?Q+&FEy=i^eqX z)H{*W-Ce1|=ACMfVZ8}*U?G&NWFc@LK*=LsQ#@N@ObO{3h|hr!Tk}9Dz6d1# z8n#TK_~IStAn-z7KFqalVVCbQS59(qQtFDJMWrp|8X?DEU07&2Hp7toLs>oLi6!B( zfZ<0aQ0&Y&=n}$aQZrv*W~qJrSa2oR@jG#6a?cf%u+L1)%5gs~!|$X>cJZFKxfV`b z>`cigc;#1rwG>--^&(S!016k1m`w#Xux;sPRX!p-t~%KFN^VT=3rh?XDK*1wONO=k zEb+Y3k=*pNVio#A?ViMRcfxaK!V{=YjGUY(sxjSL{fY5+(yQc2i^Y+Q?b2zZcImVf zm|hrPT#PzNe5^XOu1q?lURj9faCqh8!pS$Ziz%Q znczE#i!kXZ@`V#)?p)}P&o~R_l&^pitIOoBNbXLTyJEQ;i__bY{1TyBX~6+hvo8DM zL{U(9ihTFr&m(%FT})+FK@`pdk9yzj`t3eucMJ9bfsl2m$IY_ul15B{EYY2XPxJWJ-|gTzmB5rU%iFE)GcxZ72Z*{PBe&X@Ea5rn9f|V=EsQmc3Li zzZsDdb0*w@0hQmm)`QdY zbflD?)9ps9HJHl?fR9|QCLLen^R%MS`Xdb5?ILQQmL88W6Gbu3gRb@MsVL(gUa_JxsdOU=bsNdsd|I z8^l`OjNevZ#;+<$zO)RVOb0aP5o6Y6;()ZC9NLssG`MfRQFeM_I5`%sH%iQ|`^p|5 zO#rlv7+W}Z#pzMMrc&6FL`jC_ur2vr@&T|7&j=>O`W3Rkk-y$3^Z+M!`&=4(zZ8>c z+zZ9pkk#VGhHcrRM^YfIHx zX5xoA-XHqvPA3d#Fq;3QAgWZ8dYNd{70DZ~1;>z7tf_8dfK%huYzq${72cPZjKPCL zqUeQj9cqU(5~Ha~dWb)Aj=2Ab{}3Ul<*l=pFjP}3E=o+^XM2#1=lA+3$RVL*yb8pc zn}Nv?QRZw&CtoP>qhdT2Fh8c+r`}7CI{D`lT(K{W+A?!JYQzA4-tB7{wL#!eAzmi{ z(0bH*zvOGfAwe&-hPgg%=(G=#Hnme}cdrvSW0YU!-2z&Xc=w(_pWD~Uu^0_4_C&5o zx8sJSCw6d<)Cc5Cedow5D=S&?T6Oj+E1nNdZLX74$L<>8_srbcayJ zXFjQU+*ezejR6{zcXR*t*OFbgKjlkAbG%Dof!idyJt5=NE7HrSuD5HA=Eav5P23Im z3^$4~1qv`1x+nRBj%Uo$qYmC>gT@>iG-?Di76@Nu5eyWcsiF0`=XB`E5Zi3&4EA(Q zvHnxNE`XXI^%y0HE2nx|7D%9J#;=ZD#qrX(9RBK^@T022V~$-RO~VF2Ie8%vzPQjw_m~teoQ5f&55y z?7)f9Jt*@Pz)kYjKSY8hX9ZOKz1&Psco0!RUp49|JO)^#EvOnxS!N=!R8=LNA=Qz3 zBa_<~Su#X81d>m*qdLrr8c+0Ty9h1xB>bQ*A|v!vR%?mwN*_KJ9wC5MZUSh#1J@st zCX0!_>J7RNSZaO|Lz`o?d`H9D zCV8%u!jd%6|Agvmg4z(*Smjz4Yf6Vo2@dWN16+ zV{7Du9Jzu7$K(*R9`$XTxviDl>u(`UJ8JM2q(i-o2xt}tqm~Qc`tt#qyw;gzW4THL z_{g5e!m+vL@druXE9Wm(r^J$5ME~9teibfyfa1_tLbxBtXa+V}{4kO-s@c(;fb3x4 zU=q;1dRXhs!^bk~yx?W+L!hhnSD6lAr>NVf!X-4VUk^%?znJPYbJ+z71^>4AAPO&T zomwF7Ii~8^?5EiL7HKb@FiHxL3X@240B4r#0PSx>fyvqj$=?W)2i-4b8nip0KAot; z_S^pYp1$BU$AuE#e(!-Pu8HZO`e*2d7srPc+;g;}{;57>JFl)-epX(c8MtBV_+a9v z0+A?`5e__bW?towlhG1BfV{fR{Z_)rjSg11&<$>@a2F0zo!EprI_-;QyI2KuN;y_5 z#?cfc&Ut0Otg2XkW}dOKi&t>X=bo7tPRuhx?$<&I?L~C8Nkw*`X>-4ukkfGzN~jps zDBErOd!C2CjGPRFbV#sUe)UFp-mazt_Pn_dtd8`>r8{Q_FB$?}w^b+miPrX-WELr&r@L+>BPnqg?!MY7!9 znVxdeY6ZHtbz1sZf4=QaLx6$F@RYX>(UJy{6{tOxf9XcvQ}+WKenjv&2_d~L_(VC; z+1Jq#fojm4Xa$yYqSNPOOCk~I{jGz;l%>N(CJT< z)sr~`#X82|VH=cBhw00P=*yc~?Qq-hrp(?IN=*5$&M!c^b_}0@`bY@-brkAnB4n?< z{-8`((7jU&z5)uMi|+FlLbGTSe4EWGCtgJgvml;}){}=xEAYfG z@}RjPO2t?^5xZ2^v;09(xSZnN-_Cjeb1GK%JjGueIYkVt-(yL1f7rD4@=kB^u2l>QgPUuI1D) zDKxH=-D#45E^wUIDxrvvD4?h$fDEY>P}9Wzd$4iJ<2qyNd$EJLk(uDuK@!41^U|h=v8{&)ut7_D>oYWA727PHRAL zkTIIx<^%6?BDd(Z+{Qgnc(Rp*5CZ@(%Wa_g`vbf`(Iy35Kb zLL*h8%WsOw0?uLI&klrk?r1|i$nKJx?4%bBB}oIW7V#s(A13ZT(2Bnn;s zip)w#Z4SB*s%f6dxkgJZ!-v2>v$}-lx6${^PO$(KQj91bV>&f=)E%Ej%8Lu)mw1wQ z?S-4Y>Iuq=x9HJfwD$5O+}5)Rm-Sf=C#f~7cJPY*^*B%b9=X-Dv>+pWvaS)bW`1W- zbdfeE_kLnia|;Av&v8gO^>T9k9<8fFJn0EL(QVegXK-%uV8@ctEQ>oTMCYG16grNG z?ehOlj7 zTkkX$t4*(>aF|vt@^!*aPB9ZUv!Atzp})P2wJkx;=$1fUb`Y;lQLcWQirE6=Ivb^Z z2GOcVK>WaeU7{an103&+zKT8-!;W&5k4lnx zKR?^G@jLW0(AAs-CS~z6_K@kN6E-I<-$pmtZlQnC4n?Xe8s!|OG+v>%h5&C^yiY74^cWHqxK_m5G7K#}EYDn7xkD+W_m zc&Hh&XIPiN2T(=2yH9>ltyTUqab`OdXSRnG7*fq`3{1RPAdYDb6vxA5$+zC5g65Ir zrnqx-3}m>AJ}UZcf&KFMuI63j(A6{x{?Iiw_ed%Az%xGQn`QUz(x+G%5@St4JRz7T z6$+`J%QxI-zRxpbWv7xNGC>IeC_9eSh>B zl2^<{RGMBnlNpGm?GWP?RFWR`^A>nFPnUCVhZvv39U;ckKc%`T6262aBgA<6XYvAq zAmP*b=8;d}E+LR3h=0sgBBQvkOh5}Ug%2@BRzxv({=8272?2&02p8Evc&`nFUT+2n z>nRF1UBDp%3#;-sFHxoK%P^!GdUyyU`g9I_e_+%^S9*sO!k&m9j>Xq%+9}x3COd=X z@@WM!(Ux9KvJ9oi?<#rO&U?HT~w4+F2Ht6AX2som;o7XGna*l&du4U7Vgg0AHyO?E!V zo8?7Uv!Go05=bOOU1~y`qc7Tu>>`+>U6_5s(&dwGXtOkwK_aJUDB9Kjwv^wmX)r6u zM>ZBn+1DrZVGNV-kS5-|OgE;h`F(!*@9N(k0c!wkdouRDLRUH_Pz|AjOKKak1%}h3 zo@^4xuHoJj{WgHQjJwo{cKmJuYz^th*pa&ht_6_OqngPD&8+9pXw26rHr6BK1J_%i z!ziv7@G^$^t~H8VW%P_;fe3tmNo2J?ASz?Xu7yMv*c1X+fR73Uyk(_)bOj_*!!rW@ z2=L|-n;Qe|)SDT^?fmNVAo^2%*m`({vrwAK7U&W`G6{Jt=-O1fY+OC@1Aw)OhOh?H zTeMXn*0vg7$H(Gc40O%eqc0x)&giaz=z8`lJRnkJDZ580Ebl;9Q(2OB%M1XS<1w>w z@k-<^@(S6YAUd#ldGgcC3kjQiUi6fJx}&Uu2Bt?<#F&Do%F220L?_7mIozgBY4}{D z7g$Gj%2aW~=NiAD*KkLf>>KG(Uo_eX<_^2FjN69qF>V|Z^l&yjvzTQ4ME=fxcVk&8 z{3KC;gaY2qX}LF`_Jmc>YIc>X`pJc^=ze_w=eetXGEUz=)sAgHr59@G-RHwbg9U8! zC+z?aZ{H@u0EqX#01ub)N>m3Y?nDpI9grvw-;r0gK=Bl<7p?V$MUDa6C42IRNWr7m zRq)WD%wCowS5E?;U5V+r3#+<36VE>%Z+4t*IpZX|_#kZgWmclvZMnOuH(B4sx88bq z=AbrMQ(BSxx#YhV5%dBvz%6&Gp)XfvqEei5WTWp}F#)dHCee1Ly}#fI7lE@OL!4Ts z<(TW4XuELd+;=a9_sV%3nAEIj&6Mu*uQ_9u=1i-hS5h;yLy$A4j*9Up#UD0kV|b-2 zM`NNaJt|L9*r7az>H&j#shLl7vyAshQ`>%Wz!yXgk*7l|l=>6q3CSFqMURQY@i&%) zUE`D^Yy7X}{o`;v#FH$_)%4Nssfm6J9+){?~8pJ2ST@yma4!zAXFWPXGAv5deH8ulmBe`1MndOzaRnu{!>asjziSOs8Uo!=6yhTiMPu)-#Rn zr2jg58ilR0`EP|V^vufJa00rQP7c&hRaY_EMK~_|l^*Iu(eos6F%<&A7bPa09B{v; ziJU%YW=k}R-HeD)d@;~0V^UmQ%D_x5&6(1iLt?OudE3PMffkU#KoFCRs85(WR7-;}IXVMBQbKn*|6KB)2i%070?% zTcLZ6XEXaYBU(lsVF!$)xxkKKL{zuTc>{E}WDC^(CxL^*EJTN%>uiF4e5MnOW+o*i ztg;1ywgb|1N`DV$>O2CO{)hdE={fv9hLfVn{H{Z{rWNXv+Xn&(1k0%YJXOSicKIK= z%sThnF8{-m_0u0p^v`3Z`sazU`p4D^p=h#MWixq~BNZ*6v{tUwT=&Y0(&SawfGiFO zyj|j9O`_RCL-I7nNsQ|K181ZBIJX$W*}Vtmu&ZzEI^v`2SxN|?=(LIWB?Z5@}VAXVWDYb-44 z%^D7_Z8@81yq1Is|J?wqo_<^VL${0!$<zOI=?Sawkzrujhcp9F^rD+3-o$Vz7=M;tySt;;>$A z@u}45hi!Kh1T+s9TmlfwzH3!rr-FL3@_QgF#=@Pf8xuQ_7a_1re)PDmsUGMWSE`sB zTJ1{Za|0kqY}M8j-3wmhhqYL^bOovdi~bwe4RV~%!l zL(>pm+m?~9SQWL!u=W&QS2#(%n}^fNuPKW8&HK~66M^q-@o6JB_^7gLS_y5X&@j$7 zmwM8p*5jhuRvEBb@!llczwjYM-A=<_^5OXzIBy_hdXrtB(P*-`7^WIf)|_t|tL&*@ zR>dq|!+)w=3*^B$kZ#HF_wA~d9S^YoirUz)wr#k~@=q1b#wTZqVvN`n37Cuit35sT zau>pJ7R76(Yw}{}ZduZlJ3(s6ldht4=*V!f95@=L^S;AO#H_0F zQi5Y##7(vG3_*s4#caFLR4HkdD=@evsT=IHelz_E6YW6P_!JNQS}!(K{p~~gwST5L zGg9QVzgJ?t=m;Onxyf`x7c3Do+IXqEv6h>G-N-iXK0bwzP)c7`b8q*b8{HQXuT-m| zAyu&8J&B9%__TcwtHEeq$a~8@)_fvIg<}>Zq|Y5Fiicw=+~O8KS&IrQcVJ{ZtW)kKt(+KD85GBfywdk<9LO12Ym7HS`~iM9kAlzCvigTX7>+owA{-GLDPky zZl^m?6AyQ(@K$$VW<0!Ag}1u{bK>FcD!d2hn=i)a?REzi#lw44_;2pOjq&i`tir{M z*+SoKI4A%cJx7JX5A$%$IPc^5ywBaOt-Otg(Y$uMTkp{KZWYdVw+cNL59fm}(1$Y` ztD%2|vaLV}C9@r@JT7w91_3&AT>;OcNVfY@*7q(U4`k`fLdY%yf79F1k+F>e{JD`r z)tS0&T^=qbQcEq>B8(1UY57#k9B%#Y1LO2!+AsrmIn{YGOcTd9x_W((QiP;6g zSkD1LRb!KvQXD#nIx`2CQnT_e&yn6%{WW8Md5MRdXo=b$OswqT-d9l(MW-^5Moi(Z z{b%r+E>tweqmXk!1DYbDjN_=_D66R4yHYFFOlOyC3t&_)b0M3Z56upCufm_92YAB{ z$?YOH)3h;iM74rSBuVJP1SKf&Tytt|W)tsk6GQyFO)*Hi` z%8GzC9zWp`mdycvAi!JQ2{@i*CXm8l~Z95tCiAQ_35~00nIzb%$HMvx4L-A zXw{9zVwb1&eEVIzx(K89YP2AVE2|4?hi-6bDtBvgVN}4mx=76^0PQR(Czm;HNBdhS zR&2!}%jLSgYVgQ(9%M`a2P--xZKp;Y$)W`wa$9@s)$+bQzhJG=I!Sz4+w2fTf&F zLrjc|&}uVtGN^XeC*aos^1JwPS@B&TKiI~va;l`+wggYe=j4UANRS1q48!B)Wd*`D zSs>s%CzvQ|l7s)EkoPkqHX9Ot?T8(m6FI5jpx8zjcc#G? z-dAs{NHop|AhewQeO{?(Ps5>lNfGO$FhW7sco#>En1}>K&k$D4zTSiM4o4L+LQuzk zl}WWuh(B>3ru7&(@Ej0A5zcx!3dgu^#O3v&G*+Z?^vqjuC+fnVfkuUrzU!q7Ybb!@ zd>SeNs8yic`_J0(bPXp2dG(|xshsR7K<7-(&1M^BXG=`YF)M8pe}dW(Ox!65K6&2R zl&N?6_u!pV`o!I)ca7c%(5`bffujBF3HXBn;*fV<>cK8drg0fva&7Y0%Tz`<aIP96_zJ#m2C3eSBCzdmCg9$z{qCBbQmgRjh`^zgODu z-hI462?6DaV^J`P&LzAem_H8f-265-set_=<+FbgM#^gh{wU*y$8`r1KbL1anv2bU zRJoXi3@gB=m?tPQ;SW`_>^yO^bd%}Hp{+(!F8hx)_I z#})Adenj@t-2~hs=fv8?&wSk(DxU&Qq5wHLa^B6Bb8EJoa>|iHqBy1y&={-o3E_37 z0~|BRE5IQP9FA~$cfK&2_Y;=8ZoqdOuo{qe=~42!vw3A#QllsCPIuS<5TDl?p9ho4 zng5FUp6C>_@)ugqwgi9^9oytH<1zqu3)!(m%Qw9%brMZ@0CTn~F7W0fvxY>;tf93f zn|X3yW*bTa?9~A?Hf)d`F6G3+; zi1&EWa*C5c#%kUF;%0+JB>s+gP8K#(H|Vdwk*`8GT_k)dPIOTH(0?ou(4#Nh+QD+iuU#;yMj)N^xD;KJ5SVT3d!)%bjEz<6u@L( zCV7@eb{cFtqX-|d8kgcbMs2Y2kZAa%0C38mTqARc_f2C-giN9j% zcKq)(vcm;0lpO213C4`Fh2bf;4?t&w=n`gSLaptMu$|JXfvQ?l+gr_}`&3hQ=B1jh z%xYems^*)sQ`IyY)o>7{9f(a+bqn>@t#-~qb(4C{44lI%k5?1!;7-XzkpZ_I$PRkx zIwSG|pyKYrhM(_G_UcdUoexhwjaAj`8Jqp~2Y%tDgsn*B5S_dc;TsaTx_cu%-!+;? zGuP?Y1>CM%)XBicPj8l!fzKv)26!uXB3Ig%3vR-JJ|FJ@;F|P(pDLIuvsCp!I6pNm zm3~%G)`&NGcjJi)<&35yh#i_8LnDP? zKPj_Kj?wgOCV#)4aui!!X-8#!W=3KlY1}OvU&6+?;wRk18FAF}B!f3^;L1d*=8fC{ zPD-2n_5oqZ$^#QW2c-}Ne18?MDJQ+#=bvB|+^@aH$;tI@n;{$(lrx&ND~?OvmC0}T?%9_MtauE^d;%}ZnUd5i~D`t!^d zoQF9e+XLm3qwW*^(G{vJNBijBm|f%KUcYG z-F#LnR-9o7QTX#u_k;0_#-LqyFHcV`gW-dOByQp?5(g4ZJI~7NI@1|Pm#g!hA>PDt z^FnVb7#%<`G$Y%6`{lH!`G>4vZVw-Fg5PMmQSxC%F5v=v#wl;^4+LOrpI4+JUX7w` zp%V+g+J$mwE&VQ!pLZU7x-%aLJX4dnCK1 zD6;G1MIzgh*?q4*jw2&FIrenWSC4yr&`hKc95majPJ+mJ9Erw3v%TqqX5A{?rwU=z zG?7rBdT}BHE-Gs&5pXX%UkSKnt(BHZA>?L<ZDMZ()bT=In(tlA+-mE z%yUAnJt*XAC&YJ9$RsD^ve*-Pb4RzRaM8K0ytcL38>9&5HLb6kU?ar_ zb8MvAEC)HnhgBqLE3PB{iMYxS8RhD0Me5;~OZlh_rV;T^uAmkd;SfLES6+qtOq{9} zDC1RpXt_PPfF(+)J=ud*Vo%PuuNWt5miX)$OvwB4YI1{-Dp#IVR#k6_%+10tRLe2X zTeL`O77{I=zO&@JQe6%$i?y41FezYa?)EcEU21QgU2(G<KNyt-|tK4Kb|thPC`k{&)x*NGy@JV+mV9(q-DUTw5L5 z+Ke@)yKN(Ct=vWySE6r zr$b2pG{lJx`42$|`!gOy;9$s{RxYc=gGqE3&CmCj&-c_abB&5mAYXsWe7dfT07Qnn z>s|>)zg{i!RTUpahMDm{oY*gZlK84pj0hGC?BokiDF?c^v)ktel+<_J45=R@y)NcX5L?4HxqUZ4uuhh}S zlj!1QJ?v4xLUW1k!l9zeaEce|=;BFq@vO;Pz7pZfIX9u_7O2)x9I=R%$&g$td_q`g?6DN8BIye`PBdLys=PajJ!Kq<%M)U0s^`x{Ifu2#gT{gz zu*aFmeyv4Cl|0mLEh^#jbPNmHMbLyrGuusd8F!soP9~EilXa$#&snlv!o$}2?b+hV zq0RQm9`UQ3xPFdxTR||n(bsa@(Wry9ZX3td^L3NQbIE&6hJGKj<&F_>+XzKZj4+XMxZcGTSXU((hs0E`Y>Lf-e-GP;syd|?53*sIc zhbd||MLNLj8!E+=!;AP_S!CWw6J&~FA0wDC|0}6A^SdR89E>(BSCO>z!d?wGu?!D% zDi5CCZ&}?$BfT8AAvc${@}yzy4IV7X!*_7`4*y}dX$0*z-=*&77ul;tW2((lKYIe; zWOO0#6;4`cU$=*YU6b~BKdG4^T4Qd_Tks_WnqyL0y04IfnVaIDefBx4Pj($^-HY@B) z{~I}Zs|%5Eb43={wtM=7gZRU?>Z1VQdEOD)v(pG z?-M!TEH(L}HE;&DWBuPQ9r~DOu5hRE*^E|mZQg-7FFQZBnzysw6Bw{rbX~DW)Sm>c zNvIxsY@6VpdTDX003-F%qN6A!W#(!3fhyDpwRv|d+>Z(kq>dnix{pk)xo@qm$mO6_1^l6FM=1C8sKQmjc{ug8`!3$AWJFdT72kwD*{4ySE9OG8gCSxk1}Yw11@NC2H&z2czRR+4-BI?z81>)QiG@Ra&QAb-97Y-L+hkuA3O% zi|U9Ik+-31wKhL|dx5KNSorp_uG$MksD;PT%HtSU?U@`44RAW(A$8b7CWR7#1;@WR zW&!4*Ov8|u5fHd6trFsrF_T3_iK+Fy2%fw7J~FMOWD7;KPY&NPj-0QQoF}jI z^F3hBYCb0Jz}XX!b#V4f!p9Y4`Tm?uIqT2@GP?uqDg{}QoNV7Y$xE#p{++wFH`s3T zf?bBvXh*cq!griNf7D9j1s2D#IYs6tkoo0K4Nu7DJmUauXMJ_Z`T>^#n!nC}LP1tC z2VLgW)dzjZD2{Nffaj@r2-yt$H&v!ew6|^Jff{@R`WEdz!2(-(`Tx29gI#bu(){f zst|zGc;I0G1tzQqmiZ ze-Kv1K2|k^HltN5gI=+SkBTl!H&49gZ;ZMt7{W$#ElGfSU9PWjS8X1dG<^%7b7FJQ zSKUFEk3scfzF=Sh3L7pXNL?s>+gvyK=q!?$)^YYmHQuh^7W3q>nj;RtqjGJLNIVE^ z?=vfSP=rxf$uC4LACl>Yl>l$DRqpHju7WHx=`yXeIfz%q3*Vw;y)#{{;{w(==xBkt z&XvXGXkwwtL-CZm%>MjplFy+X)si4(li8Do}r`X80 z+FbtyZFM|L{@COr#9L;kw0EIEfa?a+2r?v1MZu1 zK$!kV;=t0#5gAl`$6Ysij=$pCJf1+Vn4Di*sq~CKU$YfFUWjn97<(S}xq@ib_U#2c z`NbKU&o(2Mx{k{g1f5Q~!YQMC^_Jq(IFT{`%lgHcs-UgsAp05nNKUjc@6D7(&4RZ3 zzOjZUTo_h)@jo9ctLM52x?=f@<+v9&o;(O_jWO;H4t`a3c;u=X6=1_d9S{st99YmV z$G+3&vq5{UQlV?j^#rYX<7AQOv#-rB+XZ|V^7xRv1v8KL3fg_!Gzeb`w)}ICr}5YlnbNAHWf(9T`W*rMpd~gBuLg}I$*p07zMTy z2Ll^vQgD+jI8O)MW(nM2eQLoC@HAsVWSbDJwn)#gIyV{zNeN zBvh;VK!PcGbMSkuel*8P^MMSGO$&|^QId<(Y%Y7Gw{8B1l0$~B7C~L|XAi(_dSmld z0rg{&9df|QV`oX4nyv-s>P(E4Cd&hGZw_&5UaU{pro29wFRpdiCd3g)G>{RklRFUFU1u$%SUN?Z)R1|1# zjDIchc~b7zvNRpuwFNP3*{-s!71!i1C|3N9_e!O49<{0NR<#$(1ql7Lz4w~@nw@@> zE(zP28?=v+-4i(u@%TxI*)Gd3+lv2r-pz74P)5NOWPw~%ZKt}tm*meMB{D6^m}Rf{ zTAt);(s4cHdHb2fB@Az-VYvg8Ng^`F0~Zc=%K_i0`@6K?Rhje5rS^4g1!z`n3pDXg zR761qx*hOtoPPwT?DIsYGp{$OTJW02wQle0byuQWKWb(LyldtMojAUV>pHlkC>V`ATl57`eiN{ewD6*R8&Gw9{*(`Fe@x>}Ht+m>XT3g41@{s3oIf(;ODM+L7r+7wsJiMw`#8=l5q6TVly*mfxsgQK<>YD8w%Yb4uNn&BR!yK#2iO(A& zQgu1{Q#aPZeoDzG7vY`#f^pe3`3%YF@*uE}_|Upg2{V4yHV$N-y$zlyD-Jt!c3jTH zXZ64u`OofAUHn4VacV*o(vX?0>{NXeUhHuR&KmKZ9;#uTkL07``uqhsJVl}s=rLEm z?lKQT3$<658oyrzUb6pp5WIec=TP7!he#B>VoL9VPbzvCc!{b-_Rx*XrZYhV?6&w{ zM#H@@8m5-oxABi`TQ>tXvlpOIdGy&oeZ9@>4V z5ij)T@cqfkQt%%X-XO)BdERZA_`eL#LHct|3jcpBiRCf$oOtaKL+Q&kbfnDm!UD|X z)gShMg&D9sE!CRr$xg%j5_*BN-dFv51$bSV-Gi*`oE|OzKU8lr-aqag39pR)g1!0d zvp%K8yF?KWIlxkvuZah1$%@OqYA`s!{lX9AO7B2C?wL4ebf-!3M< zt}@M#PviDD>}b$FmYy2VS)bH&`Mv%rs_X;3-4V>Ean{9FeO^Vq5T^QkAx3C{fSy&$ zObSD#&Z}wBpaA??ZvW1oY_IlDOizux=*neXMv1e(HKfTgEifM1_~@MNGei5x zFFYQEACx`->)|Y5P`r1$Y(gAKsw}!zbb&hWyA$IL zR@6|&W!G1R=6br1s&HK-<9s+b2BP^Tp`6$gh`(K&U$Mg2hKIexu=+wVxZw$MyCT$T zcznx@G3GMdD{!yC9m5^Ny&3mr+?}{PanqS0-Iu>5uTVowYHWI z+@-jExP7>*aaZG>g?pAhUMdQsx<>24T7ufKkR9(GhHZI*1!raO2YMJfOF!ADkYT91 zLi+yu^s-`2bJ?95Q<>8dus8FJpTfsb)cjCr_;kI<3&|X2?lXD3Ms0OZ+{~LOUqzos zTcG8uxs?+U_I`D^xy~GwrQYzG)9P=zF8dRd%_Hb`eU`D?j2_=2#j5`@J#-a=JtX`Q z{w@=J9-xQxAl9_`hqw=qKDD>1v6~yecX)d2I`6&RCP>o-VTpE zFghgfD<>TXn*UKA!x{!13^MzFAhZ9Z-u*YBcmMSKpW7dXgK)wchJs(}J=Ckx+O42p z+!y#*oeA3`s(QJg$5WV-8JDK0Zki&hn?gnQ?n~_(ChnJL^Q@z4 z5n4_CG@d8T5m~M1=BX^6weAwGH(8f_>bGX^ws|lz z_K(FGZ*rf6dboAX%W$}?`z27F)U31~lJH>ke&J{Q*3*)Qzh&hzEMLo`Qh+KuX#G^h zYhNl65Wn!iFTfPW9dUF0n@Zho?Rj``n*IxRm`j%gNX^;Ar-|*8OC^9e;^_#$K z43@x5e1Vx9906u>jKunxM5z^+i8FpV)fAYi^w#|n2%IKi0X2yMxFk8?k|=;n@&-~8 z7HnTCVe+?bsmcMJ1mjeAv$D9Hs$I&mmzHRkSPJn3pp)%$Cn6QPMd4Ph;MN@z_fG@C zJ_WZ56mC6|tzkKrnu1o9)@;z~_Wc~dY?;qq_sxT#RUEVetLyG@j)E?fnInC`zn{ji zUVaWfPAzrZ2sltm5_LDI^>8#el%-F4QjqbQasFI{I7Rxr>65au;=HNwyY@d|bF)(Px;GLr^q=x-J1~=S9w-iD^(Xo?-#@&f%H_+W-r~B#^(Xgw_ZFz zd7y-hjJ^k3kM0{Weg5^izR^B(^{f9bsek<>e|f!6j`K|~<=n1BsrPAK3|^Z_o@24Z z;skg-(u9GJ$9@rcO&hI;wL(*lv%bAZq`0A|uRvs@nc}SXW%Y8j7H6>?BR5FEINyGj zxkx%VN+HYJR|XVlNq--He(UAme@@nV>OUIz~bnbs$WIMGtIehzl$uH5RLzL-! z1;*ol!=Ilbh4q>94?ADUc;Y~v;=^S;p#jOqfjgwy?ha=>4Gr4Pi29=NU6+P$hWt#X zg+XEL$j@v^tTwEb459SE;bHApcR*kxu2J%!)$x65jkL8EiMVMa?^W<0C;S#tG{2If zRVpc3r6WaqeQ0Z?UwrD_e_qCzmXI!c#rBLFk5Yzk6O-bCCN9WRfg z37EocL<6GAS7zzXbxoY)l8}d5fq`ycN*q_BwIf>%Aw=Bw1{gYJrbdZNv=_vxI$T#v+%r*YA<$A-DBJhZ8QnzgCd-(FOAl|x!=+NIQam6M9jK7e zL59xc*t2w@eh2#hbl*QDeJ>SrG75=ML{Nx6NnwtzOGe*IUpEz!Qk2nj&^2f-5(3bd zGcwuyHI|+PuM)J^a?-gd$Z2OtM=(0~0VsyzFVK4fv8c3WbwV)YNFXl+LqIC6g&js? zHCfVyH}FpIw#w+~8^D`Dyej(LI0QtHh*$qK{U`;>RX3$*hY*WTfHBqQxPhh*G(i&x zVpa-S2>c8zng1=aUm%HBN<`)u;%TDLERB|-GA6)@j%@nrA&K`2qw*o0X;nMl?eR;I zl`!0opl;3dKFO*Uca6mLGs%mhN}yjPf7dv5#=CU$aJ*;Sq>36d<1@0yV@%aC@dGrL ze9BZ$`UV=ssd30KCJEJ)v3m^S5E;9Gz*BXT9<@$HiK0g7S~W@^DHc{v4O1bp4ATWN zOnc=&K(u$f%1ABMBQ*sC9(Z7kQqFXbj7&zUjLeV7RMX@1_yp+%ib9vAqB6)CWP#>B z5I?3r#06ds#Bb6NSCIJ(C=Yia4h#eD#$TjF2jV|-AbyjAc(ar%r2%opf6r(K;13CW zR~lnxv=cmIF|HY}P@9M1qCxMUfcRK}I3uQ%p~77W$+e1erTH09SL5Ti3hI9i-^Bi~sF$Hg6qd1y!K-^7b=oJ_q9Gl}WP%3~@@Sf+udzOZG zwZNOMOOLQ+fIG~PS|)x)z*-zDfOl(ZeEk#fmeB>M8DK?HUQr*ItHHIx8C zpOc!wn6lLj7P6laGN?G)43g?hVk?Ch3K>-s9(^Yh+AGPiokfa=ky$K7Q}rwc^^_hk zN@g@Oz#zsmJ|opJ_-YhT#f_N(6Bod9Ow}pLv3KjdzUWM5sF_T`!x?Gnv?qXKxT%T6 zna=)1->Y#Z3Sd*y81jQYjVXG##rDXJ&9Eom-OKqJTsd0B*y*VD%Ef8GIi`6MWFADH{HIW6H4>OPb#u;jQX#LvJ1AU*P7y7S?t6(0J0fA=c44IgcU+MExCbLnG zoS`y3^T+b&DtCd=>e9l#mt~3`Pcx6nufoi$8L9Mm#veElcAtCBY#OEx{UoCJ^==06 z)lWXwTT+6lPrcx@&K&QOB9G;vMk%u0-TG~+dB|c+z5@};-8GUZ#qSB|h{z$2#N5uQ63 zJdQi4{sY6~;|W8r|2pChT>svaJGz_I`<*Z}!7QQex%X^B8A%yOq8k;JrxSUfxqnZm z)x_Q??YboIkZNKtR#kqUy|f}ZfhCGr)UIdzoqQ<`blDhhMq%PmyX8YP;T+toJ5^Oh zLCoThkhwIhm9{WOlqLe_eNtK|oC7WV89S77@5L+4@$_4l^jaT@muZz(KScqI5ZWzuM`drmz%m3Tm%A2 z>urXP1|_f4=e>cEkRM?5 z9FKlTA#3r~#b>(Yr8mCi!HaF!SOt{N@$zDM5D8_*omkwQKN?NP5`jQbdMw<(e2Utm zB0;Ki;zLKOpO06-^Oeu<)lV!3#--(gRHuFTB_=@4_3+}|I9|L%di1vQr1OCAoBr&- z1b!}RHgxzcIq6J+g}_h2;$Rq_LeS7*_`y3vhvC)74-Uh3b{z_a1H#YP_%DH9?6@xi zzsX-Z9Q;oHLh$?D--iyrqp2x`?T|S5U+;e*_-$JMFM(f}OE*Kuzw8qa2S14Z7r?*o z{cY&*dwJa8@SD>$82n_vzITH7Nk$7bCelb ze}mu3Zy9VpJd0|I{@Kj=P{wNfJ0i@ z;tn>0UihADq1;z2o1V<1KCDb`Q}cs;;q|TdL%~aGJ{Y{dbvSq>k3Iyv{>z<)*JW=F z9Zeo3zrk96apEwo=X|Gr@4OdXX0JQA`NA=!`H4)PFwIX~Pp=P#DY>fUefbIdmH6+} zI$7b#^qoU*_sX$@xBIgAp!`9`{C@osy_`=OPdm$YDH4&ApIE16&hL6^ml^qQ zWC2tAq;tF~%>K4hz~N;s#M%=*x1xtcT_BL?n4y{rKSHt~{Sh9`y|x5AK$UNNc65#BFPdJ!R7J{7fj2DAV=%EhFMCpjT}p3vwDrgzl$!X3?_KM`RB)L(|uY* z&V%qjsvi%@{}g-?`nmde=qH@cNz^^f01b)bao8lloH75$&wO*}2=ddT2B)7VzjG-1 zdC+*ca!nd`Y4Uk^{(2UT9&9}P88UwBkAK3l z{wOyptef3dB*q74-v%5~y@LS!*MmsLNP9#^n!u6lgp1~Gl`~ETInU9L{khh=js{AD7T%ky<2tnzKlK@2UPk zMEuof_5LLow1%C`BoK%kvtj)&6`l{yqTP8!ADHgyJDI4INwWWRWr$wvKP@`b^azvIph_G!dLpTGX@VTTInTH+1{X!mP}0kkGBDSFQQE^^g{3$F`jw#$#l|O#i42 zhhxTS08AewJ`8>N_=q%o`_Pxe<8STO|D*Kfzq$24RJ8v-aR)>D(cAlX-;n9cX^$PY z|Hj)L^cFotZ_!DInEA*Y@`453)`4CEf;OnX}2e zspj8c(`rVleg62PG#tjQk_}2b2TkJgk`2!;eFd?!?7&ZD?Vsc9#;b3R#I&OYe#MFP<6WfmjqJB+B-Lr(PX(jP;m5Pu;qpzphtj{wlw0~P*H>t85K@{XA- z*QmmFlrZP9k)Ktu$g|*NRVB^Qion0^EsuZH>cFTrzjbI{1lBvX*L#$b-UHXcSVTmH z4m2}_lfX;rM^~qBCHXnSLH+#pzvY=xwY3J*GJbgYIuTbC7IXswS7K#4hHgEMU z^GBgtdzQT+XuCVsgzT*J^{i*@%Rx#>>%IK+`A4W*#44rjy9L!)@|zwS>SIXdU8Twk zezEedQsrIMuRLmW^X76JW!gHxdwKr+(RhAaUBC|JWc5?vrPdqjJ%gbARY3fa+Jv9C#=luGZE%RTo?QP*}UC~_$p zFxD3JeVqXOiM(IJ^&Y#81!d=i3+1PFq;~_#lZjojreXE+ZiQU5i+#~9DOt$Y_vg#eF(FV{bxzh=~i_lT^ zPp*0Z^6fVsj2TP*dw?9NanW$&?lx8I=3%sbWQWnTI3uPm>nG$k+GrNtqpME*QYy!5 zGU8=`A~sBASL#x4-DcK)g%0t#633HMW{5|(oHU||DKo^SLrC*3qRn&&HLo6-s`;$r zoSHv_P;vmMmF6ZM%uGyw&C?x2fvx>QVj~g@`gzSuw`g|1kkWKWC^LlGEpw%6*UFcI z>nQ`*ZrMnU46a13gsYcP{&iFhh?Xi8+#-|#M!|*aAaktU99|0d<*+%2X>Z|8=qcP5x z)7bcrolIWDPgfv?fHc25-H=Yc6zCtxNW0QWd+$JLS7fI^7v@W)o!6T-6a8Z8n60Up zmktn9a4lQI-<2pv!B{#ELaIlp5RiMMgy^ncApl&OM7c77e^z+#v35KmjwPK42veP| zQpBod%tU%d7|rX6xT*rqRgd{UXGBc_h+KLy2Vz7!Ns8=xwJs_B^XQZZcv#1vTND_AjN-#`;_8j5}L@TKzj zE5gbYj8YBnQ?JfZPQ8AT5mTTU4f}y6Zw?tt>j}c`Rqm|BO;W6ma*^`NHkMwcqf|Ii z{Jl|hE+gxYc>LmF^xA_wZ+MDCZs_?>I4Ps?xQuc$YPk8>6yyYkKrZp;euO2Kjv=rk zh62mH{KUU!Mg(B3`HA16z&Q;myk;@o2*6y4pZ5!KW+Xz;F5f3j^#qj$WSJu&8b`aN z4NJeKqV{~M8Z=EiFQRKiDq?9y#LnzQtwfaCM`D{8EH@d=_w_h5s`Xt(qgt?-MpJWW&-q64 zBBBUaCJK_7D<6=(bb9jZh%HmiQ(4B(HX4I?LbGy>#*6e9)azXJ)icd#JS`(hMt>Kj ztGi6oDh=$s#4{;^5cR#GZn7niGg9|oQTKAASzcFH6=M#Tzbsv`wM6Puu^wJ1eN<9L z!_&c!NKba+eo2~9h1N8=oRycDmMS(9`-GDGM)LxqD@yK)D=78!gOb;1oTdu!g&8#o zvtRBj7-*WmST-ur-H%RGr;GOGC0@u31X)Y-61#Tyt?IHgv|2|b9?Xmn{%jtbDk(NL zv6R60*O%yN>UVk0ED>Mq_}rKB(fAxYh5-!Z9|4j^b0ejy7FX*Q2eA}h#P4*Hf4yJw zZ_3b%^o%i@gQ>K62?Z?|mc}VN2BX=XJVSUzxXsd$#?qt7#;HJW4#QG86zd$ur*lx4 z)^n`U{PsVf@~+LUY)$1i!4IT5J)>X4X%1wbE3p8|6hGFf{x3hV9!-&;s1IDuF_ykCOmN$`har+!_i0~jDN5%;%DVnVq)}oKy!y!;936^5y!1;Nx_Ss|2G*_*=*TY4BD>6J8QWL##xjpUnTC zkniH&`JeC$dZM?>R*X-aE!0qx(3N!iIY#qW z$wXm?|2>87ldv?pr}BtHHrEAi>aeUo*%Q_1G> zm6`=+xf4Ij%z|pW()owoiQ6PlsvQlVt7ss2^9zInG~o=R@hO7M>rQ&NZ=Z@XJK8eUXx>0X)g58o9ShUlp_~7^RP#l+2{@K1cUIy~ zDL^C0n>sTH|Mydwy{I#LHkDcYRHy1!lZ&P!Nyo>Z@^Kn-y=qLEuKz8nF(+%sPgP?I zdK(iz-Wfu!R37mg9Ul>H>T(`(d|pfYY?WG{?Wv0Dqji{{>(ShXxs~Y4#GND8vna<5)bwxcguMANzb&cS&60n0%JTs z@eo<2Fef!UDQ!iXpmIzdCvFNs`RkfJve zb^97~NwGpS374!na%+z3RE!UE4Q3I>!aRi8i1`Pm@P!=L`IyTwH)EPGk78D1Uc-Ed z8S!F{>m*DS<|fSjn3pi4P?B4SxeW7F%$=BDVmdIdV%#t1xX#1`G2g=6jd>cg9rFoh z*ef}%BFq#_E#^mlS%uk(c^@-udycCdGXqnD`2}VzrVDe- ztK^B9k6Gb-KZpGuX3UNp*F;PZb0cOU<{r!+Fl#X{V{%^0agD`XjA_6~yx(ApS&exS z^A5)IIqM1c^C5!%ml=gvoPOvObxh_GKca@g^QgT$HlAE>d%#x{!DrG zu~n%2q)eaC|Fwg=vZ`KEKc^^V{jW1lWk7DS38tLRufQQ)UMim04DZ7hE^+jqj-Ofo zRLK8PJF~*hcdEQp8&dAU?96%#gw!7i6tw2F_QGheFa`{n9|Pev|%w_z=8-3X9oonp9=ljqr zag}+sscw1+?`r2R|4I6ULMc8xrk1{unvFYN`ra8RPvdDw4(Gq|w0QaLH*6HlqTBg@ zs794Nsn~udWao2_H_LCMWNG!6MZhOK@PxW6MelQ~$qQ!o*0!Am@tVISlRVRTCO!>2 zlk5RB?2#;uNE^*P;Lk5guJLZN+l))vP47m#$22b8=;w+6ue|7pHGk?l!)$wxZIit^ zokhCI2mA#j^m|{SaFPbRFW5Z+2li94 z3!IR<6}wQ;_8LygI(oqiGqonG=S%O?JWo8;;vA+ z_}!8V&#m?5vM%72)-1UI_;%$!mFweSQO;Fx8=YR2i^CuNK_BXnl@b?+%R~0fK8{-} z{ax3IZhHBX{n=o2^o{3Ea>c8W-LgVzc?F2#ceeOVa{Sh4zt79?D{=hfI0y08i(i4` z_Y3WJkNCM9zh>?CP4Rml$)}VtU;CXQe%l;BS;msziPP{~>-bI8e!HshTjBVful*hu zzxy1&leAxx__a8GhW5K${AwM)eRLLO6pG(0$M0S3m#Du@@W?$U{-NIc+%Wffj7j*7yIrs_m< zbfU9xI*G2+i3;%{(U-8S!eVh$6egzVL}%+nui|tPouU(U;6tM4u&lyO;;1OR8%wIU z{{_{iCY(;9kMSY)e2HfjF2u45ZxcsF;l)^zs9h&2#pxt^QYSh=;#q|!VOfP=7Dq+l zdm)|ZCpys%oKB(^ooGEiBzhjpD%>oNio$!aq@=IwL`!ixiLTU%Y9*dkxCqNCyj>g> zg+44vRH74|jnheVf=)C+;sG}-tMFuTR1|gvb)rwUDnPu3(@B)Thu9nN!Pbqn zMd44eq@<^GqGp^#_B}x;6tJ=EUR#rI4TPN zfF+6E+oAyRAWo;GPJD=cm&CIQe~M)l-YbrZ!W+-fiTaRBs&V|4d0vPsdV{Q(i<|#rCdi%__FA`9*%sFWU$Fayi?zW=`t~#2tsp#~g_n zfhoqga^*ia%ayCSR2*4i^iLnoH8=AwJ0~YMhd+stot@)$yK=I!UC5aD6{B2P*}0C5 z+s&W)!Oj&!sboOn%zVX{@^iBJpkDGRMf8g@kdu>r@F#wIM5Vn2Hk4*}*PLjIAk^iF z^c2;MOublK!u9I>)jTC6;zb^{ojlSWG3n^q(L8T!TD-ZY=Dql0C5S(|?iS(UdO77M z%!amo97E%E!OQD^OP|ya-=7T4Zj*yG-94&XUc*w|qI#n@OVvdgPU)Wvr*u@W^Eonk z3bPFJDCR6o>JMP6KY{2!^+%7%Uru)B?EdVtFzk`lA4c|GU;h<#y6(PV3f;1o?@{f# z8%wwA9G9zT%_>+$ez|VUZxI!e(}S%)AW|ddhnR(!R*cK-qUTe6?{;VZQ` zDE5uWgYTI~FqNuo(MsT}w4FEX?LAfY&!rF^wG5uLI_OD;&!8Rj1V3w|E8MjceY@MUYDe-obS&W0teSa-_uF9qZ%S^f_aj zn7&lZVJR6gXoYdpQ??wDb-6vwx(|86NW0?_~9>&k!)UcD|W<|ymI}447+@Pf% z#x*;D?eX-(Sb^RmpeN9LysW~NXrSi=h(FXoJafG`ej*^et)lMyImVe=Z#%p0EHm&Z$t4UvQyhJP&{4nyp=>!Bs@&uR9q;F`AILv=6FoJ$Gs^ z7S7eUt}3o>NXR&@y&{sxuDv*taMzwJUq?muWY+~L@P(SmDP+O5z2@9Lu9H=aq71(m z795%3+HN%8#llWT*i5cB10A0X(pjR%kn6>BE3F%f%R_&a`qEFyO2SGjqh}m-+WF|C z<@&LDan6*rR2b~od4du7wgT%Xp{FE1e~W`{9~|!szmrvWduX;ADIxnOvgH%9f4&UM zv@4rj9E1<=$*r5i3+_Q^Ip_RkgDG5>Z6hdH)6Z*%#41}8{BIQ{FF1Q^aQ2R_)3k4> zX>Hw+p{7@AM~9l;tV;!s4%u%6NEOySx4y=fvbeIbN|9 zz}Wy(4#dwD4GOb_CZWWe)A&###(J=6>*6zm=rP$C@_w+OxNEI=6iQa(@U1(l>yLc@ zAiwJ&{1@dCr~X&=D-CbCsJHRNTY2-(?Ijad$o}C%{CV2*1iSsqFde=N<)6^)0MV0^|?Wyl`h>ly{hmu(fG31FqfH@VNi~izr znZ)juB+)Z!4(yZXlI4aElPrN`es^&zfxwr+&RwZuAp%AAN}))ICe6040*OB^5S{Cm zx7bUlIk#F+^eZ2xy~b?VcR4kxKkGuVjKOtB5ID~<7Pe<%_A_1I!DAHFx=<3vluY&}sQ)ktq)jqc_VmSVc7hrQ!Q8eFWdY`R7g8MHcRjP!%b>So=4d?6|e}oU8 z9JFtY@X7N`_Z2Uf#_;@H;|`&o^MraXmAHxb2;vhiiufpc~fwbsK+ z^Z83m?|LKh8+^O6?M-q!tDwtX62l#oY1vq^T@u(GqTssmIq`<8@Ki?SMIw76#S=wTiAz@Yl5u}<+myyDG9WcA?@Vx zuDnokO~CtX&F=$^yKCq8Z7>JP?6`CT6{nVL_uf(LHkMS-DYT)kxPjL}4cCJ4K^VO} zM}Kd)+*SK!-W}&{aKCq5O?PPG*2%W}$ViWS{zWEl)>qh-jU}cvvg>>WWTB+2yS4>xdmtIr!!~1+y z^a}SXiD^u3LzHVx-fw!Jt9e)6xtzg+>Lo~Emr2&PNAyijvE6Hg1I(*vQSdu9SkWr* zGnzhQ64jnYQy1S3RnR^2Djw=}^|qQPk(OT!NanO2k?nS!hj|n;2NT4&24bQAU-Qdi zc_1sktlsqkD+XuDz@o)*WVzw}vk73Y>v`IC5hm4M)m9gP%go}7w3GELxvL+Q>|e8B zk>&D1f6_lu=^N)yH@*Mw;Gr3@C1QqiXrGyh`hQFP9&_q<_}ns654=eyF;Ww<%n0MI zmf1z^bw%EXh52=Hm>5jWJRDRduLdzEGfA%vM6b*X>UTGJMN3{SWwP*jlpXc?_}=FD zbvkz3u{pw};&M_F&O=_?T1oEKxy9wz9&ao?3N%qHsjvidL-wOZ5IX%HRxoFpC%h=% zWvt{0#HP2YR(R29-Z>FUc%jQDbJ8+CjU~c7_@no_VvNJcKA#a;iAQC$u{ew!V#zq0 z163l}UxJ$tiZ)q>TT{V7cbkb|QTL?qYu$IL85l-vc>82nFfxANZhkklH^}TOf5u~%9?y2&He<;N0Dy_r z;SOo8kkWZ-oqE0b4WVt{Kx*W3g}Kot(GChsb(~{YQqv+m>GPGRv<>QQ%gFn)D$!9K zqj>4b&PuiN_S-w`PeS&(=&oIl7j9=ke!QnL0exar~|rkj%|6&aDmE#b;)(0+U~<$*{6dvzq9Rm(J)Wi(Z(7*8&vX)I6dCxd)2ag_(`_tZc_qwC zIgn2;jahcV?)s4fIk4@P#WL=fQ%=;mE$rVU1M5d!AdjQEJP*hjwtLl zB2UrY6s9ECR9WtIrWdZ-SR!{cEA93Kf?U|yq{~M~H=c__;8Ds;#k}7ef9*XMM?yP{ zmfHnzvule>BL~LTA&Gf5ek&#W?QVe5RVa{&j*cF8zRS-4eZc-$t)GXP#@*}8B&T>; zQqn808cUm`j`n+(MkhVVmrL?02mx9~86wsWzuh3@tt$t~Su`TeHgnpYmdFhy*?^7_ zAt1`gNks!d^dg=KqVF_k6z^b1+NpCpNs?>KoDWo+Ywil7=60DRFWZ_THW?!$JzB^~ zMv}a+Bm8l)%^6yZzsrvIb{LUc1x(KHOZ<=Q%Ys?5e$Xuq*c%r7MP7iWo?E8c`7c9s zWvB$buhg;)J2?qM`+5DuN-mFcw4w@8G9?`#LuTHM!gvh#J!visa6gbZd9u0!j*p^^< zrFEAeccs-J$Q`u)Ly#L!LGECCLkhX^5#+`a#H7uz#`4oA@OqpXMYiFg- z7-${%nNy7L2k4JTt=C0ZRHRu2`+e4<)q%3V`B9?R9?(;~y}e;CH+fw1uLa(9Bc|Gu zK1%$0IL!(yw5w*Bc0t&?W&R04yQ-QeIgQ5O5(LNnktP$9HYXP15wvFzO8@^@g%*6A zL><87lAt}QBQX;%v*CcNh$5z%(WNZnSRpdq&nCdGT4>Lh<=s$oLeu&>H)Ql^FwMF zCsdHbjBY>REH%~B+9Pzs^k}(&9$2fwzcL!|N`zkXIt0d%_hGcUV+4QEC z2hCKDGKhO~nnF&A8%U8+zptzMT|@m^I9$_PzaY_6og^#c8e|4kN|&JPMYi!h7YI*HW+L4%`fZ8?9%}oA@=e zM!I&YYD!bYMv+()kx?@KgMpwXSxMDyOeH6kN}W!ZI8V(->F)cgs>YR6Bi08zr>1g9 zL)v^?_WXc~8W`~d1A#{Jkn;Zyy;s%OiBuI-vc$>(LR97OcP0MgP@#a@m5^Daf37NR zo`in=P@#-bSK{JBg%(NZiG*hKO)t*O>Vwk-sZ0(AimC_1#})tkqycb7@)5v1OOyed zAW0KHKUApnc;b#jg_1O!kh?({P3Rq#rG1(p!Yx78H;?NxEE(piUKzvk^9u%Ohh!%0 zkZT%}&Ant}J}#*fH!ziDRG=4zt$h$n<}w9=zT-}^=pAy4++20BYj`*z)0I$kAN5}%I}73n z3n{))W%7MrunBHd$=B@fFBCc)L(BvThmnD#w+F57cQe@-P4dEdDyPP?RN}h1fu z{8B~5FCA|;$D|5sqs?d>MVv~zL5Q}rA+=_3$U{+l^ZBXHK2Pe;V$lAvS}V55uky0O zd8!~@vODtnZ2YRagAJAx!T@vAF-D6>`;>o*WqG;w=6{Z5iC(Jt9N3mi9kvBKgKe3{ z5ylgP)-(ctFDNC&+JSjiL$`7Sm>pK7`k>3>0J>(P8GXtXhAq&5pPwI$UX~U7Zy1GS zEvwt6Fp1UtQ{FYqRBKZaIabSdfc>>1trYh5(kgp4Cl=Ld#jkVLVH6km9>$D6((O7G za|vbxCUlhB^(N*#$8S!7+tr9^!|x_c6Xrq8Nn_ovU*Z2-?4M(v#%#sBi^=3q)cUs) zE((n{BKgi(1Zy^>;r)B1{$+ow;>;&2CUhZ{e+xARvlVsIFF`VypZo4U25O^vNDFHm zy&5RnW$yNYIqrZxcYK*h4;l+eW!j$_k9Lc27k<=O85jogn>lM`v@8^wWURbfMP!I{W2PVO8kO8|eO2~qEFWPW31cx7B2#^fegM;G)FXP|k z8nhslTw0SDrP%)Hq>E(BU?I);?mPQXbnP2A#X7ggcq}lAdfAUGS^mL!uBKf^6>>6|4KWym=(11jrfS~3Gyt=M<^6&&-1=s z^B371qXr`Vnkzf13wz~b8Bf_MGN9y_Gt%-)-aMx^BEpohg9wu$&&!Xdy`!q>Z?zmt z`hDj%5u@;-$UXp+t_&dGYSx8}ZFP~p;NlmtmOs}eT)t@~7APmvb7(Wr<7d3E6Y z#8}J$k;on{tM9^T-}%Gp)0|}m+a|RmwM6X?%(z^*%&zY??R_%2G{%T*s_891U{4$G zXI(ArvD-!FFfU|3R~2=~RPBW3%*sKDGCR_0H<0IAtLzQ3Nfk^}EWi;bxkU02P%gwr zQKC+K6(y2!0|b?$DEwx@t#igG=cqCLiv%NWK) zm$sYsF%5fjJGq?R6tlNExf-Dz zO*@R1A4zxEI}%H=8}<&9Z0C!pX`bFimS@%3!7Y($%C781cDRKi=-BQg9a`$DJ6(3w zK=l?KM|PWkM-026Z#<*vUVKCLi}4CJBsCC@q|CA%iBYQPky7*za%F{jq1-><(ko?a z#76jFG>U$LO1oJAE_JIrqOzj76G!djDsQZocf($czwy&l)+>VYwn02A6NI0s;AV|_WKuptjRN7%d7Rjgf`C#VOc%iTH zd82UxUEsjVZjsjOi_Q&uK>Tc@Nhmwz6smHDQ;yLj8uK$-98d+yP*yEI52v}i>9tqk zjp~jG+RZXD^s%WDkEa9yii)4%?UK_}C(z*K#1s+Ek z0TdtsWjiWn<{NjfNzBJDx}=AbgWh#q(Pr5nUGfnwQESvJ#MW>BS(@qB-lqLBM=$6< zp})SJV23ZOeuARPMcka04-P(vzJViN6h;Pidll19d|Eo2Q=DwP-}lt)NF1xO;5IKf zaF3z@nyv=XjVdSxrYQN>EID-K5Sb@jK22#jQGx6+gB%T+{9L~)MSkw3GleIS!bH}5 z<2gCPzd6*E$4%`w0?|4*?_=N7LKKvVn$BJSXt=j?i`1?DOm$4U->%YAY1cFrPWPhC zkdiWQ*XxKAm4A1B9VZrE?wX)nnF@Gx2mjul;bDjWWqSjC`&`sLMs@8=!*th5zl!wh z8Qhmd-6Nt4v%Gta$X=8q&X_jKoA&F;_QYul^!W<(HvoFS-6SYz+M5re zE@(0&L}-D+K}9Vb3NwN;w3@~Q&PjUfAO*iCmW)mz1>m`0zEFdoW3y=s9pJ5wBNQnp zhy}eHY8Sx4G+p-!CCB19X1Fse-ddB*!OyxGA^XfqyD3h>)I8MGiKBLs%tK?PU01iJ z+I1F$%Uqd7e2Jo_4i)3vbd1rd7|zgd4?$_X2Uy$#h_W4l#-z|<)McrLdPbuJOhM>i zdTBIyoDfFTNJTOe2beSkF8!&d(YS*U2xsCo6=Sr5w+sNyQ`paO(k4Fb%p4ByGWR~h zI?5X;H6jo4A=?t&#I!p?pS61$IALuE%B$=TgZAki#yxFj>_fM3OkXHm+rH-V3;y8HhpB!K|I8x%C|vBnllwP@4^2XqE!;EqlzDk>^! zY}L}%r=?*g#MUJ+31qxZrHhre+NR6XVrwh5?mpH8WLGxpN>#LrGsXq01((+R-=A~t zolF32`#itr^?&_-z6^8kxo1D$^WDz(`#qNU*OFoWyHyM_J-o@gdnup$hVjtNLzLD4 zbUNJ_<6IcS=%L=mWUgXOUwM6CpL zjEgp7{-86o+;5{rAz&K`5*@S?43pmexmi6;(!5_)KRv-jA-lUwu*AZr$ODHQN%A__ zB%+~5oO5#&?6e8|z*SF+Wv3;x(`II;&EchuZ0%(8*=OokSR*={N_H0@iVM&2J{`ikRCrM1HP0e>A^-NSWbw z+eQPaPpM8}9yirD1r48QN?8Z}{EFv&@5kj;_)S5PaRy)5o6Gi&MH zIDs5K!xzWuA(_2!NiutOx0}6iDH+?{Y}38E*f|x;rmxqbY8w`!!`b^i=7m-h2Y0MZ zanQawd-nCw@DuZfD+58fTPs+I6z5;<-cU4F+4$lkBx6brU8cVCyOduzQ88M#fkKnH z%CG(&^@aC$r)DS@&-cU{FGsocH^yuE!32mMSdDv+#Il!l8Fdz+)LkUSrmm>>cf&y5 zM(%c)^bl<3gFJ_lPW(k*o_Fr~^w4B3zNvh5w0xt4Nh3$Pxyo{yMQ(JZ>B8OHZ%43X zv|O-rpbo*1tGS4v9Mi3gjNwwj*9_^jI5p4T{KtSpc#_YU-*go_;ho(r(ec71u6N;5 zSXFE#SYGA@8v}GKD1Xmxk4cuSC7Fr%3ZW9c_~Odn7?ytcys_?*sCRw)%wy0xmapl5 zq5Yc5A%P_Q1sZG0UAGOkQHCAk7$U2~hBM0ST+^ofPrii1jX9@3iM)jda2pkrr5|d_ zEeML$#X-KgvwK_>*n3V;KoqbbUvml!O@CbtxCvXz%tbQS1Rh{QXtlmw#z)Q1x$E^MaIr>WkC)Nk;xb{W-HOD0H<7wb(+)ZSO)LKYZ+;x+*9- zMMdSmt;utY+r@_$opfbTbeM|%U7&SMWrfq(L96~GXhIq_6Zjd}nb7>(nb28+#%!jv z|I0yT_cNP?+ihj^Lz47|_v5Eu42oV$(Y|@M|NY39A71XDuLk9&socqSo>xn7&AiWy zKWHS>rcJ=RtbW{y#`HW@lgJuiS{?5xV{`TmGY>WF4DdoO-6Jrbf08~qcVASQz9#b? zb$x}poO`BL-4}|mU9o0ga4{+OMf|tS8N8taOJ&}xa2CaQK?_gx_oMs~7=Bshn{tV& zN@Mw!t8Pzt(YL|=iEPFCSa?Ot^H?ab^8xM|vP1p@n4)iZ4DDJf=3RDu{@_yw$e&KZ zU?|(+B1HH^=tL%VCvX1^(gsJhOzUcND>15#B)zMbkN}^x5kxS-95{g_>exG>U8&xa z7|j?Wba8;r7*r#wA_~*vrSuq-bv9%7yR4RIvfFGoRozI{6I8W9J$6_1zU0?BoUHeX zf^i_eG5?GGfPhimXHE)ru5F9=kA3$$IF98yRgfu`oAS+k^k+xOQ!zV?ehYRWOChVP-&C4MO>NC!%tWje@K zq=O0qv1bu~lG$-&=OHcFp zsd%$%2O0N27 z4ugwY>|7k2TS0u7b=v6k6&6gGfWtSVWx`kk{2){p=(!D7qRhdWH?uw-o0U!eTEYuF7*a9!tN4`h3cZd zR=@q);ZT6PNsoaQa!uV5vk(1dIn zi8-=dQp|GZ9`d{gdoZ{f_M0 zPz&2(Z02d#VH^P?Q+TkL<=1=2vf#I5`Cc)L=VuWDuT#&=tS}?L$da$c=3`1f%ab7G z0)8<*=4lbC81$j_F)uP&UU++WFiwRc-*udm?xiw3png2JgL{; z=T~-|RaW($KmCXiyjRyFN38L(l0@>|BuT7j=!u`$3rZOC@OWuNV&@#AeVM*C5oN`?>&blxIzImKKdo)8|@%kj`uGd;O6k~u=?i$~DQy>}r- zKZ9Q@b*ghZzD-W0UQo_Rx_0Y#&oM_B`oleKJ(VNKh(8l_f z$7tioVjBnWR5BN4#W(zbi5ObUvQt{;U4X;no7zpj=lE)Oz(zk`=|+C@$7Fe+nB_K} z{1H6~<5@bVW<&$>{g9aNfQTDaG_&ncJ2b}Sbes&2i07vqKW9;21J?32EmggR3KNY& zrt?F43qvwJL-1g286uCY9%sP_3K_32P4xPfA212^wp;9`u{`+*DnI)B^mw@a1gvnj zW&riC{MvZ}kNH^Y?v%#Q2Y>v?O zji0M@LO=2qvV5VKF-8&zJo@-a~sxC0!a*kfyk9i)O(;7JH%Ib@|)R@X6*V^n>{gT{jhc&VOt|MSby(C z)3DRo=~wMT`_t6@!(!cwdD2k2__aWPCtJ;;G;@0CpJk{auh%Wt+4{?Q zf2coQ>t^m>Lcc=ky?E-@lhaW{qy4?C`8t}LP;Blnzq$SSMS4KuaFNs4URwU51+@PLaBQqkRSav zu=g66h>@{thd=ZlzoIV_zf7?KTV3*UeK2S2PiCk%Hop+X@!!p@JPk515hoS+GXh zZP0HDb)ROlFlfx4K6KE>34nUG$fE3Q*;$oA~sc{lp?{{tJj>}fH07uxJ}K$`7cJ20h%EGHJTjOR&6MlzXC zh;-`-IBggF6{Mwx=Bz2EYyuI+;G-x7I{%RadQIyC$L>b7|q_P6gcij}9&|F9Wd?vZb@I+H$j z*SR@?)$cpZeA{=|Z|7&E**12N*jF}7g#XkfMua!0$@k*B_#&iu>;oH*uLzyP-?!ZwY@r{QZHyKz7uxu~d|vyLPZW zCVC1Ni_s?UX&?%jP+2DE&_#!x992sjB0UD&eWL&_pw9{KNF+b#vQ7{Zy6NyxH{9oR zY~a-m|FRY^bUJ!fIOpY+B{Q)<)qoMQbV+=q%)0#NpmVyI?Yq2lV9~B0+oTQ$+mf<6 zqWm_}P5DE1DX*wD9F$(@7xJsb3M6tWe$RxYhx>Yx^Nubml|D`+ zP-E5vafSusbr^Y#Xz$|Ae!&W(xUi2U6UzCs8&9XFq$aaXOU*>b7h6?6Gd>3!>Mr`# z7HxE^(qF!>jz0VP|6R0y{~do{H&c+m@0RGjAr?gIG3;AMvDij{o>ku*wc<=nA;YZ6 zBKCKAy6W70*K~fQx||sc-{|t(T1jM=6yn7`))ooQ!7R;)d$rbu;mGPy^B6VwUd>lxJr=}fWRq;cqkJ(NHyuRIiWda@65KcjIM{cN5T#X zRnhjh>*jG5fw~dpe30L%2{|=xjWfE;sfpA%qZ2i}PH;v?>v)gwK7se?yhnI%=6yQv zbKucPYIe&vkh0yCL-gI$yx7gaqhXh8>1~b)w;Q zb0dBW#oAHkL~C6SM^eSR0q;VCR^S2 znWOns7ob)l#FIJ9q=3 zVW)T<-`|8m_NTp$6>HwWOx*kSWBMh_1ipPs-*_I!vsd@}2@LFd^GjM?e)4bah9$v(VHve}$|VjnM&i$rlqoBXf|ObQGL0W~jf1@r!!b3EUM&8bi)-r$I!c+8-2h3OOBjkj21?_n1XWOm(Dc zJm+^~z6oQD3;USG`JZ;#h3g=*o9o=9U34!K&WqXd1Na0)0umVwT8V;BKrJ=kkkR0l z8gR&Ha7zt1WHh*?CJH_Qx6~xSCm@mt_yn}#ZcpGlp1xafpYXPLtDM_o^)u1>tib+9 zUFK}NG3rGtq{5sjsNYbe=U0t? zYM{P|XC{TBK)J1qTC2a0g~oNRolfmpf8e&Q9GJ*9R*PvHMW>tN*3KD*>)aamh)KSF zF}q}x)=uDqc7Uf-y>E}w^jR}uY~DfumD7>cT=S($h0T0D*1ZaId=_ZiXq)E8~M z;b>=s5j7ilmM zNE1)Ra|AQ-`3*OG{@ZTu%(|!(>*aYH+Fc&k@|ee1%un48>DHs!*pEW-Iui`U_RdV} zf$B=;k%vgu>`Z-++6~<;vycmN}G}t9mpWBB)!^1=Dq$@ zbJTms&0PrfD%a8GNhr@**0oZfADi@C&K&o(_L|WBF}=w!lHg~-q=|{&s-?(flZpMl6pnX6)6d=toMKoUnF@KY`Br6Js?=gWrLCA&vq~St=%%sx3%p`zEfA&^R?xY zmx}1~Q`*Bmm=Y$12!N@IQ?u1{$F*-ndq{?O6t;Y=Ed2~-emZNnVub7EjC_Qk{`E7A zpuQa{cro(1S@^!kOT?{5WKU)UE|;r8WlAP>uvhu3qXSV(QEgD63d*s%#sID}M3#g{ z41))2m6=H=vC2G}&DmMQv&6n;D|bO+XJMXTEXB-eCY{T|Nb#dGJC^^FSf z-vip)@Xg$_fqdmG+5}^%sGL#=dyicXXlL8W;fq0TuHC$ij z5AVx(-^6oF zvTq_7T!(mcov#4#H5y;N%5Je<6{U4n(o7x*PyqG606=DvRJ|laKmwbr<>JhZdSB`4 ziOipkVInZ5r@H)RFr--a^ubA6*3I3h9_HLge(W#wP3yUpnKrx{23fMo!uAUpVe-Sb zVzpW-Pa8oRftvX-va}JNtwfC|UA_r%_=mn|EHU{eUxZ%mi_lN{BDBQj8+@_Z{F<%~ z{i&VPO6a>;dU&E#y_RBl|Elozxk!>AVG9oui(&zOQ z7Lw!S+F39G?p%CWBa_f~kmV!fa*c|i@KG(D3Yt;|>%mV%iu{DR;&TA+75U=;<5@N$ zSp3lu@EAIzyV*&r>`S(SJ$UwFKp+wx0^c%(w=TgA^KxGV0L#DlbAgP=cFxdP$o2CH zL#{=GjXoVhE!tV<$HTQIO1ITdx1@R**&x+JJ~oI{WA;sYlb0uqq03UuA(kODx{H8S z*`~!-C+SZ{{>#@KCCn19ZOYA?kSte3h-SK`z#0mHG~0OTVnvBBLjTk%P-sX#qoLvH zc+^`YuSQt&?15l>99D$KsVz+$-G?Pl-lrZLHmx^gMzJ)p|s-s8sB*xg<3C|j~R?UM)Vf495C z+-(Sy!X>{q9&_t*6(a~8>nyt2?5R_XOBP4KPR1j_x#x6gA1}S>*buz$)6w#E&OH@w zrEq!X?UT8wScS6RUMavsOxF~|V1ySO2{l*Iulh)2ZIF!tnzX2(snpKv0E` z-d%5@R?-}T1EFRJy>Ae*9Y>_s8EdVyw@ zW$llKL9~C?AgX0T&N#QFB>zA9WH%*0BSabD7EP*95>^$o!g_@<8D(v%WCQSpiroaS}t5u-6i!cMeh`1=vH4#nh=iX`#4(Suw zia74Q7&wk|qAE1gm;nok1^zH5%5f0Pa{{uL#?$1zlT<*~7ozu@n#^YYF?Cu;_NX_# zmfM-(lNLy{W8?=pi!wYhF({j)F#?kT2nsz)m^Azf+iDWtguYSZm%HUX-c`L-u6JB- z!&V#!BXW3xU|mr^r$~?RC&uVH!7}l!PC*O5AncoK#j9jf=IyfdP{8~77UUvRRIP|i zYI2Df1Fqvj4jqxsT4ALwgU^MR34(F1qF^YJM&RE=XNFOk5sD zp1L%exw@__eE{2ZoI9~LJtLYmF5J;=reb^%XwNHdZ_A$x~NXup7+jc>a4Y zRDdqGYomXH95N;4MDeF4)CRhddYxE&g6NAATk2X5LNuI$N^HPC>l<3rSa^!@&)S>3 z>E9>3gDA8$HCcKDPD>@DFzOZ{!*Ayy%All5?ISQf_1N+t-A09xGAO-T-?5xg^ginP zq=aE@JaCJPJsbsHZ*~9JtFJgFD6H`2u6Kd5r=OOqQM<{0HH&;4{lR;%+T{2&05TNN zQLx0az6u--u<9pB-Be1hO$}8z#XjV5SuReExT_TekubqiO}OCb#A%TxFly47_C81> z_0z@d+DPljCNH7@jp;Y~zNzRVc!nTAvU5PaGeAjMPJA8};n%0ed=*9)ojoShNrIp* zcn@fZpSAL_2hYDg|L2#qcej2d*t^GnPJ35weyPEG_o~*Cy^Cue8G^lgF%4hb=z7n( zov)^UZngpLQf-slFQ2uu@RC75(-?D4s@iiSL|yIgC2l8^6R#!I$~t{;E?=B=BjOlY zuAcOpL`sw^fSp*tB+6p2^#z}7jEKztwdY^Is3Pbt9`lmJ;W+vcwbPC^Q zn4Q_|75JMIz4?~Cxw6r)HXpaFO&jvLWo}Y+C5%nWJ_Ah6^Ehiw;8?~#pp_$Qg7b4h zy-Pe4gZ1Rz25?*Ipa@I&b6R2uX~iyD6oLE+oUIIv7@$g})M1J|6-945i3@_;dn`Ab z)8C5^XuYgdAD8f0vk#!>_;SU&)dcjMyFBzyi9Ps>n*#dxC+c@PujF4y$~2#z_fI`e z{e%i6*lHS|hR}qma5lZzIFCX^8AAR#WD!e8aG8ybZ6PtU6A zh6^v2zIej0{G^dy;WWy|hRpw$xu_0I{D&(^L@iR0Ld zAV`{>1C!nkj#(F*fJkyzV^qyaFWruKutcPX|zPVm2#Hd>KxL)MT5} z(BHAukm^byKQhvoc6~ss-@=*N8}%|90Iwa0b?mbrK&-u%k`4di#JWh9<+LLJ9iZCr z$wkQ|pw>1rksn2!1u@jxkm`4$_nAH$QZ3EvZlroXiI!B)<7szN4T3YIdJd$zF(B0` zk?Khz)jLwh6-hO;XBgz!uus5m9+w5k^RMu_*gl2QVyMzP`JYAG!O0@+~i;kI=-sS`qF`HulChLm2ZJB~lm z2nFE)QDqST>df)a*VO)~?;T{|X?XwGx0(e{ur(uLRU5YSkNqME;P1kjWQ+lgkofi5 zw{@I+VHHQy(eT!}uvfiJxr$YN<@m_TOKn52BHjuGlNO*Pb2rzkt3(=v@A~2d6Je0MkQaAdUJ?2xe}+JkjJBD^>iKh!S&7@7oCqUqC-f9Nzm(n8VjEiyNsVXz^$C`bSlsWebnz&;CCA~ zY^J5rjYS%Lf}zply!AS*BUt1R16jLJX!iPY0syUP*@Z%Xk9x7&sMj`{qkaO8Psn3a z;##|*E^@QXb+*&KJkysjc!R@>*t{-3_341j{1@GII(x|*_r9(P05)S>E6$bX444zq z3OTd@Z!_u-1ZEa<;yZVO&WyPlJW-P*g)8!ZTN4c6J?6cC z1rzz7gdy#El{e8ILa6l@Mlv>o+Y-c19~2(an$8s{9VxSWYe%A zwN^Zb!yPJ`jeTGY0ndui@^R(0841~}(SgR3?Fu91fakfpY-{Sc#b|_L6Wi)qLH25! z-n+;%o3zKhF`M12p?WbRZ~I&?;WFM-*&_^p&cql3|7iZlK5Y*o5T1aHk>2KKJ}fvN z@-v^^1BMhMFwgZ&#+RaZl(BBY5r8Y_MI8BSx?g$4GAV6SiD)oAls=x5r1tyk$Q9^E z%97#jsWFB0?Gy_EC{~CMTvyiNjtLJoXL9Pa+5UeGB?3S*Z zjf@)WvY{j6Y{r`We^pdU3D|WRuuUG<>!@GG6e*Ho_BJCyGIQebW=Cz%>t-V4^!F-| z2ov@g@dtazu3N9BTU9?G6+xWfcB*zhfCbh=U%AGBVEW1WdbxUKe##U!<>Ix$dJ;WH z637J6D-Nksd%1pue`nE?WKDX91sd&rd@CKHoQEiYrpt9PmT>q&4H+`(Ja`?a7UnFH791~2c0-dD#oBz4`qv@Ebm(dhQ7HMvw!yyiC{I4$dH{qee=jx(4Kor?X$Fjx>Iy zCY4af;B6;L4e}9h)aJbnzf$3?61(!Ta}B%Vb8E$uJ{lX>5$lRCFm3ST`}JhI1rZ!F*vKGt>r!h8FwS7NLPW zdGftdym-c{J-phP_I7@mO;GDL;fExcCm|Tk7X!S2#_g{esOGoI+?PuW+LUhgt5rrh zbD~}$prjdk)AEuH$LS=V*RjV0S#X<(2WbANklQa+VZ^MJo0-Twyy0|wgFI@2YKaMA z!V%%=tr0~6d_B~#-Q$F?Pj$UD`4LYDwT4CqsP+7_wR}dkGZ?l0=u)9pRJnUp>twly z^VM{>K-1OWnKpW$)i%=*taC%p#AsdXp+)-adS_t!RIywUHcW)jaI~)F<$(ofwW^SX zxL0vfy_;EM1f;cZy1#Tiy+2$vkki7ESymKi_6E!8++g`~)sE%dbX@8#n<`&cw&GX= z`kDJ4Vah56B&LF5wpvakNh-eYZ{Gv>G4%_KJlfEH${)&oxFhZ3VLUqiO(o4jrkhe# z#xntE*fGC{25Y#?V&`%mswn~TKB6X67jh@-UmTA+)}$uW@!{$?;Zuzxh8fuKJcrqw zLP?2W0MVq5&R=d)(^UbeS*5svK07VNe{KK$QPF)^+nSc+d=U5B;Gl&z(kKZB+8CZ+ z?za&P#Q0Y*pkmeL!R9n?X#TGH!< z98HW?w;mmiRx9>d6$BDv1jU(K>w3dM@$-MARbs@iqeiH1`9nPGRDvrWfCk{l+jA&4y- z(EEG&b#n_AKg$opXU{JZVpm?;Vv|Vvh4hGeO;dZS64Gqis`92&FE!CGj-2W+zPuCvE0>V@$f%d4o>9mFfDo;@)u#v==WtaofEID@ezvfRB=dE z-YE=mWM3r_0~*#!lqbN()arz{Z(k)twn|;bm?ZcdUC3X1T5)Ldx)iRA^i93m_dBX`n0t)+&pMRI(aNc#rC zu8MU0&FSbPHST>ws3y8&Imqo95-^*KW?rZen-@uqARRon+@ybom3_@z$9pZ?GZy}H zx|uhwdPe8sHTo!PNP4u1EHH~KpvaCH{3deWx8T1%{|jUSArFOG3y_C55_@YlQcXSy z_~~msUkeiCy=P zg`Z7-vH<~bV}2aV0s09rxZk}8*=6e9U1qc1s_yMFfbaV`zQwQWJ)|7m1sDE9%aMuP zZ|!h4sz1y`6XE%+s7!JE8K zCA>qtjICp3x<&%(7s;};0>gNI6S)WMM%|ddZ>OCh#anZ|Z<%CyQb$#zH-%;2n`=e$ zXSSDx3P+LVEc}@MweoW`{AGW=p`^w2KETIJgBBbN9jy2X^R?nWKt?+J{z*x#{;lAb z^;Adf2$q)F0sO+x@MDwV`^wP2G8%rRWgH7`hqEF7GWPU>&;=&bP=BVi-VwXrki0?Y z$J-!<4KPsUoy%YyZk4e|K1Bjs#6ODKRF|JUO+e5FmkgUu^K%af)-PDk!k+;E-zD41 ztMJ;>OVC7-4MP5~cSK+*_EgB%(@LSnVJIgQ!?>?rer#T}TE~-1G$usdZhmzEOzI2a zw+Wg1yxaRn#L+|GW8eVS=jZKHi7GQ4le2`k*s?M>uwCYzW<@2AAdC_cQ7M1g`{uTb zgk>m@H5&WVljPpgQW>)JPdjNBAs6&L zF@OUjlGW;9OF4r!QG$&2)SSg&h&9sA5sdc5D~#CXJ+l)rkxRRqi~782wV)DoTRwV- zq#82Y9?BYS54PJ54g>sy2VaO#Gb%kYe=WR=IH9&N)@;0gg;n!%x$4i6IR@C{|IPlU z8!~Gm|9kyKmo~#3gc+>nRetOJFzPr?c{}R09?U%Y{e-s$x{}}cCiC%>Hiu4$6kPB^ zAu5v+AteeDB%n)A>WJ_fz^d0Oy@vr-J;t6O(=B}Rkg`cpuL>S1Rv=S-YaT&z=j2L1 zT4|nS70^-JVxA#&bf9Cca-+fPHotdT%^#MpL{)y@CrO$1usv?e`baO^3OUo!*KPjcaDTZ^uAo}t=uWQpSi;x*muaV_P$6iT^62K)p~II zwWHCunE=3j<3*D;=C=`m#~2J(X6IFNY`HZ(#u-N~993EU&M@2_JGZvgsQ-$w7T)eG zm<3G9c*Sl6I{=*yX>1akuCH&`kk}P>9BOuj)`guv3zZUJRwQ!OJC;|ZDwbBI%Mqjz zr+pCgzn7)`?-jd#|3(+}*+}i!d53!TNBY%6d$qB5)Z-lcn7*iZQAB&F^$fi%+cue) zSfSRKvKd=RJp?xOM=Q&=H_1{LYCTL}mIbwU^B`-=kxJdRf2!DNb~i>3Ad;l_bpB+A zAo|?lNZqhkamYUUl0 z@J^`}tv^WUCI2Eu_uR6wiJaaU(t8|$`XF6llqMNsFWLn%`aK_~p_WJ5UYq(F*qLfl zvaI^DcV;y|9G0Z&ClC;*VFz1jxZC>z_}P)9y@9VBQ|_bZC-S#UHrRKpRX8Bepd<8E zeHX8=94jZM`{W;QGi+Ca!-~Oq{DQ?Y>K~#sws7bANB6;JyZK1z;-|yytcN zJ>00RPaI-d-fptE(sY~i_rN-9L;e>DCd8l!oiE9pY_>RMEpoJRQhf^b&4&E(FpW^0 zifGrQdV8M$20RAKZ`(h8hG|D!4Pnw{jtTGoX?XvkeM4gkn2K%KfDBT}{>EN3*WnX8 zoh2cEj$_;PORrZ@>=*7RaHs2B)1aeio?66G;!{Bn zPUj*GcaME}H8tEj8%Cgsuqq$Ync#FFf8NQ#1pV3cXk-3!#XdZyR^ShXEfSs+aM45O zSZ}o36Y2#|Fpyzu9Jx{i(=hB_e_ANE8;8rg19;d?6 zs*1<4n$=*xNZ_$CLng2aa66j-BiG}I27yhFxu$zpb-vBIKoFX`Impxz8Sbx3bq2bl z{i$cToktw_Y{QT1iPOcVx5>N>gXO18xm*uFm#>a53zZ34=BTKwE86Tkfokk~MDOu@ zth6dwDE-Z8JN6()d-PZ6geAGnULTr5f6VC1PuRjC0&* zdW0c!h3zx|D{IN+Z;6>}h#g^HRK$B;t|8WmQhO{rX?sDg=v?-58!bi$we&MSkdALk zdTHxnvBs(_Uuc5xlV=1i49%vokf;9iTnwnX`!1cVDQ+E6IR*e=u=75nUZ)0H z@oDubN~H}9wp!~nk}Cs(eWV@5?EI@(xtUQ6V-P9Z2zw${Kl@Y$Uv}nH3y#qFp+J$1u~KJ`%bZ zLHL;~403G^Q7!(WCG&QoX(;g@57s;L{*bx*`^(EMYKM{6`AM&nspX-sZt@+>h_hfM zFO%=o>s)2-ZXVDJcIV7mXSeLT~6LJC{q#EvXmA11}*6suCx!(6I3oNgT&3v-t z*YuhWZ?8(9Y3xtea!9eph2XggT2fj_h;VSBZRisgnog|G-}XTTQ=c1Ls3w#i<$CM# z-ybV7x~XrNZ5j*krM%uTJE#6?}3*@)GKRvd8mF{LCO3K{PW+e*0X7yH0YcAu; zAajW!3+601nZ#K53LZP&aWqwClZv6c;V&3rL8{u$i)A00@vP_?yxO(+%lD@~YR_+) za*JF(n9CzJ<~O*ET?Md57QCe4lsD#=(jDW92cw!;f!o+<>pQiW)_jz}-szgpYaGrH zM1dYij070>hUqA~TyM01Xp7RCyi;K&@bd00Q=phrG3i~K8e2TSiDl1lQRzz7drOt| z_e8@zEmai8=%f$bx?kZKeAjzgew)ZWq+3w9U@j{N=JJxia*B)NTnKa~ zVsJ&J?nT;yCfwi4HU?!6q%JT!?} zVD?{h7Cuf3vGC`roy`3tF&AbpSFb7jnpa~c;Vhg)r(`FQ^swJu)T4YH+#J-h#NOeT zHAyjV9@57uD?V5hOE>yXjpka72yuiFAuMjyhhwZ1aemsOq!cRaEq(G|LYjzr&!A*5 zDY%8wrDr}3e(KyBbrO7Vx?Ii&3I{MK3t1C+Rd{G`c>aRDwSTs|-V*I=PApPGS49#S zwy%nuhToR9`R#ldy!o_aze_6Ifp+`OmCUs#!sB{p)moXie2v$W^d`|pH6UWl{H-7U z`KrxWHU_9JBviK;Vs*0Zfq&uPpgcu%_$^u~ol|GQ$JG&YH{$ z=JhtZ1aVn4Kr9~9;c`7}-6Pcn4Va25G0 z!T19m8O7&V_AXQFz#_AaI(yWR_l&N()e>JuSNiIGpcRt~=k_JmneuiY#FSwKuYMi_ z>pvG@I}66c;tAaw6M|N4&i;?Ur~YQIa|UQXX|E8{L@2r}m(xoU$f z48%?RtM*o&y{HkeaxWa@ESPT}3kSJblN^JejCvb)ZqB?D@E@9|COeM^*dN_xcQj}Q zL8f6Y`WTo!4L9}y`{NT#Td+UIVQSh}uBnQP>p<>SaHIhYP{f~uP{E--D$pJ3OPv$W4E~a^K zp5n&(9-jtptdFWA|MQJ?>zvXR`4#8S9aT6XTn3iVtCSYzV&16 zSHDrZvyL}At7%*QBZInO0fS-#dkVT1-&V4r#td|!4@_>TzQ3>b1zhZ=dSw`Z!*#mm zEAUggsa`1ER4XJzb=qybE}Iik(?;olF+^gAl`;D{&}nn}j1s(r)jEWBb_W&XJ^})6 z?HK~6pr|`NIDPgez269#C$o2n99la0*id1M?{qPjR-2Q%j>o@AAtKa!r#`n|(~PmI zV%7RhNj(xR?`gu!Ub>oPZ-J;Ihz;LasiFScOaaKD6vA4r_(16LIrPZ^ErdNkcXYs= zf6VUmGrm+7Ah-0;V2`KmR@{aBB^X_>M&66T9(ES$^i;Hbj~h6O{=wMZEVCT%`~9g} zYr|``Oq#lF`*SA)m9)2=%FN}=(`h_$!W4>kyqX%*-sbWu(;~wb)CH}mOVSKIK`7v$Lo|De?2rH-l+2j z*K_-zdXDt#;hN(6CwffJRs5V^M4x@^sw<+NfCDORGEuj`v%kv+W##r&u(5F7ug?2Ps z5&9W_Ro6+a8~j&ZZau1o3>o5|rRhiKAyqmLsnNkkt$%WZ{d>M)YyR~i!ddrPb^_k2 zV?QmZJu425uEbSL2oX6+kY|pohNL;~Z(mBgxD7g;VmGW5|8$ULaaH<69i;%kSKK{> z^M?NPP@N<7jS%@FdX!hOhAO&)DrOX`_)bv8b}V0}1uxCKoEW@p$JB7Y;H8@{FHnu? zS>14_?KNFC zVKZbCwgNkv2T?G@JGP_`#R)}g)sBx_M-T2FTkd6XX)3>m_H_L7&a)_LMjA84&)@1o9saz&i3iual z+Fb7j{RGEWH(p>#s?$}gJQInl<8)@pu%lB`Tag-`xj}ub>KkSs@KH1dWuf%ZwkO|u z_XB!jyFrJXj@h6O%BjX;xeGqHobs7+6Aap6Y5X_#c+I{w(f9C`GY-UeoN@wqV!zC{?z4C6*PcVDuq9e2{{xjt9JEKW#OCO>Y zO^vpbR)N!rftJ2nn^0Cv80MFPdzj8;!^6!WZ=yDZKf_aNKu-du*p3n0vuKHhGyszx zv}Q`JN=Y#ZGVB~Kz>$&Gy8KAOT`Ty{Om0gj)(qi%ad+yH7-u)Oh*)zu-;5`qi#HUZ zrL<|}pW<{ZWIE00YCB%9?DxSn0JU|3G7b?MvJ%^6tB&rw7MBMJSM1qDaU zAkKe!Z$4`>^Jn;<+bRv`QZgZhZwhcq+iaFX!*E1_FbWOoJeAah_t(NkOl$2C->DRg z+i>6nJjQ@R2Prm+6=Y(#{mXgI+MP++Q6CR449TU{1DwV3Lb5AjpE z-;4B?N205v)zkq1to7|X^XYT6!%IL?(CbdTy4~q~i`^%TbT_{ieILVrDUrL(q%jEaoDryCL1C!_G zxaDGXd`T@88aPml;iknL_;(XNVYcafXU~=Av|rsFS{>IlJ@n>iG{y?`fsKUIaTqV~ zzgrDgK2}%05E=j;x_|7khaSW2*nI9E`$HZFKJ2d#1sE3DInFfw(ZP(kj$u}~fqOAP zpR{Dy(n#r%qW7IVR3dYPIbM@@pE1TU`w_sni=G8Lx@MHq`48R=7V*cP9#f>1hKQ%e zFRe;_j2tuA{+q}g&;%^Lc{9kj3S!WyLu4QCm0DP)hbM?}F0arwwi&iKlk{$Pw5*;2 zmpulRI>~kqTZLR#jOoa{Gh*J*sPmJxEyE_?!l2UF;pwD*aegNZtKCi>)06ZJglnX) zJuLyza4Sreodp-|TI%?u#criD)w#{g?Lspwx5hstO&@ES>0|h)ovn=v7&i)Pk68U6f8 zu2i;|%0L_LlqykEEb(nhSk7TcYB;Qh0KIRR&vWF*{a%w|P*9iIE_oXQy8Aq4n(E?}dlf!Hi*iIXS-hs3bp_F0q!G4eaqbM9aPgE! z7$3^jSDSo$O==gu;=smPFjbgROE>AgA( zwZRn7fOA}O$X!}FGt0)osV4uGqIK_al<;xJkvtlL-moQZnJnMRvh`Xl69`p#@VYbK z>mRTu!8?6(`;}6jzm7>?33_lkOz7Ok%h+Qolt)|8HY#))Dzy?-rfBIQbUfj^%=a?xG$2bM#c-$I8?0vS-TiC6RXhFZh z173LAYXVAL{FOQ@{08=%1W?P3+0I6@8feoCqNx{=hS~g<|9Iw&pvSl100IDtSn95> z_HG`+bE;eJ@Doe1j;+93tUUR9)&qwZQd<3lZ8;#|INx7s(<}hbue8jGA;Imu1e5k8 z*#hGFl1UMT_NPuLtNe$j+lgLNG`=&uAUYCCIU%D6{lnKIRW)tD;(601} zGpk$A2+tJDv)-E8ROJ`?5SAI z?(KWbZIK}nX?TWUZWQ=ST2w7OEJ3V}#my%W#kJ@bNM@BA>?(fZ3?6;ZqZ!dKGYhzk zm}gskf+ouXCp}p>SNXlDlv^qhg$*U(k~i8U91_wMOsqIqste^OkHH?}Cw~+4m~D9B zPd;oL{!Lbq~oCr&PCoAv~pe?r169xKU=z8VkX} zt_?qtI>85JU4-B*e4A1*2pHX!K=pyeCZAKdS5vj?nTDksS4%X~^8F&ako3N;iePxU z`6<>#C?COge&h-OS&;U<@pf4w)zb*#x{8L{wAr}IeOBX^fYoVzy^jxddz<=F6}4_l7nnb9JleYbUE6z94OxgEr(yaWK|}!8SE4Wn8|P7 zERLDQ&R2qwx}tjis+j%iccXN1a!EhNh4)0#o3Bm=tK~0rusC000t;_p45e{S^cWfTg6 zmlYp^g#TNAnJ$GheMJ5&M8NCeT}VMzf^%)GQ1rdyR@k$59a5}KWKFL8%c$w)H0304 znk)K=1V<3No<9_WrQ#JA#izDmNBr175e=TeYuIetXTgbTwkBOZdzfVGULi0g4^ zV!_;4E`Hhc#8)-My=ySeTJ1YN-D@158l$;u@pHMRs`bEVV=J~A1{(Sf^PZGh=YOI) zAp-1JZ&fsV4dQtkOVgpJWAy$CF)eMzA-B02T+Safoe;~G%a&E#yw(F5{ z;qO>|bxoSpk=Lf==tE&5Hc>O7$RyMrCClHDHad1e(d;Aupf3A%{bDlZJ%l*wE3~UF zd*BkpBQgUwVtZ;reB$YKtsf^^EbRodkiJjrD^6It^(bU~u=EhPV2#(yb|U5f zjw$7CV!aywD?J46S9e9dc{P2NzY`GQvu^HDIVNf@Qu)RZO+9Bnxr5e7teelfilU;B zSqutdrJhe}RI3+W>?QyZgSSK3gny7{xf-S)p3v(aig01m>dd z&iAP$=`G6BH#3nq0z97o2g06-4B&LVZohByzdId|l3*^3=3J<-oMiPOQk^C^m*2y? zO_2&U<#cqDBbuA~{;deCI3nD@H(Ez;PaKL+VF6#smabMMb=6ockszBc-~Y~8bdAaj z^1>UO%q*3rGOSqVeTu8lG&%CVM*~%^e#Zy;{V9^|{bu3!Tee|_2Q(D^27qV+M$m;y z?o1~SQ;A>gll4GaGsJsDid z_Mz@j-zO}7@*X7wpT6c-;CZDW*_-UucyTAeoqX&eL1(eMclfOfo&}`%Ego(R-F&~r zebuF1AvQHdBOA{2;9OER??}_T)JLqnzdt`mAO@RtZ9A~o*q{8yo@Rjt!a3mM+)f){ zG8-8FLOeGKr8@>k!%u-w`0xK|`WN98ld$)StlOh$@G7S)FFF(pVfp?XT$wEkh#D3< zs=LPitG<>;T|kD|5ix=C!G2yZCt4Fi=+O_rhkt~5^lnD9K0Ziu_5TVEi>8X5=#a$)5U+D+;LC(%emvhu{`iF39vbFCajSVC+ zR_FW7PltYveMo+rPM6FFlh6p{$Hzq>h`EiVmH*lAE6is(b)iW=PX11f(eRGBP2qI) zTm`2#4*M5|GGD8rkqgLXeD#g0tVBY!$bYmPY@xF2^S^tqOpg8M%1dHL%WtKajzlw$ z3<<_-$D02fIwbY(5i`KM#0wfF_?tX%;-Sa^T+zY{(F4vLh#rvGaY}Vn`WI2N%gx;e z8}qX;RaRB=$t^c%jxlO+YekViIyiI~#(_gkLr>o&=IEiO@4SYsc32&1H|Y9Lz_)b$ zql0RH9~=g&f!pE6{1%=CEoGVJ>LBWXv*03-XG2dT={O*ZFlx2rf2u*rvsJJnuWJLF z4Ugo*FTzmIf4GNaI1%F42a)`i8fHtt<*?3sGKsQC${(-Gz@PWsZrX`?XW>+{C3R>tyhYwP<-Rc#F_u?1O`MRbm&R*L z%U?`PIq!?Os2f$QW!LH~yN0a-?f5fKvx;g{XZj-t_PKCzk;bnTxwu25!p5G_;MDZq z-s!2wk;&|F1&((q9&y~at<{2wrstY?2Ltt54mEPN2_KMoWkSsRv2ZbQ0t8K7 zAvjFTwR7ew`;ADbwbrQBn)gpR!F&lx&brV9Z!ikvnVPTWBnCI*q7PCX`_Ee zBQbEw8tt{Cmx8yNf<3AK*wJ|r4t-T=RNc0IE{0oDQc2sze6TS7Wd7RH4^w?^G2jw= zMksJurg#X86r=SFK5rkA{*?8vi-zBF7IdK6Hqe$N%pg1^izb+vX&CwdNc_b$YwZX1 z(1`%1RInww90fX&d4+=4n{C+S72>+h;jj72@30f63rG~V#B5Gr0_aH9PqzUT-G*1? zOdg4`nY-zzrPmGp+;59IB2=Np?!+}%2>dvg?2>5!FCkWRP-b|Fx(-1mr zQO!E!M}@ynVNG~@h`kklBmEz8(iVUa2gCJh6$XQ?tT-CJC)+TKV4~67HD%$ifk@iF zrbrl892_rC*Y)`)3}B@XMOpJTA(DL+2Lo;1DjNr*oH!T_Js|2+)NMgk|0;$&9T@Uw z|8dOYgn&$XBk5NTWAZ-91N-3XI-?_h9Y0d(g6ITmf!t`pLoVeJ5MHyDAA@)p{{5#{ z)V~c!Qe~FAa@l=8M-t!WdKWf}{{SH8BnZ06#gc~qKuOfhoN)~SkrDDw{@Q}$>M9}Y zrs;A|{Aqn7wI#jFW+q_;LOjO>kayM#vCB7oJHOO5A(8oeKk}Q7(c&AF0Jnc!(f>$n zN(1hw`MK2~wM6edoCu-} zy*(@vThC91k3qQ)=HCwc%x)iwvq2U45)@WiZbXC%6 zL6#xo_~i?}rjs(%IWpd!f9~BfCKSkUI_I0UiMLa9CO09M48`d{Yj01gj1cW@w2-_R z6F!Y1YDy}~_`vX;j`5{sW)nN!K>sa%nNg;UZmZ?;U8nO|y6;ZJaL(xvj}sf&TX=(C z*rN%|vKfv+aa#O>oI%atehE8o*0r++_{3FIyjZ1qB!3$HH~qbyiltqcZA=e_#&VG%eMGaHzeXb+->#oDfizaf#uG85 zX*y2F>7%gDPM-%vd5iT~0i(P05Z-(*!y~rxlpb8tr73`)3p?5Oz|*>Hu2CzS@D4Sr z3=;8ih?8k0gTW((+jufS+ks;rHSd-1_H)DQ(tE)jRz)XHg}PeDH?=p>bkbS0k!Mvc z!qR9eS9G#s{d0XB75NYp)d1aRWP?!@AhQdKa=MmlRZUPJ+k$D%cj~o6xSEdpEq%lw z!x07<7A_;*;=@%Zs4=JWY*Kuj=ybZg2ro`IQP9+cnKFMkhyHuRxzx1qFAV2R>4og7 z6h0x?SDX>N5kW6Esn8`%pEodqoXd*izP_+6K&#_a6fmgzvoRk}ZQ zm3q^3v8`sO3egt6iPZifAW^qlTUwnxfCNTuL0f7h;XPk$r*JfFs2>AJLinA1;e5T0 zPyfSZzWTUbr{e>3wvj0!@t-I@#g-b*!C4y z2)xj&J{8L8gry1w%G8@-|Bc>!{$K5lXqI}TuISRT(#{z8XfdbQ#2BweS)|>$Xaz+K z1UGEua8kUY*zYFKi7RkBBzk#*$n8z#1U-h3l4EP?=(u-Yb(ByDBhmL0rzufBT!+UA zq`WXX3+$z;+;Frib$tKw@MA4c*ovZq@FjxhjhAMO@SK{m{uQuITBH8hF5mSM4+3E_#h zDacszF(dAZGcpG`k+aUWfuD-{n+3}T>2EBj3zL3?ge@_a5fS$Z>~Cw_3M&u|v9r);^wDCyr)vWVim1xig9y=vh-C^3x+}Fl@B0ru( z_V7Hdt&hJ=yW(*#15Ljp8 z;x`7SiQKPrke3kWm}H6TaF;?&)tH|F9oIz+Z0~jXmo}CGV0rj2$=fFIdR3^7r_N}N z(|I~`VYa>W?odO}BY(br4AaZq^kW3z$iMYV%iOi{-6+UljY!cw?w%)ft&STW3oHs#9;;_*@+QE%r~5o#+@zCm~+|JA>sq{LeAn;V$aa6a`h zj?JER7JL*0AoeGs9fkgm>of>D4EPa7x$ugygY!Q|S4};&tnWF?|4&r#!ox~2hVN~C zIO-2s1f(ji9M-pw31ApQKj(V;axjFH?{NlV}f?D$DlTSgI_$=;8}^ z4M+b7_{5&tA?PE4z6#>dU9aA=QSa5*#4pr23+J(fMy&sxJTavHL85|WSb5%CnaoXE zNwctuQ#o0kgpj((K$%X*q(W5O7vdU|Bf6ubUWyeoHSW&daWysLd>0XKQMW$p=F6Vc z&{%eMb>9j0`1~Jh7yyY*GCMAron4G*pFqcEoE%ipi9ILpkc_EgkcT&p2Ay)d=M-O4 zlmB(M1jV+C=xZ(3oJu1K)3E$d6h@sr-cu-co+TjUB=ywlZR!|~oz)w<$sJg3rYWG+ zY1_xlilWqhsm@vOnpk^meV8L70gF^MBlOnks!jB07x2x@4wEzg1yoFRt`K8gUHURV=E;~uIiEh~+l(Qg`O3U)lEyy)pC%VA{RDU+A+<79N^nd#XwdA{Bj z{eXXyxyn@^f6o}}g=n*JB^>tEK%$r>6Ox5AhK&pSSK+GHL5v|Kv5 zm!HnA6F2Y^VsQn>%HucYi#B)1$hSx$1ThZaMD)nPfA;+Et!`5%vy zENL53;RT32ymQrnX&c|aRdi}Pe_8%E^A`%0m-D~=^MCBi|ABwY{#hM(8R9(1{UP>H zTY9iYs~2LE93jQBuIrr5v2}tUG_ch#|C0+S)u+(%hNwT*PhzCU-Go!j;KD{l-czFqL^WqK%4oLV#ZSoW8T zNi=jK?)@V^@k`at!mk@>zXAykXrCDmf5{99VV3}w+|fZCpMMag&EA7hmpUYA;V7A# z2Cn(N@o)UKu(Z>4Bo!rDAG6jQ^M!BIpS(Wkw9;BSvDFrtfq4e2y4f4F7!1?t_yZ4| zS7@}(LSZ&PE0(%C+`*7RHVf*`v#xjG4ijP>F3FU)+5^SsjCtSE2&0*I%TnW#{*vd; zLh-pi@BUV-gTmZzNzI6ImsmEVynU`;S^8vu()?+%C+ou=r1zn|!~KJGZXV}SS~Iu# z&mC^aQy%j4YUitM*rJ%h;Xg|#;02S|Eq;nfC->>a!`G1BEn)-LiV|c#&7`K_v1%> z7o$=UYSvP$NgYK!39Jfg<{rLVX`Lr8@vUoYFxN!pJ}5}2KYcY%dFts;&*f>GdHTF8 zSC1;z!kt6h9yBC`jL8cD090nL^fn6VR!MJlyk@J4C9loMt`O1&gZ5}0mBv1;}7RLkk* zXnWeD^;k>2PCyBWT*N9^TaB02NvBrS9>7bT|M$1np2-B%)Al{@`+xs`KA$lAvi7<@ z>v^8_T-7^m7WK~QI*>xEYXUXxk;9={@62}jiCe7@jvGmv@4z~n)$onrC0=?`n{6@>4$iE~Bp5tQO)Osu* zyp!Bh*7`|hQA!f}h!lD7hHJNg0-+jqWWHfX z7Kf61PL7YAemzacKUukm`C|aiaw%Ujxr+8z%AEU4(QC8v68x3IgX*Vc(imy&N*XmR zieq|g*_2ZYJcqOVL257`WgM)aY1GvFBc4Xtp6^^UM4F_osk|tuaM$v4q^ToEmGi(W z`#Z}H)@$2xoK@YJ?eV`;Fhos8fZ7LjiB{s{3bQ?69OiUwW+z6H4_Kg`$W$agwEUK6pl+%a`nfqf;S&Xo#tPY7844BhK2VKLcbF#z3qx>(Lq&22=u?DZ z$%iKZB<0YlC3DiuFzI zDQ~Unc;`h5N@x9;*;WK1f5Kobq1xe*;kRa(y4;A!?ro8Y=GqcA&QzALiIj;Zc`r09 zs%~8}kiXQtHqH_vW~COUqkR;WXkFCDZj3AN201ZxfdDGHyMVL9HXAMiQeNUAQ9T2wqK3Mf(qCMR*A5paD-v!3M^ zwrAfvL?dpSo?mX}#&S1yihK$klvz%jnJH;UeHy*ieCK7I=$|do9n{(4ma>`U$N|B7%O}hn> za_F`RmZX$#eZ@Lxt>@P`XeqQ0B;}oo)}#5rkdz<>7{*F+v=Vk-Fo>Y&Nwc3d+^DDy zi#D_imn9D1qE8ni+{_;`&qz6~! zbC?EjTVNRI$legU|G|cxHpbvGPbutxcQ}@^1BMoMz~G9DkZdnBpEm!MB+Gjlfj7x+ za22D)a>S33NV1Y$u=Q$b=dEQ^T4ZBiyb<_bDH^MVKc(k09ZAN@C?Z>Q@3zmP%(DPDm-Sb3;lYdaTy zt$l@BUuMKA)Q3Uxvs{CMkB}?_F-DEzG}Mh~y~wbp9hnP(XV}jDm*9gmwtL)r`O|Rr z98%M7Oz*4sF{bzRue%Lb66{CDhQ=PB^dx7jjoKk0Qk< zULi?HR*Z!2-Zg?^)acEuf$2TNwZRzcw^?Pu?l&>QXz=TI?%w2azkIzKcLU9i7+MiCc5dPCi?Yt}$LZ*rgnh3PX6i-+3&54{0ULC*q7_!xH z9vtRvM##Z=kkclC&Wr`-b^{I(Z&UVXa45MGKceK5E6}@8N~IBvZkN?uF#8kV%e?Kd z=^~57xFjn0xNZs1QqX!${UuWLEE zl>9Th(s*WAV=nrGfcG8H5eGMf4eZDIe0BkvKaf|j87qFFE1bu+WG{S!<=aEs)=(NV zX*$%sm3Fl07Y=Z(@ymF=O3zug3+kVjyXHLKp2B}4egx}9_DjW%fvH3q^sKQTRC54cYAcEt#JCc0F@XK{pAAg_mryxy;F zd0!$bJLY6Uypi;AcTGPDVD03F+vJ0$I;X4M-u3a5PqgB@vRphJJ#;f!7`}~edtX`h zVSBVcJ92SS#Ed**%z-#wk6CRkkoly$nqn2EF~6nr zij(@~ftHN3fp=v!DOJV|TJf*R?Qc*2G>Vcg>Gk-jjlWw=fQg}mlinfS2M)Jz#@VTO z3j-|^_kEjfo@lft6QmPqc^th+*Bf+6fZs-a__yqrJ8Dpq@5|B8tok|%KB^sI(o~qn zV(Bv^rysItrUCo2no#E#}dKpMwZ^eHpAHB}3Zd}_s2mdN_F0jn6apFG42#Yqw z(#?_V>SeaNwlj%MpsHf&FmgW=t2aWE*`pW*Sjad;wcKx*SvuX@y^^x}XX-M0WV+vd z!=gG-j3XJTk*Deiw-6y`>Gok?ns|ofdVeC+aAvTzekJPXT2~xI^;VcVgP_<%OPA7Ic zc(&j&-%VxGE*@>r)%&4_1!#*dVZ%n#cPQqf>0bn`kn88Wv8CqoHk@ivQPw zfp`t5d9{|(qEv)a^9R;)mDW-&;#HEdku-RcQtPg?H6I%Fx<9mLFm&RlDpq)tzY@eD;g3ld`CzkXj)^HIsWBTGvkszl_^ii8~9-Wb{ZMK+oKobBxzagmsLh z7Suk18s(NY39SZLw)h@2#XD!nP}ZNXzcGLA`Rlf{&{Xm+41 z)NpNeYh9@ETI38So;@j_t!TfO4Z*fA5$%T>KZj_a5yr?AL}_z6mnlY*x??=EhCRY% zAXn?N`CAH(S;t^YiEeWz!sFfSgcUzxhpHmk!Up*y?ClOWJZ#bubc=%s$?m{*2uZk& z!wf%nj4ThLusok3YJ`L`I@?7W{}?BaO_z~*a7?WBnwlEIO-@pAtO{`Tqi-$d8 zJXTLjUsgt1mx#^%b0)5ZQYe$G@0kcrHBH$!_XjQS1VD#DE@C9!>Dra3k+EA7*U~pl zmM7tg-_b`gbMyI)Vp<(qag{7vHi-z9Sqdn90az=TePI-1rAlYTos`z7l~10 z>yVdN<1ftkmr1l2@?H_IAj1amiJO0t{I_BR>BkxAPxa->$p@qyDrP!1XOAT+hNfdW z#GuX-2hE%|HfgQ1JdZ6@FgmT z&CCW+{h2C9X=TD)uM*MS2#+jaGMic>bzQa&b!JFEowShOzjKz&mU+n7SB03`m~v0e zjvs3*>Z`YD~f zSmF}u$-buv9BssmfePLd6%D$-EE5UsTE!L=Er8@myw7I4(PHZnQae4VXUF^e^Ex+D zmPY^=#)Qq}4SJF@TMlqc+b^n3-k|45Xa`{dUSYg`<0PkWFumgcOctwI2?=gk0#x6W#V$f{L zR=y%p2+pET^w%M84U@8>lQTcsG_;?+7#KO>^+ZS|{o(+PI2S@I^^wvWLYct6)&=KK1qLuIoE8rke>7}-fy%fe*K@?!P9^Hn1=BNrXIr|nf5O$ zw0}{t{n=tiW{Dk{W!Mqt^?JSc&O#eG(t4(1> zoX*#{F5yR9%Rf2Yy)1tueY>DZd{u#;_{aG@16ddUV~~aSKmoG;y>B1Lk`^o9E5H(b z6=4hh(ODK_ygrZE6)eDwd<>%ADT-hX9r|s<1;N&7#q;c}T7>E_v!1a$xC>CZD;Pge zDW;k9O&pEsfrfDELbMnJe%h2>`J&%BoTN?1zGXY+bRn_I7t*MTvkKCd z5#R5{UNzhz1m8NP(flq(z1yXpeM~=W$(CoqTA|dB^fk;?tzoTE;3B{OfN9u&6e+@>h(p3duruqlhgQ6Yz zM8&;jxjRc#Y9-PjcJGe6#-@+`du$|fG?J(ZL--R1b54PM$yWxg&YFe-H&vU0?A4|-PiuKXL zf$mHHa5wINoPKmS+9l#M-Kc3^$i294`5iP!;5fO8+A_86d2&P z8WFYh*vl*4gBO1(Jmq!wLB+&`-QLQ~M7{Gl1}}ttBh|9W{C2wg3yfFga(w|fE)G2VLy$UqNWHE>*vmL?8K>tuaj(YbSWP>wrt?rt^$H>V$i^t<$YUc^F)c>OW-)Q-CEDbCbRNFec?q zHISY@=6<5`6LW$y4^iOPXQ%vTGMqmh?|FSnBwe{bQ`)ra@v?{$f*alAclG(7(^YSd z`las5j-n#seV&!;oV1ELL8`rw2I<6Xb%OT4LOtA?j@#avju(1Omowsi>gc}dao$Dh@3cF3reJsQ!@q);w(2B$B^7ypwgv|m zaZQ^T4;z9$)Z-KmWLw1V)0ric!cUw>bz+Ptk!^jVz?em$JdDK14-etpW+S!#mdEV~l$_Mb>! zq9!m$Fc#Su!HEK@mg}j-d$xZ$KmQA>_`-XIRWyzb{whkeSK#0N&#&hCn!;)h_g64C zVqjT6WHmKIW;I)vEP&tI$6iD-C~Hcyt6hiunuLo)Iiq>K$6vsgCM+Ii7w||HkR+0v zPHY}YE#PW2j3o`&a*_(EUv?SAO^9X-+Tnp`Fm56ab$=i7z$A45MNVU47g*os#(JEJI)# ztBz;VY(w6b!Gqqf*xdO8&CTJGidC1Sxpt2CnyqJ^EA;b-fe*)I-Q$MTRwqGPv1RJ3cGe5!a5Z6bqdDHT^~Oj^~Lw0 zv+K4xyJt#ucEfKo))-$Y=*4G71s^RCA3PQ z=y_BCl263A>N8iT`JnKG4+`w3UNcIZH0(h4Y%dHn0z=>f;dCwwJ=QVOA1AFRJlFfY zFB*Z6NiHi6uI$P=l+cAgx49FyaYsF<5j~iv_qY)i@CPW{9ois z@erZbom=ULY!)-7%&DsCSvL65%C&1kIDVY%;oRyLd=%gT5|rJPUG-lD>hU(KCLSOG zMSYEHhT%3|VeAcw3OT?8hzVEknBe4U!w)Pub60zT8EF59nE{!v%9gj{A7BQgD)N~D z+qHcN$iB?LJj)EYjq5~9Iy9N3%s?eMV{`km0-Lf|{$&s)*}!6a94oMBFe|W1%~)38 z3Rr<#p)LJir;3s#8ASt@JV>2TSdz22_VLaCi!1YY6ZRV!uO&Qf#rP$E6Me@XbRYU| z)~G#GS(7#dGG_fPAu8B|7Pf53?Ej~s>}|unXQ!S;=ql_a)~J*@iX(NvzSii{) z8}d+oZ$u!s*3D)ZH^LI=m}kw|OMXQOGt zEP!nfl~FL;SZqvohPJU07!MeYY|A}HJIVYkdt2B`4p&icoJ0tpD8TE+>{Q$^EzgnI zIndsz#;5ygzTg!6LvzNbe~M>h=6g0T+>YOCmVKp=f&apMPuM9n{}E^@HQ&Ss`iS{P z$KTgG%b)MpHQ&jB`JUm=cc-;t^PV$rf){7zrvyi8{pK z@nzO~(#-l2%*<{#!ssjHpzZfjR!V}2X{_a@La&PJvXOPs;Y9sw_6+N2VITJ52J?=booW~p1z87SQgeyC zgXI_u{%hwmU#fnZFI87=a!J)ca?XwLz2&*yE{$LR&^;s{TSyeslzCOW1(C{{Cy0l) zwf+l&hoat_zRs@M16*)bDhJ9#4c|9xQ0Fe-B8>Y(!-dB0@Iu3sl=>YC=X{voA;*8| z8nO@kNy^QPL>;$Mm+bT+*bZSH1hdm_o}el<`cdE!-LMgUL~!Hq`JSlvKDk^Cw*%iJ zKMUV82R{pAllKq$S*$DgS-kv)yu*x3+kkro>3yuv#fO}jf599}4^Ow98np{GRB|<)_Ef5sv0nXA@?rP>GkgMN|+{$SDvYf~*6G}u~X^Y!V zf&;?pC%++ODlMhI&ax|n=PX4gUWz34OPvjYx#Czug+|$opi^g&9 zNBI9JR_uU&8zHnYwJGSgIX@c9#Wk*`Ka)ICDbf;8-e3S^8-yvfPT2R=kLrV(=Pri}S zV$rQ6HAE4jO4G1}Yv{d~4>ep9Y`w%MRHgP~y&qvew&kPk$G%b0^D~jo;t5> zA?}{CzHroj2LmSrsjzQyZYC4IW@pJSQkyQfYwC>hQnOU4g}iG#XL$^z)ze~ zzpddWLpe@pG{1{MxXF)2xTY8gH(5ZqNQokfUri{BUpZa+qw>^OspQ6c z%=8s*O;4UJ>4^@!)@sOaZj7-Sx<%R!TvVAAY#5CVxA%Fq6$qid77%_x5w#D`Y3D~u8I8E`npQSQ?S#o=DOLt+D4_+ z&hp_US`b+6$5kKC5pMmOALKJNP|Lm%PEu$-%BM!~wVInj_9*`MPM6VK6zb?wZ`irZ zth{i$Cn%SsH>gYE%Z8FXR(`MAH}nGRdGEaLSuGI zL})Q@GT`hiyARevj)=Kf9E}0~Av(D+<7U(gVPmc(Kw<6Q^ zzs-^m@&1W;Bfhj%q>j)>h50YITR2@uQcKa>qHCP)tghb*a|N(YXPGTzq;yVantGJ% z3w&(!mM*bv^%>@XPh`K}X}#foC@AnAF(6D>*4tDaJv)@ZHyqgf{Ci2D+a%`H;`Q~67Khz~YFNPXU=Xq+d*PbYtX&iNllxC8# zgHFw%L}7Ww&l8Tf`a;F>wd{Q~`Bw_!KumvUVWsi8s)&t6wUx3lZxO(|E1odcj$5)n z_5$UkPeB`p>JNV?g3uBlgoa`Nnk@k#XNAN) zoX=@Afkws79AT&A(A3!HEK@3WX-QU^&K02Tq|$}%`h*Wf25}Cp-%tW*49x)AM))bi zo$B1e35Go_cBHAui*T0F-sb?~;sNgUa+jR|-YD2wKSF#nG+zqT@h1XxOtfBq`Cb!?uW^sFtXc48T@t#+a4igM z!X+~Un%3Ex%mPz>?)hu&R6cK5^Fc4nPJlEzid;zT~0V;ndaGR=tnE){~|$ za}aTWxE|#uWTP%Yzs!a{jt%YSq@2t%41Fq3VIHUdmZHw`W$G68K4nvnt)wT{b=2`2 zE#E*GjVT-2A6$S#SNme@p*Lp7a7x98X?kd?_t*|31)p*|`h+mtbUU1*4JX(-!QAUUG9sefe3$Ye9a7Qsb)k2^e*WK;k5KUFgIJvMgDcS$rGoYD3-A$6Uj-z2D}$ zLq!hni8S`GQ_S;jp(K-_2hfd%^(S>w_gmjpFZBLA?UgDg zdAsR~=}{@E=;rZ<5(h0$*EQ@7V=ggym^x?4gUG@`+=Jr4RnNgKg-pijrz1TtS47GW z5)<`Qa;aiF?;NTf01X8F$kzOcc`n$s7MdF#BY)+62at0Dg*9*`r0-qgz+epB|SmuQ0CWBJU(5&Y+- z&I1g#LaWUq6k=g2M``}4Jzd+t7Q7))Ha%nc2lkTq@IJa>q_I(Nm!z?i1W^Wx7T3e* z4~C%E1VI3e$bs3)Q1h+_z~E#=6+FpE*}efgfN$QPw^}<|Xg3n;+UayYNNeCrb_9+F zJ$*w&dhg^}5q^cR?pvDy5C+ZK;*XlOVP@8H(+gAf2|H!O%#`JhwDYwaw5j<@472mJ zofLzk>=fZ@>rW96ofQ)+)v%ov+t2*tbdxQ$>>_qscuKyo%i-cTW{(H`$#_Rrf)>BX z49OJKo_9yoJ0a?RDaO zndsVBqfYlEo;Q1Ej2nDjI4xZOZShDx3k{yf?+a@8dLKg zNlo5~nRMedH7$48rh=v^{Nw&tn>z5LnhLhuVObc`LK}X?F0DwRJU_!;U#P*Hx}EMn zf-)DZ3^!g{z1WA1CkyULTSY{hltK@!$3$PdA4!ke^4z<5h``RH8UsE3V~w@J4F>TV zBLw)yyEJ!({p-|~w|rnSTm8v2k4h#J!x!Vt)Kr+$iGv{eXgjw@Kx*lKDNwV;3qZ}j zpSE*g-$zZK?8wbX_i-+EHi`$8@9UC57Dfu^q*Fe5%8G_@@%TiD{G#OpZ%?7NNY zTb|N?C&EH-5_UQ_uqJ?dt@i|;Q}AV>6f}<(~^6JES@GFj+yWO z8f$A38)_NEm|-02bibl?X}p?nyYiN{7?ou173=#6r5EVOv3zqu;|=Rm##3=OOWxhR6s&gTi10sj;~ zhD+oEuk-d-B8?Fz)WZjFRz*kls5O5OAt(H2)SK}tq|VKxY(}&^1089T{7gu?HL+yw ztbdZGj`=ct;gf(sDCN&#`rpNt+sSLEcdTD%>O*FJ*$3#!`;Vh|6kBSkT{0y;q2Wf< zvdffv#akl=nygsb03`yuFRfiU6{Gnd^2a}7hxwr*6h-X+C;v3AqA@V%p^z6vWFRRO zkvA3SNa8Uo?;9f5P4jHYfc(xCOKO7=$8iIQ7;)Q_f%km9iZ)m`*#n%T+6>VcxHr)DxS`Z_lde;Dz3=wi z1y~8n+I5dB{0Q>bc)R-_7W;c$$LiOyjk(ThRVf6+7nr_@|D5H|=>JaaVgk5OY&4IK z&_+m)ZQu58Ud|L1pRS~eWjjArX@kHJuf<3E-jzXx#ns>J5LQ-avHuRP-xgZ&L(@rj z_fDB!5%i^>;}^Zd?KkZ87hdf(kvY8r+9LCdDyOSWnMtTJcj;nUDER(U9N% zK*Mkjg@U%4TwA3=+9;yU7a7ZaPua2Tuw&WEj|pg_u@u77o7&VY9pXoW*}r~Uq1xSV zGLGCQ>3`u#Zfs%vrlTS6${ITnm&=9uapK@UHk~dU);h{H9?`6Z_*q|mVS@X1?TV&v zm%zWDW* zHBBLD=6lE!!i~>3$uF}#WY`#D3psb&o$h+i%aOYC7knKe%B^#EoK*7Vq~p_ai3f1U zx#?O~hDKZX(LDlz6pSK{>rd4qp>#oE1zoM7qwdP1Jj{CWO4tajH5f z1|&kuW>xW9hai-nT5r}EeuCLi8$M8Im`ZZd=TNIz>&0Dxvc%ZJP^5qTt+Ol+OO&f- zJm&73OrAz!Ft?q4RM&7$$5D**=1%8Ap&;thtca?Y=bI{kBQxtxr=#zMF+A)o?=#EC z{Lc^ZEH?Q3C2`(q>FQ%+M8ReZb+TJEbY615S=wX_NvMk2^y4h*()*cY!DVNi7fTJ>x6!XQ1e`|2(4;T>a|7iuw_aFw~9i9 zeV9k+r|ZSc+LNZvkh4c%he{nvy{cZt(zdj~y-jjPiO$#L$DZ`hb)|heiK5!B_phbl z$5%iZWJ_zSC@g}2O!LuX0JgnNVKCWZW+TOqQz_B4b%C;6(7Z6k%m@0iP@5@UuxclX z4RbC?b|p7ZHno`9kd5F>XW2iYwiNCVCSXqq{-nIj_Y_bBQ=x~AmJBVvMz!^?C(4Wa zNM#e*IyuxSD0;-Fhj5*sERHLf&IIVMPw4DKG1}FDjsspUTq&p+bELMJgl0?zOn+WrI9EpCsKjzA}Uvbl9wyzA72@8 z_`CVI%D_wf-NE($7ygx1R0Jwa5dDge`&X{zfPl8nOKJ-hsvQ z)>+o>)*@?%3Z6%c3_s_qPn!z-+{pv{oDHh96E;rZBDStP)grF$o z-Y|6pcr9h>R$_1ay|du7T4yzyU-?8YkMIBsfwY3Bm>2@1qb8cbmh8{IC#6@L;$xZO zEku4Y8rWjAN!EX_Ck0Wz`8D$)i<~;Ek5B+hB8ifJfPmRG#rTy?=ws?GAV)|?mOTSs ziO|0GKn>A*TG}|S0@?Wo`LS@@K24f$?}jINnEIyvH--lzBdL@KAxUSmKRN}o3U4HQ zXQU&Qp+t>zh;-C%sMtr-KT(Krr5cIkpPIa{2JzxF$K7|Erf~kTxEvuUF{V;C8&1^4 zAT7oA%fh|6M1mxn(4Xl53>lL3A?uN>gJS9oLLZ=KvueZMa-q>d!4>-|V%~%@KNRAk zief0l`Svo=T2Ls6s#j8u-**4qIn>ni$1&;C)+P6xZXJlrCQY{rg$eu`g+g-8?v8iA z$H%t7{%wANMTG*eq(-68u_q9iKODL5lx>7PxwkCp-IU=o1y%=6-S(Ht;ujJuMLb1S z;_Rr+iCZ|8Ol-nptmlshV}cMrESmoIR(3z<3wc?6l1xdcsfUL<(Uiz44N9hIV5+vS zBNWvde^UEb@{oXCapEqTtUD3%z)cLbYh@J(d_kf9Lk8EsW{s)8lKSJPMQyx0>i!0G zBdl<}P9s-K_BqprCJvEsH8B)s=Kb8E|iwzRkE(w-`D7wK)msCJmI6sOjR`b$Fjr*no9gE z)VL{rmz(eYHIr_bs-G}t3%NOu>K!cKUd5}p|L{g~WSAXFDi=@hPh%lnH4`}T|>C@V? z5B+F3_3SX-QTNh~_KVNWgb5Xc`meVfCMl0~Snmv34nT`GrWV(v76*H0H0eH;`gg%a zB()eH*~PV~#dZ8ljioLNr54BdNN!5`)Z%%m#fx~+7D@eQJH@k8YRC=-%hNWA%#Vxe zcco@5ig`KggDEisW@Nca5&c*{Irzej**;{E`n~HEazk+}A)b?sBbca1v}F0u0;J2% z7|ZctSPWZvkcIdlcqKj!K~=5N2H!^2r>Cob&krq)A=P_$T&%oD(Ek?&TQdyVzw=Vk zvy?3_pz5uHKf9&SR06INm^f9Pfd94a?$at9YI>Q_oofHKUwhk`#p*!ImYa2Z4YpCA z+}>IA*Zc9VQ08(7CW{-)--Rz5nlGLYi$ zqlG(q^I?Bh9#s0q&|>1Ds?ML-I!y-(Vk6Urc{1={;oZmombNnJ+T4^r`CG+Q>Op}3 zHO=)coxP6g;q2Baujf0exHy6`5|qjo#q0{~)r9(oCr~5u+pYZCqz;yIZ?dd_vyUJ){YLU z^Nqrdi79Lz`$2`xbup@NFXaqnGf~1#XpEtkG#Sd)eJ;P`ILp5TPjq?m-HO(#^l6F> zz63<2JyV5Y-&Vf27_?d#6t-g)78CovNnA)JN0nCcp+#k4mpDmj)*}UDdONbojEcsG zn*{;qmUGZ;>U_4f}P=*PqH-}#o>#MPRw{Qm{B zMSiXc*i2Xc_2tii>9Dc!O_6HRU1OS|b7?Src3JlJ$<}DQxj`jAWlNs0D|r!8xtjQqrdNFT{7bfn zwWfzLr7h3!skb#-#wVIpO=wfWico#2nmfnOF_*r4(gsAHJLz!Dm;${%Wy6Z*uSvgM zNycDpgx|?PNr$5dYK}e?B|8%7`HdXI>>dAoc5JSMsBj^qbb z&hjvYyzB0LXr?dIb06hFAh)0U=t%tzbsw!(ecpm`goE8~i8n^Nq*%^2ueY1^Fuss2 zL+78ZsOYbJz=65<^z@iuBo)4v4{yx|{lafi#uUDf3$J-Ma{KJfCyp?h=l?K|ewpp$ zo{mqa<5Ec9sK?jc+ea7CS;HDOGw^cKy}aergl}EooDhDog+zE)EXg@~vRzNU*D^G9 z^%8VOBsKqXGeQL-f`k#5M$`9A3Lw?xq>=p@7IvVah30koW)m#Wlp!9JKSua3TA_r?@9+_;0&eHHZYNesr|@_9OqBuCBHNid1+xH#V!{nGGgAv z(M4(^Ph%qg2WC+XFpCo&WEO7)*cjjz1~}|0Bxi$Wv5qOoAqfsUyzaefuko9=2tUGi z^Y*oty+59>k8$@5zrpJ}O94vrZ{8ltTQm8Khxu!#4(N3oA4_Z8`8560v7_q=F7h)g z6nwYB&CjUNYypOai8_q%-GcTXQ%q$JF|+ACU3i}-+q>SUc+cjNe!I@K_7mX1S{KdX z7%qYYUnZgb^6Uv%2}=goLHUSx_41e(zE*l>66V!rC)_xh&9_9h5qhrEH_yjqD|l{+ z2#)Q>IP=Nu7e*U8GVSMOV4vLn%=-_2C4B%lBlSNIZsI}Ads{SyGd#hBv81^H*;MBS zWJ8ae>~t0{$)cvubjZhB9ghjW*^G~0I&bajQ!x(8J;h!NomLt66o1qBJC~jRVfPn@ zD+7JJ|G|vPz`d0D1HVUy2xP>c?vLbsf!8U}k02?5NzsF&P6>X+X=CA3-)ST4aN>@n znr}#H&R)uH$F^1xlAO8<(BS2hu*rNr(i^^82LXQX)Nd?x#rMRk4vl)}1%#NN7hEbNKWVI`^@m2qaU)uu+(|KlV{(O3=l#oZk}$xZ)l@pmdjxjgTnNqcVeb{`%waA*$60`b{}Y_=0LeI} zP)4gD(%Tm|tBUaN*{z_Nn@uU4bX3qVQnyvj}&JJ>uU!R6d=$1S$mNY+J_ey(be!TA6?49``kcGW7KVJ7;_Rjox z-S^l#{aEwe`tA&!W7abxBlR7+j*Q~4#!1`Uz-X_?j#eM9ui~2=kx80wK*)!wOm-Yo zAvE)Z-h178A0cuvzczyYnsD z4k>B`(ImJOL;<*G5aF-6!PJnzmi%cqPb3RP9Bdwk6FGM16;I`s%HlwvmdPC*O|LK= z@c^|<{Gh^l8vm#wyk!J$$d}sH%m5&KD%x;Q9bHZwtENu}g5l)#Aew47KmJqC#JO`* z?NfP&hiABPF5{8Kau_5?9}OJ4^=pk?i(7AQb3?p!0Hm8TcR*w~bzTjB0L-N~SWMA> zMiq-<ngRcE1czXcVq(8r*WQ1T=@l zdBa9tjs$#r?WiR&Tpdaj3%Jx6#d$aPJ8Jl9Tq6xU9C*lMsoLC9A- z`k6@jM1IB_w~yQbHBMi{g$fMgs|TtwRM@W-vafZQrPcY z)0w{=)0ti$<j_w6&k>e!;J*)(p&#~{OCz52$~Quad=h1{1~_eqPHKk>EBX9i*Y- zeZ~$@@J6@~r}J(uyiuY0M(Tbod~Ba$YV6EQJR9{k=Bo2!(@TtaR{T%$>vaK%X#Yv> zz6lDvEfMX|qKGz@`r;rF?a;kNv0^6BZ zU^{bOY9<2PnTTV%+xa5f@vfiNHs9H-2g<4#MDIWppX78jlh z#NriiVkmv8&ZYjdj0mDC^{#261HX)Ti5sG+ zVai@ZXNO`qRh7dy<(gn~YDpCpRW+vw@XRn`sj21#E$^r2HtJ`}r8rXu&~J{~<%{}@ zm)-MUVxKo>Ge-@^j1qBL*Avg%H%NYgx-*Ff@zVuAu*Gj7(rwSV7;=|229BrH^Lwb{N9Zs^2i6* zFuOg4*=<~@r-|X#YWx*=T(6H1txlIbX{a+Eag)~s*$f+7kFoL-O{pJm*yl##! z4H1gZ2)6uIq}-ePFFG+?Jq&=kdU@_Dzn-G{4VMb|LkC}!cv8+dGndLkP)iX2La%VVohrtS|^I<5?55i@rBd{0>|8w5=P(~PS z$ZpsOML*%((SOI=?6M-KF?%?iMjs|^UxVTZ;lPl2fB4^YfCzcJ%mLzMP)6 zbbw&b<+39FInnDGhFne;xjvE0A@O5Htq-5m5WRpU!eXERkvL)w*LVr9PHxTSTvxcI0?6Qvl- z;H%7s;j5=wUdau|V%O>V29=n@zA@IFXAevtiD2B$E%9Sx4c`$y*%!aq1J6GAB^+$I zE1bGr_ywhPzHn&i{|*u!EFEPye6-=$?cU|Y1ZUr1uv?sipSghVzy#aJk6?V^$Mc4i z1^UmYl7X<`^T+#E2pD&n+>V{)^i=gmygKGz7`sGl;Sv)d!=nMQ#R&zm#gVae_(fv^ z_GI=izXQ{mylI~Vxv|tQ7S??nDg%~Vz4_W9RBa07VZFWZ@+6)f_h-C4hyhT9i+^ijU<&s&&@ z)L={Gzgn9L4>Rsd3-`#h8PV(oTwo#^OD9;#w-v8uKLrf^In5&Hil40iK7rEG=^F1t zVbq%olT{5Uo>tXw_0HP2g@;4>|H!vd>^5qjWy%n}!4l8CJ9m0B`f!PaI2qk75mBA{ zD;?}~$>&eLY#SNHEJZcB-h1K~FQFIyezL=(BdHrj40BgS zX<@}PYE(G_QsFyuNd1b9-udB;#%Z+oZNWWFN|dcu%&@RHQf)MhJi}R`VfiAQV#|_z zrwpU2Mh<3cf>Er$8l=;v$ZrY{6U)ooV8R8)M`8>=Mz0qe`C@a* z7Y8vua>?3eWh(F`{6&nM$4wbVs8}tGe_~j4_ycNnH50_T@U8vC-kYzVJ-;&WDt`rq zwSEiN(l-}hSmiVI4A@H;Q#}(sU@i;Gf$_PhmnEF0Nr{d8=m_LT+KrLM9Y($_3zdTW zYDePDXzHKMTXY~9YLzc#{P;-v2K%rq(zqu+LEyk)qf^Z?f<49W_elOl-Y6rljHP}! zX%z)z2Z8fDHoip&agH{r-vuVOaLx)@1Gg2BwJiCtUBU(%U4SJ_X6MA6WVR+gBAKl~-n8ei#02kFmGV6O zpZz?BM#(*6<3m#>NP*9squDSYpB+Cex#t9@i}O*S`Ec~3eQz|6#M0StME!44L8S4; zL=E)e_LUTI&feC)P7kd~-T+tJ9P>=FHsjgWw3lbw%0S{c*P9(Aj?A|B{>@&bc4f3- z0!b?JJ&jMa{H5^;Cn<_WPSJ6Z2J#4?2V5@pVxaoVV%~CXc2hm>%7Yx|sQ$CX>PM@3 z?B^P$mDIl&5whx@us$)7q1>`UL#chi*tl-W)*ZsmvPM~NSBb&)ZsR>R11GQhbRhZ& z9nrt`$OHP($v^s_{^#Gd&5fHA1T6m-$@Xph89J)3n-RS8;(PYRR-Smt44=C?(YE`c z4Mw6MZ1$e+@8Fpq=;p31@lnlP+lw!U+U6PP8IOND;5!kUpbLqsBNs0h z^hCT{2Y2VI7{l(}bSAP_cZMkOX(m$In@oh>9H*zoTSt?p_gy{eS1$l>`(=tjyq?B` z*oRbs>7GmC$0heHOe}3~+8=5$9om*um$&vq#pJQ_UU+1Tz%&26OVmbU~(7rL}7iJ ziJ-+|KX?!KPUk582MY8OOCY6sepD}Dav<+M7+3&EOdeQu6&YCdg9p~Fu#~LUb`)EK zmT7unnbM=YwV&2%4X%de-*>{PurSS3m?@p+1@XG%p06g(VEUGf9yF!>S~ezY$&^8l zb2SuomTMsf&-OGj#lZ%5T`!KIlM~hr8lRV;Ajg97SPv&g7l(q9)9JjD0((gg>W0Qg z1N8R{jgJ)U4|BTkX@ObpG$|F>y;ui_G2+Qy3HtJPuwvRryccs#>TK8GPTl!!%bQ;& z=qs-75c9>B?9l_2{0WY*bY3p@Wd?gLgA?7eC_chavHtZG13eGIgAxI!+usn&)n@ zqtOAkr129fo7DKSLwKyY8T}(0OF{uA2Vj4c?RuhNuPI+tnLwPmG5gye>Z|zpe79oe z(CyipdApP5({S#mW>v3eFniT-&(Op-_8|{nDI_(EUl1XJ@-?>hIn=8y=GR+g1{9wj z^Zv7zrv;aJu~aNSSpIN7ZRg#umqF6<@e%l+7_*6K>tl`VuUdf3Z`y|7w*9_Z?+48)d-bt%&z)@ znY#nA+n~e3J)6gyHRxJy)`amFOJHhgEChe*m(UqJ<~@vTCom-wp7JUNbP?zNt^lot zR@`TNh4h=@ebk(wTpD%m&o+B^tJ_g;yKHo?{}bX)Slx{XPD0rl+uFI3>Cu~J62#H3 zYy(Z=N)>79eB8O8U@qZjDb3yMiQ{#QB7!`|?ja-yPiP1uZRrp|aX@GV-c9lzT}?M~ z6;wj8E!n%iZ^kVX2ekuH@V3)fCcEWe*`GfSAMaku87*?UyeV}{>V!B)oRGNSyr_wdxY|7O!G9l`&NdqJtmTUhWm zPzG?>?I6Lh2g3}BW>Z}PL;q9-Wq5-EY^lm!kDtt1-=dc>uUn_a`sa0IWOO<%a#lnr z7fOG&B3u0jF?cdNC)|-=n`s~<0}YJI|Jk&;S3BZ*a8tk+;??-v&JBq(>6L$Sbh;KW zG{4nQI#R)@(Dr0-2Xt<{;rE5cZysn|_2fF3&nj6wjRLOJ%2-h5{zWv98*cXr-dj#B z%&Nkq&6k}J|NrNIz=|CA2?c^eHCZ{4D2#@d)*X-em zQ(WW_D&=}<{bV2ho@L4j9ORqRbY=AV@J<8te7YtO9hr%yy7f5f-J+k4m-(+8Nfg2a z-5Xx7JU)Hj_Sjw5tHghnMMgdmO_}S$SJWLSj}R5Y*6n}%D~8S-V3Em%>A4J}`gq7m zA>ncEwM+RdWx9CV1K99PQBzHf-}iF1hB|D^l34C#(8TA3eq*1uBnamtvZe1f}8zG zdPqPW95u1$WU*$QruJf((QT@-7-sY_)4oM3X-UhVre;{@^-Gtbb$%VY3Q3UANl1 zKE?ybmeO4*cYw8u)2T>9G0$)Zmh>vp5MK4AU?v7ZY1IY|-|3vnBTa$x&EvUpx-^4> zr^4wRqcWNf=bOV#A&J|W7OmYQuZq9Tq{8#bgJ9(Qu6K4YikT?E8J=~^q308x(voPl zp3hB+q&-am2=F81ACVL%j9KH%u6K{!Of8=ay5;K!n+YNxD>W1Rc=_0HE#JR=$1Fi3 zNF~Em`a5AVyKJG6|8K}X_FiF^DWVnoKe5nRzJapDIG>O1yGdqg$q$A&%f=h>mzWK& zr9%zCEH>oTZ`$RH@ipL@wF`#hRtfOd>29Cp8_(02_e)K^$tu}7oCkaHm~|}QTNLn@ z&*g0Aj{&4U2y$Hm(T67{S_mGGEgTB)dxqv}G2)#aO&K+5|746t7KEJRw=CU1;b{Nw zTv~;@p;YC=%+hYozVdQmY3p~D=wG8mVDp}3UB1A&u)Nb)-n?1feC~+Bf+|Db_M)Fg zJ~h*>uUTHAla#Y#O6|Omca_?C?Je)3QA1w~_Fm{s{Mmk7OPhS4&(8fXb+?z2)am?J z^Ry(Qsg8(yql&~e0-Bdz8rbs_utO_AG5srr;=TJfNS+5g8;b*`Xkx4}m#B_4zD6*t zvOwL?TurR;jl{@U<14Gn0*i(^p{=rXJ4Eo7UuPg~C5XbfVS4NOuR?9J!1-F`v`57G z;q2Ld>2;a<%mU|HA}qj+E4IRH*s(Iyu}a&N52c%iAmd*xR~KBQLX+n4H(wVE^V3 z?jn8ex!A@~h1bz;Cb_vuwMF29=i!B{U-~gs`G&I3{*kIwH;zT`K27aw`~QX7;cy?} zr_>%hMD&GmCH&kMOpKqcTC`1j}SvcXdlr0eEg#NF({Y&vC$8PMyyZl&jbSt z9gpcV_k28)@*RpY81haFdL1FIh$dA_EeO#%nz-d-9N91k@EzG6EjqFZVdm=VH((YO zKSKOl!I$m3rM_%8SYI{;U&EKJOCO1_C75axyaErL3{6BlX5%5BB{VdxD5AAO{DVeO z2>x$9h1~~_3JrLD%XxfL42* zn=&vK`@xqi(?dO4JYGE1YQsZ~;K2jBT3i`xT$8Ajw_1=72A&^0PM{v5`*a=3{kbBMsVvdgfRZ<4@V=f+sdp4j9kbr<*I zpM@mgG1*$~uC+(T55%%Aq8NZ%vegGz7mAq1!58)e{C|)kBT=|6}F{uvarBhz5ywwX7}$BOu+D5NZ1!o_!3q|$lM3}=L@4)^5B-YcmS4`FEZ19hb0u@; zxk0mQ$t6HUp=B$1X16X!k7a&Pp^7ORawlp3E++4lw(Uf5ACl7ip>)eWM@U3K!fo8z z@*;<;Z?2#&per_MHU#yZrDGDKIR+nJ?EW}_Dad>J&HFt|4@(@%`~8aZ!TZEWx^x}Y zsPY18od?A4u8^ANn zM%li-*;{56+PCU8gsF}%S+y-PAkrma>k(B*QgA6k0hz%{wg8J{I?e#JGYW12y?zj7 zGnU?_8dc!-HU;(Df4uqbKKlV87eN(){%I(p_u(nKxSVY-H%L&W78EZn6i#1Srp@@z zY(~u?&ONhb82^J4@OB+nvfuaKuU?n-0@*3-UZ8um`L2PjaH`kk?}SRCL*-63Tj3bH z6%JRvV!Ih$DcuaumTU&+{$FS>SjfixTQJOY0=Tfw1KXFIE!k_Cb~Fp81A|vhTDbJI zL=&;5*cHhPGslP86<7qDs2R8%ha_Z!fNzjE)X?Zme??R0CSsQ1B*QyJgyN_8y|&Ax zrLE2r(im=Aon=~`xAfG+bld9kl2(r)JSH`{_hayBnpcywhIrMSHE41}X_FEK21P{= zfo+*hCnEVw0Sf_FLS?z29v2=GyNPFXI^yqoH;;D50wlKF(PS^=hPeI^oFB7qv4{GE zyKC9}?Fb+VWdiQF6idHE%x!<*ES|M5o@I9XLjpNwTbomRA^BdJ&Fq(aZ-~>CgWPGm z3fSHDhs}ph@)@4?%VHaCcieG_xiNy4^m1t8CrZ+$isU@=6IqUfJs>?^PGK^=+=7)w zI6oxnMaFrL3(N}{0ixc7{ra!wYbh-ULp<jvNOUEV-5ERZW!mcRBtOB$Yp9-SS z5c!*DYTB5cW^4M456n{%b^8MIp@nJ+t7$2NAvU@C(uakDQE#@Q)R9`D;-J%06)y`S zdBp93*nvNxEJ(c={J#!#z6W#`!0n85#qTvq-bNkD~>`$J2{hBzVWojopHadJdqs#6sQ z7W5|1c<(R#fIOZ*eBX@G>!4u^$GfX7Y_?bd0SlT6H*`x0?mL zt(K{^0>$ezrN*2J1Y^{GHGu>c!A3Z^`YGjAQ?8R|z4e@~n88h1<+~$tz~={lg&Gr; zl=*5|$yao86Cdu$PPbo8@MeJ9o>isg=<4(?lbvYZ#VhV9%MF>5QDlg^y@w-vGM$hK zXI4nt;=M&YFgu9Ph{ai!VJH@jA@9?ZLBo=ua5PT^i+x);nQxWL+XM z5VK-$b9%(PeP9jFXEpY&#OaD?jch#jxuNUD$G4y1r`<7mY|K**nwkD} zlp)0%bFhOr_%bZ6H($4%jd5`wkGHBHdLfuO$i8dT_dD`qYX)j<@!Q&(AN%fU#kS5Z zJf*Ghj{YxlTUu>l3{-8JUM+^0`8mRt%c@tU&C6Ux?<;xVuN24%?J7itw1Ctzbn$cJ zG+)&qooZ|Zn|BbKAscJl!1}91sm%XMD((ZdW}kk=aKT;osDzmb(8XNSuBO^w(DbY_ ztz>qr=|bD5{dwK5FxEs|Px|s>-*^4dCob}5`HSJc+(p!kGo07FV=$L+ir)(Y=4Veg z9Z4KZ>sgu;SgJ`)K%o~}gPY*inS|6*#!m~CZ~q8EFy_rjWZB9l`|*8~+8IoNqa95| zl3={LfVmeEIs^41<>z7%J|n`xd&X@3Lr7c(5=lO$0w$ii^27gk`}q(K8O8lfDuK^y zJFoBGPmhb6c-Np!oc+*Eyv;l<*~E%Yp|j-0PZT%tPk1y~oy8VzvcSL9Y`*nO3UULp z`PL8Ke8=)ez;h{;#Jss%S&X{=1>A5*SXG`t+^$`)RXHkq!yi-6EB@{}w4|Qs?%(tu zVykMZbUMEQeCp^?<#aBxmo;2oYA=Iao?|cD0o|u4R|2|Y0NrVT?p(ljyVI%TTTzyz zGeQ)hNE=_9u7Ws$j`j2$+<>!gvEQ2wtTx!)I@*lZxqB|;m?1BwN}gmn6lDY@Mt|&d zp21^W$v&iR*pz+i{++)S53;pwjTP%ZfF}&TuFC0pmyVWDHHWp z7uq$e!1Naf!^kWO-JJc3-zJv$W(9!`jmQ$Kr~Bx_)_w(pD>e!1X_{m@cLJ8#!UPFt zUN{(#v?|hz`cS|jpNTDL`*pkPRve`=gEXovc-K$q8GFjWR4hFv&@XpFTh)$%sT1ir_aO!Z>|g1 zZ)5s{RUEL^^mhxoKD3d-Tx1Whjh$(Waj2QQv$QXN!7c}*p(*?HWxvwCkg?BnguwH3 z1XVPfO??D0t#{FKX)AvWdRo5^dRi~k6idwkoq&~^Q-lZc5tGkwC?27S%=6Ppwc7I? zf7(Ga5wCLNPU5K5lf18MrJ7BLSHu7yG)_n{V_v@>yhibkdla*<4NPS=0l5%7!Nq>v3f3T%&N#M9gmeEQb+Fd`)fm(1%Ad`zh@x^ZAZx&aF zyyv4muMBN2e<4>M^ImWp>Ju}f-kczo25{=j0*ox;eM^VyY+|WZsqF_0P^5P6_jCRC ze+CySLjG@BzVGfb3tE+!Z95!|r7J(UlHj|h-)ka0eN45Fjw|_-nv#Jj~RX$(PXp!S#{OU~@98*}FlE zV#u3Sqp#-~ttw6$Wzv9BL7kgiFBPx~N#Y*l>p*r^rcfJ7ebDZ5&7lI)&(i{870|5* zfc$dJvAd$%PW5S=<~T>5&cPNYE5+g2T-HWXF3kNC*;RcXfc_Y?B;S_TDjC`Q4B%ge)*&8r;U&ge)Lv@!SHQ>A?QPIm&wv)%8=^ z-COUfNQ~R{T;bq`^XZo6Lo(T~y^8kv5QN3$Xc6s8rpZq zwa_pFXaxe3kW8=B#@4QM+ivNvEnT(JU8`tY4Im_lO8iw(t4&*fOpMjo76_>1^L(9q zXEGDO?d~7n$9MC1Ozyqso_l`2&-=X3`{y0?HSxyS$#M^Qf>XZy{d4iGybPzxFHMox zjy~HNgEq^Q=LW`KLW1ns+SREo5&{WdNmL~KCt=V!Q*z4ST8!Lwmt*9%>Ivau8Mh%~ z$G6C{-zX_K?=CP$uJM$ynL6knc{DfXPuI-x5`Km>IHkYoy14|?|M49U)4PfZl`XJG>o3($djiWPe-Hq{7FGxk$q$HLYi=*H+uK;ObcMf5T4Tp1%YLD=uq|^hFwq{89jZ}AvXGbSQs^T#;fv1@fd0R zONBj3$eHvx>kP3HB!-h8r`Au2p;}LQ;x2vl&!$M!pWYJ2s}iq!YiZqm?o6$|j@4^D z#CJ{Y_14`T(u{ZKREpc0X9-v|w>Gk84WUdrM~pVm4kyJ`Z@lh?tQN93iKU7sz^>IV zPqT6wbuqfsO!8$mE>N7yX36Nc0_Br3ZOpK+kI;GN`T3@uCt44EODn*{vMCoL5C`3kwjv=F;U2)-j!C4vb`sk)%h z?l4?8H=%hJ`3nmFW}%2Qi;fZdA*qNCwlh**4xb|Fl05-mX>0-x*l~2T-8Ep$tiMR| z^EN+##)OFILyl=eM6@@Q@-eQr6k_%3Zh>XQ{c3OcPi9?o&<47he){Di&mwMLe-t4#5{0Eu1^I66< zAR+@+O|_?CzNcP?SuOr(?M=4Tyu!VkWi`jRb0sjy;+oqjEyG^^u_^hdqMohhf8jqu zAfV76O#ag(p@*twoM6Ik^T=NZeb2kw+0N2?aMtF|&06||YoAF=>_;jnAU$muOOHu2 z0o5W&DB^jgH%S`+A%1*#IC&9kjQ_JZ*H1FKxU>D~W%C$1GhH(^9a|We(CiX~sc3WF z%49^H3p7T}kTZ|~fPDm4#?fXBG~ORcn~9I(FR+@P)jdc+%*1r^iBdDvt9eK~b{q$V zVk_|gIYJN~KIw;QE(1&wsB9o$8O>*cJYZjK=D(EiRH6@-ZreUAXbO2qVSE& zA@ye3Rr2;LnCJF}M|v)yKx3-jvr2a*^#zSROSua}>El28FZh{o*1W4eu1WLXfE>Ph zC+Q?qx7C^Jn#dx5*BkWYvpYFciotI@tXOJGSVLJxvrT+_sN2fpN z+&W1P2kt6mXyrY1V9guU8UjhHJ@`ssVWJ_3p$NSteueyQKSNjNVFjR&ZGly9f#6Z~ zh*eJ2KY#i^kQuqqFpWavWdm!TqQnj2^Hm2OOdp-O{*LAdK&?M?eg~F}c-(}jtqa!u z$|ilugvQ@qruXp?uH%3c1MD>^jygcb#b0ncC3h9SQYjD}ScIt)PmO?lW1bC)#rP(6 zCi3l6eZA!?vQyXATVw0nE#Jjm)>ymC@=fpNxtr%cp8EocZ3A&M`}PED>4>!^NKuIF ziQh{xM}z^o3NS^uw%D?o94a*sfhVgG&YEK3i8TfMcTo@v&VvPvcrvhXHQyLmsL8@Y zlj(mJ|C~*ZJa|w%=6rbQH}GIJi5L&o-CDJzvT^xjR!*3G3E$3U&L@4|9iCXJ)%u&^ zj7PBmG+1}P8Q9ajfwh{%a5dk!qq=+E;AhSHY(y}5zeZObWqlntBJpdX8Su=V{LiHo zQ04`!JQO3OBNyzJge0@#4_x?QwGhcns_M^Ey?XVOPzx1*m@Qa)JH z$Ek*4l=`+>mH8A|yeXX0GNnBI_Y833C}Bt`VWFasgM|y#!ljtq9dLa^OJ;?rp54B9 zGwE~FxX)@Q4`~-E4d+^Vy#1*7II_Na`mF7{c&L7hn(l4?KnaxXyoNd(SqpcC+(9q;ihGm zy|>Fg2_{vv9qm-;3?kVcqtypxL5~zouFOhT(G3^FyaJ74RQ5Vh+0(*Z9f9rEvxa1P zwAuRFIJO_Wknuk=I#9c{p>E3<5SpRr+0VAbWES)rZyf=E!6%4~Ri*#%*UW5xg%Yji zGx+bKvjEyvBH()bYC#STOy8UR<~&~I!x~hq3XVwG@LUOw z)qFCqoHfT8v{sRe){G;9kqGy)Xid1lptVz7v}U(?_$(IB!DS5#2Jx6;kN7B*eeH6Y zR%orbxMPCg7}l`%QMd*Gd$_Rmvu&* zWIOLy?N?LdB1ceqn(`{5Wk~$qqphm)Z>NwR5fxn~1wGtHMn4-F{W3?wP@A`$&)j64 z3J=9vb0*aTh|zVfrvZv=BulVzfmysP&rN1|cDl=Rw!1t-W_hwU8E|)Pwy`$XvK-CY zTubagcNNZXmz9Go)))(fHiqjqhph`Yho`V0LmLCgZ5ubiJcAL$!rS|-S%{&-FTXMA zpa0nf#bq}PY*B#3y6d#?rn8|azT{M#2ce}3={MG-ut=g#Wu?fy=CK6*4vL}0p$IpR z@o~Yr6+YaYgPzB6s?wTXHi{Rp^~_=M5<(;M@EV7j^C7I(<`k1LF%$6k7*F(kH~zx&4Idf>7(1 zQJ#7xnmmKgOVe-f@vFdD(d5Fz7kX8Gq4!eEV4)KZF7%r!G`SGQrb|`N1i3j^l@X!u zl?M2iA3Lw;NaqdKv|V+tSgS{pMLK74Xe_(U4w$jeq6(tDPw@lj>89W3 z_4FvWQ7}c+(>8xKM(O6eNb-JtMPZ^Z45?9bYc)zx5P4ovOY)1_!N>H^D=K7)x|RII zVZnvJpCYRC;dP$=V8p>y{*Lt7KV-?5Pc%g>s~H&IY)UbXUr+NKzwR)OU!OX266_*` zy;-NP74nOEeKkMCd9O3K@p}o~0D-FmuI;3BdKc5-oBRD@vFUU#!)GI{bEG5S zvg+M+8YHLWH!pdo{}AqEuk}rNHJV)9%|Ra#(!P*&>cwmMcSWmCU$$5l3zBp1Luk{M zoVz|FA!@y@@|yH{JBz@~E6dP9m2rK2;z=4%KHQPCNB0+`X zK0CP_0_4iA+#r%U*!*lAr!@rRRWy@B`8VCCH0=XZG`UaR?$Z+UbYLJBVX^4U2r~>1 zCB{K{ZJyseJO|<>3ie9NkZk#mOqwexG2;BE>W(DiXe1cN$bl(le15LI1JP}%^4zH4 zxX;XVu6(mkoRVGe1>l}kgcCakoKAx4K>w`8$KHlut3(i~X-@_Sn^Ob^Uk>Pv;2a2- z$xfAFGK5M0?5azgTi#?qqBv_?j)&5#z<;sJ7^T;cI7T-@Ic+D^T+QT)ICD2Nw+F26Y&Pu({Dy_X4$ML&ieDu8Ppvx7UgAWy`iM=- ztI)*1ONe4Mu|3nDoZwp;RI5qHi99t8tErYGHPk0p@mAAm=Fyzs2WP`-!UQN^udYcx z!U6*=gvu&Vx=-q}tW#fO6UNY$T^Ww(@nOf+c#mvFP9DN=G%u`P2UAQlZKwBN!z5f7NP8cmXFkUAV3fSFnEAatdSaMk$`nV zJ|IMM03k>b-uWEE$>>JsrF{K$t4T4~^Wfn`5{AG-znKaUlYrtQmP^nLHo~dYr)Z8r z&D1Dw_^1vpHecsKbcwKCG!7O1p=Y9hGM+DNXU<(3rqfu0g95bB! zezj&J`TZI$=_|Hs>V6796}*o^FQ>OYf-suBBAEITek=l2W``l3Mwi_YFfV!*)8LuT zbzA#pI+5LdW(E}HvzFC*3vFTC!x_YWnZ-ze;$YH=ci|7emIgiYhde-Mk_qkfK(dLF8W#tEEAaX%LqveA-cv?)sgO zR;abP-Snj1`VRX%EajO_@I{8sAQ|EDAqWO2UER+28LsLa)kYB5k#^mYR`X1ra;NcC zWQgFs41ay-e11yVGxI4%P0oCpL1u11yDu`>p*}Mqnp38iY0Wv!*Fq%+^Jf^Ozc!o2 z9P!s;`Z>0_l}gB|Et<=ET{@aKsAm31S?0dbR-RjgIb}rGhLg=}^=6}T^S6?ObtI_h zRGU6s<-*j!1zC7f3$ z^kNpzWy(N!pdG<4q(CbM5b%6uGLMMBh|=e7=t*%T_R!#*c)RQA&=vM4_Tg7tZpFWl z*oRwjc@>{U5RTY%`Sm_u9=<2b*Y_lO{l@hnVL;>wyj&i|O9PLLXa0N72s~oxdUD_q z@KHhU@c|RdvG=IJBdm1=l_8F+ZC#K86dwK zkdHjgKc>Afkl1$=8ojj7tO&?er$x4dEFU)XYJT{&2P!!+iHG~y?=$LP4HrBA0m98p z780D@%p!1mOJ)7g`R_g5vpGQm1`DzA(9Rs&uK~sFGz%)7 z-crP|>t=}5K!Y4W`Vo+X$N_Zb)3$ zmqrZ~%xWI4?3&?#yMEap`@MC`lD%1r_X}FGv%SSDjKbnQUrTnf7Vji2+0U53LRzxr zTD+*&co@YEEOc_fjVyG0K$@ooU=%mD(3pT5TxfW}L>CG|xZgI=Lg+lVNv16=@VyEK zT5SH)1w+ZMbphv`%x-&I(7?N`nPg7INdDv3}|c z_q5D@33hGlG9!^IjN{;&VNn~rpl$JU!Xm4lNuTm>oW?t4SR26_#~66ZAK%0sFdr}R z8<+|dJVQLQbrZ}YLBle+BD3W_fpY|n zWTj|0SVkI#gO`zp#T|`Ha)^&pNi{=K>n@|SVD2=} zHvPX^>0pGg>HMmAL!52JOdEsjs|l=j}q3axYK83`v33Xb&A$s^hG`uNyt zx|-<^C^`}*bxSF6uHNEBhckl4_->%8{EOZi{=#hf4dEnb2iqc!sE>)79bT3GLNJ6Bj zB%2Wg`Lk57!ukXWsM$l`7I&4zM@!dGb$ zXs~njGm7}e*TvIqZ8hqN2C3y_b&Lyh7Y$}U7gsxy{JC}**Z=)hEIYl7>L@mQmrKnU zOa)2wv?M`(=sp%C3Y=(e@qjVGWpj< zfG*Ppm1QU_@j<^lg(Hn&fu41zW~{2i%or@t)uRRJhhTwjKZe*>N#x+U>u4wo)Zkjx z)LWKIn?;_5WaEY&ia6(pk@0PW;!e4`nttlW1Hdc>$J#29^lQRU`iFSF8Eegq;J1KWj#|_e<*kwOa9R|4kKD z*(z3>D*AJ)a9P0Hk5>Qr#sycZ0FT(o8>r$2s_zFT7zxrH>&$hraV#7a>%86zJox?*iiu=-Xd0 zMxtjg=W5_FBU79pvNx9>Js;co5XwiAFf<11daN}f#hCJF>S4{)V>^3l=xrwoL9K}o$+oau_$;BhRSyWKHVc<%(ko3H;7RIZg)N}|ibUX{fsmE(5+6mnU ztD=qYDeD!m?^7;N99+~`5hr5Aj!2Jpi;6(0FW|fTRvlm*KV!B0x=aVNX}dK9k3h|% zw8J^6!wPbWLigS2ONQ<K_@B26zd~p^SkWkso2lfO^Ecu6ZAjSNT1^9}nm}|^O^}}TUey3; zUe*1o8kXNP>Cm=4PZ)LC8$ohr zH*(2mj`T3^6C1@Ou;NF`ZCCLHh<7^{*J0p)X8Y2qcC8gVQ|I#qt}}w1j{cgDFnQQ* zt*)c>y_6Jc>-kt~OF?5;C=x0xQikTwn?r8Ajkx#VcSHxz2NE9>!=;-NLaDhQyD)C2 zR`@hBD2~a?*Nnc@g<$kEinpO;LZs>KCXLqhEgd0$V4IeZXxuv;sW<)3=AoJUhh`4o zEDtbH{t@Vz4#_{_;OzCofXJ~bzEqi?$!Q4*`7Oa$gFmskIFM*B4%9twtv;JkVJHH1 zFD{;j|LN4UZFJ03eQ>`Hs#=a8WNPwa!;^T5fpZHBe-=(}e$9XwN0R{O z6Xslpc&Ft?a&khM$7KS;>#3avb50_=Sfu78awb>~0u4&QJAgdKo4ftkh+}> zyCh$jL%BN7e~ULnaL2z;#tR4@9ctb4z16f;ppkT+E=o7ZKus9SxWz)mf(}6;bb8!nI}tc3So4m3Ztxvif9VG3Bm`4Q+J!h^!U}T8@IRN z--W=bKIzrr%Hj_6>R?Ea^>6mQQa}uA8DXiiHA1wDy)UjD-{F!uU4)y2M5>IoC0W(m=0gB%9HHhqudil;$QQ zbnU5y^&ux4xL|#abgP+jF#Eb@8xA=AWkRQ#3v+KK+64fZ;G~{M=8^H-gUL1y|40O-zdJ(?bunRb!N3&5ALaYj{< z;R|o-MyaDK{g7{x{CgP2SkGk?q<(f;Uz2E^T7-yxnnVG|%ePZB9t3~I6uyg1B1uu#e+a4Q<7_hVF0aDFt>EL3eHm3$F zHS3|Knkw2T12jKZV}O?Rur?cqS@21*W6>3?{v_nb*ehX`j&6mYGvO05Y7h6Pi<1lo zeb)qdNc?GS>>zuCzqw|VMTFV+fNc-vcISeDvwXT#_O-*=)|V|TdHe@`J5Q`%(l z7@bx^bst-+``8a$sLf3HJWj4)u|Df-I(k^mCuZl{#bPMdG360~HXJ4{6BrQ>i{*;P zj-VVf(KT!*V6n+L{1i`~^FBwvy!n2e1efVl_mYdw>OFXVf;XD)v)VK0tgRq}&SK*; z6OJ0Gfp`P#LJhUr=oWyk!p_Ip`n{1DhtO(Vp|HcaLg}9-+94<2FN}Aa%`pV4OQ;}7 z1G1>#EzvQ;39sqK)4%AEik~}%ds?mr4fy1wAC|7qw7KOD1FAz;2bP@P>R@}w@^W8O zZE}n_#a$hfwBKgeha&prjn^+o$X_3eDAufhWu4uKT?w&brQ-)FyC`P^P^6;FsHLVJ zk;VNeDGK!ipgE{Nnu=9c#6Ac9-9t%4A5gC9*w#^t*t-iBz`Q|x z3S~YsRSbbH4ei=-r3M5_>A6tiBBE$>F0YvBOzSox>ZwjkJEP%B`eG-WrRd7+ccxGL zp}Rt@);CZMWdBDA4i#9%0;oc5cPx^9ApdMr&Y1@*gB+Jv^q8BbL&8)`I^9TxVOUS8 z^1dni2mU%8vd;@Ws5AH?dw!cJLQbm{&YgGlol;k@sb?hm5*W!mIWsk`drCVUmIq=e z2bUj0Ti}pn!ofO;OtVj?*(!$4tKl$iyEC#mzMLoYfm|w3gisV((P-|48m-ljX0Qf| zcV?Bu0K4oeY1f9Wh|CY`##<%5qsePgy{Du2XZRouBrD}R-^}!Ao|p0|6nfn}m*`WDSWSCCo%Pn; z+j^#Xd48NN=QJ1F9+$}e?z1>k# z@EAYWgcCq;|D@nzj5K9`cGcD4)R#7*dsa=V?UdC2GNXG|;M`UQRVWQKOwKBdt=X6S zMm^`o$~i=5#}cR!oiZJ>IU@7~b=}6u?0Am&ZwM4YU>A8&ddQS z!!O9}K-dKh)jwOFtAEyf$f6)oq<=QMB4EtuWoD+0Nv?qXT%~g6Gtb)Mg%tkHP`<_! z^#o6lRbLYGLy9z(#Euq4Qffj)VgELoC)`amUv56R(2o+Sy6dW*k>=71Vdrx6&+u@O zDn`5aDNpaLJpf}bIlEILb`;rj{D}f)6Z;euSiXUn-6ZZVoGYK^eyD8h#}JW&s%PJJ zpVG7tQCN%n)a^dq##6q^!OeQ_7_aHB2d=;r)90V7&-mctH3924z)(j@ySrT)T0d@* z`0R?T(ip5>nD4DZ5h#o~7rXjmT^u=SbKju0SpOx?9lN{fZBWz9ITzuARw2`eL$(8KP?>`h}*x1~!+zm=wbfQs?0O#xUoNZ__)Z1O}Sl z)kbRc#egs8gRo)DN?ok^@4O*H9~aV90xzR4=6QIvk{?0^xCF1O?>>uN%A>O3<+rMJ&PQSAu4Qxx)vvJAs=Gw`N|=e{CBh?O zPjgd+xYOJq2)$D`xQu9C$Bpgmx2Npu`8Ky^Vu_h%QZ-nPA^$RpVa9acn8D>MhPjcl zGS2=->+7s6_hVY_Du!v{9zrqfCnOJ$!wGS~hSI_T`19n@b~?yh4nY4xq@^v{vtO)O1?3i>Pqp z3opFtXYGK|`$kP?hSBcwz`HL)1oRB31n0W*APr(HWSumOwiiT-)Rq|EVkTXm@k(kf zXnPsoaJ(tyjW_bq_3pypfRJ4nIxw4oH}-AO^;!BnyFPwJj=b^z2?;~Szko_K{+yNY z@!l>c+ZkoA^`N))pq;F;*MB`I#02Lpy0N)Elgcp(Ochc_u-F2gegsss^bd;i!8S3L`Dh7_-Y1Ume*2_-y)a1j+tvg75I&@)jq=nB0#2*Qz4YIwsQB3%q!R{U zT}iE2XeUP{`q9&Q%$=y$+R-|}%ZG9DjVaxH4xcx22<2au5R`Cq`d&P-xW-UO^k@ss z96Ispmv?Z4;zaBbYKK{3C;)dK?s?aARwFRnz`JSAP@S~%_3{4!fFIOIJA%cfM$;#C zI+VJuvd}0dIqdV8vEdHOncZm*Z1VPfbULinqxz+KbYYI_Q70CyQRj$=SmB~dn*W&u z=`<`0X@27Vfb*0qz}OR87-6>X9JH zP(cWi=J5>tj}&lx%M&2kRuDqc6ClmeD^Gy*1@6OGd_!L2h66#hj|9SYG+!MX#{)K66%a*w?dc|_qQO@gysiJ^7a3gV)~)IUh- z!l*#(@f7@r%JhP2Krqx8PW@KW4kLADY=R)eMIo5Lky;#8#3s9RGcpu7qLDzkMjNLFFs(z z6}XGNsEQU9OANt`Q1So{sAz#fdv$voek$;tWfl{ufx5j`^Hp#Z{}Y3`r_>yRE%(D@ z8=DH?@`H$O#bDAAH2VdyHNc#(wY$YjIf0KLsUt|^=0S%*z-*z3Y%($ST{e|F%w>h& z>^EvTua=SKZacUg&u%-vFY&gWYMMX`PK6%x_>Y@-mABt)AR&*x(!7W=wcY#+Z*(S} zgCx!4uOb|Qy&6ic@Dr#{^qGW{M@lg*>U4zRt%jW!(x3ZqqWJ3uk@nySLegHV8Rw|# z%bjjt?mk3c+OmB?*CyK+9|f2#bgJ8z(~Uec+n*0$!R7U*n}q!Sw0iy7#v8gq>oe@) z6@Jql=UuNi%vOeaMzdB2yv+Fye(H(#{0-Wp5(nU?KEjRo6!Q`X;HTbep6=Y6%TI0V z`H{)Y>pQuDpIUm7%TKMI^e2~}TFKS$Q}Ns6My#0KCZ|C1+E>lO=ThZqp8lpm?9@-l zC-TUj{?%f4*INdlidAHs_BQ=h?V5rpQVDZg+Zq6K27XE^Lj25=(fi+h5whG&67)qD=}OVd-hEFPcPM8fYxZiBr)ck}l1I_JRaz+6G zSauX@d1Xcc0hmUiDhtt{;Z5EMj3FU^1SF!@3YBd@$hpLK7K%b2u_eW>j-qeqF%i_q zEWJ79IpSS79nn;MX<+YOaL^0k+WLNWogJtN)$MEe194D~$*gnusEzPZ%}82Jo7{!_ z8|s{qs=OdSlZyplt*#M}2kW}6HLJNnr1qE+5cMyqh+XTHxBl30Rl(%#a;}45?UlF1 zSVei@;jb&FCszZ+|1rL*sV|ZoF3;Mje^CjHV|ptmCf8gR%j4utK4*XLuqn?8)K5|` zoQr(gY{EFHk!E7&0Ma!%p_--RM$q|_S^usqJ0>S}?}hii=JH3N03ma#`BfQrJVBRU z74LDGJ>MKo{Cb$@DrRXlr>hpZi_vQRcbccQhsUc6%^8H^1aWrJGd5BRLL;0yJykZ1 zou#lc{c{IeDJI(AzE*)o_0ihRtEjFYyN)b$8X|XZ&6hoGo zFM6Ld4n=xaptdA2V5tb@=QtYk;Mo?d_&Ggu$>842F&a+8h)ZCou4KY+0>6F=JqtBP zQVCHunaG>bW<0^%SGj->nGMa*PNCk=iYD`T}Y4?i_sFNcR zcDH=?wUUA{{0_wf#M2f1yt1+;wK~AuX>f5x`f8w~P*WM`FbBv$$1pve_dAB)Y8fXI zF?k%pAV0n0)38Y%YAR}a7hjWiCf4#6Bu-#E3RfcEQha8C=^K#6@+sBthKw2jFf6n(s5OzzOgx=bIq-|>2u)nN*8 z%hm^rtlSRzsgJ@Iml$*LF>3NZygWL{5pdo+Vk=c4tXwu@|&FXhs}8q zjCAK^HB+9q1`dLe?t_p?L0+p50`SIzkjc9I8itNb{Xy$^Ufwz$9G6D3EZ61bKlHd1 zn4JE@<~(Rz+Viq%T)OibanQK5AB0T0^SU{RObQH&@c#qIq~7G5m$xbh`=>_v+?5~% za`^Sw^^dH_zE50n)tQxW$aPZhw&If)yx-0A$?I|6C)U%Ld7HZ)K?O$Yn6tdmSNd~F z!D;+%;`ao{)PLnS@tu-_+5Af1Dk*sV&60vkA)9XH_uAVf1&{MwpbNTtW{{!#;#QnFqZ{d0_*I$r!WKT)Kc7AtIZjfu7UlsRzdB30g`?>!C z*UPzXBW)$^D535+_56hUaa^}^t>yYY?K_Qk|H}Q_q+QK5McRCRXYqTCpTqlt!eKT4 zzy2#KE*UXym{)~R^vHqL;`VKj=qmzIE?I{VxsprNluVP2nt+#gUK&c~bHAGc~i z#B+R1U|Un=y&QxJdjhO4JJnR#sVpyvRZ$&Dd46q?n+BDFE3+oAY{+VtopBUy<-`bU z+E0N_$EtzLI2tUSe4Z{=(}$FH-V6L&Iv-;G{IWeF=GXjvw}|;?2L6cisetobPd6D# zeg*^Myq_s+4OxeOXOf{=I2K33m#Y=Iw+jM@U z-@FcTaa&=Qp<8+HSSp+to{2?LRmgb~Cv~afP85ERzX^TO0?#;?XaS{*FAEH83Zo1btb4NIjUYBtn$&>BT7YUhSbu^$DTg}&aRfYa+djSXdIs`ylT z=v%sk9->FP-%d^KL<8>To7!L-^o3RCK)~2|A}(vk z6KBW@ZE}YV{qpW$(N7Gx=MLc&>SV!?A+(wkBznH`dY9LIym)PP7+Ge|kAZ1urdNJe zKQyK)3mG!J{`Rz>p{F7lbR{M^{{w} z?R?ye?I%hXS=-Mq=GlIZkbE#)^{BWnSVT3ZzxiG%5F4k3HT;6fg;;#fF#Mk6!a2!> zut*ky?H*{P+VqHP;2xz>Mm;&;%s^Y~{p5^AKpO97EW>q_^4Ljpfti}_#Y580^ncBk zh0xF2GzQDg9T;EqqPpJ)?<1BmG_)GG*KQ-LmVsx@E6w7w!YaT)gztrom}1OLr!ViQ7VS+s#Aqo`+wDyXX$j zcXhM{9&ai7`6ZXJ1z2pi3&n;g! zz=Q4Lw&w&qIks$kW6T4~|1^w;ui;!@%lgl)#c$N z_`%^zPRi8>4dn!ba7{QF#)h|1f(OgoIx2%@dhS7DZ-RIAo`^fY<2T9@ulG~ZOQcs% zrLQO{LSScww+bz9v8tdB#3@8$LQ0#sI9VnS_Kl1ioIF7?aT%@;TzBo3o7(2TS5okG ze&g_2dk@#A`TZxqf|CCOe}yH(O5E@fIgKqUavzFxV;%}iin%KpHVmDv>GX3w{mbpM z>2Cp>V_{A)|C8HcMHEjZRAc^z{ZBqVY+gEW@So;sx8}$DJ1BaFN%-WqIo~K_&f`CJ zoBPqwd$sRGe!1y~FEu~cp_-x`U-(-|!QK3h{Ci2kR<1weS5W+a;IFWFSh3sroW>3t z<~|J5jd>_6F5-@R;BzW{{C-YpbT-0ebyG=PSgA>c?|EYFxOLc0M4w#o`egjjQ>arl%$i zulr)@l8VOL#^Pt*#s0GhjnE4ThL$oCI~>4rgRp9wTl;XyaQ{Jn@`;Xt_zRg(B5WHq z+A-?2ci8Y{{DJE;-7xJp@l2dRDTKcBa$VPw(@dj$rcu(lsMa?(Y)M~g+7>%0Cry;= zk#+rxEqxLjnV#e}za;t9vP|{n+sv4ukLTbernt*%0MD7Gm@M^ID7H$3#?TZeJkCzk z71;Bq6U}5?JqjdUv5Poolu8)ZynQ3+y}$}~;@|-L;?Bk6?TL6BzOdA|@kmbR+b8@A zW{iG)QlAhnN|$s^nWXf%`pD+Vw2t_giFa%4RA3zBj&qqWu(6aX%&FNZyg@maroT9v zq{I_7rrkXkLk16i{*=nS41g$12FBqUHJA+e^7`ilu$_GtI%aIj9-z&maG$!VyVx!o z=EBy02T!{UJnbI}PnR4Lo@#(6>Cpm4r)S`)(uF5#9FB>^IN-^LfvlZc=_4LNUt-HZ z{N2pNeG=Scx;&)4E+l=0KE5Nke|azAr3*7aU!7V}Sa;hHm_OEeDSZm-mo^ds9I)XA z(tWg@ob-VUXM@eigCw^FW_=C<)&F>X9%ekFhaAsy7|*YAz@v$iGULf&7>=DxAA@-m zxL!xE)JgyVQSRlX8qU9b;&5vG{ASd&fC#MY?2G%*vc*k23(qXp8@7m5gd-hRFb-&B zmhc2n$r53yo@#gr_w$S!CtAlo zoMba&{k0)uUCmf${efz{S+YTmXmE0$op`4(-t&))=&dxxjR)63jd>$_zG=e$W<=`^ z>;?^5+XvEAoXOD}ujVY{?im4RlZyjJn<@7aQ-MM@!=*0~J`x^+3|m2kXyz1#CT?Oe zb=s+!I1^46f}hZNPlYq9_y-1GT+Zem5i1~amdgtGhv4`A6&d&)LH&8~yTUZ#e*?cTN{D&t zgZpedPhjb$5cjLzZDcC&a9)bvDh$nhDAE%{vODB-2cCU5l3cdSI(1Q}b?UN>_$04i zPv|JJ!?D2a)VtwLZx%<2-pT5Ng|Or73k*CJP2JiTaz45+b)4cw7u3COC0256bMP6o zxX>=zZuzF}4A$*gJV_gTYW6z2sNFg>z79GNpL!cC-?R?v)a4t}cVKMW+`a;jTCWo$ zlDF8?uMBPAiw#6~h_55_y7bj)J>~O@{mj0$ab-+Ek+K^V%oj-(X@~Smak2B@a|Y=Q;x9SlLA%=-Y3ARyLaz)_Hs2*>bAxa@ z;6T!z@;q$odHFd8k3glKs~x-W8Zbc?(UCnrLHI85ZdGLda}np|Kw|%qOK+L-+(xwQ z1_FEg0(F}Rx~$U_<50CF;B+Fn*xtMyT}wjG>_763;fYNn5`XNM_ShWf*<|U=RN3s$ zAImYI=*e)ZY)AS8%8{D+Ec{eJuus`e56$2rUob@)?wq;HjE0MU*^RIwH$Z{AMS1{c zNA3UB*h)?!KD&0hui+A>{J?EOSGV~k2i%Og9v;|CS4E$gnX?BbZ2Rq*1q0)29uqq2 zI82@&kw=A}Nc<1CNDoj7`OHvkCMd>NmCaOuD?UR6nM(2wA9N$JZwwKCfW5?iZZ_*? zU%A!vUnYf{|1c?KI65~e++f8_p3zoQ!laCjtpKCn4h6U*v2RrDONsrXVmBrB9T~fp zF^^r9*f&z%g-6CNO6)r#R+rd+MC`MPePd%26Z^-;PEPDAjUAiVUm80qv2R3dbYlOA z*l^>ibj!vOl)l9rx3+8?YwnLQ|4}9+{Ydj4&qCaD{Ng`nIR2NL|M=%B@H%SGH@?iV zcK_>fXBRldt2U)aCb|dDn6kL4a=!T#U$k=9bKSf7=Y5Qj`+0|`DJc$(F;hH7CaMY) z*=mxUM&;0(_*=Y*TcLA1 zQG-T^B&}0YPJN8vDh+AoJ2z~$96ALnOK<<@xS|@Fq0MGkspEYnLpVMo^J1{ZsR!41 zf}MC|J=GM%KgFFfq>Pty*J#pm+C$fC?AkzerbBYO#bSS!2DRVri;vNBy=qrcR@Pk^rO}abRi#HOuvcJHvVqUchWK0Uu8| z!3b0=);q*A_5Mt}wG#qChEfM#80 z{<+rBxiM2RE7#4zeqt{2FcDju&Q0(H&-8gMaPko5k>WL@pyvAs~$PvJt3Oh*<3p|%Xk)m5N+XTo?E%+g%X*UyWJCh^M zI}zs^KbQkrbYsBjiXvdc?4gy{#)b%Y0uKj@;6}w)MxAlb%4_fsuwiWpJH?wKPS_W6 zR(GnXWax2u7L6olzZ7w%c1f25Q~vlpfxTa0=5b>(t;5x2Z64MKmcTK zv%a>Sda>r>zj+}P>b}qlwVMBf|6$Q)%|8Uqh3Bu)HV{dj{?dE<1_B%@eUNCgABZ|T z@Z#7kS15^YYnpIT6GV9E2WAejVyJ>}7{EWuChq;ZPj9QIzs8BkZb%<>AUgjc6&{7$ ztRTiHmQ3fO?HqAtujC0+rAa(p?A&QAh77=jlUC1N8YT0(oY#`xo>5vcT;k^D0~ zSb@gM1J3mN+CaV4vWeY_$i>=;(E>?nV-7pt)+2K9ubX|E4LWwTw(d_KV&{IF7gn|Jk_!8k+o}s#jaPBa+LG%ji{1p}a zs>p)R;}tc06;wLUSx3&?&*8U-_sgQm#~OK^{_Z)5zBRp6L-ZH`kj+E$;w+rICORfq}Cyp~#Gr z&&+;wDj%5ufG>t>SuIPB2mhJR4h_$Q$_&*m^e;J@8gg_19&thbYIFd=T7q~*zz%|d z-0o~45Hcz9JalF@@fReL`y1iJ#{=;)703eXk$p{gezOn@1nvp%Xkjp?so6V)y{b!` zrd9b^i_}^F&A5)9mTAbjrq1|I)+Os4-})M)8T@3Z$VQ zzbL2gCP+e{?kf83uJ&ir7i*;%RQV(xon-T?sf%F6ltuYCG-xrqf)lz~n@j{EBjCu5 zH{FIg$eweIo!ElR=at1U2h~wf2Oa&_V+^Wg=0sa+Ky1)^&MXxf@i`NH^K!_D=i+bm=%mROKeNK}T_}2%qq#!5%#y#c zdctsIb_1v@vkNT!oWKY4f0yum)IGVGbGGMp-K3i%+|l8>_84Kv+sw|8bAo%D7x5zk z=ROxNmpACL_nj?04Vr0=(za@^2Qm0W>$&|K+NoHDIy6chvYNn#Oq$!BbhK_q`~m~t zXy7)|HK4+F#--iEXZoZ+i1B5$mY8pvOpYn9n#GnZ?x7VNOaV0Gl}Hg#+Ixyk6gv@A zDwX{-ZO?y1xB$nKcZ@R3ik^pgoboEpC6~T$J9i%N?4+&cubXT~E`1rS-182lUR~2 z-|BtzJe@Aux)S!;=j1+F(3IsUtSdXapkumEjqRB3*M;+{v)Mhd#>aOgRJG{T9G+Gt z5z=z7M%%fxlq%DYqgPCAW4BG8m-{-8ZRQ?3vj6MFqh9r{8WD8Demiwbr9EYjjq}?Y zlA_{d88O<+GPkX%pg~0W9(fZF^#z4>0bj!jD9}O#5Ckhw1%7Zg<8lE%316v>Un(EO z&o=zUIUo{V#eor~;fSrW9#@5~RPNN9Gd%djy&{hK?5tF7|9_k*6Vp{ssBNP0!?-K~ z^s9N4%6UCkyTiQ-E#gc}k9w^~nRWZq=Y3i38l8SCd_cy;&(Zz}(U6siHBW4=x(f** zxRqq*OMbcD{sp&z+6KS1<|o{FQzi#Aks*v6vELpMeFz`tJHi5yx{mnR(78Ke*Be=) zbD*b$WOMR{}=&$2FY8C5@MLoXVTj^izKj$U9wuN67=N9)6CE zq4hVA`w@Un^CPQjJMq{wdWy~cpLG6PBM+ml{2^3#bEbcCo@e?8clfkuT^g}C?5wCW z-Jt7~y9aH`?m>g+SWvbll)Vs?E%?b$2Wds$=76|;fSam9qIv)(?DY{T^?=sWk9Qw1 z_`zzGRz;@444-K;7UjXZe^Ii{M2-G(JI|gNc$cbn6phf|kIcB6G|h6d>+VvaG-79@2AYlvqof&c;eHM`IC4P&#JoTp(;s z@Ya8bUOH2Q5yPn6C6kWLP*>yI4n5e7hc63E+-5XH9yMxF^?}rvkqj>^U2;OeNOVU$YSdz@T>5wb ze934FMaM@3k_*wV0(?Xt1MbhwOit}hR?aj{_mnX2A3`F*pK3Y;=(8vp%{*|#_H;L&Zgdnd{>&(?d z9G;f9tvKMM%Qb1cx!z~&H?-#n8Relc6ajKkSbH7{n*j=QHiwdzma*w{@oC_OEp26t z%Ae)n$0z}k=>8P~4TjO@;nzqKPGyG2b_H8%YC$KMwn9LYTmZ+5@EH;3KMci*M3tZ@ z$y?I~$3YTlYn@X}f!bE*72uRF+A3G3Zc=D%K_T2Wk*qqrmH%1;l#Jiq(@~Dtwo|W-=#q^rQyjqfFkO2pK(Ap48?I^<6}G>YsRSyM%emp2a6|x9t(dc+(6z zKNR_a$G{05=`(AT)%SujGV^iBmE!{ht3fM?r>GCQplVsU{sXu_9Pw*|BQ6R^jqHxfIZOPaO+FtV@oR%4&QJ(tP7CRmUx$jL z>iBT*_I1wd&9BBeCE|RAkJT$r_&Ek%JyHC4C#Mo=38=SK1{F5 ze)7D~|Bz3*GM~6d{p?p4XTSPBUvXA#cMcGvtW)y*rUim$XAh%w-D1T{U<~AWmR%D) zuc&s5+3eR*rl!6seOYy;$yZQP-SWE^!@>@=e!>@@$$oKyzR0b`UAVTC0BOPOU7VK@ z2wcvu_$WK6`5SCee%`r2wGH#(n$klxL1kQ+Dn5mXCx!wuTb_z8CKP#L&KJ3b9-_e9 z*RE{}k_iVUSnbN&qzKqotj89<4BkzyzQp@oCRFPiz0Cp+d@Y=MY=z098q^~il zs_RnT#OJXCbATR8a0>CVF0F75cqw>x!++RS(ECF=R|Y8Pz~+pkW$6cSk*)SFo1Hh1 z`I)|!$y6I_YQ)PVxK^!#^sOMU9XwG7mdZf< z-rf>}NTuQ7Gb_NwwAzw{d_l(bHSx8Ik+{57?K!3P>{(R39Qow7-ZH0rIu8TmfB0`Y z;glN5{J{8Qd8%)XuQgPibYw~?3F%5}GTufXuM;kshj(s@n^1dpAtl^lIpzDVQAt;u zlH9WrV*Y{g&wQV=(iXNYZ8$evf32r%!Xcnuo6)Lw>xBWFlHbinJ!A?JAJ4#NRAFqjFr{&ZQfZAtOibME@e!1MH>LC0s>W*Et>x4X@66O5b89Ed?UWp$ z1*TL}MS2891EuFiQcye6jj%X*87A6r+nME)D=KlbuyiiJk*@R2p)oVu(P_mORcboehPsURxe>(`hDtPWmh=S=4RAwpirS4DoKb z#VCq(Mw}0z7oeTP*uI7Q+^-F`-nvdQmwNrP6<%)^qPJ4^OP@zJREUtc4w4`H z62ptcc&B!0FWW9s7|atqeNbnWnei;QBX%)snGEr_9;cbu6@LBquW;qw5M*45KlXyW zApRXK3tL`0-{!_Czw~OYJuBJHQ`p(s^O(89uf3?q^Y6Nia>VREwU@=*udQ8{+@a(z zuH?vr+fiWR)mUXTwZ_&V)p=fdm#@#{RWq@rB~SeKdUM4{a1Es_YtYlycinu;ZiJN7 z==j5I{8Mn^_)PjcY44q#sU*kV&a3A|j2=yCm0lfh>r3meUh0_U0mu}FgIIXhL;dDZ zt092|Tg%nB=wq7>J4@&UL$a4d_q-W&(E1QrwJqYDpP{V8R1y>zH)mGUZ@KmCieZiJ z-IHui^NF0fuK5wK0D%p5N3)3A93tx5dWM+HZ0jNCt<0Y8(P9yTc}kh3dSu9XLh{=U z>FX=0)C~Orpf%vU7IE%ZIkLJuA2z(~&$S&~RV7dD<5(cYowk$eCQG`Z3e0C(;g)be zO&iz}PRKFl>kS=zQ~|5#vt~0)O*5M-s4u;Hy>_12RcuhZDTX<`M7vP>HPUq-bbhPe za?q@0OA4iC9KZ~8n}qY}M@<$}dmuFf*2)9YY(xbR(dECJQT-)OR+sppMN9}w0+^|QHe-JiQ(xWO2w(S}HJBD-OY zw_hAR7>v;-PASn@?+rV9<$0mmG6%6=b<-a>tm_L2tK5Bnz^RHftfD!&J)N}c@ev5= z1OohnigRm5uBPncKM=G!i#6&)M?5_=(?UBO(6f6`ApP^B$Kwm$QGm<1y)H+CK@- zncY9lcwApifKK*LFF56I1yr{4eT@Wsy7ccpB+m6ivv)CdVq?xhECP}<1Ets$T0_Q) zmupWFshOJDZb|;)wQo1x4xIAd%QNi@9j<+M{<}9{pVYpd&kGZy7MqR+4h-~M!Bfz= zgzyjbc=U#cxft)VW~|{-b%o7XgAdGDGi_G0SZ|5tYyG&&OGVq#_83+xmQnu2gdpVb zn?8qx2)+wVypdlCyp3ayqs(z3j672U}@#3npD$;k>zblY7=vymV+q z4)f@pz$kJfK-h^7(fqxPcWx|*+1NRz4?}NAwc$Xzh#{hnrnTG5zEEg8OZ+0;Qe~(L z?TH`nwPSIGs~J7Zwem&4^F?r;HoN$;K;yD`1@W)oSp|_gnqdOgC12o-T5(gGE3fdh zC^w~#Szj2RpwE@3$jCDC-i3`BRZDg8+!mob2NI~kfM8{di z&t&olRo_!Z|NVYnV7?hhX}Y4GzyYtYn}aqpyx(mfGVVAkKHR7O}7Dx4H zU!k@74vGq-t|8~kR$?I!&K6_AW39f02V%=ogw=8t_jL&DmQ2j++bKe6>e!V}3n$Nh zLHl@Ygy}`^C>WDaxHlRUXSIG0`FhCtHx~f5_7_9!KWEEDuLm!vxR}jUDnUnihomgYY&HE89}7^P zZ|Djkj%c3Ev&dv9w@#?^MO@qLWOJjYMQj<;aJ~N`l=*^?^JXOZEA@dottPmSEc{DQ zQG5bU9FSn>D9<6j?Ho7CJDYK+m}~PxzCyzZjwkl$@mv7u>C3uZSg~5afbbvx*=$GD<9_zL^k#tDrJAOj*BgK$aUiXxwP56cW89q#x*Iam zQD2GGavyES>55umjtr8QGbB8^1LcgbI#8>qFepr|zJ%nul4D7*S}x??cFOmETnjO@ zJ?;xSXYbLybM_y&^!g^sY8pG!O+jZ-sqIt~Hp|e~)Cbwx%>{l$M3Kot^xJr=s*;qdwqdsrM+j8{NwI5XBD|Xv(aO2lgcBb(c(-yDscadCIay|)G zOEdR0{?lr(*Z8A#@0>l1%V8QHJKt+~F8y^-`}d(Wmu-K1gxhwMD{rmWI{tU#@;6RR z%(62Veu2?1w3_~^Mt`@H|5KjZ^k<*J?nVEmXBJ?5Em+<^e-O*B2OYp!--)ij2$JtC7ZDhr@1 z0B7-`_99$yL3t$^W2Xy@Ne^407pUtJK7nz;L?IAoI8d*>~tG;0rg6&Y2JW;3cUc%&)B!SV<{FQd4qL#RNe@c4ed6^ zE_z;RXi~xA7?$k;raNpxdo{_a&oLpdSc!MsH6T-RYxUcLS8YO@t(IrGubYbzbg<^u zmosBH!BEwm>F2g-2$^cL1)-Zg`-NUqwVzMUeZkv+j)hTa@O?k{KGgI^tjt8JH9LRr z{GelY7q-_vLlquOj*rWfV6w6`1iPsXM0w{Wp$m1$GP)XiJSwCa%rfWNL}S*csl~S z6Ms7l-at>37X#zpOnSUaW6gbodE(r*EwoE+^%rm?zLkiww|42=ePir&o!3r6|23rZ znL;vel_lD`Od-a==op@mi!Uf>TwcNVxG&eo^C)Fp45Tp^jZss`@ccrq%`4=^RtgDK znBx|!csK1Rr3BxSsagAG_E#~ak&Obt_$s@`pZ?7C{(^x>WrS{0NxXMpTV1TuZg`%q z%mT6>tQ2!cw!%8R{dF!_l9tue*jWV}^Emk2QfV(a%bX7Y$2Lw+nezFD@*n4uf#~4oL$L1FwUobn9TSiI((H8Kt87;_us=C7-pMCM+oh8~z=1#^0&p9_S;9u+;Xt#+Up6EZW;l0QGz=qwynGCGAcVnrZ_P%9X^_=`W z(-YMlLOp<8sKZzK27zQ{+r94J*b9B;K)^cpBkE4OGIhQs?5*y?ZedlmZ9b+_FwIX#584>i~7C`P5)I6)lmAb_Bgb1VX9a ztA;lb!~BjW{7$Bn{&4a_ep z03d}&rzc(KXH1}Q3JSJO$6_WqMb05gxrd^@PI?st4iGPX9#$0fgZ@mi{xvMuzXo;V ziJ`bNV|9eq6MUVM#n%Z`p#g39I-i=dJu_Z;>>a#G4CA*(feC~ASa34afNbN7hC$gGq z1$Khufb(9k_A6!9n!i!IVIXJedx#%pcAkznlbE%+aJe8u*N~4a@CR&n_&wfNp=2c? zcuqtWo6dsGI8IY4P`V?1`U#X(K0T1Z0|%rBzt;4l|Iq`K%ArZEBI}>-7N=$k(kh*@ zC5fppoHcrPgWqdOoS;n6nrJevUw!(_9mSOXW__k~<9Om+Q#!iE#<#r%)0zScJrB$)fiN@kf&(v!}Vqq*Q?de>w#L_1T?TGwVJOWYcqu#+079=IpzNREb&YhgKytY&hP|I2C+Uylt;|wJp`&mR1V^s!oWI0Lsf3NLA3@_QaGLwFQE;^Zoy8pP4fg zqV4_e{oU_FGkc%?-fQo@_S$Q&y%wLJCTJRVm$m8d>_L;%vp5&hl|bZgplE@Pbl_@y znWJt=wPb_D?!%<8m4B2;04FU8n&fj;h2mJh=i2Kamj*RGythH$z72zp)r= z?tQ4_F`6m}>3!y?kN-uDI4B7=N4J|3%Y6%D19CS}^qi68Yo0Uu^-^`^4iLq^5_5DZ`@mGRuvj;y50VAyZr&x{$*?|E(X)uf4E87FS8VA z(bk!Qs}oGUcc$M|xbWMl{q12U`i%CzZMS!nYOfTR)><8{RbkRve9kNp@n%5W3!#RY zC1ha~&i^;`z|EW2nkw_Ce>x1~wjBnb6@N)e2$=8q>|NGe44eUKoHBO0c_tI3-_Oc< zmpU$XT4inp&2NEhmc3RtuEHU9u?|_w-N+pdh#JqPCjvCdbk9bP42WbN)ZOzBsT`h#=Op(_q%Zlb^q%>L)NP#B8s_krZ%n@q zBC2*j_*RlH$(9j8i)~l{KcEK;34lrH>k8+CQpf88%wz8Ky1IHu;sZr-+4yh>{cD(E zc)nn6AQA!rR@tq!QjiXKGB+my+gzB;uF7Lta|c}W19MlYW$h|v(tZ*)_6m+5($B4u zi{(M$54qVo7%K(4J0BXN%`FT7U9;8NgFxMUTH&z6Bo02AE_lx-4z9k}#=^4E?YM^+ z;~AzlHVLA<2DO;{4jNPUVB7W?CnZovT+t8M2eEI5$nz#B2!)%wlp3YClf)-n!ULpd zi0?TdwW?InnN7rG@|a`)bYG#?x((fmT@2J1PQt-frO=D}Mr;l<(Qxyqqm$zMY^-3s zzam~R_9u5UC>>U0uK-pM8X~NSrvx-0V9Kmt-UonPQ3!D-e`zO(Rt2-2){hVlmn*3IPD-^&LMz1IV;0e4F;pPBL^hC~Y0kRmc6D1vR;99937 zi%>~#6(#pS;#tq$lb^jyMwmL!XEx#-FQ5Cc610|IqApz-dg42YZtrGeE)XJj@K7 zMC(P1{Pfv;``uWfU8+1@1xVb$0G5UhjVU{!VF)Xq9X9abq=VoAk2|4Hw77+1v%B4` zcSngO8KoO{Vfx?I&>dZ!3fZ&@-tJkADt^;4d>MD$-5rfMDONCSQwx4k7EvD4c1PEy zd~w@nZN%-2!1)5RZ7vsCj@g|MU%)t%$QUr4OPErG1)nyBhIidvdhCh{w2gmWYvv0i z_K!_X61-m(5FLXW7>Ey$=G)c?I&@3l&tFVl84tXCzm7zvkA~7ML0$vab76GA zhI2OHOa@OK-e^!nAMJV#bG$ps#lh}Dc{3&j<`d>u2SEg9wQ>kee6jm*2oC}LQfAZ7 zipCkx9o-FwA>Gk>)J0#AJu5E40QXaL1*29Ei^-v3MwE!tI_YY)qV*<|MQ}yyrW9l9 z?m;VBk4hT1c@-9Qw_!@FFLOt)Dgilk2K5xB16uI?EjM>rCRCwts!s$YAg%U>g5GNi zdg=4ofnP7|q6+*zwC)Kx@cTX5=VuRKB9?G$5MZHN01=@3e+xGU{+|uO*U<^G2JUZd^DP<%f-Ww^8rWjWxtZ!116*>Pw7z z;I4Y$hkCyOL|B(dA)R!8-=y|7+TDAcRNqJr@?f9F$h?jScv2L{bI2p@H@Tu+jx+LG!Y4 zcz!1Q8iB`UgZMT4Z^loPQA{qxw?)Z{+%vUNB)?7&>uXCU+`4U#j2pa|SMkdOqegB6f~Dl)o{pc|M8N_$-2?&RF3 z`$^Z_f9EdfDc_k zX3^qe-NZ#B!W}NRZd~fom91JB2o|t-k8H^fxjBem{Xn(%6tp+G)SCzmmxtngXZVdp zUL?y3p}1X^IpOb#zTD`QCE571515~`@Hzfz{d2TAVIBBE<2B$y8X61^1+WUJY+<0v z{3{J;eO^gwv!s_+_|K|yGdx*1 zH-fACR#oNE`Tqgk)w~P?*hVMoGid@FjDaJ*(p_0sjl;EQ7$7_lnypwlAzZ?pM36R0 z#lofI1sovIrk*e*qX(K0%-^7{e`iZy7M9q7b;31Ycut>neHfjy{FjfXx6vh@&Y zTn_h26m=Em{&#=@&d272*Pht2g-woYNFGA!lBYW#6-=d_@ID{@ce;aSFCNj=0k8W@ zKk`G9Bf61ijbG;mSNr$ipNYtd1^D~S>ca8^h{bDDn+aQihXx4>>TW`O3Vus*MFDo| zQVCP}e*nLdV)RvZFUaFtoO!zWT?k%x&;KeX)wyEp?FzH5ejwfbw+Kj)q81{`kz67{0pW?ZGxP?;T6Jczq5M1Fm=MTeq_RYS6RO>I^ zhr9J=N^n3{!WaEpw$`liBU+6ENG!&;$b1)m50v10ar&`7T0&M$2G9fDt!rLqQ_vXM zGGKw`1o%UiU(Rt{xmXNXD*|pv5(}uW_>J3TURN01fs^gslPcKM1xr$_&Wrcy)4y90 z!WbA`r{D!n!1V!;eZWZG44CMxE`hjH z&{Zhz6s}a6z&yXwt0P=oPCOgkT#9K0^5#-Ru4P?deETb}@@UOuQvm}Z11wTG>8pUf z@Y?9I%x$F#+lrV_*|I0_pJm~&a zYEU>#UNz$|N+)ow?D2B+&vKY#Q?y4X8`puvKL$Dj{H0{Z3Dod4Lv-iTA-ls}GP65Z zj>F8C?v&cy`4}%SQr*G4IJNH~^kqDfp)WGm(q|bLl)aWxQ%_a|6oXZnyZx2EanMhi z=XFK8sxYqSLTzHTxf$)JbPxixB*AY}GkUZWEKwK{dk4notBvcS8tr-y#ki&+8_5LZ zIV(T~DHwBcQ)7r5r{bVd495cz3{}d@zG#5EN>}o}-&O%`=FL9Cet}0Fj%ITWrYZ$o zaU|Xsm(ziMe2I=DmEsvtU^=L=o{)~s-gwvuo3#u2aE1Id81kSeJ8A+JRV3d&ko!^V7) zAe4E?#S6AMUJug$P$}YQdNG0qCHFvEzrAo3F{96 z^G?u|`&kJ5n)`y4dwC&j-|gZ;nD@H45EkT(`2#5-bqUK0VG#DX3I;F`3grEdFNB4U z<6H={N%+^FFdhY=i$+2*Zc-6$|5ET8`JEmJCBKHK6?Rno;$?(r5Kg8R6~kCA#`R^! z^{W9$$_#v9PKzv2wV|(k2!{ zF|q8W390~VPB90)Hr^@b`n(<_0l9;SG+CF~PR_J$%ED8;e()Qy6Jk)Kbj)@Rgc0Sh z+0M~0qB16CJI4g6=xFQOIRwk1{59J-Mn;ssDC{5|BPx#B9#>!DnC%=d#EE0JbI9-| zj@iyp!xtU1odah?`D?a&#Lr)lD{k}>7)7M~k(#3k%|XT5=vh#Hu*qKwOJZsAZZ}kMBl&H)?Kq(Wi}$EWhxqshTy} z<%(;1c_%7nYmy`$w!CW?q!;+lUu-qrzil63ao0)_SK8@f%*<5xp8U#9Mlra+H+Vmm;aAOw~ZgTuc zAl(^Vtj28{Og$`Ccwx5U;QmqQWTP+K4U_ z(ciPJu?G*@jYq3TNUN1}RI=ss^m%H_i;a3}!&K_I?Cc!@NQN%g&HIzn;$N_lvdvpK zjV?f6@f7N64<-y+h6RjHoPkc*%}3V=qKlm_K&NueJ(H5;88P`VbrV<1+(X`g0^*@DFjfL7w^Q609dKXr-MsN9Ni0a9XkTA9h-&Qp?KSA}rZVj0^!t3K`vq zbL0y7Bq`iXe2l{=P)swCF}ye&G!qlUi&i$TRo-HF86i*4#^`hA+en-nQht@VU{AGVenr5KPKzh+{IIfvkCde%=;UatDkH z(8c_|;eZNZVRtGv;|J@fVp&N`!a|i8$0TkG{m4k$04#qx=S#plx&yzkts5d!?sF#C?dOau9>qlooQ=}Y#z6@xhDRDT2s2xg0 z!k7_F4QL@IO*36>`Qr%HT8R_we!v0?yQ8(Xt1xy5VRXWan4j~W`ROkCMtB~>I6)ak zcgfY^tL!P0H1Ki>zE>kEY25{2kg>uyhb(+1zSpXFI$^E4yfbh#P68#IGuU2^y$#Bq z5b~sk2|Gjx>|+@Vlq-E0Y`RC#2q>8n5l;P9MoDvzG|zp*<;o91fNLdlV8o`LskU7WIY?Qp7F&+41S3?Y7fKL3I-~qkFQngOV+O;tP{k^j51{P;){zG zDe0*7Sl$%Jz^D_(1>$#je5vyU6pKj|I02YlB-K2`Rayz|CiZjlAyGz|-BYya3V5;F zWQkyP?OpQi@a?8BP++JkbgDLI8wjP%A89x2T#f!1!-Zipv}z9kvL z#i<0YtUgEt)mcvLVNO5TB;N5=`I(W!U=#Ul#bRJ{{Dd^Y-Gy;Z%cK`~}zX#~p z0+SfOXE-w*>M9(W+SyY)?^itukK zrYuoslEj3bToBSeP(VJII15eo0jz}!^5FEJ$vO39G$G=HiU!c;0nHzW#m7F}ATUu* zaAFsIBNyaUmqT%2YEz(!-qfxTGz@}_yMj9vs@R@j03ncAo~swY#TSxuWx`=A;c&J4 zHjv4f+zx`^aUu|`OIgtl-|oiV&3H7e=8tU((PE1H!{?+Ip0*eFF zVf(!O0d`kRr1`Wd-h8dS2?08`v~n5|5T-}K5b}sC0*ihQG|_lq0V!Z!Q)2xMGZs3X zL7wuv%zCLvzHv(DH}shSngO!_6N`0FQsR|>v7BRo6r|FHT(`Cq0~vM`XDHi{4%@>1 zPEIyfuxoNj8 z9}(cXaP1u3qfhM73wG*w<2zC}WL;rJ;0aq@^!WJDWYgp+pmMwMAl)j|36)OlHO4u0 zFDT#8>5~?e?EOnGVbJGJ^5A#&q~dF?1$9M%i{ofJVUU`7~Iy$VRfV5iUb*^ac(wxGeDgilfTYah)|2E0@*lu^HVFXj)%hizu!2tCF@w zs?(>dW`w?ct4}-sn6~`Ol4J^gkF@SXBXV)}i#=>%MFgPsLpNWxettJuLRxD9isULHggyh2OBZT-tjYOYG*0a(S_w2C3k&Fre54bN zv++W%HP1savSRFcaxIIUCod|@``QIohqNe+f{L{Uq?~c-FQ&N`jlrtSd-j*YvDm7$ z#ZaJ3AEcw{0nA%9ue&!OCPHctOg%M#U^$XT#CLEK#PD!->kN(3nGRjYE02OsoZvk& zE&b-+@?(MSPL=_AgbioH2}{M@A+Ck(OMrw2t)^9VIx>T%fp`eZ}w993oRze zGG)fH|3qs~Vr!3}-3ZybaIQVkZ^s-=) z8v;EEzETS*4QbgZIFnyqEE3GvfrJSQZu$P|%FcW3VZ4;XI0(&#uNIuO0Mdl&h*7!q z?mQ^dyLb9$Qrjss5?=E;$O8u}RAwJP3{G3UvR~JN{d(nqu3a^tS026hvoOVvn76V& zjD`$^){>=5E!{gT7q(F3OCu*;xoH!3{;hiS?}?>(xMg1qg%-Q;dfuMl-$a1|^GjtY zU>;QX5LVJW}qYgPTrH{vaj>p2!9uJnL==+UBo_-WEA5h~#lmXgHAqtGg zOf?>taXc1IIMOVbTbQ_#4T3PeFQkvgubt6o9`(7Sp*3@XP-8)A8SCZUSlHpxCdgSO zmM$tZ6(#_2vLJK3&H*W#IbLtu($ z+~K5+5?&W(jMCR_wh~}RjLkJrz7Dygg|xHShTH^_fL z+U}>hL*v+_n_HA(CFom5RQet^R#6iWNtc>>`2Z6Wf%70jOT!a64MH9gL3wMY;RVmc zZk$GH@C|bje3*MOHj2J6X7|zE1zQU`ojA}^FVZe|j&{Q#y|ouljs|5N^`)PIbv}XF z$EoZ*%ViX>1r@M>UajOUt>o3-2wJ74DEN3wdD~mr8Fpv(pzqt9$7p$L_dQTcfqN3Z zIO%3c!PY>*i##+@+uLmZ-tsDheHYuwaANP)H*gQbzojYz>##H6RuuHqThzz~{I(W~ z!oZmH=||r{NYFfrz`(@61q+S&>rgQTUc%CK&88I zlq<7Jgh8tx|ue*FB-?mEdG8urV z$B5jV5B+y=$E(ZRZ=Ef_i7jGXK!Z?jFqqTP=Ym?L2{c#knj+_Au*3Vq9h#eYh z+r)k*D_F2CXh<4uU01Xp*QY5FQS1Zq9xHV~vH=@3vFXT>7yJabD+e|0hY4lY=ml#a z3Gm>=IBo)P_S-wz?b-|_=19BQ6#xfzEG&0_keHFEF4$ge$T;|J6^6_$}JsC0v-8i|*Sr+Hs3D6+J@9h+J);1n4o)p1XFQ(D#N%c!c zhc&j0$IZF;%nqGwFN1G=sHWD3=$9AsB`L1~6v`F61%zcmuXi1k+&vvflB3IkC2N?dE9@=D*hJ8Y0SPb zCYX0*zqav@BNv>WI;d|vsLj{V8B3EE2-S@w1q&wFN!Gvyy&mmxXG9mW1Q~Q>J>-@W zdQ}n$^|l=0%HUHVOhs@WxahI`>#!-5DVvSS35gSWh0lzz=P;p3Cpd98d0eh|PH=>M z23L$-0YzwJa#yN=k#NZu*oa*C*N=m-d(@2>>Lf!=Zanf5 zjJ|@wbrQV8nySLS613-K>=D*Yd|F3I8;|wGy*Rg-BN>8S2=x0dtFAARfW@-777!sC zRT+h77Jxkm0UCnsR&5;KCV(x8lOVKd92*~ovSPU^uvvyAh3pN8HDW>Zo`Td$|A(=h zVff-eBlp-vw+80LA2{)eUWi+135j3Ll|5kOmH6U#Q76uta0pv zM2otL1f4P^jerHDRYV`wE1A0XSApIw=}|f0ud*6)?~W84N;n)uI6``N%S8@xNf*wr zEAJoX+J?V3@aM{gd_q<>|G`BT{7aioke`?hMzIO=Zl4Ppun!by0^M?1#Hs>@;<>8( z!+^1p6AljB2Z!y0!}bZ}0t#|heAkBDq?HPC#c&03Xh|_>Hb4vaAXrhOh4t2V8fG_H z+o^y8w4ni|@}Dd`eqfyAOu>O740d2V-oxKt@b`Hz&{eYmfuQ0#2Vl;jbq9(L+IC@6 ztAL=&PtKM96@ZwWN*8^{2FTP06hKPgCION!0LdQ$Ao>3tfZV#`cYyL=@Rx_e{{cKW za0(tAyZ>`|ocnDX9{vXvJSyP+ufyX{fI}_{F2dhGfJb8r9udL=7vlf76J)|2Hb7=S zqyVDB{a*&iicbj(l=}tzeLg(W<@3st+Yu;xv-yW$Me$-02O5#_NvK;~b3alEBR0{z zib+7Yd2#fLqj@^ zZ08D1PPG3VnITbjq0^LXn<7(sd2sLS^aPJWk3eU&^yJgQ$&xtV7R&JQm;kluAe*2Z zKm_l7CZy3+(0SEnWDPpQxgNsRWfMOH>|@Lb=zdsa7AKT*VZ6(1X2|p={z8eC*;IpG zLEwlEt+G$0fX0_8qK``;ZwXBi220~fey6t1Jri%JT%~)$!|{R&s@f03;_I*uWOh-f z>k#~}GU&IW@a}Q*LvSNu?FC86GSON*$OYZYI2Tm4;Mp#@#Lz!?4Dr^~ajFN<^-a6SZ|9GoTu4S#VNG`L=4aXBmhLs|hngm8Pxh!5gm&k>w!D5~!R$be?MD zk<^N9jEP_LAFFULGiRGHb$qE)0i_FaFO2tv+1xsmo}cp!r$gUF)({(Pw zg--kx?H__#6!L1 z2N6-NfaZgk5Wak-NykZjno6CIr-o?6ja_)`C~k7T%J`EDT}FU6_&`jWofw`H^Ee9e zK+I@=`Cg9M9%~P{e7uT@pn?EdXruUYl1FLjo-ac<4EB7N6Igz;v+pGMx#?9Y*%e-? z*7?mnxYexp=WO#=ZmZH}?eXR8hNY+ZC*xClpcBv@QyzyQsFrO$+;aAv{HrW{l*jGQ zeC7o~R|f@z?F%s{Dj~UymS_)3_tHe_g=<0@3`jAbwgIDms)6xu%r^CE3 zXt12k$lrGh(~*26lfg-+xgT7?K&D5`E69Mz-7I7;1NT;$dwsE7x34ljKMzIq<#^X; zAz%zN*w4=o=HOCBg>g!TAzQQussVfdj>f`tW1M|T9zeoZCcAf&bPwqQIVLA54lts) z5johsfGORBouv`b_njBW*(R0ZdnB~xM+pdmAAnNxh06e&RdNhi_+%2!LqG*+W*e*J znW^u3NpvDekX6BisR`=udK&L)9b^yNff9k?K}-I@xH#(k3_ z%nwFS8Mh^`9}*I<2d|5vNi0J=@_oooGMnej-PY3pxJ+bP_+G}$xV4Ljdk4iDcB*lO z#0Bo@dJRNic;XUoiynj*>7DPNa%3}vC7H?|(&)}a-_1xWG^Nu#sll+@0EyEIJ=QWQ zg5n@X#b%eN=C-J&Ai!gdkQs8H-MD8ZHD4L*)XR726L;zpUlx$IZi66}vl49tOZ7b|YqR>!51RKML^2!In2&ImPh&dm?Pf7Es`D$ zq8CI-Djo*l6*+{K%#X?s^QMdjxS*X_YbgNeqMv%TD0K~*FL&VArN43zx|RUA08Cv;lzKWcl$aJ%h`j zc8Ax?oV3A&8UtuSkB?rUc5}Qw2akn>g2)n%wrGePQV;pEOGvDFFc~|-`nAM{ z-nH+&@LUWH=mg)|jr_;l;Zt<-2_w>Itc8i2BC@ z?OMxr6c8QA4Hra@=V&dz#aG|y(SgG7*y!;Bt>x$VrZu1^8J-s%7#|t|VKuGgA$&us z^Qo4pu(FqHxFR(E5j{RxYgvLAqzjM36XZEQ15Z8D1}Zv`1A*e>x#1Zn#uS9Wxo2!) z_{C^N@q zGIHS(7>O$gG3^IT3v-nsrxQI^5V|}XXV}7-NKzOYhTpN_(W&^t5TvZfhTN$aTlT!R zHlD?C;sXk2vRip)4-x44CLS9NN{QYr3hMKqt-NUTjROhuzUGP_bGdC#9O}T~*wxiB zTz+%qH&1@Kg1Y39MVDAx>FO9EA-Ir3cmaP`OhzgEJJWXQFSY#>;PQ`ggX5XzlP8C{ zvfvKK-zfZz#oq3DPQjLx?>8ymkHv@a5If$uG9TSM z)iu*BG;l>TV!@fw_wz&JqVH#Mie`oHjLppL>QJ2~M(m0nYKRVa@bK&XY*@8@e^^>t zSZ_LPciRSpfGj#tH)QhhG2bt`Itp26hk{r>{g4;!>cC`0C|`MYb&Qc;oIK#y_$%Fx zc77Ng7{2IyHDotmFGKdyPm)6>ZSBDFLZ-AK!@39l`vsCci@%NbUmWh%v_Dp0@9#?ZK!DHVh$~A*xx>}EY`Sr+DaD-_eC18#O;*TSWThqAt!|CMD_vrIh5`mb7 z-|y@#;yNm9IS|T&iNNsrkp6lm3wnYA(arh(%3bq+>jPe&gxx7^ZenM&1$Sju+mk*O zD4>uZr@bUairL=1Z0~-b$YI;<{X$xMp$6)|(cV4bxi}`Wy&z<}(B3!D-spf9y5Zhg za7W)e2}}9UKLe$e2w&*yMwgRs2C&BiirmwSyAZ)KQEN0kBDI>+1Cg5Jcw%afkJ@GB zkx-{~K3@WbMs$hJe)l6z-Ul*$5na5Bb+}6)(ms~9)E}NcLaY4{9yyb)kjWNcCP$$DJSDslAt*C zFP9}tkQzU}4^vw=kDHLIo-SlW_(DZ0+nf=w0)-_aOtLfd%4U*15WY;~jfGAZx~Bw0 zkr2v46pgS7@Q4FM@O$909Yh`}z!Rv9@FV;(u1HA<`=*P+k5m!hYBAm}q6cpoP{e8^ z=635VZ=$2EkK<|#yq;)McRV|kY$vYB$=t)+yJaOvEG35LN0T>D3&#s0WAK4S) zO&>s^Dn{P(((|7Axp~7cf>9{&ymf_CReD6`corY~H5E$(P~wOqkvO`Q1%rHwaO~SV z_`RRxzTUBCf$VI*UzvmS5r+LRA_}(1iqo}+Hj6I;UwkBPr4f2CTm0ei@>Q0D+k4YM zxIiHMD^Q%76o}MU^FOaIqneFQHB$bCCzP-3=JFaH+R~1rc_T6#x-VIR4L~tj3+I9S*K#m^@RKs{;foGpkpa*Ur21DXkK?q~|74x*oKfa-{<2pKlNuJCoVW=2DIg6gm!;5;AY-Q3m@*f} zu(GotZ!oB?j`X_1(5TwZaRYOc4o7b;y13{8^M3B?)>fDmRn#wpzpV~@`OO|b=FNRy z7Dxc%+GFW;2rT#``?U=Z0As*9AZ^uJn^3MJ&KPclblSKkTU;&rt_BH4CBDc*$FR`E zOmHD6rE4+;3B~?P%E0xW0{$%SUrw0>&SuND@R-aJ5b{C>32nFdg!Yyy*cK|yHKkD= zx6*;B6rEr%!$FuVu(5$?2aj^Da4u@>LJ(d(+Cfm+#~22NaO<*6PJR$gnq+#xISY7U zA~cliEA7M`Pz4hD%w=>Cn1e8Tek0p%f(}O<=mrD5L9W{aW2wSfer2=*<^F zUCgS(&*gO&;T3?k4svesQrrSzTg2%_;l^en>2^cxs0EZ8gA4tFR;d zl|5SX*QEP6$`JwFBGZ0|4l4eQI$K-R4~v#wlHyE17)K+q)#&A$g>GJOHk^0!7Zk|6 zKyl>apuzbIMkqkw8?#ix75spUCZXNta{dAVEs$B};3AtohCYR$`6wp}XC_6&U9Mt& zYzvsH7#uLKz}x{>3o>!DkQO3HZv-m$E;z|vCKwfz(Y2@_GiMy>dB1&^c`=#hC_pe4 z$epPAz{YsCy16n}aEGegKL0mq$jUCxr*JYRwxsEtzjD#<5GK2jxr`2hyBJ_w1jEL{ z_#k5rLkSqJARmNU1EAK(i%Im=61{Y{wl4poLU*_jcb!<$uq3d#FYnZNv?mLB&f+?? zYsRvX>@0r*%GcWK@Qb?lp;EMm4&#KG$80|B5iDuI07a%P3BW&B;LqP7;E$_3u4(|9 zH?$+F%oRF5`_Kwsjo+-%u^%K?eLl=gF%A#;XV#cr-Cwy|jb>&}=(12bF%yT#lH5L% znb=Dx@lcs+sEr7jB+#y>2KCHeWhWP)B$MlsTr*cPIj7WiZg0}Mnwr#i26_&1yK*eYFt7ITikxwWhTZ7!3VzbAW6Nj}loG%KuV~pb{j#~k4 z=QVt)g}<-21Hrb;q>9yAeyxI3iv7Lc$0wTL&evL3u?*FWegAGZqXl6nG-Cne1?Lp| zM0!{nqMH|Qr_5cWZcg3In~^%+58&tSNsZQ@&|#p68Od!+8d+ervjw{OcHhZnTbwnk z){i&aRKz>}oPN2ZZ+#s5lWyGPsxrR9=}rwmN~9DfAocDl7iKxOZj}qszMP#tLrYI| z;&?*kBe~VdOAL>VugU8_4%N9wyyLUNc*$-YM8krynI+ayz6WXJ5_%5Jc4b|L)%iV3 zVlOK(->Qz~u7Y*EcdT8Kj!QqWCCmR_Z}@*%qIc(hz?LSqL_f`2@MUug(tn^w z<0E|?MECwu1mw2kOqx`Z8vAO#ZPFs<%?*GF6#g%@D}&Jv#(L__kAn|&g%5FaL4EBZ$k^+?(Xqk~)IfjL^tp(^0cn;SyarWQ__SF}pVN)>3MXRq zrBK)`bM}f7slIiu&sfO>eywUBp3$|7?)l}>{MJY8{<6FoVkB(AP8 zFApMgI53X{r6vLPXMitD@Agmfay+0?S}o4w3D{!|z=$UzD7gpu({1H@t>B9U7Q>=1 zR^X+sY~K|Q!u-eOL3qh7FOKs5*7f=2VSjD>IL)@um2+^dee(>RAFDcq{c`3A3+5B|DxT0(Y1^l#W#bdXbfkyS_?ae z&P)H~k$^m|i(8LwX6GAkQ+-W#F!vSquMGWruw=l&)5Og zv-I&SPWI*abVED{ro+02f-_CP3^WfqAL6^(*JXeQq z{B{zNyYPb(JNc;L?!T15Lit}Hp)&W`TJwj`a&ZJJ-v}?n-7RL~6ZizBeGHEE$zdQB z&QDu#Y;v{YT#x}WfpSb)A~qw!ND!L|?#J#f;$r6_;XxLJ%tNI-JDD>471qin*&IiD zd)eLK%lS9i1@Ybvc(FY#>Jop>V~p}u9tfAW9?@FQ0pjBgz3Mat6xiSN6;ahl`Z^4W!fWkf&R-g(_+Ok2IR%>|x@q%rGyeSrJ z8|OmyS_i-k!s-q2Mj7_uA)8kXnGRy*VCjG!yL%GtTgR~f1xx$whkRHl4W>I|2q-I-d|nV0uTXG+nTEtz{z`5`sBY%)gIlTxFK zZoQG(jt2FQRb!a1dOp=ZX16!yAt(A%h(B?n+oSver1MhSbOu@vg-=9TUh4%(-+28{ zL!Po1G6+8ZaJ-*-BL$*C`jr>H}bowLwax(C`D5RMnI>9}>n+iAF! zgiA5)4U`Q*-ra|~Wb$Ovq#cl`MHCqFA z0+dIdO4bX6XsMC6hNszZicy2mbPlRYC#)L8ILkxUN0J{b{Lem6nKH#KsgOOz&9uwF{DG{EIqD#m6wN8YqV5h_JDQq9a}7QE^y`Zu&Thi+1IT@k4#N^u z%ZU=HmEEIv{N4UXRCjwSo6kg)_g3(&e9GmcT6eHW;qxTL|*10%VrGCTEP&StVX+96{zV5)3SALBep2XC3Vl>UvL!SvIxsR+8a+M|mjVN0 zL#IZMkA+>Bf&37}Z}QQxA{3hxyilS7N{paT!l84+78MXkMh8Yg(e&|Aq3bAjf|?3g z(+Jiyf;Ej{O=DQoXx22EH4SG?!&5bpQ`*&`1QC=_f)e)-L6446ne}nLoMIn3IR#I` zQ7eWwkF9%k4grJ-GA{syAvOK#{Ny`FIiJh@0Obky!wwzHH{#c}6eV`)jKv;WLNSzS zdSiq4HDbdJwQ!6Lv}leGv50PLC{tf`becM8cFOvehM8$>qLC>Whnf58dHBkST{RA2 zJ^L6I%?EnL*KT~>+8x~o$CZ_$4`}VEkrp%E7b0Abd7)aUH!J){WUziG+3Vht?EU!K z$jOH?j=>KTP1}*krDF5pAi@m?&tHs9#VXjNf=iOYWh%Hr1$&dhx(cpQ!L<^s@HNE< z(Y{;JK9rkmU9Tw`wUe);`+a0wWZ@=R`=6GHEQ)%6fx7hJg z52#&OiQ_GEycLeu>v*Xi)y`JqcxxSRo#U-{ybX@G(eXwc?=r``!tt(hysI7W8ppfV z@pd@gxZ~|{yt^ImKF52|@mh|z-|-%Eyevp`wj@RROOB`>Rv-!NZ@uGfNP3M;5qNdOTqe$@`Zr*>CE9>rX}GZ|1n;fJrn})FRYaUk%apT1 zIji8nwmW`-wq;VP@U?I-$@vkB#^vKa%s9-<70HQbY+3~`U%{oF2W+llw^s~7a@|W? zVqP!&pq8Oq{_nUjZM5$&|~HrtX5w~aj`Tmf-q~}$WpM^X&D0D zHljVM^Q)QMh^~Qis}X$>&a&uQhGEY}N8sy@#_^l2x_MCLvgo8y4Guo#-SdETF;XAt z$_kxB+eT-bqgJi6_wsn(utd?HkDrg+`OsQI1M~Ir)tz1(=oiQ+E5q_E8Yj-Y3A=zo z%}3XuW*S@to7jt*beOV)p|*+Us4uH3@}Ta3bu3TTAx7+TVXi#;cI!K2d z&7v3n&gR@tL=rUC51r-*NOPq91`MbdX_z!TQ8ynGjF0+psRjGfn<3*2_vBq5(2ezs zd!Cq?=W;v%c#K1mJP*WfwDiPIzp4Jk9xGPm|dB=2+fcFIV=2U#oXqQ`;GOlVnX;U)^pDajRokqqgkGvXQFKq zh+7i?fT2jt4UWVZU#>t6O7H6ViGw(0GDH zh9+)k1ifK}5lNa6!i7CnahDr6xd9WL-6#{;n;DESpaYZh@o0fZNy?RRD}$d}+!MYH z2#Ba14dml9>p`X>&Lc|_5S)1rDQ#`pmo%&-J3kCNSST}D1hV~p!xWcq!)VNwjLdm< z=6;Y{$;?PS@}06&W|YO<&9~udtkCq#K`bG!)pfV3{%4sby!3WP3EUJl}&oy@D3oT?&)326YU&CL9#1FU(ZcTnaZ+nL)kGuLHiUavC82W76eGY2v=*CVqZSgHgQ zd-OU&YbI!fjBz^O&Z%YQY{;zkj%S#8)?jFT*r+;8#Z+k>Zp_S_c#|C-4UyZ7nxC~Z zKb)C4l9_qCWd53GP=^=UnQJpMFU!olQe_6gkWuqRcIHzvGq1?ZTq~Kcc6l;0f4WHZ z`E48t)B3zBGxM2}ImhMkWYiqDGe4f0d39#yKkS#eIk@Jio%!pTnb#n5a*)?b&aVy5 z8L)Gno0)TMX0?k{weCS3F0?Zr&d=y@M`q@Kk<2xGS_P=25YR3>RpyqnHZyZPtm@U=M`q?jVb$BsnVAo!ReK?F2FRg7%W^Ye^@N?fB{R2`miyQn>@FIO<9HgBZ?kh= zo|&`XZnV9%y&#zZt4K!X^X$x{GBY2`%-n{|0RlP#WS!aWzL4tmOV~luKvn`G2cJTj z0RL3|dWtGQx}MR3r|bgE%mT_X3n+977>tK*vkSO9tpHT{`s*2#g$v~cHWZ=#XAkNE zl}zf^M7xv(Zc5Vnk)PR&Rumf8FnXBRHFHoY*1M21=49s`VOjxh6p&n?S4eISNb}&_ zPujU7nYoM8a*s~s=JSUP7~X2#Ab9V!3=nt(1fu~0OuozlCffyMp#aFVF(n9` z3OLEGptx0O#bGuKi=ZHCAlZ>>i{Gd_&DsyLnt=EXDoN%>VO~{Oaz01n%0Hd%mP-W z6)o{7EqU2z>Q7;s|U5p(xP^$f#A&^#0l)0W-Nd|0LRdhD)?pFarX8Cm+5 ztk5_}#7;sta2W)iDbl}iNsi0ZpsMBJ%||=IM8O?q{OsNECU8`;y$FW4Wp|jl$EW9R zLT+63g1?Dl=D)*yGLJKO{51iIpeI{q7>B{v0g*GDR(I&JIVIMn@2I|RMie;zB^x|Q zf^`5%$ID8(y%ax^@NRDn30dndu*P|Dfy3VDpy3G`bvQ%UGFk&e7Ost6vy@>G*{DL>#%rElz z&5t%R2Q~KPV^VgVH%~M04va;L%rTZtrS_tVYOMhO9*hS~}VrN62o5>_*5z zh8#plKSLlH2@d^_QD*sJe7g|tj#cL{%8kSxCiVb!FmvYxLrb`W&^AiG;;pcbOUIE9 z_}}0MqBZL=I>JMFdKp)h@iaMsDIQ7NFBOmE*585+Vm!@+y4j|jlsuy$%n&dR)7X9L zesK`|edd7Av;bxR+qw&iXNW_l$j;WbmNUeNiet8Qs4sEMw$=EudHbrdNGM@Xlkbyi z?EYV<#%|bjrmH+*^K-zWWOI}JoF5}D#m~`yMSc!7EvqgxJwY|*FoT?E662gepDy!z z3{#w*@*ZgL!nRc2V@NzeLCz26zOEal^0tw0V}~ejo1iO|MtR$a7wk03+vWmYXNM?n zo7)Ld-nL>VM0wjhPKffhl{g{F+g9d;C~sSZ6QaCrUMEC(+jJ*HdE0875an&FbwZT4 ztyluOk5an&#=Y%M4+d(HpdD|=}M0wl#oe<@1 zJLZHaZyT|Aa=wVSE#C=I-Zr-rqP%UzPKffhd7KdCZ7Xp?l(((S2~pm*3MWK)+q_PQ z^0w(ti1N18I3dd0R_lZ)Z(E%cqP%VOPKffhH8>&SRaY5Uj1fi{Q93peGwh=iiI|T* zWZ0Eu8=vAf9Gg`p@`5&&*WB0;48i<@?gJ};oPq6qs}-^jti?BQy)Uj%ePB1ff$4n* z6`~LH;~RJ$H!c4u8zHts?uGaKLH5Eb*j``5Rziax_QEHAr1nCfAnt|74%vI*R&w&^ z%NGnv%kF7?a)^7OrXK^k5=2X`e40Rca^tgIs2lX*@k}i5)a_-i-hYoBPggFCG)n#; z`Z%$h!OahMQbRTJfdqKpQ3zS+KOlW#$E^UmV(!&Mjl-fvQuqSmq& z-3~mLRHh!-m=sP)yYDccUxo_I?#aB4{*ud8Gva57#0OAq#W(9~v&`3;{>bMZ3%?#T zxA5i;q8AwKOG^S~Ar`87SJqnZ4ngeg%Hmk=MUcwx#JlR&QCC4Lv5BJR-{H*ZaayiVzpX5U`={%n{^~$DPdDG{ zgVvxN2;op47KLzbs|Xrn`ylQUDA~9It?r47a`-1A(D1hX2s#u3Oh z4hQt)^?vgWzxj^uC?w2ZCb+9(5G*&Z0NDLm#{!0b#IaeiT*x6^Q5=lrZb2q=?^0-u z&V|ZiMDl}?mz%l$Rk4Lx0V6j*5betfKO9DVXVn`M1`Gt1avZ358J z;B8LhOlo}%1b7wf$o#7hOZpqUc>IuwpGPKh)U%Ir&>G)K6rJ=o$Lkm=kv$@?ghUvC z2drxk134L`AgL=D33&)W@0NPxV;U`k+yLKU94B&7DTL9dz^yG*y9CkH;g-+xg_-~f2f z795~>h`9v8zK&nwZY*HF8ZckB7F>|y>Yah}F$|RCEc9sWs@9)(&6;<@hJj zBlm2$MZ~T&|30J|vG6>|BhUB+RLfktW(uxzOAZnlhsQ^EKnkk+D3U-k*aQ>_b!9Ww zlb$>!7z?jQFM|J)NECIx#pEGqdio$M{61rXIY$wBQljW5D(cjLxie8T0UwyUs<_=i z3%+I3`f~h`f^JQO&qk;Ay$C*G$6BW^KP}5~sT25jksR$i(u>PMfICstf)$N6=0tbo zBK*&(@HSvs2-2g#UXg{9+Y;itk7(4?p>#yyy;3UqRE32ngBd<-i;( zx++!tC`k@m8?mBuQ-Q}YTZuHZjeRh0Uvzb<@OM)U)3{+`U-OtsRO$BaMkI9?mrL_3oXGF}E_(5>U%{SiEWv%?pnXZ>ClfUZUp#3#X z9D^tXA|Ab*_j^Ov@#z)b$9XG4*^~pz3jfs{_4Gs2vEMXgVX$wce+KEjXgiQM9m}CyW=-BWe25zAk_6ytn-``3z%gWa8I&;P_lqTHydql+=(qZ)CNUA&C;5E$PrCsg*62b za!i%p^7?%Dw+Y(C_D5N&hvGD zh2QJa+TTNYO^4(iEa#I8P%R;lJzCoj@refD0|dAi1ByqW1aN_L^akBrQmj`NR)lNJ zX4WxT3dxD<=EdEXww5HuF5T?6a_NQ5x4X#KP#!)Gqb& zyy!O|vuWu0*YX8MF`$X=8?|UigXK53fcbb3^Db!A@AI4g6*L-l`(xD*PigG&n}>t6 z75i7`&35?m=*E`-rP44udfz0zlaAe#t8c{3i;I7J+Hb&k`gITp+7=qt?HbQO2*L+S z_lN(~`%`YGT&?vuGnj!oimlh14^*H&5rcyyNI5EP8HOp2glkw#VN8xlodLwdYhane)B#TMoPvdbAYkch?) zK=4^>U&U6hf=b5hlA~0~*nAos(GjPc4@s|e(ZYZ!=-PzFV(Fcv8&`rN+zf&g*eDz1 zR1QSV!T9P&)BLeOR_{|psy5Juf|wMvVi4RQ{*)E&lOnFj>iwo>QNe0iC{7NerIR zKy0t55xB@amgtEd%hB53!n^@#{Ty1U+FI3mBoMpb3klsS^ACQ_|DMl$)o(mGiNLjH zjH6W)i<7jry7jQofLhfSuvbSlC9v~e0-Xlqvxi48D+uzP$fL@uMR_RfW1soDAJmqY zh4qhRVY2pWAYSDZrY(C|Mp7AN6|*hWTU`-|J;Gxc1HR6HvT9P>S&;rIkq4Z9o=Lr) zMA7%(;Mi-+0w^YE!xZN%^%fbYtyVm`yI11oq94%fUW!TldJq`7rnu*@>c zEG#+F=?oRh=-Vu<^v%m- z7k}T}aYbz0O3}jSH@iN5`qmZf*s$(wweB{nm*IWpmcBfDnf!JVpGOlCwSH{K94Ei2 z2A}psYwUOX79an)5viL$oJ1`R5N6~CehhVED7BUdJOT3&4m)r5tY+Tv3kKvNyE&!o7ln`hF2GvdZIq z-wB$+WiC&kqB3Y$hg0H*)?)K@7&PKmX703pJ13Foo0O3fNthDJs52T~kF~Cr)JNlK zY}!cybC^C4=k}JJY#Yw6YHsqH1>M1dm8%!Ii6P10yP3N9rlFyQ_!GEcwCsOkfhc{; zbLd5(sbJR>Oeef3(c1SSi$3ptz@#@HNQMMzk#v-GqGGHFp-{Rc^^-^qP#+$K#XfJd zz-;$`f>{q-ff*FM=iNPR8WzxYD#71}Ld`dLVamqgqz!Kgy$V{^N-Sq8rk0e*KS z54u~Zo0<-ud0KC!6nl_meA!-)uhYtfG7IQ$0{wbiu@=KOP#SG;f&yl5f)-@Fp@#hYoza7ZWk}TeSsm!us01cpBJg<>T?Uwr+ED zAS--M%ii!f*j7ZVGxMUG;gODTd}d_&;`o2KI~Vwn1nEHNAc0teqXKhZCh`(FAKKnBoPuoFhEtT zFSM_jPObQYfRDNVwfC9H3`DEn*ZckMy~*#)IcJ~!Tzl`e*Is))T>Mg;IWMc!tQwbJ zSy>wctI&Hmi(tTmR1d?btH*cSc%K2lVN}oDH$etq`-VOQm68}_u#~)7; zR=_8Gkuw!3@*&*T_`>HHF2)9`gVT0aoXo_PV_WG~t$eLHQUUh2Q-vB|4#}XIT=+U| zmBmkHzU7ZDuhjYYE$@M3VeMuw9+0D>w*6XIC%@3F6BdGP@oOf!tdrzz8j>!45lg3F zwhC7>fCESCk=@pVBT#5hjorI#s;6Oh=mP7(^Yc<;|GrhzsaW_vf0z@!d{}DiZWA(A z_9Gei_2|HmX>73I?1s>2Co1Vr;)5L-4nj`jNl`3MO2x3n*m4Qh4YUTDDuoSqU7aWRH^_D>INFIsWHlC|81i_FqsAnwn$(<9N!Qgf z!A*y)BFy71mvlbuXmvD|3W+hcL*OmNPkUCj`VTTVcU-wP6?;TaRc!HvOL@vvq@0Re zPlhjGD67t|hNbtH;fJI?(1(KIvrMOk3UQm7EW-<`eD~p%<-upIrWgF`KlTvOAJH~e zwQq((9B?Pg0!m55Km#h3Zo~l-QR07aL?JiGQR074#E3SX2)Pw3_No4W@(Ac=Xwb!4 zPB^TkfLyl}SX&*?@vsvx{jH8Py*# zzshDACb|{pY1)s;*8Z%FLPn6xIUMSOZ&b|-osw9x#vg4JkO(}KY#^+r=YtiQ_6bM93_L!CSe=;Rkv-&)HZ>($>14Dy z`Eh?#!U4fm_<~b28`I$GI%inUIdKnm#mK8LXi2@>%kHPp&+d=qurP>m- zJkB$ZR>ulz5{2Mse3OdL^DO-EK%RPvg_MDRDHW0<<_@b z>Wj=BR?noq1tY0%W%J!2S^;avFMzW8RH@n|vl`tp(;*|0`7lQb0+3z-+HD#9akf9I zb54)IekuOATzG3l?vBTPDSwQ(Hl@v8HQQizoIKH0Dwc$fa?30Q$;6uPWapZxj6n~X z%6u-}A3iaKASNkJ9;z~BYlkZTf(i=PC@7XwxGBRF{$s2Sf;QAs1_8}Vmxm4WXlZW% z8-p7ENKg1m`ee0OBR%0~KFjj>JhRT=A9d>>`k^a8ELpg{QXFCn10F{)S@_)xFR0Sx zk~`|5YBGjE-Hi#C#ULEEbgyw3mI|H4-ma<@So(#~xYMZVmGlb5lN!5dBTTVAVH%Cq zd_p1wmQ!wHoJ@K1_n~H;T%>yvWO@*uPWv46Au*}*H$z| z9q?{>zZ5KaXu=J4UA1hs-O332t}@=m_)Qd&XX_hzNhBM$#qZ~AUFi930I;2-_l+`b z$(i{UelPf0(5+Jpc(~3&U?UPOaRWdU)EH{$_U|B4zFYDv!)Y|r=q<~$Z zvy>bpODyFIr%3W*91v)j_EdLqzEGmnC0$0o)PA<9Xvg?WMdwq|`*g!K<}sCn;~-m_ zYO#KlUC&1$b4@+PNVz!t%c`i9%<(ju&>j`03wm-gNuAI(j zZ$Evhq(wFW7qGy4d`v|4@fxd{l4WN@}Z#6 zB~XMu$>Nvk^R(|N=L*u_3$C79_F zh+J3W`@JOLZ)G6zIXu$uB{k#!Ah&Ac8bm$sRZoHrtoF|_$KVAWw`bCs%-=IMyg4A7 zqjp`8qo69c_>D>C_$_&60$xlCJN!1DgPIz4TOG4_#S~%_as+mCW-2@|#_B|Xgsj`%~65}wx?do76Ny1>IKEt>UxTm&}2F(Gt+=;1F#TF3dvdxWl!)#}lSK!+j0Dni~sz5nqk8gx3q| zR)lv}@Q^JMTU zU$jw-JifbZiXZ!29AU{ZMC1GL_v}DVtDepTw#l?}*2^s6 zZzTaT``}k=zxUiDf;ybYx0aZj40Qw~Wt>X_J}fsMTDkSM$WkM9UdaB(QY#A@H@k-P9a0UkJ0gGM!qH1d<}>rr7sAW-)J&mRyxv9V7A&a!08^;keHR0KAPGGI$!GzPL^I z#X|yD{^*O_hVF|t(-&=r^@X`Qhs;VK?m!EaFH8etlw@YfC!( z*nDBz%K2O5+f}WU8^7c#85z6b)Z(X(0noZ|K@2k~jZ6gNWf%%e3~VC^IFWb22jxPM>=((muEypje-`>^SPD~zMLew zI-PZ_UVCAf9wd^~Xgeloqqpt{RqM!2wwtYSoh_k$)e+xKj?s&%9MS!&u{X#h(`tY$Bw}8p zGJer?GhObGRN^8sY6y9m{f% zYMz`aw@Ub6&m)}moR$wrzMMUJ%z3D>A86!r(CyJ8I-D)XL|A5yDv!;Hj*kiMsEa>> z%n{vmrJ{OS_p}|n08lSGb-LWFb{1IA^gr;k z?2|$>j(%sHrWxDf+;P90da3r=#P9iBD86#0|5zf5Ba`;L_;?fX58QP`TU}b2xQz(E zV}bJ|I{9fkxR64cE7}fT&3$P}bk!Z?5+0~thLNM)$*ZEPN|<2Alc@;hw&&e-oXK@9 zcb#incS@2RoV#qCu3y~*6QPE?TkLbm391M3&d9xw5~{D%6fnH)Pg)$@wZd#STv};$ zib9u9g{o_JiWK?ry!q88_#3R6Z86e{gOQAXzLT9rdUdi@dz(<4keX)?$7xqMRbYja z#GVuJzxyJh7Xoru5PnzlFAXvMgA!ar*9RrW5w~;Dwy8Z@7s5k!3 zqarRi+)uc74YSlAZFM1_eBiLgCB1F=r8U=eFg9yzw&xY856frL)<;zwmu{d>~e zszXLb8VIoxfG`ivz;LJ-pSrlh8!f+^@1CaUoP0a#OW|cR&z})EFX)~VDcBO_Vk9e-}5>9-vBu`Qques$xI^}u#i z=pGda57J}dCm8)V-YT2q%K*)-USXXC?#CaEUQB)JNwM7PiGLpnTNj)Uk|E;cxB4S1 zp{Y{A(Z0yJSmyFa&ho2NLI9@iblrFlA&%NFfl_VVhLvs`9LhbU9n``xj&=nC;z<>1 z;V^vRRRLtu5s9UeR8A9G# z?15H3BU2BYmTNdckQRyel{fI8aSwI(M_@I;NxAgLe)V=7W9u*_^?1FQN(oYD6%Z0; zS09kgGGf*r{zg98S35Wo^AB7ysjV90SuQM-i* zawbn58?j+K^%!!4U_5Wb7k+E4`ZHS~ue$M@Go$0rMJfzwCxCvBKpPF#i*L1!7ZfjR zVYMy(!(ydk4m*D7S(*HACV!nwrrV{r`np7JU~Wa+`+J$UbF0aQlb&7)kJk_edTvrr zcOIGj0f^8rdnd)NpbBx?gkxeunT?;%LY>`cL1H4|!&6k!RRZMV{-p zYPiO7d2-xX{$Ki%S1_!=2v=oQaG2|k6KSi00{xO#kk1p(wDlXbt%NJxUfot9RPwU2 z_$ZIV@+Eiuqm#L%f0QhSh?_supY+ds=^OViEmxL%|KP7#aV28b>xX;HPITzA)Nh4b zzki)uc4`sbIy{BM$PiO{|A0D?(Wrx*+6_4+6V6eE$%Sch%A-13NhP$Dx?50D?M~3b zHJI5Js%kNGRFhe!Y$Gb5x*(+1=rvZ@h4av|i%sx?F4zaKr7;ATmn<4N-&C(dZ6OTH zLfn|QjH#cIK}XV4yEEN8Q6FN3zSe{kh|$hVwtylAoo$wl3SOF(uyK@0Si>DZs3BX< zzxI}fikj3w?at&`SyB7Pny4}E;xe_kN!?gRoFfOz;;m4un7@Y!bJ;&t0v_ACAG3!) zsH)(3Mzo;bZfGjAI!{9yEC6xfi;gEILgY;i1Gt$hY{W801>ZEWQ_6!sI{7a}r*ovp zf+B=xLD~Zy?&R8ySHj>F*q5nbt<+UZ%v<;OR0_z1Y%^w55&^^*nrB57L4&XcsH&KmLrQh z20k0C9%{C2k5q4u5Px084No=0+l7B5G7=CkWAvI6bJ$qUH(dPa#jWn5!$>h}PJbzn zmGMMPrZTdovDmam&puPgM3$I6Lh;G6v+XyTWoMm`j}Pm2hNJBB=G(u>6Tvu=(`6gu ze;r)Lgq)Eb%yKOl9OjKhi;UNq1#N3QNJfXyk(H$k-%9AnluJiK!Y!7g|M{st#!4^H zO0k1VD=rpv3w5QosD>l|!g7o16dc|}NYb&T;Q#y%E8Rotsv zAOmZ;CQ)O23;42C!xAYqy~{>X|noqCq0 zQ*lM|o<2^}bZW3_zCUuNqu!IyJLzC)nAP4XPX>`m1#*a0#D>W?hg#hv_S+AoR?$om zcT?<@iA;5y#KtJY*QKiS;sL6w>!@ebAkliV)IIzjMC-XO(fX^4rDqM%x}G`rf0Ag; zAy|tYwq2mF`B@Yzr?f({TBl}6)*GM~UCLCZTbeSxNXEUE31lc0?2z8fC1Pj24-u;e z*JKSo0h$0$2w9QQj?c$+n~Qx4C>FwQEhy?PH_}t_>eDjc{|ps|dK^Rc;=7zM6=CFF z${UP@2%Z-8c8US-Zl|pK18ba!oVm`dro<(wF4n6hka)5M6Y7{-gTKmat@?s4H;p}N zW6+@B4Zc^#e_ER<{d2l>roEZJiBAhnsL9d9T=^8a0kZK1$VOD^P%@q=pGEH9tR%v= zk<|q{*Z9Brn%*ADdTh3b`YfFq7GHSrCH6%u)%P-F)4YyY)3nVj#bzgu;x8`i>BJfv z^*pn}B9X^(;74Z7iJtO>Ja_$J`9eaYoMmN|@S&8y!{hqJMR;+QrUhgxT9GC8f-~RE z;Ja8U`Y7A&6n-3gn%6gB6{>wE1)#C54~he7Bywr8n_ox1{>Xh*cX4+V%=!ED249qh zWnmI)KupNr8*u`SBcSfB9gF#2st73kil*ZXDU3h5y(;gM|212_s z)H7U#g@TzZToB!cP$(;;x4mi)UuA97AFYmC1Si63Y=VdZ4p#e(1o#<1(Qd}@b}8r4pPU95MHjk=DV17s|*m^U};`Zy6c49=bPV5<=1YqS?;1ioT0 zCLQ%nsW#Gh!K*W8BOIvA1_Km{R3!UXk8E~k&}VF8XMNB5_)$6+9wfofe zWJzl5&%Yzb z1fz@t<9p9BuEL@0&t0Pkkrw#ec3z~VGHnc@SC1X43~p;dV4veev`o$n`RFN+yi-d{82Nf$Jx|M=D*FEdzt)HqVO*4 zf?D*N(iq5KssMb0PhAPW^BiF=ZX7Ql{@th2{DQIHP7_uxzko=Zs9Nx|lMtPp>JnAK zLU=yO0zcz~i)m!|1>*5-9n~;8Uu$_n4N8!?z2LG-F^#?{=QVq~Hl#f+pW2HQvOe>H z0aG_2SX3KJ{=^JPsmvt6h2(u~mL?#@u#5@v!Vfh)eF_ zu3g~+3zqrN;Iwyv03U20x%QMI(b-(XP3vq%+vQ@ri>NrOq{zW!__6qV)&o+-kW?!y*MKay zI&UQo$P`iWenVRM)%bp&3dbc}7UZu&d}dbXE3#H+7On?MtUJ58uj3vY*&l53B2{e| zcuUW8Gil2276}OB6V8wPwD@@PsXTTi-LCAE>^p(2xO3jZe#wX)SRHeOKxMVRv&WoP z78^kXca%07<0RpKK&p#lR58!PHs4ko#nU0lr!7-=l47?R|}9 zdBIbC%F!y$A8W0z3Jq_)F0U$taSmrOwJZ}|ha=RSg78c4Fh&{~tK~-9;R*ygP3{F< z$p?{>MN@gy)>Ya@YmHcCa5#ukHk?5+QBQQm5pC_R1aCl}Hx}FL4~!;?rscvsoJY$JvU#HkLLM8p{1dC9qZdxoO!OGd4*qIc`rC{jFwfkn2)dc5g-A&qW zvm4K|TL+c~hx1z#I!#mxq&?N?{WIr&H4I0Q|0o4kJVtI>ECE_#KeQ)HjFm#N#aNjS zT8uTSI>%E(&4G~PTp3>41h4iJfMimrB>ZTlw4tRKt&Y|A!I6;tV>eP#DlW$-_qrjC zf}(ZEHwZygH@r2)%=)7hK2q06i%>i2^xgjYFV_X(&n~U=J<8}<$pzj$)67?Gj6lY$ z@zY5kXd4IyfcxySOp*^WhOHFs&w}WTi}oi-uBUZG9e7A|A}U=!)%Oc_KzT`rNxx0hl%Mm-F|ZrS3DEH zpP61btd;+s@miLt&r#GzSAY(pZ@P?;w+~4sH9@Au^RmHg7uOHM zby?zMOrfct>+!cSy#uN&#KsBH)TkHE)3i74XtXJ^+B-DqJ($vv;FJ97t2IoJP+>s5 zl{`swjnlTs{MaJ%MUFa@@b3Ou5tZ0W8mnE7ChgWMp}fPJQ*D2d6~@;)obF9o54}?E z>z$>|k%2rTUoLAZ>Ec!iVP*Hu(h?@V-qlih`3pq8T)|aM3?%QqTt`w(f%ER?d7fm+ z^L(x)d|w`j{JfQ9@#7HFkS<<68H;4Ldc}^+S|a{!F-+!*%v$amCi6vBOYGzYLi%kP zBhZNjH0gJ4YV5JMPo+JYx}K`3>on>2x$i>y^@1riiLA+ML;eLKAu1VyN`0l{6=PH( zyrK-g;>M*_J`r$MF}Bfoq~9oMjV&{MzKr(Qtg`0k!Ye9u`6 zE1RF=l-#S9HgfvNlk5V93xh|<(3OZJE`vUvRV-&(vQhI#*r@S=^&jGCma!`$^tx={ zW><>PyXhdu?VR{StdeTf1O7BAJo2{8ZX@^T?1FW|UxXAkTaEP5S&02bsLl?rY)pkF zH$|2;hR?4aj`fDDk;aY(?VY0>H7?<2a6c?;&*a#L^|{^=L@%J{T)S!7g0QRtW}S9T z3!7C>vvCJk?zQ%`B2Qgyk!SAdF5M^KX1o6({{G8k;73Ym>XY*;%XkH<85yA$C@Zvv zYg5xU+jY@<*d10N((*bkZ)ADqOg^%Feq{L)0@+!wZzX#CL?*B{MYw#j&8+vT z6qDYs{_11WJ4||C+8Uvm^pJ+z<4@woNbYwxnsb{qU!bB|v_bQ?P`e1Y&EB3C{t{Lt zbGT2mnm3^yDwNbrQc+AbVt%Sjr-VVotXwsq+u;gsuF|X-Ex0L>v!nXLy-e3tnk0<0 z$xW@Q<2TYKzkHb|w@91Z)T;UVi~Oop3-q)6s#RC$XZcmDgqV!9$*-EhJcsFAV675| znNpT}OcY9t@}?22~ggfNNmaWe3pfb|X;sQHf$-Q(w-h&kg#?$q2}5zpKn z|5k~aJD-~_ck@Noy$Ost(xXL$l;oUh&8xXc*hUw@A##TodojMb!;6k!#BFmT*B3jH zPsrG8jGsOJ@UDjCxG(s5NNh*|x4*|y2Q{i>R=U5xaMSzr_kG{`DE+-WY|cS>D79ID&>{ubqTex|B_tslF^-mZS!u1hyPtf9?V?sr73tPO&Q!wh03XK8fde@-W zh5?KC{wE0^E3Y*u#nYB*!AJ3$7Y)`G(|d3}ydwwX2ubvS1;8f=N!ZRVbS3W)xsNt+)nZB6h{m6|&k# zlGNAHXSIv;h2Go)eu49AiL*5V z81AiWBslWG5^ny;y?2?nd*#;K`T#d6i|@jBvs+i4c6cJ|dfj-D^$E_>JeA#Dv*8b_7B2S#_ zRj&8Ajy|`@Gm7gNt}ktziiQ;-KU7%A)Bgp3)am{H0NVS1e4j+aT~3?1HF6Xv z=6V(~^Ev+8*Cx&|AYoq9hklKrkq^^7o`h(-#rK?^=J32CUB_^`<#*{F@3VxcOG-t; zMFtGhUl7H7`}YOIYTD%#?=C`xjWo}2fbSxYq)o7X?1pR=r-s2RV+8r_D47o-U4dw#To0NSI06<12nIj5I@+ zHD<}I$hT=@O&ynyfXS+75W66^pP+x{$)cfg0P|_S2-Y;l??2^T))-cig|?g}n|;-m z-0^fFgNd~GYu%jVuhozF0p$H}t`f+}8B(6CMxVvpSs8|O03r{*GR;1{(r2yMVT}em zTcf4edjTn1?kZf^uS1SrICC{(RZwzrq8BX0lX?sU7mtlD)=ONrNqNIRXWUiDC`WPN z`sJkg%yQJw804X`^sjUf=VC(iEs;81E_FiLOlfbiJev}AUF1~R$tqLq_AC}-Yc=s1 zluj)jv2qqTv$Wp!b8J{0H)Srn$<3RJlpTM35=*^R*|*@q{^_5F<7y$JrZb=E^3u%h%AQ zO=x+o*}IU^;&=vf;%xtvE&eH8zGwl)gJQvI7JqFVeBz*S@IPS>-2R;y2FF&*n$ZHW z;vUk5Mr1y0%46;AF<)%eEg9!~*8n+*>eh!*M1N}mW@GX|n9 zlkgu$YEzjB8RWurUCmvMI{Iu4Xow%}i{YA9Y(?EQ4=QKbxg41|JV0(Z(NdpiwAVQG zU+XJ&q9^x-IGWfNzsxUGeTV^YBP$kW;hMNfw8%M0>gZHQ%b%wd&`KG<@xR>#Z63j( zI7d&e7p37>+K~xHbp=ErCr+$n4#UzlA|>OcOplixdw}?12Dl zofMw2Am0cp!5yv#mtwe{OJX`X=nwTAws$hKd={!;Xn+PZYR7cd3<(OK0TY)8MLL%yWh zt3&}g6tb<7&dohelzEi?gB}M@RbybfcLq33)-an!y(YxDoYlYc>-RKgAS$aLbpxJ^ zkJ?oIipr%6;O{x=Jo@0|cO@wY4X8`qE~}?DIU>M`k8?AaAsI+y6KPLQq`==A^-lfOrPk`bB$V!)Z}v~BrL^InEhDhs?2i^Cl4w=L z0*d|kEv6O-0Kd2NhwVJ2950TP9agYXzIT~ty%mvn@pdS?A#b!`rC#`Ktn?*B)YA<;cQAC7 zq{R}fW)&osNgT~=qnyMSQ~{olk&a9?fO;9=k?u0Siiz)l-G9>LH#N#Ca(t)U(l~3 z&FlWeCD~u!NzB%-GJ%Oakf_tIZdR$piP>onCXUswv{)j)mng|j`<5oX?e$nZl&`NR zg!Bf8=h_>jDv1}&D=^isPw;B5cMHl-#PqA%z+s7B=vQH0lT}{gd-`>(d3_^shkkWi z^j@M}zq(C$ClS)GN0`V56Ibe2IHQu)zJ!>#%2e_|!qKm?#_@F^A%-UG_2uUE&BRIi zwZgpaO^nm8Bh2gD39%BG$?C0yU^08XThQx?f9hAaMQnGF>4}NF}c`F{zs;d96_$U_Odwz@CX_SfU9a zuZ>3Cz{bq9jR+`uu)WE%4@)5Ven5f}J-S7BLiMS+WlUK$v(mP_eH?>F=9cl)6(Il{ zY8~H^dSb%dB7*By!)dwE8=_hX*xQn=2j9cixa^tUo7zCT;nl1Chq>*^A{toZ8V%*(>M#l=F&Oyv+#=6# zf01W2*JQ5KxIV>oEtk!816PFW>s;UC`ZZUK>j|#sxsqH5xV{}I@?606Gp>iYHghfH zTEX=dt|-@TuBXo{^8A(SEv~=uzK^Tm{36c@T&Hn0avjNaKG$VjNAtay>vXPt?Pmb6w80fvcRWkZT&(B(58|Y_54+eO%X)-`}{dA=GO=(s9oa zkw3&y)W3*wh>}x5VczgO!wAVM&ioA@K4Qd(kt0Wzl$4Z~jvAF$T6#nthGs@%JE(XJ zfBNUha-Pi3k;P-i9(827{2pC#%&~IG^Em#>%a0sCru?Ym$|uNg#l&MP<&tN)B>Z^( z%FD->A2*@=xbovpIDzNm$|p{mIH|n6YVzdr$;VZlz+ZX!$3C7{&TDn`iFtV^O__3X z<0+?1J+IO=sXhH;r=M1HM$Ktwo^e*)X=k2E_^DG*tEoS0>S^+Q+SF5OYCdu5 zDFjZfAJuSnLqo%;(&>%=&cAcgf9GcYPCDsq**|gYqe)A{IK?YwL`!tB7lhc9xhvE} zo%&LlP+5%)aZPlxyD>zkM2P?G4Iw&bSHSCzep83M^}5+`8lv+nWo)?3W`eBb*x^Sc zQ+;lY6oA^(nX(v-!C!cZ_vPLwI=Rxb@m)g;`v@(8?R#!=0 zL(rf;e!1j(`h1=5$=r0l#L(*a1E}N6_dl5LkEg%uRw_5Z7GYBg>AdRBXNTRn8~{{yS$}Z{af+FMGJJker`kJhd0glf26KRC4UH(Bk~ZT)`)KS=)!=Su$#J@-ENYgQVGnDzSM9xJv>4P%UC#q@zERg>WZ|_H+3>(utWL8TD?Hli$z@yzbSn@*6rbyusu-Qgpm`G*d@m?XP|5QuZp8pWS=e zFX?dd_}AT#6GP%>r%Au-FnxYt`oga^i!+V#=|85SR_6~WDR@$- zU6|c7Qj0=%)*AFS)w7`nmqe^&*$>&~^L5v9E^* zEUUB6w65cvfQt++^=hMzs}2jt;~Jx&rQ27_v^yk*T&q} zy^h2kQrTN*f zp4?Xe+uf7NxSWhbKORh5mKzy3XGK0+YEdnU_0cMHU?T)XJ=MV{YtCAh8zLg#S3UsyVh#FIGkZv3m;R<%bqQwt6FtrPPJ zamuU{g_l>|SZSRo?7eEIhL9TFIX{7iOXrOGw&|R8UvxW1R-Jh`1G@$pow>#QuoRq% z#qO_F)!_OMY{@Af&$40uY!9Cs@l(84UgaY zxHWqR=cziKCLeS2$tQMW@zN4gL^^kq`ANv_Sk+ze{+&Aeaaq|9owH7!Zb=Q%OUT_R zZuuUM(w@GSr)zg2NhF2NEIu?3B3+nndAAi7b0h>gQkN|)-{H};txKmPm$}7RP18#M z#5s~{1ooD9Tz^jJB%W=OPwl^cT<92HJ}WP~uRkJ$(}$_gTtD1uFQgD1yDW4B5oSsR zyZHKH!Aqsor3DmILby-rB_B@}gUeDh@1_-iPM~Z6482h2)Y~A_%C z+j=bUu7?8bk3m?GRaUz@o5A4(3AAzriQ__6zzJ5~ZcN0KOVVR2UF8M1RR^niJE2Kmho>N8Q?KEc7hIW8}Bmi}uM4#ub6 zpg8MiVw;+8uxAh{s-KBzYTn?}aPiIRL_s!{xK&4|ksAJL9-!J{-CQdrQAxk}Edfxs zo}dHfmHF#0tgu#<>$lI6b7O@c8|a<+re>idi5xlt|4RsENFzQ*?g1neJB}xU2SyR=OCbWuRnN-{d9?pQ9uVwmm|3R#OPVz< zHVL0mg4al0M(PTy^IDUdw?3=$9(j?IkMM0$GAc2EB%Qo0JNaObn|#8P2lHt*t|&7l znR>3yH!*ZQJ4MPH* zvtACzdNixCXT6-};S5m!$^m1KK1g)ws!x!~30$XhP35ZQ8qZb6)yQ=e*DNki-iQ&y z@<)s)D9pV$1K=-@vw-}f5hDtVb1w;(F#R`tMA3+1{@?$PymKNH7Y{Ekq+l}P$}2=1 z6O(Sk3JW}h7Z)R(neTp2=Shm9#|Pnew7~B^+Ptg@_&s)~f#15THT+t+8Tg@?4^*&# z!0&PTm;D{jmHPL1{dd2fv%9h;quR4;qam&-i8k;m?{a=pY-;_RK-KMe3F9YyZq}P$zJGX{KFLf z_ztKHMwh4TTC*FCU*l5By;5tB0gwBv!Q(z_fVt0=0v`8SgUx+5z!L!XN?tB#)6Wt! z{VV`>pV$7D8uV~I!SxlcPOclc?%=wI>t|fgat;3Jt&cw362pH({)~Ig9v-RX9$0h>;E5^7?5P} zQ#khC^bAlww$@;$f+ZR#?|dZ}DAJqkMgB?fn_T|}n3ygzotp02^j*GXKM&EpLj*|* z{ythl5B@52}{Tfa<^w5wpSo^Lx|vY&=y~&&FmA-x_Xu(BT?L&d)fk z)ARQpdw;BzWfJ8N3NoLfZ5YIOo%!uS*zE?^6tdhD9+Z-5Zg{ zTDWZN3_g!pY(6i{e3slA4ZG1=eTw8JMK7T}B3uTq%8U;haU_j^BZkwCO&CJ{lF4w` zZj<5TnGC}N3$4yS10^YMm_Mki*^*+^E0 z#ruGObTwQsanlGMeH!fHs$U2y!s2aOs3QS+RoAe$Wdx_{_NAgcq4@!bZs`{}wd81i z?1Y;JwBAgO+Qi%s$Nrbde4r_Ub*%8fC#_EL7AJ(-u=&?%7Wk@p+_mdDTWguw>bbVR z%CWz-dIXU1qq*%@*H>ie6Q~}4bo@qv)m&9xi(lB_7?BM|v$SMqvdDG47%iv`sPawv zt51Io$k%{z%y_;U-{5|Fn}mUqXXVp>iZV+;mG-)y#O-GQx1W5{ereTBeH0o{I5=G; zPYr#x5<}peeki&5tr^{ZYxd3t6rgwbtQork*6gkD-{qT0%O-Wz6aZj#YFR{+jjbX& zH@;c=+o!1pDn>6@t44!Sf$5etocV?-MgR460}~vC@jzW}tX_-BZOj*Ll8U1ZEr$RK z{meFb@G1oB*p&X3$X4fUNo$M*&V-T^Ck0)Jv3C2`(9yoM?}F^$;8C>iamfZFIXAaR z9=D23Eslqx|1qG8?{cCK$pH3gX+7EM1=L#k-zAo$ zG_2RiuUCNm2oK9j%~{b;65?)C?|Bpdi*Vc&cHG2$+GZ_UewyFtqz4*A`O*^_%P4J= zw$*9nbSys7f~~mFYu_Bid1g=Y8b@K~jXE6Rt2aq5bQ)s86Mf+gl0ho?NBJ5&M(OI% zBND3C>b~C6{PAVKvmPv>jEI!+iLU0Omi-ii^xlTQwv49BpI$wXN}ND_nQh|xM`WK+ zmAb+xG*oMw4`$-6tyo&*DOxT#Msi9|Y9_P$H;4h`qZ`4!4SpNy$GpJR^`~59FZFP=YVKC^f~pPt_k8k z?E=)ncLpmRyxXVEr#O*MXIn5-e{>?l98_goj)|}Op|#W-BXfpRk@ylE3gpj_?fjDH zY?0S9YSb|l+p&51g_@y^{a;<`04$kcLyjfD-z-4wxmP#})M~c2RWe4K0=yhPRfhlU zL@r15<&Yrsp)ST61!{-3x@!#?1Qep}8euAq>R!-dOSZ8?8W1h5gtuXL&|=<*%7(UN zy5Q0t^~r0(2Md~UWVYQ9YC=aX9AR~&$kBCE!Wiz@%WL>xVKWw2VMzwX(-zfh68A)i z!ZnHBkANkhzJh#PK=479zuoeYb5+4fYK@$l*54$*R)?IJ`IOi@38A-L@Cjdi!8GG7 z&o-!68%ujxkTB+}kH9wd1z1<4^0(l)C>z9?Lq?b zwQ^W!ge|-4nsLc5%Vz?zJ`*|f`8fH!r!aIZ{x*XB=Cn3yn-rg>bM(HoQDtJ~vp<$#htsc~WroYf& z>7ggObNlIW_>uq?h&Df~E-quXObZ~@C|FWVYNhR^&54%k)eu|RBj(f>jJ7)N&W??|OTpvKy^ zr>OKww|Ft`A@{iN#8gVOc8&GhPm?7^Cge+WPG0yxp%tD=P;H74^93C4$Ojr_l*TBt z(b)U-i_M_96&hJZ3ua@ftSi3u44Jq@N%dkFkkgNiu;Y1cc&~X2v$aNy4BbU`ZgE~$ z!PaCrS;o7tkxD`nFsghv@u*NL&l{~)-M!w9Y6(cJV5h9QafZ-QooMFS^z|`Thmh0) zFLR`6=i|dg+@DZ7g9KK+7<->W0!JB-D5g-?Xo762J?;qPDKi3jc1K`nj2&%d>uQ8! ztj-dh)z6ld3QNIGlI`=)FWpe4ig(=a~2y*H5jb z+INC}USghuX9#Swn}XZk(r3(=ciUvOFCZ@&ZVAAi5I>S;D9P@+6#`gn=;@FL_7Jj` zkk3kp=xBH<(}lavA%Z@AW}@aHS}Z<%WnR5YY@A3{YwmeQ-p1)|GWH9i*A{1{ikTpP zPHagR&{%49{7UyorWw(KJM#M-RX$WpMDb{FCh7vy_~`>i_lKU31JiQnW1ROP=cC?U z$b8)M1|X}1>YXG&80?D=YQ#3CuHVc}KR|SRYNu|=2ee@5`S}wj)!_W({3bnNu$7JZ zNh^E{L3)0E+EH(@$I@n%p^h^X5@QkRIr$E@-Tll-C)MiH&26{}puHItV4?F3y`gAUDh{gEzJj%K+ zW>Ex!4z}9mE=wF9hDCY%cut+YYPYCI9IrF@y^evIS^S-B9m(?LEnQmqT3;wxW<|7N3wA`wlgCkt?9mz%hv{TDFbqadTb!#b{3R!-|)&(Va;@59^j~RBejs|#K6Iw_}j`l}% zsq~|pt&rPmHfof@!erN9R&8}?mCX9fPPRIJ#0SD^td4K4UryOte^mC;n zb)QDhUMW_-V-l{OZc>}<{cNsY75W8uLw65zqMv2BUz5-NVO9mI!hLer4h72l>}YA7 zyvitd9Q-$sfIgIjA%!W63_wrrB_56EI0vevMI)zCu9l3+Mm{c)i@lM@w0gRzdc|E|4-~YTX z`ju*yST6&h;hC1Q@QqB?4sq?n{_Ch@F=QT-luZ=<5iP&LbcswkGpl_081rt|)x-Ss z=xAw!?p-=oB9kT`C2|9l2A4$Flk<0G5SS4T%jpk>Vv}UQ^QmEy>O3Yd>xQ1qGI1}Z zH4^WZ(TyyM9U8(v$W0 z{S@2E?OwDlkT`F9qdU zk>gLJXx<(R1+pUU88YI}O~k6yriPZv=CIjbK^N;?Y*56h2aR2@lYPmo7iPcZt{1|p zFid6m20nEnOje&_D7*&4RGXC$Zt48#-IU*a)bz)=Ege}{Pq$%e0B@xaVmQ2M+CFWX zBIT{Wu54+I2FM^h&a1#d$#&JNt;9n{L)dqsQ4CG5b~mgjYkuB~tp#iKkC+q&-&D_0 zXVa0t9iS{9K6vnk0Yw}d;ZxtKCQ|Zf>=Vd?7APNyhl_gnKGqC&h}tLu=Inf0*J@XM zBIUTo3^Jkp@ew9evd;>AqgW>8ZpxKD`R|qcWAZw@+}lj(A?4nXDR<9*yWCTUEccip z%gs0ChF4a5Lc@LP+KS|{C?vuL+Z-IN{h1dFWSbh7=EE@(N3mF~V7|gU5O&{uWBCKW z=b-`;SGHo**b}@?Ix09)&1_7?8fG=Npdq&c>p7|5WT)ZnAQP$=8|h*z=}dMp@Lo}i zUMb&0d&Jh;iwd*CF)0!OFRbCFf+s?cH8s}HZfu#z=+SAPh#!REM_Twk=StESBq_E| zy;Tc+k&~-nn#opa0mg!0)MXjwb5RImkv`txSKUqRh*aGT%-w^|^Z})COgtm>hDLZN z`R;B?SUAJsVu1jI_n?Df%s*Uy9WqDlkCLMOc2Y>2e9=!9 z8yn_&khVV?!gMt(h%v$(ye>e*^+^jh5$B}wI^78it|Kx;HqWD?{e!} zeQwjXoV)8*S@%OGp4BOO`EtgSx7UpuPshz^vSx@=hwLU_!uZqK{X{qRv`ntc&el0D zyv>w8pSvzS(^A8NAG)RYN#lZ4qW@O-;+OYi^+XesdzRo6u@2Ev40kkIjzwHUC-!(X>Ysb-S%kfUFr8I0-JQ2}I%U@`Ixt4`+_jsVM z3}cArG-Ig5HoDf&$|MoYx91qET{honOuLd5t#EpT_o72Gyr1u;6S%w|l4kZ!9qHIE z+hZBNJgB)Rxm*|VfMHdUVjWN7=95~;_a=OMUaX^(jS7uuiq5bkWTp;rxoIR?SUQN2 z)7-QpOm$sVv(avGBW$gu1n&&fsm8KdWK0$A`^+uN2E zhI^)=ow+rI-WXEPy)nGsr7#q`|23y!Q_EOwY$?l52dmEIJ&tw%YiiW^SEWbOHs+dZ zjeV`?EV489@k;}`S{60nu0_j5E zi-CbDec}v^m`>#U;&4wY^mkbTbIpyp)jZVv*yDcnT+^Dln4!P0%omwkER6Ssj<9}k zYBnGgmeu|z`ox;C+wX}PH!1Mtxw*9&i$L{OG-s+h;ILpV|WC9G2dr-2k z%oC~;D^#tI3KdBSdR)^85w$+KPpA*8{U7uJ-dS#TEj{9B{GzHQ$uRP7Z3l!HwN{C= zSK9$iky`jXG9;IJb)siDrKg?R$b;fs}Bt#O0K&Bk2OyVBR*>2d~ zyd6XS;cc3)y#zDl($)@hLUj?&$LO_rLcY%zWU)j`5@7r54ny~1uQ8YIogs8DyJ;1t zel9H=KM4|zpgn^@j_Qw#CnG}jx}GMG`{VC%HY3L@twe@iTFA(y1r>+0lgg|Ijmcw9 zVj%yPPuW3Dm*7BQJzxU!>@`!(Og#Ah_U|jn(%$uQlX}|@|2@xEi6*rb2ZjB5rrT3` z?5>!nY095~+)pKVfq#46Vx?S{u% zzG6>$s^iH}H9Jw+D06T*sa&Yy<~P+SJh-svtot z3FJdJNu+OWv<4=61@2x|Ue%Nj!P{l;h)J>G0m$AfX{5b>$1YTN!DcFA_TqYv_U`~Dr1wsbrZJQ_DisV=f= zepvR?_fipWq&j&-`lXiu8J}WIGyGWDkQ-v@ufz7k7a0%IwSWs_9dWOE*{c%a1C>@- zY(rTOLce=)r6+^U^qW`qiNMz0)f3*5nzBPg8t8_ebK7ZEMw* zCPY?t?Qu(p!HfV*Qh>K(ZxER2oMYtNf}jM@Iat|DS3cK#h1vzyt5RF-U5LCqv44ll z-`KGQYb2ApQ(H(fT>TMB@*ho8{(`;EU25z8Kdz z^qztIrfj3e-mQ`1B>NGz5rbfdY87LXzzKZyHTSUmQhPzx8gdByv;9Ierq8Fa|1IuG z6Z-W1pjW*Fdnvx#y%fPZXlt|J=ec0*-UwN@a zSS>8%O5sDgUQc}aPsaEDMyv!bKM{UwxVKnDfWFKGsNHPNx;KhigIM2GTY8_7&QgI8d6R}t=;Cz7)bh^&?<=4*utOu=6X%|pw z{LMM*xsEzD7n*NKb{#Q()9`(XXR(vp=u=O{@9Hv`$|)#Lm|(?2VBoRU|RLMby-)sS1_YaZ*;*yLi3H)B;Kg4NG?Bl zus_bp=?`yJrbGNy^vLN|s>`Yt8}m{61+uZur&=1VYM>)Sa~;J(LuSy5+dbQ|yT{n0 z9ptxV_fMl_qIs0HuW;5t2WjrxYfb9iLk9Tr@wR$i_?F+N$V2&MN94l(A)+{DBy&n0 zJY9aO!|`Fk@!@y@9@7Vk4JUJhn4C=>yCLOCd6GwNu=q=sZm8uiS-9b1{xXBTlpNDA z{o3G2_eIMei;prOtrn1ODi)69)qvDBE4gWw!1LAeEAd(cIM2be+(#badOf|^fK7-i z6xj^h7K@~{J2lJ_&=`!X&djJTQjOzT7aIZZ15)>c;x?|8Cvnj$%at6bHVor^O41)a z?{@l1DH zsRfm{#wfB$y>9Q{$?O^DE!pXv^tv5>d7>Tu>qH7I#uGC336h`lEov2cJ|{Zrsx`Gt zfV-qJ+TWd0Kqt0~%R3rFt0>M@h@VJ;iSKXGTWDyVj~#q50Uy zfOpnWf^qsK-o8|KAP*`vMZ^~1?Dcb{6HaR##=_grW3Wmc?m-tWowRVJSKT3G3 zpTnIP4_T9kc(UlY_AJg*Rj18Wr8VcPg3|(O>UpYkny^SelQWMBed=IxZtfg%)CM!6 z!tOwx>Vu={PNClHDda18J2_frkM+?0iHMJepWtw2r*IX&;Lav@2vf}8lNYrjAd2D|hOg=IeMdc&wSM*(EbYeI>h-WAqf2X)0~q znhHR6n#C4RQ2U>jww4_9PC6L=8yMqnf-z1Gs4e!x(p{YLS?$|-61U?q?k;3LU%QiC zzP3;5Th!rB@6o!BQG->!o?FKU()m3pH3e&R`6g{lcS_7((ibS{Pu`~S2tTh+Om_H~ zqHf0P!wfNIsL8p#DmUwM105R$X$&GML7Hynf=3L}sBn?y-igUkbhkdT*uT?P!gkI$ zC71o=Vj;`sL+;KApIzf3ka^H-$O|GyClZ%XPGA)Fpk6@)$n~-HP*2Ct5POA-yj6>3 zhG>Vw3#zUFn+SbtP>D>LI1m&HP$Lp|z8XR>TF&`zpWjT__}_k}aZAXZtf?M3pO#4? z2lIZnD;jnSPI-V(Th{Q*oHP@SVy+mRWX#i+RkiHl?-s>klI9=>Hr5(hEkz~HU7cG_N0@an;GM(_&(25*N$62)H{fM2)pXzR$YKR?EZy|Y{ zea0MVn?LMRqNm=5=zohM?&39$lV_m z3k9LkmtWl^vvd%F#*&<>>V1+E9sBA^C@0k>^VeAvk=d=vZwkL`wI0+IPdC^zruux7 zwmAEramH=-P1@>|bOlP-7F!SP6)J-je^H-rQ7kPPFo~BgcYc-h$y%*?-*LEuas@+M}&?!AJ5{a9Jb&2FO6T3q5ml3S9Fa&%=kU^#{c&C-QO>x6c(9= zwA%su`}MF+kK{>o#!&o${vUq00bKEK9KbSu%k)|&OxHs^an^{ofqEI4na~9LQDHW~ zPm&?99Ky9Gv(ZJM1bKxf^(rLR3(k}+j*x=#*D9@C;yglqeO2y@iQ$ERi70_yZC zIY5Ffv@QMyJ~8D(E9uyxOL%4c1px8s&SvVNqHgr?P2NcgF~Fx{~8s z|CDES=mji8vs`+EY)QU;mzfOfWE^C6LSGTS{AAL$ItK9%gKPi+WC!KrPljkd4gff_ zWN|2V7VQiyiY2E>;>@;5zISwmjuxEL>U8u6NBKF2NXLcz-^2k|llo4K?>=g3>#B;+ z5npEa^vmmo1pJ0nHK1e_W^T{jcYSKF1YYe4F{IXO*IXVtZ9u&#bn z*S=7(8<)BwVDmIg*Nc1#(dq3e<0(%1PoMCMaQtAU-@Q&M{hfQMG~y)UJZ%uZ*ZSC8 z*5V&$W9YMiMbA2mo=twn$@EMQDIN8&q;%A8a#P;yFw7pNAhRc}-6VOGIEx^`_9f&X z!L3?CY%3X>_eEdBj+IuRp?~E_WFwXp`Ws$YT01!M28X1b+UN^ER_txKPt!bB_(aXK zXPhP$^0c1%coG#n86sy8zoR!Pu1{)25H#*`W*G37_@}&Hczh;qNhMzRl z)P+@zt!|u{96ozF2RUr^+UnIN+ZNM*<3HDWHuHKP50j_$V z!G7ojkV)aI?KTr2I7L!r4Sd`&p>ic0sX)gztNru(;Yq9G)AF!rGgDx&ii6cworBG> zI+U)n>u+t;yGy0col<8D|fr0=WA!6NmTtP4NW0g;b3mNN&?W$ zmFJ4N(b6fHs+8wac}6>*=cP=eEnh27;Zki=vEA@bYt<`EjKps;^W^85d6FKJdcF)j z9uF{S-0?VGFD7O!Iczl6rerLpf_wB>lp1Hvuen*{(WmqjtCaEhYm|Y~%ZIo%ON)Vi zoA8|Rcqvj-Y?r(t_MDu}3{t<@+%2nPHDGf&TYhzm!BXEaSSrnc0Kaw7F}{u-!Ec+T z*T8RjH2YOplK9mfl7!-(4Az1f(0!2dt=t;Anm>m0tuH_3YuLDK+}vovk@7HRPPAZzJdAMgYQ}?fXm>LmDjQ9^ z;Z@2aNr+1FApZDji_FD4 z4E|8LbMd;5uz)%l_FiTw4UTmeR{CjtpyLn0qXQj}GaVQ0%&HSB?Z>iSl~gfVJ{U5X zZ!Sh@)2&Ejl%F-ry7*1giq70tEd1|KER$S1h9->h(S%U}oHS-g6p)CP2ZYQLTB{~B zTaZXARr4>>!a6-S3I?fslo1IA(O5$;NTrKS1cOX6SVLowNd}u}407XXSs3JPP=;CD z22Zy1;u6j|*<#xKZ|>d(tg2%D`^Og)MT1NV-$}GkLrEp^t-vHV3PqMmmPM9EmPHCi zrimg+?kLhMvh0v$k!2BOhbU`)~vN=X07EXGh6?${r!Y9vA6vVkwebg{v@AqAIP7L+8_5HzV?^E zt0MU_)3m>g-*^#wqxLtM3ECfj^(y2(t`#%zojK5Vj4#D8&dY?ki*=6fj;5`668M@0 zS5^EBJCE8X@RB0C;w2$ey8CG)^!V=*;xF>a)tpJlTy}1*Ya!`uHdhZ?Ptn{HNHy`? zdDzg3ndk;86NY|lx`Af$qaBX^kMD1V{@`QN4a|%>y-~V>p~r(3$oC)rLZw(egsGo+ zcQwyIa37EvWGy|HFCOxj7vtRWjm3=bxEI`hFOO02AcNJPC%K#G04x_^#i3Tb>Lr7} z8(}6r%vroyX8Y5X2{{$qUG1E)L*^^^x`@BJD1Vwh%bGmqd^K(_{B*<|o)zF{x#MM$ zgh%O*%H>d)b@~aF`Bm<9_-SSH+_K!&tRKJ+((qEXy%~F5eU8caKWBWMw50@dYlBuL zrOx*=?fE&Cj=uYI9^B3Bs~zM$i;ktWHf z{P+P33|w&mU-M9?tg@Nsdd79)XD;M&ume`j35mng79)r54O-BS z(>NrjPt?duICHw(AG;n&3AP^|oBv%2r#_MgTSIxb`64K&S9)1cudL#cLA_!N`43kf z?*RYJQ#$-7U-k2!xA%yR=SOf_n<@T7etc$?TWlGw$4f$9H%~Y5&Gxa8LBam-X3AWA zrTlJtEF;>_h2J49m<#NgI}<;;d?}VEX#%9R@zhK`XH6z;{P^E;XmbC^UqjqI+CA`6 zIZX#MmTuDh3E#L!(f4LjEGRFXanAd4-QGM?Uhs;5Q-daYf+jZb?D_{LVqGg%_$jN; z!%Y9GtIl82lrG|wI23N z_4|6(0FJyqXu{^Y-oCfV@&~{9tmpgZJWfphEhG8-GqFbmQsNis-mp<#MmzEIW3spW zZrY|9H!=K_KTgf0!o01vt{ZQE6PpoY`1khNL3M#a5gSj3bT&Jc(Tkq|kj^)L=&v*R zyTPcBME+aqK?d-pUJl*sZC&OiA^CVVh}RvsIR7*2`Hu%{>) zi!YJSIZ@tqezKyQ$9MRBjr<^#tb8qKlF?iKE^3m|UH~gFCNJ3>w*d<1zlAakf@z#cY1hi~&-wT#gl7rXBHe`=`980xO5kNx_2F z$;vrDc=unP$O)4-eegpJd}`o#PdD0q-gEDFh2#N^h`3v%6nNzw_mN+^-2D^thyRi` zfRF8~!t{PwX1?6RHge`TwTvE#{9P&@@piZ0;<|0IG{rb~`^PH|hx}C8B=cfk<2BSX zqgF2i_zGeXzp;l;fSGN%*B{9}eyO<`K>sqGyPGrf&!;tfDOyfz7nsMs^bBd0zyN+u zm9w*#zhB0E6w9T!?7INS!>Fs zSKNRtCn{w5CXWj8OKi>QY5k0s&)o2zs1Il8QI>`V%eyM9TMVA-uaG^{ZtzC#2KBjE zE=uVf7GA|jh8(#o%VxwcFX69sb4|&yRKy@&7Of5$aKs$R=6R^Dcpt#iCUj0U|K&Cd zZrjL$+uUqmlE3)i4>NE1;fJ^|bd$hu44B;)-y{2!n`BM{uO9n=e|R_Na_7`Gih7|P z^$LwDU$Qh&=UY+Zc=hTg9vR~Q%>8!GsU|@SlK5Y7Ilu8%O*FI zFdsdb0T*zQ`t{Ly~ zlj+W&hvzWm_cl52FX58o#ZG*|5NO)NRq|??grRMQWe$tON?bF`7}tzf@(kNVUHAXS zmoj{>T2JT6&!P2rB*^SrGubuSnT+dX57!6q9?p2#Hy+1VVKbhv6Xl7y1otSuWExg= z#*XK<`gz>Ri z$F$YAj^}7M$%a2)m1VRx;S+K{&pb~SYx62dzWb2*j6>_a=ek25;7SVp_Ma~Q9#-e~ zhowJYuUpFg3zU8AZD*D}Pkvs`pC4~r-aN>bh~mI{4ezS1NB)P!;l01nl~gVTMyPUOaTax7R*&FaMGw{CD}cPyVqZdDWcE4-fdsyV#qTH}HH0&yj!2 z_07Y>{7KCRZ{bnDJ}1p|e|BP@!_K&>DPKOGyYb5tJGhjuPZb+TRl53r0UZ|mS;*u$#idwdz)`zCf_#kwK8AVg~`Iq7e3|3lRhv3 z{W4tK!t*0PoW%L@F4nM?X~YfvDQH0)H+4QK^FUAfe_8|21!qPI|NHrZo4!lhQoUIx z^Ruk_ecrUAlNhMxvjWDhxoz?kW1DWgq@^?GFj3aT4C~sc{RHsiK~kaKmA*W-fl}3) zT%aQx+&_HjEQ$Nr+k!TjC2{+l{(-w}dkhJ6$BSzc@Jdf!BDmxxStYjwr-lWM>yBIL z$KF=zY{Q&}H~1>6URwvhWh9PQB=E^6?!>N%iQ=B*MbiRw(o;r{-EDZnGo;6j za->}D^d{Vi3~JN@%+cjJvj;KfBEFgPwg9f14c@x(Er~=AVirD`Gd5p^HBOvMpIg^8 zPIs|%qI4JLe0RnQQ9jM>)6<-@G%_K4Jzp0j@Y`>_r#Wx;z_riSZW;jBx~%2a#>~@K z-kzcdZ_ZcUe{0;@1|;$3xMSMvOiT!L(h@blHVJ=2^%xl*H z7dOOkGyN5i5WdruyDK9at>ANO%HYnw&fl-10IT89 zrOQpd_5@r>d!>?aExsN-fh&9ycjB(V{ic%miC+$@gW?&|`McEdngTzJh$9`WHWAU^zOKIHjwQPu|Q1tYhJNbcJPoOa0@cFh_L zS%I4EdxS?;FyCd)Xgd#;uyGy%I5I(+&GXVrxZEE$ZZ>b3M4U8TxhJJO@C-tww>&oT zvSwG{Z*@!f%IOCz;a=pd8p${5=b{(--5TUxi9F4q1=sb-8>_J zUzs+PA0_Xi&2hcAIl5%{I3c_`fz!Jf&2c-wy%*zk2WRr<#H6|KAIb89xY$FRyf=|@ zu5wv-ko+B+Gmx*Ra?V$FdzI&f`6O8*1&=n%10HhIFaHHSJWCem_u1lYyLje6?s+|| zd6~Wp8=_W1Lb%)#Ch#pvFxKVsT6Ip%tlZ&IvPq5a zhguByX~2=XtIxVFpBucjox{8xvmD>v4ll?5PPU`V@i{eFkS}ZS)6VE)xsBJ|pna@w z`Mr70fM1qz;W)k>aXZ&!2~K-W@HQ{rGqVi;*SZc)dp(B_9(n43)7W>tq_Ie+ZP8C1_6?!gTjLRT!|#%Im}eKTHS0u`JR9-njd44gCNOm zPQ_L>|L#rbb93!zchSxefa#+7sMt~W7-w6D0O}SvYyEq2z7yQbu!;P}$1yL+-+tzT ze7zg>F38_p=UtG0)Vm;`r!8ecel;(CkcTnand@_T{BpVM=nl&KK?cH2tL5v-T7ld- z^J@LAjaKXPleK4CtC3p7{mk%?`#C&Bl=E?_eULXgqV;~pJH9L@RvBB~VHQX{ zD{1FPSB)LuXHG26S%puIvV>QT`F1=|yA=E#+xs&j3$doQ@^){GwEl zyZvL{+g(@gdhG$LT)ep2tg?26Z|8@qT!EW>rx;#k&Edimc_jc3;QHnl7oxWcuttvm z`vC5r+25LL|8MUvA3{Cie)2T=U*2DN?+@26CI6@WZQZC-)hc!A7+&L{jQ>H+^2+1l zZu~^KQ?2=bsal=-G>f?85z8>X7L`YU`3sQ4_^OZR(fM^2U+}Pe(89~P`SJ8vV<0PvYmdqV%9h;4Q89QhHQBihWr=bLH29+};FipVp&b7se!_hdZ6Uta3b z?~_^Q^Pjb|f`cMH_XOUwId3hH9?aJeU6aJfL znB&|>_=j(jnSb*m`KB`4%XKk73KYzh%3~{LVtE_aU3}1lZ{;76>EojPe&8Qn`tc7T zZ66ztA0ca*V5w-^!%1=pcp0x~keYLu(lt-+G?DZ%z!sGIBX0yV$ow7B;J4HHpFs=9 z^PfDm`dd)n(?7^0a)8jq1)K~%<`6V-6W8!Yo&=nCdePSAaB)`Xree>yo)kFIV>S)+%V6TIl;0{!IFD^KU!QEX2&nFIWDx znm5TeXQ&TnS+aSZlg*KXUpGZJw*^lTAFXS~v+6RJ?t|2M9Ou3D;^l!6eCx%JY0Jx!-aM%+s9h`SkR-(+qje7Eg69@#9e z)3`U^%)=%L30MZI!^R2jrE)^I(&u}@&m?_3C~2o(l@R#3IZ+?wd!J+7PV9^iuZ#=i zyE7i1InZt7kjfc-^bs9?^f<`ZfrQBj84r?}mlW|kkInVTP1=QgMGcj#zd{lq(I6}Rtth3_J|Cb&B_DrQ;j#-+@!k3H+~eEUb8%asjU z%3ECF+q|Rme7VA-^SE4*hj@A1s`22w8Lcq2Xa?tb&A40!@tRwdvM+tUAvEdB*nH#k zd2AlFsAKc|_7(nLU}bz@1sAjwc3d+Vh@Z)YEd$x|*qE&ML2v!13!BUR58C%QS(9du zNAWZwMz;SZyVB>c^yVL?;=a))nki|?3{_%VN(8!;Q>3Vztym^p|% zbz@z(J%)`uCL3|N@kRmP1BLy0T_i@KWL&`%jhTbdcH|1*!Y?pz1y=fwruuGD%{$`) zD@F$Hk}BqZ@-Y=3xIV5~rB&xwoaX+{Kb&_(CMXkp1#cF>KlB&IqU5mqgZlR#Z~DZh z9B=(h#mn(leAOQxZ(RG*zcs3P4Bzdvx-}h(_Ex>GTTA4s*KWt>cXVZjJjhsS)37n6KNsNDesjNWPuA8HVP=+4q1p7rcx``0*g56#J~+2`6@V z?|@$Ot%ykainIrHW+KHV(sF&FZwk^EL& zfBt#9SvYz(zlUA!)}n^{`2{x*S`@=q-EsV))j0lIUtCT@|DZ(|32}S4kGrO$epk5% znHR5Scjmu&;r{8b&0Q-931iGX!DjhKmxZHo2hj6b{Sn;I~)E{+d1HeXI3<_4MhF_^p29 zI2~8chlTtX-w(+5?)YCt_}5_mt4w|#O5#856u21D{WHJeSCX3Xrd(d1#EXHyas|bI z%KzWzYfR=AMTT7y^LfoDe{zAEJS-Q!K0P};^FqDF$#BWd$B(n(Wc}%hSwlGTasL0$b%Y(QH3J!KHK)71 zXU^=Isa@+To=4Z)a2Jw>I-U%J+WWCMluzXi)GGCMw zxV>?Q#RIF}^{1x8;s;0g^^QDBEf1ER!vn57&u0ErAzipE`uW`H!hilNUHG3b|BHR) zUo-qamp{LAqEY$dHf^ufri{JO{;Ii$gEiDSbH}|Kn|iuj!i~XDxrZ zn&gXYe!x)N28T3TzDc-hjKPwM=I@-QU6J}_V+D8 z^OZ*gKf10*aibF9A^C(rE)g^Rf)!|{M0or*ylUw0O5~2eQX+q%y_|J?_!3TSB-!{=t144qVevc*TN!8*1I? z=>4a8s3+0A*FlrQQrE{bsT3| zoWN^fe!n=uj0afh^O(a%oGI*-M^z)w7q!d-nQ5`%kWg z|Jr{xu7$Jq7yoH}kjI?HcswTL+(GtujJbp5<5Cui4RpErp|@d!%uyjtu~A=P#xu@X zDdtR^dxuNBt9Vcez7sy*p75Yxjc*v^cgF+|&Fti%nT*S1XlAc9G-FnZ@d%CNhXY*4 z0U8a>_|BZx&{FR>k@PDC=JtrElg;^^mqExvubm0J?(ixMZSCiZ ziQuf9wJ*8#uk|I;O8#>DsPOeCFGT&R_94%Z{r-IOzu2F6ufeSL(a=w-&hAedwU7UC zN7AT$EHxYXUu++J%=nOAf5_zrzq!iXJoEdRu}HPj+er5CylXSg&siJEO@FD8oV9&8 z_jA74&u(1HxS3nr_l%nt>-v>%=DH?X_tWNfuDNLPA5h^w%+#BWBc3JQ)Z<5_RN;rvg(87(V_pWyHWUbl z@gtx){1{~J-#Fs$t`2>(q2_9xhd3k)ynj|+tClYz@Qd`#{3$EPvL!M4aJk&+@+f0iH*$ZR2_*u6g1kalunJ@rYC7 z_et<~sd&Wo-JNk22LeV0R+|v=n>kM-RR_H*gK==OER>%Zj|=9@4Nj2Xwc2L=*^hsD zk60Lw^qSYJo!*!|tiNC830M9D!Ru-RxSHKT^1#h4vOKcDb$WgFunw%thjICy4%xar z(kxx*l%3UNPG*Q}XvwwZy# zHZh})=8dWkTIR_cb(AN!LS6FB(8uMp$170y?YA<494ik7xnv0nKOD5xJ)+I&5dl0F z>n9)o_G^{Nla8_$VxcFiS%1&^pz_*QGcVyqZk*ws7@y}+S^mV@H~I<>4iGfsGg*z~ z;Wv0}p0PjZ-KKU4Tj`qxN4&TQ+ZlDnc4jn}xC8iV=K3C?-th|;KgcZG+iP#{Q#}2d z^K+9K`?;e0tPOI>$GGzSbN}9tyDa{~0aqV?1}G}-t=Nqtd6YY@q-kjrYRQK%2P)t| zCPYI17}rRC*LWDo`>)tMWtmio*o=0;ykwayG0o{cm~zLs3%Dpn`qOie+bmhEvIWh9 ztg)m=WlNe2`HdxI_*#+;pm@liELpFz6-7XHDD&-}TUOdg%+?eLIn0t_Dg)_zdA%^t z8(1<%WgFT7IoXoQD%;XKkdrK#rt%zm8nVEW(nUyyf@n76dX@?K=IwB%PDBRNB*@RK zm?awXT#AJ}WXUR(?I;|w&3jHE)T%s>T0nNQWP{4~bcjEg$c50`lEFNsA{h#yt&s7S zj8J(#y$P9O$yk*a&=Sa*EKB(#xiSfn?@m!2N;9DsT5;1=cA)W)Pg^oiWk(tex!RIN zDmzhU$PJd1FPO>Bbf(iM&7Rg;vRY*qIso~DB}rvh+5p+2+$mi@Ub-&HcB5j*b6N5( zhRTw5*8)BBJgo3wrPTBAOKo`wI`id?U<7d-^o z@_nZm19(N5TBEz-Zqk>My0G@FUrKr7Z1}UF}b^AaAi`t;zv(1LP3y z>$v;&Ms8qV+Df7iq(KPbvU7Du>V`kkc$#q;e?T4LRMCWh#f!HIP}BtX4Uk`a`-cNh&X= z5Xk2(>DK}!bOkm1WD4OuONO!>na8h;puLd)uw<0RjH3@ByRCC7)unO-y#P7FlBp`M zq=k@^ESaTpB;5g-XUPJU@iZFpS(b4n&ArW`Sp8Mh8~!ybvPb18Y76Fi4bWZO5;H$Rv{ z>A@lR{(zq&M36j9Vj@){z?B@pD~nX#NUI?4G3on?v`qa?lnej76}ejFBuazaY)Mji zGmU}#){=g$P++%EU&s@d3{{y*=R&sjI2n#oc`N-WAHc}>kF=yqYKE{0CA z;?}FYlUhUGX32ooD8OlSq))s;ASF&}&#* z4KhvrJ(K~z!FXST$!1^LTpHxPG!`LtSz9mE=;;&<`AMOmeC2K`cR z_V^M@)~cLIUqOztWP{2Ks(_qm$zc9ap5!)@UV@y?GVZNxZxuzb$0b)2T7VGGTG3-! z<34N(Fv zKo{SVK1GmCR{Uy>A3$$Gp0p&XY(-B(_WZbU;(l#7adQ>Zn(jl8Asob8UZJd|JOk-^ z$Z;%7eVu%i>NXS&JT~Gl@6CRfT5+>f2GN(0+bmh2GMGMs zBuf^nJeO8NHrwFrjz?uX%7yG|$r_dCQ5xi6OV+DwPh%jjw`4$Dlu`)wg}j$#X)A9b zhN(WEf}oSFxG^d(pkqf&F+6C=WR;<`8}bcF*f|HQ?m+KC?-%VW;cV3%>1pV&jZRS% zs_aCwA#bx}iOSA23G!u2R;lblv5;R_vQ}kR3Wsd7$=POu%5KyG@?J{@pMydSqeI`B zf;eEw2$dJoR>=4&C)rq)-RVupEK8=S45uZK?^`lmWe>`P{LPYiDtl52UAYRYp(~$cdIDmA&ZOI#USSEa?}7WP8&lNWV{1u=+#UZ?{J4>VYqe~$dTe3i9 z6t#!kX3}o&ja)2go6FZr>DXbj$DOu0X?rw!f7%WC5KFsntdaQU{4{_{5#)U=&@rsNdz_|n zFg1m|(URFJhtR=8rZ66ognb8eq3WTu5&BIlZi&ia^eW^rOIE2IPLD!HS36m%Re3qx z3z=uh29;OPSjbN-8GJ5^FqWbryY6t3jZhg!p^&#)GFIgX`i0D%K55Aml~>YNkegWY zNKQI)Q;t$?BdG$i<4$Lrc^WgGUV@x%$s(0k(IQBXCCgNfqG^!f^4yzV*;T7_Q4-|C zmL!!46b1P+%eWF>8~1C6LK;oM@HhO!NjX&I82aH~rX03fGD>A4eFk~OZYQQoWfHvy zxzduUDzB#JApJjcVrHqlhUP)0S+YQ7GEIj3#FE7-ucdg%zMnhEdQ^_32*@W`S_39E z>~ZaN9koD+kF4nR8vS}Y#NW>1>!4#SOMQc70q3C<$I%w(@EZG=3sXIwUV|RV+FN}w zDksomkoQ_LS!D{{2f5smX)14^>mj$vR()soY}FGf8u|?@ZlTH>DHQSvOO~j-iGDd~ z_BO+kRVpXZSCFsBR(;(-t?HZUBj`LUZiC8OXeH$PmJDu>LQJJx$mcB?q4HKrgPd>4 zSe27$4CFg3W&D`A?~uHW`a(W!#Z1?jx6`?hvn`pYati(Utto~{mMl^^l|F}zwPcyf zJE$CTrX{OYrqK$>@s=c&cTzUwU`zUipoFH;ZIHLKbS`*9Ro_J;q32q0qg38a7ef|X z(xq}bwT4_T2|FiQ)%Q@{H>Mz(e_=PYEYpe6)DreA4$V;r4H7aM)c*rYctG;$vuR4PUK^IsF2b_fIN z_Bz{)U@0fV`ScFtTua8PTtH7lmRK@HWe&}T{Kk^$Di_iu$n(E+wwb3gmtr9kELo)T zVG4(wW63g=i>L+UeoI!X%%elKrVvK#bGAt;AEB*~xt8<`MIkJvHzBJm8LHAvOCURa z#Wm_X?xIvbN;9Dcvi8=fOJzQdhrCAO`Wj2B>c?mhbea`6OXcI#5i-Y;1u6^Z)PA$C z&s(xs%pyWiQ{fDS0eWt0Ya zt0lu!K1E|7pR{C*%BQI>qsTOA_1> z#aL9@l)52EsCGFp5ilorGPEFDHFH$9>#P>GXbd@jB zD#)9yn0YE!Q6A)cj_K@mk?NP}PUuQ2;WCx4P$Fc=0cWe#DvPNfWSS*O<*U>V@_kGC zbwXLKrsH3lJw4|eC)rSyuTc$ToF$`FzE1B$W?0gtat%EXIl+>tD&L^_kjpKZrSeU> zoh4u26fodx(a*eLq+UvB6k*TgrW4=YbA#by!M`bCsg?!4AH7ehx`n{$QHe0e@ zfd+bVl*5rFS9w9dt4jrt)2S26Cb$V^sc~=0IjzGFfFA-2z!=$uyPk(Fn+2 zESascoO(iD{!b@Eg(}~t0Lb|)t#hmD59rVyQw*h6+$xppXe;D0OV+CVkluvMvSfqG zk7x-?uF>Ewrbe&#hLIZeP$ptN&(t|2A~>k%3K|bR&l`!;iB(xigCQ#|nWAz%b%tDJ z$#j(;)9EkFo;FxAPvr(W0J+zaMJhMa2FSkua>}<%m?YEqPrv zC#$ZZ*Ps_Rik+tV3wjiKjc8xivQ_V)>Cm6D_MTJ(XJ(JA?na+f88!%&p9v<}jj9&aK-<=0dM znZO%!_BB@Z0h$jzO|-9^Q&fLLlc76VL#62|4^lkjLyeNoQ~gi62>Q)NNf)X97qx`0 zZ4|pqH4*JL#c^((Qwh~7578%(w_B1_9;P=SH(Ao}LX=eSE^zNaCOGg*3@OsdBGH+6yh%#v9u>&Xvt@b^y40+mPUn}3)> zc+Qf=Dv!}d$o-b|sQiImg>3h4C)pa6KhmR+@s_Mtd7SQrOk?RBS^?crfIm?(^b?|e z*W+QTPtc{%&RcyV?@kVn42oVeZx8Q3Un%KZ`HUoZV)YoTx!WwmBBO}@-s_j zsXUjGAzK}Hk}Xi#js`#uvt+T#^XPoYc`Tjs^{8%7C#uc9mRNCXREE$V$ZsrJukw6a z2YLQaPL^abxwNDUs0cE_l3^-CDF`Z}>FIlosWf%H>yD5l8mMl@(m3BaGk*)f=kSf*Ps1!Qzgi{o?D#K_QkK_2IxvFZiLEk8U}gXlCdg#P&de!1}94?Dtl5>$OkQ%uJR%} z_^By~H!PW_@?xrj{MwR5DkJDM$o4-w+bmPriyngIfNr(#cSi%D!}Jo7vB)mUOA?N41czS~68-6s?E+&XQRwFQu0u zyZz#9vp{8kdIWN;C5u%Kpt~V+E$LA?kgkC&vt*6RXzCAHXUTe%mr)30*I%6s1w^3u z22sOSQwY~uGE8L*?S))u$rzP`=|jlBTQXVY5PAXfuqD$}4yA>VT~0X}%2qjy?to0T zWTDF8G#c_jOO~j-oFXA#wq%vcD<~N93rp6jjHMqwF@@0PHzz|4D&y!g$SW)v+zZ7w zg5HB%V95xTSJHEkYb_b8awN@zBul2KjHk(volZL$N>_Om#Y5g~$vl;#C<5{cOBShg zQ6S{UmMl}5K;LgMg>ZtU)5TS*9!=Y!BmAO#=QUC}hDsst`pE9Z{CcC55@{*)Fe`4T z%ByJ>Mq+hDcetv6hGfm}9^cCbLOJ=K_L=}*$Em^4YW_k%S-;yON zZ=pqy>6WZgnM%_jUu5Z=4Qo~3N@JiUzfKcvP(7J0f!<&x9efFj@HPs9w97X_8E?rb zmG{z{kXe>=sZ6IOkT+UVUTr6riuX|_q~zCI5Lqf`PzvOImMl;?lZHY*X~|-h8PpZ> zb4z+uW>OQ#j!m3x)~K9C-)=C4Fx`^%D(|OFkRD40^u?}Z(Q3#}O`T-JR6aoYkXKnU zM&)cuhkU@2$toYD>mXmZWSYu3bQxq&GiRIGD(6xMmOL&~$bg4_ZuEwcf`5p9{n+g1 zS})~*B^q-c?S~{wR;kRUO2|&l?G{+e8qbZq2tACow?-Q@?gDxk@)k=5_d@~Z(4CM= zEE%D4Atgetm96?l-(pqgQY3T>e>+ntsvo9vpa-$`W-49fB09R>6vb?b>l=^CQ=LaU zq2CwnJEV$KKSFOq|7s;&rgAYo1v#jNv)yWyZh8Q6tR;D5(i|9%(oK-LEV*j99V6qo z)6A#g&>LA>%gRGJ7?$-tMx79%c}r*0QLLr*AE)0c%`T5(8CSwzjK)HGm-+(w3Vx9l zIaTEoQ~|lgMD{&nk)?hKy#U`jz}a$v%B8drGT%zMSml#+2V}J+Jt~*cXvp(8Su4*q z>Yt+C@Yh+JtylRpwT1l5N;%+Cltv-dSD4c1V8skm`3&uXyvc0Vx3@9sm($zuk6MwF zRX$5kvE=GYW59=CnKz77!gKThVjlBS4w$VmSI|w6JzF`2Sg7)Ox&kuAk|iqtM%^LZ zmaI})ME;N;TC!H<3q&4M4o5B7pmHUB0@MW$JkZHdp2}kC0y&kX)mVzuze=Y*GQ0Y+@xEFuQ@@(_ z!T-}ryjtaJC^{iXCJdb{UON1~DUtzJWWUR>V_(uX$g3IL8KJSW4kDu1LlkkKsTN_?$9Mg4L5uFMq06f1JN%AaUEWQmFFYr}c!Ptcq2RgDub zQr|$2!#7xom#O@jWVKo1@ZrY$w(nAZno8k^ihpZ?w_izR&$T31dQIqY1j%ZgL>31z zvv%pw6-N8c-37XZW|Rznh`l%YVwKHl0A%~~9qCc&Pv=8+vt*6R7WDJGX2<(mvR-9N z`VunUk^w_dqyh91WU3{@RJNj(kXKqVMrCWtg}m94$tnXW4e|j?rm1X0V<4ZjWVXt- z)EDv0zHrJfqdMO5h~l$wUDKjj8z#z10i=?GDYS2 zTolwE{s{ZHl6Kx~rE8E2=*M@=UU%VJN3YCN8A_i+CR?&dWd|yU%&}yd%8s-G@?A?- ztL#MCkY8JpRCcD@Ae(n^GUPW5<G#+y6oRxY9#M6NKx_uNyx#=n?C;g1^c%UQs1lx74ql$zb{(8)=dHy5V9 z7uCQIX76nqF)Dl0`;fPr$i9sytM5b4!Y{NUr>VSz9)f(ulG!RF=~l=got@1Vs_aW6 zA-7qwL}fp^7&5hs6SGQX6t#x@!IHHqFQp@InWA{Os}r+9Wq+!M?9k1T!Iz^D2hiJ) zud}qSP9oF~q^0b+RAU)%B_8yqAvG9Hvk7R zlN+*mxRY$C%FF2<$WfMzQh5bk3%S^mE|sw~5OSX-Q&q;%1(2~loNZ>Q96=}FG=-33 z$pV#E(mu$ImMm5|k~}QAN<9p?O563+)TK(}=|#kx?8J;wIhxu*zHiB7m1F4m8>SGtMmRCkR3=glcbEA(0`Zi>qB^d@AD zCDT<-pe2yMSTav#3S~l`e@UakWz{#(c<3uwdyAq>mk3iWR%KV=w-+gmUO91rAHt;Mmjr_s`6I4 z8#3CGSt=*fHIT_Hox%SC)wfX;^aHH^1ZQ)|P8j zPNm(DQ!QDq@(wD4d_ofTm2tq8D8@8;26~1SH%#T7GzW5=C1X@hqgx>JBw^oVN3!a> zC>HuoD{h*~yD1zp(URFJr&9~adnI9Cjtf=aL;qTBibBfS+uTZ2-b-5`2UxO7B|rZN zd9x(!%WnVQDreArkV{x{^#zaA>XYttCS4D?#)=uiAw=@?kB~L8Rp0K! zs?MZP=%b>26FVuYXVK5En!Rn^*V)^2mG{$^kUcG#r;?w4gmhW5NF_i22sx9bGhbAu znxB7!e$4(oK&-#`kxUO;hU%@R9ltm0{Z!7v!}am zi&XOSkE={E486=Qr83paX&3a}ti5|$t@2rV7xHhGB$dz6Gmtwi>E}Wjt)MxO{)3!k zLsjzgkB~8zj8e(ZKSDmp(m5<#s*5Nb`U5L&s>&Cr1!Pc+v(+q>E9uZnrXa>zvOwjF zv=wrdC5u(QL~lX{40e+Bs9Z%$An&qdjmnoP6Y^6_)~kGlQXnrJBG-bxJ}V%BuLax4 z380uRLx_GH!dp3EtVO;`9U#YAGDhWU`t?P#vr{aYtnxM551D7lG?lMYCFHY~%vQOE zRzZGf$wHNHP#)wLmMl^ECfxx&N$XZgyAp^DVj*arDmT&=$X%AKSGkGSKz?t@fJ78x z6%{~sxWdU(n99vG6Ee|~F)Fvvc*uE{Ojh{`4TdbWWSYvY)ERP_C9_p-qtkyg`&nhl zLY1G=0m#=ZS)y_~ZD7eqU=@S%CZ1MJ_+zVEI3VSN*9vb6F8QKN@CM<{z?Tc31Rk8k zygB#+;ql-R!u>t1C4Ivq!DEHD0G}q|L%>snw*((6{M7R%pXtH_z=sGw2%aarl_x;b zH+&m-k?__Yf8iq}{95ob;ep7f;VZzag|`9kE#Y&)NqAfEcEYEF`(4fa9PpFeR%je} zsPG`<)9~ToQNn}44@mf);4b0kf^QMt7CcpWJM7m^;m23t(p30)*sndp_kkA(Z;$*K zz5%>gcnEl`SYT?VkYlL3_zC`$3@Ot5)$dBPuzyq#f-U0bpF5#2F!-RK4 zI)+Ds#|ZBPzCglv0Z$g*8GM>>fABQnT|BM)xgHHa@|-D$Y~fu!0Y1JPyij;IPfH(P z2VNpP%u0V1c$M%A!N;gi6FlbQEGJsKVl9wEFZcxwqC z2_7r_BJg9}|4|5ditvk3&L@SRdKT?pcm&G1sibodJWqHpw;mg2lgbzagXA7STUN1Zb`7wM7c)(cZgTW_D_$2T!;X}Yj3y%hm5k3^{*6=Ri z$-;+uT1dMcE8+dY(}WL4I))#42JK(?<={gk{BH0<=A6XEjLNTIP3yo*Bz!Ek+g-x1 z0W`s;Om%=1V71_5fl#|Av_-2H9QhLR`^xe zZc|Ao1UyCfD5PWfsY0}W;V$sQlKw&PJmCr8JB4opFA_c)+ckVGc$x4q*zO()zXH5k zcp}mtGU2HYcjyp_%}@EYM0z$Z)kbHVF{ zr+|+ZJ_S5r9P=BnUBi>W!-P-7{u&+)9wYolE1fRj$--{}?=R{5gQp3f1m02jk*Co9 zh2M8t{;5`HUqQ%OG`yjJ*R@WXtCPnqBi!f(TN4W9%a zJf8XO*skI6;1R;7Sm{K9#|obczEjc<0Z$Qr2Y9*gQ_Il)g{NV=h93ma6MiS^w^G7y z11}Oj4f!#AEqIymyO6%&E5NIT-wnQ6(#ZuU;nTsF2%iq_H-Y&*$dBRUz(a-Ki~KB? z@Wa8Qgr_4vhW7+_3BM2N8{QT?Rrn0>1(MG3C(-_e&jg<)d>?p$@C@X~@D1R_!ZVSd z84`XCxJURbC5rD*@c9|G?$>FfqC6h05Uqwsa$CBn18 zn+jhAUL|}!cx&PL;I+aRfFI-Ae98oG5S|0RNBAW0;2W4P#Qqu{4;~>r7yEla!bgI~ z3V#^oZ+HlJitt59-|$mQ(Ef$zfp3v?4uaN(l>lMxZgzPkAbh0bjE>)3V$4YvGC#GQOvo1A7@lvz?yo3yCnP* z2tPx@w*^lXz65-t@Z(RQ{R>|TK0^3D@B-mag7+4_0lZlFGK;SP_XvLqyq$z!23{ll zY4DRgmPK>H>xCDhJPn@$9&jV`XHcF^C7mSjFyYHlo`y$*#|VEG=^Ne!JX!d2;D=?q z{@`iCSAg#nexv~HU-FBJYa@Jiw9z)OS|fv*<63cO1A3*e=~^TBI{uLNH% zJQKV@_>15RgiitwzKQuu;ERRFgGUHo1wKP~BzUawm%%3r4*^dR{tEbH;in!)`xjme zK3e!e@I2wKg7+7`4ZKMBYVaY#*MgS`e+|65@DFBZNQe2MTi;2z=cf-e`o47^78-@z9Mp9@|uybOGr@G0N{H#2_^e1`BO z@G#-!;1h*MgU1MeAAE%HF5t<+KL8&s+#ftm_&V_Z!jI&m{R{sPyrb~l;Dy3J0`D$- z9e9aw4|r?gtH7&-SAZYmk#@=luN7Vieo}ZQc!Tiu;0J_H0uR20`N!Z}gvWzN2;Ts{ zM|dQ7tniH%4*^dRz6rci!k>B+?O%8m_-f$?!SjS~245n48+eiMEx7M9d@XpH@K3;J zOZXMw)xx)ePZpjFPR!-J%&2@DYnl%3m&)Nk#r@-02|o@zRQPt>KTZ@r96U;RHS%eA zPjHv;9pED*d|U8T;XA>53qS5g`xm|oyua{$;040}0p3yg2Jm9xyTO|ZUjyzD{u%gT zp4Xve;5EWOM>!Zi7rb704Y82TbX}>axgpzJWTi=l*1kg9}ONOd@r_Zco*cY_xS-w(cA_&V?s;kDokgs%dxV$St@FQf9W zSyMiEt%N^-{hcP^Gr=2#e*->N_$2V)$;`ji_8>eSJVN+EZ4bgD!DEI06Zx4aJOn&N z_`kqM2tV}*+P`oD?=Acwc%JY>I4}1Xz74!c_+gxvhX`K_UM9TGN`D1-weat(^mD;U z_!01SlFoE+zuTC94}OwoBWWCXsPKQId<-8B9wodU{D6e-3GNbp6nu;Dw&1D4kAas8 zKc0v7FZ>6TbGh(+;03~eL^)Rq-vC}L{5bMy_!@AJ@Sng}OZa8rHNsDTFA+W$yk2+% z_-x@*zyoe){xkApcoKM+@RP{T0tp`t9wYo0q+@s&@MPh?f=`q1{@`iCPl1mWeq<5a zzwqBsK8EiGFBEZz3-1Z;65bB^G`uZ%s_^r`XGr+txoH2w+av$8h3^9| z5FUd3FA%-~yjb}8*skGgz&*k*0G}q|mx0#^4+S49d@gvs@DAWZgiiqvxPy5|z`INMXz&=}oxxiR?*g7IyoIto9s5bd8i_uJhVm3QN8(QfcU z2_J@hHkI(}z)OT*2!5E?iO?$WD&gHNo)2CtJlx`$;0?lifbW!aCV>a1G4BapE<7GQ zLik1CD}_gb#|pm~6;eEk}2%iq_cPI0H*skH@z(a*cp}s~)_~GDD!Y@TS zhW7+_3GWZyTf(;mPi4;adjX^J0j%lx0(h@+u?R2VNjN8s%pA2Jm9xmw_LU z@N2+5!UutG5xxw(MtBT(sqner^}+{Zf6IkW0S}nQd|d!2VWxGA3RO?<>0f0ADNH#FZ>Fvcj3Fi3x&sOKOlS^c!}^hq_aTyD)1`d zBfzH#&j+s+ekJ%=;hEqK!bgG+5k3h#_%7!0;N6ACgGUIz3i&iV5D)x7VgkJ|b*((@>s;7`_d>Ncdgg$9Q=ttpzU=emD3Y;VZzag-^$J4bKH9;rC#>2PFJ-aKC$* z--~n%9|s=Focry6bI|g1)-)VEO2XfV@H-`)p5QLwGr-G*w*^lXJ`?3^`0+Vt|H3oC zS4#MO;03}n!50hP0A4J77TSs7Yrs9i??*dXBH@>T*9gx-ehi-rUN8Is@Yxc63V1*| z^V#5&g(rcB34aiLwD4%~7~yk}Ps6)_Ckvko-e1D|gQp392wd+@cBr`@KxYd!WV$Imhk!DwZe12kMW9U$^>s<&h@*WQTamFGzmQT zJ`SIY{O^(Q@!%1{9|o88)D#IGD|`{sUm`pNJVkgO_G`89Q?t?jg+HSGnDB$(dBPVX zol@c3z>9>t!IukP3tlGtQSb%ASAbUw&j+6-JQtjVKZg9z5I!B;ZwB+n!6ynI2OcWC z0O@oWJ{&ws_!HQ#(ZYLzyM!;nevK907Ccq>Qlw+jKmGvPzwjr)M@aa6;03~$f%g`^ z0lZlFQ{e4{uL1W6e;WDkD0~@sjqpP7ro!if*9(6J>1^S3`!oeSU?%hB*e_YnPf6fm z!k@){ofIAo9wYoYq+`0P{CV)5!jEL3{R{sa^0`O&Ztz0kMc|df z*MXM^e*x(%7QPC+O883Tzf^cWc&+dkk$;m;CU}GJmynJrhe_bU8O&FKn{?vABZR*U zzFg9e1dkQ|3i7#9cnElk@M3V2&r|oK{R@8;>5P@|2f_1%uSWi73*QD_B>Xkx-=wn^ zyiEA(NN0(JUjbe%d=0osCl{QAzX3j3!cPbH%Vhp0_%z|;z(a+XfSY^{2agi|7Wfbe z-xJ&=ycB$d@V4No!run(E&TW_w1466fVUIA54=G5TJVm-H-Hxle;2%|@HOBb;eQ7| z%#YR3GVmJVW#Bu7&jqg+{vPVZ@G0N{vzV8ImrM90@G#-;qh1V;29FW`fwn6N-vvBb z_&RL2Qn){On(z<7R|`LqiS{r2BXD`%h<1Y)3in{U%Z0B4FJaF8_A89aD=J$0(<<;P z314ZYpATLue7%)^CU}GJkHKe4`jfze?`OUN*AEMX$Ad=*--zpn#lj=OV})*9-pw z+@v!FJm3N5d%(L(`bpqn!uNu=79I^ABm7GoFNSvkPZqup{1`uUN&etz!oLFFBmBq= zw146I!7GLD1}_v|i}t@o_&V?s;a}sp+bMh%c$M%2$fx1?;I+cP0WX*Encxk=zXe|@ zd=hx@Y~}}%AH(CpBZU7Ge6fU&1dkQ|FQhY3cnElka6(cPY3sVkomuHTn~}( zHfK6eVA0v<4j`AP6{;Yr|O z!hZo@DLfiHM)Q1xJPiDR@ZI2r!Y>3rEPNe!iSX{=JB6( zUM@TzyjFM*@Rh+vi6Ab6heK9%OWWr6T*;6=hO(c@b9TJSRAkx1W! zUjbe%yf64P37-p2!ux@b6+Ru@Z$9%VrGCrwShk-dp(bX=wk#qp@AX_kkA(zYN>$FX1k=c#ZJE z;2kBMx#0D}hk!Q~J_S5r0rR2AkKsw+VZw(YKdmKvGN@-~+Ep1ArQWQ&LsYxIZqCkwI z5k(`Fx{zWiw_rqL-sd^b1`_+@e!us=|GeC5cK0)9&zw1P=KPv7TlpsX1f}N?!>^Y& z(I+ZB#-s9fx<~OF56U~~UU@U)nJ!Nc!EcstrhDbt^hrvO@zL@^x~=roGW-yEG2N&1 z81I^`@=u?v_>CWySJ7{guVXxWVR?*xo6=)^ zuH01#FH-!*r^++vx62nXp7HV=`V{#L`bfD=|B}*UJWXCg|FY6Ehv83tP350HRp~K) zP+m>HL-8ALl-JPjluuzi8|8KMV);1wN_iXoE~Ur#V)=3UG^J+(!_SnbgyDB9J;np_ zO!_^F-}o4LK7G1;6yq5#FQVToA4E@<&!*p}^cX)jOXZ(lqVx=9`2F%#^sgu$f%}$k);zQ2fTX$hXqx z$~QBfHS!kvH|4A8VR?-HEqMifuH3Z@{-AsgeX2Zz{*ZhMeY`w}UMe3)A1Sx#^Llxj zyo6pRAHnb^zpC<256TD756Y|Q^W`V-(^9cUc@2Gm`~ZEUybg}@y9-pi5SwEw!@QdZg>5F>#OnFKb{9*YDh7ZUy>EDqrqK}d1(--&h;qoH-cjf%utXQ&qHvJL# zWcsoDRsQKqdij3&Dtfs*m*Ka`H_{fjyqF%5H`BXjsQlBH%Qw>x%d6;)d^LTKd@cP^ z`8xU*`Br*VzMQ^B-a`MLyp$f6$LNps^0{)?a(K0T8pBVOXV4#)PoR&N=g?QkC(}pD zZTk1+x%4!73H=HAQ2NQQsQlAc%16)-%B$%=kPo0Y%4_IP%1_`o;9?u)b@Wy8M224} zZ=?TEew5)C%a7An%UkI)2eZPDa{b%xZ^lkD@^mX#(^!4&4`p@O1^r*a@{)+~)p3Qhr-br7t z{=f0*^7KdHzf}K!5##a7v+2K5{KiMi3+XlT84N!}UQGYBd@{Z3K9zs^hF*SHUPb?n zJeT43$k)=Jk`JYCk#D7Mlqb^H$Xn>Y)o~dQ%VYGXbzB1&ey-dVg>O;c)o8<@SBjq;z8F>ReO%GZ3w`#w}SIXPye~_7T~%$EK_N)9bWfAC_0qUzFF<_sG}MU+U#s{9^fW`T_Mbjn9;) zJPvS~en{TT@ayGG^gqit)1&fs`g`)#^q{Jf9jGru4`KO;$dW;{GSJO}Rioa1_L;q0D-xrQ;l-JQa<<0b! z@;3TM@>cp{`EmMb`2qS&dCC*;kL3;YfIO4_iF^Znj69#-rSoolxV(t|seA>)C(CEk zyHy^HAG=fKpPsPY%r~xP`2F%#^u+CE{@?gE`6hZlc?H9-mp9Rq z0eL2UxO@(Mj69!yseB53xV(sdnS2~QSw5Sdi2{Y4PoN+BvdTaGa+Rye^!@Tx^btzG z@on-=^eg1K48LC9M9-2BrAOuM^pQ%B@u0ku{yBLf!%vr|uY!MG=``+@XVbHl&H)TR zT3$&1g7#~Ch`g9SN`B%}gzx&2%0K-|`2qT2c@_OC`62oq`C9sDc{6>Bd@KEG`DXeW zc?*#akt{=j$l`p4Hm1od%P+m>HK|YS&D6gUC%O}t`%IoN3<)i2;qc8 zK_4wIr2FJ^=tJbi^vUum^sXY6fBG%*arDFTD!N}jfxbt+mL8CgqHmFJrQa$aL|-Fs zq2DGyJq#X}$LK}!M24R$cl{WCyZk7_PnBoTr^s9Bzh`knGc^hS9Nob@)SwiugZ8|8Hjf0x3~VfdBuHu^OA6#8QM zar)izarBw;lr`{s|XUR9vr_0lS0{@zP zGu4{!RI0`Wkr){af-}dRQK#KPaC-pDTC$6#kHW6n&~ZgI+2hL?18Dq0f^K zrH_=`^fGxOJxyLh56X`Yg`f1R{L|;lPtXs_tLY2m2k4FR8u~(c1AU{sj{a?VGkvAJ zjlM{}nZ8(loc^$UHGQT$Wi9+W@(uKWJd?gyzJfkRo=^X-d=Y)PyommYyn>!ApG{vP zpF=-(i^@N}Tt0=qU%rZ7A)iLyCf`I4$tTd)%bVzx@=^4tyqzAF=hB1nPWn>$Q2KOv z`p@9YpVR;q(QF$|ck9;jX zD&I`sBHv2?p1hX6M&3eyOumjDmdEJT^5yioa@RWexpuavjZ zSIbAx7t4>+e|kG|4Lp;_sX;BHS%fn(egq#>g`FO+FxUHY>2#=;WsG!D2DHvr1DSyjXalrSYAbc zNfB!8uQf||qm9M6!$xG;4>>9pOep_ACy2>m>41dh4@=vdqx6=2^SJ4~fwe)TBP4w;ZX8L-06Mct# zGd(JAr#H%1(}VI(`cC;e`gD2vui(4n%jsTuHoZw+N*^sRr0CN&v^e&Ie zKmA4d6#8L#75ydo4Ei4VTKXROWcn8QR{CCfE`5!>g}zTdfgYB}=q>V5^tp0Z4g6*K zAo^5!2EA22ls;abLw`k{NFOP;>95L<4uPl1OX&OMr|Bmrs{GSmlOLiVlvmSVmp9WJ zTk;k3fIO3aP`-#hMxIZ9 zTV6pQE-#|LBcDT0md~cQ%cszfO;Gu#zbl_c-!ET9KO~<(-zMKg|Fe7)eZ9Pi{+>LS z9+kJ#56g$rgYr)LU*w7O>GJdq@b~2d=w5j?JtjXf7(QBFNIxP!Kp!G6rXQ6bqIbDf z{^=d^X8K`y75%UB&GbF;we(~12KpBHR{96>4fHkg7W&`hE9hZ)jDB3cnm$+V`VIW= z@(TJ?c?SK2d=7oQJcs^Y@9Q01R~N{P(F^{ zD6gS+%16*Q%IoMK$w$#w%G=*Y=KWO)TWDsQKsBcDSL$~)=j%BRq$%hNZ)Q{?05UU@dXzkD)%w7if$K%Pq< zA}^*7lnraa|o z_;C3YdO)5@zf?YsK1QBTzf3-vK3rZz&y?rVljXDNm&=FJkKL&9Pah#4Mc*%9MZZEm zh`vp}iJm1teLj4>yoo+ieuy5Gx6?l-KS~eEJL#X7x6-G}(>KAh<+XILJe&Rnc{6>q zypTRhzL`EmUQEAI&i@_wSXY6{Km96s1^uwRiauJtoW4iCmVULI|9kVXE%L4OYvj}D zYve8T9Qho2SRSKaE1yE2D|h`4o+}?mpDNFw=gB9~$IEl**U3lGN6Kyb82KQ2n!JR5 zy?iMBGsX83sdW_m!LN&ljJHGPacpMH~k9eudGh+ZgPPEVH4rn}{(^kZXH{^=9s)9Cx< ztLPKubLiXTo9G_-6#9C36WuExM~}+e={L(q(1Y?$`Xu=%`gD2vGjLlzi0+kV(|z*O z7JRh4kUm+S$nZnt#q?X`M;X2=U*#W;di!-ytsk3XhviiaA5i#148KRdmVT?enZ8B7 zm42IiGkuM`g*(Xkjehb5m4Eu3@;UT_@@jgqdHW&!sPx zAE)0VA4;DoPuT*WE>ENfORzbXET7HrUs3pG zhCg<_%0GREd^3H&d=>qEc>{f$d=vev@(uL$@+SIB`3ibe-cFw-Uq=thJLzAOFQ-qJ zr#}auEia{e<=OPF%PZ)k<%RS)@;US&@?!co56EZG56i3QbLErid*o~B z-<0Rlx5&5Bza^hQUn6g!KPVqX56ffphvb9kbLFnz!%O8O=u_nx^m+0D^zrf>dYSx0 z8hoVOrU&JT44)=1q0g5eW%!fVsr=Iy$Xn?L<<<0s@CCNH7?Kt6?j@>-RD`jhe*^n>zh`YQQkdZWCC{zG{#eWSdNzFIzkzEa*s z|B-wYeX;yF{m1e_^qKOM=S{u+c~I>dY>oxwnef`5DEt71A0yAF|5ScrAbhyIh`v^y z$neSX+4P^uk23tR9F>3iI(aL7zkC(_=ki1JZSqa@U&x#3>*Y=K_43X1sJxy2OL+r5 zDDR~IO1^*3w@J(GCeGh!O`m^#u^pSF#zD0g|06a}zLVr$vh<@^Fm4Ev0wtJJmpXDZSv*xfIO4_CwVD-j69$I zg1mx0TwX-4lh2_i%V*Q;3h@+_^zu| z{^>8tk23sWc@=$+yp_I3zLvgMeu%zBzLmaD-b`O3Z=tuyH`BxN82x4WYWiHcs}9~O zub@wrXV72SVb&`eA1}|Lzq-S$*Imx=Bjq-Izv3~TCNH7CCNE|9lUJ(z(_fcQqaT!4 z)7#_|=#BCk`WrjUI$q-&<#qG}@=*-GQr<>?Q|ULpSbm)TmeQZg@H6Ep_3(q*uknC9 zlm51RD8rAD=hNSjC(?(@i|Fn0qbcxY`E2^TN~iH-qg4LshvcmczhAzJ{%58C0DYT$ z6a77<{}6q>yor8T`!ybwx6}V3Z)W(Qyp#UEd^3HzJiP%PldqGq94<7Eu!y{uZ5%Degste0d^nTBHzmJe^Yv9 zF#H;M3;no!GCeGh(f{7d=gM8%;V0y|3_n$#LH{rLQ2Kaz4*eg!e5Bl_pOhyue44z3 zeoB7yT=>asm4Et&@)Puf@@jgg`~baCUPJ##-ay|ducM!qH`7JS)NN@FK?osBOgkS%G>GZ%16+H@=kh+d;opAJiQU# zUw+~oxL2M{A0R(XA1yDW50oFG50MwsQ{~O{uFt9b)6?Xw^uzKh`g!tN`X2dOx+Pyn z-y+{iPnU0?uaURV&zG;DhvhN)Ao(KtT)Ar}{DNLSRh~f~ET6&f3FOi>4hOd;j(TB+s z8Gf<+IDNSMD8tW`r|g1XDsQC+{g8yoi3ed;>jMKAS#5zL|b3 zOXZ(_g?u%AzkC%vOI|_WCf`IKDPK-sFK?oMPF_ln%G>FmmrtVy<(>3w`3(AWd3qE4 z3-ZZyuRNPRN}fv}Eia^BDIZ54A}^+2B_BcWx?#PE&s8u~c-4EjcS9lfB@ zJV#@ErM!)PW264}qZxj&{5XAlqxqe*Qu<7JN;CY6ir;uZo=Lw+K8@kW$n)W-w$@^<3u=IV`WD->UQ&-y>g3zfJKQ-y+{iFOnbSe%Hub=(o#T>0x<{K1Jy< zK3DE~3H~Le=K#Y`m1n?le%}Grei_M%jhE*z{8Ytn!jF{O^gHAYj3-TALcdeKfqwEb zm4AA%(qsIfyqbQO(zBW28|5|hY04kt8|8KMyA{9jmGU8V>}?wq~E9XENA#J@_c%U(qnwMyoml4#cw=WKAS#6UdnimU8?d=zh6F$zF)qI z{#B*N_%`__`b?!~2E(tHH_>M)J;tN*cKX*8zww~FlRjHMnej}Qr|*S-U7kz#%CqTn zlpf=w<%RTbC_UpCeu%u7{(#~!-Zfn1pFUSUg5eL#tLWd951{Xnucd!Wej*XRMZT5( zp!@)Rjl6~aki3B&mdEI&@(uL4a@Riiyk0(4oXVBB+ zCG-XI$@G)MRQ~A;<+=2O@@o3G@*4W0UcOOYM}JtJ$nY!WZS?QRk0!tu%a79+ zH=5^^jn9;)w7|cs^J_dH&!j)1^J{#JJfFU#SNy}}MfCDs=}DH)rdRX|f9w*Ke|kuM zg6Z5ZUq!E!AE0lOZ=#2L#j{@CL|-azW%#JPoxZGBJVALUy-MD|@YCh#FT*49X1Z6N zO5s`*(6`99(yQf* z=xgLHaMat&K(&u!b1W>6G5iXJpTqET<*ruv_vNMZsqzf^6Y^>F@$ww{O8E@>NV!e_ zfqXJOOL`YQQ2`ayX${fF`i^hS9NeYJcPeWSdN{v&xVeWkpO{$u%2 z`eONU`WpEN`b>GsEAXGl2haoZO!`mdgXm-A`Si8D;vX(AqW`Q{{K@j!^mTHR{$m*` z|MZ{BP5SrCSJ8hVH~F(oz6s8L7m`xD9-Cw9@3jeiy4v*I>&!%sXm(oYe3+ca+FQN~T7t^1TFQ<21r1DSSC|^xKEU%*fR=$D0 zN4}Q+w7izSMZT53N#0CfBX6PqPJVzMmdEIudOFY06(DFcro^q*ArdgI;-jz@z3AA*5xt*z8{CKhvVO&93cbAQsWnET@ow{63c@_SSbh(aqk9WB?xq^cncP0j(mdmP*4UU+tw$mS93ch+O z)ONt-N-E0;Id9=jB2)O+ocR6{;`?l)^u9Bz-p_Vj+*Z=r#H z?rr#<%e^VV?d<3Nox;NIAzys|Dh0YE{;jSd@n{Cb;ejYlS>7pTx=AK><;(q~o1beC zpC|Inmk%-p4GQ?scPM%~oWyd2u!r<<)#s=fP*YbQ2bKh(} zC!wG22v`;)$zO<9EVe1ji0oBaTs%Myj-0a5YO*>;u-aB94?p} zhZcbKTxi}&aRrzRtycSyFO1ygVpZNpWs$75%O!C#swd2QT0gn6t-;90im<-qH zVm4!n&4g{u;o(?S&;E0^Up4DY`R$wkmwur9U-Fs!KXt3gng^JMIp%aOEcxgBFTC1> zy7^z^f7oj_UD-ST>u)f2k=yA)yl%_$Y3xrPLrI0!bGytbcqV?}>lemzYh4@$pBFy` zkH_H^yqd2p!JBw~W|iDn61)+)Sc_Z?<}vm6+z~&Qcg4R~a9R3lbpgVJ>#)7hdSX}XvAg!yCv?KElMd%5o?8DO{KJ{6jdLrklt zPKa;0CLZ(qjO)O4alP2>oCKhtpNj2w$B{*SFACR={2P!(JYVMA{^1;yz3_X%0kCsW zA$4^mBPYtRrx#<9bmhXCz~4jQ@NR61m$PEDa=p&px45}ZoAX*(5HHH_6X4cf0l0bg zO?@_B^O?3c(VGA(F-hkQ49piF>yRtr&5tgVxqWmgs`cc!J%b?!?kX zJpW^#?^91yn=hU{`>WsWv-u&j*&iv(%D3?++aFC^c>N77?1+|$Q*t(iu|F+g{ePy` z7}GaRR%MsDYH)pod1zMEU<6>2W{u)Lt*Rt^{!9};;>;Cj8sa~`uNLM&KYsIU3;%?z z7#fVf7)!cJpEu+4KVO5deO_CiFrn3#$h0o=Fix|ZAvY<&ytBJG%!CH6mER5T)$ZK< zMX?9Wwui@(&mi49+~uFRQ2oqHJ#y+J^ilOGI2hUZ_=ndZX?5y*JbQIQPpeatSvI7m zFnB)qx40tSm>k8~^f(h!L(SdY4eo*#E7Z?aYM~5r}@Lkjz?iAuVzR1KBqlLa`p}usv4?R0O;!ZKI;kvS9J7U7v`ToeY zzKC7ukCby?_O9~dcfYrjNFsup9L&(CCsWu=k&_$q0WTTyy(1yg0d`o{zXf^lXbhR> zyyh(1!FQb(aZ&p1$c;@7VzHeU;`7bK!AL)Ys&S%vI$U+$!BUcuI8VgK$Ssjpv!!gSo{ zoac9T<+XMX3B7ie%h}#BzVBD>;aA_}R~MZ5>dOe(^VRMAstw4i>qvC!{Z4!o;>1TK zjz%fAqfv{E?HV3vRO5#)K^EHOJJ#am?)cyiBRt#LG4&2R^w;9NQ+A{{<5c;5?B_Ud z`y(ao9_KIq$igPS^HKDh3CQ&at?vE>vBH}Ms@t+ zyB6Vm&N5wmNiFu+Vsr7?>8I*5%ii>b_Xg3T7v=|?Clw^6XT0Zks_KwJpH=(r;L>yX zl2Y2w-QCDhA+Ei8oQsZ;x*V?XIjODo*t_z}{>JM7)x!I}@Xp{Ne8{(*6dNb~ci!+Z ztMV5pJw9h&%oVRy*T+9^8u+QHRafG(+qp9}^kTOi!5Qt|UU0w){S1e5<`8adv&SyT zFGC$Si90&T9ktocBl&s9Z0CkqXZ!oMvyACy9W%Ieps8xCivEZy;4I60gC+XO6nsMQ z&Bl)5_)F75l=E9kLwVlWKH9JyHx1L+ZIyvqLmaWn!^WrR9t54>|SyrP@=EYgINuT)Q zl-D6$dCT}0)j*wPUuz_uIA_^Q*bph_U-levCO<_Vt|Q0mOiJzE?k;GXclDXP9*n%6 zlV66)Z36SUoq7GH?JUAcy@Az4c-5!f-DdQhcPg)yC-%+(pLX;0TdAL-1?j@(%jTzT zy)g0IC2r@fBfmrKHz7Lg820UAr{5KR(-(a#|4rnhr_FhV1v}P=O2Y57Z#~a-?vgT@U(6{qlWq*zrLzM5GEZ?k%6KrLT3dFgl zK$H$}I}Psc245s~M*uAXs`{pY)d9l`j_Wj8IRoWB(?ZL3laJIXg`=8?=bQM zJ_pSQB1iZ2Cjn=l9Zl=^hpuj~)97cAZrk#7Lk+OrPZYtj7N3_J_^(AGMq9*jI|aA6#l9YjSL41?qt^G?$?rnfGmfsqjwsm)%p5 zN@UjLbab`bZRfP#IpX`U9u;YdRawJp7*m?O%xz~HI_VE&*`YnC=@E$=nTywaFJF

pTlrqu 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

Y;~-3QP$72e1Zk=at1X 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%0Dfb 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�nzdEjgXHiMh;Y@aVM3gcV%&HOWg# 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

=ba(ZOxg!4Dn$ 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ũ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≤HN0b|vfLHmCpVXe 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

EdtQ0V3t{uLu$dxKrr&&DYH54~oMW@P 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

AX=?A4K$8Q>rJ8IYf0J< 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ℜ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%0D^FhIzSxZZgDMCWUFft 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

@Ht74nrRZB)C;*tnW~p4d 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≪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

K|w` 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 z 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

GKJfcL?4cmcHAG%FyrNyhV2YQ~q&&oeECZ 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�>oj8pEFHtAyx6@A{zfJ--uTBQ(r{_U& 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 P6em?@zgPMJXoma`&wW$1 literal 0 HcmV?d00001 diff --git a/vendor/directx/d3d_compiler/d3dcompiler_47.lib b/vendor/directx/d3d_compiler/d3dcompiler_47.lib new file mode 100644 index 0000000000000000000000000000000000000000..022890ad9b9ebfc75c0b913c80d9078c948686a6 GIT binary patch literal 8512 zcmcIpy>k;s6o0n)6vh~Te_J>tKqi1BTXHg!1PRN=0vT&0dE%szW$9#VB1@W+RHTB6 zg5hsqC@51CxV51^ue{Py-f_D*{;!qUw=pYHA3{k`3NAN$r9e$1-5 z{hvM8z4qs--~MfU`Sc(D_eiG?c!RuLQN z9F4~C293YxG>6}eystTptV4g$e3jGqeaL}kfx&3(Bcn_vwvpIOrZdsi)JigzNN*-H z(Z%S>=0+kGUrlC~mMN3DyA_W&%h5f%AQwxoZ{59F7wVHCUTT;T|Un92@t2ehZcknj~ z+G1*DQtOc@rn?bYNp6P2iPgwf4D47rS8C+ZDF%+g^!sj>D!buuF#MYi*F^v*5iQoT zy7t!eM5bLPsq7UiWvQgzWS95*(`q&+Y>_au(dOvkTP+lnTwRLcHyY9BmQvToj+JY5 zwUMhsugyZCrqqRfY9WIWl1iauLoygvTfDfdX4O9|WpojP56M(rEml+e*}S4!Vj`34 z8Y@>D^;B`MoUJ!hg>AAW4K*dryx(S{-m;^tT|kVK^D+t3WejK+IX+TU*=_8_%7uze zWsA$D*qjnsRoFQUZZaX05w;^ug>|-Rdca7^YuRE6 zw&J%|J*n9EkmPFU@ znxJv=(i~0FY3ipl*8lyp)rXK1&LhnB6Vu+WUAKP$A zuC&-<0+jfb!y`4HmD+`AS-OSdTk3d1T44EE_!L9F$kr2!UD(P&j?jZoXSmWLZp*OO zR!oK>0CCGmXtn#BaDqTvb9`}6MVh!X3^<~wBmFpI(oxQ3JaBi>VhsRUXf(5iVZBa9 z^Lfv-WSgiwfoOJYkNhoSo;9G>&l!W8?cD4j*s&E|1*U29vL42ufylIc zLFBgbh$cDrqs(FF4L2V#Ap}n`d4j)~Jcri^eEGS~IJ60ZHa{}?qBmJg**VYYS@+N#3Pi1wkJ%3H?I}**?RUODn0%nrP4p3|Mc%Zyu;*ssmq0QHnJ$u3E&xW zj2|ZN%U--$wq?&y^F%Mv@Zd=_{iO+@ltxNk*csX==G029QmA_`C$D(pvAcKlcH65T zUrZlHgbdGq;i!R3&we$7K_hl*gz5`BJw2a3i9OMUn6ABKtU#DZ(|+IJXmjOwy37)j zK_@b0f)uC^7p`t8CMX0>Ne7-k25jYF6|TI&$5KWLA_% zyZ8uJv}o{|b^K|3=x=64Y}{^H$LH)d4vAQQmy3$FeQ?odEVt!@xE5-;dM$h~s4tY} z!^{W8Crn|(2bT;!^Ywp?5B<&Ly0yxmv%(jlN2jgSzi6#9!A6Pl4_Le_Yjf`J=BZl} zRN9TyA@hEb-5*-oUxD^Bs7l-q_SWs%7v>0K*^nbdWRy>+bdCx4XR_eg?mUAo^F)CL zj}X!L&E1h__q~--#o2uWygnPAd2;N)ZU$SR9ah!U^2T z-95{3#rm!TYaDFhI|C-7RXj={+m0B^E-{K7YtEUNtxD5QXc2Ppr0<}`pj``l;VS`e zcb`Kpt9}*O=S^%`RV@K;d;MEQ>>(4~t!D3p20<4KU|DLIYarYRbQ^JmBMSEo9YHh- zCP&=-8gm@wh>qKgj-a~aC3cb HRESULT, + AddRef: proc "stdcall" (this: ^IUnknown) -> ULONG, + Release: proc "stdcall" (this: ^IUnknown) -> ULONG, +} + +@(default_calling_convention="stdcall") +foreign dxgi { + CreateDXGIFactory :: proc(riid: ^IID, ppFactory: rawptr) -> HRESULT --- + CreateDXGIFactory1 :: proc(riid: ^IID, ppFactory: rawptr) -> HRESULT --- + CreateDXGIFactory2 :: proc(Flags: u32, riid: ^IID, ppFactory: rawptr) -> HRESULT --- + DXGIGetDebugInterface1 :: proc(Flags: u32, riid: ^IID, pDebug: rawptr) -> HRESULT --- +} + +CreateDXGIFactoryEx :: proc "stdcall" (riid: IID, ppFactory: rawptr) -> HRESULT { + riid := riid + return CreateDXGIFactory(&riid, ppFactory) +} +CreateDXGIFactory1Ex :: proc "stdcall" (riid: IID, ppFactory: rawptr) -> HRESULT { + riid := riid + return CreateDXGIFactory1(&riid, ppFactory) +} +CreateDXGIFactory2Ex :: proc "stdcall" (Flags: u32, riid: IID, ppFactory: rawptr) -> HRESULT { + riid := riid + return CreateDXGIFactory2(Flags, &riid, ppFactory) +} +DXGIGetDebugInterface1Ex :: proc "stdcall" (Flags: u32, riid: IID, pDebug: rawptr) -> HRESULT { + riid := riid + return DXGIGetDebugInterface1(Flags, &riid, pDebug) +} + + + +STANDARD_MULTISAMPLE_QUALITY_PATTERN :: 0xffffffff +CENTER_MULTISAMPLE_QUALITY_PATTERN :: 0xfffffffe +FORMAT_DEFINED :: 1 +_FACDXGI :: 0x87a + +CPU_ACCESS :: enum u32 { + NONE = 0, + DYNAMIC = 1, + READ_WRITE = 2, + SCRATCH = 3, + FIELD = 15, +} + +USAGE :: enum u32 { // TODO: convert to bit_set + SHADER_INPUT = 0x00000010, + RENDER_TARGET_OUTPUT = 0x00000020, + BACK_BUFFER = 0x00000040, + SHARED = 0x00000080, + READ_ONLY = 0x00000100, + DISCARD_ON_PRESENT = 0x00000200, + UNORDERED_ACCESS = 0x00000400, +} + +RESOURCE_PRIORITY :: enum u32 { + MINIMUM = 0x28000000, + LOW = 0x50000000, + NORMAL = 0x78000000, + HIGH = 0xa0000000, + MAXIMUM = 0xc8000000, +} + +MAP :: enum u32 { // TODO: convert to bit_set + READ = 1, + WRITE = 2, + DISCARD = 4, +} + +ENUM_MODES :: enum u32 { // TODO: convert to bit_set + INTERLACED = 1, + SCALING = 2, + STEREO = 4, + DISABLED_STEREO = 8, +} + +MAX_SWAP_CHAIN_BUFFERS :: 16 +PRESENT :: enum u32 { // TODO: convert to bit_set + TEST = 0x00000001, + DO_NOT_SEQUENCE = 0x00000002, + RESTART = 0x00000004, + DO_NOT_WAIT = 0x00000008, + STEREO_PREFER_RIGHT = 0x00000010, + STEREO_TEMPORARY_MONO = 0x00000020, + RESTRICT_TO_OUTPUT = 0x00000040, + USE_DURATION = 0x00000100, + ALLOW_TEARING = 0x00000200, +} + +MWA :: enum u32 { // TODO: convert to bit_set + NO_WINDOW_CHANGES = 1 << 0, + NO_ALT_ENTER = 1 << 1, + NO_PRINT_SCREEN = 1 << 2, + VALID = 0x7, +} + +SHARED_RESOURCE_READ :: 0x80000000 +SHARED_RESOURCE_WRITE :: 1 +CREATE_FACTORY_DEBUG :: 0x1 + +RATIONAL :: struct { + Numerator: u32, + Denominator: u32, +} + +SAMPLE_DESC :: struct { + Count: u32, + Quality: u32, +} + +COLOR_SPACE_TYPE :: enum i32 { + RGB_FULL_G22_NONE_P709 = 0, + RGB_FULL_G10_NONE_P709 = 1, + RGB_STUDIO_G22_NONE_P709 = 2, + RGB_STUDIO_G22_NONE_P2020 = 3, + RESERVED = 4, + YCBCR_FULL_G22_NONE_P709_X601 = 5, + YCBCR_STUDIO_G22_LEFT_P601 = 6, + YCBCR_FULL_G22_LEFT_P601 = 7, + YCBCR_STUDIO_G22_LEFT_P709 = 8, + YCBCR_FULL_G22_LEFT_P709 = 9, + YCBCR_STUDIO_G22_LEFT_P2020 = 10, + YCBCR_FULL_G22_LEFT_P2020 = 11, + RGB_FULL_G2084_NONE_P2020 = 12, + YCBCR_STUDIO_G2084_LEFT_P2020 = 13, + RGB_STUDIO_G2084_NONE_P2020 = 14, + YCBCR_STUDIO_G22_TOPLEFT_P2020 = 15, + YCBCR_STUDIO_G2084_TOPLEFT_P2020 = 16, + RGB_FULL_G22_NONE_P2020 = 17, + YCBCR_STUDIO_GHLG_TOPLEFT_P2020 = 18, + YCBCR_FULL_GHLG_TOPLEFT_P2020 = 19, + RGB_STUDIO_G24_NONE_P709 = 20, + RGB_STUDIO_G24_NONE_P2020 = 21, + YCBCR_STUDIO_G24_LEFT_P709 = 22, + YCBCR_STUDIO_G24_LEFT_P2020 = 23, + YCBCR_STUDIO_G24_TOPLEFT_P2020 = 24, + CUSTOM = -1, +} + +FORMAT :: enum i32 { + UNKNOWN = 0, + R32G32B32A32_TYPELESS = 1, + R32G32B32A32_FLOAT = 2, + R32G32B32A32_UINT = 3, + R32G32B32A32_SINT = 4, + R32G32B32_TYPELESS = 5, + R32G32B32_FLOAT = 6, + R32G32B32_UINT = 7, + R32G32B32_SINT = 8, + R16G16B16A16_TYPELESS = 9, + R16G16B16A16_FLOAT = 10, + R16G16B16A16_UNORM = 11, + R16G16B16A16_UINT = 12, + R16G16B16A16_SNORM = 13, + R16G16B16A16_SINT = 14, + R32G32_TYPELESS = 15, + R32G32_FLOAT = 16, + R32G32_UINT = 17, + R32G32_SINT = 18, + R32G8X24_TYPELESS = 19, + D32_FLOAT_S8X24_UINT = 20, + R32_FLOAT_X8X24_TYPELESS = 21, + X32_TYPELESS_G8X24_UINT = 22, + R10G10B10A2_TYPELESS = 23, + R10G10B10A2_UNORM = 24, + R10G10B10A2_UINT = 25, + R11G11B10_FLOAT = 26, + R8G8B8A8_TYPELESS = 27, + R8G8B8A8_UNORM = 28, + R8G8B8A8_UNORM_SRGB = 29, + R8G8B8A8_UINT = 30, + R8G8B8A8_SNORM = 31, + R8G8B8A8_SINT = 32, + R16G16_TYPELESS = 33, + R16G16_FLOAT = 34, + R16G16_UNORM = 35, + R16G16_UINT = 36, + R16G16_SNORM = 37, + R16G16_SINT = 38, + R32_TYPELESS = 39, + D32_FLOAT = 40, + R32_FLOAT = 41, + R32_UINT = 42, + R32_SINT = 43, + R24G8_TYPELESS = 44, + D24_UNORM_S8_UINT = 45, + R24_UNORM_X8_TYPELESS = 46, + X24_TYPELESS_G8_UINT = 47, + R8G8_TYPELESS = 48, + R8G8_UNORM = 49, + R8G8_UINT = 50, + R8G8_SNORM = 51, + R8G8_SINT = 52, + R16_TYPELESS = 53, + R16_FLOAT = 54, + D16_UNORM = 55, + R16_UNORM = 56, + R16_UINT = 57, + R16_SNORM = 58, + R16_SINT = 59, + R8_TYPELESS = 60, + R8_UNORM = 61, + R8_UINT = 62, + R8_SNORM = 63, + R8_SINT = 64, + A8_UNORM = 65, + R1_UNORM = 66, + R9G9B9E5_SHAREDEXP = 67, + R8G8_B8G8_UNORM = 68, + G8R8_G8B8_UNORM = 69, + BC1_TYPELESS = 70, + BC1_UNORM = 71, + BC1_UNORM_SRGB = 72, + BC2_TYPELESS = 73, + BC2_UNORM = 74, + BC2_UNORM_SRGB = 75, + BC3_TYPELESS = 76, + BC3_UNORM = 77, + BC3_UNORM_SRGB = 78, + BC4_TYPELESS = 79, + BC4_UNORM = 80, + BC4_SNORM = 81, + BC5_TYPELESS = 82, + BC5_UNORM = 83, + BC5_SNORM = 84, + B5G6R5_UNORM = 85, + B5G5R5A1_UNORM = 86, + B8G8R8A8_UNORM = 87, + B8G8R8X8_UNORM = 88, + R10G10B10_XR_BIAS_A2_UNORM = 89, + B8G8R8A8_TYPELESS = 90, + B8G8R8A8_UNORM_SRGB = 91, + B8G8R8X8_TYPELESS = 92, + B8G8R8X8_UNORM_SRGB = 93, + BC6H_TYPELESS = 94, + BC6H_UF16 = 95, + BC6H_SF16 = 96, + BC7_TYPELESS = 97, + BC7_UNORM = 98, + BC7_UNORM_SRGB = 99, + AYUV = 100, + Y410 = 101, + Y416 = 102, + NV12 = 103, + P010 = 104, + P016 = 105, + _420_OPAQUE = 106, + YUY2 = 107, + Y210 = 108, + Y216 = 109, + NV11 = 110, + AI44 = 111, + IA44 = 112, + P8 = 113, + A8P8 = 114, + B4G4R4A4_UNORM = 115, + + P208 = 130, + V208 = 131, + V408 = 132, + + SAMPLER_FEEDBACK_MIN_MIP_OPAQUE = 189, + SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 190, + + FORCE_UINT = -1, +} + +RGB :: struct { + Red: f32, + Green: f32, + Blue: f32, +} + +D3DCOLORVALUE :: struct { + r: f32, + g: f32, + b: f32, + a: f32, +} + +RGBA :: D3DCOLORVALUE + +GAMMA_CONTROL :: struct { + Scale: RGB, + Offset: RGB, + GammaCurve: [1025]RGB, +} + +GAMMA_CONTROL_CAPABILITIES :: struct { + ScaleAndOffsetSupported: BOOL, + MaxConvertedValue: f32, + MinConvertedValue: f32, + NumGammaControlPoints: u32, + ControlPointPositions: [1025]f32, +} + +MODE_SCANLINE_ORDER :: enum i32 { + UNSPECIFIED = 0, + PROGRESSIVE = 1, + UPPER_FIELD_FIRST = 2, + LOWER_FIELD_FIRST = 3, +} + +MODE_SCALING :: enum i32 { + UNSPECIFIED = 0, + CENTERED = 1, + STRETCHED = 2, +} + +MODE_ROTATION :: enum i32 { + UNSPECIFIED = 0, + IDENTITY = 1, + ROTATE90 = 2, + ROTATE180 = 3, + ROTATE270 = 4, +} + +MODE_DESC :: struct { + Width: u32, + Height: u32, + RefreshRate: RATIONAL, + Format: FORMAT, + ScanlineOrdering: MODE_SCANLINE_ORDER, + Scaling: MODE_SCALING, +} + +JPEG_DC_HUFFMAN_TABLE :: struct { + CodeCounts: [12]u8, + CodeValues: [12]u8, +} + +JPEG_AC_HUFFMAN_TABLE :: struct { + CodeCounts: [16]u8, + CodeValues: [162]u8, +} + +JPEG_QUANTIZATION_TABLE :: struct { + Elements: [64]u8, +} + +FRAME_STATISTICS :: struct { + PresentCount: u32, + PresentRefreshCount: u32, + SyncRefreshCount: u32, + SyncQPCTime: LARGE_INTEGER, + SyncGPUTime: LARGE_INTEGER, +} + +MAPPED_RECT :: struct { + Pitch: i32, + pBits: [^]u8, +} + +ADAPTER_DESC :: struct { + Description: [128]i16, + VendorId: u32, + DeviceId: u32, + SubSysId: u32, + Revision: u32, + DedicatedVideoMemory: SIZE_T, + DedicatedSystemMemory: SIZE_T, + SharedSystemMemory: SIZE_T, + AdapterLuid: LUID, +} + +OUTPUT_DESC :: struct { + DeviceName: [32]i16, + DesktopCoordinates: RECT, + AttachedToDesktop: BOOL, + Rotation: MODE_ROTATION, + Monitor: HMONITOR, +} + +SHARED_RESOURCE :: struct { + Handle: HANDLE, +} + +RESIDENCY :: enum i32 { + FULLY_RESIDENT = 1, + RESIDENT_IN_SHARED_MEMORY = 2, + EVICTED_TO_DISK = 3, +} + +SURFACE_DESC :: struct { + Width: u32, + Height: u32, + Format: FORMAT, + SampleDesc: SAMPLE_DESC, +} + +SWAP_EFFECT :: enum i32 { + DISCARD = 0, + SEQUENTIAL = 1, + FLIP_SEQUENTIAL = 3, + FLIP_DISCARD = 4, +} + +SWAP_CHAIN_FLAG :: enum u32 { // TODO: convert to bit_set + NONPREROTATED = 0x1, + ALLOW_MODE_SWITCH = 0x2, + GDI_COMPATIBLE = 0x4, + RESTRICTED_CONTENT = 0x8, + RESTRICT_SHARED_RESOURCE_DRIVER = 0x10, + DISPLAY_ONLY = 0x20, + FRAME_LATENCY_WAITABLE_OBJECT = 0x40, + FOREGROUND_LAYER = 0x80, + FULLSCREEN_VIDEO = 0x100, + YUV_VIDEO = 0x200, + HW_PROTECTED = 0x400, + ALLOW_TEARING = 0x800, + RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS = 0x1000, +} + +SWAP_CHAIN_DESC :: struct { + BufferDesc: MODE_DESC, + SampleDesc: SAMPLE_DESC, + BufferUsage: USAGE, + BufferCount: u32, + OutputWindow: HWND, + Windowed: BOOL, + SwapEffect: SWAP_EFFECT, + Flags: u32, +} + + +IObject_UUID :: "AEC22FB8-76F3-4639-9BE0-28EB43A67A2E" +IObject :: struct #raw_union { + #subtype iunknown: IUnknown, + using vtable: ^IObject_VTable, +} +IObject_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetPrivateData: proc "stdcall" (this: ^IObject, Name: ^GUID, DataSize: u32, pData: rawptr) -> HRESULT, + SetPrivateDataInterface: proc "stdcall" (this: ^IObject, Name: ^GUID, pUnknown: ^IUnknown) -> HRESULT, + GetPrivateData: proc "stdcall" (this: ^IObject, Name: ^GUID, pDataSize: ^u32, pData: rawptr) -> HRESULT, + GetParent: proc "stdcall" (this: ^IObject, riid: ^IID, ppParent: ^rawptr) -> HRESULT, +} + +IDeviceSubObject_UUID :: "3D3E0379-F9DE-4D58-BB6C-18D62992F1A6" +IDeviceSubObject :: struct #raw_union { + #subtype idxgiobject: IObject, + using idxgidevicesubobject_vtable: ^IDeviceSubObject_VTable, +} +IDeviceSubObject_VTable :: struct { + using idxgiobject_vtable: IObject_VTable, + GetDevice: proc "stdcall" (this: ^IDeviceSubObject, riid: ^IID, ppDevice: ^rawptr) -> HRESULT, +} + +IResource_UUID :: "035F3AB4-482E-4E50-B41F-8A7F8BD8960B" +IResource :: struct #raw_union { + #subtype idxgidevicesubobject: IDeviceSubObject, + using idxgiresource_vtable: ^IResource_VTable, +} +IResource_VTable :: struct { + using idxgidevicesubobject_vtable: IDeviceSubObject_VTable, + GetSharedHandle: proc "stdcall" (this: ^IResource, pSharedHandle: ^HANDLE) -> HRESULT, + GetUsage: proc "stdcall" (this: ^IResource, pUsage: ^USAGE) -> HRESULT, + SetEvictionPriority: proc "stdcall" (this: ^IResource, EvictionPriority: u32) -> HRESULT, + GetEvictionPriority: proc "stdcall" (this: ^IResource, pEvictionPriority: ^u32) -> HRESULT, +} + +IKeyedMutex_UUID :: "9D8E1289-D7B3-465F-8126-250E349AF85D" +IKeyedMutex :: struct #raw_union { + #subtype idxgidevicesubobject: IDeviceSubObject, + using idxgikeyedmutex_vtable: ^IKeyedMutex_VTable, +} +IKeyedMutex_VTable :: struct { + using idxgidevicesubobject_vtable: IDeviceSubObject_VTable, + AcquireSync: proc "stdcall" (this: ^IKeyedMutex, Key: u64, dwMilliseconds: u32) -> HRESULT, + ReleaseSync: proc "stdcall" (this: ^IKeyedMutex, Key: u64) -> HRESULT, +} + +ISurface_UUID :: "CAFCB56C-6AC3-4889-BF47-9E23BBD260EC" +ISurface :: struct #raw_union { + #subtype idxgidevicesubobject: IDeviceSubObject, + using idxgisurface_vtable: ^ISurface_VTable, +} +ISurface_VTable :: struct { + using idxgidevicesubobject_vtable: IDeviceSubObject_VTable, + GetDesc: proc "stdcall" (this: ^ISurface, pDesc: ^SURFACE_DESC) -> HRESULT, + Map: proc "stdcall" (this: ^ISurface, pLockedRect: ^MAPPED_RECT, MapFlags: u32) -> HRESULT, + Unmap: proc "stdcall" (this: ^ISurface) -> HRESULT, +} + +ISurface1_UUID :: "4AE63092-6327-4C1B-80AE-BFE12EA32B86" +ISurface1 :: struct #raw_union { + #subtype idxgisurface: ISurface, + using idxgisurface1_vtable: ^ISurface1_VTable, +} +ISurface1_VTable :: struct { + using idxgisurface_vtable: ISurface_VTable, + GetDC: proc "stdcall" (this: ^ISurface1, Discard: BOOL, phdc: ^HDC) -> HRESULT, + ReleaseDC: proc "stdcall" (this: ^ISurface1, pDirtyRect: ^RECT) -> HRESULT, +} + +IAdapter_UUID :: "2411E7E1-12AC-4CCF-BD14-9798E8534DC0" +IAdapter :: struct #raw_union { + #subtype idxgiobject: IObject, + using idxgiadapter_vtable: ^IAdapter_VTable, +} +IAdapter_VTable :: struct { + using idxgiobject_vtable: IObject_VTable, + EnumOutputs: proc "stdcall" (this: ^IAdapter, Output: u32, ppOutput: ^^IOutput) -> HRESULT, + GetDesc: proc "stdcall" (this: ^IAdapter, pDesc: ^ADAPTER_DESC) -> HRESULT, + CheckInterfaceSupport: proc "stdcall" (this: ^IAdapter, InterfaceName: ^GUID, pUMDVersion: ^LARGE_INTEGER) -> HRESULT, +} + +IOutput_UUID :: "AE02EEDB-C735-4690-8D52-5A8DC20213AA" +IOutput :: struct #raw_union { + #subtype idxgiobject: IObject, + using idxgioutput_vtable: ^IOutput_VTable, +} +IOutput_VTable :: struct { + using idxgiobject_vtable: IObject_VTable, + GetDesc: proc "stdcall" (this: ^IOutput, pDesc: ^OUTPUT_DESC) -> HRESULT, + GetDisplayModeList: proc "stdcall" (this: ^IOutput, EnumFormat: FORMAT, Flags: u32, pNumModes: ^u32, pDesc: ^MODE_DESC) -> HRESULT, + FindClosestMatchingMode: proc "stdcall" (this: ^IOutput, pModeToMatch: ^MODE_DESC, pClosestMatch: ^MODE_DESC, pConcernedDevice: ^IUnknown) -> HRESULT, + WaitForVBlank: proc "stdcall" (this: ^IOutput) -> HRESULT, + TakeOwnership: proc "stdcall" (this: ^IOutput, pDevice: ^IUnknown, Exclusive: BOOL) -> HRESULT, + ReleaseOwnership: proc "stdcall" (this: ^IOutput), + GetGammaControlCapabilities: proc "stdcall" (this: ^IOutput, pGammaCaps: ^GAMMA_CONTROL_CAPABILITIES) -> HRESULT, + SetGammaControl: proc "stdcall" (this: ^IOutput, pArray: ^GAMMA_CONTROL) -> HRESULT, + GetGammaControl: proc "stdcall" (this: ^IOutput, pArray: ^GAMMA_CONTROL) -> HRESULT, + SetDisplaySurface: proc "stdcall" (this: ^IOutput, pScanoutSurface: ^ISurface) -> HRESULT, + GetDisplaySurfaceData: proc "stdcall" (this: ^IOutput, pDestination: ^ISurface) -> HRESULT, + GetFrameStatistics: proc "stdcall" (this: ^IOutput, pStats: ^FRAME_STATISTICS) -> HRESULT, +} + +ISwapChain_UUID :: "310D36A0-D2E7-4C0A-AA04-6A9D23B8886A" +ISwapChain :: struct #raw_union { + #subtype idxgidevicesubobject: IDeviceSubObject, + using idxgiswapchain_vtable: ^ISwapChain_VTable, +} +ISwapChain_VTable :: struct { + using idxgidevicesubobject_vtable: IDeviceSubObject_VTable, + Present: proc "stdcall" (this: ^ISwapChain, SyncInterval: u32, Flags: u32) -> HRESULT, + GetBuffer: proc "stdcall" (this: ^ISwapChain, Buffer: u32, riid: ^IID, ppSurface: ^rawptr) -> HRESULT, + SetFullscreenState: proc "stdcall" (this: ^ISwapChain, Fullscreen: BOOL, pTarget: ^IOutput) -> HRESULT, + GetFullscreenState: proc "stdcall" (this: ^ISwapChain, pFullscreen: ^BOOL, ppTarget: ^^IOutput) -> HRESULT, + GetDesc: proc "stdcall" (this: ^ISwapChain, pDesc: ^SWAP_CHAIN_DESC) -> HRESULT, + ResizeBuffers: proc "stdcall" (this: ^ISwapChain, BufferCount: u32, Width: u32, Height: u32, NewFormat: FORMAT, SwapChainFlags: u32) -> HRESULT, + ResizeTarget: proc "stdcall" (this: ^ISwapChain, pNewTargetParameters: ^MODE_DESC) -> HRESULT, + GetContainingOutput: proc "stdcall" (this: ^ISwapChain, ppOutput: ^^IOutput) -> HRESULT, + GetFrameStatistics: proc "stdcall" (this: ^ISwapChain, pStats: ^FRAME_STATISTICS) -> HRESULT, + GetLastPresentCount: proc "stdcall" (this: ^ISwapChain, pLastPresentCount: ^u32) -> HRESULT, +} + +IFactory_UUID :: "7B7166EC-21C7-44AE-B21A-C9AE321AE369" +IFactory :: struct #raw_union { + #subtype idxgiobject: IObject, + using idxgifactory_vtable: ^IFactory_VTable, +} +IFactory_VTable :: struct { + using idxgiobject_vtable: IObject_VTable, + EnumAdapters: proc "stdcall" (this: ^IFactory, Adapter: u32, ppAdapter: ^^IAdapter) -> HRESULT, + MakeWindowAssociation: proc "stdcall" (this: ^IFactory, WindowHandle: HWND, Flags: u32) -> HRESULT, + GetWindowAssociation: proc "stdcall" (this: ^IFactory, pWindowHandle: ^HWND) -> HRESULT, + CreateSwapChain: proc "stdcall" (this: ^IFactory, pDevice: ^IUnknown, pDesc: ^SWAP_CHAIN_DESC, ppSwapChain: ^^ISwapChain) -> HRESULT, + CreateSoftwareAdapter: proc "stdcall" (this: ^IFactory, Module: HMODULE, ppAdapter: ^^IAdapter) -> HRESULT, +} +IDevice_UUID :: "54EC77FA-1377-44E6-8C32-88FD5F44C84C" +IDevice :: struct #raw_union { + #subtype idxgiobject: IObject, + using idxgidevice_vtable: ^IDevice_VTable, +} +IDevice_VTable :: struct { + using idxgiobject_vtable: IObject_VTable, + GetAdapter: proc "stdcall" (this: ^IDevice, pAdapter: ^^IAdapter) -> HRESULT, + CreateSurface: proc "stdcall" (this: ^IDevice, pDesc: ^SURFACE_DESC, NumSurfaces: u32, Usage: USAGE, pSharedResource: ^SHARED_RESOURCE, ppSurface: ^^ISurface) -> HRESULT, + QueryResourceResidency: proc "stdcall" (this: ^IDevice, ppResources: ^^IUnknown, pResidencyStatus: ^RESIDENCY, NumResources: u32) -> HRESULT, + SetGPUThreadPriority: proc "stdcall" (this: ^IDevice, Priority: i32) -> HRESULT, + GetGPUThreadPriority: proc "stdcall" (this: ^IDevice, pPriority: ^i32) -> HRESULT, +} +ADAPTER_FLAG :: enum u32 { // TODO: convert to bit_set + NONE = 0x0, + REMOTE = 0x1, + SOFTWARE = 0x2, + FORCE_DWORD = 0xffffffff, +} + +ADAPTER_DESC1 :: struct { + Description: [128]i16, + VendorId: u32, + DeviceId: u32, + SubSysId: u32, + Revision: u32, + DedicatedVideoMemory: SIZE_T, + DedicatedSystemMemory: SIZE_T, + SharedSystemMemory: SIZE_T, + AdapterLuid: LUID, + Flags: u32, +} + +DISPLAY_COLOR_SPACE :: struct { + PrimaryCoordinates: [8][2]f32, + WhitePoints: [16][2]f32, +} + + +IFactory1_UUID :: "770AAE78-F26F-4DBA-A829-253C83D1B387" +IFactory1 :: struct #raw_union { + #subtype idxgifactory: IFactory, + using idxgifactory1_vtable: ^IFactory1_VTable, +} +IFactory1_VTable :: struct { + using idxgifactory_vtable: IFactory_VTable, + EnumAdapters1: proc "stdcall" (this: ^IFactory1, Adapter: u32, ppAdapter: ^^IAdapter1) -> HRESULT, + IsCurrent: proc "stdcall" (this: ^IFactory1) -> BOOL, +} + +IAdapter1_UUID :: "29038F61-3839-4626-91FD-086879011A05" +IAdapter1 :: struct #raw_union { + #subtype idxgiadapter: IAdapter, + using idxgiadapter1_vtable: ^IAdapter1_VTable, +} +IAdapter1_VTable :: struct { + using idxgiadapter_vtable: IAdapter_VTable, + GetDesc1: proc "stdcall" (this: ^IAdapter1, pDesc: ^ADAPTER_DESC1) -> HRESULT, +} + +IDevice1_UUID :: "77DB970F-6276-48BA-BA28-070143B4392C" +IDevice1 :: struct #raw_union { + #subtype idxgidevice: IDevice, + using idxgidevice1_vtable: ^IDevice1_VTable, +} +IDevice1_VTable :: struct { + using idxgidevice_vtable: IDevice_VTable, + SetMaximumFrameLatency: proc "stdcall" (this: ^IDevice1, MaxLatency: u32) -> HRESULT, + GetMaximumFrameLatency: proc "stdcall" (this: ^IDevice1, pMaxLatency: ^u32) -> HRESULT, +} + +IDisplayControl_UUID :: "EA9DBF1A-C88E-4486-854A-98AA0138F30C" +IDisplayControl :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxgidisplaycontrol_vtable: ^IDisplayControl_VTable, +} +IDisplayControl_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + IsStereoEnabled: proc "stdcall" (this: ^IDisplayControl) -> BOOL, + SetStereoEnabled: proc "stdcall" (this: ^IDisplayControl, enabled: BOOL), +} +OUTDUPL_MOVE_RECT :: struct { + SourcePoint: POINT, + DestinationRect: RECT, +} + +OUTDUPL_DESC :: struct { + ModeDesc: MODE_DESC, + Rotation: MODE_ROTATION, + DesktopImageInSystemMemory: BOOL, +} + +OUTDUPL_POINTER_POSITION :: struct { + Position: POINT, + Visible: BOOL, +} + +OUTDUPL_POINTER_SHAPE_TYPE :: enum i32 { + MONOCHROME = 1, + COLOR = 2, + MASKED_COLOR = 4, +} + +OUTDUPL_POINTER_SHAPE_INFO :: struct { + Type: u32, + Width: u32, + Height: u32, + Pitch: u32, + HotSpot: POINT, +} + +OUTDUPL_FRAME_INFO :: struct { + LastPresentTime: LARGE_INTEGER, + LastMouseUpdateTime: LARGE_INTEGER, + AccumulatedFrames: u32, + RectsCoalesced: BOOL, + ProtectedContentMaskedOut: BOOL, + PointerPosition: OUTDUPL_POINTER_POSITION, + TotalMetadataBufferSize: u32, + PointerShapeBufferSize: u32, +} + + +IOutputDuplication_UUID :: "191CFAC3-A341-470D-B26E-A864F428319C" +IOutputDuplication :: struct #raw_union { + #subtype idxgiobject: IObject, + using idxgioutputduplication_vtable: ^IOutputDuplication_VTable, +} +IOutputDuplication_VTable :: struct { + using idxgiobject_vtable: IObject_VTable, + GetDesc: proc "stdcall" (this: ^IOutputDuplication, pDesc: ^OUTDUPL_DESC), + AcquireNextFrame: proc "stdcall" (this: ^IOutputDuplication, TimeoutInMilliseconds: u32, pFrameInfo: ^OUTDUPL_FRAME_INFO, ppDesktopResource: ^^IResource) -> HRESULT, + GetFrameDirtyRects: proc "stdcall" (this: ^IOutputDuplication, DirtyRectsBufferSize: u32, pDirtyRectsBuffer: ^RECT, pDirtyRectsBufferSizeRequired: ^u32) -> HRESULT, + GetFrameMoveRects: proc "stdcall" (this: ^IOutputDuplication, MoveRectsBufferSize: u32, pMoveRectBuffer: ^OUTDUPL_MOVE_RECT, pMoveRectsBufferSizeRequired: ^u32) -> HRESULT, + GetFramePointerShape: proc "stdcall" (this: ^IOutputDuplication, PointerShapeBufferSize: u32, pPointerShapeBuffer: rawptr, pPointerShapeBufferSizeRequired: ^u32, pPointerShapeInfo: ^OUTDUPL_POINTER_SHAPE_INFO) -> HRESULT, + MapDesktopSurface: proc "stdcall" (this: ^IOutputDuplication, pLockedRect: ^MAPPED_RECT) -> HRESULT, + UnMapDesktopSurface: proc "stdcall" (this: ^IOutputDuplication) -> HRESULT, + ReleaseFrame: proc "stdcall" (this: ^IOutputDuplication) -> HRESULT, +} +ALPHA_MODE :: enum i32 { + UNSPECIFIED = 0, + PREMULTIPLIED = 1, + STRAIGHT = 2, + IGNORE = 3, + FORCE_DWORD = -1, +} + + +ISurface2_UUID :: "ABA496DD-B617-4CB8-A866-BC44D7EB1FA2" +ISurface2 :: struct #raw_union { + #subtype idxgisurface1: ISurface1, + using idxgisurface2_vtable: ^ISurface2_VTable, +} +ISurface2_VTable :: struct { + using idxgisurface1_vtable: ISurface1_VTable, + GetResource: proc "stdcall" (this: ^ISurface2, riid: ^IID, ppParentResource: ^rawptr, pSubresourceIndex: ^u32) -> HRESULT, +} + +IResource1_UUID :: "30961379-4609-4A41-998E-54FE567EE0C1" +IResource1 :: struct #raw_union { + #subtype idxgiresource: IResource, + using idxgiresource1_vtable: ^IResource1_VTable, +} +IResource1_VTable :: struct { + using idxgiresource_vtable: IResource_VTable, + CreateSubresourceSurface: proc "stdcall" (this: ^IResource1, index: u32, ppSurface: ^^ISurface2) -> HRESULT, + CreateSharedHandle: proc "stdcall" (this: ^IResource1, pAttributes: ^win32.SECURITY_ATTRIBUTES, dwAccess: u32, lpName: ^i16, pHandle: ^HANDLE) -> HRESULT, +} +OFFER_RESOURCE_PRIORITY :: enum i32 { + LOW = 1, + NORMAL = 2, + HIGH = 3, +} + + +IDevice2_UUID :: "05008617-FBFD-4051-A790-144884B4F6A9" +IDevice2 :: struct #raw_union { + #subtype idxgidevice1: IDevice1, + using idxgidevice2_vtable: ^IDevice2_VTable, +} +IDevice2_VTable :: struct { + using idxgidevice1_vtable: IDevice1_VTable, + OfferResources: proc "stdcall" (this: ^IDevice2, NumResources: u32, ppResources: ^^IResource, Priority: OFFER_RESOURCE_PRIORITY) -> HRESULT, + ReclaimResources: proc "stdcall" (this: ^IDevice2, NumResources: u32, ppResources: ^^IResource, pDiscarded: ^BOOL) -> HRESULT, + EnqueueSetEvent: proc "stdcall" (this: ^IDevice2, hEvent: HANDLE) -> HRESULT, +} +MODE_DESC1 :: struct { + Width: u32, + Height: u32, + RefreshRate: RATIONAL, + Format: FORMAT, + ScanlineOrdering: MODE_SCANLINE_ORDER, + Scaling: MODE_SCALING, + Stereo: BOOL, +} + +SCALING :: enum i32 { + STRETCH = 0, + NONE = 1, + ASPECT_RATIO_STRETCH = 2, +} + +SWAP_CHAIN_DESC1 :: struct { + Width: u32, + Height: u32, + Format: FORMAT, + Stereo: BOOL, + SampleDesc: SAMPLE_DESC, + BufferUsage: USAGE, + BufferCount: u32, + Scaling: SCALING, + SwapEffect: SWAP_EFFECT, + AlphaMode: ALPHA_MODE, + Flags: u32, +} + +SWAP_CHAIN_FULLSCREEN_DESC :: struct { + RefreshRate: RATIONAL, + ScanlineOrdering: MODE_SCANLINE_ORDER, + Scaling: MODE_SCALING, + Windowed: BOOL, +} + +PRESENT_PARAMETERS :: struct { + DirtyRectsCount: u32, + + pDirtyRects: [^]RECT, + pScrollRect: ^RECT, + pScrollOffset: ^POINT, +} + + +ISwapChain1_UUID :: "790A45F7-0D42-4876-983A-0A55CFE6F4AA" +ISwapChain1 :: struct #raw_union { + #subtype idxgiswapchain: ISwapChain, + using idxgiswapchain1_vtable: ^ISwapChain1_VTable, +} +ISwapChain1_VTable :: struct { + using idxgiswapchain_vtable: ISwapChain_VTable, + GetDesc1: proc "stdcall" (this: ^ISwapChain1, pDesc: ^SWAP_CHAIN_DESC1) -> HRESULT, + GetFullscreenDesc: proc "stdcall" (this: ^ISwapChain1, pDesc: ^SWAP_CHAIN_FULLSCREEN_DESC) -> HRESULT, + GetHwnd: proc "stdcall" (this: ^ISwapChain1, pHwnd: ^HWND) -> HRESULT, + GetCoreWindow: proc "stdcall" (this: ^ISwapChain1, refiid: ^IID, ppUnk: ^rawptr) -> HRESULT, + Present1: proc "stdcall" (this: ^ISwapChain1, SyncInterval: u32, PresentFlags: u32, pPresentParameters: ^PRESENT_PARAMETERS) -> HRESULT, + IsTemporaryMonoSupported: proc "stdcall" (this: ^ISwapChain1) -> BOOL, + GetRestrictToOutput: proc "stdcall" (this: ^ISwapChain1, ppRestrictToOutput: ^^IOutput) -> HRESULT, + SetBackgroundColor: proc "stdcall" (this: ^ISwapChain1, pColor: ^RGBA) -> HRESULT, + GetBackgroundColor: proc "stdcall" (this: ^ISwapChain1, pColor: ^RGBA) -> HRESULT, + SetRotation: proc "stdcall" (this: ^ISwapChain1, Rotation: MODE_ROTATION) -> HRESULT, + GetRotation: proc "stdcall" (this: ^ISwapChain1, pRotation: ^MODE_ROTATION) -> HRESULT, +} + +IFactory2_UUID :: "50C83A1C-E072-4C48-87B0-3630FA36A6D0" +IFactory2 :: struct #raw_union { + #subtype idxgifactory1: IFactory1, + using idxgifactory2_vtable: ^IFactory2_VTable, +} +IFactory2_VTable :: struct { + using idxgifactory1_vtable: IFactory1_VTable, + IsWindowedStereoEnabled: proc "stdcall" (this: ^IFactory2) -> BOOL, + CreateSwapChainForHwnd: proc "stdcall" (this: ^IFactory2, pDevice: ^IUnknown, hWnd: HWND, pDesc: ^SWAP_CHAIN_DESC1, pFullscreenDesc: ^SWAP_CHAIN_FULLSCREEN_DESC, pRestrictToOutput: ^IOutput, ppSwapChain: ^^ISwapChain1) -> HRESULT, + CreateSwapChainForCoreWindow: proc "stdcall" (this: ^IFactory2, pDevice: ^IUnknown, pWindow: ^IUnknown, pDesc: ^SWAP_CHAIN_DESC1, pRestrictToOutput: ^IOutput, ppSwapChain: ^^ISwapChain1) -> HRESULT, + GetSharedResourceAdapterLuid: proc "stdcall" (this: ^IFactory2, hResource: HANDLE, pLuid: ^LUID) -> HRESULT, + RegisterStereoStatusWindow: proc "stdcall" (this: ^IFactory2, WindowHandle: HWND, wMsg: u32, pdwCookie: ^u32) -> HRESULT, + RegisterStereoStatusEvent: proc "stdcall" (this: ^IFactory2, hEvent: HANDLE, pdwCookie: ^u32) -> HRESULT, + UnregisterStereoStatus: proc "stdcall" (this: ^IFactory2, dwCookie: u32), + RegisterOcclusionStatusWindow: proc "stdcall" (this: ^IFactory2, WindowHandle: HWND, wMsg: u32, pdwCookie: ^u32) -> HRESULT, + RegisterOcclusionStatusEvent: proc "stdcall" (this: ^IFactory2, hEvent: HANDLE, pdwCookie: ^u32) -> HRESULT, + UnregisterOcclusionStatus: proc "stdcall" (this: ^IFactory2, dwCookie: u32), + CreateSwapChainForComposition: proc "stdcall" (this: ^IFactory2, pDevice: ^IUnknown, pDesc: ^SWAP_CHAIN_DESC1, pRestrictToOutput: ^IOutput, ppSwapChain: ^^ISwapChain1) -> HRESULT, +} +GRAPHICS_PREEMPTION_GRANULARITY :: enum i32 { + DMA_BUFFER_BOUNDARY = 0, + PRIMITIVE_BOUNDARY = 1, + TRIANGLE_BOUNDARY = 2, + PIXEL_BOUNDARY = 3, + INSTRUCTION_BOUNDARY = 4, +} + +COMPUTE_PREEMPTION_GRANULARITY :: enum i32 { + DMA_BUFFER_BOUNDARY = 0, + DISPATCH_BOUNDARY = 1, + THREAD_GROUP_BOUNDARY = 2, + THREAD_BOUNDARY = 3, + INSTRUCTION_BOUNDARY = 4, +} + +ADAPTER_DESC2 :: struct { + Description: [128]i16, + VendorId: u32, + DeviceId: u32, + SubSysId: u32, + Revision: u32, + DedicatedVideoMemory: SIZE_T, + DedicatedSystemMemory: SIZE_T, + SharedSystemMemory: SIZE_T, + AdapterLuid: LUID, + Flags: u32, + GraphicsPreemptionGranularity: GRAPHICS_PREEMPTION_GRANULARITY, + ComputePreemptionGranularity: COMPUTE_PREEMPTION_GRANULARITY, +} + + +IAdapter2_UUID :: "0AA1AE0A-FA0E-4B84-8644-E05FF8E5ACB5" +IAdapter2 :: struct #raw_union { + #subtype idxgiadapter1: IAdapter1, + using idxgiadapter2_vtable: ^IAdapter2_VTable, +} +IAdapter2_VTable :: struct { + using idxgiadapter1_vtable: IAdapter1_VTable, + GetDesc2: proc "stdcall" (this: ^IAdapter2, pDesc: ^ADAPTER_DESC2) -> HRESULT, +} + +IOutput1_UUID :: "00CDDEA8-939B-4B83-A340-A685226666CC" +IOutput1 :: struct #raw_union { + #subtype idxgioutput: IOutput, + using idxgioutput1_vtable: ^IOutput1_VTable, +} +IOutput1_VTable :: struct { + using idxgioutput_vtable: IOutput_VTable, + GetDisplayModeList1: proc "stdcall" (this: ^IOutput1, EnumFormat: FORMAT, Flags: u32, pNumModes: ^u32, pDesc: ^MODE_DESC1) -> HRESULT, + FindClosestMatchingMode1: proc "stdcall" (this: ^IOutput1, pModeToMatch: ^MODE_DESC1, pClosestMatch: ^MODE_DESC1, pConcernedDevice: ^IUnknown) -> HRESULT, + GetDisplaySurfaceData1: proc "stdcall" (this: ^IOutput1, pDestination: ^IResource) -> HRESULT, + DuplicateOutput: proc "stdcall" (this: ^IOutput1, pDevice: ^IUnknown, ppOutputDuplication: ^^IOutputDuplication) -> HRESULT, +} +IDevice3_UUID :: "6007896C-3244-4AFD-BF18-A6D3BEDA5023" +IDevice3 :: struct #raw_union { + #subtype idxgidevice2: IDevice2, + using idxgidevice3_vtable: ^IDevice3_VTable, +} +IDevice3_VTable :: struct { + using idxgidevice2_vtable: IDevice2_VTable, + Trim: proc "stdcall" (this: ^IDevice3), +} +MATRIX_3X2_F :: struct { + _11: f32, + _12: f32, + _21: f32, + _22: f32, + _31: f32, + _32: f32, +} + + +ISwapChain2_UUID :: "A8BE2AC4-199F-4946-B331-79599FB98DE7" +ISwapChain2 :: struct #raw_union { + #subtype idxgiswapchain1: ISwapChain1, + using idxgiswapchain2_vtable: ^ISwapChain2_VTable, +} +ISwapChain2_VTable :: struct { + using idxgiswapchain1_vtable: ISwapChain1_VTable, + SetSourceSize: proc "stdcall" (this: ^ISwapChain2, Width: u32, Height: u32) -> HRESULT, + GetSourceSize: proc "stdcall" (this: ^ISwapChain2, pWidth: ^u32, pHeight: ^u32) -> HRESULT, + SetMaximumFrameLatency: proc "stdcall" (this: ^ISwapChain2, MaxLatency: u32) -> HRESULT, + GetMaximumFrameLatency: proc "stdcall" (this: ^ISwapChain2, pMaxLatency: ^u32) -> HRESULT, + GetFrameLatencyWaitableObject: proc "stdcall" (this: ^ISwapChain2) -> HANDLE, + SetMatrixTransform: proc "stdcall" (this: ^ISwapChain2, pMatrix: ^MATRIX_3X2_F) -> HRESULT, + GetMatrixTransform: proc "stdcall" (this: ^ISwapChain2, pMatrix: ^MATRIX_3X2_F) -> HRESULT, +} + +IOutput2_UUID :: "595E39D1-2724-4663-99B1-DA969DE28364" +IOutput2 :: struct #raw_union { + #subtype idxgioutput1: IOutput1, + using idxgioutput2_vtable: ^IOutput2_VTable, +} +IOutput2_VTable :: struct { + using idxgioutput1_vtable: IOutput1_VTable, + SupportsOverlays: proc "stdcall" (this: ^IOutput2) -> BOOL, +} + +IFactory3_UUID :: "25483823-CD46-4C7D-86CA-47AA95B837BD" +IFactory3 :: struct #raw_union { + #subtype idxgifactory2: IFactory2, + using idxgifactory3_vtable: ^IFactory3_VTable, +} +IFactory3_VTable :: struct { + using idxgifactory2_vtable: IFactory2_VTable, + GetCreationFlags: proc "stdcall" (this: ^IFactory3) -> u32, +} +DECODE_SWAP_CHAIN_DESC :: struct { + Flags: u32, +} + +MULTIPLANE_OVERLAY_YCbCr_FLAGS :: enum u32 { // TODO: convert to bit_set + NOMINAL_RANGE = 0x1, + BT709 = 0x2, + xvYCC = 0x4, +} + + +IDecodeSwapChain_UUID :: "2633066B-4514-4C7A-8FD8-12EA98059D18" +IDecodeSwapChain :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxgidecodeswapchain_vtable: ^IDecodeSwapChain_VTable, +} +IDecodeSwapChain_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + PresentBuffer: proc "stdcall" (this: ^IDecodeSwapChain, BufferToPresent: u32, SyncInterval: u32, Flags: u32) -> HRESULT, + SetSourceRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT, + SetTargetRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT, + SetDestSize: proc "stdcall" (this: ^IDecodeSwapChain, Width: u32, Height: u32) -> HRESULT, + GetSourceRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT, + GetTargetRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT, + GetDestSize: proc "stdcall" (this: ^IDecodeSwapChain, pWidth: ^u32, pHeight: ^u32) -> HRESULT, + SetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain, ColorSpace: MULTIPLANE_OVERLAY_YCbCr_FLAGS) -> HRESULT, + GetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain) -> MULTIPLANE_OVERLAY_YCbCr_FLAGS, +} + +IFactoryMedia_UUID :: "41E7D1F2-A591-4F7B-A2E5-FA9C843E1C12" +IFactoryMedia :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxgifactorymedia_vtable: ^IFactoryMedia_VTable, +} +IFactoryMedia_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + CreateSwapChainForCompositionSurfaceHandle: proc "stdcall" (this: ^IFactoryMedia, pDevice: ^IUnknown, hSurface: HANDLE, pDesc: ^SWAP_CHAIN_DESC1, pRestrictToOutput: ^IOutput, ppSwapChain: ^^ISwapChain1) -> HRESULT, + CreateDecodeSwapChainForCompositionSurfaceHandle: proc "stdcall" (this: ^IFactoryMedia, pDevice: ^IUnknown, hSurface: HANDLE, pDesc: ^DECODE_SWAP_CHAIN_DESC, pYuvDecodeBuffers: ^IResource, pRestrictToOutput: ^IOutput, ppSwapChain: ^^IDecodeSwapChain) -> HRESULT, +} +FRAME_PRESENTATION_MODE :: enum i32 { + COMPOSED = 0, + OVERLAY = 1, + NONE = 2, + COMPOSITION_FAILURE = 3, +} + +FRAME_STATISTICS_MEDIA :: struct { + PresentCount: u32, + PresentRefreshCount: u32, + SyncRefreshCount: u32, + SyncQPCTime: LARGE_INTEGER, + SyncGPUTime: LARGE_INTEGER, + CompositionMode: FRAME_PRESENTATION_MODE, + ApprovedPresentDuration: u32, +} + + +ISwapChainMedia_UUID :: "DD95B90B-F05F-4F6A-BD65-25BFB264BD84" +ISwapChainMedia :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxgiswapchainmedia_vtable: ^ISwapChainMedia_VTable, +} +ISwapChainMedia_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetFrameStatisticsMedia: proc "stdcall" (this: ^ISwapChainMedia, pStats: ^FRAME_STATISTICS_MEDIA) -> HRESULT, + SetPresentDuration: proc "stdcall" (this: ^ISwapChainMedia, Duration: u32) -> HRESULT, + CheckPresentDurationSupport: proc "stdcall" (this: ^ISwapChainMedia, DesiredPresentDuration: u32, pClosestSmallerPresentDuration: ^u32, pClosestLargerPresentDuration: ^u32) -> HRESULT, +} +OVERLAY_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set + DIRECT = 0x1, + SCALING = 0x2, +} + + +IOutput3_UUID :: "8A6BB301-7E7E-41F4-A8E0-5B32F7F99B18" +IOutput3 :: struct #raw_union { + #subtype idxgioutput2: IOutput2, + using idxgioutput3_vtable: ^IOutput3_VTable, +} +IOutput3_VTable :: struct { + using idxgioutput2_vtable: IOutput2_VTable, + CheckOverlaySupport: proc "stdcall" (this: ^IOutput3, EnumFormat: FORMAT, pConcernedDevice: ^IUnknown, pFlags: ^u32) -> HRESULT, +} +SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set + PRESENT = 0x1, + OVERLAY_PRESENT = 0x2, +} + + +ISwapChain3_UUID :: "94D99BDB-F1F8-4AB0-B236-7DA0170EDAB1" +ISwapChain3 :: struct #raw_union { + #subtype idxgiswapchain2: ISwapChain2, + using idxgiswapchain3_vtable: ^ISwapChain3_VTable, +} +ISwapChain3_VTable :: struct { + using idxgiswapchain2_vtable: ISwapChain2_VTable, + GetCurrentBackBufferIndex: proc "stdcall" (this: ^ISwapChain3) -> u32, + CheckColorSpaceSupport: proc "stdcall" (this: ^ISwapChain3, ColorSpace: COLOR_SPACE_TYPE, pColorSpaceSupport: ^u32) -> HRESULT, + SetColorSpace1: proc "stdcall" (this: ^ISwapChain3, ColorSpace: COLOR_SPACE_TYPE) -> HRESULT, + ResizeBuffers1: proc "stdcall" (this: ^ISwapChain3, BufferCount: u32, Width: u32, Height: u32, Format: FORMAT, SwapChainFlags: u32, pCreationNodeMask: ^u32, ppPresentQueue: ^^IUnknown) -> HRESULT, +} +OVERLAY_COLOR_SPACE_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set + PRESENT = 0x1, +} + + +IOutput4_UUID :: "DC7DCA35-2196-414D-9F53-617884032A60" +IOutput4 :: struct #raw_union { + #subtype idxgioutput3: IOutput3, + using idxgioutput4_vtable: ^IOutput4_VTable, +} +IOutput4_VTable :: struct { + using idxgioutput3_vtable: IOutput3_VTable, + CheckOverlayColorSpaceSupport: proc "stdcall" (this: ^IOutput4, Format: FORMAT, ColorSpace: COLOR_SPACE_TYPE, pConcernedDevice: ^IUnknown, pFlags: ^u32) -> HRESULT, +} + +IFactory4_UUID :: "1BC6EA02-EF36-464F-BF0C-21CA39E5168A" +IFactory4 :: struct #raw_union { + #subtype idxgifactory3: IFactory3, + using idxgifactory4_vtable: ^IFactory4_VTable, +} +IFactory4_VTable :: struct { + using idxgifactory3_vtable: IFactory3_VTable, + EnumAdapterByLuid: proc "stdcall" (this: ^IFactory4, AdapterLuid: LUID, riid: ^IID, ppvAdapter: ^rawptr) -> HRESULT, + EnumWarpAdapter: proc "stdcall" (this: ^IFactory4, riid: ^IID, ppvAdapter: ^rawptr) -> HRESULT, +} +MEMORY_SEGMENT_GROUP :: enum i32 { + LOCAL = 0, + NON_LOCAL = 1, +} + +QUERY_VIDEO_MEMORY_INFO :: struct { + Budget: u64, + CurrentUsage: u64, + AvailableForReservation: u64, + CurrentReservation: u64, +} + + +IAdapter3_UUID :: "645967A4-1392-4310-A798-8053CE3E93FD" +IAdapter3 :: struct #raw_union { + #subtype idxgiadapter2: IAdapter2, + using idxgiadapter3_vtable: ^IAdapter3_VTable, +} +IAdapter3_VTable :: struct { + using idxgiadapter2_vtable: IAdapter2_VTable, + RegisterHardwareContentProtectionTeardownStatusEvent: proc "stdcall" (this: ^IAdapter3, hEvent: HANDLE, pdwCookie: ^u32) -> HRESULT, + UnregisterHardwareContentProtectionTeardownStatus: proc "stdcall" (this: ^IAdapter3, dwCookie: u32), + QueryVideoMemoryInfo: proc "stdcall" (this: ^IAdapter3, NodeIndex: u32, MemorySegmentGroup: MEMORY_SEGMENT_GROUP, pVideoMemoryInfo: ^QUERY_VIDEO_MEMORY_INFO) -> HRESULT, + SetVideoMemoryReservation: proc "stdcall" (this: ^IAdapter3, NodeIndex: u32, MemorySegmentGroup: MEMORY_SEGMENT_GROUP, Reservation: u64) -> HRESULT, + RegisterVideoMemoryBudgetChangeNotificationEvent: proc "stdcall" (this: ^IAdapter3, hEvent: HANDLE, pdwCookie: ^u32) -> HRESULT, + UnregisterVideoMemoryBudgetChangeNotification: proc "stdcall" (this: ^IAdapter3, dwCookie: u32), +} \ No newline at end of file From df23cf47c69877e69b75d109e4da58e782070ac8 Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 16 Feb 2022 22:08:39 -0500 Subject: [PATCH 0209/1052] fix odin test --- src/llvm_backend.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 52c46cadc..c777819c3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1694,6 +1694,11 @@ void lb_generate_code(lbGenerator *gen) { } } + if (build_context.command_kind == Command_test && !already_has_entry_point) { + TIME_SECTION("LLVM main"); + lb_create_main_procedure(default_module, startup_runtime); + } + for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; for_array(i, m->missing_procedures_to_check) { From 78eb388110087f3e5d77fa766f116a54bf42c25f Mon Sep 17 00:00:00 2001 From: Tail Wag Games Date: Thu, 17 Feb 2022 00:58:38 -0600 Subject: [PATCH 0210/1052] Adding capture procedures to user32 Adding `GetCapture`, `SetCapture` and `ReleaseCapture` functions - https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcapture --- core/sys/win32/user32.odin | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/sys/win32/user32.odin b/core/sys/win32/user32.odin index 593fdbb8e..fdf6a91f6 100644 --- a/core/sys/win32/user32.odin +++ b/core/sys/win32/user32.odin @@ -101,6 +101,9 @@ foreign user32 { } @(link_name="GetCursorPos") get_cursor_pos :: proc(p: ^Point) -> Bool --- @(link_name="SetCursorPos") set_cursor_pos :: proc(x, y: i32) -> Bool --- + @(link_name="GetCapure") get_capture :: proc(hwnd: Hwnd) -> Hwnd --- + @(link_name="SetCapture") set_capture :: proc(hwnd: Hwnd) -> Hwnd --- + @(link_name="ReleaseCapture") release_capture :: proc() -> Bool --- @(link_name="ScreenToClient") screen_to_client :: proc(h: Hwnd, p: ^Point) -> Bool --- @(link_name="ClientToScreen") client_to_screen :: proc(h: Hwnd, p: ^Point) -> Bool --- @(link_name="PostQuitMessage") post_quit_message :: proc(exit_code: i32) --- From 75e15b05b0aa563e4e40430b79d69f0796bf5a98 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 17 Feb 2022 12:46:04 +0000 Subject: [PATCH 0211/1052] Correct alias --- vendor/directx/dxgi/dxgi.odin | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/vendor/directx/dxgi/dxgi.odin b/vendor/directx/dxgi/dxgi.odin index 899dc102b..0b8feba4c 100644 --- a/vendor/directx/dxgi/dxgi.odin +++ b/vendor/directx/dxgi/dxgi.odin @@ -8,8 +8,8 @@ foreign import dxgi { import win32 "core:sys/windows" -IID :: win32.LUID LUID :: win32.LUID +IID :: win32.GUID UUID :: win32.GUID GUID :: win32.GUID HANDLE :: win32.HANDLE @@ -44,25 +44,6 @@ foreign dxgi { DXGIGetDebugInterface1 :: proc(Flags: u32, riid: ^IID, pDebug: rawptr) -> HRESULT --- } -CreateDXGIFactoryEx :: proc "stdcall" (riid: IID, ppFactory: rawptr) -> HRESULT { - riid := riid - return CreateDXGIFactory(&riid, ppFactory) -} -CreateDXGIFactory1Ex :: proc "stdcall" (riid: IID, ppFactory: rawptr) -> HRESULT { - riid := riid - return CreateDXGIFactory1(&riid, ppFactory) -} -CreateDXGIFactory2Ex :: proc "stdcall" (Flags: u32, riid: IID, ppFactory: rawptr) -> HRESULT { - riid := riid - return CreateDXGIFactory2(Flags, &riid, ppFactory) -} -DXGIGetDebugInterface1Ex :: proc "stdcall" (Flags: u32, riid: IID, pDebug: rawptr) -> HRESULT { - riid := riid - return DXGIGetDebugInterface1(Flags, &riid, pDebug) -} - - - STANDARD_MULTISAMPLE_QUALITY_PATTERN :: 0xffffffff CENTER_MULTISAMPLE_QUALITY_PATTERN :: 0xfffffffe FORMAT_DEFINED :: 1 @@ -127,9 +108,9 @@ MWA :: enum u32 { // TODO: convert to bit_set VALID = 0x7, } -SHARED_RESOURCE_READ :: 0x80000000 +SHARED_RESOURCE_READ :: 0x80000000 SHARED_RESOURCE_WRITE :: 1 -CREATE_FACTORY_DEBUG :: 0x1 +CREATE_FACTORY_DEBUG :: 0x1 RATIONAL :: struct { Numerator: u32, From f138f71fa6f391adea5c6aac6d5a02d63df4e6af Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 17 Feb 2022 13:14:21 +0000 Subject: [PATCH 0212/1052] Add UUID pointer values --- vendor/directx/d3d11/d3d11.odin | 147 +++++++++++------- vendor/directx/d3d_compiler/d3d_compiler.odin | 6 +- vendor/directx/dxgi/dxgi.odin | 105 ++++++++----- 3 files changed, 170 insertions(+), 88 deletions(-) diff --git a/vendor/directx/d3d11/d3d11.odin b/vendor/directx/d3d11/d3d11.odin index 668d8b9cb..b880d2e67 100644 --- a/vendor/directx/d3d11/d3d11.odin +++ b/vendor/directx/d3d11/d3d11.odin @@ -29,7 +29,7 @@ foreign d3d11 { pAdapter: ^dxgi.IAdapter, DriverType: DRIVER_TYPE, Software: HMODULE, - Flags: CREATE_DEVICE_FLAG, + Flags: CREATE_DEVICE_FLAGS, pFeatureLevels: ^FEATURE_LEVEL, FeatureLevels: u32, SDKVersion: u32, @@ -684,7 +684,8 @@ SRV_DIMENSION :: enum i32 { PFN_DESTRUCTION_CALLBACK :: #type proc "c" (a0: rawptr) -ID3DDestructionNotifier_UUID :: "A06EB39A-50DA-425B-8C31-4EECD6C270F3" +ID3DDestructionNotifier_UUID_STRING :: "A06EB39A-50DA-425B-8C31-4EECD6C270F3" +ID3DDestructionNotifier_UUID := &IID{0xA06EB39A, 0x50DA, 0x425B, {0x8C, 0x31, 0x4E, 0xEC, 0xD6, 0xC2, 0x70, 0xF3}} ID3DDestructionNotifier :: struct #raw_union { #subtype iunknown: IUnknown, using id3ddestructionnotifier_vtable: ^ID3DDestructionNotifier_VTable, @@ -1100,7 +1101,8 @@ CBOX :: struct { } -IDeviceChild_UUID :: "1841E5C8-16B0-489B-BCC8-44CFB0D5DEAE" +IDeviceChild_UUID_STRING :: "1841E5C8-16B0-489B-BCC8-44CFB0D5DEAE" +IDeviceChild_UUID := &IID{0x1841E5C8, 0x16B0, 0x489B, {0xBC, 0xC8, 0x44, 0xCF, 0xB0, 0xD5, 0xDE, 0xAE}} IDeviceChild :: struct #raw_union { #subtype iunknown: IUnknown, using id3d11devicechild_vtable: ^IDeviceChild_VTable, @@ -1164,7 +1166,8 @@ CDEPTH_STENCIL_DESC :: struct { } -IDepthStencilState_UUID :: "03823EFB-8D8F-4E1C-9AA2-F64BB2CBFDF1" +IDepthStencilState_UUID_STRING :: "03823EFB-8D8F-4E1C-9AA2-F64BB2CBFDF1" +IDepthStencilState_UUID := &IID{0x03823EFB, 0x8D8F, 0x4E1C, {0x9A, 0xA2, 0xF6, 0x4B, 0xB2, 0xCB, 0xFD, 0xF1}} IDepthStencilState :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11depthstencilstate_vtable: ^IDepthStencilState_VTable, @@ -1233,7 +1236,8 @@ CBLEND_DESC :: struct { } -IBlendState_UUID :: "75B68FAA-347D-4159-8F45-A0640F01CD9A" +IBlendState_UUID_STRING :: "75B68FAA-347D-4159-8F45-A0640F01CD9A" +IBlendState_UUID := &IID{0x75B68FAA, 0x347D, 0x4159, {0x8F, 0x45, 0xA0, 0x64, 0x0F, 0x01, 0xCD, 0x9A}} IBlendState :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11blendstate_vtable: ^IBlendState_VTable, @@ -1262,7 +1266,8 @@ CRASTERIZER_DESC :: struct { } -IRasterizerState_UUID :: "9BB4AB81-AB1A-4D8F-B506-FC04200B6EE7" +IRasterizerState_UUID_STRING :: "9BB4AB81-AB1A-4D8F-B506-FC04200B6EE7" +IRasterizerState_UUID := &IID{0x9BB4AB81, 0xAB1A, 0x4D8F, {0xB5, 0x06, 0xFC, 0x04, 0x20, 0x0B, 0x6E, 0xE7}} IRasterizerState :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11rasterizerstate_vtable: ^IRasterizerState_VTable, @@ -1286,7 +1291,8 @@ MAPPED_SUBRESOURCE :: struct { } -IResource_UUID :: "DC8E63F3-D12B-4952-B47B-5E45026A862D" +IResource_UUID_STRING :: "DC8E63F3-D12B-4952-B47B-5E45026A862D" +IResource_UUID := &IID{0xDC8E63F3, 0xD12B, 0x4952, {0xB4, 0x7B, 0x5E, 0x45, 0x02, 0x6A, 0x86, 0x2D}} IResource :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11resource_vtable: ^IResource_VTable, @@ -1313,7 +1319,8 @@ CBUFFER_DESC :: struct { } -IBuffer_UUID :: "48570B85-D1EE-4FCD-A250-EB350722B037" +IBuffer_UUID_STRING :: "48570B85-D1EE-4FCD-A250-EB350722B037" +IBuffer_UUID := &IID{0x48570B85, 0xD1EE, 0x4FCD, {0xA2, 0x50, 0xEB, 0x35, 0x07, 0x22, 0xB0, 0x37}} IBuffer :: struct #raw_union { #subtype id3d11resource: IResource, using id3d11buffer_vtable: ^IBuffer_VTable, @@ -1340,7 +1347,8 @@ CTEXTURE1D_DESC :: struct { } -ITexture1D_UUID :: "F8FB5C27-C6B3-4F75-A4C8-439AF2EF564C" +ITexture1D_UUID_STRING :: "F8FB5C27-C6B3-4F75-A4C8-439AF2EF564C" +ITexture1D_UUID := &IID{0xF8FB5C27, 0xC6B3, 0x4F75, {0xA4, 0xC8, 0x43, 0x9A, 0xF2, 0xEF, 0x56, 0x4C}} ITexture1D :: struct #raw_union { #subtype id3d11resource: IResource, using id3d11texture1d_vtable: ^ITexture1D_VTable, @@ -1369,7 +1377,8 @@ CTEXTURE2D_DESC :: struct { } -ITexture2D_UUID :: "6F15AAF2-D208-4E89-9AB4-489535D34F9C" +ITexture2D_UUID_STRING :: "6F15AAF2-D208-4E89-9AB4-489535D34F9C" +ITexture2D_UUID := &IID{0x6F15AAF2, 0xD208, 0x4E89, {0x9A, 0xB4, 0x48, 0x95, 0x35, 0xD3, 0x4F, 0x9C}} ITexture2D :: struct #raw_union { #subtype id3d11resource: IResource, using id3d11texture2d_vtable: ^ITexture2D_VTable, @@ -1397,7 +1406,8 @@ CTEXTURE3D_DESC :: struct { } -ITexture3D_UUID :: "037E866E-F56D-4357-A8AF-9DABBE6E250E" +ITexture3D_UUID_STRING :: "037E866E-F56D-4357-A8AF-9DABBE6E250E" +ITexture3D_UUID := &IID{0x037E866E, 0xF56D, 0x4357, {0xA8, 0xAF, 0x9D, 0xAB, 0xBE, 0x6E, 0x25, 0x0E}} ITexture3D :: struct #raw_union { #subtype id3d11resource: IResource, using id3d11texture3d_vtable: ^ITexture3D_VTable, @@ -1418,7 +1428,8 @@ TEXTURECUBE_FACE :: enum i32 { } -IView_UUID :: "839D1216-BB2E-412B-B7F4-A9DBEBE08ED1" +IView_UUID_STRING :: "839D1216-BB2E-412B-B7F4-A9DBEBE08ED1" +IView_UUID := &IID{0x839D1216, 0xBB2E, 0x412B, {0xB7, 0xF4, 0xA9, 0xDB, 0xEB, 0xE0, 0x8E, 0xD1}} IView :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11view_vtable: ^IView_VTable, @@ -1523,7 +1534,8 @@ CSHADER_RESOURCE_VIEW_DESC :: struct { } -IShaderResourceView_UUID :: "B0E06FE0-8192-4E1A-B1CA-36D7414710B2" +IShaderResourceView_UUID_STRING :: "B0E06FE0-8192-4E1A-B1CA-36D7414710B2" +IShaderResourceView_UUID := &IID{0xB0E06FE0, 0x8192, 0x4E1A, {0xB1, 0xCA, 0x36, 0xD7, 0x41, 0x47, 0x10, 0xB2}} IShaderResourceView :: struct #raw_union { #subtype id3d11view: IView, using id3d11shaderresourceview_vtable: ^IShaderResourceView_VTable, @@ -1600,7 +1612,8 @@ CRENDER_TARGET_VIEW_DESC :: struct { } -IRenderTargetView_UUID :: "DFDBA067-0B8D-4865-875B-D7B4516CC164" +IRenderTargetView_UUID_STRING :: "DFDBA067-0B8D-4865-875B-D7B4516CC164" +IRenderTargetView_UUID := &IID{0xDFDBA067, 0x0B8D, 0x4865, {0x87, 0x5B, 0xD7, 0xB4, 0x51, 0x6C, 0xC1, 0x64}} IRenderTargetView :: struct #raw_union { #subtype id3d11view: IView, using id3d11rendertargetview_vtable: ^IRenderTargetView_VTable, @@ -1668,7 +1681,8 @@ CDEPTH_STENCIL_VIEW_DESC :: struct { } -IDepthStencilView_UUID :: "9FDAC92A-1876-48C3-AFAD-25B94F84A9B6" +IDepthStencilView_UUID_STRING :: "9FDAC92A-1876-48C3-AFAD-25B94F84A9B6" +IDepthStencilView_UUID := &IID{0x9FDAC92A, 0x1876, 0x48C3, {0xAF, 0xAD, 0x25, 0xB9, 0x4F, 0x84, 0xA9, 0xB6}} IDepthStencilView :: struct #raw_union { #subtype id3d11view: IView, using id3d11depthstencilview_vtable: ^IDepthStencilView_VTable, @@ -1735,7 +1749,8 @@ CUNORDERED_ACCESS_VIEW_DESC :: struct { } -IUnorderedAccessView_UUID :: "28ACF509-7F5C-48F6-8611-F316010A6380" +IUnorderedAccessView_UUID_STRING :: "28ACF509-7F5C-48F6-8611-F316010A6380" +IUnorderedAccessView_UUID := &IID{0x28ACF509, 0x7F5C, 0x48F6, {0x86, 0x11, 0xF3, 0x16, 0x01, 0x0A, 0x63, 0x80}} IUnorderedAccessView :: struct #raw_union { #subtype id3d11view: IView, using id3d11unorderedaccessview_vtable: ^IUnorderedAccessView_VTable, @@ -1747,43 +1762,50 @@ IUnorderedAccessView_VTable :: struct { -IVertexShader_UUID :: "3B301D64-D678-4289-8897-22F8928B72F3" +IVertexShader_UUID_STRING :: "3B301D64-D678-4289-8897-22F8928B72F3" +IVertexShader_UUID := &IID{0x3B301D64, 0xD678, 0x4289, {0x88, 0x97, 0x22, 0xF8, 0x92, 0x8B, 0x72, 0xF3}} IVertexShader :: struct { using id3d11devicechild: IDeviceChild, } -IHullShader_UUID :: "8E5C6061-628A-4C8E-8264-BBE45CB3D5DD" +IHullShader_UUID_STRING :: "8E5C6061-628A-4C8E-8264-BBE45CB3D5DD" +IHullShader_UUID := &IID{0x8E5C6061, 0x628A, 0x4C8E, {0x82, 0x64, 0xBB, 0xE4, 0x5C, 0xB3, 0xD5, 0xDD}} IHullShader :: struct { using id3d11devicechild: IDeviceChild, } -IDomainShader_UUID :: "F582C508-0F36-490C-9977-31EECE268CFA" +IDomainShader_UUID_STRING :: "F582C508-0F36-490C-9977-31EECE268CFA" +IDomainShader_UUID := &IID{0xF582C508, 0x0F36, 0x490C, {0x99, 0x77, 0x31, 0xEE, 0xCE, 0x26, 0x8C, 0xFA}} IDomainShader :: struct { using id3d11devicechild: IDeviceChild, } -IGeometryShader_UUID :: "38325B96-EFFB-4022-BA02-2E795B70275C" +IGeometryShader_UUID_STRING :: "38325B96-EFFB-4022-BA02-2E795B70275C" +IGeometryShader_UUID := &IID{0x38325B96, 0xEFFB, 0x4022, {0xBA, 0x02, 0x2E, 0x79, 0x5B, 0x70, 0x27, 0x5C}} IGeometryShader :: struct { using id3d11devicechild: IDeviceChild, } -IPixelShader_UUID :: "EA82E40D-51DC-4F33-93D4-DB7C9125AE8C" +IPixelShader_UUID_STRING :: "EA82E40D-51DC-4F33-93D4-DB7C9125AE8C" +IPixelShader_UUID := &IID{0xEA82E40D, 0x51DC, 0x4F33, {0x93, 0xD4, 0xDB, 0x7C, 0x91, 0x25, 0xAE, 0x8C}} IPixelShader :: struct { using id3d11devicechild: IDeviceChild, } -IComputeShader_UUID :: "4F5B196E-C2BD-495E-BD01-1FDED38E4969" +IComputeShader_UUID_STRING :: "4F5B196E-C2BD-495E-BD01-1FDED38E4969" +IComputeShader_UUID := &IID{0x4F5B196E, 0xC2BD, 0x495E, {0xBD, 0x01, 0x1F, 0xDE, 0xD3, 0x8E, 0x49, 0x69}} IComputeShader :: struct { using id3d11devicechild: IDeviceChild, } -IInputLayout_UUID :: "E4819DDC-4CF0-4025-BD26-5DE82A3E07B7" +IInputLayout_UUID_STRING :: "E4819DDC-4CF0-4025-BD26-5DE82A3E07B7" +IInputLayout_UUID := &IID{0xE4819DDC, 0x4CF0, 0x4025, {0xBD, 0x26, 0x5D, 0xE8, 0x2A, 0x3E, 0x07, 0xB7}} IInputLayout :: struct { using id3d11devicechild: IDeviceChild, } @@ -1865,7 +1887,8 @@ CSAMPLER_DESC :: struct { } -ISamplerState_UUID :: "DA6FEA51-564C-4487-9810-F0D0F9B4E3A5" +ISamplerState_UUID_STRING :: "DA6FEA51-564C-4487-9810-F0D0F9B4E3A5" +ISamplerState_UUID := &IID{0xDA6FEA51, 0x564C, 0x4487, {0x98, 0x10, 0xF0, 0xD0, 0xF9, 0xB4, 0xE3, 0xA5}} ISamplerState :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11samplerstate_vtable: ^ISamplerState_VTable, @@ -1926,7 +1949,8 @@ FORMAT_SUPPORT2 :: enum i32 { // TODO: make bit_set } -IAsynchronous_UUID :: "4B35D0CD-1E15-4258-9C98-1B1333F6DD3B" +IAsynchronous_UUID_STRING :: "4B35D0CD-1E15-4258-9C98-1B1333F6DD3B" +IAsynchronous_UUID := &IID{0x4B35D0CD, 0x1E15, 0x4258, {0x9C, 0x98, 0x1B, 0x13, 0x33, 0xF6, 0xDD, 0x3B}} IAsynchronous :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11asynchronous_vtable: ^IAsynchronous_VTable, @@ -1974,7 +1998,8 @@ CQUERY_DESC :: struct { } -IQuery_UUID :: "D6C00747-87B7-425E-B84D-44D108560AFD" +IQuery_UUID_STRING :: "D6C00747-87B7-425E-B84D-44D108560AFD" +IQuery_UUID := &IID{0xD6C00747, 0x87B7, 0x425E, {0xB8, 0x4D, 0x44, 0xD1, 0x08, 0x56, 0x0A, 0xFD}} IQuery :: struct #raw_union { #subtype id3d11asynchronous: IAsynchronous, using id3d11query_vtable: ^IQuery_VTable, @@ -1986,7 +2011,8 @@ IQuery_VTable :: struct { -IPredicate_UUID :: "9EB576DD-9F77-4D86-81AA-8BAB5FE490E2" +IPredicate_UUID_STRING :: "9EB576DD-9F77-4D86-81AA-8BAB5FE490E2" +IPredicate_UUID := &IID{0x9EB576DD, 0x9F77, 0x4D86, {0x81, 0xAA, 0x8B, 0xAB, 0x5F, 0xE4, 0x90, 0xE2}} IPredicate :: struct { using id3d11query: IQuery, } @@ -2042,7 +2068,8 @@ COUNTER_INFO :: struct { } -ICounter_UUID :: "6E8C49FB-A371-4770-B440-29086022B741" +ICounter_UUID_STRING :: "6E8C49FB-A371-4770-B440-29086022B741" +ICounter_UUID := &IID{0x6E8C49FB, 0xA371, 0x4770, {0xB4, 0x40, 0x29, 0x08, 0x60, 0x22, 0xB7, 0x41}} ICounter :: struct #raw_union { #subtype id3d11asynchronous: IAsynchronous, using id3d11counter_vtable: ^ICounter_VTable, @@ -2075,7 +2102,8 @@ CLASS_INSTANCE_DESC :: struct { } -IClassInstance_UUID :: "A6CD7FAA-B0B7-4A2F-9436-8662A65797CB" +IClassInstance_UUID_STRING :: "A6CD7FAA-B0B7-4A2F-9436-8662A65797CB" +IClassInstance_UUID := &IID{0xA6CD7FAA, 0xB0B7, 0x4A2F, {0x94, 0x36, 0x86, 0x62, 0xA6, 0x57, 0x97, 0xCB}} IClassInstance :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11classinstance_vtable: ^IClassInstance_VTable, @@ -2090,7 +2118,8 @@ IClassInstance_VTable :: struct { -IClassLinkage_UUID :: "DDF57CBA-9543-46E4-A12B-F207A0FE7FED" +IClassLinkage_UUID_STRING :: "DDF57CBA-9543-46E4-A12B-F207A0FE7FED" +IClassLinkage_UUID := &IID{0xDDF57CBA, 0x9543, 0x46E4, {0xA1, 0x2B, 0xF2, 0x07, 0xA0, 0xFE, 0x7F, 0xED}} IClassLinkage :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11classlinkage_vtable: ^IClassLinkage_VTable, @@ -2103,7 +2132,8 @@ IClassLinkage_VTable :: struct { -ICommandList_UUID :: "A24BC4D1-769E-43F7-8013-98FF566C18E2" +ICommandList_UUID_STRING :: "A24BC4D1-769E-43F7-8013-98FF566C18E2" +ICommandList_UUID := &IID{0xA24BC4D1, 0x769E, 0x43F7, {0x80, 0x13, 0x98, 0xFF, 0x56, 0x6C, 0x18, 0xE2}} ICommandList :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11commandlist_vtable: ^ICommandList_VTable, @@ -2277,7 +2307,8 @@ FEATURE_DATA_OPTIONS5 :: struct { } -IDeviceContext_UUID :: "C0BFA96C-E089-44FB-8EAF-26F8796190DA" +IDeviceContext_UUID_STRING :: "C0BFA96C-E089-44FB-8EAF-26F8796190DA" +IDeviceContext_UUID := &IID{0xC0BFA96C, 0xE089, 0x44FB, {0x8E, 0xAF, 0x26, 0xF8, 0x79, 0x61, 0x90, 0xDA}} IDeviceContext :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11devicecontext_vtable: ^IDeviceContext_VTable, @@ -2484,7 +2515,8 @@ VIDEO_DECODER_EXTENSION :: struct { } -IVideoDecoder_UUID :: "3C9C5B51-995D-48D1-9B8D-FA5CAEDED65C" +IVideoDecoder_UUID_STRING :: "3C9C5B51-995D-48D1-9B8D-FA5CAEDED65C" +IVideoDecoder_UUID := &IID{0x3C9C5B51, 0x995D, 0x48D1, {0x9B, 0x8D, 0xFA, 0x5C, 0xAE, 0xDE, 0xD6, 0x5C}} IVideoDecoder :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11videodecoder_vtable: ^IVideoDecoder_VTable, @@ -2679,7 +2711,8 @@ VIDEO_PROCESSOR_CONTENT_DESC :: struct { } -IVideoProcessorEnumerator_UUID :: "31627037-53AB-4200-9061-05FAA9AB45F9" +IVideoProcessorEnumerator_UUID_STRING :: "31627037-53AB-4200-9061-05FAA9AB45F9" +IVideoProcessorEnumerator_UUID := &IID{0x31627037, 0x53AB, 0x4200, {0x90, 0x61, 0x05, 0xFA, 0xA9, 0xAB, 0x45, 0xF9}} IVideoProcessorEnumerator :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11videoprocessorenumerator_vtable: ^IVideoProcessorEnumerator_VTable, @@ -2789,7 +2822,8 @@ VIDEO_PROCESSOR_STREAM :: struct { } -IVideoProcessor_UUID :: "1D7B0652-185F-41C6-85CE-0C5BE3D4AE6C" +IVideoProcessor_UUID_STRING :: "1D7B0652-185F-41C6-85CE-0C5BE3D4AE6C" +IVideoProcessor_UUID := &IID{0x1D7B0652, 0x185F, 0x41C6, {0x85, 0xCE, 0x0C, 0x5B, 0xE3, 0xD4, 0xAE, 0x6C}} IVideoProcessor :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11videoprocessor_vtable: ^IVideoProcessor_VTable, @@ -2812,7 +2846,8 @@ AUTHENTICATED_CHANNEL_TYPE :: enum i32 { } -IAuthenticatedChannel_UUID :: "3015A308-DCBD-47AA-A747-192486D14D4A" +IAuthenticatedChannel_UUID_STRING :: "3015A308-DCBD-47AA-A747-192486D14D4A" +IAuthenticatedChannel_UUID := &IID{0x3015A308, 0xDCBD, 0x47AA, {0xA7, 0x47, 0x19, 0x24, 0x86, 0xD1, 0x4D, 0x4A}} IAuthenticatedChannel :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11authenticatedchannel_vtable: ^IAuthenticatedChannel_VTable, @@ -3020,7 +3055,8 @@ AUTHENTICATED_CONFIGURE_ACCESSIBLE_ENCRYPTION_INPUT :: struct { -ICryptoSession_UUID :: "9B32F9AD-BDCC-40A6-A39D-D5C865845720" +ICryptoSession_UUID_STRING :: "9B32F9AD-BDCC-40A6-A39D-D5C865845720" +ICryptoSession_UUID := &IID{0x9B32F9AD, 0xBDCC, 0x40A6, {0xA3, 0x9D, 0xD5, 0xC8, 0x65, 0x84, 0x57, 0x20}} ICryptoSession :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11cryptosession_vtable: ^ICryptoSession_VTable, @@ -3053,7 +3089,8 @@ VIDEO_DECODER_OUTPUT_VIEW_DESC :: struct { } -IVideoDecoderOutputView_UUID :: "C2931AEA-2A85-4F20-860F-FBA1FD256E18" +IVideoDecoderOutputView_UUID_STRING :: "C2931AEA-2A85-4F20-860F-FBA1FD256E18" +IVideoDecoderOutputView_UUID := &IID{0xC2931AEA, 0x2A85, 0x4F20, {0x86, 0x0F, 0xFB, 0xA1, 0xFD, 0x25, 0x6E, 0x18}} IVideoDecoderOutputView :: struct #raw_union { #subtype id3d11view: IView, using id3d11videodecoderoutputview_vtable: ^IVideoDecoderOutputView_VTable, @@ -3083,7 +3120,8 @@ VIDEO_PROCESSOR_INPUT_VIEW_DESC :: struct { } -IVideoProcessorInputView_UUID :: "11EC5A5F-51DC-4945-AB34-6E8C21300EA5" +IVideoProcessorInputView_UUID_STRING :: "11EC5A5F-51DC-4945-AB34-6E8C21300EA5" +IVideoProcessorInputView_UUID := &IID{0x11EC5A5F, 0x51DC, 0x4945, {0xAB, 0x34, 0x6E, 0x8C, 0x21, 0x30, 0x0E, 0xA5}} IVideoProcessorInputView :: struct #raw_union { #subtype id3d11view: IView, using id3d11videoprocessorinputview_vtable: ^IVideoProcessorInputView_VTable, @@ -3119,7 +3157,8 @@ VIDEO_PROCESSOR_OUTPUT_VIEW_DESC :: struct { } -IVideoProcessorOutputView_UUID :: "A048285E-25A9-4527-BD93-D68B68C44254" +IVideoProcessorOutputView_UUID_STRING :: "A048285E-25A9-4527-BD93-D68B68C44254" +IVideoProcessorOutputView_UUID := &IID{0xA048285E, 0x25A9, 0x4527, {0xBD, 0x93, 0xD6, 0x8B, 0x68, 0xC4, 0x42, 0x54}} IVideoProcessorOutputView :: struct #raw_union { #subtype id3d11view: IView, using id3d11videoprocessoroutputview_vtable: ^IVideoProcessorOutputView_VTable, @@ -3131,7 +3170,8 @@ IVideoProcessorOutputView_VTable :: struct { -IVideoContext_UUID :: "61F21C45-3C0E-4A74-9CEA-67100D9AD5E4" +IVideoContext_UUID_STRING :: "61F21C45-3C0E-4A74-9CEA-67100D9AD5E4" +IVideoContext_UUID := &IID{0x61F21C45, 0x3C0E, 0x4A74, {0x9C, 0xEA, 0x67, 0x10, 0x0D, 0x9A, 0xD5, 0xE4}} IVideoContext :: struct #raw_union { #subtype id3d11devicechild: IDeviceChild, using id3d11videocontext_vtable: ^IVideoContext_VTable, @@ -3200,7 +3240,8 @@ IVideoContext_VTable :: struct { -IVideoDevice_UUID :: "10EC4D5B-975A-4689-B9E4-D0AAC30FE333" +IVideoDevice_UUID_STRING :: "10EC4D5B-975A-4689-B9E4-D0AAC30FE333" +IVideoDevice_UUID := &IID{0x10EC4D5B, 0x975A, 0x4689, {0xB9, 0xE4, 0xD0, 0xAA, 0xC3, 0x0F, 0xE3, 0x33}} IVideoDevice :: struct #raw_union { #subtype iunknown: IUnknown, using id3d11videodevice_vtable: ^IVideoDevice_VTable, @@ -3228,7 +3269,8 @@ IVideoDevice_VTable :: struct { -IDevice_UUID :: "DB6F6DDB-AC77-4E88-8253-819DF9BBF140" +IDevice_UUID_STRING :: "DB6F6DDB-AC77-4E88-8253-819DF9BBF140" +IDevice_UUID := &IID{0xDB6F6DDB, 0xAC77, 0x4E88, {0x82, 0x53, 0x81, 0x9D, 0xF9, 0xBB, 0xF1, 0x40}} IDevice :: struct #raw_union { #subtype iunknown: IUnknown, using id3d11device_vtable: ^IDevice_VTable, @@ -3278,16 +3320,17 @@ IDevice_VTable :: struct { } +CREATE_DEVICE_FLAGS :: distinct bit_set[CREATE_DEVICE_FLAG; u32] CREATE_DEVICE_FLAG :: enum u32 { // TODO: make bit_set - SINGLETHREADED = 0x1, - DEBUG = 0x2, - SWITCH_TO_REF = 0x4, - PREVENT_INTERNAL_THREADING_OPTIMIZATIONS = 0x8, - BGRA_SUPPORT = 0x20, - DEBUGGABLE = 0x40, - PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY = 0x80, - DISABLE_GPU_TIMEOUT = 0x100, - VIDEO_SUPPORT = 0x800, + SINGLETHREADED = 0, + DEBUG = 1, + SWITCH_TO_REF = 2, + PREVENT_INTERNAL_THREADING_OPTIMIZATIONS = 3, + BGRA_SUPPORT = 5, + DEBUGGABLE = 6, + PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY = 7, + DISABLE_GPU_TIMEOUT = 8, + VIDEO_SUPPORT = 12, } PFN_CREATE_DEVICE :: #type proc "c" (a0: ^dxgi.IAdapter, a1: DRIVER_TYPE, a2: HMODULE, a3: u32, a4: ^FEATURE_LEVEL, a5: u32, a6: u32, a7: ^^IDevice, a8: ^FEATURE_LEVEL, a9: ^^IDeviceContext) -> HRESULT diff --git a/vendor/directx/d3d_compiler/d3d_compiler.odin b/vendor/directx/d3d_compiler/d3d_compiler.odin index 9157e3585..559452f78 100644 --- a/vendor/directx/d3d_compiler/d3d_compiler.odin +++ b/vendor/directx/d3d_compiler/d3d_compiler.odin @@ -109,18 +109,22 @@ SHADER_MACRO :: struct { Definition: cstring, } +ID3D10Blob_UUID_STRING :: "8BA5FB08-5195-40E2-AC58-0D989C3A0102" +ID3D10Blob_UUID := &IID{0x8BA5FB08, 0x5195, 0x40E2, {0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02}} ID3D10Blob :: struct { #subtype iunknown: IUnknown, using id3d10blob_vtable: ^ID3D10Blob_VTable, } ID3D10Blob_VTable :: struct { using iunknown_vtable: IUnknown_VTable, - GetBufferPointer: proc "stdcall" (this: ^ID3D10Blob), + GetBufferPointer: proc "stdcall" (this: ^ID3D10Blob) -> rawptr, GetBufferSize: proc "stdcall" (this: ^ID3D10Blob) -> SIZE_T, } ID3DBlob :: ID3D10Blob +ID3DBlob_VTable :: ID3D10Blob_VTable + INCLUDE_TYPE :: enum i32 { INCLUDE_LOCAL = 0, diff --git a/vendor/directx/dxgi/dxgi.odin b/vendor/directx/dxgi/dxgi.odin index 0b8feba4c..70c5a9e71 100644 --- a/vendor/directx/dxgi/dxgi.odin +++ b/vendor/directx/dxgi/dxgi.odin @@ -437,7 +437,8 @@ SWAP_CHAIN_DESC :: struct { } -IObject_UUID :: "AEC22FB8-76F3-4639-9BE0-28EB43A67A2E" +IObject_UUID_STRING :: "AEC22FB8-76F3-4639-9BE0-28EB43A67A2E" +IObject_UUID := &IID{0xAEC22FB8, 0x76F3, 0x4639, {0x9B, 0xE0, 0x28, 0xEB, 0x43, 0xA6, 0x7A, 0x2E}} IObject :: struct #raw_union { #subtype iunknown: IUnknown, using vtable: ^IObject_VTable, @@ -450,7 +451,8 @@ IObject_VTable :: struct { GetParent: proc "stdcall" (this: ^IObject, riid: ^IID, ppParent: ^rawptr) -> HRESULT, } -IDeviceSubObject_UUID :: "3D3E0379-F9DE-4D58-BB6C-18D62992F1A6" +IDeviceSubObject_UUID_STRING :: "3D3E0379-F9DE-4D58-BB6C-18D62992F1A6" +IDeviceSubObject_UUID := &IID{0x3D3E0379, 0xF9DE, 0x4D58, {0xBB, 0x6C, 0x18, 0xD6, 0x29, 0x92, 0xF1, 0xA6}} IDeviceSubObject :: struct #raw_union { #subtype idxgiobject: IObject, using idxgidevicesubobject_vtable: ^IDeviceSubObject_VTable, @@ -460,7 +462,8 @@ IDeviceSubObject_VTable :: struct { GetDevice: proc "stdcall" (this: ^IDeviceSubObject, riid: ^IID, ppDevice: ^rawptr) -> HRESULT, } -IResource_UUID :: "035F3AB4-482E-4E50-B41F-8A7F8BD8960B" +IResource_UUID_STRING :: "035F3AB4-482E-4E50-B41F-8A7F8BD8960B" +IResource_UUID := &IID{0x035F3AB4, 0x482E, 0x4E50, {0xB4, 0x1F, 0x8A, 0x7F, 0x8B, 0xD8, 0x96, 0x0B}} IResource :: struct #raw_union { #subtype idxgidevicesubobject: IDeviceSubObject, using idxgiresource_vtable: ^IResource_VTable, @@ -473,7 +476,8 @@ IResource_VTable :: struct { GetEvictionPriority: proc "stdcall" (this: ^IResource, pEvictionPriority: ^u32) -> HRESULT, } -IKeyedMutex_UUID :: "9D8E1289-D7B3-465F-8126-250E349AF85D" +IKeyedMutex_UUID_STRING :: "9D8E1289-D7B3-465F-8126-250E349AF85D" +IKeyedMutex_UUID := &IID{0x9D8E1289, 0xD7B3, 0x465F, {0x81, 0x26, 0x25, 0x0E, 0x34, 0x9A, 0xF8, 0x5D}} IKeyedMutex :: struct #raw_union { #subtype idxgidevicesubobject: IDeviceSubObject, using idxgikeyedmutex_vtable: ^IKeyedMutex_VTable, @@ -484,7 +488,8 @@ IKeyedMutex_VTable :: struct { ReleaseSync: proc "stdcall" (this: ^IKeyedMutex, Key: u64) -> HRESULT, } -ISurface_UUID :: "CAFCB56C-6AC3-4889-BF47-9E23BBD260EC" +ISurface_UUID_STRING :: "CAFCB56C-6AC3-4889-BF47-9E23BBD260EC" +ISurface_UUID := &IID{0xCAFCB56C, 0x6AC3, 0x4889, {0xBF, 0x47, 0x9E, 0x23, 0xBB, 0xD2, 0x60, 0xEC}} ISurface :: struct #raw_union { #subtype idxgidevicesubobject: IDeviceSubObject, using idxgisurface_vtable: ^ISurface_VTable, @@ -496,7 +501,8 @@ ISurface_VTable :: struct { Unmap: proc "stdcall" (this: ^ISurface) -> HRESULT, } -ISurface1_UUID :: "4AE63092-6327-4C1B-80AE-BFE12EA32B86" +ISurface1_UUID_STRING :: "4AE63092-6327-4C1B-80AE-BFE12EA32B86" +ISurface1_UUID := &IID{0x4AE63092, 0x6327, 0x4C1B, {0x80, 0xAE, 0xBF, 0xE1, 0x2E, 0xA3, 0x2B, 0x86}} ISurface1 :: struct #raw_union { #subtype idxgisurface: ISurface, using idxgisurface1_vtable: ^ISurface1_VTable, @@ -507,7 +513,8 @@ ISurface1_VTable :: struct { ReleaseDC: proc "stdcall" (this: ^ISurface1, pDirtyRect: ^RECT) -> HRESULT, } -IAdapter_UUID :: "2411E7E1-12AC-4CCF-BD14-9798E8534DC0" +IAdapter_UUID_STRING :: "2411E7E1-12AC-4CCF-BD14-9798E8534DC0" +IAdapter_UUID := &IID{0x2411E7E1, 0x12AC, 0x4CCF, {0xBD, 0x14, 0x97, 0x98, 0xE8, 0x53, 0x4D, 0xC0}} IAdapter :: struct #raw_union { #subtype idxgiobject: IObject, using idxgiadapter_vtable: ^IAdapter_VTable, @@ -519,7 +526,8 @@ IAdapter_VTable :: struct { CheckInterfaceSupport: proc "stdcall" (this: ^IAdapter, InterfaceName: ^GUID, pUMDVersion: ^LARGE_INTEGER) -> HRESULT, } -IOutput_UUID :: "AE02EEDB-C735-4690-8D52-5A8DC20213AA" +IOutput_UUID_STRING :: "AE02EEDB-C735-4690-8D52-5A8DC20213AA" +IOutput_UUID := &IID{0xAE02EEDB, 0xC735, 0x4690, {0x8D, 0x52, 0x5A, 0x8D, 0xC2, 0x02, 0x13, 0xAA}} IOutput :: struct #raw_union { #subtype idxgiobject: IObject, using idxgioutput_vtable: ^IOutput_VTable, @@ -540,7 +548,8 @@ IOutput_VTable :: struct { GetFrameStatistics: proc "stdcall" (this: ^IOutput, pStats: ^FRAME_STATISTICS) -> HRESULT, } -ISwapChain_UUID :: "310D36A0-D2E7-4C0A-AA04-6A9D23B8886A" +ISwapChain_UUID_STRING :: "310D36A0-D2E7-4C0A-AA04-6A9D23B8886A" +ISwapChain_UUID := &IID{0x310D36A0, 0xD2E7, 0x4C0A, {0xAA, 0x04, 0x6A, 0x9D, 0x23, 0xB8, 0x88, 0x6A}} ISwapChain :: struct #raw_union { #subtype idxgidevicesubobject: IDeviceSubObject, using idxgiswapchain_vtable: ^ISwapChain_VTable, @@ -559,7 +568,8 @@ ISwapChain_VTable :: struct { GetLastPresentCount: proc "stdcall" (this: ^ISwapChain, pLastPresentCount: ^u32) -> HRESULT, } -IFactory_UUID :: "7B7166EC-21C7-44AE-B21A-C9AE321AE369" +IFactory_UUID_STRING :: "7B7166EC-21C7-44AE-B21A-C9AE321AE369" +IFactory_UUID := &IID{0x7B7166EC, 0x21C7, 0x44AE, {0xB2, 0x1A, 0xC9, 0xAE, 0x32, 0x1A, 0xE3, 0x69}} IFactory :: struct #raw_union { #subtype idxgiobject: IObject, using idxgifactory_vtable: ^IFactory_VTable, @@ -572,7 +582,8 @@ IFactory_VTable :: struct { CreateSwapChain: proc "stdcall" (this: ^IFactory, pDevice: ^IUnknown, pDesc: ^SWAP_CHAIN_DESC, ppSwapChain: ^^ISwapChain) -> HRESULT, CreateSoftwareAdapter: proc "stdcall" (this: ^IFactory, Module: HMODULE, ppAdapter: ^^IAdapter) -> HRESULT, } -IDevice_UUID :: "54EC77FA-1377-44E6-8C32-88FD5F44C84C" +IDevice_UUID_STRING :: "54EC77FA-1377-44E6-8C32-88FD5F44C84C" +IDevice_UUID := &IID{0x54EC77FA, 0x1377, 0x44E6, {0x8C, 0x32, 0x88, 0xFD, 0x5F, 0x44, 0xC8, 0x4C}} IDevice :: struct #raw_union { #subtype idxgiobject: IObject, using idxgidevice_vtable: ^IDevice_VTable, @@ -611,7 +622,8 @@ DISPLAY_COLOR_SPACE :: struct { } -IFactory1_UUID :: "770AAE78-F26F-4DBA-A829-253C83D1B387" +IFactory1_UUID_STRING :: "770AAE78-F26F-4DBA-A829-253C83D1B387" +IFactory1_UUID := &IID{0x770AAE78, 0xF26F, 0x4DBA, {0xA8, 0x29, 0x25, 0x3C, 0x83, 0xD1, 0xB3, 0x87}} IFactory1 :: struct #raw_union { #subtype idxgifactory: IFactory, using idxgifactory1_vtable: ^IFactory1_VTable, @@ -622,7 +634,8 @@ IFactory1_VTable :: struct { IsCurrent: proc "stdcall" (this: ^IFactory1) -> BOOL, } -IAdapter1_UUID :: "29038F61-3839-4626-91FD-086879011A05" +IAdapter1_UUID_STRING :: "29038F61-3839-4626-91FD-086879011A05" +IAdapter1_UUID := &IID{0x29038F61, 0x3839, 0x4626, {0x91, 0xFD, 0x08, 0x68, 0x79, 0x01, 0x1A, 0x05}} IAdapter1 :: struct #raw_union { #subtype idxgiadapter: IAdapter, using idxgiadapter1_vtable: ^IAdapter1_VTable, @@ -632,7 +645,8 @@ IAdapter1_VTable :: struct { GetDesc1: proc "stdcall" (this: ^IAdapter1, pDesc: ^ADAPTER_DESC1) -> HRESULT, } -IDevice1_UUID :: "77DB970F-6276-48BA-BA28-070143B4392C" +IDevice1_UUID_STRING :: "77DB970F-6276-48BA-BA28-070143B4392C" +IDevice1_UUID := &IID{0x77DB970F, 0x6276, 0x48BA, {0xBA, 0x28, 0x07, 0x01, 0x43, 0xB4, 0x39, 0x2C}} IDevice1 :: struct #raw_union { #subtype idxgidevice: IDevice, using idxgidevice1_vtable: ^IDevice1_VTable, @@ -643,7 +657,8 @@ IDevice1_VTable :: struct { GetMaximumFrameLatency: proc "stdcall" (this: ^IDevice1, pMaxLatency: ^u32) -> HRESULT, } -IDisplayControl_UUID :: "EA9DBF1A-C88E-4486-854A-98AA0138F30C" +IDisplayControl_UUID_STRING :: "EA9DBF1A-C88E-4486-854A-98AA0138F30C" +IDisplayControl_UUID := &IID{0xEA9DBF1A, 0xC88E, 0x4486, {0x85, 0x4A, 0x98, 0xAA, 0x01, 0x38, 0xF3, 0x0C}} IDisplayControl :: struct #raw_union { #subtype iunknown: IUnknown, using idxgidisplaycontrol_vtable: ^IDisplayControl_VTable, @@ -695,7 +710,8 @@ OUTDUPL_FRAME_INFO :: struct { } -IOutputDuplication_UUID :: "191CFAC3-A341-470D-B26E-A864F428319C" +IOutputDuplication_UUID_STRING :: "191CFAC3-A341-470D-B26E-A864F428319C" +IOutputDuplication_UUID := &IID{0x191CFAC3, 0xA341, 0x470D, {0xB2, 0x6E, 0xA8, 0x64, 0xF4, 0x28, 0x31, 0x9C}} IOutputDuplication :: struct #raw_union { #subtype idxgiobject: IObject, using idxgioutputduplication_vtable: ^IOutputDuplication_VTable, @@ -720,7 +736,8 @@ ALPHA_MODE :: enum i32 { } -ISurface2_UUID :: "ABA496DD-B617-4CB8-A866-BC44D7EB1FA2" +ISurface2_UUID_STRING :: "ABA496DD-B617-4CB8-A866-BC44D7EB1FA2" +ISurface2_UUID := &IID{0xABA496DD, 0xB617, 0x4CB8, {0xA8, 0x66, 0xBC, 0x44, 0xD7, 0xEB, 0x1F, 0xA2}} ISurface2 :: struct #raw_union { #subtype idxgisurface1: ISurface1, using idxgisurface2_vtable: ^ISurface2_VTable, @@ -730,7 +747,8 @@ ISurface2_VTable :: struct { GetResource: proc "stdcall" (this: ^ISurface2, riid: ^IID, ppParentResource: ^rawptr, pSubresourceIndex: ^u32) -> HRESULT, } -IResource1_UUID :: "30961379-4609-4A41-998E-54FE567EE0C1" +IResource1_UUID_STRING :: "30961379-4609-4A41-998E-54FE567EE0C1" +IResource1_UUID := &IID{0x30961379, 0x4609, 0x4A41, {0x99, 0x8E, 0x54, 0xFE, 0x56, 0x7E, 0xE0, 0xC1}} IResource1 :: struct #raw_union { #subtype idxgiresource: IResource, using idxgiresource1_vtable: ^IResource1_VTable, @@ -747,7 +765,8 @@ OFFER_RESOURCE_PRIORITY :: enum i32 { } -IDevice2_UUID :: "05008617-FBFD-4051-A790-144884B4F6A9" +IDevice2_UUID_STRING :: "05008617-FBFD-4051-A790-144884B4F6A9" +IDevice2_UUID := &IID{0x05008617, 0xFBFD, 0x4051, {0xA7, 0x90, 0x14, 0x48, 0x84, 0xB4, 0xF6, 0xA9}} IDevice2 :: struct #raw_union { #subtype idxgidevice1: IDevice1, using idxgidevice2_vtable: ^IDevice2_VTable, @@ -804,7 +823,8 @@ PRESENT_PARAMETERS :: struct { } -ISwapChain1_UUID :: "790A45F7-0D42-4876-983A-0A55CFE6F4AA" +ISwapChain1_UUID_STRING :: "790A45F7-0D42-4876-983A-0A55CFE6F4AA" +ISwapChain1_UUID := &IID{0x790A45F7, 0x0D42, 0x4876, {0x98, 0x3A, 0x0A, 0x55, 0xCF, 0xE6, 0xF4, 0xAA}} ISwapChain1 :: struct #raw_union { #subtype idxgiswapchain: ISwapChain, using idxgiswapchain1_vtable: ^ISwapChain1_VTable, @@ -824,7 +844,8 @@ ISwapChain1_VTable :: struct { GetRotation: proc "stdcall" (this: ^ISwapChain1, pRotation: ^MODE_ROTATION) -> HRESULT, } -IFactory2_UUID :: "50C83A1C-E072-4C48-87B0-3630FA36A6D0" +IFactory2_UUID_STRING :: "50C83A1C-E072-4C48-87B0-3630FA36A6D0" +IFactory2_UUID := &IID{0x50C83A1C, 0xE072, 0x4C48, {0x87, 0xB0, 0x36, 0x30, 0xFA, 0x36, 0xA6, 0xD0}} IFactory2 :: struct #raw_union { #subtype idxgifactory1: IFactory1, using idxgifactory2_vtable: ^IFactory2_VTable, @@ -875,7 +896,8 @@ ADAPTER_DESC2 :: struct { } -IAdapter2_UUID :: "0AA1AE0A-FA0E-4B84-8644-E05FF8E5ACB5" +IAdapter2_UUID_STRING :: "0AA1AE0A-FA0E-4B84-8644-E05FF8E5ACB5" +IAdapter2_UUID := &IID{0x0AA1AE0A, 0xFA0E, 0x4B84, {0x86, 0x44, 0xE0, 0x5F, 0xF8, 0xE5, 0xAC, 0xB5}} IAdapter2 :: struct #raw_union { #subtype idxgiadapter1: IAdapter1, using idxgiadapter2_vtable: ^IAdapter2_VTable, @@ -885,7 +907,8 @@ IAdapter2_VTable :: struct { GetDesc2: proc "stdcall" (this: ^IAdapter2, pDesc: ^ADAPTER_DESC2) -> HRESULT, } -IOutput1_UUID :: "00CDDEA8-939B-4B83-A340-A685226666CC" +IOutput1_UUID_STRING :: "00CDDEA8-939B-4B83-A340-A685226666CC" +IOutput1_UUID := &IID{0x00CDDEA8, 0x939B, 0x4B83, {0xA3, 0x40, 0xA6, 0x85, 0x22, 0x66, 0x66, 0xCC}} IOutput1 :: struct #raw_union { #subtype idxgioutput: IOutput, using idxgioutput1_vtable: ^IOutput1_VTable, @@ -897,7 +920,8 @@ IOutput1_VTable :: struct { GetDisplaySurfaceData1: proc "stdcall" (this: ^IOutput1, pDestination: ^IResource) -> HRESULT, DuplicateOutput: proc "stdcall" (this: ^IOutput1, pDevice: ^IUnknown, ppOutputDuplication: ^^IOutputDuplication) -> HRESULT, } -IDevice3_UUID :: "6007896C-3244-4AFD-BF18-A6D3BEDA5023" +IDevice3_UUID_STRING :: "6007896C-3244-4AFD-BF18-A6D3BEDA5023" +IDevice3_UUID := &IID{0x6007896C, 0x3244, 0x4AFD, {0xBF, 0x18, 0xA6, 0xD3, 0xBE, 0xDA, 0x50, 0x23}} IDevice3 :: struct #raw_union { #subtype idxgidevice2: IDevice2, using idxgidevice3_vtable: ^IDevice3_VTable, @@ -916,7 +940,8 @@ MATRIX_3X2_F :: struct { } -ISwapChain2_UUID :: "A8BE2AC4-199F-4946-B331-79599FB98DE7" +ISwapChain2_UUID_STRING :: "A8BE2AC4-199F-4946-B331-79599FB98DE7" +ISwapChain2_UUID := &IID{0xA8BE2AC4, 0x199F, 0x4946, {0xB3, 0x31, 0x79, 0x59, 0x9F, 0xB9, 0x8D, 0xE7}} ISwapChain2 :: struct #raw_union { #subtype idxgiswapchain1: ISwapChain1, using idxgiswapchain2_vtable: ^ISwapChain2_VTable, @@ -932,7 +957,8 @@ ISwapChain2_VTable :: struct { GetMatrixTransform: proc "stdcall" (this: ^ISwapChain2, pMatrix: ^MATRIX_3X2_F) -> HRESULT, } -IOutput2_UUID :: "595E39D1-2724-4663-99B1-DA969DE28364" +IOutput2_UUID_STRING :: "595E39D1-2724-4663-99B1-DA969DE28364" +IOutput2_UUID := &IID{0x595E39D1, 0x2724, 0x4663, {0x99, 0xB1, 0xDA, 0x96, 0x9D, 0xE2, 0x83, 0x64}} IOutput2 :: struct #raw_union { #subtype idxgioutput1: IOutput1, using idxgioutput2_vtable: ^IOutput2_VTable, @@ -942,7 +968,8 @@ IOutput2_VTable :: struct { SupportsOverlays: proc "stdcall" (this: ^IOutput2) -> BOOL, } -IFactory3_UUID :: "25483823-CD46-4C7D-86CA-47AA95B837BD" +IFactory3_UUID_STRING :: "25483823-CD46-4C7D-86CA-47AA95B837BD" +IFactory3_UUID := &IID{0x25483823, 0xCD46, 0x4C7D, {0x86, 0xCA, 0x47, 0xAA, 0x95, 0xB8, 0x37, 0xBD}} IFactory3 :: struct #raw_union { #subtype idxgifactory2: IFactory2, using idxgifactory3_vtable: ^IFactory3_VTable, @@ -962,7 +989,8 @@ MULTIPLANE_OVERLAY_YCbCr_FLAGS :: enum u32 { // TODO: convert to bit_set } -IDecodeSwapChain_UUID :: "2633066B-4514-4C7A-8FD8-12EA98059D18" +IDecodeSwapChain_UUID_STRING :: "2633066B-4514-4C7A-8FD8-12EA98059D18" +IDecodeSwapChain_UUID := &IID{0x2633066B, 0x4514, 0x4C7A, {0x8F, 0xD8, 0x12, 0xEA, 0x98, 0x05, 0x9D, 0x18}} IDecodeSwapChain :: struct #raw_union { #subtype iunknown: IUnknown, using idxgidecodeswapchain_vtable: ^IDecodeSwapChain_VTable, @@ -980,7 +1008,8 @@ IDecodeSwapChain_VTable :: struct { GetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain) -> MULTIPLANE_OVERLAY_YCbCr_FLAGS, } -IFactoryMedia_UUID :: "41E7D1F2-A591-4F7B-A2E5-FA9C843E1C12" +IFactoryMedia_UUID_STRING :: "41E7D1F2-A591-4F7B-A2E5-FA9C843E1C12" +IFactoryMedia_UUID := &IID{0x41E7D1F2, 0xA591, 0x4F7B, {0xA2, 0xE5, 0xFA, 0x9C, 0x84, 0x3E, 0x1C, 0x12}} IFactoryMedia :: struct #raw_union { #subtype iunknown: IUnknown, using idxgifactorymedia_vtable: ^IFactoryMedia_VTable, @@ -1008,7 +1037,8 @@ FRAME_STATISTICS_MEDIA :: struct { } -ISwapChainMedia_UUID :: "DD95B90B-F05F-4F6A-BD65-25BFB264BD84" +ISwapChainMedia_UUID_STRING :: "DD95B90B-F05F-4F6A-BD65-25BFB264BD84" +ISwapChainMedia_UUID := &IID{0xDD95B90B, 0xF05F, 0x4F6A, {0xBD, 0x65, 0x25, 0xBF, 0xB2, 0x64, 0xBD, 0x84}} ISwapChainMedia :: struct #raw_union { #subtype iunknown: IUnknown, using idxgiswapchainmedia_vtable: ^ISwapChainMedia_VTable, @@ -1025,7 +1055,8 @@ OVERLAY_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set } -IOutput3_UUID :: "8A6BB301-7E7E-41F4-A8E0-5B32F7F99B18" +IOutput3_UUID_STRING :: "8A6BB301-7E7E-41F4-A8E0-5B32F7F99B18" +IOutput3_UUID := &IID{0x8A6BB301, 0x7E7E, 0x41F4, {0xA8, 0xE0, 0x5B, 0x32, 0xF7, 0xF9, 0x9B, 0x18}} IOutput3 :: struct #raw_union { #subtype idxgioutput2: IOutput2, using idxgioutput3_vtable: ^IOutput3_VTable, @@ -1040,7 +1071,8 @@ SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set } -ISwapChain3_UUID :: "94D99BDB-F1F8-4AB0-B236-7DA0170EDAB1" +ISwapChain3_UUID_STRING :: "94D99BDB-F1F8-4AB0-B236-7DA0170EDAB1" +ISwapChain3_UUID := &IID{0x94D99BDB, 0xF1F8, 0x4AB0, {0xB2, 0x36, 0x7D, 0xA0, 0x17, 0x0E, 0xDA, 0xB1}} ISwapChain3 :: struct #raw_union { #subtype idxgiswapchain2: ISwapChain2, using idxgiswapchain3_vtable: ^ISwapChain3_VTable, @@ -1057,7 +1089,8 @@ OVERLAY_COLOR_SPACE_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set } -IOutput4_UUID :: "DC7DCA35-2196-414D-9F53-617884032A60" +IOutput4_UUID_STRING :: "DC7DCA35-2196-414D-9F53-617884032A60" +IOutput4_UUID := &IID{0xDC7DCA35, 0x2196, 0x414D, {0x9F, 0x53, 0x61, 0x78, 0x84, 0x03, 0x2A, 0x60}} IOutput4 :: struct #raw_union { #subtype idxgioutput3: IOutput3, using idxgioutput4_vtable: ^IOutput4_VTable, @@ -1067,7 +1100,8 @@ IOutput4_VTable :: struct { CheckOverlayColorSpaceSupport: proc "stdcall" (this: ^IOutput4, Format: FORMAT, ColorSpace: COLOR_SPACE_TYPE, pConcernedDevice: ^IUnknown, pFlags: ^u32) -> HRESULT, } -IFactory4_UUID :: "1BC6EA02-EF36-464F-BF0C-21CA39E5168A" +IFactory4_UUID_STRING :: "1BC6EA02-EF36-464F-BF0C-21CA39E5168A" +IFactory4_UUID := &IID{0x1BC6EA02, 0xEF36, 0x464F, {0xBF, 0x0C, 0x21, 0xCA, 0x39, 0xE5, 0x16, 0x8A}} IFactory4 :: struct #raw_union { #subtype idxgifactory3: IFactory3, using idxgifactory4_vtable: ^IFactory4_VTable, @@ -1090,7 +1124,8 @@ QUERY_VIDEO_MEMORY_INFO :: struct { } -IAdapter3_UUID :: "645967A4-1392-4310-A798-8053CE3E93FD" +IAdapter3_UUID_STRING :: "645967A4-1392-4310-A798-8053CE3E93FD" +IAdapter3_UUID := &IID{0x645967A4, 0x1392, 0x4310, {0xA7, 0x98, 0x80, 0x53, 0xCE, 0x3E, 0x93, 0xFD}} IAdapter3 :: struct #raw_union { #subtype idxgiadapter2: IAdapter2, using idxgiadapter3_vtable: ^IAdapter3_VTable, From bea2f3644325454e7fe0e12313528359d0782843 Mon Sep 17 00:00:00 2001 From: CiD- Date: Thu, 17 Feb 2022 10:48:30 -0500 Subject: [PATCH 0213/1052] improve entry point check logic --- src/llvm_backend.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index c777819c3..07b8e97b2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1468,9 +1468,8 @@ void lb_generate_code(lbGenerator *gen) { if ((e->scope->flags&ScopeFlag_Init) && name == "main") { GB_ASSERT(e == info->entry_point); } - if (e->Procedure.is_export || - (e->Procedure.link_name.len > 0) || - ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { + if (build_context.command_kind == Command_test && + (e->Procedure.is_export || e->Procedure.link_name.len > 0)) { String link_name = e->Procedure.link_name; if (e->pkg->kind == Package_Runtime) { if (link_name == "main" || From ffc45e8cc239ebf72e38a17a47a57c19e8b4cb39 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 17 Feb 2022 20:48:37 +0000 Subject: [PATCH 0214/1052] Add `intrinsics.constant_utf16_cstring` --- src/check_builtin.cpp | 49 +++++++++++++++--------- src/checker_builtin_procs.hpp | 6 +++ src/llvm_backend_proc.cpp | 71 +++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 18 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c7ada8e03..1535f6644 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -223,31 +223,28 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Sliceinfo->objc_msgSend_types, call, data); mutex_unlock(&c->info->objc_types_mutex); - add_package_dependency(c, "runtime", "objc_lookUpClass"); - add_package_dependency(c, "runtime", "sel_registerName"); - add_package_dependency(c, "runtime", "objc_allocateClassPair"); - add_package_dependency(c, "runtime", "objc_msgSend"); add_package_dependency(c, "runtime", "objc_msgSend_fpret"); add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); add_package_dependency(c, "runtime", "objc_msgSend_stret"); } +bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) { + Operand op = {}; + check_expr(c, &op, expr); + if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) { + if (name_) *name_ = op.value.value_string; + return true; + } + gbString e = expr_to_string(op.expr); + gbString t = type_to_string(op.type); + error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; +} + bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { - auto const is_constant_string = [](CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) -> bool { - Operand op = {}; - check_expr(c, &op, expr); - if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) { - if (name_) *name_ = op.value.value_string; - return true; - } - gbString e = expr_to_string(op.expr); - gbString t = type_to_string(op.type); - error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t); - gb_string_free(t); - gb_string_free(e); - return false; - }; String builtin_name = builtin_procs[id].name; if (build_context.metrics.os != TargetOs_darwin) { @@ -371,6 +368,10 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } operand->mode = Addressing_Value; + + add_package_dependency(c, "runtime", "objc_lookUpClass"); + add_package_dependency(c, "runtime", "sel_registerName"); + add_package_dependency(c, "runtime", "objc_allocateClassPair"); return true; } break; } @@ -4086,6 +4087,18 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_constant_utf16_cstring: + { + String value = {}; + if (!is_constant_string(c, builtin_name, ce->args[0], &value)) { + return false; + } + operand->mode = Addressing_Value; + operand->type = alloc_type_multi_pointer(t_u16); + operand->value = {}; + break; + } + } diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 19fa94ee6..cba952ddf 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -258,6 +258,9 @@ BuiltinProc__type_end, BuiltinProc_objc_register_selector, BuiltinProc_objc_register_class, + BuiltinProc_constant_utf16_cstring, + + BuiltinProc_COUNT, }; gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { @@ -517,4 +520,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + }; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 261e2819c..7bc7fb61f 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2122,6 +2122,77 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr); case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr); case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr); + + + case BuiltinProc_constant_utf16_cstring: + { + auto const encode_surrogate_pair = [](Rune r, u16 *r1, u16 *r2) { + if (r < 0x10000 || r > 0x10ffff) { + *r1 = 0xfffd; + *r2 = 0xfffd; + } else { + r -= 0x10000; + *r1 = 0xd800 + ((r>>10)&0x3ff); + *r2 = 0xdc00 + (r&0x3ff); + } + }; + + lbModule *m = p->module; + + auto tav = type_and_value_of_expr(ce->args[0]); + GB_ASSERT(tav.value.kind == ExactValue_String); + String value = tav.value.value_string; + + LLVMTypeRef llvm_u16 = lb_type(m, t_u16); + + isize max_len = value.len*2 + 1; + LLVMValueRef *buffer = gb_alloc_array(temporary_allocator(), LLVMValueRef, max_len); + isize n = 0; + while (value.len > 0) { + Rune r = 0; + isize w = gb_utf8_decode(value.text, value.len, &r); + value.text += w; + value.len -= w; + if ((0 <= r && r < 0xd800) || (0xe000 <= r && r < 0x10000)) { + buffer[n++] = LLVMConstInt(llvm_u16, cast(u16)r, false); + } else if (0x10000 <= r && r <= 0x10ffff) { + u16 r1, r2; + encode_surrogate_pair(r, &r1, &r2); + buffer[n++] = LLVMConstInt(llvm_u16, r1, false); + buffer[n++] = LLVMConstInt(llvm_u16, r2, false); + } else { + buffer[n++] = LLVMConstInt(llvm_u16, 0xfffd, false); + } + } + + buffer[n++] = LLVMConstInt(llvm_u16, 0, false); + + LLVMValueRef array = LLVMConstArray(llvm_u16, buffer, cast(unsigned int)n); + + char *name = nullptr; + { + isize max_len = 7+8+1; + name = gb_alloc_array(permanent_allocator(), char, max_len); + u32 id = m->gen->global_array_index.fetch_add(1); + isize len = gb_snprintf(name, max_len, "csbs$%x", id); + len -= 1; + } + LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name); + LLVMSetInitializer(global_data, array); + LLVMSetLinkage(global_data, LLVMInternalLinkage); + + + + LLVMValueRef indices[] = { + LLVMConstInt(lb_type(m, t_u32), 0, false), + LLVMConstInt(lb_type(m, t_u32), 0, false), + }; + lbValue res = {}; + res.type = tv.type; + res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), ""); + return res; + + } } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); From 746d5fc322a410625435fd05bb847481919a918f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 17 Feb 2022 20:48:50 +0000 Subject: [PATCH 0215/1052] Correct D3D packages --- vendor/directx/d3d11/d3d11.odin | 2 +- vendor/directx/d3d_compiler/d3d_compiler.odin | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vendor/directx/d3d11/d3d11.odin b/vendor/directx/d3d11/d3d11.odin index b880d2e67..2adb7925a 100644 --- a/vendor/directx/d3d11/d3d11.odin +++ b/vendor/directx/d3d11/d3d11.odin @@ -2361,7 +2361,7 @@ IDeviceContext_VTable :: struct { ClearRenderTargetView: proc "stdcall" (this: ^IDeviceContext, pRenderTargetView: ^IRenderTargetView, ColorRGBA: ^[4]f32), ClearUnorderedAccessViewUint: proc "stdcall" (this: ^IDeviceContext, pUnorderedAccessView: ^IUnorderedAccessView, Values: ^[4]u32), ClearUnorderedAccessViewFloat: proc "stdcall" (this: ^IDeviceContext, pUnorderedAccessView: ^IUnorderedAccessView, Values: ^[4]f32), - ClearDepthStencilView: proc "stdcall" (this: ^IDeviceContext, pDepthStencilView: ^IDepthStencilView, ClearFlags: u32, Depth: f32, Stencil: u8), + ClearDepthStencilView: proc "stdcall" (this: ^IDeviceContext, pDepthStencilView: ^IDepthStencilView, ClearFlags: CLEAR_FLAG, Depth: f32, Stencil: u8), GenerateMips: proc "stdcall" (this: ^IDeviceContext, pShaderResourceView: ^IShaderResourceView), SetResourceMinLOD: proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource, MinLOD: f32), GetResourceMinLOD: proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource) -> f32, diff --git a/vendor/directx/d3d_compiler/d3d_compiler.odin b/vendor/directx/d3d_compiler/d3d_compiler.odin index 559452f78..2506f239c 100644 --- a/vendor/directx/d3d_compiler/d3d_compiler.odin +++ b/vendor/directx/d3d_compiler/d3d_compiler.odin @@ -111,7 +111,7 @@ SHADER_MACRO :: struct { ID3D10Blob_UUID_STRING :: "8BA5FB08-5195-40E2-AC58-0D989C3A0102" ID3D10Blob_UUID := &IID{0x8BA5FB08, 0x5195, 0x40E2, {0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02}} -ID3D10Blob :: struct { +ID3D10Blob :: struct #raw_union { #subtype iunknown: IUnknown, using id3d10blob_vtable: ^ID3D10Blob_VTable, } @@ -143,7 +143,7 @@ ID3DInclude_VTable :: struct { } -ID3D11Module :: struct { +ID3D11Module :: struct #raw_union { #subtype iunknown: IUnknown, using id3d11module_vtable: ^ID3D11Module_VTable, } @@ -153,7 +153,7 @@ ID3D11Module_VTable :: struct { } -ID3D11ModuleInstance :: struct { +ID3D11ModuleInstance :: struct #raw_union { #subtype iunknown: IUnknown, using id3d11moduleinstance_vtable: ^ID3D11ModuleInstance_VTable, } @@ -172,7 +172,7 @@ ID3D11ModuleInstance_VTable :: struct { } -ID3D11Linker :: struct { +ID3D11Linker :: struct #raw_union { #subtype iunknown: IUnknown, using id3d11linker_vtable: ^ID3D11Linker_VTable, } From 197b83299229a6d8733b2b6b2b3397ea717fbb17 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 15:56:53 +0000 Subject: [PATCH 0216/1052] Add vendor:directx and vendor:darwin packages for documentation generation --- examples/all/all_vendor.odin | 18 ++++++++++++++++-- src/check_builtin.cpp | 5 +++-- vendor/darwin/Foundation/NSArray.odin | 1 - .../darwin/Foundation/NSAutoreleasePool.odin | 1 - vendor/darwin/Foundation/NSBundle.odin | 1 - vendor/darwin/Foundation/NSData.odin | 1 - vendor/darwin/Foundation/NSDate.odin | 1 - vendor/darwin/Foundation/NSDictionary.odin | 1 - vendor/darwin/Foundation/NSEnumerator.odin | 1 - vendor/darwin/Foundation/NSError.odin | 1 - vendor/darwin/Foundation/NSLock.odin | 1 - vendor/darwin/Foundation/NSNotification.odin | 1 - vendor/darwin/Foundation/NSNumber.odin | 7 ++++--- vendor/darwin/Foundation/NSObject.odin | 1 - vendor/darwin/Foundation/NSRange.odin | 1 - vendor/darwin/Foundation/NSString.odin | 1 - vendor/darwin/Foundation/NSTypes.odin | 1 - vendor/darwin/Foundation/NSURL.odin | 1 - vendor/darwin/Foundation/NSWindow.odin | 1 - vendor/darwin/Metal/MetalClasses.odin | 1 - vendor/darwin/Metal/MetalEnums.odin | 1 - vendor/darwin/Metal/MetalErrors.odin | 1 - vendor/darwin/Metal/MetalProcedures.odin | 1 - vendor/darwin/Metal/MetalTypes.odin | 1 - vendor/darwin/QuartzCore/QuartzCore.odin | 1 - 25 files changed, 23 insertions(+), 29 deletions(-) diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index f94e092af..9aa109e5b 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -1,7 +1,6 @@ //+build windows package all - import botan "vendor:botan" import ENet "vendor:ENet" import gl "vendor:OpenGL" @@ -25,6 +24,15 @@ import stb_vorbis "vendor:stb/vorbis" import vk "vendor:vulkan" +import D3D11 "vendor:directx/d3d11" +import D3D12 "vendor:directx/d3d12" +import DXGI "vendor:directx/dxgi" + +// note these are technicaly darwin only but they are added to aid with documentation generation +import NS "vendor:darwin/Foundation" +import MTL "vendor:darwin/Metal" +import CA "vendor:darwin/QuartzCore" + _ :: botan _ :: ENet @@ -44,4 +52,10 @@ _ :: stbi _ :: stbrp _ :: stbtt _ :: stb_vorbis -_ :: vk \ No newline at end of file +_ :: vk +_ :: D3D11 +_ :: D3D12 +_ :: DXGI +_ :: NS +_ :: MTL +_ :: CA \ No newline at end of file diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1535f6644..fb7a6efce 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -248,8 +248,9 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call String builtin_name = builtin_procs[id].name; if (build_context.metrics.os != TargetOs_darwin) { - error(call, "'%.*s' only works on darwin", LIT(builtin_name)); - return false; + if (!build_context.generate_docs) { // allow on doc generation (e.g. Metal stuff) + error(call, "'%.*s' only works on darwin", LIT(builtin_name)); + } } diff --git a/vendor/darwin/Foundation/NSArray.odin b/vendor/darwin/Foundation/NSArray.odin index 4392c2791..d6021838b 100644 --- a/vendor/darwin/Foundation/NSArray.odin +++ b/vendor/darwin/Foundation/NSArray.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSAutoreleasePool.odin b/vendor/darwin/Foundation/NSAutoreleasePool.odin index f0157107e..a388a7146 100644 --- a/vendor/darwin/Foundation/NSAutoreleasePool.odin +++ b/vendor/darwin/Foundation/NSAutoreleasePool.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSAutoreleasePool") diff --git a/vendor/darwin/Foundation/NSBundle.odin b/vendor/darwin/Foundation/NSBundle.odin index 2e9d0df83..5e136378b 100644 --- a/vendor/darwin/Foundation/NSBundle.odin +++ b/vendor/darwin/Foundation/NSBundle.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSBundle") diff --git a/vendor/darwin/Foundation/NSData.odin b/vendor/darwin/Foundation/NSData.odin index b5367af07..3c6369e86 100644 --- a/vendor/darwin/Foundation/NSData.odin +++ b/vendor/darwin/Foundation/NSData.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSData") diff --git a/vendor/darwin/Foundation/NSDate.odin b/vendor/darwin/Foundation/NSDate.odin index 5aef42c13..e30cb07d0 100644 --- a/vendor/darwin/Foundation/NSDate.odin +++ b/vendor/darwin/Foundation/NSDate.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSDate") diff --git a/vendor/darwin/Foundation/NSDictionary.odin b/vendor/darwin/Foundation/NSDictionary.odin index 54f2e3446..3832c05f1 100644 --- a/vendor/darwin/Foundation/NSDictionary.odin +++ b/vendor/darwin/Foundation/NSDictionary.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSDictionary") diff --git a/vendor/darwin/Foundation/NSEnumerator.odin b/vendor/darwin/Foundation/NSEnumerator.odin index 0f1bdc482..1c7ddeed2 100644 --- a/vendor/darwin/Foundation/NSEnumerator.odin +++ b/vendor/darwin/Foundation/NSEnumerator.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:c" diff --git a/vendor/darwin/Foundation/NSError.odin b/vendor/darwin/Foundation/NSError.odin index 868e6acc6..23e6eaba7 100644 --- a/vendor/darwin/Foundation/NSError.odin +++ b/vendor/darwin/Foundation/NSError.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation foreign import "system:Foundation.framework" diff --git a/vendor/darwin/Foundation/NSLock.odin b/vendor/darwin/Foundation/NSLock.odin index 48c3a0e23..c48b5dbad 100644 --- a/vendor/darwin/Foundation/NSLock.odin +++ b/vendor/darwin/Foundation/NSLock.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation Locking :: struct($T: typeid) {using _: Object} diff --git a/vendor/darwin/Foundation/NSNotification.odin b/vendor/darwin/Foundation/NSNotification.odin index da9874bbc..ec8dddab7 100644 --- a/vendor/darwin/Foundation/NSNotification.odin +++ b/vendor/darwin/Foundation/NSNotification.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSNotification") diff --git a/vendor/darwin/Foundation/NSNumber.odin b/vendor/darwin/Foundation/NSNumber.odin index eb28b7099..b0cfbfb40 100644 --- a/vendor/darwin/Foundation/NSNumber.odin +++ b/vendor/darwin/Foundation/NSNumber.odin @@ -1,10 +1,11 @@ -//+build darwin package objc_Foundation import "core:c" -#assert(size_of(c.long) == size_of(int)) -#assert(size_of(c.ulong) == size_of(uint)) +when ODIN_OS == .Darwin { + #assert(size_of(c.long) == size_of(int)) + #assert(size_of(c.ulong) == size_of(uint)) +} @(objc_class="NSValue") Value :: struct{using _: Copying(Value)} diff --git a/vendor/darwin/Foundation/NSObject.odin b/vendor/darwin/Foundation/NSObject.odin index 33ef26a23..1ce17f2f5 100644 --- a/vendor/darwin/Foundation/NSObject.odin +++ b/vendor/darwin/Foundation/NSObject.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSRange.odin b/vendor/darwin/Foundation/NSRange.odin index 48bce5f38..74ce595a3 100644 --- a/vendor/darwin/Foundation/NSRange.odin +++ b/vendor/darwin/Foundation/NSRange.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation Range :: struct { diff --git a/vendor/darwin/Foundation/NSString.odin b/vendor/darwin/Foundation/NSString.odin index 5807db2db..45b5df37b 100644 --- a/vendor/darwin/Foundation/NSString.odin +++ b/vendor/darwin/Foundation/NSString.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation foreign import "system:Foundation.framework" diff --git a/vendor/darwin/Foundation/NSTypes.odin b/vendor/darwin/Foundation/NSTypes.odin index 2cb9000e9..47f75630f 100644 --- a/vendor/darwin/Foundation/NSTypes.odin +++ b/vendor/darwin/Foundation/NSTypes.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSURL.odin b/vendor/darwin/Foundation/NSURL.odin index 995117a65..72e5fc906 100644 --- a/vendor/darwin/Foundation/NSURL.odin +++ b/vendor/darwin/Foundation/NSURL.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSURL") diff --git a/vendor/darwin/Foundation/NSWindow.odin b/vendor/darwin/Foundation/NSWindow.odin index 654009bda..dec5a160c 100644 --- a/vendor/darwin/Foundation/NSWindow.odin +++ b/vendor/darwin/Foundation/NSWindow.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 4bc43002d..9713bba02 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalEnums.odin b/vendor/darwin/Metal/MetalEnums.odin index 5cfa33558..2a6ab749a 100644 --- a/vendor/darwin/Metal/MetalEnums.odin +++ b/vendor/darwin/Metal/MetalEnums.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalErrors.odin b/vendor/darwin/Metal/MetalErrors.odin index da37b59ff..f214466e5 100644 --- a/vendor/darwin/Metal/MetalErrors.odin +++ b/vendor/darwin/Metal/MetalErrors.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalProcedures.odin b/vendor/darwin/Metal/MetalProcedures.odin index 24ec2f8dd..b76c7f541 100644 --- a/vendor/darwin/Metal/MetalProcedures.odin +++ b/vendor/darwin/Metal/MetalProcedures.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalTypes.odin b/vendor/darwin/Metal/MetalTypes.odin index 1aabfa83e..673769c09 100644 --- a/vendor/darwin/Metal/MetalTypes.odin +++ b/vendor/darwin/Metal/MetalTypes.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/QuartzCore/QuartzCore.odin b/vendor/darwin/QuartzCore/QuartzCore.odin index 7bcf216f1..fb6e04b07 100644 --- a/vendor/darwin/QuartzCore/QuartzCore.odin +++ b/vendor/darwin/QuartzCore/QuartzCore.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_QuartzCore import NS "vendor:darwin/Foundation" From 7e33a86d5433eac2b0182c49d90d0f762e74c2ea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:01:11 +0000 Subject: [PATCH 0217/1052] Remove unneeded semicolon --- vendor/darwin/Metal/MetalEnums.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/darwin/Metal/MetalEnums.odin b/vendor/darwin/Metal/MetalEnums.odin index 2a6ab749a..7d72483ff 100644 --- a/vendor/darwin/Metal/MetalEnums.odin +++ b/vendor/darwin/Metal/MetalEnums.odin @@ -26,7 +26,7 @@ AccelerationStructureInstanceDescriptorType :: enum NS.UInteger { Default = 0, UserID = 1, Motion = 2, -}; +} DataType :: enum NS.UInteger { From 454c92dc64b43934062a661c6e05ea4168b1b78e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:05:26 +0000 Subject: [PATCH 0218/1052] Allow objc intrinsics within `odin check` and `odin docs` but disallow for `odin build` --- src/check_builtin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index fb7a6efce..c6b7de506 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -248,7 +248,8 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call String builtin_name = builtin_procs[id].name; if (build_context.metrics.os != TargetOs_darwin) { - if (!build_context.generate_docs) { // allow on doc generation (e.g. Metal stuff) + // allow on doc generation (e.g. Metal stuff) + if (!build_context.command_kind == Command_doc && !builtin_name.command_kind == Command_check) { error(call, "'%.*s' only works on darwin", LIT(builtin_name)); } } From 1843d522173a646786a226320e1443d43591fbca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:07:06 +0000 Subject: [PATCH 0219/1052] Fix typo --- src/check_builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c6b7de506..f440aa4d5 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -249,7 +249,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call if (build_context.metrics.os != TargetOs_darwin) { // allow on doc generation (e.g. Metal stuff) - if (!build_context.command_kind == Command_doc && !builtin_name.command_kind == Command_check) { + if (build_context.command_kind != Command_doc && build_context.command_kind != Command_check) { error(call, "'%.*s' only works on darwin", LIT(builtin_name)); } } From 5f8137025d0abb946c186dc01271495cf839a871 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:12:21 +0000 Subject: [PATCH 0220/1052] Use `try_to_add_package_dependency` --- src/check_builtin.cpp | 14 +++++++------- src/checker.cpp | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index f440aa4d5..eb9d7f293 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -223,10 +223,10 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Sliceinfo->objc_msgSend_types, call, data); mutex_unlock(&c->info->objc_types_mutex); - add_package_dependency(c, "runtime", "objc_msgSend"); - add_package_dependency(c, "runtime", "objc_msgSend_fpret"); - add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); - add_package_dependency(c, "runtime", "objc_msgSend_stret"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend_fpret"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret"); } bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) { @@ -371,9 +371,9 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } operand->mode = Addressing_Value; - add_package_dependency(c, "runtime", "objc_lookUpClass"); - add_package_dependency(c, "runtime", "sel_registerName"); - add_package_dependency(c, "runtime", "objc_allocateClassPair"); + try_to_add_package_dependency(c, "runtime", "objc_lookUpClass"); + try_to_add_package_dependency(c, "runtime", "sel_registerName"); + try_to_add_package_dependency(c, "runtime", "objc_allocateClassPair"); return true; } break; } diff --git a/src/checker.cpp b/src/checker.cpp index 81e6f256e..f8aa8d45b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -733,12 +733,25 @@ void add_package_dependency(CheckerContext *c, char const *package_name, char co String n = make_string_c(name); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); Entity *e = scope_lookup(p->scope, n); - e->flags |= EntityFlag_Used; GB_ASSERT_MSG(e != nullptr, "%s", name); GB_ASSERT(c->decl != nullptr); + e->flags |= EntityFlag_Used; add_dependency(c->info, c->decl, e); } +void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { + String n = make_string_c(name); + AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); + Entity *e = scope_lookup(p->scope, n); + if (e == nullptr) { + return; + } + GB_ASSERT(c->decl != nullptr); + e->flags |= EntityFlag_Used; + add_dependency(c->info, c->decl, e); +} + + void add_declaration_dependency(CheckerContext *c, Entity *e) { if (e == nullptr) { return; From 4c62a32b046e8b804f58830113b3f60ba48716a9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:13:52 +0000 Subject: [PATCH 0221/1052] Keep -vet happy --- vendor/darwin/Foundation/NSNumber.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vendor/darwin/Foundation/NSNumber.odin b/vendor/darwin/Foundation/NSNumber.odin index b0cfbfb40..9201557a3 100644 --- a/vendor/darwin/Foundation/NSNumber.odin +++ b/vendor/darwin/Foundation/NSNumber.odin @@ -1,8 +1,9 @@ package objc_Foundation -import "core:c" - when ODIN_OS == .Darwin { + import "core:c" + _ :: c + #assert(size_of(c.long) == size_of(int)) #assert(size_of(c.ulong) == size_of(uint)) } From cd89d8a3c414a6929ec058a04aeec568d99505a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:24:08 +0000 Subject: [PATCH 0222/1052] Add better error message for compiler when OOM happens --- src/common_memory.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/common_memory.cpp b/src/common_memory.cpp index 096c35b5c..953462077 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -139,6 +139,7 @@ struct PlatformMemoryBlock { }; +gb_global std::atomic global_platform_memory_total_usage; gb_global PlatformMemoryBlock global_platform_memory_block_sentinel; PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size); @@ -158,10 +159,17 @@ void platform_virtual_memory_protect(void *memory, isize size); PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) { PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)VirtualAlloc(0, total_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no..."); + if (pmblock == nullptr) { + gb_printf_err("Out of Virtual memory, oh no...\n"); + gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size); + gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage); + GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no..."); + } + global_platform_memory_total_usage += total_size; return pmblock; } void platform_virtual_memory_free(PlatformMemoryBlock *block) { + global_platform_memory_total_usage -= block->total_size; GB_ASSERT(VirtualFree(block, 0, MEM_RELEASE)); } void platform_virtual_memory_protect(void *memory, isize size) { @@ -180,11 +188,18 @@ void platform_virtual_memory_protect(void *memory, isize size); PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) { PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no..."); + if (pmblock == nullptr) { + gb_printf_err("Out of Virtual memory, oh no...\n"); + gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size); + gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage); + GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no..."); + } + global_platform_memory_total_usage += total_size; return pmblock; } void platform_virtual_memory_free(PlatformMemoryBlock *block) { isize size = block->total_size; + global_platform_memory_total_usage -= size; munmap(block, size); } void platform_virtual_memory_protect(void *memory, isize size) { From 71df46456a4db2592e8cebbdd4c46dc8b58b5a24 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 21:30:25 +0000 Subject: [PATCH 0223/1052] Minimize memory usage by having an arena per thread rather than an arena per file --- src/array.cpp | 4 +++- src/checker.cpp | 4 ++-- src/common.cpp | 2 +- src/main.cpp | 2 +- src/parser.cpp | 12 ++++++------ src/parser.hpp | 6 ++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/array.cpp b/src/array.cpp index ac3727978..d08bd647f 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -89,7 +89,9 @@ template void slice_init(Slice *s, gbAllocator const &allocator, isize count) { GB_ASSERT(count >= 0); s->data = gb_alloc_array(allocator, T, count); - GB_ASSERT(s->data != nullptr); + if (count > 0) { + GB_ASSERT(s->data != nullptr); + } s->count = count; } diff --git a/src/checker.cpp b/src/checker.cpp index f8aa8d45b..f440b7c9a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -225,8 +225,8 @@ bool decl_info_has_init(DeclInfo *d) { Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) { Scope *s = gb_alloc_item(permanent_allocator(), Scope); s->parent = parent; - string_map_init(&s->elements, permanent_allocator(), init_elements_capacity); - ptr_set_init(&s->imported, permanent_allocator(), 0); + string_map_init(&s->elements, heap_allocator(), init_elements_capacity); + ptr_set_init(&s->imported, heap_allocator(), 0); mutex_init(&s->mutex); if (parent != nullptr && parent != builtin_pkg->scope) { diff --git a/src/common.cpp b/src/common.cpp index ab2a46118..d3ee95b76 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1021,7 +1021,7 @@ LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_fil #endif } - gbFileContents fc = gb_file_read_contents(heap_allocator(), true, fullpath); + gbFileContents fc = gb_file_read_contents(permanent_allocator(), true, fullpath); if (fc.size > I32_MAX) { err = LoadedFile_FileTooLarge; diff --git a/src/main.cpp b/src/main.cpp index 014fbf822..291b56996 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2577,7 +2577,7 @@ int main(int arg_count, char const **arg_ptr) { // NOTE(bill): add 'shared' directory if it is not already set if (!find_library_collection_path(str_lit("shared"), nullptr)) { add_library_collection(str_lit("shared"), - get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared"))); + get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared"))); } diff --git a/src/parser.cpp b/src/parser.cpp index 7309d9769..8a7ab2d20 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -57,6 +57,9 @@ isize ast_node_size(AstKind kind) { return align_formula_isize(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind], gb_align_of(void *)); } + +gb_global std::atomic global_total_node_memory_allocated; + // NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++ Ast *alloc_ast_node(AstFile *f, AstKind kind) { gbAllocator a = ast_allocator(f); @@ -66,6 +69,9 @@ Ast *alloc_ast_node(AstFile *f, AstKind kind) { Ast *node = cast(Ast *)gb_alloc(a, size); node->kind = kind; node->file_id = f ? f->id : 0; + + global_total_node_memory_allocated += size; + return node; } @@ -4851,12 +4857,6 @@ ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) { f->prev_token = f->tokens[f->prev_token_index]; f->curr_token = f->tokens[f->curr_token_index]; - isize const page_size = 4*1024; - isize block_size = 2*f->tokens.count*gb_size_of(Ast); - block_size = ((block_size + page_size-1)/page_size) * page_size; - block_size = gb_clamp(block_size, page_size, DEFAULT_MINIMUM_BLOCK_SIZE); - f->arena.minimum_block_size = block_size; - array_init(&f->comments, heap_allocator(), 0, 0); array_init(&f->imports, heap_allocator(), 0, 0); diff --git a/src/parser.hpp b/src/parser.hpp index 83c755553..f6791a291 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -97,8 +97,6 @@ struct AstFile { AstPackage * pkg; Scope * scope; - Arena arena; - Ast * pkg_decl; String fullpath; Tokenizer tokenizer; @@ -801,10 +799,10 @@ gb_inline bool is_ast_when_stmt(Ast *node) { return node->kind == Ast_WhenStmt; } -gb_global gb_thread_local Arena global_ast_arena = {}; +gb_global gb_thread_local Arena global_thread_local_ast_arena = {}; gbAllocator ast_allocator(AstFile *f) { - Arena *arena = f ? &f->arena : &global_ast_arena; + Arena *arena = &global_thread_local_ast_arena; return arena_allocator(arena); } From 23be56af597882100db9a167a82771a98b654cf5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 21:45:20 +0000 Subject: [PATCH 0224/1052] Remove prefixes from D3D12 constants --- vendor/directx/d3d12/d3d12_constants.odin | 1058 ++++++++++----------- 1 file changed, 529 insertions(+), 529 deletions(-) diff --git a/vendor/directx/d3d12/d3d12_constants.odin b/vendor/directx/d3d12/d3d12_constants.odin index 0fbda6b6a..3f83dca6b 100644 --- a/vendor/directx/d3d12/d3d12_constants.odin +++ b/vendor/directx/d3d12/d3d12_constants.odin @@ -1,531 +1,531 @@ package directx_d3d12 -D3D_FL9_1_REQ_TEXTURE1D_U_DIMENSION :: 2048 -D3D_FL9_3_REQ_TEXTURE1D_U_DIMENSION :: 4096 -D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 2048 -D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 4096 -D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION :: 512 -D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION :: 4096 -D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 256 -D3D_FL9_1_DEFAULT_MAX_ANISOTROPY :: 2 -D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT :: 65535 -D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT :: 1048575 -D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT :: 1 -D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT :: 4 -D3D_FL9_1_MAX_TEXTURE_REPEAT :: 128 -D3D_FL9_2_MAX_TEXTURE_REPEAT :: 2048 -D3D_FL9_3_MAX_TEXTURE_REPEAT :: 8192 - -D3D_COMPONENT_MASK_X :: 1 -D3D_COMPONENT_MASK_Y :: 2 -D3D_COMPONENT_MASK_Z :: 4 -D3D_COMPONENT_MASK_W :: 8 - -D3D12_16BIT_INDEX_STRIP_CUT_VALUE :: 0xffff -D3D12_32BIT_INDEX_STRIP_CUT_VALUE :: 0xffffffff -D3D12_8BIT_INDEX_STRIP_CUT_VALUE :: 0xff - -D3D12_APPEND_ALIGNED_ELEMENT :: 0xffffffff -D3D12_ARRAY_AXIS_ADDRESS_RANGE_BIT_COUNT :: 9 - -D3D12_CLIP_OR_CULL_DISTANCE_COUNT :: 8 -D3D12_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT :: 2 - -D3D12_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT :: 14 -D3D12_COMMONSHADER_CONSTANT_BUFFER_COMPONENTS :: 4 -D3D12_COMMONSHADER_CONSTANT_BUFFER_COMPONENT_BIT_COUNT :: 32 -D3D12_COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT :: 15 -D3D12_COMMONSHADER_CONSTANT_BUFFER_PARTIAL_UPDATE_EXTENTS_BYTE_ALIGNMENT :: 16 -D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 -D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT :: 15 -D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 -D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 -D3D12_COMMONSHADER_FLOWCONTROL_NESTING_LIMIT :: 64 -D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 -D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COUNT :: 1 -D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 -D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 -D3D12_COMMONSHADER_IMMEDIATE_VALUE_COMPONENT_BIT_COUNT :: 32 -D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_COMPONENTS :: 1 -D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT :: 128 -D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_READS_PER_INST :: 1 -D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_READ_PORTS :: 1 -D3D12_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT :: 128 -D3D12_COMMONSHADER_SAMPLER_REGISTER_COMPONENTS :: 1 -D3D12_COMMONSHADER_SAMPLER_REGISTER_COUNT :: 16 -D3D12_COMMONSHADER_SAMPLER_REGISTER_READS_PER_INST :: 1 -D3D12_COMMONSHADER_SAMPLER_REGISTER_READ_PORTS :: 1 -D3D12_COMMONSHADER_SAMPLER_SLOT_COUNT :: 16 -D3D12_COMMONSHADER_SUBROUTINE_NESTING_LIMIT :: 32 -D3D12_COMMONSHADER_TEMP_REGISTER_COMPONENTS :: 4 -D3D12_COMMONSHADER_TEMP_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_COMMONSHADER_TEMP_REGISTER_COUNT :: 4096 -D3D12_COMMONSHADER_TEMP_REGISTER_READS_PER_INST :: 3 -D3D12_COMMONSHADER_TEMP_REGISTER_READ_PORTS :: 3 -D3D12_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MAX :: 10 -D3D12_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MIN :: -10 -D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE :: -8 -D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE :: 7 - -D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT :: 256 - -D3D12_CS_4_X_BUCKET00_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 256 -D3D12_CS_4_X_BUCKET00_MAX_NUM_THREADS_PER_GROUP :: 64 -D3D12_CS_4_X_BUCKET01_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 240 -D3D12_CS_4_X_BUCKET01_MAX_NUM_THREADS_PER_GROUP :: 68 -D3D12_CS_4_X_BUCKET02_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 224 -D3D12_CS_4_X_BUCKET02_MAX_NUM_THREADS_PER_GROUP :: 72 -D3D12_CS_4_X_BUCKET03_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 208 -D3D12_CS_4_X_BUCKET03_MAX_NUM_THREADS_PER_GROUP :: 76 -D3D12_CS_4_X_BUCKET04_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 192 -D3D12_CS_4_X_BUCKET04_MAX_NUM_THREADS_PER_GROUP :: 84 -D3D12_CS_4_X_BUCKET05_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 176 -D3D12_CS_4_X_BUCKET05_MAX_NUM_THREADS_PER_GROUP :: 92 -D3D12_CS_4_X_BUCKET06_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 160 -D3D12_CS_4_X_BUCKET06_MAX_NUM_THREADS_PER_GROUP :: 100 -D3D12_CS_4_X_BUCKET07_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 144 -D3D12_CS_4_X_BUCKET07_MAX_NUM_THREADS_PER_GROUP :: 112 -D3D12_CS_4_X_BUCKET08_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 128 -D3D12_CS_4_X_BUCKET08_MAX_NUM_THREADS_PER_GROUP :: 128 -D3D12_CS_4_X_BUCKET09_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 112 -D3D12_CS_4_X_BUCKET09_MAX_NUM_THREADS_PER_GROUP :: 144 -D3D12_CS_4_X_BUCKET10_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 96 -D3D12_CS_4_X_BUCKET10_MAX_NUM_THREADS_PER_GROUP :: 168 -D3D12_CS_4_X_BUCKET11_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 80 -D3D12_CS_4_X_BUCKET11_MAX_NUM_THREADS_PER_GROUP :: 204 -D3D12_CS_4_X_BUCKET12_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 64 -D3D12_CS_4_X_BUCKET12_MAX_NUM_THREADS_PER_GROUP :: 256 -D3D12_CS_4_X_BUCKET13_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 48 -D3D12_CS_4_X_BUCKET13_MAX_NUM_THREADS_PER_GROUP :: 340 -D3D12_CS_4_X_BUCKET14_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 32 -D3D12_CS_4_X_BUCKET14_MAX_NUM_THREADS_PER_GROUP :: 512 -D3D12_CS_4_X_BUCKET15_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 16 -D3D12_CS_4_X_BUCKET15_MAX_NUM_THREADS_PER_GROUP :: 768 -D3D12_CS_4_X_DISPATCH_MAX_THREAD_GROUPS_IN_Z_DIMENSION :: 1 -D3D12_CS_4_X_RAW_UAV_BYTE_ALIGNMENT :: 256 -D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 768 -D3D12_CS_4_X_THREAD_GROUP_MAX_X :: 768 -D3D12_CS_4_X_THREAD_GROUP_MAX_Y :: 768 -D3D12_CS_4_X_UAV_REGISTER_COUNT :: 1 - -D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION :: 65535 -D3D12_CS_TGSM_REGISTER_COUNT :: 8192 -D3D12_CS_TGSM_REGISTER_READS_PER_INST :: 1 -D3D12_CS_TGSM_RESOURCE_REGISTER_COMPONENTS :: 1 -D3D12_CS_TGSM_RESOURCE_REGISTER_READ_PORTS :: 1 -D3D12_CS_THREADGROUPID_REGISTER_COMPONENTS :: 3 -D3D12_CS_THREADGROUPID_REGISTER_COUNT :: 1 -D3D12_CS_THREADIDINGROUPFLATTENED_REGISTER_COMPONENTS :: 1 -D3D12_CS_THREADIDINGROUPFLATTENED_REGISTER_COUNT :: 1 -D3D12_CS_THREADIDINGROUP_REGISTER_COMPONENTS :: 3 -D3D12_CS_THREADIDINGROUP_REGISTER_COUNT :: 1 -D3D12_CS_THREADID_REGISTER_COMPONENTS :: 3 -D3D12_CS_THREADID_REGISTER_COUNT :: 1 -D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 1024 -D3D12_CS_THREAD_GROUP_MAX_X :: 1024 -D3D12_CS_THREAD_GROUP_MAX_Y :: 1024 -D3D12_CS_THREAD_GROUP_MAX_Z :: 64 -D3D12_CS_THREAD_GROUP_MIN_X :: 1 -D3D12_CS_THREAD_GROUP_MIN_Y :: 1 -D3D12_CS_THREAD_GROUP_MIN_Z :: 1 -D3D12_CS_THREAD_LOCAL_TEMP_REGISTER_POOL :: 16384 - -D3D12_DEFAULT_BLEND_FACTOR_ALPHA :: 1.0 -D3D12_DEFAULT_BLEND_FACTOR_BLUE :: 1.0 -D3D12_DEFAULT_BLEND_FACTOR_GREEN :: 1.0 -D3D12_DEFAULT_BLEND_FACTOR_RED :: 1.0 -D3D12_DEFAULT_BORDER_COLOR_COMPONENT :: 0.0 -D3D12_DEFAULT_DEPTH_BIAS :: 0 -D3D12_DEFAULT_DEPTH_BIAS_CLAMP :: 0.0 -D3D12_DEFAULT_MAX_ANISOTROPY :: 16 -D3D12_DEFAULT_MIP_LOD_BIAS :: 0.0 -D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 4194304 -D3D12_DEFAULT_RENDER_TARGET_ARRAY_INDEX :: 0 - -D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT :: 65536 -D3D12_DEFAULT_SAMPLE_MASK :: 0xffffffff -D3D12_DEFAULT_SCISSOR_ENDX :: 0 -D3D12_DEFAULT_SCISSOR_ENDY :: 0 -D3D12_DEFAULT_SCISSOR_STARTX :: 0 -D3D12_DEFAULT_SCISSOR_STARTY :: 0 -D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS :: 0.0 -D3D12_DEFAULT_STENCIL_READ_MASK :: 0xff -D3D12_DEFAULT_STENCIL_REFERENCE :: 0 -D3D12_DEFAULT_STENCIL_WRITE_MASK :: 0xff -D3D12_DEFAULT_VIEWPORT_AND_SCISSORRECT_INDEX :: 0 -D3D12_DEFAULT_VIEWPORT_HEIGHT :: 0 -D3D12_DEFAULT_VIEWPORT_MAX_DEPTH :: 0.0 -D3D12_DEFAULT_VIEWPORT_MIN_DEPTH :: 0.0 -D3D12_DEFAULT_VIEWPORT_TOPLEFTX :: 0 -D3D12_DEFAULT_VIEWPORT_TOPLEFTY :: 0 -D3D12_DEFAULT_VIEWPORT_WIDTH :: 0 - -D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND :: 0xffffffff - -D3D12_DRIVER_RESERVED_REGISTER_SPACE_VALUES_END :: 0xfffffff7 -D3D12_DRIVER_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0 - -D3D12_DS_INPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 -D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENTS :: 4 -D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COUNT :: 32 -D3D12_DS_INPUT_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 -D3D12_DS_INPUT_CONTROL_POINT_REGISTER_READ_PORTS :: 1 -D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENTS :: 3 -D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COUNT :: 1 -D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_READS_PER_INST :: 2 -D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_READ_PORTS :: 1 -D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 -D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 -D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 -D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 -D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 -D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 -D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 -D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 -D3D12_DS_OUTPUT_REGISTER_COMPONENTS :: 4 -D3D12_DS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_DS_OUTPUT_REGISTER_COUNT :: 32 - -D3D12_FLOAT16_FUSED_TOLERANCE_IN_ULP :: 0.6 -D3D12_FLOAT32_MAX :: 3.402823466e+38 -D3D12_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP :: 0.6 -D3D12_FLOAT_TO_SRGB_EXPONENT_DENOMINATOR :: 2.4 -D3D12_FLOAT_TO_SRGB_EXPONENT_NUMERATOR :: 1.0 -D3D12_FLOAT_TO_SRGB_OFFSET :: 0.055 -D3D12_FLOAT_TO_SRGB_SCALE_1 :: 12.92 -D3D12_FLOAT_TO_SRGB_SCALE_2 :: 1.055 -D3D12_FLOAT_TO_SRGB_THRESHOLD :: 0.0031308 -D3D12_FTOI_INSTRUCTION_MAX_INPUT :: 2147483647.999 -D3D12_FTOI_INSTRUCTION_MIN_INPUT :: -2147483648.999 -D3D12_FTOU_INSTRUCTION_MAX_INPUT :: 4294967295.999 -D3D12_FTOU_INSTRUCTION_MIN_INPUT :: 0.0 - -D3D12_GS_INPUT_INSTANCE_ID_READS_PER_INST :: 2 -D3D12_GS_INPUT_INSTANCE_ID_READ_PORTS :: 1 -D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENTS :: 1 -D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COUNT :: 1 -D3D12_GS_INPUT_PRIM_CONST_REGISTER_COMPONENTS :: 1 -D3D12_GS_INPUT_PRIM_CONST_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_GS_INPUT_PRIM_CONST_REGISTER_COUNT :: 1 -D3D12_GS_INPUT_PRIM_CONST_REGISTER_READS_PER_INST :: 2 -D3D12_GS_INPUT_PRIM_CONST_REGISTER_READ_PORTS :: 1 -D3D12_GS_INPUT_REGISTER_COMPONENTS :: 4 -D3D12_GS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_GS_INPUT_REGISTER_COUNT :: 32 -D3D12_GS_INPUT_REGISTER_READS_PER_INST :: 2 -D3D12_GS_INPUT_REGISTER_READ_PORTS :: 1 -D3D12_GS_INPUT_REGISTER_VERTICES :: 32 -D3D12_GS_MAX_INSTANCE_COUNT :: 32 -D3D12_GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES :: 1024 -D3D12_GS_OUTPUT_ELEMENTS :: 32 -D3D12_GS_OUTPUT_REGISTER_COMPONENTS :: 4 -D3D12_GS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_GS_OUTPUT_REGISTER_COUNT :: 32 - -D3D12_HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT :: 32 -D3D12_HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT :: 32 -D3D12_HS_CONTROL_POINT_REGISTER_COMPONENTS :: 4 -D3D12_HS_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_HS_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 -D3D12_HS_CONTROL_POINT_REGISTER_READ_PORTS :: 1 -D3D12_HS_FORK_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff -D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENTS :: 1 -D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COUNT :: 1 -D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 -D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READ_PORTS :: 1 -D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENTS :: 1 -D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COUNT :: 1 -D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 -D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READ_PORTS :: 1 -D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 -D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 -D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 -D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 -D3D12_HS_JOIN_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff -D3D12_HS_MAXTESSFACTOR_LOWER_BOUND :: 1.0 -D3D12_HS_MAXTESSFACTOR_UPPER_BOUND :: 64.0 -D3D12_HS_OUTPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 -D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENTS :: 1 -D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COUNT :: 1 -D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READS_PER_INST :: 2 -D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READ_PORTS :: 1 -D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 -D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 -D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 -D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 -D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_SCALAR_COMPONENTS :: 128 - -D3D12_IA_DEFAULT_INDEX_BUFFER_OFFSET_IN_BYTES :: 0 -D3D12_IA_DEFAULT_PRIMITIVE_TOPOLOGY :: 0 -D3D12_IA_DEFAULT_VERTEX_BUFFER_OFFSET_IN_BYTES :: 0 -D3D12_IA_INDEX_INPUT_RESOURCE_SLOT_COUNT :: 1 -D3D12_IA_INSTANCE_ID_BIT_COUNT :: 32 -D3D12_IA_INTEGER_ARITHMETIC_BIT_COUNT :: 32 -D3D12_IA_PATCH_MAX_CONTROL_POINT_COUNT :: 32 -D3D12_IA_PRIMITIVE_ID_BIT_COUNT :: 32 -D3D12_IA_VERTEX_ID_BIT_COUNT :: 32 -D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT :: 32 -D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENTS_COMPONENTS :: 128 -D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT :: 32 - -D3D12_INTEGER_DIVIDE_BY_ZERO_QUOTIENT :: 0xffffffff -D3D12_INTEGER_DIVIDE_BY_ZERO_REMAINDER :: 0xffffffff - -D3D12_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL :: 0xffffffff -D3D12_KEEP_UNORDERED_ACCESS_VIEWS :: 0xffffffff - -D3D12_LINEAR_GAMMA :: 1.0 -D3D12_MAJOR_VERSION :: 12 - -D3D12_MAX_BORDER_COLOR_COMPONENT :: 1.0 -D3D12_MAX_DEPTH :: 1.0 -D3D12_MAX_LIVE_STATIC_SAMPLERS :: 2032 -D3D12_MAX_MAXANISOTROPY :: 16 -D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT :: 32 -D3D12_MAX_POSITION_VALUE :: 3.402823466e+34D3D12_MAX_ROOT_COST :: 64 -D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1 :: 1000000 -D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2 :: 1000000 -D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE :: 2048 -D3D12_MAX_TEXTURE_DIMENSION_2_TO_EXP :: 17 -D3D12_MAX_VIEW_INSTANCE_COUNT :: 4 - -D3D12_MINOR_VERSION :: 0 - -D3D12_MIN_BORDER_COLOR_COMPONENT :: 0.0 -D3D12_MIN_DEPTH :: 0.0 -D3D12_MIN_MAXANISOTROPY :: 0 - -D3D12_MIP_LOD_BIAS_MAX :: 15.99 -D3D12_MIP_LOD_BIAS_MIN :: -16.0 -D3D12_MIP_LOD_FRACTIONAL_BIT_COUNT :: 8 -D3D12_MIP_LOD_RANGE_BIT_COUNT :: 8 - -D3D12_MULTISAMPLE_ANTIALIAS_LINE_WIDTH :: 1.4 -D3D12_NONSAMPLE_FETCH_OUT_OF_RANGE_ACCESS_RESULT :: 0 - -D3D12_OS_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff -D3D12_OS_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff8 - -D3D12_PACKED_TILE :: 0xffffffff - -D3D12_PIXEL_ADDRESS_RANGE_BIT_COUNT :: 15 - -D3D12_PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT :: 16 - -D3D12_PS_CS_UAV_REGISTER_COMPONENTS :: 1 -D3D12_PS_CS_UAV_REGISTER_COUNT :: 8 -D3D12_PS_CS_UAV_REGISTER_READS_PER_INST :: 1 -D3D12_PS_CS_UAV_REGISTER_READ_PORTS :: 1 -D3D12_PS_FRONTFACING_DEFAULT_VALUE :: 0xffffffff -D3D12_PS_FRONTFACING_FALSE_VALUE :: 0 -D3D12_PS_FRONTFACING_TRUE_VALUE :: 0xffffffff -D3D12_PS_INPUT_REGISTER_COMPONENTS :: 4 -D3D12_PS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_PS_INPUT_REGISTER_COUNT :: 32 -D3D12_PS_INPUT_REGISTER_READS_PER_INST :: 2 -D3D12_PS_INPUT_REGISTER_READ_PORTS :: 1 -D3D12_PS_LEGACY_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.0 -D3D12_PS_OUTPUT_DEPTH_REGISTER_COMPONENTS :: 1 -D3D12_PS_OUTPUT_DEPTH_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_PS_OUTPUT_DEPTH_REGISTER_COUNT :: 1 -D3D12_PS_OUTPUT_MASK_REGISTER_COMPONENTS :: 1 -D3D12_PS_OUTPUT_MASK_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_PS_OUTPUT_MASK_REGISTER_COUNT :: 1 -D3D12_PS_OUTPUT_REGISTER_COMPONENTS :: 4 -D3D12_PS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_PS_OUTPUT_REGISTER_COUNT :: 8 -D3D12_PS_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.5 - -D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT :: 16 - -D3D12_RAYTRACING_AABB_BYTE_ALIGNMENT :: 8 -D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT :: 256 -D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT :: 16 -D3D12_RAYTRACING_MAX_ATTRIBUTE_SIZE_IN_BYTES :: 32 -D3D12_RAYTRACING_MAX_DECLARABLE_TRACE_RECURSION_DEPTH :: 31 -D3D12_RAYTRACING_MAX_GEOMETRIES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 16777216 -D3D12_RAYTRACING_MAX_INSTANCES_PER_TOP_LEVEL_ACCELERATION_STRUCTURE :: 16777216 -D3D12_RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 536870912 -D3D12_RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS :: 1073741824 -D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE :: 4096 -D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT :: 32 -D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT :: 64 -D3D12_RAYTRACING_TRANSFORM3X4_BYTE_ALIGNMENT :: 16 - -D3D12_REQ_BLEND_OBJECT_COUNT_PER_DEVICE :: 4096 -D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP :: 27 -D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 -D3D12_REQ_DEPTH_STENCIL_OBJECT_COUNT_PER_DEVICE :: 4096 -D3D12_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 32 -D3D12_REQ_DRAW_VERTEX_COUNT_2_TO_EXP :: 32 -D3D12_REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION :: 16384 -D3D12_REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT :: 1024 -D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 -D3D12_REQ_MAXANISOTROPY :: 16 -D3D12_REQ_MIP_LEVELS :: 15 -D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES :: 2048 -D3D12_REQ_RASTERIZER_OBJECT_COUNT_PER_DEVICE :: 4096 -D3D12_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH :: 16384 -D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM :: 128 -D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_B_TERM :: 0.25 -D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM :: 2048 -D3D12_REQ_RESOURCE_VIEW_COUNT_PER_DEVICE_2_TO_EXP :: 20 -D3D12_REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE :: 4096 -D3D12_REQ_SUBRESOURCES :: 30720 -D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION :: 2048 -D3D12_REQ_TEXTURE1D_U_DIMENSION :: 16384 -D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION :: 2048 -D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 16384 -D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 2048 -D3D12_REQ_TEXTURECUBE_DIMENSION :: 16384 - -D3D12_RESINFO_INSTRUCTION_MISSING_COMPONENT_RETVAL :: 0 - -D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES :: 0xffffffff - -D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT :: 2 - -D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES :: 32 -D3D12_SHADER_MAJOR_VERSION :: 5 -D3D12_SHADER_MAX_INSTANCES :: 65535 -D3D12_SHADER_MAX_INTERFACES :: 253 -D3D12_SHADER_MAX_INTERFACE_CALL_SITES :: 4096 -D3D12_SHADER_MAX_TYPES :: 65535 -D3D12_SHADER_MINOR_VERSION :: 1 - -D3D12_SHIFT_INSTRUCTION_PAD_VALUE :: 0 -D3D12_SHIFT_INSTRUCTION_SHIFT_VALUE_BIT_COUNT :: 5 - -D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT :: 8 - -D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 65536 -D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT :: 4096 - -D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES :: 2048 -D3D12_SO_BUFFER_MAX_WRITE_WINDOW_IN_BYTES :: 512 -D3D12_SO_BUFFER_SLOT_COUNT :: 4 -D3D12_SO_DDI_REGISTER_INDEX_DENOTING_GAP :: 0xffffffff -D3D12_SO_NO_RASTERIZED_STREAM :: 0xffffffff -D3D12_SO_OUTPUT_COMPONENT_COUNT :: 128 -D3D12_SO_STREAM_COUNT :: 4 - -D3D12_SPEC_DATE_DAY :: 14 -D3D12_SPEC_DATE_MONTH :: 11 -D3D12_SPEC_DATE_YEAR :: 2014 -D3D12_SPEC_VERSION :: 1.16 - -D3D12_SRGB_GAMMA :: 2.2 -D3D12_SRGB_TO_FLOAT_DENOMINATOR_1 :: 12.92 -D3D12_SRGB_TO_FLOAT_DENOMINATOR_2 :: 1.055 -D3D12_SRGB_TO_FLOAT_EXPONENT :: 2.4 -D3D12_SRGB_TO_FLOAT_OFFSET :: 0.055 -D3D12_SRGB_TO_FLOAT_THRESHOLD :: 0.04045 -D3D12_SRGB_TO_FLOAT_TOLERANCE_IN_ULP :: 0.5 - -D3D12_STANDARD_COMPONENT_BIT_COUNT :: 32 -D3D12_STANDARD_COMPONENT_BIT_COUNT_DOUBLED :: 64 -D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE :: 4 -D3D12_STANDARD_PIXEL_COMPONENT_COUNT :: 128 -D3D12_STANDARD_PIXEL_ELEMENT_COUNT :: 32 -D3D12_STANDARD_VECTOR_SIZE :: 4 -D3D12_STANDARD_VERTEX_ELEMENT_COUNT :: 32 -D3D12_STANDARD_VERTEX_TOTAL_COMPONENT_COUNT :: 64 - -D3D12_SUBPIXEL_FRACTIONAL_BIT_COUNT :: 8 -D3D12_SUBTEXEL_FRACTIONAL_BIT_COUNT :: 8 - -D3D12_SYSTEM_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff -D3D12_SYSTEM_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0 - -D3D12_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR :: 64 -D3D12_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 64 -D3D12_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR :: 63 -D3D12_TESSELLATOR_MAX_TESSELLATION_FACTOR :: 64 -D3D12_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR :: 2 -D3D12_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 1 -D3D12_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR :: 1 - -D3D12_TEXEL_ADDRESS_RANGE_BIT_COUNT :: 16 - -D3D12_TEXTURE_DATA_PITCH_ALIGNMENT :: 256 -D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT :: 512 - -D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES :: 65536 - -D3D12_TRACKED_WORKLOAD_MAX_INSTANCES :: 32 - -D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT :: 4096 -D3D12_UAV_SLOT_COUNT :: 64 - -D3D12_UNBOUND_MEMORY_ACCESS_RESULT :: 0 - -D3D12_VIDEO_DECODE_MAX_ARGUMENTS :: 10 -D3D12_VIDEO_DECODE_MAX_HISTOGRAM_COMPONENTS :: 4 -D3D12_VIDEO_DECODE_MIN_BITSTREAM_OFFSET_ALIGNMENT :: 256 -D3D12_VIDEO_DECODE_MIN_HISTOGRAM_OFFSET_ALIGNMENT :: 256 -D3D12_VIDEO_DECODE_STATUS_MACROBLOCKS_AFFECTED_UNKNOWN :: 0xffffffff -D3D12_VIDEO_PROCESS_MAX_FILTERS :: 32 -D3D12_VIDEO_PROCESS_STEREO_VIEWS :: 2 - -D3D12_VIEWPORT_AND_SCISSORRECT_MAX_INDEX :: 15 -D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE :: 16 -D3D12_VIEWPORT_BOUNDS_MAX :: 32767 -D3D12_VIEWPORT_BOUNDS_MIN :: -32768 - -D3D12_VS_INPUT_REGISTER_COMPONENTS :: 4 -D3D12_VS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_VS_INPUT_REGISTER_COUNT :: 32 -D3D12_VS_INPUT_REGISTER_READS_PER_INST :: 2 -D3D12_VS_INPUT_REGISTER_READ_PORTS :: 1 -D3D12_VS_OUTPUT_REGISTER_COMPONENTS :: 4 -D3D12_VS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 -D3D12_VS_OUTPUT_REGISTER_COUNT :: 32 - -D3D12_WHQL_CONTEXT_COUNT_FOR_RESOURCE_LIMIT :: 10 -D3D12_WHQL_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 25 -D3D12_WHQL_DRAW_VERTEX_COUNT_2_TO_EXP :: 25 - -D3D12_SHADER_COMPONENT_MAPPING_MASK :: 0x7 -D3D12_SHADER_COMPONENT_MAPPING_SHIFT :: 3 - -D3D12_FILTER_REDUCTION_TYPE_MASK :: 0x3 -D3D12_FILTER_REDUCTION_TYPE_SHIFT :: 7 -D3D12_FILTER_TYPE_MASK :: 0x3 - -D3D12_MIN_FILTER_SHIFT :: 4 -D3D12_MAG_FILTER_SHIFT :: 2 -D3D12_MIP_FILTER_SHIFT :: 0 - -D3D12_ANISOTROPIC_FILTERING_BIT :: 0x40 - -D3D12_INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT :: 1024 - -D3D12_SHADING_RATE_X_AXIS_SHIFT :: 2 -D3D12_SHADING_RATE_VALID_MASK :: 3 - -D3D_RETURN_PARAMETER_INDEX :: -1 - -D3D_SHADER_REQUIRES_DOUBLES :: 0x00000001 -D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL :: 0x00000002 -D3D_SHADER_REQUIRES_UAVS_AT_EVERY_STAGE :: 0x00000004 -D3D_SHADER_REQUIRES_64_UAVS :: 0x00000008 -D3D_SHADER_REQUIRES_MINIMUM_PRECISION :: 0x00000010 -D3D_SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS :: 0x00000020 -D3D_SHADER_REQUIRES_11_1_SHADER_EXTENSIONS :: 0x00000040 -D3D_SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING :: 0x00000080 -D3D_SHADER_REQUIRES_TILED_RESOURCES :: 0x00000100 -D3D_SHADER_REQUIRES_STENCIL_REF :: 0x00000200 -D3D_SHADER_REQUIRES_INNER_COVERAGE :: 0x00000400 -D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS :: 0x00000800 -D3D_SHADER_REQUIRES_ROVS :: 0x00001000 -D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER :: 0x00002000 +FL9_1_REQ_TEXTURE1D_U_DIMENSION :: 2048 +FL9_3_REQ_TEXTURE1D_U_DIMENSION :: 4096 +FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 2048 +FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 4096 +FL9_1_REQ_TEXTURECUBE_DIMENSION :: 512 +FL9_3_REQ_TEXTURECUBE_DIMENSION :: 4096 +FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 256 +FL9_1_DEFAULT_MAX_ANISOTROPY :: 2 +FL9_1_IA_PRIMITIVE_MAX_COUNT :: 65535 +FL9_2_IA_PRIMITIVE_MAX_COUNT :: 1048575 +FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT :: 1 +FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT :: 4 +FL9_1_MAX_TEXTURE_REPEAT :: 128 +FL9_2_MAX_TEXTURE_REPEAT :: 2048 +FL9_3_MAX_TEXTURE_REPEAT :: 8192 + +COMPONENT_MASK_X :: 1 +COMPONENT_MASK_Y :: 2 +COMPONENT_MASK_Z :: 4 +COMPONENT_MASK_W :: 8 + +_16BIT_INDEX_STRIP_CUT_VALUE :: 0xffff +_32BIT_INDEX_STRIP_CUT_VALUE :: 0xffffffff +_8BIT_INDEX_STRIP_CUT_VALUE :: 0xff + +APPEND_ALIGNED_ELEMENT :: 0xffffffff +ARRAY_AXIS_ADDRESS_RANGE_BIT_COUNT :: 9 + +CLIP_OR_CULL_DISTANCE_COUNT :: 8 +CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT :: 2 + +COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT :: 14 +COMMONSHADER_CONSTANT_BUFFER_COMPONENTS :: 4 +COMMONSHADER_CONSTANT_BUFFER_COMPONENT_BIT_COUNT :: 32 +COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT :: 15 +COMMONSHADER_CONSTANT_BUFFER_PARTIAL_UPDATE_EXTENTS_BYTE_ALIGNMENT :: 16 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT :: 15 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 +COMMONSHADER_FLOWCONTROL_NESTING_LIMIT :: 64 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COUNT :: 1 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1 +COMMONSHADER_IMMEDIATE_VALUE_COMPONENT_BIT_COUNT :: 32 +COMMONSHADER_INPUT_RESOURCE_REGISTER_COMPONENTS :: 1 +COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT :: 128 +COMMONSHADER_INPUT_RESOURCE_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_INPUT_RESOURCE_REGISTER_READ_PORTS :: 1 +COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT :: 128 +COMMONSHADER_SAMPLER_REGISTER_COMPONENTS :: 1 +COMMONSHADER_SAMPLER_REGISTER_COUNT :: 16 +COMMONSHADER_SAMPLER_REGISTER_READS_PER_INST :: 1 +COMMONSHADER_SAMPLER_REGISTER_READ_PORTS :: 1 +COMMONSHADER_SAMPLER_SLOT_COUNT :: 16 +COMMONSHADER_SUBROUTINE_NESTING_LIMIT :: 32 +COMMONSHADER_TEMP_REGISTER_COMPONENTS :: 4 +COMMONSHADER_TEMP_REGISTER_COMPONENT_BIT_COUNT :: 32 +COMMONSHADER_TEMP_REGISTER_COUNT :: 4096 +COMMONSHADER_TEMP_REGISTER_READS_PER_INST :: 3 +COMMONSHADER_TEMP_REGISTER_READ_PORTS :: 3 +COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MAX :: 10 +COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MIN :: -10 +COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE :: -8 +COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE :: 7 + +CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT :: 256 + +CS_4_X_BUCKET00_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 256 +CS_4_X_BUCKET00_MAX_NUM_THREADS_PER_GROUP :: 64 +CS_4_X_BUCKET01_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 240 +CS_4_X_BUCKET01_MAX_NUM_THREADS_PER_GROUP :: 68 +CS_4_X_BUCKET02_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 224 +CS_4_X_BUCKET02_MAX_NUM_THREADS_PER_GROUP :: 72 +CS_4_X_BUCKET03_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 208 +CS_4_X_BUCKET03_MAX_NUM_THREADS_PER_GROUP :: 76 +CS_4_X_BUCKET04_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 192 +CS_4_X_BUCKET04_MAX_NUM_THREADS_PER_GROUP :: 84 +CS_4_X_BUCKET05_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 176 +CS_4_X_BUCKET05_MAX_NUM_THREADS_PER_GROUP :: 92 +CS_4_X_BUCKET06_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 160 +CS_4_X_BUCKET06_MAX_NUM_THREADS_PER_GROUP :: 100 +CS_4_X_BUCKET07_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 144 +CS_4_X_BUCKET07_MAX_NUM_THREADS_PER_GROUP :: 112 +CS_4_X_BUCKET08_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 128 +CS_4_X_BUCKET08_MAX_NUM_THREADS_PER_GROUP :: 128 +CS_4_X_BUCKET09_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 112 +CS_4_X_BUCKET09_MAX_NUM_THREADS_PER_GROUP :: 144 +CS_4_X_BUCKET10_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 96 +CS_4_X_BUCKET10_MAX_NUM_THREADS_PER_GROUP :: 168 +CS_4_X_BUCKET11_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 80 +CS_4_X_BUCKET11_MAX_NUM_THREADS_PER_GROUP :: 204 +CS_4_X_BUCKET12_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 64 +CS_4_X_BUCKET12_MAX_NUM_THREADS_PER_GROUP :: 256 +CS_4_X_BUCKET13_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 48 +CS_4_X_BUCKET13_MAX_NUM_THREADS_PER_GROUP :: 340 +CS_4_X_BUCKET14_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 32 +CS_4_X_BUCKET14_MAX_NUM_THREADS_PER_GROUP :: 512 +CS_4_X_BUCKET15_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 16 +CS_4_X_BUCKET15_MAX_NUM_THREADS_PER_GROUP :: 768 +CS_4_X_DISPATCH_MAX_THREAD_GROUPS_IN_Z_DIMENSION :: 1 +CS_4_X_RAW_UAV_BYTE_ALIGNMENT :: 256 +CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 768 +CS_4_X_THREAD_GROUP_MAX_X :: 768 +CS_4_X_THREAD_GROUP_MAX_Y :: 768 +CS_4_X_UAV_REGISTER_COUNT :: 1 + +CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION :: 65535 +CS_TGSM_REGISTER_COUNT :: 8192 +CS_TGSM_REGISTER_READS_PER_INST :: 1 +CS_TGSM_RESOURCE_REGISTER_COMPONENTS :: 1 +CS_TGSM_RESOURCE_REGISTER_READ_PORTS :: 1 +CS_THREADGROUPID_REGISTER_COMPONENTS :: 3 +CS_THREADGROUPID_REGISTER_COUNT :: 1 +CS_THREADIDINGROUPFLATTENED_REGISTER_COMPONENTS :: 1 +CS_THREADIDINGROUPFLATTENED_REGISTER_COUNT :: 1 +CS_THREADIDINGROUP_REGISTER_COMPONENTS :: 3 +CS_THREADIDINGROUP_REGISTER_COUNT :: 1 +CS_THREADID_REGISTER_COMPONENTS :: 3 +CS_THREADID_REGISTER_COUNT :: 1 +CS_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 1024 +CS_THREAD_GROUP_MAX_X :: 1024 +CS_THREAD_GROUP_MAX_Y :: 1024 +CS_THREAD_GROUP_MAX_Z :: 64 +CS_THREAD_GROUP_MIN_X :: 1 +CS_THREAD_GROUP_MIN_Y :: 1 +CS_THREAD_GROUP_MIN_Z :: 1 +CS_THREAD_LOCAL_TEMP_REGISTER_POOL :: 16384 + +DEFAULT_BLEND_FACTOR_ALPHA :: 1.0 +DEFAULT_BLEND_FACTOR_BLUE :: 1.0 +DEFAULT_BLEND_FACTOR_GREEN :: 1.0 +DEFAULT_BLEND_FACTOR_RED :: 1.0 +DEFAULT_BORDER_COLOR_COMPONENT :: 0.0 +DEFAULT_DEPTH_BIAS :: 0 +DEFAULT_DEPTH_BIAS_CLAMP :: 0.0 +DEFAULT_MAX_ANISOTROPY :: 16 +DEFAULT_MIP_LOD_BIAS :: 0.0 +DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 4194304 +DEFAULT_RENDER_TARGET_ARRAY_INDEX :: 0 + +DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT :: 65536 +DEFAULT_SAMPLE_MASK :: 0xffffffff +DEFAULT_SCISSOR_ENDX :: 0 +DEFAULT_SCISSOR_ENDY :: 0 +DEFAULT_SCISSOR_STARTX :: 0 +DEFAULT_SCISSOR_STARTY :: 0 +DEFAULT_SLOPE_SCALED_DEPTH_BIAS :: 0.0 +DEFAULT_STENCIL_READ_MASK :: 0xff +DEFAULT_STENCIL_REFERENCE :: 0 +DEFAULT_STENCIL_WRITE_MASK :: 0xff +DEFAULT_VIEWPORT_AND_SCISSORRECT_INDEX :: 0 +DEFAULT_VIEWPORT_HEIGHT :: 0 +DEFAULT_VIEWPORT_MAX_DEPTH :: 0.0 +DEFAULT_VIEWPORT_MIN_DEPTH :: 0.0 +DEFAULT_VIEWPORT_TOPLEFTX :: 0 +DEFAULT_VIEWPORT_TOPLEFTY :: 0 +DEFAULT_VIEWPORT_WIDTH :: 0 + +DESCRIPTOR_RANGE_OFFSET_APPEND :: 0xffffffff + +DRIVER_RESERVED_REGISTER_SPACE_VALUES_END :: 0xfffffff7 +DRIVER_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0 + +DS_INPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 +DS_INPUT_CONTROL_POINT_REGISTER_COMPONENTS :: 4 +DS_INPUT_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_CONTROL_POINT_REGISTER_COUNT :: 32 +DS_INPUT_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 +DS_INPUT_CONTROL_POINT_REGISTER_READ_PORTS :: 1 +DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENTS :: 3 +DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_DOMAIN_POINT_REGISTER_COUNT :: 1 +DS_INPUT_DOMAIN_POINT_REGISTER_READS_PER_INST :: 2 +DS_INPUT_DOMAIN_POINT_REGISTER_READ_PORTS :: 1 +DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 +DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 +DS_INPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 +DS_INPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 +DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 +DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 +DS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 +DS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 +DS_OUTPUT_REGISTER_COMPONENTS :: 4 +DS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +DS_OUTPUT_REGISTER_COUNT :: 32 + +FLOAT16_FUSED_TOLERANCE_IN_ULP :: 0.6 +FLOAT32_MAX :: 3.402823466e+38 +FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP :: 0.6 +FLOAT_TO_SRGB_EXPONENT_DENOMINATOR :: 2.4 +FLOAT_TO_SRGB_EXPONENT_NUMERATOR :: 1.0 +FLOAT_TO_SRGB_OFFSET :: 0.055 +FLOAT_TO_SRGB_SCALE_1 :: 12.92 +FLOAT_TO_SRGB_SCALE_2 :: 1.055 +FLOAT_TO_SRGB_THRESHOLD :: 0.0031308 +FTOI_INSTRUCTION_MAX_INPUT :: 2147483647.999 +FTOI_INSTRUCTION_MIN_INPUT :: -2147483648.999 +FTOU_INSTRUCTION_MAX_INPUT :: 4294967295.999 +FTOU_INSTRUCTION_MIN_INPUT :: 0.0 + +GS_INPUT_INSTANCE_ID_READS_PER_INST :: 2 +GS_INPUT_INSTANCE_ID_READ_PORTS :: 1 +GS_INPUT_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +GS_INPUT_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_INPUT_INSTANCE_ID_REGISTER_COUNT :: 1 +GS_INPUT_PRIM_CONST_REGISTER_COMPONENTS :: 1 +GS_INPUT_PRIM_CONST_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_INPUT_PRIM_CONST_REGISTER_COUNT :: 1 +GS_INPUT_PRIM_CONST_REGISTER_READS_PER_INST :: 2 +GS_INPUT_PRIM_CONST_REGISTER_READ_PORTS :: 1 +GS_INPUT_REGISTER_COMPONENTS :: 4 +GS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_INPUT_REGISTER_COUNT :: 32 +GS_INPUT_REGISTER_READS_PER_INST :: 2 +GS_INPUT_REGISTER_READ_PORTS :: 1 +GS_INPUT_REGISTER_VERTICES :: 32 +GS_MAX_INSTANCE_COUNT :: 32 +GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES :: 1024 +GS_OUTPUT_ELEMENTS :: 32 +GS_OUTPUT_REGISTER_COMPONENTS :: 4 +GS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +GS_OUTPUT_REGISTER_COUNT :: 32 + +HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT :: 32 +HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT :: 32 +HS_CONTROL_POINT_REGISTER_COMPONENTS :: 4 +HS_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_CONTROL_POINT_REGISTER_READS_PER_INST :: 2 +HS_CONTROL_POINT_REGISTER_READ_PORTS :: 1 +HS_FORK_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff +HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_COUNT :: 1 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 +HS_INPUT_FORK_INSTANCE_ID_REGISTER_READ_PORTS :: 1 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENTS :: 1 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COUNT :: 1 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READS_PER_INST :: 2 +HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READ_PORTS :: 1 +HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1 +HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1 +HS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2 +HS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1 +HS_JOIN_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff +HS_MAXTESSFACTOR_LOWER_BOUND :: 1.0 +HS_MAXTESSFACTOR_UPPER_BOUND :: 64.0 +HS_OUTPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENTS :: 1 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COUNT :: 1 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READS_PER_INST :: 2 +HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READ_PORTS :: 1 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1 +HS_OUTPUT_PATCH_CONSTANT_REGISTER_SCALAR_COMPONENTS :: 128 + +IA_DEFAULT_INDEX_BUFFER_OFFSET_IN_BYTES :: 0 +IA_DEFAULT_PRIMITIVE_TOPOLOGY :: 0 +IA_DEFAULT_VERTEX_BUFFER_OFFSET_IN_BYTES :: 0 +IA_INDEX_INPUT_RESOURCE_SLOT_COUNT :: 1 +IA_INSTANCE_ID_BIT_COUNT :: 32 +IA_INTEGER_ARITHMETIC_BIT_COUNT :: 32 +IA_PATCH_MAX_CONTROL_POINT_COUNT :: 32 +IA_PRIMITIVE_ID_BIT_COUNT :: 32 +IA_VERTEX_ID_BIT_COUNT :: 32 +IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT :: 32 +IA_VERTEX_INPUT_STRUCTURE_ELEMENTS_COMPONENTS :: 128 +IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT :: 32 + +INTEGER_DIVIDE_BY_ZERO_QUOTIENT :: 0xffffffff +INTEGER_DIVIDE_BY_ZERO_REMAINDER :: 0xffffffff + +KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL :: 0xffffffff +KEEP_UNORDERED_ACCESS_VIEWS :: 0xffffffff + +LINEAR_GAMMA :: 1.0 +MAJOR_VERSION :: 12 + +MAX_BORDER_COLOR_COMPONENT :: 1.0 +MAX_DEPTH :: 1.0 +MAX_LIVE_STATIC_SAMPLERS :: 2032 +MAX_MAXANISOTROPY :: 16 +MAX_MULTISAMPLE_SAMPLE_COUNT :: 32 +MAX_POSITION_VALUE :: 3.402823466e+34D3D12_MAX_ROOT_COST :: 64 +MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1 :: 1000000 +MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2 :: 1000000 +MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE :: 2048 +MAX_TEXTURE_DIMENSION_2_TO_EXP :: 17 +MAX_VIEW_INSTANCE_COUNT :: 4 + +MINOR_VERSION :: 0 + +MIN_BORDER_COLOR_COMPONENT :: 0.0 +MIN_DEPTH :: 0.0 +MIN_MAXANISOTROPY :: 0 + +MIP_LOD_BIAS_MAX :: 15.99 +MIP_LOD_BIAS_MIN :: -16.0 +MIP_LOD_FRACTIONAL_BIT_COUNT :: 8 +MIP_LOD_RANGE_BIT_COUNT :: 8 + +MULTISAMPLE_ANTIALIAS_LINE_WIDTH :: 1.4 +NONSAMPLE_FETCH_OUT_OF_RANGE_ACCESS_RESULT :: 0 + +OS_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff +OS_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff8 + +PACKED_TILE :: 0xffffffff + +PIXEL_ADDRESS_RANGE_BIT_COUNT :: 15 + +PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT :: 16 + +PS_CS_UAV_REGISTER_COMPONENTS :: 1 +PS_CS_UAV_REGISTER_COUNT :: 8 +PS_CS_UAV_REGISTER_READS_PER_INST :: 1 +PS_CS_UAV_REGISTER_READ_PORTS :: 1 +PS_FRONTFACING_DEFAULT_VALUE :: 0xffffffff +PS_FRONTFACING_FALSE_VALUE :: 0 +PS_FRONTFACING_TRUE_VALUE :: 0xffffffff +PS_INPUT_REGISTER_COMPONENTS :: 4 +PS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_INPUT_REGISTER_COUNT :: 32 +PS_INPUT_REGISTER_READS_PER_INST :: 2 +PS_INPUT_REGISTER_READ_PORTS :: 1 +PS_LEGACY_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.0 +PS_OUTPUT_DEPTH_REGISTER_COMPONENTS :: 1 +PS_OUTPUT_DEPTH_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_OUTPUT_DEPTH_REGISTER_COUNT :: 1 +PS_OUTPUT_MASK_REGISTER_COMPONENTS :: 1 +PS_OUTPUT_MASK_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_OUTPUT_MASK_REGISTER_COUNT :: 1 +PS_OUTPUT_REGISTER_COMPONENTS :: 4 +PS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +PS_OUTPUT_REGISTER_COUNT :: 8 +PS_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.5 + +RAW_UAV_SRV_BYTE_ALIGNMENT :: 16 + +RAYTRACING_AABB_BYTE_ALIGNMENT :: 8 +RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT :: 256 +RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT :: 16 +RAYTRACING_MAX_ATTRIBUTE_SIZE_IN_BYTES :: 32 +RAYTRACING_MAX_DECLARABLE_TRACE_RECURSION_DEPTH :: 31 +RAYTRACING_MAX_GEOMETRIES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 16777216 +RAYTRACING_MAX_INSTANCES_PER_TOP_LEVEL_ACCELERATION_STRUCTURE :: 16777216 +RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 536870912 +RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS :: 1073741824 +RAYTRACING_MAX_SHADER_RECORD_STRIDE :: 4096 +RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT :: 32 +RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT :: 64 +RAYTRACING_TRANSFORM3X4_BYTE_ALIGNMENT :: 16 + +REQ_BLEND_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP :: 27 +REQ_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 +REQ_DEPTH_STENCIL_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 32 +REQ_DRAW_VERTEX_COUNT_2_TO_EXP :: 32 +REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION :: 16384 +REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT :: 1024 +REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096 +REQ_MAXANISOTROPY :: 16 +REQ_MIP_LEVELS :: 15 +REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES :: 2048 +REQ_RASTERIZER_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_RENDER_TO_BUFFER_WINDOW_WIDTH :: 16384 +REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM :: 128 +REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_B_TERM :: 0.25 +REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM :: 2048 +REQ_RESOURCE_VIEW_COUNT_PER_DEVICE_2_TO_EXP :: 20 +REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE :: 4096 +REQ_SUBRESOURCES :: 30720 +REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION :: 2048 +REQ_TEXTURE1D_U_DIMENSION :: 16384 +REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION :: 2048 +REQ_TEXTURE2D_U_OR_V_DIMENSION :: 16384 +REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 2048 +REQ_TEXTURECUBE_DIMENSION :: 16384 + +RESINFO_INSTRUCTION_MISSING_COMPONENT_RETVAL :: 0 + +RESOURCE_BARRIER_ALL_SUBRESOURCES :: 0xffffffff + +RS_SET_SHADING_RATE_COMBINER_COUNT :: 2 + +SHADER_IDENTIFIER_SIZE_IN_BYTES :: 32 +SHADER_MAJOR_VERSION :: 5 +SHADER_MAX_INSTANCES :: 65535 +SHADER_MAX_INTERFACES :: 253 +SHADER_MAX_INTERFACE_CALL_SITES :: 4096 +SHADER_MAX_TYPES :: 65535 +SHADER_MINOR_VERSION :: 1 + +SHIFT_INSTRUCTION_PAD_VALUE :: 0 +SHIFT_INSTRUCTION_SHIFT_VALUE_BIT_COUNT :: 5 + +SIMULTANEOUS_RENDER_TARGET_COUNT :: 8 + +SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 65536 +SMALL_RESOURCE_PLACEMENT_ALIGNMENT :: 4096 + +SO_BUFFER_MAX_STRIDE_IN_BYTES :: 2048 +SO_BUFFER_MAX_WRITE_WINDOW_IN_BYTES :: 512 +SO_BUFFER_SLOT_COUNT :: 4 +SO_DDI_REGISTER_INDEX_DENOTING_GAP :: 0xffffffff +SO_NO_RASTERIZED_STREAM :: 0xffffffff +SO_OUTPUT_COMPONENT_COUNT :: 128 +SO_STREAM_COUNT :: 4 + +SPEC_DATE_DAY :: 14 +SPEC_DATE_MONTH :: 11 +SPEC_DATE_YEAR :: 2014 +SPEC_VERSION :: 1.16 + +SRGB_GAMMA :: 2.2 +SRGB_TO_FLOAT_DENOMINATOR_1 :: 12.92 +SRGB_TO_FLOAT_DENOMINATOR_2 :: 1.055 +SRGB_TO_FLOAT_EXPONENT :: 2.4 +SRGB_TO_FLOAT_OFFSET :: 0.055 +SRGB_TO_FLOAT_THRESHOLD :: 0.04045 +SRGB_TO_FLOAT_TOLERANCE_IN_ULP :: 0.5 + +STANDARD_COMPONENT_BIT_COUNT :: 32 +STANDARD_COMPONENT_BIT_COUNT_DOUBLED :: 64 +STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE :: 4 +STANDARD_PIXEL_COMPONENT_COUNT :: 128 +STANDARD_PIXEL_ELEMENT_COUNT :: 32 +STANDARD_VECTOR_SIZE :: 4 +STANDARD_VERTEX_ELEMENT_COUNT :: 32 +STANDARD_VERTEX_TOTAL_COMPONENT_COUNT :: 64 + +SUBPIXEL_FRACTIONAL_BIT_COUNT :: 8 +SUBTEXEL_FRACTIONAL_BIT_COUNT :: 8 + +SYSTEM_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff +SYSTEM_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0 + +TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR :: 64 +TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 64 +TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR :: 63 +TESSELLATOR_MAX_TESSELLATION_FACTOR :: 64 +TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR :: 2 +TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 1 +TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR :: 1 + +TEXEL_ADDRESS_RANGE_BIT_COUNT :: 16 + +TEXTURE_DATA_PITCH_ALIGNMENT :: 256 +TEXTURE_DATA_PLACEMENT_ALIGNMENT :: 512 + +TILED_RESOURCE_TILE_SIZE_IN_BYTES :: 65536 + +TRACKED_WORKLOAD_MAX_INSTANCES :: 32 + +UAV_COUNTER_PLACEMENT_ALIGNMENT :: 4096 +UAV_SLOT_COUNT :: 64 + +UNBOUND_MEMORY_ACCESS_RESULT :: 0 + +VIDEO_DECODE_MAX_ARGUMENTS :: 10 +VIDEO_DECODE_MAX_HISTOGRAM_COMPONENTS :: 4 +VIDEO_DECODE_MIN_BITSTREAM_OFFSET_ALIGNMENT :: 256 +VIDEO_DECODE_MIN_HISTOGRAM_OFFSET_ALIGNMENT :: 256 +VIDEO_DECODE_STATUS_MACROBLOCKS_AFFECTED_UNKNOWN :: 0xffffffff +VIDEO_PROCESS_MAX_FILTERS :: 32 +VIDEO_PROCESS_STEREO_VIEWS :: 2 + +VIEWPORT_AND_SCISSORRECT_MAX_INDEX :: 15 +VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE :: 16 +VIEWPORT_BOUNDS_MAX :: 32767 +VIEWPORT_BOUNDS_MIN :: -32768 + +VS_INPUT_REGISTER_COMPONENTS :: 4 +VS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +VS_INPUT_REGISTER_COUNT :: 32 +VS_INPUT_REGISTER_READS_PER_INST :: 2 +VS_INPUT_REGISTER_READ_PORTS :: 1 +VS_OUTPUT_REGISTER_COMPONENTS :: 4 +VS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32 +VS_OUTPUT_REGISTER_COUNT :: 32 + +WHQL_CONTEXT_COUNT_FOR_RESOURCE_LIMIT :: 10 +WHQL_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 25 +WHQL_DRAW_VERTEX_COUNT_2_TO_EXP :: 25 + +SHADER_COMPONENT_MAPPING_MASK :: 0x7 +SHADER_COMPONENT_MAPPING_SHIFT :: 3 + +FILTER_REDUCTION_TYPE_MASK :: 0x3 +FILTER_REDUCTION_TYPE_SHIFT :: 7 +FILTER_TYPE_MASK :: 0x3 + +MIN_FILTER_SHIFT :: 4 +MAG_FILTER_SHIFT :: 2 +MIP_FILTER_SHIFT :: 0 + +ANISOTROPIC_FILTERING_BIT :: 0x40 + +INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT :: 1024 + +SHADING_RATE_X_AXIS_SHIFT :: 2 +SHADING_RATE_VALID_MASK :: 3 + +RETURN_PARAMETER_INDEX :: -1 + +SHADER_REQUIRES_DOUBLES :: 0x00000001 +SHADER_REQUIRES_EARLY_DEPTH_STENCIL :: 0x00000002 +SHADER_REQUIRES_UAVS_AT_EVERY_STAGE :: 0x00000004 +SHADER_REQUIRES_64_UAVS :: 0x00000008 +SHADER_REQUIRES_MINIMUM_PRECISION :: 0x00000010 +SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS :: 0x00000020 +SHADER_REQUIRES_11_1_SHADER_EXTENSIONS :: 0x00000040 +SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING :: 0x00000080 +SHADER_REQUIRES_TILED_RESOURCES :: 0x00000100 +SHADER_REQUIRES_STENCIL_REF :: 0x00000200 +SHADER_REQUIRES_INNER_COVERAGE :: 0x00000400 +SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS :: 0x00000800 +SHADER_REQUIRES_ROVS :: 0x00001000 +SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER :: 0x00002000 From 54a6637d38c5abd8a2b483d4505c9ea318b77dc0 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Fri, 18 Feb 2022 20:50:49 -0800 Subject: [PATCH 0225/1052] Use the _unix_fstat pointer to avoid 144B copies on fileIO --- core/os/os_linux.odin | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 140b84d8a..4edfa46da 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -501,11 +501,13 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { } file_size :: proc(fd: Handle) -> (i64, Errno) { - s, err := _fstat(fd) - if err != ERROR_NONE { - return 0, err - } - return max(s.size, 0), ERROR_NONE + // deliberately uninitialized; the syscall fills this buffer for us + s: OS_Stat = --- + result := _unix_fstat(fd, &s) + if result < 0 { + return 0, _get_errno(result) + } + return max(s.size, 0), ERROR_NONE } rename :: proc(old_path, new_path: string) -> Errno { From 276e014d180dc571571cab341dbadadf2cf07594 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 19 Feb 2022 15:45:01 +0000 Subject: [PATCH 0226/1052] Update comment in demo.odin --- examples/demo/demo.odin | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index a4b678ae7..044860ff7 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -11,22 +11,28 @@ import "core:intrinsics" import "core:math/big" /* - The Odin programming language is fast, concise, readable, pragmatic and open sourced. - It is designed with the intent of replacing C with the following goals: - * simplicity - * high performance - * built for modern systems - * joy of programming + Odin is a general-purpose programming language with distinct typing built + for high performance, modern systems and data-oriented programming. + + Odin is the C alternative for the Joy of Programming. # Installing Odin Getting Started - https://odin-lang.org/docs/install/ Instructions for downloading and install the Odin compiler and libraries. # Learning Odin + Getting Started - https://odin-lang.org/docs/install/ + Getting Started with Odin. Downloading, installing, and getting your + first program to compile and run. Overview of Odin - https://odin-lang.org/docs/overview/ - An overview of the Odin programming language. + An overview of the Odin programming language and its features. Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/ Answers to common questions about Odin. + Packages - https://pkg.odin-lang.org/ + Documentation for all the official packages part of the + core and vendor library collections. + Nightly Builds - https://odin-lang.org/docs/nightly/ + Get the latest nightly builds of Odin. */ the_basics :: proc() { From b3d797598e1411524171e0f0cd7e672cc1c85ef6 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sat, 19 Feb 2022 15:48:32 -0800 Subject: [PATCH 0227/1052] fprintf tweaked to avoid calling file_size --- core/fmt/fmt.odin | 66 +++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 360a00b32..d800fd149 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -236,10 +236,11 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int { wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi: Info arg_index: int = 0 + ret: int = 0 end := len(fmt) was_prev_index := false - size0 := io.size(auto_cast w) + total_size := 0 loop: for i := 0; i < end; /**/ { fi = Info{writer = w, good_arg_index = true, reordered = fi.reordered} @@ -249,7 +250,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 } if i > prev_i { - io.write_string(fi.writer, fmt[prev_i:i]) + ret, _ = io.write_string(fi.writer, fmt[prev_i:i]) + total_size += ret } if i >= end { break loop @@ -265,12 +267,14 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 } io.write_byte(fi.writer, char) + total_size += 1 continue loop } else if char == '{' { if i < end && fmt[i] == char { // Skip extra one i += 1 io.write_byte(fi.writer, char) + total_size += 1 continue loop } } @@ -301,7 +305,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index) if !fi.width_set { - io.write_string(w, "%!(BAD WIDTH)") + ret, _ = io.write_string(w, "%!(BAD WIDTH)") + total_size += ret } if fi.width < 0 { @@ -332,7 +337,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi.prec_set = false } if !fi.prec_set { - io.write_string(fi.writer, "%!(BAD PRECISION)") + ret, _ = io.write_string(fi.writer, "%!(BAD PRECISION)") + total_size += ret } was_prev_index = false } else { @@ -345,7 +351,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if i >= end { - io.write_string(fi.writer, "%!(NO VERB)") + ret, _ = io.write_string(fi.writer, "%!(NO VERB)") + total_size += ret break loop } @@ -355,10 +362,13 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { switch { case verb == '%': io.write_byte(fi.writer, '%') + total_size += 1 case !fi.good_arg_index: - io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)") + ret, _ = io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)") + total_size += ret case arg_index >= len(args): - io.write_string(fi.writer, "%!(MISSING ARGUMENT)") + ret, _ = io.write_string(fi.writer, "%!(MISSING ARGUMENT)") + total_size += ret case: fmt_arg(&fi, args[arg_index], verb) arg_index += 1 @@ -374,14 +384,16 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { arg_index = new_arg_index i = new_i } else { - io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER ") + ret, _ = io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER ") + total_size += ret // Skip over the bad argument start_index := i for i < end && fmt[i] != '}' && fmt[i] != ':' { i += 1 } fmt_arg(&fi, fmt[start_index:i], 'v') - io.write_string(fi.writer, ")") + ret, _ = io.write_string(fi.writer, ")") + total_size += ret } } @@ -414,7 +426,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index) if !fi.width_set { - io.write_string(fi.writer, "%!(BAD WIDTH)") + ret, _ = io.write_string(fi.writer, "%!(BAD WIDTH)") + total_size += ret } if fi.width < 0 { @@ -445,7 +458,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi.prec_set = false } if !fi.prec_set { - io.write_string(fi.writer, "%!(BAD PRECISION)") + ret, _ = io.write_string(fi.writer, "%!(BAD PRECISION)") + total_size += ret } was_prev_index = false } else { @@ -459,7 +473,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { if i >= end { - io.write_string(fi.writer, "%!(NO VERB)") + ret, _ = io.write_string(fi.writer, "%!(NO VERB)") + total_size += ret break loop } @@ -469,7 +484,8 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if i >= end { - io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)") + ret, _ = io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)") + total_size += ret break loop } @@ -478,11 +494,14 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { switch { case brace != '}': - io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)") + ret, _ = io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)") + total_size += ret case !fi.good_arg_index: - io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)") + ret, _ = io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)") + total_size += ret case arg_index >= len(args): - io.write_string(fi.writer, "%!(MISSING ARGUMENT)") + ret, _ = io.write_string(fi.writer, "%!(MISSING ARGUMENT)") + total_size += ret case: fmt_arg(&fi, args[arg_index], verb) arg_index += 1 @@ -491,25 +510,28 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if !fi.reordered && arg_index < len(args) { - io.write_string(fi.writer, "%!(EXTRA ") + ret, _ = io.write_string(fi.writer, "%!(EXTRA ") + total_size += ret for arg, index in args[arg_index:] { if index > 0 { - io.write_string(fi.writer, ", ") + ret, _ = io.write_string(fi.writer, ", ") + total_size += ret } if arg == nil { - io.write_string(fi.writer, "") + ret, _ = io.write_string(fi.writer, "") + total_size += ret } else { fmt_arg(&fi, args[index], 'v') } } - io.write_string(fi.writer, ")") + ret, _ = io.write_string(fi.writer, ")") + total_size += ret } io.flush(auto_cast w) - size1 := io.size(auto_cast w) - return int(size1 - size0) + return int(total_size) } // wprint_type is a utility procedure to write a ^runtime.Type_Info value to w From ddf9c4a65b1cddc44665274a311be2449d48977c Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sat, 19 Feb 2022 16:38:33 -0800 Subject: [PATCH 0228/1052] switch to passing total_size to the io.writers --- core/fmt/fmt.odin | 67 ++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index d800fd149..2dc7534f9 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -236,7 +236,6 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int { wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi: Info arg_index: int = 0 - ret: int = 0 end := len(fmt) was_prev_index := false @@ -250,8 +249,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 } if i > prev_i { - ret, _ = io.write_string(fi.writer, fmt[prev_i:i]) - total_size += ret + io.write_string(fi.writer, fmt[prev_i:i], &total_size) } if i >= end { break loop @@ -266,15 +264,13 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { // Skip extra one i += 1 } - io.write_byte(fi.writer, char) - total_size += 1 + io.write_byte(fi.writer, char, &total_size) continue loop } else if char == '{' { if i < end && fmt[i] == char { // Skip extra one i += 1 - io.write_byte(fi.writer, char) - total_size += 1 + io.write_byte(fi.writer, char, &total_size) continue loop } } @@ -305,8 +301,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index) if !fi.width_set { - ret, _ = io.write_string(w, "%!(BAD WIDTH)") - total_size += ret + io.write_string(w, "%!(BAD WIDTH)", &total_size) } if fi.width < 0 { @@ -337,8 +332,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi.prec_set = false } if !fi.prec_set { - ret, _ = io.write_string(fi.writer, "%!(BAD PRECISION)") - total_size += ret + io.write_string(fi.writer, "%!(BAD PRECISION)", &total_size) } was_prev_index = false } else { @@ -351,8 +345,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if i >= end { - ret, _ = io.write_string(fi.writer, "%!(NO VERB)") - total_size += ret + io.write_string(fi.writer, "%!(NO VERB)", &total_size) break loop } @@ -361,14 +354,11 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { switch { case verb == '%': - io.write_byte(fi.writer, '%') - total_size += 1 + io.write_byte(fi.writer, '%', &total_size) case !fi.good_arg_index: - ret, _ = io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)") - total_size += ret + io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)", &total_size) case arg_index >= len(args): - ret, _ = io.write_string(fi.writer, "%!(MISSING ARGUMENT)") - total_size += ret + io.write_string(fi.writer, "%!(MISSING ARGUMENT)", &total_size) case: fmt_arg(&fi, args[arg_index], verb) arg_index += 1 @@ -384,16 +374,14 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { arg_index = new_arg_index i = new_i } else { - ret, _ = io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER ") - total_size += ret + io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER ", &total_size) // Skip over the bad argument start_index := i for i < end && fmt[i] != '}' && fmt[i] != ':' { i += 1 } fmt_arg(&fi, fmt[start_index:i], 'v') - ret, _ = io.write_string(fi.writer, ")") - total_size += ret + io.write_string(fi.writer, ")", &total_size) } } @@ -426,8 +414,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index) if !fi.width_set { - ret, _ = io.write_string(fi.writer, "%!(BAD WIDTH)") - total_size += ret + io.write_string(fi.writer, "%!(BAD WIDTH)", &total_size) } if fi.width < 0 { @@ -458,8 +445,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi.prec_set = false } if !fi.prec_set { - ret, _ = io.write_string(fi.writer, "%!(BAD PRECISION)") - total_size += ret + io.write_string(fi.writer, "%!(BAD PRECISION)", &total_size) } was_prev_index = false } else { @@ -473,8 +459,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { if i >= end { - ret, _ = io.write_string(fi.writer, "%!(NO VERB)") - total_size += ret + io.write_string(fi.writer, "%!(NO VERB)", &total_size) break loop } @@ -484,8 +469,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if i >= end { - ret, _ = io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)") - total_size += ret + io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)", &total_size) break loop } @@ -494,14 +478,11 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { switch { case brace != '}': - ret, _ = io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)") - total_size += ret + io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)", &total_size) case !fi.good_arg_index: - ret, _ = io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)") - total_size += ret + io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)", &total_size) case arg_index >= len(args): - ret, _ = io.write_string(fi.writer, "%!(MISSING ARGUMENT)") - total_size += ret + io.write_string(fi.writer, "%!(MISSING ARGUMENT)", &total_size) case: fmt_arg(&fi, args[arg_index], verb) arg_index += 1 @@ -510,23 +491,19 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if !fi.reordered && arg_index < len(args) { - ret, _ = io.write_string(fi.writer, "%!(EXTRA ") - total_size += ret + io.write_string(fi.writer, "%!(EXTRA ", &total_size) for arg, index in args[arg_index:] { if index > 0 { - ret, _ = io.write_string(fi.writer, ", ") - total_size += ret + io.write_string(fi.writer, ", ", &total_size) } if arg == nil { - ret, _ = io.write_string(fi.writer, "") - total_size += ret + io.write_string(fi.writer, "", &total_size) } else { fmt_arg(&fi, args[index], 'v') } } - ret, _ = io.write_string(fi.writer, ")") - total_size += ret + io.write_string(fi.writer, ")", &total_size) } io.flush(auto_cast w) From d7eabf571c745d86862662fb03069f2dc7ac9530 Mon Sep 17 00:00:00 2001 From: Patric Dexheimer Date: Sun, 20 Feb 2022 02:10:34 -0300 Subject: [PATCH 0229/1052] Memory Leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `dir` will leak memory if u use it with allocators that don´t care in freeing the memory at the end ( like arenas or the temp_allocator ) , because `strings.clone` and `strings.concatenate` are not using the passed allocator. --- core/path/filepath/path.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin index d6e36f649..ba6e11044 100644 --- a/core/path/filepath/path.odin +++ b/core/path/filepath/path.odin @@ -284,13 +284,14 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> ( } dir :: proc(path: string, allocator := context.allocator) -> string { + context.allocator = allocator vol := volume_name(path) i := len(path) - 1 for i >= len(vol) && !is_separator(path[i]) { i -= 1 } - dir := clean(path[len(vol) : i+1], allocator) - defer delete(dir, allocator) + dir := clean(path[len(vol) : i+1]) + defer delete(dir) if dir == "." && len(vol) > 2 { return strings.clone(vol) } From ba61d911da7f08dfac7dd5eaf6ed7f6754e16eca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Feb 2022 13:26:27 +0000 Subject: [PATCH 0230/1052] Remove dead code --- src/llvm_backend_proc.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7bc7fb61f..7ead77c2c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -57,6 +57,7 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); } + lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) { GB_ASSERT(entity != nullptr); GB_ASSERT(entity->kind == Entity_Procedure); @@ -163,14 +164,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) break; } - - - // lbCallingConventionKind cc_kind = lbCallingConvention_C; - // // TODO(bill): Clean up this logic - // if (build_context.metrics.os != TargetOs_js) { - // cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; - // } - // LLVMSetFunctionCallConv(p->value, cc_kind); lbValue proc_value = {p->value, p->type}; lb_add_entity(m, entity, proc_value); lb_add_member(m, p->name, proc_value); From 1bec9e5331bad9aaecee8ba80bf2cbeb97bb3ef0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Feb 2022 14:19:52 +0000 Subject: [PATCH 0231/1052] Add `freestanding_amd64_gnu` --- src/build_settings.cpp | 36 ++++++++++++++++++++++++++++++++---- src/llvm_abi.cpp | 4 +++- src/llvm_backend.cpp | 13 +++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 610e4f847..cc76f9e7c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -8,7 +8,7 @@ // #define DEFAULT_TO_THREADED_CHECKER // #endif -enum TargetOsKind { +enum TargetOsKind : u16 { TargetOs_Invalid, TargetOs_windows, @@ -25,7 +25,7 @@ enum TargetOsKind { TargetOs_COUNT, }; -enum TargetArchKind { +enum TargetArchKind : u16 { TargetArch_Invalid, TargetArch_amd64, @@ -37,7 +37,7 @@ enum TargetArchKind { TargetArch_COUNT, }; -enum TargetEndianKind { +enum TargetEndianKind : u8 { TargetEndian_Invalid, TargetEndian_Little, @@ -46,6 +46,16 @@ enum TargetEndianKind { TargetEndian_COUNT, }; +enum TargetABIKind : u16 { + TargetABI_Default, + + TargetABI_MSVC, + TargetABI_GNU, + + TargetABI_COUNT, +}; + + String target_os_names[TargetOs_COUNT] = { str_lit(""), str_lit("windows"), @@ -75,6 +85,12 @@ String target_endian_names[TargetEndian_COUNT] = { str_lit("big"), }; +String target_abi_names[TargetABI_COUNT] = { + str_lit(""), + str_lit("win64"), + str_lit("sysv"), +}; + TargetEndianKind target_endians[TargetArch_COUNT] = { TargetEndian_Invalid, TargetEndian_Little, @@ -98,6 +114,7 @@ struct TargetMetrics { isize max_align; String target_triplet; String target_data_layout; + TargetABIKind abi; }; @@ -399,6 +416,16 @@ gb_global TargetMetrics target_wasi_wasm32 = { // str_lit(""), // }; +gb_global TargetMetrics target_freestanding_amd64_gnu = { + TargetOs_freestanding, + TargetArch_amd64, + 8, + 16, + str_lit("x86_64-pc-none-gnu"), + str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), + TargetABI_GNU, +}; + struct NamedTargetMetrics { @@ -420,7 +447,8 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("js_wasm32"), &target_js_wasm32 }, - // { str_lit("freestanding_wasm64"), &target_freestanding_wasm64 }, + + { str_lit("freestanding_amd64_gnu"), &target_freestanding_amd64_gnu }, }; NamedTargetMetrics *selected_target_metrics; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 0244b73d6..770e54ac8 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1194,8 +1194,10 @@ LB_ABI_INFO(lb_get_abi_info) { switch (build_context.metrics.arch) { case TargetArch_amd64: - if (build_context.metrics.os == TargetOs_windows) { + if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_MSVC) { return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + } else if (build_context.metrics.abi == TargetABI_GNU) { + return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } else { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 52c46cadc..934daee28 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -996,6 +996,19 @@ String lb_filepath_obj_for_module(lbModule *m) { case TargetOs_essence: ext = STR_LIT(".o"); break; + + case TargetOs_freestanding: + switch (build_context.metrics.abi) { + default: + case TargetABI_Default: + case TargetABI_GNU: + ext = STR_LIT(".o"); + break; + case TargetABI_MSVC: + ext = STR_LIT(".obj"); + break; + } + break; } } } From 0fa487f468b1f63d5ec97ae8bbb0da01717f32cc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Feb 2022 14:27:44 +0000 Subject: [PATCH 0232/1052] Add `-foreign-error-procedures` --- core/runtime/error_checks.odin | 20 +++++++++++++++++++- src/build_settings.cpp | 2 ++ src/checker.cpp | 1 + src/main.cpp | 12 ++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index 14d55c64c..ad6902e2d 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -17,6 +17,24 @@ type_assertion_trap :: proc "contextless" () -> ! { } +when ODIN_FOREIGN_ERROR_PROCEDURES { + foreign { + bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) --- + slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! --- + multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! --- + multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) --- + slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) --- + slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) --- + dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) --- + matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) --- + type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) --- + type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) --- + make_slice_error_loc :: proc "contextless" (loc := #caller_location, len: int) --- + make_dynamic_array_error_loc :: proc "contextless" (using loc := #caller_location, len, cap: int) --- + make_map_expr_error_loc :: proc "contextless" (loc := #caller_location, cap: int) --- + } +} else { + bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { if 0 <= index && index < count { return @@ -231,7 +249,7 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca handle_error(loc, cap) } - +} diff --git a/src/build_settings.cpp b/src/build_settings.cpp index cc76f9e7c..cd9bdb40c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -200,6 +200,7 @@ struct BuildContext { bool ODIN_DEBUG; // Odin in debug mode bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) + bool ODIN_FOREIGN_ERROR_PROCEDURES; ErrorPosStyle ODIN_ERROR_POS_STYLE; @@ -269,6 +270,7 @@ struct BuildContext { bool copy_file_contents; + u32 cmd_doc_flags; Array extra_packages; diff --git a/src/checker.cpp b/src/checker.cpp index f440b7c9a..fe1d362fa 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -976,6 +976,7 @@ void init_universal(void) { add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules); add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); add_global_bool_constant("ODIN_NO_ENTRY_POINT", bc->no_entry_point); + add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES); // Builtin Procedures diff --git a/src/main.cpp b/src/main.cpp index 291b56996..5746ef146 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -632,6 +632,7 @@ enum BuildFlagKind { BuildFlag_InsertSemicolon, BuildFlag_StrictStyle, BuildFlag_StrictStyleInitOnly, + BuildFlag_ForeignErrorProcedures, BuildFlag_Compact, BuildFlag_GlobalDefinitions, @@ -785,10 +786,13 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InsertSemicolon, str_lit("insert-semicolon"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query); + add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc); add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc); add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc); @@ -1356,6 +1360,9 @@ bool parse_build_flags(Array args) { case BuildFlag_DefaultToNilAllocator: build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true; break; + case BuildFlag_ForeignErrorProcedures: + build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true; + break; case BuildFlag_InsertSemicolon: { gb_printf_err("-insert-semicolon flag is not required any more\n"); bad_flags = true; @@ -2084,6 +2091,11 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-verbose-errors"); print_usage_line(2, "Prints verbose error messages showing the code on that line and the location in that line"); print_usage_line(0, ""); + + print_usage_line(1, "-foreign-error-procedures"); + print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit"); + print_usage_line(0, ""); + } if (run_or_build) { From 3e5c60f74672651044d70303e8b0a8e56ca765f2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Feb 2022 14:48:12 +0000 Subject: [PATCH 0233/1052] Add `-reloc-mode:` --- src/build_settings.cpp | 9 +++++++++ src/llvm_backend.cpp | 14 ++++++++++++++ src/main.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index cd9bdb40c..d56a343df 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -189,6 +189,13 @@ enum ErrorPosStyle { ErrorPosStyle_COUNT }; +enum RelocMode { + RelocMode_Default, + RelocMode_Static, + RelocMode_PIC, + RelocMode_DynamicNoPIC, +}; + // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -270,6 +277,8 @@ struct BuildContext { bool copy_file_contents; + RelocMode reloc_mode; + u32 cmd_doc_flags; Array extra_packages; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 934daee28..692b96c51 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1308,6 +1308,20 @@ void lb_generate_code(lbGenerator *gen) { reloc_mode = LLVMRelocPIC; } + switch (build_context.reloc_mode) { + case RelocMode_Default: + break; + case RelocMode_Static: + reloc_mode = LLVMRelocStatic; + break; + case RelocMode_PIC: + reloc_mode = LLVMRelocPIC; + break; + case RelocMode_DynamicNoPIC: + reloc_mode = LLVMRelocDynamicNoPic; + break; + } + for_array(i, gen->modules.entries) { target_machines[i] = LLVMCreateTargetMachine( target, target_triple, llvm_cpu, diff --git a/src/main.cpp b/src/main.cpp index 5746ef146..087f2b442 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -625,6 +625,8 @@ enum BuildFlagKind { BuildFlag_ExtraAssemblerFlags, BuildFlag_Microarch, + BuildFlag_RelocMode, + BuildFlag_TestName, BuildFlag_DisallowDo, @@ -779,6 +781,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); @@ -1339,6 +1343,28 @@ bool parse_build_flags(Array args) { string_to_lower(&build_context.microarch); break; } + case BuildFlag_RelocMode: { + GB_ASSERT(value.kind == ExactValue_String); + String v = value.value_string; + if (v == "default") { + build_context.reloc_mode = RelocMode_Default; + } else if (v == "static") { + build_context.reloc_mode = RelocMode_Static; + } else if (v == "pic") { + build_context.reloc_mode = RelocMode_PIC; + } else if (v == "dynamic-no-pic") { + build_context.reloc_mode = RelocMode_DynamicNoPIC; + } else { + gb_printf_err("-reloc-mode flag expected one of the following\n"); + gb_printf_err("\tdefault\n"); + gb_printf_err("\tstatic\n"); + gb_printf_err("\tpic\n"); + gb_printf_err("\tdynamic-no-pic\n"); + bad_flags = true; + } + + break; + } case BuildFlag_TestName: { GB_ASSERT(value.kind == ExactValue_String); { From 14cb19c2df6c5204ddd691a62b80de0bb0d573cb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Feb 2022 22:31:13 +0000 Subject: [PATCH 0234/1052] Update fmt to record the bytes written in the fmt.Info --- core/fmt/fmt.odin | 413 ++++++++++++++++++++-------------------- core/reflect/types.odin | 8 +- 2 files changed, 207 insertions(+), 214 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 2dc7534f9..d6c1894b7 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -32,6 +32,8 @@ Info :: struct { writer: io.Writer, arg: any, // Temporary record_level: int, + + n: int, // bytes written } // Custom formatter signature. It returns true if the formatting was successful and false when it could not be done @@ -196,19 +198,16 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int { // so I am going to keep the same behaviour as `*println` for `*print` - size0 := io.size(auto_cast w) - for _, i in args { if i > 0 { - io.write_string(fi.writer, sep) + io.write_string(fi.writer, sep, &fi.n) } fmt_value(&fi, args[i], 'v') } io.flush(auto_cast w) - size1 := io.size(auto_cast w) - return int(size1 - size0) + return fi.n } // wprintln formats using the default print settings and writes to w @@ -216,20 +215,16 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int { fi: Info fi.writer = w - size0 := io.size(auto_cast w) - for _, i in args { if i > 0 { - io.write_string(fi.writer, sep) + io.write_string(fi.writer, sep, &fi.n) } fmt_value(&fi, args[i], 'v') } - io.write_byte(fi.writer, '\n') + io.write_byte(fi.writer, '\n', &fi.n) io.flush(auto_cast w) - - size1 := io.size(auto_cast w) - return int(size1 - size0) + return fi.n } // wprintf formats according to the specififed format string and writes to w @@ -239,8 +234,6 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { end := len(fmt) was_prev_index := false - total_size := 0 - loop: for i := 0; i < end; /**/ { fi = Info{writer = w, good_arg_index = true, reordered = fi.reordered} @@ -249,7 +242,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 } if i > prev_i { - io.write_string(fi.writer, fmt[prev_i:i], &total_size) + io.write_string(fi.writer, fmt[prev_i:i], &fi.n) } if i >= end { break loop @@ -264,13 +257,13 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { // Skip extra one i += 1 } - io.write_byte(fi.writer, char, &total_size) + io.write_byte(fi.writer, char, &fi.n) continue loop } else if char == '{' { if i < end && fmt[i] == char { // Skip extra one i += 1 - io.write_byte(fi.writer, char, &total_size) + io.write_byte(fi.writer, char, &fi.n) continue loop } } @@ -301,7 +294,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index) if !fi.width_set { - io.write_string(w, "%!(BAD WIDTH)", &total_size) + io.write_string(w, "%!(BAD WIDTH)", &fi.n) } if fi.width < 0 { @@ -332,7 +325,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi.prec_set = false } if !fi.prec_set { - io.write_string(fi.writer, "%!(BAD PRECISION)", &total_size) + io.write_string(fi.writer, "%!(BAD PRECISION)", &fi.n) } was_prev_index = false } else { @@ -345,7 +338,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if i >= end { - io.write_string(fi.writer, "%!(NO VERB)", &total_size) + io.write_string(fi.writer, "%!(NO VERB)", &fi.n) break loop } @@ -354,11 +347,11 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { switch { case verb == '%': - io.write_byte(fi.writer, '%', &total_size) + io.write_byte(fi.writer, '%', &fi.n) case !fi.good_arg_index: - io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)", &total_size) + io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)", &fi.n) case arg_index >= len(args): - io.write_string(fi.writer, "%!(MISSING ARGUMENT)", &total_size) + io.write_string(fi.writer, "%!(MISSING ARGUMENT)", &fi.n) case: fmt_arg(&fi, args[arg_index], verb) arg_index += 1 @@ -374,14 +367,14 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { arg_index = new_arg_index i = new_i } else { - io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER ", &total_size) + io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER ", &fi.n) // Skip over the bad argument start_index := i for i < end && fmt[i] != '}' && fmt[i] != ':' { i += 1 } fmt_arg(&fi, fmt[start_index:i], 'v') - io.write_string(fi.writer, ")", &total_size) + io.write_string(fi.writer, ")", &fi.n) } } @@ -414,7 +407,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { i += 1 fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index) if !fi.width_set { - io.write_string(fi.writer, "%!(BAD WIDTH)", &total_size) + io.write_string(fi.writer, "%!(BAD WIDTH)", &fi.n) } if fi.width < 0 { @@ -445,7 +438,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { fi.prec_set = false } if !fi.prec_set { - io.write_string(fi.writer, "%!(BAD PRECISION)", &total_size) + io.write_string(fi.writer, "%!(BAD PRECISION)", &fi.n) } was_prev_index = false } else { @@ -459,7 +452,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { if i >= end { - io.write_string(fi.writer, "%!(NO VERB)", &total_size) + io.write_string(fi.writer, "%!(NO VERB)", &fi.n) break loop } @@ -469,7 +462,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if i >= end { - io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)", &total_size) + io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)", &fi.n) break loop } @@ -478,11 +471,11 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { switch { case brace != '}': - io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)", &total_size) + io.write_string(fi.writer, "%!(MISSING CLOSE BRACE)", &fi.n) case !fi.good_arg_index: - io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)", &total_size) + io.write_string(fi.writer, "%!(BAD ARGUMENT NUMBER)", &fi.n) case arg_index >= len(args): - io.write_string(fi.writer, "%!(MISSING ARGUMENT)", &total_size) + io.write_string(fi.writer, "%!(MISSING ARGUMENT)", &fi.n) case: fmt_arg(&fi, args[arg_index], verb) arg_index += 1 @@ -491,24 +484,24 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { } if !fi.reordered && arg_index < len(args) { - io.write_string(fi.writer, "%!(EXTRA ", &total_size) + io.write_string(fi.writer, "%!(EXTRA ", &fi.n) for arg, index in args[arg_index:] { if index > 0 { - io.write_string(fi.writer, ", ", &total_size) + io.write_string(fi.writer, ", ", &fi.n) } if arg == nil { - io.write_string(fi.writer, "", &total_size) + io.write_string(fi.writer, "", &fi.n) } else { fmt_arg(&fi, args[index], 'v') } } - io.write_string(fi.writer, ")", &total_size) + io.write_string(fi.writer, ")", &fi.n) } io.flush(auto_cast w) - return int(total_size) + return fi.n } // wprint_type is a utility procedure to write a ^runtime.Type_Info value to w @@ -596,23 +589,23 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) { fmt_bad_verb :: proc(using fi: ^Info, verb: rune) { - io.write_string(writer, "%!") - io.write_rune(writer, verb) - io.write_byte(writer, '(') + io.write_string(writer, "%!", &fi.n) + io.write_rune(writer, verb, &fi.n) + io.write_byte(writer, '(', &fi.n) if arg.id != nil { - reflect.write_typeid(writer, arg.id) - io.write_byte(writer, '=') + reflect.write_typeid(writer, arg.id, &fi.n) + io.write_byte(writer, '=', &fi.n) fmt_value(fi, arg, 'v') } else { - io.write_string(writer, "") + io.write_string(writer, "", &fi.n) } - io.write_byte(writer, ')') + io.write_byte(writer, ')', &fi.n) } fmt_bool :: proc(using fi: ^Info, b: bool, verb: rune) { switch verb { case 't', 'v': - io.write_string(writer, b ? "true" : "false") + io.write_string(writer, b ? "true" : "false", &fi.n) case: fmt_bad_verb(fi, verb) } @@ -630,7 +623,7 @@ fmt_write_padding :: proc(fi: ^Info, width: int) { } for i := 0; i < width; i += 1 { - io.write_byte(fi.writer, pad_byte) + io.write_byte(fi.writer, pad_byte, &fi.n) } } @@ -689,8 +682,8 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d case 16: c = 'x' } if c != 0 { - io.write_byte(fi.writer, '0') - io.write_byte(fi.writer, c) + io.write_byte(fi.writer, '0', &fi.n) + io.write_byte(fi.writer, c, &fi.n) } } @@ -755,8 +748,8 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i case 16: c = 'x' } if c != 0 { - io.write_byte(fi.writer, '0') - io.write_byte(fi.writer, c) + io.write_byte(fi.writer, '0', &fi.n) + io.write_byte(fi.writer, c, &fi.n) } } @@ -772,9 +765,9 @@ __DIGITS_UPPER := "0123456789ABCDEFX" fmt_rune :: proc(fi: ^Info, r: rune, verb: rune) { switch verb { case 'c', 'r', 'v': - io.write_rune(fi.writer, r) + io.write_rune(fi.writer, r, &fi.n) case 'q': - strings.write_quoted_rune(fi.writer, r) + fi.n += strings.write_quoted_rune(fi.writer, r) case: fmt_int(fi, u64(r), false, 32, verb) } @@ -796,7 +789,7 @@ fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) { if r < 0 || r > utf8.MAX_RUNE { fmt_bad_verb(fi, verb) } else { - io.write_string(fi.writer, "U+") + io.write_string(fi.writer, "U+", &fi.n) _fmt_int(fi, u, 16, false, bit_size, __DIGITS_UPPER) } @@ -821,7 +814,7 @@ fmt_int_128 :: proc(fi: ^Info, u: u128, is_signed: bool, bit_size: int, verb: ru if r < 0 || r > utf8.MAX_RUNE { fmt_bad_verb(fi, verb) } else { - io.write_string(fi.writer, "U+") + io.write_string(fi.writer, "U+", &fi.n) _fmt_int_128(fi, u, 16, false, bit_size, __DIGITS_UPPER) } @@ -832,18 +825,18 @@ fmt_int_128 :: proc(fi: ^Info, u: u128, is_signed: bool, bit_size: int, verb: ru _pad :: proc(fi: ^Info, s: string) { if !fi.width_set { - io.write_string(fi.writer, s) + io.write_string(fi.writer, s, &fi.n) return } width := fi.width - utf8.rune_count_in_string(s) if fi.minus { // right pad - io.write_string(fi.writer, s) + io.write_string(fi.writer, s, &fi.n) fmt_write_padding(fi, width) } else { // left pad fmt_write_padding(fi, width) - io.write_string(fi.writer, s) + io.write_string(fi.writer, s, &fi.n) } } @@ -869,15 +862,15 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { } if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') { - io.write_string(fi.writer, string(b)) + io.write_string(fi.writer, string(b), &fi.n) return } if fi.plus || b[0] != '+' { if fi.zero && fi.width_set && fi.width > len(b) { - io.write_byte(fi.writer, b[0]) + io.write_byte(fi.writer, b[0], &fi.n) fmt_write_padding(fi, fi.width - len(b)) - io.write_string(fi.writer, string(b[1:])) + io.write_string(fi.writer, string(b[1:]), &fi.n) } else { _pad(fi, string(b)) } @@ -905,15 +898,15 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { } if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') { - io.write_string(fi.writer, string(b)) + io.write_string(fi.writer, string(b), &fi.n) return } if fi.plus || str[0] != '+' { if fi.zero && fi.width_set && fi.width > len(b) { - io.write_byte(fi.writer, b[0]) + io.write_byte(fi.writer, b[0], &fi.n) fmt_write_padding(fi, fi.width - len(b)) - io.write_string(fi.writer, string(b[1:])) + io.write_string(fi.writer, string(b[1:]), &fi.n) } else { _pad(fi, string(b)) } @@ -937,7 +930,7 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { case: panic("Unhandled float size") } - io.write_string(fi.writer, "0h") + io.write_string(fi.writer, "0h", &fi.n) _fmt_int(fi, u, 16, false, bit_size, __DIGITS_LOWER if verb == 'h' else __DIGITS_UPPER) @@ -950,15 +943,15 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { fmt_string :: proc(fi: ^Info, s: string, verb: rune) { switch verb { case 's', 'v': - io.write_string(fi.writer, s) + io.write_string(fi.writer, s, &fi.n) if fi.width_set && len(s) < fi.width { for _ in 0.. 0 && space { - io.write_byte(fi.writer, ' ') + io.write_byte(fi.writer, ' ', &fi.n) } char_set := __DIGITS_UPPER if verb == 'x' { @@ -989,7 +982,7 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) { switch verb { case 'p', 'v': if !fi.hash || verb == 'v' { - io.write_string(fi.writer, "0x") + io.write_string(fi.writer, "0x", &fi.n) } _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER) @@ -1051,7 +1044,7 @@ string_to_enum_value :: proc($T: typeid, s: string) -> (T, bool) { fmt_enum :: proc(fi: ^Info, v: any, verb: rune) { if v.id == nil || v.data == nil { - io.write_string(fi.writer, "") + io.write_string(fi.writer, "", &fi.n) return } @@ -1065,11 +1058,11 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) { fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, verb) case 's', 'v': if str, ok := enum_value_to_string(v); ok { - io.write_string(fi.writer, str) + io.write_string(fi.writer, str, &fi.n) } else { - io.write_string(fi.writer, "%!(BAD ENUM VALUE=") + io.write_string(fi.writer, "%!(BAD ENUM VALUE=", &fi.n) fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, 'i') - io.write_string(fi.writer, ")") + io.write_string(fi.writer, ")", &fi.n) } } } @@ -1163,12 +1156,12 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { et := runtime.type_info_base(info.elem) if name != "" { - io.write_string(fi.writer, name) + io.write_string(fi.writer, name, &fi.n) } else { - reflect.write_type(fi.writer, type_info) + reflect.write_type(fi.writer, type_info, &fi.n) } - io.write_byte(fi.writer, '{') - defer io.write_byte(fi.writer, '}') + io.write_byte(fi.writer, '{', &fi.n) + defer io.write_byte(fi.writer, '}', &fi.n) e, is_enum := et.variant.(runtime.Type_Info_Enum) commas := 0 @@ -1178,21 +1171,21 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { } if commas > 0 { - io.write_string(fi.writer, ", ") + io.write_string(fi.writer, ", ", &fi.n) } if is_enum { for ev, evi in e.values { v := u64(ev) if v == u64(i) { - io.write_string(fi.writer, e.names[evi]) + io.write_string(fi.writer, e.names[evi], &fi.n) commas += 1 continue loop } } } v := i64(i) + info.lower - io.write_i64(fi.writer, v, 10) + io.write_i64(fi.writer, v, 10, &fi.n) commas += 1 } } @@ -1200,20 +1193,20 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { fmt_write_indent :: proc(fi: ^Info) { for in 0.. 0 { io.write_string(fi.writer, ", ") } + if i > 0 { io.write_string(fi.writer, ", ", &fi.n) } data := uintptr(array_data) + uintptr(i*elem_size) fmt_arg(fi, any{rawptr(data), elem_id}, verb) @@ -1245,14 +1238,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { n -= 1 } for in 0..") + io.write_string(fi.writer, "", &fi.n) return } @@ -1278,12 +1271,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { // Built-in Custom Formatters for core library types switch a in v { case runtime.Source_Code_Location: - io.write_string(fi.writer, a.file_path) - io.write_byte(fi.writer, '(') - io.write_int(fi.writer, int(a.line)) - io.write_byte(fi.writer, ':') - io.write_int(fi.writer, int(a.column)) - io.write_byte(fi.writer, ')') + io.write_string(fi.writer, a.file_path, &fi.n) + io.write_byte(fi.writer, '(', &fi.n) + io.write_int(fi.writer, int(a.line), 10, &fi.n) + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.column), 10, &fi.n) + io.write_byte(fi.writer, ')', &fi.n) return case time.Duration: @@ -1337,7 +1330,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { w -= 1 switch { case u == 0: - io.write_string(fi.writer, "0s") + io.write_string(fi.writer, "0s", &fi.n) return case u < u64(time.Microsecond): prec = 0 @@ -1376,7 +1369,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { w -= 1 buf[w] = '-' } - io.write_string(fi.writer, string(buf[w:])) + io.write_string(fi.writer, string(buf[w:]), &fi.n) return case time.Time: @@ -1385,20 +1378,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { h, min, s := time.clock(t) ns := (t._nsec - (t._nsec/1e9 + time.UNIX_TO_ABSOLUTE)*1e9) % 1e9 write_padded_number(fi, i64(y), 4) - io.write_byte(fi.writer, '-') + io.write_byte(fi.writer, '-', &fi.n) write_padded_number(fi, i64(mon), 2) - io.write_byte(fi.writer, '-') + io.write_byte(fi.writer, '-', &fi.n) write_padded_number(fi, i64(d), 2) - io.write_byte(fi.writer, ' ') + io.write_byte(fi.writer, ' ', &fi.n) write_padded_number(fi, i64(h), 2) - io.write_byte(fi.writer, ':') + io.write_byte(fi.writer, ':', &fi.n) write_padded_number(fi, i64(min), 2) - io.write_byte(fi.writer, ':') + io.write_byte(fi.writer, ':', &fi.n) write_padded_number(fi, i64(s), 2) - io.write_byte(fi.writer, '.') + io.write_byte(fi.writer, '.', &fi.n) write_padded_number(fi, (ns), 9) - io.write_string(fi.writer, " +0000 UTC") + io.write_string(fi.writer, " +0000 UTC", &fi.n) return } @@ -1409,15 +1402,15 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { return } if b.is_raw_union { - io.write_string(fi.writer, info.name) - io.write_string(fi.writer, "{}") + io.write_string(fi.writer, info.name, &fi.n) + io.write_string(fi.writer, "{}", &fi.n) return } is_soa := b.soa_kind != .None - io.write_string(fi.writer, info.name) - io.write_byte(fi.writer, '[' if is_soa else '{') + io.write_string(fi.writer, info.name, &fi.n) + io.write_byte(fi.writer, '[' if is_soa else '{', &fi.n) hash := fi.hash; defer fi.hash = hash indent := fi.indent; defer fi.indent -= 1 @@ -1426,13 +1419,13 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fi.indent += 1 if hash { - io.write_byte(fi.writer, '\n') + io.write_byte(fi.writer, '\n', &fi.n) } defer { if hash { - for in 0.. 0 { io.write_string(fi.writer, ", ") } + if !hash && index > 0 { io.write_string(fi.writer, ", ", &fi.n) } field_count := -1 - if !hash && field_count > 0 { io.write_string(fi.writer, ", ") } + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - io.write_string(fi.writer, base_type_name) - io.write_byte(fi.writer, '{') - defer io.write_byte(fi.writer, '}') + io.write_string(fi.writer, base_type_name, &fi.n) + io.write_byte(fi.writer, '{', &fi.n) + defer io.write_byte(fi.writer, '}', &fi.n) for name, i in b.names { field_count += 1 - if !hash && field_count > 0 { io.write_string(fi.writer, ", ") } + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } if hash { fmt_write_indent(fi) } - io.write_string(fi.writer, name) - io.write_string(fi.writer, " = ") + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) t := b.types[i].variant.(runtime.Type_Info_Array).elem t_size := uintptr(t.size) if reflect.is_any(t) { - io.write_string(fi.writer, "any{}") + io.write_string(fi.writer, "any{}", &fi.n) } else { data := rawptr(uintptr(v.data) + b.offsets[i] + index*t_size) fmt_arg(fi, any{data, t.id}, 'v') } - if hash { io.write_string(fi.writer, ",\n") } + if hash { io.write_string(fi.writer, ",\n", &fi.n) } } } } else { @@ -1488,17 +1481,17 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_write_indent(fi) } - io.write_string(fi.writer, name) - io.write_string(fi.writer, " = ") + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) if t := b.types[i]; reflect.is_any(t) { - io.write_string(fi.writer, "any{}") + io.write_string(fi.writer, "any{}", &fi.n) } else { data := rawptr(uintptr(v.data) + b.offsets[i]) fmt_arg(fi, any{data, t.id}, 'v') } - if hash { io.write_string(fi.writer, ",\n") } + if hash { io.write_string(fi.writer, ",\n", &fi.n) } } } @@ -1518,7 +1511,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Pointer: if v.id == typeid_of(^runtime.Type_Info) { - reflect.write_type(fi.writer, (^^runtime.Type_Info)(v.data)^) + reflect.write_type(fi.writer, (^^runtime.Type_Info)(v.data)^, &fi.n) } else { ptr := (^rawptr)(v.data)^ if verb != 'p' && info.elem != nil { @@ -1532,7 +1525,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { runtime.Type_Info_Dynamic_Array, runtime.Type_Info_Map: if ptr == nil { - io.write_string(fi.writer, "") + io.write_string(fi.writer, "", &fi.n) return } if fi.record_level < 1 { @@ -1546,13 +1539,13 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Struct, runtime.Type_Info_Union: if ptr == nil { - io.write_string(fi.writer, "") + io.write_string(fi.writer, "", &fi.n) return } if fi.record_level < 1 { fi.record_level += 1 defer fi.record_level -= 1 - io.write_byte(fi.writer, '&') + io.write_byte(fi.writer, '&', &fi.n) fmt_value(fi, a, verb) return } @@ -1575,13 +1568,13 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { runtime.Type_Info_Dynamic_Array, runtime.Type_Info_Map: if ptr == nil { - io.write_string(fi.writer, "") + io.write_string(fi.writer, "", &fi.n) return } if fi.record_level < 1 { fi.record_level += 1 defer fi.record_level -= 1 - io.write_byte(fi.writer, '&') + io.write_byte(fi.writer, '&', &fi.n) fmt_value(fi, a, verb) return } @@ -1589,13 +1582,13 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Struct, runtime.Type_Info_Union: if ptr == nil { - io.write_string(fi.writer, "") + io.write_string(fi.writer, "", &fi.n) return } if fi.record_level < 1 { fi.record_level += 1 defer fi.record_level -= 1 - io.write_byte(fi.writer, '&') + io.write_byte(fi.writer, '&', &fi.n) fmt_value(fi, a, verb) return } @@ -1614,11 +1607,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Enumerated_Array: if fi.hash { - io.write_string(fi.writer, "[\n") + io.write_string(fi.writer, "[\n", &fi.n) defer { - io.write_byte(fi.writer, '\n') + io.write_byte(fi.writer, '\n', &fi.n) fmt_write_indent(fi) - io.write_byte(fi.writer, ']') + io.write_byte(fi.writer, ']', &fi.n) } indent := fi.indent fi.indent += 1 @@ -1629,32 +1622,32 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { idx, ok := stored_enum_value_to_string(info.index, info.min_value, i) if ok { - io.write_byte(fi.writer, '.') - io.write_string(fi.writer, idx) + io.write_byte(fi.writer, '.', &fi.n) + io.write_string(fi.writer, idx, &fi.n) } else { - io.write_i64(fi.writer, i64(info.min_value)+i64(i)) + io.write_i64(fi.writer, i64(info.min_value)+i64(i), 10, &fi.n) } - io.write_string(fi.writer, " = ") + io.write_string(fi.writer, " = ", &fi.n) data := uintptr(v.data) + uintptr(i*info.elem_size) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) - io.write_string(fi.writer, ",\n") + io.write_string(fi.writer, ",\n", &fi.n) } } else { - io.write_byte(fi.writer, '[') - defer io.write_byte(fi.writer, ']') + io.write_byte(fi.writer, '[', &fi.n) + defer io.write_byte(fi.writer, ']', &fi.n) for i in 0.. 0 { io.write_string(fi.writer, ", ") } + if i > 0 { io.write_string(fi.writer, ", ", &fi.n) } idx, ok := stored_enum_value_to_string(info.index, info.min_value, i) if ok { - io.write_byte(fi.writer, '.') - io.write_string(fi.writer, idx) + io.write_byte(fi.writer, '.', &fi.n) + io.write_string(fi.writer, idx, &fi.n) } else { - io.write_i64(fi.writer, i64(info.min_value)+i64(i)) + io.write_i64(fi.writer, i64(info.min_value)+i64(i), 10, &fi.n) } - io.write_string(fi.writer, " = ") + io.write_string(fi.writer, " = ", &fi.n) data := uintptr(v.data) + uintptr(i*info.elem_size) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) @@ -1673,10 +1666,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } case runtime.Type_Info_Simd_Vector: - io.write_byte(fi.writer, '<') - defer io.write_byte(fi.writer, '>') + io.write_byte(fi.writer, '<', &fi.n) + defer io.write_byte(fi.writer, '>', &fi.n) for i in 0.. 0 { io.write_string(fi.writer, ", ") } + if i > 0 { io.write_string(fi.writer, ", ", &fi.n) } data := uintptr(v.data) + uintptr(i*info.elem_size) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) @@ -1699,8 +1692,8 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { return } - io.write_string(fi.writer, "map[") - defer io.write_byte(fi.writer, ']') + io.write_string(fi.writer, "map[", &fi.n) + defer io.write_byte(fi.writer, ']', &fi.n) m := (^mem.Raw_Map)(v.data) if m != nil { @@ -1714,14 +1707,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { entry_size := ed.elem_size for i in 0.. 0 { io.write_string(fi.writer, ", ") } + if i > 0 { io.write_string(fi.writer, ", ", &fi.n) } data := uintptr(entries.data) + uintptr(i*entry_size) key := data + entry_type.offsets[2] fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, 'v') - io.write_string(fi.writer, "=") + io.write_string(fi.writer, "=", &fi.n) value := data + entry_type.offsets[3] fmt_arg(fi, any{rawptr(value), info.value.id}, 'v') @@ -1730,21 +1723,21 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Struct: if info.is_raw_union { - io.write_string(fi.writer, "(raw_union)") + io.write_string(fi.writer, "(raw_union)", &fi.n) return } is_soa := info.soa_kind != .None - io.write_byte(fi.writer, '[' if is_soa else '{') - defer io.write_byte(fi.writer, ']' if is_soa else '}') + io.write_byte(fi.writer, '[' if is_soa else '{', &fi.n) + defer io.write_byte(fi.writer, ']' if is_soa else '}', &fi.n) fi.indent += 1; defer fi.indent -= 1 hash := fi.hash; defer fi.hash = hash // fi.hash = false; - if hash { io.write_byte(fi.writer, '\n') } + if hash { io.write_byte(fi.writer, '\n', &fi.n) } if is_soa { fi.indent += 1 @@ -1773,33 +1766,33 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { for index in 0.. 0 { io.write_string(fi.writer, ", ") } + if !hash && index > 0 { io.write_string(fi.writer, ", ", &fi.n) } field_count := -1 - if !hash && field_count > 0 { io.write_string(fi.writer, ", ") } + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - io.write_string(fi.writer, base_type_name) - io.write_byte(fi.writer, '{') - defer io.write_byte(fi.writer, '}') + io.write_string(fi.writer, base_type_name, &fi.n) + io.write_byte(fi.writer, '{', &fi.n) + defer io.write_byte(fi.writer, '}', &fi.n) for i in 0.. 0 { io.write_string(fi.writer, ", ") } + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } if hash { fmt_write_indent(fi) } - io.write_string(fi.writer, name) - io.write_string(fi.writer, " = ") + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) if info.soa_kind == .Fixed { t := info.types[i].variant.(runtime.Type_Info_Array).elem t_size := uintptr(t.size) if reflect.is_any(t) { - io.write_string(fi.writer, "any{}") + io.write_string(fi.writer, "any{}", &fi.n) } else { data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size) fmt_arg(fi, any{data, t.id}, 'v') @@ -1808,7 +1801,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { t := info.types[i].variant.(runtime.Type_Info_Pointer).elem t_size := uintptr(t.size) if reflect.is_any(t) { - io.write_string(fi.writer, "any{}") + io.write_string(fi.writer, "any{}", &fi.n) } else { field_ptr := (^^byte)(uintptr(v.data) + info.offsets[i])^ data := rawptr(uintptr(field_ptr) + index*t_size) @@ -1816,7 +1809,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } } - if hash { io.write_string(fi.writer, ",\n") } + if hash { io.write_string(fi.writer, ",\n", &fi.n) } } } } else { @@ -1824,23 +1817,23 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { for name, i in info.names { field_count += 1 - if !hash && field_count > 0 { io.write_string(fi.writer, ", ") } + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } if hash { fmt_write_indent(fi) } - io.write_string(fi.writer, name) - io.write_string(fi.writer, " = ") + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) if t := info.types[i]; reflect.is_any(t) { - io.write_string(fi.writer, "any{}") + io.write_string(fi.writer, "any{}", &fi.n) } else { data := rawptr(uintptr(v.data) + info.offsets[i]) fmt_arg(fi, any{data, t.id}, 'v') } if hash { - io.write_string(fi.writer, ",\n") + io.write_string(fi.writer, ",\n", &fi.n) } } } @@ -1848,14 +1841,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Union: if type_info.size == 0 { - io.write_string(fi.writer, "nil") + io.write_string(fi.writer, "nil", &fi.n) return } if reflect.type_info_union_is_pure_maybe(info) { if v.data == nil { - io.write_string(fi.writer, "nil") + io.write_string(fi.writer, "nil", &fi.n) } else { id := info.variants[0].id fmt_arg(fi, any{v.data, id}, verb) @@ -1881,12 +1874,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { assert(tag >= 0) if v.data == nil { - io.write_string(fi.writer, "nil") + io.write_string(fi.writer, "nil", &fi.n) } else if info.no_nil { id := info.variants[tag].id fmt_arg(fi, any{v.data, id}, verb) } else if tag == 0 { - io.write_string(fi.writer, "nil") + io.write_string(fi.writer, "nil", &fi.n) } else { id := info.variants[tag-1].id fmt_arg(fi, any{v.data, id}, verb) @@ -1898,16 +1891,16 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Procedure: ptr := (^rawptr)(v.data)^ if ptr == nil { - io.write_string(fi.writer, "nil") + io.write_string(fi.writer, "nil", &fi.n) } else { - reflect.write_typeid(fi.writer, v.id) - io.write_string(fi.writer, " @ ") + reflect.write_typeid(fi.writer, v.id, &fi.n) + io.write_string(fi.writer, " @ ", &fi.n) fmt_pointer(fi, ptr, 'p') } case runtime.Type_Info_Type_Id: id := (^typeid)(v.data)^ - reflect.write_typeid(fi.writer, id) + reflect.write_typeid(fi.writer, id, &fi.n) case runtime.Type_Info_Bit_Set: fmt_bit_set(fi, v) @@ -1924,18 +1917,18 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { if verb == 'p' { fmt_pointer(fi, ptr, 'p') } else if ptr == nil { - io.write_string(fi.writer, "[]") + io.write_string(fi.writer, "[]", &fi.n) } else { len_ptr := uintptr(v.data) + uintptr(info.base_integer.size) len_any := any{rawptr(len_ptr), info.base_integer.id} len, _ := reflect.as_int(len_any) slice_type := reflect.type_info_base(info.slice).variant.(runtime.Type_Info_Slice) - io.write_byte(fi.writer, '[') - defer io.write_byte(fi.writer, ']') + io.write_byte(fi.writer, '[', &fi.n) + defer io.write_byte(fi.writer, ']', &fi.n) for i in 0.. 0 { io.write_string(fi.writer, ", ") } + if i > 0 { io.write_string(fi.writer, ", ", &fi.n) } data := uintptr(ptr) + uintptr(i*slice_type.elem_size) fmt_arg(fi, any{rawptr(data), slice_type.elem.id}, verb) @@ -1943,32 +1936,32 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } case runtime.Type_Info_Matrix: - io.write_string(fi.writer, "matrix[") - defer io.write_byte(fi.writer, ']') + io.write_string(fi.writer, "matrix[", &fi.n) + defer io.write_byte(fi.writer, ']', &fi.n) fi.indent += 1 if fi.hash { // Printed as it is written - io.write_byte(fi.writer, '\n') + io.write_byte(fi.writer, '\n', &fi.n) for row in 0.. 0 { io.write_string(fi.writer, ", ") } + if col > 0 { io.write_string(fi.writer, ", ", &fi.n) } offset := (row + col*info.elem_stride)*info.elem_size data := uintptr(v.data) + uintptr(offset) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) } - io.write_string(fi.writer, ",\n") + io.write_string(fi.writer, ",\n", &fi.n) } } else { // Printed in Row-Major layout to match text layout for row in 0.. 0 { io.write_string(fi.writer, "; ") } + if row > 0 { io.write_string(fi.writer, "; ", &fi.n) } for col in 0.. 0 { io.write_string(fi.writer, ", ") } + if col > 0 { io.write_string(fi.writer, ", ", &fi.n) } offset := (row + col*info.elem_stride)*info.elem_size @@ -1992,10 +1985,10 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) { r, i := real(c), imag(c) fmt_float(fi, r, bits/2, verb) if !fi.plus && i >= 0 { - io.write_rune(fi.writer, '+') + io.write_rune(fi.writer, '+', &fi.n) } fmt_float(fi, i, bits/2, verb) - io.write_rune(fi.writer, 'i') + io.write_rune(fi.writer, 'i', &fi.n) case: fmt_bad_verb(fi, verb) @@ -2011,22 +2004,22 @@ fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) { fmt_float(fi, r, bits/4, verb) if !fi.plus && i >= 0 { - io.write_rune(fi.writer, '+') + io.write_rune(fi.writer, '+', &fi.n) } fmt_float(fi, i, bits/4, verb) - io.write_rune(fi.writer, 'i') + io.write_rune(fi.writer, 'i', &fi.n) if !fi.plus && j >= 0 { - io.write_rune(fi.writer, '+') + io.write_rune(fi.writer, '+', &fi.n) } fmt_float(fi, j, bits/4, verb) - io.write_rune(fi.writer, 'j') + io.write_rune(fi.writer, 'j', &fi.n) if !fi.plus && k >= 0 { - io.write_rune(fi.writer, '+') + io.write_rune(fi.writer, '+', &fi.n) } fmt_float(fi, k, bits/4, verb) - io.write_rune(fi.writer, 'k') + io.write_rune(fi.writer, 'k', &fi.n) case: fmt_bad_verb(fi, verb) @@ -2046,7 +2039,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { switch a in arg { case ^runtime.Type_Info: ti = a } - reflect.write_type(fi.writer, ti) + reflect.write_type(fi.writer, ti, &fi.n) return } @@ -2064,12 +2057,12 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { custom_types: switch a in arg { case runtime.Source_Code_Location: if fi.hash && verb == 'v' { - io.write_string(fi.writer, a.file_path) - io.write_byte(fi.writer, '(') - io.write_i64(fi.writer, i64(a.line), 10) - io.write_byte(fi.writer, ':') - io.write_i64(fi.writer, i64(a.column), 10) - io.write_byte(fi.writer, ')') + io.write_string(fi.writer, a.file_path, &fi.n) + io.write_byte(fi.writer, '(', &fi.n) + io.write_i64(fi.writer, i64(a.line), 10, &fi.n) + io.write_byte(fi.writer, ':', &fi.n) + io.write_i64(fi.writer, i64(a.column), 10, &fi.n) + io.write_byte(fi.writer, ')', &fi.n) return } } @@ -2121,7 +2114,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case string: fmt_string(fi, a, verb) case cstring: fmt_cstring(fi, a, verb) - case typeid: reflect.write_typeid(fi.writer, a) + case typeid: reflect.write_typeid(fi.writer, a, &fi.n) case i16le: fmt_int(fi, u64(a), true, 16, verb) case u16le: fmt_int(fi, u64(a), false, 16, verb) diff --git a/core/reflect/types.odin b/core/reflect/types.odin index a9a4a8d48..2e2149820 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -334,11 +334,11 @@ is_relative_slice :: proc(info: ^Type_Info) -> bool { -write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid) { - write_type(buf, type_info_of(id)) +write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) { + return write_type_writer(strings.to_writer(buf), type_info_of(id)) } -write_typeid_writer :: proc(writer: io.Writer, id: typeid) { - write_type(writer, type_info_of(id)) +write_typeid_writer :: proc(writer: io.Writer, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) { + return write_type_writer(writer, type_info_of(id), n_written) } write_typeid :: proc{ From db5a1b0c785001d95a51ad3397e2e51fbad49859 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Mon, 21 Feb 2022 09:12:59 +0000 Subject: [PATCH 0235/1052] Add doc comments to strings.split() and strings.split_n() --- core/strings/strings.odin | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 4daa0bacd..70a3ec8e8 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -280,10 +280,29 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato return res[:i+1] } +/* + * Splits a string into parts, based on a separator. + * Returned strings are substrings of 's'. + * ``` + * s := "aaa.bbb.ccc.ddd.eee" // 5 parts + * ss := split(s, ".") + * fmt.println(ss) // [aaa, bbb, ccc, ddd, eee] + * ``` + */ split :: proc(s, sep: string, allocator := context.allocator) -> []string { return _split(s, sep, 0, -1, allocator) } +/* + * Splits a string into a total of 'n' parts, based on a separator. + * Returns fewer parts if there wasn't enough occurrences of the separator. + * Returned strings are substrings of 's'. + * ``` + * s := "aaa.bbb.ccc.ddd.eee" // 5 parts present + * ss := split_n(s, ".", 3) // total of 3 wanted + * fmt.println(ss) // [aaa, bbb, ccc.ddd.eee] + * ``` + */ split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> []string { return _split(s, sep, 0, n, allocator) } From 2abba6e0579d2e2451a2c922dc3341f0075625b1 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Mon, 21 Feb 2022 09:51:03 +0000 Subject: [PATCH 0236/1052] Don't use leading asterisks --- core/strings/strings.odin | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 70a3ec8e8..670da166b 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -281,28 +281,28 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato } /* - * Splits a string into parts, based on a separator. - * Returned strings are substrings of 's'. - * ``` - * s := "aaa.bbb.ccc.ddd.eee" // 5 parts - * ss := split(s, ".") - * fmt.println(ss) // [aaa, bbb, ccc, ddd, eee] - * ``` - */ + Splits a string into parts, based on a separator. + Returned strings are substrings of 's'. + ``` + s := "aaa.bbb.ccc.ddd.eee" // 5 parts + ss := split(s, ".") + fmt.println(ss) // [aaa, bbb, ccc, ddd, eee] + ``` +*/ split :: proc(s, sep: string, allocator := context.allocator) -> []string { return _split(s, sep, 0, -1, allocator) } /* - * Splits a string into a total of 'n' parts, based on a separator. - * Returns fewer parts if there wasn't enough occurrences of the separator. - * Returned strings are substrings of 's'. - * ``` - * s := "aaa.bbb.ccc.ddd.eee" // 5 parts present - * ss := split_n(s, ".", 3) // total of 3 wanted - * fmt.println(ss) // [aaa, bbb, ccc.ddd.eee] - * ``` - */ + Splits a string into a total of 'n' parts, based on a separator. + Returns fewer parts if there wasn't enough occurrences of the separator. + Returned strings are substrings of 's'. + ``` + s := "aaa.bbb.ccc.ddd.eee" // 5 parts present + ss := split_n(s, ".", 3) // total of 3 wanted + fmt.println(ss) // [aaa, bbb, ccc.ddd.eee] + ``` +*/ split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> []string { return _split(s, sep, 0, n, allocator) } From 345032f804752306f4d29fe0f298643c7ad23b30 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 21 Feb 2022 12:35:52 +0000 Subject: [PATCH 0237/1052] Get env stuff working on Windows --- core/os/os2/env.odin | 15 ++------ core/os/os2/env_windows.odin | 72 +++++++++++++++++++++-------------- core/os/os2/errors.odin | 56 ++++++++++++++++----------- core/os/os2/file.odin | 31 ++++++++++----- core/os/os2/file_windows.odin | 2 +- core/os/os2/user.odin | 22 +++++------ 6 files changed, 112 insertions(+), 86 deletions(-) diff --git a/core/os/os2/env.odin b/core/os/os2/env.odin index f25290a59..f1a3e40c7 100644 --- a/core/os/os2/env.odin +++ b/core/os/os2/env.odin @@ -1,20 +1,11 @@ package os2 -// get_env retrieves the value of the environment variable named by the key -// It returns the value, which will be empty if the variable is not present -// To distinguish between an empty value and an unset value, use lookup_env -// NOTE: the value will be allocated with the supplied allocator -get_env :: proc(key: string, allocator := context.allocator) -> string { - value, _ := lookup_env(key, allocator) - return value -} - -// lookup_env gets the value of the environment variable named by the key +// get_env gets the value of the environment variable named by the key // If the variable is found in the environment the value (which can be empty) is returned and the boolean is true // Otherwise the returned value will be empty and the boolean will be false // NOTE: the value will be allocated with the supplied allocator -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { - return _lookup_env(key, allocator) +get_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + return _get_env(key, allocator) } // set_env sets the value of the environment variable named by the key diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin index af04db858..a3b97375b 100644 --- a/core/os/os2/env_windows.odin +++ b/core/os/os2/env_windows.odin @@ -1,50 +1,56 @@ //+private package os2 +import "core:runtime" import "core:mem" import win32 "core:sys/windows" -_lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +_get_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { if key == "" { return } wkey := win32.utf8_to_wstring(key) - b := make([dynamic]u16, 100, context.temp_allocator) - for { - n := win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) - if n == 0 { - err := win32.GetLastError() - if err == win32.ERROR_ENVVAR_NOT_FOUND { - return "", false - } - } - if n <= u32(len(b)) { - value = win32.utf16_to_utf8(b[:n], allocator) - found = true - return - } - - resize(&b, len(b)*2) + // https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentvariablew + buf_len := win32.GetEnvironmentVariableW(wkey, nil, 0) + if buf_len == 0 { + return } + buf := make([dynamic]u16, buf_len, context.temp_allocator) + n := win32.GetEnvironmentVariableW(wkey, raw_data(buf), buf_len) + if n == 0 { + if win32.GetLastError() == win32.ERROR_ENVVAR_NOT_FOUND { + return "", false + } + value = "" + found = true + return + } + + value = win32.utf16_to_utf8(buf[:n], allocator) + found = true + return } _set_env :: proc(key, value: string) -> bool { k := win32.utf8_to_wstring(key) v := win32.utf8_to_wstring(value) + // https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew return bool(win32.SetEnvironmentVariableW(k, v)) } _unset_env :: proc(key: string) -> bool { k := win32.utf8_to_wstring(key) + + // https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew return bool(win32.SetEnvironmentVariableW(k, nil)) } _clear_env :: proc() { envs := environ(context.temp_allocator) for env in envs { - for j in 1.. Maybe(Path_Error) { +_mkdir :: proc(name: string, perm: File_Mode) -> Error { return nil } -_mkdir_all :: proc(path: string, perm: File_Mode) -> Maybe(Path_Error) { +_mkdir_all :: proc(path: string, perm: File_Mode) -> Error { // TODO(bill): _mkdir_all for windows return nil } -_remove_all :: proc(path: string) -> Maybe(Path_Error) { +_remove_all :: proc(path: string) -> Error { // TODO(bill): _remove_all for windows return nil } diff --git a/core/os/os2/pipe_windows.odin b/core/os/os2/pipe_windows.odin index 5570ca282..628b4c836 100644 --- a/core/os/os2/pipe_windows.odin +++ b/core/os/os2/pipe_windows.odin @@ -4,8 +4,12 @@ package os2 import win32 "core:sys/windows" _pipe :: proc() -> (r, w: Handle, err: Error) { + sa: win32.SECURITY_ATTRIBUTES + sa.nLength = size_of(win32.SECURITY_ATTRIBUTES) + sa.bInheritHandle = true + p: [2]win32.HANDLE - if !win32.CreatePipe(&p[0], &p[1], nil, 0) { + if !win32.CreatePipe(&p[0], &p[1], &sa, 0) { return 0, 0, Platform_Error{i32(win32.GetLastError())} } return Handle(p[0]), Handle(p[1]), nil diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin index 19f1453ff..34d0de1c5 100644 --- a/core/os/os2/stat.odin +++ b/core/os/os2/stat.odin @@ -24,15 +24,15 @@ file_info_delete :: proc(fi: File_Info, allocator := context.allocator) { delete(fi.fullpath, allocator) } -fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) { +fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) { return _fstat(fd, allocator) } -stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) { +stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { return _stat(name, allocator) } -lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) { +lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { return _lstat(name, allocator) } diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin index f46a9435c..23ab8a44a 100644 --- a/core/os/os2/stat_windows.odin +++ b/core/os/os2/stat_windows.odin @@ -4,9 +4,9 @@ package os2 import "core:time" import win32 "core:sys/windows" -_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) { +_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) { if fd == 0 { - return {}, Path_Error{err = .Invalid_Argument} + return {}, .Invalid_Argument } context.allocator = allocator @@ -27,10 +27,10 @@ _fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Maybe( return _file_info_from_get_file_information_by_handle(path, h) } -_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) { +_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS) } -_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) { +_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT) } _same_file :: proc(fi1, fi2: File_Info) -> bool { @@ -38,13 +38,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool { } - -_stat_errno :: proc(errno: win32.DWORD) -> Path_Error { - return Path_Error{err = Platform_Error{i32(errno)}} -} - - -full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Maybe(Path_Error)) { +full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Error) { context.allocator = allocator name := name @@ -57,7 +51,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) if n == 0 { delete(buf) - return "", _stat_errno(win32.GetLastError()) + return "", _get_platform_error() } if n <= u32(len(buf)) { return win32.utf16_to_utf8(buf[:n]), nil @@ -69,9 +63,9 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa } -internal_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Maybe(Path_Error)) { +internal_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Error) { if len(name) == 0 { - return {}, Path_Error{err = .Not_Exist} + return {}, .Not_Exist } context.allocator = allocator @@ -91,7 +85,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co fd: win32.WIN32_FIND_DATAW sh := win32.FindFirstFileW(wname, &fd) if sh == win32.INVALID_HANDLE_VALUE { - e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}} + e = _get_platform_error() return } win32.FindClose(sh) @@ -101,7 +95,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) if h == win32.INVALID_HANDLE_VALUE { - e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}} + e = _get_platform_error() return } defer win32.CloseHandle(h) @@ -130,9 +124,9 @@ _cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { } -_cleanpath_from_handle :: proc(fd: Handle) -> (string, Maybe(Path_Error)) { +_cleanpath_from_handle :: proc(fd: Handle) -> (string, Error) { if fd == 0 { - return "", Path_Error{err = .Invalid_Argument} + return "", .Invalid_Argument } h := win32.HANDLE(fd) @@ -143,7 +137,7 @@ _cleanpath_from_handle :: proc(fd: Handle) -> (string, Maybe(Path_Error)) { err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0) switch err { case win32.ERROR_PATH_NOT_FOUND, win32.ERROR_INVALID_PARAMETER: - return "", _stat_errno(err) + return "", Platform_Error{i32(err)} case win32.ERROR_NOT_ENOUGH_MEMORY: MAX_PATH = MAX_PATH*2 + 1 continue @@ -153,9 +147,9 @@ _cleanpath_from_handle :: proc(fd: Handle) -> (string, Maybe(Path_Error)) { return _cleanpath_from_buf(buf), nil } -_cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Maybe(Path_Error)) { +_cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Error) { if fd == 0 { - return nil, Path_Error{err = .Invalid_Argument} + return nil, .Invalid_Argument } h := win32.HANDLE(fd) @@ -166,7 +160,7 @@ _cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Maybe(Path_Error)) { err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0) switch err { case win32.ERROR_PATH_NOT_FOUND, win32.ERROR_INVALID_PARAMETER: - return nil, _stat_errno(err) + return nil, Platform_Error{i32(err)} case win32.ERROR_NOT_ENOUGH_MEMORY: MAX_PATH = MAX_PATH*2 + 1 continue @@ -251,7 +245,7 @@ _file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HA } -_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Maybe(Path_Error)) { +_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Error) { fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0) @@ -268,7 +262,7 @@ _file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE } -_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Maybe(Path_Error)) { +_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Error) { fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0) @@ -285,10 +279,10 @@ _file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string } -_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Maybe(Path_Error)) { +_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Error) { d: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(h, &d) { - return {}, _stat_errno(win32.GetLastError()) + return {}, _get_platform_error() } @@ -296,7 +290,7 @@ _file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HA if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) { err := win32.GetLastError() if err != win32.ERROR_INVALID_PARAMETER { - return {}, _stat_errno(err) + return {}, Platform_Error{i32(err)} } // Indicate this is a symlink on FAT file systems ti.ReparseTag = 0 diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 8c58fbd52..a530a402a 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -53,6 +53,7 @@ foreign kernel32 { LeaveCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- DeleteCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + PathFileExistsW :: proc(lpPathName: LPCWSTR) -> BOOL --- RemoveDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- SetFileAttributesW :: proc(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL --- SetLastError :: proc(dwErrCode: DWORD) --- From 6630d703f82bf06849727ba2a62d38c56366c433 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 21 Feb 2022 13:42:29 +0000 Subject: [PATCH 0239/1052] Clean up ok or error handling --- core/os/os2/file_windows.odin | 71 ++++++++++------------------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index d0cf4505d..9fdbd9a5a 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -15,6 +15,10 @@ _get_platform_error :: proc() -> Error { return Platform_Error{i32(err)} } +_ok_or_error :: proc(ok: win32.BOOL) -> Error { + return nil if ok else _get_platform_error() +} + _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { get_handle :: proc(h: win32.DWORD) -> Handle { fd := win32.GetStdHandle(h) @@ -88,17 +92,13 @@ _close :: proc(fd: Handle) -> Error { hnd := win32.HANDLE(fd) file_info: win32.BY_HANDLE_FILE_INFORMATION - if ok := win32.GetFileInformationByHandle(hnd, &file_info); !ok { - return _get_platform_error() - } + _ok_or_error(win32.GetFileInformationByHandle(hnd, &file_info)) or_return + if file_info.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { return nil } - if ok := win32.CloseHandle(hnd); !ok { - return _get_platform_error() - } - return nil + return _ok_or_error(win32.CloseHandle(hnd)) } _name :: proc(fd: Handle, allocator := context.allocator) -> string { @@ -145,10 +145,7 @@ _read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) { max_read := u32(min(BUF_SIZE, len(b)/4)) single_read_length: u32 - ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) - if !ok { - err = _get_platform_error() - } + err = _ok_or_error(win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)) buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length]) src := buf8[:buf8_len] @@ -245,9 +242,7 @@ _pread :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { h := win32.HANDLE(fd) done: win32.DWORD - if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - _get_platform_error() or_return - } + _ok_or_error(win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o)) or_return return int(done), nil } @@ -267,9 +262,7 @@ _pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { h := win32.HANDLE(fd) done: win32.DWORD - if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - _get_platform_error() or_return - } + _ok_or_error(win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o)) or_return return int(done), nil } @@ -298,9 +291,7 @@ _write_to :: proc(fd: Handle, w: io.Writer) -> (n: i64, err: Error) { _file_size :: proc(fd: Handle) -> (n: i64, err: Error) { length: win32.LARGE_INTEGER - if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) { - err = _get_platform_error() - } + err = _ok_or_error(win32.GetFileSizeEx(win32.HANDLE(fd), &length)) return i64(length), err } @@ -310,34 +301,24 @@ _sync :: proc(fd: Handle) -> Error { } _flush :: proc(fd: Handle) -> Error { - if !win32.FlushFileBuffers(win32.HANDLE(fd)) { - return _get_platform_error() - } - return nil + return _ok_or_error(win32.FlushFileBuffers(win32.HANDLE(fd))) } _truncate :: proc(fd: Handle, size: i64) -> Error { offset := seek(fd, size, .Start) or_return defer seek(fd, offset, .Start) - if !win32.SetEndOfFile(win32.HANDLE(fd)) { - return _get_platform_error() - } - return nil + return _ok_or_error(win32.SetEndOfFile(win32.HANDLE(fd))) } _remove :: proc(name: string) -> Error { p := win32.utf8_to_wstring(_fix_long_path(name)) - err, err1: Error - if !win32.DeleteFileW(p) { - err = _get_platform_error() - } + + err := _ok_or_error(win32.DeleteFileW(p)) if err == nil { return nil } - if !win32.RemoveDirectoryW(p) { - err1 = _get_platform_error() - } + err1 := _ok_or_error(win32.RemoveDirectoryW(p)) if err1 == nil { return nil } @@ -351,10 +332,7 @@ _remove :: proc(name: string) -> Error { err = err1 } else if a & win32.FILE_ATTRIBUTE_READONLY != 0 { if win32.SetFileAttributesW(p, a &~ win32.FILE_ATTRIBUTE_READONLY) { - err = nil - if !win32.DeleteFileW(p) { - err = _get_platform_error() - } + err = _ok_or_error(win32.DeleteFileW(p)) } } } @@ -366,20 +344,14 @@ _remove :: proc(name: string) -> Error { _rename :: proc(old_path, new_path: string) -> Error { from := win32.utf8_to_wstring(old_path, context.temp_allocator) to := win32.utf8_to_wstring(new_path, context.temp_allocator) - if !win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) { - return _get_platform_error() - } - return nil + return _ok_or_error(win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING)) } _link :: proc(old_name, new_name: string) -> Error { n := win32.utf8_to_wstring(_fix_long_path(new_name)) o := win32.utf8_to_wstring(_fix_long_path(old_name)) - if !win32.CreateHardLinkW(n, o, nil) { - return _get_platform_error() - } - return nil + return _ok_or_error(win32.CreateHardLinkW(n, o, nil)) } _symlink :: proc(old_name, new_name: string) -> Error { @@ -392,10 +364,7 @@ _read_link :: proc(name: string) -> (string, Error) { _unlink :: proc(path: string) -> Error { wpath := win32.utf8_to_wstring(path, context.temp_allocator) - if !win32.DeleteFileW(wpath) { - return _get_platform_error() - } - return nil + return _ok_or_error(win32.DeleteFileW(wpath)) } From 6145185478fdea85e0a2b9867e1a65a23b38dd7c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 21 Feb 2022 16:04:56 +0000 Subject: [PATCH 0240/1052] Add missing return types --- vendor/darwin/Metal/MetalClasses.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 9713bba02..8e86c60e2 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -6589,8 +6589,8 @@ Device_newRasterizationRateMap :: #force_inline proc(self: ^Device, descriptor: return msgSend(^RasterizationRateMap, self, "newRasterizationRateMapWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithCompletionHandler") -Device_newRenderPipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) { - msgSend(nil, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) +Device_newRenderPipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) -> ^RenderPipelineState { + return msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineState") Device_newRenderPipelineState :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { @@ -6598,8 +6598,8 @@ Device_newRenderPipelineState :: #force_inline proc(self: ^Device, descriptor: ^ return } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler") -Device_newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { - msgSend(nil, self, "newRenderPipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) +Device_newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) -> ^RenderPipelineState { + return msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithReflection") Device_newRenderPipelineStateWithDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { @@ -6607,8 +6607,8 @@ Device_newRenderPipelineStateWithDescriptorWithReflection :: #force_inline proc( return } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptorWithCompletionHandler") -Device_newRenderPipelineStateWithTileDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { - msgSend(nil, self, "newRenderPipelineStateWithTileDescriptor:options:completionHandler:", descriptor, options, completionHandler) +Device_newRenderPipelineStateWithTileDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) -> ^RenderPipelineState { + return msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithTileDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newRenderPipelineStateWithTileDescriptorWithReflection") Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^TileRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { From e6a7b85da44e141f170a528321ce02452731a3d4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 21 Feb 2022 20:49:59 +0000 Subject: [PATCH 0241/1052] Correct types --- vendor/darwin/Metal/MetalClasses.odin | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 8e86c60e2..56d40f5f2 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -5508,8 +5508,8 @@ Buffer_newRemoteBufferViewForDevice :: #force_inline proc(self: ^Buffer, device: return msgSend(^Buffer, self, "newRemoteBufferViewForDevice:", device) } @(objc_type=Buffer, objc_name="newTexture") -Buffer_newTexture :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: NS.UInteger, bytesPerRow: NS.UInteger) -> ^Buffer { - return msgSend(^Buffer, self, "newTextureWithDescriptor:offset:bytesPerRow:", descriptor, offset, bytesPerRow) +Buffer_newTexture :: #force_inline proc(self: ^Buffer, descriptor: ^TextureDescriptor, offset: NS.UInteger, bytesPerRow: NS.UInteger) -> ^Texture { + return msgSend(^Texture, self, "newTextureWithDescriptor:offset:bytesPerRow:", descriptor, offset, bytesPerRow) } @(objc_type=Buffer, objc_name="remoteStorageBuffer") Buffer_remoteStorageBuffer :: #force_inline proc(self: ^Buffer) -> ^Buffer { @@ -6636,8 +6636,8 @@ Device_newSharedTextureWithHandle :: #force_inline proc(self: ^Device, sharedHan return msgSend(^SharedEvent, self, "newSharedTextureWithHandle:", sharedHandle) } @(objc_type=Device, objc_name="newTexture") -Device_newTexture :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^SharedEvent { - return msgSend(^SharedEvent, self, "newTextureWithDescriptor:", desc) +Device_newTexture :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^Texture { + return msgSend(^Texture, self, "newTextureWithDescriptor:", desc) } @(objc_type=Device, objc_name="newTextureWithIOSurface") Device_newTextureWithIOSurface :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Texture { @@ -7101,24 +7101,24 @@ Heap_label :: #force_inline proc(self: ^Heap) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Heap, objc_name="maxAvailableSizeWithAlignment") -Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: NS.UInteger) -> ^Heap { - return msgSend(^Heap, self, "maxAvailableSizeWithAlignment:", alignment) +Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: NS.UInteger) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxAvailableSizeWithAlignment:", alignment) } @(objc_type=Heap, objc_name="newBuffer") -Heap_newBuffer :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Heap { - return msgSend(^Heap, self, "newBufferWithLength:options:", length, options) +Heap_newBuffer :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { + return msgSend(^Buffer, self, "newBufferWithLength:options:", length, options) } @(objc_type=Heap, objc_name="newBufferWithOptions") -Heap_newBufferWithOptions :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Heap { - return msgSend(^Heap, self, "newBufferWithLength:options:offset:", length, options, offset) +Heap_newBufferWithOptions :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Buffer { + return msgSend(^Buffer, self, "newBufferWithLength:options:offset:", length, options, offset) } @(objc_type=Heap, objc_name="newTexture") -Heap_newTexture :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Heap { - return msgSend(^Heap, self, "newTextureWithDescriptor:", desc) +Heap_newTexture :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Texture { + return msgSend(^Texture, self, "newTextureWithDescriptor:", desc) } @(objc_type=Heap, objc_name="newTextureWithOffset") -Heap_newTextureWithOffset :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Heap { - return msgSend(^Heap, self, "newTextureWithDescriptor:offset:", descriptor, offset) +Heap_newTextureWithOffset :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Texture { + return msgSend(^Texture, self, "newTextureWithDescriptor:offset:", descriptor, offset) } @(objc_type=Heap, objc_name="resourceOptions") Heap_resourceOptions :: #force_inline proc(self: ^Heap) -> ResourceOptions { From 2b5bc1d5589c5b0acba56ab5081f19145287d775 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 22 Feb 2022 17:08:57 +0100 Subject: [PATCH 0242/1052] [report] Fix `odin report` crash if `/usr/lib/os-release` doesn't exist. --- src/bug_report.cpp | 4 ++-- src/gb/gb.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 9a1cb2254..4dd251f24 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -473,11 +473,11 @@ void print_bug_report_help() { #elif defined(GB_SYSTEM_LINUX) /* - Try to parse `/usr/lib/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS` + Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS` */ gbAllocator a = heap_allocator(); - gbFileContents release = gb_file_read_contents(a, 1, "/usr/lib/os-release"); + gbFileContents release = gb_file_read_contents(a, 1, "/etc/os-release"); defer (gb_file_free_contents(&release)); b32 found = 0; diff --git a/src/gb/gb.h b/src/gb/gb.h index d9bf09436..a9d6378c9 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -6093,6 +6093,7 @@ gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char con } void gb_file_free_contents(gbFileContents *fc) { + if (fc == NULL || fc->size == 0) return; GB_ASSERT_NOT_NULL(fc->data); gb_free(fc->allocator, fc->data); fc->data = NULL; From e7be9493ba3042569fa6c8958941b3a813bed5e3 Mon Sep 17 00:00:00 2001 From: zhibog Date: Tue, 22 Feb 2022 19:56:07 +0100 Subject: [PATCH 0243/1052] Added SipHash + tests and fixed remaining semicolons in vendor/botan --- core/crypto/siphash/siphash.odin | 316 ++++++++++++++++++++++ tests/core/crypto/test_core_crypto.odin | 43 +++ tests/vendor/botan/test_vendor_botan.odin | 43 +++ vendor/botan/blake2b/blake2b.odin | 2 +- vendor/botan/gost/gost.odin | 2 +- vendor/botan/keccak/keccak.odin | 2 +- vendor/botan/md4/md4.odin | 2 +- vendor/botan/md5/md5.odin | 2 +- vendor/botan/ripemd/ripemd.odin | 2 +- vendor/botan/sha1/sha1.odin | 2 +- vendor/botan/sha2/sha2.odin | 8 +- vendor/botan/sha3/sha3.odin | 8 +- vendor/botan/shake/shake.odin | 4 +- vendor/botan/siphash/siphash.odin | 253 +++++++++++++++++ vendor/botan/skein512/skein512.odin | 6 +- vendor/botan/sm3/sm3.odin | 2 +- vendor/botan/streebog/streebog.odin | 4 +- vendor/botan/tiger/tiger.odin | 6 +- vendor/botan/whirlpool/whirlpool.odin | 2 +- 19 files changed, 682 insertions(+), 27 deletions(-) create mode 100644 core/crypto/siphash/siphash.odin create mode 100644 vendor/botan/siphash/siphash.odin diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin new file mode 100644 index 000000000..14cd53a4c --- /dev/null +++ b/core/crypto/siphash/siphash.odin @@ -0,0 +1,316 @@ +package siphash + +/* + Copyright 2022 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog: Initial implementation. + + Implementation of the SipHash hashing algorithm, as defined at and +*/ + +import "core:crypto" +import "core:crypto/util" +import "core:mem" + +/* + High level API +*/ + +KEY_SIZE :: 16 +DIGEST_SIZE :: 8 + +// sum_string_1_3 will hash the given message with the key and return +// the computed hash as a u64 +sum_string_1_3 :: proc(msg, key: string) -> u64 { + return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key)) +} + +// sum_bytes_1_3 will hash the given message with the key and return +// the computed hash as a u64 +sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 { + ctx: Context + hash: u64 + init(&ctx, key, 1, 3) + update(&ctx, msg) + final(&ctx, &hash) + return hash +} + +// sum_string_to_buffer_1_3 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) { + sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst) +} + +// sum_bytes_to_buffer_1_3 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) { + assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8") + hash := sum_bytes_1_3(msg, key) + _collect_output(dst[:], hash) +} + +sum_1_3 :: proc { + sum_string_1_3, + sum_bytes_1_3, + sum_string_to_buffer_1_3, + sum_bytes_to_buffer_1_3, +} + +// verify_u64_1_3 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool { + return sum_bytes_1_3(msg, key) == tag +} + +// verify_bytes will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_1_3(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 +} + +verify_1_3 :: proc { + verify_bytes_1_3, + verify_u64_1_3, +} + +// sum_string_2_4 will hash the given message with the key and return +// the computed hash as a u64 +sum_string_2_4 :: proc(msg, key: string) -> u64 { + return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key)) +} + +// sum_bytes_2_4 will hash the given message with the key and return +// the computed hash as a u64 +sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 { + ctx: Context + hash: u64 + init(&ctx, key, 2, 4) + update(&ctx, msg) + final(&ctx, &hash) + return hash +} + +// sum_string_to_buffer_2_4 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) { + sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst) +} + +// sum_bytes_to_buffer_2_4 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) { + assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8") + hash := sum_bytes_2_4(msg, key) + _collect_output(dst[:], hash) +} + +sum_2_4 :: proc { + sum_string_2_4, + sum_bytes_2_4, + sum_string_to_buffer_2_4, + sum_bytes_to_buffer_2_4, +} + +// verify_u64_2_4 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool { + return sum_bytes_2_4(msg, key) == tag +} + +// verify_bytes will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_2_4(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 +} + +verify_2_4 :: proc { + verify_bytes_2_4, + verify_u64_2_4, +} + +// sum_string_4_8 will hash the given message with the key and return +// the computed hash as a u64 +sum_string_4_8 :: proc(msg, key: string) -> u64 { + return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key)) +} + +// sum_bytes_4_8 will hash the given message with the key and return +// the computed hash as a u64 +sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 { + ctx: Context + hash: u64 + init(&ctx, key, 4, 8) + update(&ctx, msg) + final(&ctx, &hash) + return hash +} + +// sum_string_to_buffer_4_8 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) { + sum_bytes_to_buffer_4_8(transmute([]byte)(msg), transmute([]byte)(key), dst) +} + +// sum_bytes_to_buffer_4_8 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) { + assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8") + hash := sum_bytes_4_8(msg, key) + _collect_output(dst[:], hash) +} + +sum_4_8 :: proc { + sum_string_4_8, + sum_bytes_4_8, + sum_string_to_buffer_4_8, + sum_bytes_to_buffer_4_8, +} + +// verify_u64_4_8 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool { + return sum_bytes_4_8(msg, key) == tag +} + +// verify_bytes will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_4_8(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 +} + +verify_4_8 :: proc { + verify_bytes_4_8, + verify_u64_4_8, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) { + assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16") + ctx.c_rounds = c_rounds + ctx.d_rounds = d_rounds + is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) || + (ctx.c_rounds == 2 && ctx.d_rounds == 4) || + (ctx.c_rounds == 4 && ctx.d_rounds == 8) + assert(is_valid_setting, "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)") + ctx.k0 = util.U64_LE(key[:8]) + ctx.k1 = util.U64_LE(key[8:]) + ctx.v0 = 0x736f6d6570736575 ~ ctx.k0 + ctx.v1 = 0x646f72616e646f6d ~ ctx.k1 + ctx.v2 = 0x6c7967656e657261 ~ ctx.k0 + ctx.v3 = 0x7465646279746573 ~ ctx.k1 + ctx.is_initialized = true +} + +update :: proc(ctx: ^Context, data: []byte) { + assert(ctx.is_initialized, "crypto/siphash: Context is not initalized") + ctx.last_block = len(data) / 8 * 8 + ctx.buf = data + i := 0 + m: u64 + for i < ctx.last_block { + m = u64(ctx.buf[i] & 0xff) + i += 1 + + for r in u64(1)..<8 { + m |= u64(ctx.buf[i] & 0xff) << (r * 8) + i += 1 + } + + ctx.v3 ~= m + for _ in 0..= ctx.last_block; i -= 1 { + m <<= 8 + m |= u64(ctx.buf[i] & 0xff) + } + m |= u64(len(ctx.buf) << 56) + + ctx.v3 ~= m + + for _ in 0.. byte { + return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3)) +} + +_collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) { + dst[0] = _get_byte(7, hash) + dst[1] = _get_byte(6, hash) + dst[2] = _get_byte(5, hash) + dst[3] = _get_byte(4, hash) + dst[4] = _get_byte(3, hash) + dst[5] = _get_byte(2, hash) + dst[6] = _get_byte(1, hash) + dst[7] = _get_byte(0, hash) +} + +_compress :: #force_inline proc "contextless" (ctx: ^Context) { + ctx.v0 += ctx.v1 + ctx.v1 = util.ROTL64(ctx.v1, 13) + ctx.v1 ~= ctx.v0 + ctx.v0 = util.ROTL64(ctx.v0, 32) + ctx.v2 += ctx.v3 + ctx.v3 = util.ROTL64(ctx.v3, 16) + ctx.v3 ~= ctx.v2 + ctx.v0 += ctx.v3 + ctx.v3 = util.ROTL64(ctx.v3, 21) + ctx.v3 ~= ctx.v0 + ctx.v2 += ctx.v1 + ctx.v1 = util.ROTL64(ctx.v1, 17) + ctx.v1 ~= ctx.v2 + ctx.v2 = util.ROTL64(ctx.v2, 32) +} diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 2ad00be66..5682a6167 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -36,6 +36,7 @@ import "core:crypto/sm3" import "core:crypto/jh" import "core:crypto/groestl" import "core:crypto/haval" +import "core:crypto/siphash" TEST_count := 0 TEST_fail := 0 @@ -114,6 +115,7 @@ main :: proc() { test_haval_192(&t) test_haval_224(&t) test_haval_256(&t) + test_siphash_2_4(&t) // "modern" crypto tests test_chacha20(&t) @@ -1103,3 +1105,44 @@ test_haval_256 :: proc(t: ^testing.T) { expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } } + +@(test) +test_siphash_2_4 :: proc(t: ^testing.T) { + // Test vectors from + // https://github.com/veorq/SipHash/blob/master/vectors.h + test_vectors := [?]u64 { + 0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d, + 0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137, + 0x93f5f5799a932462, 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7, + 0x751e8fbc860ee5fb, 0x14ea5627c0843d90, 0xf723ca908e7af2ee, 0xa129ca6149be45e5, + 0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, 0xbb6dc91da77961bd, + 0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8, + 0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad, + 0xde4daaaca71dc9a5, 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342, + 0x7127512f72f27cce, 0xa7f32346f95978e3, 0x12e0b01abb051238, 0x15e034d40fa197ae, + 0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, 0x9abfd8766a33735c, + 0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95, + 0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb, + 0xe612a3cb9ecba951, 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a, + 0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, 0x7fa8220ba3b2ecea, 0x245731c13ca42499, + 0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, 0x6606d7e446282b93, + 0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572, + } + + key: [16]byte + for i in 0..<16 { + key[i] = byte(i) + } + + for i in 0.. [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/vendor/botan/gost/gost.odin b/vendor/botan/gost/gost.odin index 9f081f9cb..6bf1c5b97 100644 --- a/vendor/botan/gost/gost.odin +++ b/vendor/botan/gost/gost.odin @@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/vendor/botan/keccak/keccak.odin b/vendor/botan/keccak/keccak.odin index 3316de017..28e7374ba 100644 --- a/vendor/botan/keccak/keccak.odin +++ b/vendor/botan/keccak/keccak.odin @@ -44,7 +44,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/vendor/botan/md4/md4.odin b/vendor/botan/md4/md4.odin index c8a1ad903..174676a82 100644 --- a/vendor/botan/md4/md4.odin +++ b/vendor/botan/md4/md4.odin @@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/vendor/botan/md5/md5.odin b/vendor/botan/md5/md5.odin index 203f2d092..01e099062 100644 --- a/vendor/botan/md5/md5.odin +++ b/vendor/botan/md5/md5.odin @@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/vendor/botan/ripemd/ripemd.odin b/vendor/botan/ripemd/ripemd.odin index 0a8195a96..230e4c0d9 100644 --- a/vendor/botan/ripemd/ripemd.odin +++ b/vendor/botan/ripemd/ripemd.odin @@ -44,7 +44,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160 will hash the given input and write the diff --git a/vendor/botan/sha1/sha1.odin b/vendor/botan/sha1/sha1.odin index 005b01821..1f74c8fc2 100644 --- a/vendor/botan/sha1/sha1.odin +++ b/vendor/botan/sha1/sha1.odin @@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/vendor/botan/sha2/sha2.odin b/vendor/botan/sha2/sha2.odin index f5d6921a8..4c201cc26 100644 --- a/vendor/botan/sha2/sha2.odin +++ b/vendor/botan/sha2/sha2.odin @@ -47,7 +47,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -126,7 +126,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -205,7 +205,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -284,7 +284,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/vendor/botan/sha3/sha3.odin b/vendor/botan/sha3/sha3.odin index cf9fa5b2b..4c1b87dda 100644 --- a/vendor/botan/sha3/sha3.odin +++ b/vendor/botan/sha3/sha3.odin @@ -47,7 +47,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash); + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the @@ -126,7 +126,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -205,7 +205,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash); + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the @@ -284,7 +284,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/vendor/botan/shake/shake.odin b/vendor/botan/shake/shake.odin index ac8432f64..f1023b90e 100644 --- a/vendor/botan/shake/shake.odin +++ b/vendor/botan/shake/shake.odin @@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128 will hash the given input and write the @@ -124,7 +124,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the diff --git a/vendor/botan/siphash/siphash.odin b/vendor/botan/siphash/siphash.odin new file mode 100644 index 000000000..ae8e19917 --- /dev/null +++ b/vendor/botan/siphash/siphash.odin @@ -0,0 +1,253 @@ +package siphash + +/* + Copyright 2022 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog: Initial implementation. + + Interface for the SipHash hashing algorithm. + The hash will be computed via bindings to the Botan crypto library + + Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4 +*/ + +import "core:crypto" +import "core:crypto/util" + +import botan "../bindings" + +KEY_SIZE :: 16 +DIGEST_SIZE :: 8 + +// sum_string_1_3 will hash the given message with the key and return +// the computed hash as a u64 +sum_string_1_3 :: proc(msg, key: string) -> u64 { + return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key)) +} + +// sum_bytes_1_3 will hash the given message with the key and return +// the computed hash as a u64 +sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 { + dst: [8]byte + ctx: botan.mac_t + init(&ctx, key[:], 1, 3) + update(&ctx, msg[:]) + final(&ctx, dst[:]) + return util.U64_LE(dst[:]) +} + +// sum_string_to_buffer_1_3 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) { + sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst) +} + +// sum_bytes_to_buffer_1_3 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) { + assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8") + ctx: botan.mac_t + init(&ctx, key[:], 1, 3) + update(&ctx, msg[:]) + final(&ctx, dst[:]) +} + +sum_1_3 :: proc { + sum_string_1_3, + sum_bytes_1_3, + sum_string_to_buffer_1_3, + sum_bytes_to_buffer_1_3, +} + +// verify_u64_1_3 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool { + return sum_bytes_1_3(msg, key) == tag +} + +// verify_bytes_1_3 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_1_3(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 +} + +verify_1_3 :: proc { + verify_bytes_1_3, + verify_u64_1_3, +} + +// sum_string_2_4 will hash the given message with the key and return +// the computed hash as a u64 +sum_string_2_4 :: proc(msg, key: string) -> u64 { + return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key)) +} + +// sum_bytes_2_4 will hash the given message with the key and return +// the computed hash as a u64 +sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 { + dst: [8]byte + ctx: botan.mac_t + init(&ctx, key[:]) + update(&ctx, msg[:]) + final(&ctx, dst[:]) + return util.U64_LE(dst[:]) +} + +// sum_string_to_buffer_2_4 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) { + sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst) +} + +// sum_bytes_to_buffer_2_4 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) { + assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8") + ctx: botan.mac_t + init(&ctx, key[:]) + update(&ctx, msg[:]) + final(&ctx, dst[:]) +} + +sum_2_4 :: proc { + sum_string_2_4, + sum_bytes_2_4, + sum_string_to_buffer_2_4, + sum_bytes_to_buffer_2_4, +} + +sum_string :: sum_string_2_4 +sum_bytes :: sum_bytes_2_4 +sum_string_to_buffer :: sum_string_to_buffer_2_4 +sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4 +sum :: proc { + sum_string, + sum_bytes, + sum_string_to_buffer, + sum_bytes_to_buffer, +} + + +// verify_u64_2_4 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool { + return sum_bytes_2_4(msg, key) == tag +} + +// verify_bytes_2_4 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_2_4(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 +} + +verify_2_4 :: proc { + verify_bytes_2_4, + verify_u64_2_4, +} + +verify_bytes :: verify_bytes_2_4 +verify_u64 :: verify_u64_2_4 +verify :: proc { + verify_bytes, + verify_u64, +} + +// sum_string_4_8 will hash the given message with the key and return +// the computed hash as a u64 +sum_string_4_8 :: proc(msg, key: string) -> u64 { + return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key)) +} + +// sum_bytes_4_8 will hash the given message with the key and return +// the computed hash as a u64 +sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 { + dst: [8]byte + ctx: botan.mac_t + init(&ctx, key[:], 4, 8) + update(&ctx, msg[:]) + final(&ctx, dst[:]) + return util.U64_LE(dst[:]) +} + +// sum_string_to_buffer_4_8 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) { + sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst) +} + +// sum_bytes_to_buffer_4_8 will hash the given message with the key and write +// the computed hash into the provided destination buffer +sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) { + assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8") + ctx: botan.mac_t + init(&ctx, key[:], 4, 8) + update(&ctx, msg[:]) + final(&ctx, dst[:]) +} + +sum_4_8 :: proc { + sum_string_4_8, + sum_bytes_4_8, + sum_string_to_buffer_4_8, + sum_bytes_to_buffer_4_8, +} + +// verify_u64_4_8 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool { + return sum_bytes_4_8(msg, key) == tag +} + +// verify_bytes_4_8 will check if the supplied tag matches with the output you +// will get from the provided message and key +verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_4_8(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 +} + +verify_4_8 :: proc { + verify_bytes_4_8, + verify_u64_4_8, +} + +/* + Low level API +*/ + +Context :: botan.mac_t + +init :: proc(ctx: ^botan.mac_t, key: []byte, c_rounds := 2, d_rounds := 4) { + assert(len(key) == KEY_SIZE, "vendor/botan: Invalid key size, want 16") + is_valid_setting := (c_rounds == 1 && d_rounds == 3) || + (c_rounds == 2 && d_rounds == 4) || + (c_rounds == 4 && d_rounds == 8) + assert(is_valid_setting, "vendor/botan: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)") + if c_rounds == 1 && d_rounds == 3 { + botan.mac_init(ctx, botan.MAC_SIPHASH_1_3, 0) + } else if c_rounds == 2 && d_rounds == 4 { + botan.mac_init(ctx, botan.MAC_SIPHASH_2_4, 0) + } else if c_rounds == 4 && d_rounds == 8 { + botan.mac_init(ctx, botan.MAC_SIPHASH_4_8, 0) + } + botan.mac_set_key(ctx^, len(key) == 0 ? nil : &key[0], uint(len(key))) +} + +update :: proc "contextless" (ctx: ^botan.mac_t, data: []byte) { + botan.mac_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) +} + +final :: proc "contextless" (ctx: ^botan.mac_t, dst: []byte) { + botan.mac_final(ctx^, &dst[0]) + reset(ctx) +} + +reset :: proc(ctx: ^botan.mac_t) { + botan.mac_destroy(ctx^) +} \ No newline at end of file diff --git a/vendor/botan/skein512/skein512.odin b/vendor/botan/skein512/skein512.odin index 490eeba03..4fed07853 100644 --- a/vendor/botan/skein512/skein512.odin +++ b/vendor/botan/skein512/skein512.odin @@ -47,7 +47,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -126,7 +126,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the @@ -205,7 +205,7 @@ hash_bytes_slice :: proc(data: []byte, bit_size: int, allocator := context.alloc // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_slice :: proc(data: string, hash: []byte, bit_size: int, allocator := context.allocator) { - hash_bytes_to_buffer_slice(transmute([]byte)(data), hash, bit_size, allocator); + hash_bytes_to_buffer_slice(transmute([]byte)(data), hash, bit_size, allocator) } // hash_bytes_to_buffer_slice will hash the given input and write the diff --git a/vendor/botan/sm3/sm3.odin b/vendor/botan/sm3/sm3.odin index 7eb3f1f8d..75cf40679 100644 --- a/vendor/botan/sm3/sm3.odin +++ b/vendor/botan/sm3/sm3.odin @@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the diff --git a/vendor/botan/streebog/streebog.odin b/vendor/botan/streebog/streebog.odin index cbf2047ed..20b4e6adb 100644 --- a/vendor/botan/streebog/streebog.odin +++ b/vendor/botan/streebog/streebog.odin @@ -45,7 +45,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash); + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the @@ -124,7 +124,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash); + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the diff --git a/vendor/botan/tiger/tiger.odin b/vendor/botan/tiger/tiger.odin index b29602b26..f24dc7019 100644 --- a/vendor/botan/tiger/tiger.odin +++ b/vendor/botan/tiger/tiger.odin @@ -46,7 +46,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash); + hash_bytes_to_buffer_128(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128 will hash the given input and write the @@ -125,7 +125,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash); + hash_bytes_to_buffer_160(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_160 will hash the given input and write the @@ -204,7 +204,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192(transmute([]byte)(data), hash); + hash_bytes_to_buffer_192(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_192 will hash the given input and write the diff --git a/vendor/botan/whirlpool/whirlpool.odin b/vendor/botan/whirlpool/whirlpool.odin index 2aff3c8ed..a7c1abbe8 100644 --- a/vendor/botan/whirlpool/whirlpool.odin +++ b/vendor/botan/whirlpool/whirlpool.odin @@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash); + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the From b6dc253d8b1252d8d6554a8f5fb6804170123a57 Mon Sep 17 00:00:00 2001 From: zhibog Date: Tue, 22 Feb 2022 20:02:34 +0100 Subject: [PATCH 0244/1052] Add generic procedure for default SipHash 2-4 --- core/crypto/siphash/siphash.odin | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin index 14cd53a4c..63576551c 100644 --- a/core/crypto/siphash/siphash.odin +++ b/core/crypto/siphash/siphash.odin @@ -8,6 +8,8 @@ package siphash zhibog: Initial implementation. Implementation of the SipHash hashing algorithm, as defined at and + + Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4 */ import "core:crypto" @@ -116,6 +118,17 @@ sum_2_4 :: proc { sum_bytes_to_buffer_2_4, } +sum_string :: sum_string_2_4 +sum_bytes :: sum_bytes_2_4 +sum_string_to_buffer :: sum_string_to_buffer_2_4 +sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4 +sum :: proc { + sum_string, + sum_bytes, + sum_string_to_buffer, + sum_bytes_to_buffer, +} + // verify_u64_2_4 will check if the supplied tag matches with the output you // will get from the provided message and key verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool { @@ -135,6 +148,13 @@ verify_2_4 :: proc { verify_u64_2_4, } +verify_bytes :: verify_bytes_2_4 +verify_u64 :: verify_u64_2_4 +verify :: proc { + verify_bytes, + verify_u64, +} + // sum_string_4_8 will hash the given message with the key and return // the computed hash as a u64 sum_string_4_8 :: proc(msg, key: string) -> u64 { From 460b5149af14bd700b188d3b398786b3081f2159 Mon Sep 17 00:00:00 2001 From: zhibog Date: Tue, 22 Feb 2022 20:06:52 +0100 Subject: [PATCH 0245/1052] Added missing constants --- vendor/botan/bindings/botan.odin | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index fdddc99a9..74461871e 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -99,6 +99,10 @@ MAC_HMAC_SHA_384 :: "HMAC(SHA-384)" MAC_HMAC_SHA_512 :: "HMAC(SHA-512)" MAC_HMAC_MD5 :: "HMAC(MD5)" +MAC_SIPHASH_1_3 :: "SipHash(1,3)" +MAC_SIPHASH_2_4 :: "SipHash(2,4)" +MAC_SIPHASH_4_8 :: "SipHash(4,8)" + hash_struct :: struct{} hash_t :: ^hash_struct rng_struct :: struct{} @@ -136,11 +140,11 @@ totp_t :: ^totp_struct fpe_struct :: struct{} fpe_t :: ^fpe_struct -when ODIN_OS == .Windows { +when ODIN_OS == "windows" { foreign import botan_lib "botan.lib" -} else when ODIN_OS == .Linux { +} else when ODIN_OS == "linux" { foreign import botan_lib "system:botan-2" -} else when ODIN_OS == .Darwin { +} else when ODIN_OS == "darwin" { foreign import botan_lib "system:botan-2" } @@ -467,4 +471,4 @@ foreign botan_lib { fpe_destroy :: proc(fpe: fpe_t) -> c.int --- fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- -} \ No newline at end of file +} From cdecb0ccc3bfc260bd34dce5f76c6238decaa0ef Mon Sep 17 00:00:00 2001 From: zhibog Date: Tue, 22 Feb 2022 20:10:35 +0100 Subject: [PATCH 0246/1052] Fix Odin_OS_Type --- vendor/botan/bindings/botan.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 74461871e..70311523d 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -140,11 +140,11 @@ totp_t :: ^totp_struct fpe_struct :: struct{} fpe_t :: ^fpe_struct -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import botan_lib "botan.lib" -} else when ODIN_OS == "linux" { +} else when ODIN_OS == .Linux { foreign import botan_lib "system:botan-2" -} else when ODIN_OS == "darwin" { +} else when ODIN_OS == .Darwin { foreign import botan_lib "system:botan-2" } @@ -471,4 +471,4 @@ foreign botan_lib { fpe_destroy :: proc(fpe: fpe_t) -> c.int --- fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- -} +} \ No newline at end of file From 70e8d97ee1028aa491286195dfa75f7fc49d4133 Mon Sep 17 00:00:00 2001 From: zhibog Date: Tue, 22 Feb 2022 20:13:49 +0100 Subject: [PATCH 0247/1052] Fix procedure --- vendor/botan/siphash/siphash.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/botan/siphash/siphash.odin b/vendor/botan/siphash/siphash.odin index ae8e19917..c2b7b64f4 100644 --- a/vendor/botan/siphash/siphash.odin +++ b/vendor/botan/siphash/siphash.odin @@ -243,7 +243,7 @@ update :: proc "contextless" (ctx: ^botan.mac_t, data: []byte) { botan.mac_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.mac_t, dst: []byte) { +final :: proc(ctx: ^botan.mac_t, dst: []byte) { botan.mac_final(ctx^, &dst[0]) reset(ctx) } From cad753e3986183fa180abae480a85432b4b36af1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 22 Feb 2022 22:53:13 +0000 Subject: [PATCH 0248/1052] Simplify `parse_binary_expr` --- src/parser.cpp | 159 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 49 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 8a7ab2d20..c214df782 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3013,66 +3013,127 @@ i32 token_precedence(AstFile *f, TokenKind t) { return 0; } +// Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { +// Ast *expr = parse_unary_expr(f, lhs); +// for (i32 prec = token_precedence(f, f->curr_token.kind); prec >= prec_in; prec--) { +// for (;;) { +// Token op = f->curr_token; +// i32 op_prec = token_precedence(f, op.kind); +// if (op_prec != prec) { +// // NOTE(bill): This will also catch operators that are not valid "binary" operators +// break; +// } +// Token prev = f->prev_token; +// switch (op.kind) { +// case Token_if: +// case Token_when: +// if (prev.pos.line < op.pos.line) { +// // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition +// goto loop_end; +// } +// break; +// } +// expect_operator(f); // NOTE(bill): error checks too + +// if (op.kind == Token_Question) { +// Ast *cond = expr; +// // Token_Question +// Ast *x = parse_expr(f, lhs); +// Token token_c = expect_token(f, Token_Colon); +// Ast *y = parse_expr(f, lhs); +// expr = ast_ternary_if_expr(f, x, cond, y); +// } else if (op.kind == Token_if || op.kind == Token_when) { +// Ast *x = expr; +// Ast *cond = parse_expr(f, lhs); +// Token tok_else = expect_token(f, Token_else); +// Ast *y = parse_expr(f, lhs); + +// switch (op.kind) { +// case Token_if: +// expr = ast_ternary_if_expr(f, x, cond, y); +// break; +// case Token_when: +// expr = ast_ternary_when_expr(f, x, cond, y); +// break; +// } +// } else { +// Ast *right = parse_binary_expr(f, false, prec+1); +// if (right == nullptr) { +// syntax_error(op, "Expected expression on the right-hand side of the binary operator '%.*s'", LIT(op.string)); +// } +// if (op.kind == Token_or_else) { +// // NOTE(bill): easier to handle its logic different with its own AST kind +// expr = ast_or_else_expr(f, expr, op, right); +// } else { +// expr = ast_binary_expr(f, op, expr, right); +// } +// } + +// lhs = false; +// } +// loop_end:; +// } +// return expr; +// } + Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { Ast *expr = parse_unary_expr(f, lhs); - for (i32 prec = token_precedence(f, f->curr_token.kind); prec >= prec_in; prec--) { - for (;;) { - Token op = f->curr_token; - i32 op_prec = token_precedence(f, op.kind); - if (op_prec != prec) { - // NOTE(bill): This will also catch operators that are not valid "binary" operators - break; + for (;;) { + Token op = f->curr_token; + i32 op_prec = token_precedence(f, op.kind); + if (op_prec < prec_in) { + // NOTE(bill): This will also catch operators that are not valid "binary" operators + break; + } + Token prev = f->prev_token; + switch (op.kind) { + case Token_if: + case Token_when: + if (prev.pos.line < op.pos.line) { + // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition + goto loop_end; } - Token prev = f->prev_token; + break; + } + expect_operator(f); // NOTE(bill): error checks too + + if (op.kind == Token_Question) { + Ast *cond = expr; + // Token_Question + Ast *x = parse_expr(f, lhs); + Token token_c = expect_token(f, Token_Colon); + Ast *y = parse_expr(f, lhs); + expr = ast_ternary_if_expr(f, x, cond, y); + } else if (op.kind == Token_if || op.kind == Token_when) { + Ast *x = expr; + Ast *cond = parse_expr(f, lhs); + Token tok_else = expect_token(f, Token_else); + Ast *y = parse_expr(f, lhs); + switch (op.kind) { case Token_if: + expr = ast_ternary_if_expr(f, x, cond, y); + break; case Token_when: - if (prev.pos.line < op.pos.line) { - // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition - goto loop_end; - } + expr = ast_ternary_when_expr(f, x, cond, y); break; } - expect_operator(f); // NOTE(bill): error checks too - - if (op.kind == Token_Question) { - Ast *cond = expr; - // Token_Question - Ast *x = parse_expr(f, lhs); - Token token_c = expect_token(f, Token_Colon); - Ast *y = parse_expr(f, lhs); - expr = ast_ternary_if_expr(f, x, cond, y); - } else if (op.kind == Token_if || op.kind == Token_when) { - Ast *x = expr; - Ast *cond = parse_expr(f, lhs); - Token tok_else = expect_token(f, Token_else); - Ast *y = parse_expr(f, lhs); - - switch (op.kind) { - case Token_if: - expr = ast_ternary_if_expr(f, x, cond, y); - break; - case Token_when: - expr = ast_ternary_when_expr(f, x, cond, y); - break; - } - } else { - Ast *right = parse_binary_expr(f, false, prec+1); - if (right == nullptr) { - syntax_error(op, "Expected expression on the right-hand side of the binary operator '%.*s'", LIT(op.string)); - } - if (op.kind == Token_or_else) { - // NOTE(bill): easier to handle its logic different with its own AST kind - expr = ast_or_else_expr(f, expr, op, right); - } else { - expr = ast_binary_expr(f, op, expr, right); - } + } else { + Ast *right = parse_binary_expr(f, false, op_prec+1); + if (right == nullptr) { + syntax_error(op, "Expected expression on the right-hand side of the binary operator '%.*s'", LIT(op.string)); + } + if (op.kind == Token_or_else) { + // NOTE(bill): easier to handle its logic different with its own AST kind + expr = ast_or_else_expr(f, expr, op, right); + } else { + expr = ast_binary_expr(f, op, expr, right); } - - lhs = false; } - loop_end:; + + lhs = false; } + loop_end:; return expr; } From 62d232d798fff25597b6e3591c6a178c32fa440e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 22 Feb 2022 22:59:00 +0000 Subject: [PATCH 0249/1052] Correct `ExactValue_Pointer` --- src/exact_value.cpp | 17 +++++++++--- src/parser.cpp | 63 --------------------------------------------- 2 files changed, 14 insertions(+), 66 deletions(-) diff --git a/src/exact_value.cpp b/src/exact_value.cpp index fd90278e5..3dae96853 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -630,6 +630,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Bool: case ExactValue_String: case ExactValue_Quaternion: + case ExactValue_Pointer: + case ExactValue_Procedure: + case ExactValue_Typeid: return; case ExactValue_Integer: @@ -671,9 +674,6 @@ void match_exact_values(ExactValue *x, ExactValue *y) { return; } break; - - case ExactValue_Procedure: - return; } compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind); @@ -932,6 +932,17 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { break; } + case ExactValue_Pointer: { + switch (op) { + case Token_CmpEq: return x.value_pointer == y.value_pointer; + case Token_NotEq: return x.value_pointer != y.value_pointer; + case Token_Lt: return x.value_pointer < y.value_pointer; + case Token_LtEq: return x.value_pointer <= y.value_pointer; + case Token_Gt: return x.value_pointer > y.value_pointer; + case Token_GtEq: return x.value_pointer >= y.value_pointer; + } + } + case ExactValue_Typeid: switch (op) { case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid); diff --git a/src/parser.cpp b/src/parser.cpp index c214df782..9659e8c18 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3013,69 +3013,6 @@ i32 token_precedence(AstFile *f, TokenKind t) { return 0; } -// Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { -// Ast *expr = parse_unary_expr(f, lhs); -// for (i32 prec = token_precedence(f, f->curr_token.kind); prec >= prec_in; prec--) { -// for (;;) { -// Token op = f->curr_token; -// i32 op_prec = token_precedence(f, op.kind); -// if (op_prec != prec) { -// // NOTE(bill): This will also catch operators that are not valid "binary" operators -// break; -// } -// Token prev = f->prev_token; -// switch (op.kind) { -// case Token_if: -// case Token_when: -// if (prev.pos.line < op.pos.line) { -// // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition -// goto loop_end; -// } -// break; -// } -// expect_operator(f); // NOTE(bill): error checks too - -// if (op.kind == Token_Question) { -// Ast *cond = expr; -// // Token_Question -// Ast *x = parse_expr(f, lhs); -// Token token_c = expect_token(f, Token_Colon); -// Ast *y = parse_expr(f, lhs); -// expr = ast_ternary_if_expr(f, x, cond, y); -// } else if (op.kind == Token_if || op.kind == Token_when) { -// Ast *x = expr; -// Ast *cond = parse_expr(f, lhs); -// Token tok_else = expect_token(f, Token_else); -// Ast *y = parse_expr(f, lhs); - -// switch (op.kind) { -// case Token_if: -// expr = ast_ternary_if_expr(f, x, cond, y); -// break; -// case Token_when: -// expr = ast_ternary_when_expr(f, x, cond, y); -// break; -// } -// } else { -// Ast *right = parse_binary_expr(f, false, prec+1); -// if (right == nullptr) { -// syntax_error(op, "Expected expression on the right-hand side of the binary operator '%.*s'", LIT(op.string)); -// } -// if (op.kind == Token_or_else) { -// // NOTE(bill): easier to handle its logic different with its own AST kind -// expr = ast_or_else_expr(f, expr, op, right); -// } else { -// expr = ast_binary_expr(f, op, expr, right); -// } -// } - -// lhs = false; -// } -// loop_end:; -// } -// return expr; -// } - Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { Ast *expr = parse_unary_expr(f, lhs); for (;;) { From ad2f1ac24ebdb4937c5a469c3d3f48b8f53f6218 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 22 Feb 2022 23:01:28 +0000 Subject: [PATCH 0250/1052] Improve `union_tag_size` --- src/types.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/types.cpp b/src/types.cpp index 2c1e6162f..74080334a 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2623,6 +2623,17 @@ i64 union_tag_size(Type *u) { // TODO(bill): Is this an okay approach? i64 max_align = 1; + + if (u->Union.variants.count < 1ull<<8) { + max_align = 1; + } else if (u->Union.variants.count < 1ull<<16) { + max_align = 2; + } else if (u->Union.variants.count < 1ull<<32) { + max_align = 4; + } else { + GB_PANIC("how many variants do you have?!"); + } + for_array(i, u->Union.variants) { Type *variant_type = u->Union.variants[i]; i64 align = type_align_of(variant_type); From 83f7a887b7ab9313e520211521297a9352c408b9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 22 Feb 2022 23:03:04 +0000 Subject: [PATCH 0251/1052] Move comment --- src/exact_value.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 3dae96853..f6df48951 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -50,9 +50,9 @@ struct ExactValue { union { bool value_bool; String value_string; - BigInt value_integer; // NOTE(bill): This must be an integer and not a pointer + BigInt value_integer; f64 value_float; - i64 value_pointer; + i64 value_pointer; // NOTE(bill): This must be an integer and not a pointer Complex128 *value_complex; Quaternion256 *value_quaternion; Ast * value_compound; From e81ed9a9601f6a7761dec5b0f96cc8680a16f166 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 22 Feb 2022 23:19:49 +0000 Subject: [PATCH 0252/1052] Add "Did you mean" to Objective-C fields --- src/check_expr.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 884f1bb9f..e07dc3d60 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -132,6 +132,62 @@ void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { } } +void populate_check_did_you_mean_objc_entity(StringSet *set, Entity *e, bool is_type) { + if (e->kind != Entity_TypeName) { + return; + } + if (e->TypeName.objc_metadata == nullptr) { + return; + } + TypeNameObjCMetadata *objc_metadata = e->TypeName.objc_metadata; + Type *t = base_type(e->type); + GB_ASSERT(t->kind == Type_Struct); + + if (is_type) { + for_array(i, objc_metadata->type_entries) { + String name = objc_metadata->type_entries[i].name; + string_set_add(set, name); + } + } else { + for_array(i, objc_metadata->value_entries) { + String name = objc_metadata->value_entries[i].name; + string_set_add(set, name); + } + } + + for_array(i, t->Struct.fields) { + Entity *f = t->Struct.fields[i]; + if (f->flags & EntityFlag_Using && f->type != nullptr) { + if (f->type->kind == Type_Named && f->type->Named.type_name) { + populate_check_did_you_mean_objc_entity(set, f->type->Named.type_name, is_type); + } + } + } +} + + +void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") { + ERROR_BLOCK(); + GB_ASSERT(e->kind == Entity_TypeName); + GB_ASSERT(e->TypeName.objc_metadata != nullptr); + auto *objc_metadata = e->TypeName.objc_metadata; + mutex_lock(objc_metadata->mutex); + defer (mutex_unlock(objc_metadata->mutex)); + + StringSet set = {}; + string_set_init(&set, heap_allocator()); + defer (string_set_destroy(&set)); + populate_check_did_you_mean_objc_entity(&set, e, is_type); + + + DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), set.entries.count, name); + defer (did_you_mean_destroy(&d)); + for_array(i, set.entries) { + did_you_mean_append(&d, set.entries[i].value); + } + check_did_you_mean_print(&d, prefix); +} + void check_did_you_mean_type(String const &name, Array const &fields, char const *prefix = "") { ERROR_BLOCK(); @@ -144,6 +200,7 @@ void check_did_you_mean_type(String const &name, Array const &fields, check_did_you_mean_print(&d, prefix); } + void check_did_you_mean_type(String const &name, Slice const &fields, char const *prefix = "") { ERROR_BLOCK(); @@ -4420,7 +4477,12 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ if (operand->type != nullptr && selector->kind == Ast_Ident) { String const &name = selector->Ident.token.string; Type *bt = base_type(operand->type); - if (bt->kind == Type_Struct) { + if (operand->type->kind == Type_Named && + operand->type->Named.type_name && + operand->type->Named.type_name->kind == Entity_TypeName && + operand->type->Named.type_name->TypeName.objc_metadata) { + check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type); + } else if (bt->kind == Type_Struct) { check_did_you_mean_type(name, bt->Struct.fields); } else if (bt->kind == Type_Enum) { check_did_you_mean_type(name, bt->Enum.fields); From 3d209798c9aff4a0ebd135536234022620c9e650 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Feb 2022 11:19:51 +0000 Subject: [PATCH 0253/1052] Add help docs for `-reloc-mode:` --- src/build_settings.cpp | 2 +- src/llvm_backend.cpp | 2 ++ src/main.cpp | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d56a343df..790f7f1bc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -189,7 +189,7 @@ enum ErrorPosStyle { ErrorPosStyle_COUNT }; -enum RelocMode { +enum RelocMode : u8 { RelocMode_Default, RelocMode_Static, RelocMode_PIC, diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 692b96c51..ec22c7443 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1261,6 +1261,8 @@ void lb_generate_code(lbGenerator *gen) { LLVMCodeModel code_mode = LLVMCodeModelDefault; if (is_arch_wasm()) { code_mode = LLVMCodeModelJITDefault; + } else if (build_context.metrics.os == TargetOs_freestanding) { + code_mode = LLVMCodeModelKernel; } char const *host_cpu_name = LLVMGetHostCPUName(); diff --git a/src/main.cpp b/src/main.cpp index 087f2b442..cfc7decb1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2087,6 +2087,15 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:native"); print_usage_line(0, ""); + + print_usage_line(1, "-reloc-mode:"); + print_usage_line(2, "Specifies the reloc mode"); + print_usage_line(2, "Options:"); + print_usage_line(3, "default"); + print_usage_line(3, "static"); + print_usage_line(3, "pic"); + print_usage_line(3, "dynamic-no-pic"); + print_usage_line(0, ""); } if (check) { From 493bc653b5762514dac8c8941d6564ccf5bb8528 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Feb 2022 11:23:27 +0000 Subject: [PATCH 0254/1052] Add `@(no_red_zone)` for procedures --- src/check_decl.cpp | 8 ++++++++ src/checker.cpp | 7 +++++++ src/checker.hpp | 1 + src/entity.cpp | 1 + src/llvm_backend_proc.cpp | 4 ++++ 5 files changed, 21 insertions(+) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 45d741532..6f8caff98 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -826,6 +826,14 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } e->Procedure.optimization_mode = cast(ProcedureOptimizationMode)ac.optimization_mode; + if (ac.no_red_zone) { + if (!is_arch_wasm()) { + e->Procedure.no_red_zone = true; + } else { + error(e->token, "@(no_red_zone) is not supported on this target architecture"); + } + } + if (ac.objc_name.len || ac.objc_is_class_method || ac.objc_type) { if (ac.objc_name.len == 0 && ac.objc_is_class_method) { error(e->token, "@(objc_name) is required with @(objc_is_class_method)"); diff --git a/src/checker.cpp b/src/checker.cpp index fe1d362fa..89e60c258 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3128,6 +3128,13 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } } return true; + } else if (name == "no_red_zone") { + if (value != nullptr) { + error(elem, "Expected no value for '%.*s'", LIT(name)); + } else { + ac->no_red_zone = true; + } + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index 552e6aca7..548439774 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -117,6 +117,7 @@ struct AttributeContext { bool test : 1; bool init : 1; bool set_cold : 1; + bool no_red_zone : 1; u32 optimization_mode; // ProcedureOptimizationMode String objc_class; diff --git a/src/entity.cpp b/src/entity.cpp index f5720293f..84ddd5c6b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -226,6 +226,7 @@ struct Entity { bool is_foreign; bool is_export; bool generated_from_polymorphic; + bool no_red_zone; ProcedureOptimizationMode optimization_mode; } Procedure; struct { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7ead77c2c..209f2f67b 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -135,6 +135,10 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) lb_add_attribute_to_proc(m, p->value, "naked"); } + if (entity->Procedure.no_red_zone) { + lb_add_attribute_to_proc(m, p->value, "noredzone"); + } + switch (p->inlining) { case ProcInlining_inline: lb_add_attribute_to_proc(m, p->value, "alwaysinline"); From 196bd735d4c30964182fdf1f374f767ccb0912fa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Feb 2022 11:29:36 +0000 Subject: [PATCH 0255/1052] Replace local `@(no_red_zone)` with global `-disable-red-zone` --- src/build_settings.cpp | 8 ++++++++ src/check_decl.cpp | 8 -------- src/checker.cpp | 7 ------- src/checker.hpp | 1 - src/entity.cpp | 1 - src/llvm_backend_proc.cpp | 2 +- src/main.cpp | 8 ++++++++ 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 790f7f1bc..62f43fad3 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -278,6 +278,7 @@ struct BuildContext { bool copy_file_contents; RelocMode reloc_mode; + bool disable_red_zone; u32 cmd_doc_flags; @@ -1002,6 +1003,13 @@ void init_build_context(TargetMetrics *cross_target) { bc->threaded_checker = true; #endif + if (bc->disable_red_zone) { + if (!(bc->metrics.os == TargetOs_freestanding && !is_arch_wasm())) { + gb_printf_err("-disable-red-zone is not support for this target"); + gb_exit(1); + } + } + // NOTE(zangent): The linker flags to set the build architecture are different // across OSs. It doesn't make sense to allocate extra data on the heap diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 6f8caff98..45d741532 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -826,14 +826,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } e->Procedure.optimization_mode = cast(ProcedureOptimizationMode)ac.optimization_mode; - if (ac.no_red_zone) { - if (!is_arch_wasm()) { - e->Procedure.no_red_zone = true; - } else { - error(e->token, "@(no_red_zone) is not supported on this target architecture"); - } - } - if (ac.objc_name.len || ac.objc_is_class_method || ac.objc_type) { if (ac.objc_name.len == 0 && ac.objc_is_class_method) { error(e->token, "@(objc_name) is required with @(objc_is_class_method)"); diff --git a/src/checker.cpp b/src/checker.cpp index 89e60c258..fe1d362fa 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3128,13 +3128,6 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } } return true; - } else if (name == "no_red_zone") { - if (value != nullptr) { - error(elem, "Expected no value for '%.*s'", LIT(name)); - } else { - ac->no_red_zone = true; - } - return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index 548439774..552e6aca7 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -117,7 +117,6 @@ struct AttributeContext { bool test : 1; bool init : 1; bool set_cold : 1; - bool no_red_zone : 1; u32 optimization_mode; // ProcedureOptimizationMode String objc_class; diff --git a/src/entity.cpp b/src/entity.cpp index 84ddd5c6b..f5720293f 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -226,7 +226,6 @@ struct Entity { bool is_foreign; bool is_export; bool generated_from_polymorphic; - bool no_red_zone; ProcedureOptimizationMode optimization_mode; } Procedure; struct { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 209f2f67b..053ee2fb2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -135,7 +135,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) lb_add_attribute_to_proc(m, p->value, "naked"); } - if (entity->Procedure.no_red_zone) { + if (!entity->Procedure.is_foreign && build_context.disable_red_zone) { lb_add_attribute_to_proc(m, p->value, "noredzone"); } diff --git a/src/main.cpp b/src/main.cpp index cfc7decb1..1e7b78da4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -626,6 +626,7 @@ enum BuildFlagKind { BuildFlag_Microarch, BuildFlag_RelocMode, + BuildFlag_DisableRedZone, BuildFlag_TestName, @@ -782,6 +783,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); @@ -1365,6 +1367,9 @@ bool parse_build_flags(Array args) { break; } + case BuildFlag_DisableRedZone: + build_context.disable_red_zone = true; + break; case BuildFlag_TestName: { GB_ASSERT(value.kind == ExactValue_String); { @@ -2096,6 +2101,9 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(3, "pic"); print_usage_line(3, "dynamic-no-pic"); print_usage_line(0, ""); + + print_usage_line(1, "-disable-red-zone"); + print_usage_line(2, "Disable red zone on a supported freestanding target"); } if (check) { From 4a04a32e0ab4ad91a7b62c0a94e57312002b85d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Feb 2022 11:33:28 +0000 Subject: [PATCH 0256/1052] Change target name to `freestanding_amd64_sysv` --- src/build_settings.cpp | 10 +++++----- src/llvm_abi.cpp | 4 ++-- src/llvm_backend.cpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 62f43fad3..d6cdd7006 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -49,8 +49,8 @@ enum TargetEndianKind : u8 { enum TargetABIKind : u16 { TargetABI_Default, - TargetABI_MSVC, - TargetABI_GNU, + TargetABI_Win64, + TargetABI_SysV, TargetABI_COUNT, }; @@ -428,14 +428,14 @@ gb_global TargetMetrics target_wasi_wasm32 = { // str_lit(""), // }; -gb_global TargetMetrics target_freestanding_amd64_gnu = { +gb_global TargetMetrics target_freestanding_amd64_sysv = { TargetOs_freestanding, TargetArch_amd64, 8, 16, str_lit("x86_64-pc-none-gnu"), str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), - TargetABI_GNU, + TargetABI_SysV, }; @@ -460,7 +460,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("js_wasm32"), &target_js_wasm32 }, - { str_lit("freestanding_amd64_gnu"), &target_freestanding_amd64_gnu }, + { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv }, }; NamedTargetMetrics *selected_target_metrics; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 770e54ac8..07d2dd6e3 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1194,9 +1194,9 @@ LB_ABI_INFO(lb_get_abi_info) { switch (build_context.metrics.arch) { case TargetArch_amd64: - if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_MSVC) { + if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) { return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); - } else if (build_context.metrics.abi == TargetABI_GNU) { + } else if (build_context.metrics.abi == TargetABI_SysV) { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } else { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index ec22c7443..6ca256c4b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1001,10 +1001,10 @@ String lb_filepath_obj_for_module(lbModule *m) { switch (build_context.metrics.abi) { default: case TargetABI_Default: - case TargetABI_GNU: + case TargetABI_SysV: ext = STR_LIT(".o"); break; - case TargetABI_MSVC: + case TargetABI_Win64: ext = STR_LIT(".obj"); break; } From 384fb76a1b4c82546194409da04f6dc5e4c59da4 Mon Sep 17 00:00:00 2001 From: Jesse Stiller Date: Thu, 24 Feb 2022 12:59:06 +1000 Subject: [PATCH 0257/1052] Added options to help, and improved wording --- src/main.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 014fbf822..7bee814fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -572,14 +572,16 @@ void usage(String argv0) { print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(0, "Commands:"); - print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable."); - print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); - print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); - print_usage_line(1, "check parse and type check .odin file"); - print_usage_line(1, "query parse, type check, and output a .json file containing information about the program"); - print_usage_line(1, "doc generate documentation .odin file, or directory of .odin files"); - print_usage_line(1, "version print version"); - print_usage_line(1, "report print information useful to reporting a bug"); + print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable."); + print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); + print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); + print_usage_line(1, "check parse, and type check an .odin file, or directory of .odin files"); + print_usage_line(1, "query parse, type check, and output a .json file containing information about the program"); + print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program"); + print_usage_line(1, "test build ands runs procedures with the attribute @(test) in the initial package"); + print_usage_line(1, "doc generate documentation .odin file, or directory of .odin files"); + print_usage_line(1, "version print version"); + print_usage_line(1, "report print information useful to reporting a bug"); print_usage_line(0, ""); print_usage_line(0, "For further details on a command, use -help after the command name"); print_usage_line(1, "e.g. odin build -help"); From d4f62f52db3b263b2c081b90dca0b1a23ccb2993 Mon Sep 17 00:00:00 2001 From: Tail Wag Games Date: Thu, 24 Feb 2022 00:20:15 -0600 Subject: [PATCH 0258/1052] adding `is_16_bit_from_memory` to stbi --- vendor/stb/image/stb_image.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vendor/stb/image/stb_image.odin b/vendor/stb/image/stb_image.odin index 8a3582792..4f7e43171 100644 --- a/vendor/stb/image/stb_image.odin +++ b/vendor/stb/image/stb_image.odin @@ -74,8 +74,9 @@ foreign stbi { info_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, comp: ^c.int) -> c.int --- info_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, comp: ^c.int) -> c.int --- - is_16_bit :: proc(filename: cstring) -> b32 --- - is_16_bit_from_file :: proc(f: ^c.FILE) -> b32 --- + is_16_bit :: proc(filename: cstring) -> b32 --- + is_16_bit_from_file :: proc(f: ^c.FILE) -> b32 --- + is_16_bit_from_memory :: proc(buffer: [^]byte, len: c.int) -> c.int --- // for image formats that explicitly notate that they have premultiplied alpha, // we just return the colors as stored in the file. set this flag to force From aeaf1199ec8f9ac8b86bd71f17067dbcb734ea48 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Thu, 24 Feb 2022 01:13:51 -0800 Subject: [PATCH 0259/1052] Add make_directory so darwin can build html docs --- core/os/os_darwin.odin | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index a011fa58a..c28db2865 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -313,6 +313,7 @@ foreign libc { @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- + @(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u32) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring --- @@ -670,6 +671,15 @@ set_current_directory :: proc(path: string) -> (err: Errno) { return ERROR_NONE } +make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_mkdir(path_cstr, mode) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + exit :: proc "contextless" (code: int) -> ! { _unix_exit(i32(code)) } From 14f1793b3ec5aa012ee96eee5acad20062014718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 24 Feb 2022 11:28:42 +0000 Subject: [PATCH 0260/1052] use `context.temp_allocator` instead of general allocation + delete() where clone_to_cstring is used with foreign code, it is prefered to use `context.temp_allocator` instead of using the general allocator and manually delete the memory after use. --- core/os/os_darwin.odin | 3 +- core/os/os_freebsd.odin | 19 ++++--------- core/os/os_linux.odin | 27 ++++++------------ core/sys/darwin/xnu_system_call_helpers.odin | 30 +++++++------------- 4 files changed, 26 insertions(+), 53 deletions(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index a011fa58a..1f7e21723 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -344,9 +344,8 @@ get_last_error_string :: proc() -> string { } open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) { - cstr := strings.clone_to_cstring(path) + cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, i32(flags), u16(mode)) - delete(cstr) if handle == -1 { return INVALID_HANDLE, 1 } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 82317532d..3f5174c1b 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -267,9 +267,8 @@ get_last_error :: proc() -> int { } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - cstr := strings.clone_to_cstring(path); + cstr := strings.clone_to_cstring(path, context.temp_allocator); handle := _unix_open(cstr, c.int(flags), c.int(mode)); - delete(cstr); if handle == -1 { return INVALID_HANDLE, Errno(get_last_error()); } @@ -342,9 +341,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { } stat :: proc(path: string) -> (OS_Stat, Errno) { - cstr := strings.clone_to_cstring(path); - defer delete(cstr); - + cstr := strings.clone_to_cstring(path, context.temp_allocator); s: OS_Stat; result := _unix_stat(cstr, &s); if result == -1 { @@ -363,8 +360,7 @@ fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { } access :: proc(path: string, mask: int) -> (bool, Errno) { - cstr := strings.clone_to_cstring(path); - defer delete(cstr); + cstr := strings.clone_to_cstring(path, context.temp_allocator); result := _unix_access(cstr, c.int(mask)); if result == -1 { return false, Errno(get_last_error()); @@ -388,8 +384,7 @@ heap_free :: proc(ptr: rawptr) { } getenv :: proc(name: string) -> (string, bool) { - path_str := strings.clone_to_cstring(name); - defer delete(path_str); + path_str := strings.clone_to_cstring(name, context.temp_allocator); cstr := _unix_getenv(path_str); if cstr == nil { return "", false; @@ -432,15 +427,13 @@ current_thread_id :: proc "contextless" () -> int { } dlopen :: proc(filename: string, flags: int) -> rawptr { - cstr := strings.clone_to_cstring(filename); - defer delete(cstr); + cstr := strings.clone_to_cstring(filename, context.temp_allocator); handle := _unix_dlopen(cstr, c.int(flags)); return handle; } dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil); - cstr := strings.clone_to_cstring(symbol); - defer delete(cstr); + cstr := strings.clone_to_cstring(symbol, context.temp_allocator); proc_handle := _unix_dlsym(handle, cstr); return proc_handle; } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 4edfa46da..200d6d68d 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -460,9 +460,8 @@ fork :: proc() -> (Pid, Errno) { } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - cstr := strings.clone_to_cstring(path) + cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, flags, mode) - defer delete(cstr) if handle < 0 { return INVALID_HANDLE, _get_errno(int(handle)) } @@ -610,8 +609,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { @private _stat :: proc(path: string) -> (OS_Stat, Errno) { - cstr := strings.clone_to_cstring(path) - defer delete(cstr) + cstr := strings.clone_to_cstring(path, context.temp_allocator) // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- @@ -624,8 +622,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { @private _lstat :: proc(path: string) -> (OS_Stat, Errno) { - cstr := strings.clone_to_cstring(path) - defer delete(cstr) + cstr := strings.clone_to_cstring(path, context.temp_allocator) // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- @@ -692,8 +689,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) @private _readlink :: proc(path: string) -> (string, Errno) { - path_cstr := strings.clone_to_cstring(path) - defer delete(path_cstr) + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) bufsz : uint = 256 buf := make([]byte, bufsz) @@ -729,8 +725,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { rel = "." } - rel_cstr := strings.clone_to_cstring(rel) - defer delete(rel_cstr) + rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) path_ptr := _unix_realpath(rel_cstr, nil) if path_ptr == nil { @@ -745,8 +740,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } access :: proc(path: string, mask: int) -> (bool, Errno) { - cstr := strings.clone_to_cstring(path) - defer delete(cstr) + cstr := strings.clone_to_cstring(path, context.temp_allocator) result := _unix_access(cstr, mask) if result < 0 { return false, _get_errno(result) @@ -770,8 +764,7 @@ heap_free :: proc(ptr: rawptr) { } getenv :: proc(name: string) -> (string, bool) { - path_str := strings.clone_to_cstring(name) - defer delete(path_str) + path_str := strings.clone_to_cstring(name, context.temp_allocator) cstr := _unix_getenv(path_str) if cstr == nil { return "", false @@ -817,15 +810,13 @@ current_thread_id :: proc "contextless" () -> int { } dlopen :: proc(filename: string, flags: int) -> rawptr { - cstr := strings.clone_to_cstring(filename) - defer delete(cstr) + cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, c.int(flags)) return handle } dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) - cstr := strings.clone_to_cstring(symbol) - defer delete(cstr) + cstr := strings.clone_to_cstring(symbol, context.temp_allocator) proc_handle := _unix_dlsym(handle, cstr) return proc_handle } diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin index 5b060cfd3..94fe0bf47 100644 --- a/core/sys/darwin/xnu_system_call_helpers.odin +++ b/core/sys/darwin/xnu_system_call_helpers.odin @@ -91,8 +91,7 @@ sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, b cmode: u32 = 0 cflags: u32 = 0 - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) cflags = _sys_permission_mode(mode) @@ -124,39 +123,32 @@ sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, b } sys_mkdir :: proc(path: string, mode: Permission) -> bool { - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) cflags := _sys_permission_mode(mode) return syscall_mkdir(cpath, cflags) != -1 } sys_mkdir_at :: proc(fd: c.int, path: string, mode: Permission) -> bool { - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) cflags := _sys_permission_mode(mode) return syscall_mkdir_at(fd, cpath, cflags) != -1 } sys_rmdir :: proc(path: string, mode: Permission) -> bool { - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) cflags := _sys_permission_mode(mode) return syscall_rmdir(cpath, cflags) != -1 } sys_rename :: proc(path: string, new_path: string) -> bool { - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) - cnpath: cstring = strings.clone_to_cstring(new_path) - defer delete(cnpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) + cnpath: cstring = strings.clone_to_cstring(new_path, context.temp_allocator) return syscall_rename(cpath, cnpath) != -1 } sys_rename_at :: proc(fd: c.int, path: string, to_fd: c.int, new_path: string) -> bool { - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) - cnpath: cstring = strings.clone_to_cstring(new_path) - defer delete(cnpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) + cnpath: cstring = strings.clone_to_cstring(new_path, context.temp_allocator) return syscall_rename_at(fd, cpath, to_fd, cnpath) != -1 } @@ -165,14 +157,12 @@ sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 { } sys_chmod :: proc(path: string, mode: Permission) -> bool { - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) cmode := _sys_permission_mode(mode) return syscall_chmod(cpath, cmode) != -1 } sys_lstat :: proc(path: string, status: ^stat) -> bool { - cpath: cstring = strings.clone_to_cstring(path) - defer delete(cpath) + cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator) return syscall_lstat(cpath, status) != -1 } From d3c70f2206255f50e05dd6621132283a9b50e975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 24 Feb 2022 11:30:33 +0000 Subject: [PATCH 0261/1052] remove the optional `;` in os_freebsd.odin --- core/os/os_freebsd.odin | 544 ++++++++++++++++++++-------------------- 1 file changed, 272 insertions(+), 272 deletions(-) diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 3f5174c1b..e31eb31bb 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -7,149 +7,149 @@ import "core:runtime" import "core:strings" import "core:c" -Handle :: distinct i32; -File_Time :: distinct u64; -Errno :: distinct i32; -Syscall :: distinct i32; +Handle :: distinct i32 +File_Time :: distinct u64 +Errno :: distinct i32 +Syscall :: distinct i32 -INVALID_HANDLE :: ~Handle(0); +INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0; -EPERM: Errno : 1; -ENOENT: Errno : 2; -ESRCH: Errno : 3; -EINTR: Errno : 4; -EIO: Errno : 5; -ENXIO: Errno : 6; -E2BIG: Errno : 7; -ENOEXEC: Errno : 8; -EBADF: Errno : 9; -ECHILD: Errno : 10; -EBEADLK: Errno : 11; -ENOMEM: Errno : 12; -EACCESS: Errno : 13; -EFAULT: Errno : 14; -ENOTBLK: Errno : 15; -EBUSY: Errno : 16; -EEXIST: Errno : 17; -EXDEV: Errno : 18; -ENODEV: Errno : 19; -ENOTDIR: Errno : 20; -EISDIR: Errno : 21; -EINVAL: Errno : 22; -ENFILE: Errno : 23; -EMFILE: Errno : 24; -ENOTTY: Errno : 25; -ETXTBSY: Errno : 26; -EFBIG: Errno : 27; -ENOSPC: Errno : 28; -ESPIPE: Errno : 29; -EROFS: Errno : 30; -EMLINK: Errno : 31; -EPIPE: Errno : 32; -EDOM: Errno : 33; -ERANGE: Errno : 34; /* Result too large */ -EAGAIN: Errno : 35; -EINPROGRESS: Errno : 36; -EALREADY: Errno : 37; -ENOTSOCK: Errno : 38; -EDESTADDRREQ: Errno : 39; -EMSGSIZE: Errno : 40; -EPROTOTYPE: Errno : 41; -ENOPROTOOPT: Errno : 42; -EPROTONOSUPPORT: Errno : 43; -ESOCKTNOSUPPORT: Errno : 44; -EOPNOTSUPP: Errno : 45; -EPFNOSUPPORT: Errno : 46; -EAFNOSUPPORT: Errno : 47; -EADDRINUSE: Errno : 48; -EADDRNOTAVAIL: Errno : 49; -ENETDOWN: Errno : 50; -ENETUNREACH: Errno : 51; -ENETRESET: Errno : 52; -ECONNABORTED: Errno : 53; -ECONNRESET: Errno : 54; -ENOBUFS: Errno : 55; -EISCONN: Errno : 56; -ENOTCONN: Errno : 57; -ESHUTDOWN: Errno : 58; -ETIMEDOUT: Errno : 60; -ECONNREFUSED: Errno : 61; -ELOOP: Errno : 62; -ENAMETOOLING: Errno : 63; -EHOSTDOWN: Errno : 64; -EHOSTUNREACH: Errno : 65; -ENOTEMPTY: Errno : 66; -EPROCLIM: Errno : 67; -EUSERS: Errno : 68; -EDQUOT: Errno : 69; -ESTALE: Errno : 70; -EBADRPC: Errno : 72; -ERPCMISMATCH: Errno : 73; -EPROGUNAVAIL: Errno : 74; -EPROGMISMATCH: Errno : 75; -EPROCUNAVAIL: Errno : 76; -ENOLCK: Errno : 77; -ENOSYS: Errno : 78; -EFTYPE: Errno : 79; -EAUTH: Errno : 80; -ENEEDAUTH: Errno : 81; -EIDRM: Errno : 82; -ENOMSG: Errno : 83; -EOVERFLOW: Errno : 84; -ECANCELED: Errno : 85; -EILSEQ: Errno : 86; -ENOATTR: Errno : 87; -EDOOFUS: Errno : 88; -EBADMSG: Errno : 89; -EMULTIHOP: Errno : 90; -ENOLINK: Errno : 91; -EPROTO: Errno : 92; -ENOTCAPABLE: Errno : 93; -ECAPMODE: Errno : 94; -ENOTRECOVERABLE: Errno : 95; -EOWNERDEAD: Errno : 96; +ERROR_NONE: Errno : 0 +EPERM: Errno : 1 +ENOENT: Errno : 2 +ESRCH: Errno : 3 +EINTR: Errno : 4 +EIO: Errno : 5 +ENXIO: Errno : 6 +E2BIG: Errno : 7 +ENOEXEC: Errno : 8 +EBADF: Errno : 9 +ECHILD: Errno : 10 +EBEADLK: Errno : 11 +ENOMEM: Errno : 12 +EACCESS: Errno : 13 +EFAULT: Errno : 14 +ENOTBLK: Errno : 15 +EBUSY: Errno : 16 +EEXIST: Errno : 17 +EXDEV: Errno : 18 +ENODEV: Errno : 19 +ENOTDIR: Errno : 20 +EISDIR: Errno : 21 +EINVAL: Errno : 22 +ENFILE: Errno : 23 +EMFILE: Errno : 24 +ENOTTY: Errno : 25 +ETXTBSY: Errno : 26 +EFBIG: Errno : 27 +ENOSPC: Errno : 28 +ESPIPE: Errno : 29 +EROFS: Errno : 30 +EMLINK: Errno : 31 +EPIPE: Errno : 32 +EDOM: Errno : 33 +ERANGE: Errno : 34 /* Result too large */ +EAGAIN: Errno : 35 +EINPROGRESS: Errno : 36 +EALREADY: Errno : 37 +ENOTSOCK: Errno : 38 +EDESTADDRREQ: Errno : 39 +EMSGSIZE: Errno : 40 +EPROTOTYPE: Errno : 41 +ENOPROTOOPT: Errno : 42 +EPROTONOSUPPORT: Errno : 43 +ESOCKTNOSUPPORT: Errno : 44 +EOPNOTSUPP: Errno : 45 +EPFNOSUPPORT: Errno : 46 +EAFNOSUPPORT: Errno : 47 +EADDRINUSE: Errno : 48 +EADDRNOTAVAIL: Errno : 49 +ENETDOWN: Errno : 50 +ENETUNREACH: Errno : 51 +ENETRESET: Errno : 52 +ECONNABORTED: Errno : 53 +ECONNRESET: Errno : 54 +ENOBUFS: Errno : 55 +EISCONN: Errno : 56 +ENOTCONN: Errno : 57 +ESHUTDOWN: Errno : 58 +ETIMEDOUT: Errno : 60 +ECONNREFUSED: Errno : 61 +ELOOP: Errno : 62 +ENAMETOOLING: Errno : 63 +EHOSTDOWN: Errno : 64 +EHOSTUNREACH: Errno : 65 +ENOTEMPTY: Errno : 66 +EPROCLIM: Errno : 67 +EUSERS: Errno : 68 +EDQUOT: Errno : 69 +ESTALE: Errno : 70 +EBADRPC: Errno : 72 +ERPCMISMATCH: Errno : 73 +EPROGUNAVAIL: Errno : 74 +EPROGMISMATCH: Errno : 75 +EPROCUNAVAIL: Errno : 76 +ENOLCK: Errno : 77 +ENOSYS: Errno : 78 +EFTYPE: Errno : 79 +EAUTH: Errno : 80 +ENEEDAUTH: Errno : 81 +EIDRM: Errno : 82 +ENOMSG: Errno : 83 +EOVERFLOW: Errno : 84 +ECANCELED: Errno : 85 +EILSEQ: Errno : 86 +ENOATTR: Errno : 87 +EDOOFUS: Errno : 88 +EBADMSG: Errno : 89 +EMULTIHOP: Errno : 90 +ENOLINK: Errno : 91 +EPROTO: Errno : 92 +ENOTCAPABLE: Errno : 93 +ECAPMODE: Errno : 94 +ENOTRECOVERABLE: Errno : 95 +EOWNERDEAD: Errno : 96 -O_RDONLY :: 0x00000; -O_WRONLY :: 0x00001; -O_RDWR :: 0x00002; -O_CREATE :: 0x00040; -O_EXCL :: 0x00080; -O_NOCTTY :: 0x00100; -O_TRUNC :: 0x00200; -O_NONBLOCK :: 0x00800; -O_APPEND :: 0x00400; -O_SYNC :: 0x01000; -O_ASYNC :: 0x02000; -O_CLOEXEC :: 0x80000; +O_RDONLY :: 0x00000 +O_WRONLY :: 0x00001 +O_RDWR :: 0x00002 +O_CREATE :: 0x00040 +O_EXCL :: 0x00080 +O_NOCTTY :: 0x00100 +O_TRUNC :: 0x00200 +O_NONBLOCK :: 0x00800 +O_APPEND :: 0x00400 +O_SYNC :: 0x01000 +O_ASYNC :: 0x02000 +O_CLOEXEC :: 0x80000 -SEEK_SET :: 0; -SEEK_CUR :: 1; -SEEK_END :: 2; -SEEK_DATA :: 3; -SEEK_HOLE :: 4; -SEEK_MAX :: SEEK_HOLE; +SEEK_SET :: 0 +SEEK_CUR :: 1 +SEEK_END :: 2 +SEEK_DATA :: 3 +SEEK_HOLE :: 4 +SEEK_MAX :: SEEK_HOLE // NOTE: These are OS specific! // Do not mix these up! -RTLD_LAZY :: 0x001; -RTLD_NOW :: 0x002; -//RTLD_BINDING_MASK :: 0x3; // Called MODEMASK in dlfcn.h -RTLD_GLOBAL :: 0x100; -RTLD_LOCAL :: 0x000; -RTLD_TRACE :: 0x200; -RTLD_NODELETE :: 0x01000; -RTLD_NOLOAD :: 0x02000; +RTLD_LAZY :: 0x001 +RTLD_NOW :: 0x002 +//RTLD_BINDING_MASK :: 0x3 // Called MODEMASK in dlfcn.h +RTLD_GLOBAL :: 0x100 +RTLD_LOCAL :: 0x000 +RTLD_TRACE :: 0x200 +RTLD_NODELETE :: 0x01000 +RTLD_NOLOAD :: 0x02000 -args := _alloc_command_line_arguments(); +args := _alloc_command_line_arguments() Unix_File_Time :: struct { seconds: i64, nanoseconds: c.long, } -pid_t :: u32; +pid_t :: u32 OS_Stat :: struct { device_id: u64, @@ -177,290 +177,290 @@ OS_Stat :: struct { } // File type -S_IFMT :: 0o170000; // Type of file mask -S_IFIFO :: 0o010000; // Named pipe (fifo) -S_IFCHR :: 0o020000; // Character special -S_IFDIR :: 0o040000; // Directory -S_IFBLK :: 0o060000; // Block special -S_IFREG :: 0o100000; // Regular -S_IFLNK :: 0o120000; // Symbolic link -S_IFSOCK :: 0o140000; // Socket -//S_ISVTX :: 0o001000; // Save swapped text even after use +S_IFMT :: 0o170000 // Type of file mask +S_IFIFO :: 0o010000 // Named pipe (fifo) +S_IFCHR :: 0o020000 // Character special +S_IFDIR :: 0o040000 // Directory +S_IFBLK :: 0o060000 // Block special +S_IFREG :: 0o100000 // Regular +S_IFLNK :: 0o120000 // Symbolic link +S_IFSOCK :: 0o140000 // Socket +//S_ISVTX :: 0o001000 // Save swapped text even after use // File mode // Read, write, execute/search by owner -S_IRWXU :: 0o0700; // RWX mask for owner -S_IRUSR :: 0o0400; // R for owner -S_IWUSR :: 0o0200; // W for owner -S_IXUSR :: 0o0100; // X for owner +S_IRWXU :: 0o0700 // RWX mask for owner +S_IRUSR :: 0o0400 // R for owner +S_IWUSR :: 0o0200 // W for owner +S_IXUSR :: 0o0100 // X for owner // Read, write, execute/search by group -S_IRWXG :: 0o0070; // RWX mask for group -S_IRGRP :: 0o0040; // R for group -S_IWGRP :: 0o0020; // W for group -S_IXGRP :: 0o0010; // X for group +S_IRWXG :: 0o0070 // RWX mask for group +S_IRGRP :: 0o0040 // R for group +S_IWGRP :: 0o0020 // W for group +S_IXGRP :: 0o0010 // X for group // Read, write, execute/search by others -S_IRWXO :: 0o0007; // RWX mask for other -S_IROTH :: 0o0004; // R for other -S_IWOTH :: 0o0002; // W for other -S_IXOTH :: 0o0001; // X for other +S_IRWXO :: 0o0007 // RWX mask for other +S_IROTH :: 0o0004 // R for other +S_IWOTH :: 0o0002 // W for other +S_IXOTH :: 0o0001 // X for other -S_ISUID :: 0o4000; // Set user id on execution -S_ISGID :: 0o2000; // Set group id on execution -S_ISVTX :: 0o1000; // Directory restrcted delete +S_ISUID :: 0o4000 // Set user id on execution +S_ISGID :: 0o2000 // Set group id on execution +S_ISVTX :: 0o1000 // Directory restrcted delete -S_ISLNK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK; -S_ISREG :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG; -S_ISDIR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR; -S_ISCHR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR; -S_ISBLK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK; -S_ISFIFO :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO; -S_ISSOCK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK; +S_ISLNK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK +S_ISREG :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG +S_ISDIR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR +S_ISCHR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR +S_ISBLK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK +S_ISFIFO :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO +S_ISSOCK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK -F_OK :: 0; // Test for file existance -X_OK :: 1; // Test for execute permission -W_OK :: 2; // Test for write permission -R_OK :: 4; // Test for read permission +F_OK :: 0 // Test for file existance +X_OK :: 1 // Test for execute permission +W_OK :: 2 // Test for write permission +R_OK :: 4 // Test for read permission foreign libc { - @(link_name="__error") __errno_location :: proc() -> ^int ---; - @(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int ---; + @(link_name="__error") __errno_location :: proc() -> ^int --- + @(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int --- - @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---; - @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---; - @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---; - @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---; - @(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---; - @(link_name="gettid") _unix_gettid :: proc() -> u64 ---; - @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---; - @(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---; - @(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---; - @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---; + @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- + @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- + @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- + @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- + @(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 --- + @(link_name="gettid") _unix_gettid :: proc() -> u64 --- + @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- + @(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int --- + @(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int --- + @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int --- - @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---; - @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---; - @(link_name="free") _unix_free :: proc(ptr: rawptr) ---; - @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---; - @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---; - @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---; - @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---; + @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr --- + @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr --- + @(link_name="free") _unix_free :: proc(ptr: rawptr) --- + @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- + @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- + @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- + @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- - @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---; + @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } foreign dl { - @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---; - @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---; - @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---; - @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---; + @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr --- + @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr --- + @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int --- + @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- - @(link_name="pthread_getthreadid_np") pthread_getthreadid_np :: proc() -> c.int ---; + @(link_name="pthread_getthreadid_np") pthread_getthreadid_np :: proc() -> c.int --- } is_path_separator :: proc(r: rune) -> bool { - return r == '/'; + return r == '/' } get_last_error :: proc() -> int { - return __errno_location()^; + return __errno_location()^ } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - cstr := strings.clone_to_cstring(path, context.temp_allocator); - handle := _unix_open(cstr, c.int(flags), c.int(mode)); + cstr := strings.clone_to_cstring(path, context.temp_allocator) + handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { - return INVALID_HANDLE, Errno(get_last_error()); + return INVALID_HANDLE, Errno(get_last_error()) } - return handle, ERROR_NONE; + return handle, ERROR_NONE } close :: proc(fd: Handle) -> Errno { - result := _unix_close(fd); + result := _unix_close(fd) if result == -1 { - return Errno(get_last_error()); + return Errno(get_last_error()) } - return ERROR_NONE; + return ERROR_NONE } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - bytes_read := _unix_read(fd, &data[0], c.size_t(len(data))); + bytes_read := _unix_read(fd, &data[0], c.size_t(len(data))) if bytes_read == -1 { - return -1, Errno(get_last_error()); + return -1, Errno(get_last_error()) } - return int(bytes_read), ERROR_NONE; + return int(bytes_read), ERROR_NONE } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { - return 0, ERROR_NONE; + return 0, ERROR_NONE } - bytes_written := _unix_write(fd, &data[0], c.size_t(len(data))); + bytes_written := _unix_write(fd, &data[0], c.size_t(len(data))) if bytes_written == -1 { - return -1, Errno(get_last_error()); + return -1, Errno(get_last_error()) } - return int(bytes_written), ERROR_NONE; + return int(bytes_written), ERROR_NONE } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - res := _unix_seek(fd, offset, c.int(whence)); + res := _unix_seek(fd, offset, c.int(whence)) if res == -1 { - return -1, Errno(get_last_error()); + return -1, Errno(get_last_error()) } - return res, ERROR_NONE; + return res, ERROR_NONE } file_size :: proc(fd: Handle) -> (i64, Errno) { - s, err := fstat(fd); + s, err := fstat(fd) if err != ERROR_NONE { - return -1, err; + return -1, err } - return s.size, ERROR_NONE; + return s.size, ERROR_NONE } -stdin: Handle = 0; -stdout: Handle = 1; -stderr: Handle = 2; +stdin: Handle = 0 +stdout: Handle = 1 +stderr: Handle = 2 last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { - s, err := fstat(fd); + s, err := fstat(fd) if err != ERROR_NONE { - return 0, err; + return 0, err } - modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds; - return File_Time(modified), ERROR_NONE; + modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds + return File_Time(modified), ERROR_NONE } last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { - s, err := stat(name); + s, err := stat(name) if err != ERROR_NONE { - return 0, err; + return 0, err } - modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds; - return File_Time(modified), ERROR_NONE; + modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds + return File_Time(modified), ERROR_NONE } stat :: proc(path: string) -> (OS_Stat, Errno) { - cstr := strings.clone_to_cstring(path, context.temp_allocator); - s: OS_Stat; - result := _unix_stat(cstr, &s); + cstr := strings.clone_to_cstring(path, context.temp_allocator) + s: OS_Stat + result := _unix_stat(cstr, &s) if result == -1 { - return s, Errno(get_last_error()); + return s, Errno(get_last_error()) } - return s, ERROR_NONE; + return s, ERROR_NONE } fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { - s: OS_Stat; - result := _unix_fstat(fd, &s); + s: OS_Stat + result := _unix_fstat(fd, &s) if result == -1 { - return s, Errno(get_last_error()); + return s, Errno(get_last_error()) } - return s, ERROR_NONE; + return s, ERROR_NONE } access :: proc(path: string, mask: int) -> (bool, Errno) { - cstr := strings.clone_to_cstring(path, context.temp_allocator); - result := _unix_access(cstr, c.int(mask)); + cstr := strings.clone_to_cstring(path, context.temp_allocator) + result := _unix_access(cstr, c.int(mask)) if result == -1 { - return false, Errno(get_last_error()); + return false, Errno(get_last_error()) } - return true, ERROR_NONE; + return true, ERROR_NONE } heap_alloc :: proc(size: int) -> rawptr { - assert(size >= 0); - return _unix_calloc(1, c.size_t(size)); + assert(size >= 0) + return _unix_calloc(1, c.size_t(size)) } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on // POSIX platforms. Ensure your caller takes this into account. - return _unix_realloc(ptr, c.size_t(new_size)); + return _unix_realloc(ptr, c.size_t(new_size)) } heap_free :: proc(ptr: rawptr) { - _unix_free(ptr); + _unix_free(ptr) } getenv :: proc(name: string) -> (string, bool) { - path_str := strings.clone_to_cstring(name, context.temp_allocator); - cstr := _unix_getenv(path_str); + path_str := strings.clone_to_cstring(name, context.temp_allocator) + cstr := _unix_getenv(path_str) if cstr == nil { - return "", false; + return "", false } - return string(cstr), true; + return string(cstr), true } get_current_directory :: proc() -> string { // NOTE(tetra): I would use PATH_MAX here, but I was not able to find // an authoritative value for it across all systems. // The largest value I could find was 4096, so might as well use the page size. - page_size := get_page_size(); - buf := make([dynamic]u8, page_size); + page_size := get_page_size() + buf := make([dynamic]u8, page_size) #no_bounds_check for { - cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf))); + cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf))) if cwd != nil { - return string(cwd); + return string(cwd) } if Errno(get_last_error()) != ERANGE { - return ""; + return "" } - resize(&buf, len(buf)+page_size); + resize(&buf, len(buf)+page_size) } - unreachable(); + unreachable() } set_current_directory :: proc(path: string) -> (err: Errno) { - cstr := strings.clone_to_cstring(path, context.temp_allocator); - res := _unix_chdir(cstr); - if res == -1 do return Errno(get_last_error()); - return ERROR_NONE; + cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_chdir(cstr) + if res == -1 do return Errno(get_last_error()) + return ERROR_NONE } exit :: proc "contextless" (code: int) -> ! { - _unix_exit(c.int(code)); + _unix_exit(c.int(code)) } current_thread_id :: proc "contextless" () -> int { - return cast(int) pthread_getthreadid_np(); + return cast(int) pthread_getthreadid_np() } dlopen :: proc(filename: string, flags: int) -> rawptr { - cstr := strings.clone_to_cstring(filename, context.temp_allocator); - handle := _unix_dlopen(cstr, c.int(flags)); - return handle; + cstr := strings.clone_to_cstring(filename, context.temp_allocator) + handle := _unix_dlopen(cstr, c.int(flags)) + return handle } dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { - assert(handle != nil); - cstr := strings.clone_to_cstring(symbol, context.temp_allocator); - proc_handle := _unix_dlsym(handle, cstr); - return proc_handle; + assert(handle != nil) + cstr := strings.clone_to_cstring(symbol, context.temp_allocator) + proc_handle := _unix_dlsym(handle, cstr) + return proc_handle } dlclose :: proc(handle: rawptr) -> bool { - assert(handle != nil); - return _unix_dlclose(handle) == 0; + assert(handle != nil) + return _unix_dlclose(handle) == 0 } dlerror :: proc() -> string { - return string(_unix_dlerror()); + return string(_unix_dlerror()) } get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. - @static page_size := -1; - if page_size != -1 do return page_size; + @static page_size := -1 + if page_size != -1 do return page_size - page_size = int(_unix_getpagesize()); - return page_size; + page_size = int(_unix_getpagesize()) + return page_size } _alloc_command_line_arguments :: proc() -> []string { - res := make([]string, len(runtime.args__)); + res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { - res[i] = string(arg); + res[i] = string(arg) } - return res; + return res } From 5676c9e7ebcec9af526c59ece1faf2e8b15e457c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Fri, 25 Feb 2022 08:49:25 +0000 Subject: [PATCH 0262/1052] initial OpenBSD support --- Makefile | 6 + core/c/libc/errno.odin | 13 + core/c/libc/stdio.odin | 25 + core/c/libc/time.odin | 9 +- core/c/libc/wctype.odin | 5 + core/crypto/rand_generic.odin | 2 +- core/crypto/rand_openbsd.odin | 12 + core/dynlib/lib_unix.odin | 2 +- core/os/dir_openbsd.odin | 71 +++ core/os/os_openbsd.odin | 706 +++++++++++++++++++++++ core/os/stat_unix.odin | 2 +- core/path/filepath/path_unix.odin | 7 +- core/runtime/entry_unix.odin | 2 +- core/sync/channel_unix.odin | 2 +- core/sync/sync2/futex_openbsd.odin | 78 +++ core/sync/sync2/primitives_openbsd.odin | 9 + core/sync/sync2/primitives_pthreads.odin | 2 +- core/sync/sync_openbsd.odin | 36 ++ core/sync/sync_unix.odin | 2 +- core/sys/unix/pthread_openbsd.odin | 65 +++ core/sys/unix/pthread_unix.odin | 2 +- core/thread/thread_unix.odin | 2 +- core/time/time_unix.odin | 34 +- src/bug_report.cpp | 14 +- src/build_settings.cpp | 18 + src/check_builtin.cpp | 1 + src/checker.cpp | 1 + src/common.cpp | 2 +- src/gb/gb.h | 46 +- src/threading.cpp | 2 +- 30 files changed, 1151 insertions(+), 27 deletions(-) create mode 100644 core/crypto/rand_openbsd.odin create mode 100644 core/os/dir_openbsd.odin create mode 100644 core/os/os_openbsd.odin create mode 100644 core/sync/sync2/futex_openbsd.odin create mode 100644 core/sync/sync2/primitives_openbsd.odin create mode 100644 core/sync/sync_openbsd.odin create mode 100644 core/sys/unix/pthread_openbsd.odin diff --git a/Makefile b/Makefile index d3d3c6a2d..99c71ccd9 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,12 @@ ifeq ($(OS), Linux) CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) endif +ifeq ($(OS), OpenBSD) + LLVM_CONFIG=/usr/local/bin/llvm-config + + CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) + LDFLAGS:=$(LDFLAGS) -liconv $(shell $(LLVM_CONFIG) --libs core native --system-libs) +endif all: debug demo diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin index ecde6af59..53437f42f 100644 --- a/core/c/libc/errno.odin +++ b/core/c/libc/errno.odin @@ -27,6 +27,19 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD { ERANGE :: 34 } +when ODIN_OS == .OpenBSD { + @(private="file") + @(default_calling_convention="c") + foreign libc { + @(link_name="__errno") + _get_errno :: proc() -> ^int --- + } + + EDOM :: 33 + EILSEQ :: 84 + ERANGE :: 34 +} + when ODIN_OS == .Windows { @(private="file") @(default_calling_convention="c") diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index 9c4a1a708..fc65b954a 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -78,6 +78,31 @@ when ODIN_OS == .Linux { } } +when ODIN_OS == .OpenBSD { + fpos_t :: i64 + + _IOFBF :: 0 + _IOLBF :: 1 + _IONBF :: 1 + + BUFSIZ :: 1024 + + EOF :: int(-1) + + FOPEN_MAX :: 20 + FILENAME_MAX :: 1024 + + SEEK_SET :: 0 + SEEK_CUR :: 1 + SEEK_END :: 2 + + foreign libc { + stderr: ^FILE + stdin: ^FILE + stdout: ^FILE + } +} + when ODIN_OS == .Darwin { fpos_t :: distinct i64 diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin index b3539a227..b337e139a 100644 --- a/core/c/libc/time.odin +++ b/core/c/libc/time.odin @@ -45,7 +45,7 @@ when ODIN_OS == .Windows { } } -when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin { +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD { @(default_calling_convention="c") foreign libc { // 7.27.2 Time manipulation functions @@ -63,7 +63,12 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin { strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t --- } - CLOCKS_PER_SEC :: 1000000 + when ODIN_OS == .OpenBSD { + CLOCKS_PER_SEC :: 100 + } else { + CLOCKS_PER_SEC :: 1000000 + } + TIME_UTC :: 1 time_t :: distinct i64 diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin index 942726ba6..f833af51f 100644 --- a/core/c/libc/wctype.odin +++ b/core/c/libc/wctype.odin @@ -25,6 +25,11 @@ when ODIN_OS == .Darwin { wctype_t :: distinct u32 } +when ODIN_OS == .OpenBSD { + wctrans_t :: distinct rawptr + wctype_t :: distinct rawptr +} + @(default_calling_convention="c") foreign libc { // 7.30.2.1 Wide character classification functions diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin index be6987ee2..10edc1c8a 100644 --- a/core/crypto/rand_generic.odin +++ b/core/crypto/rand_generic.odin @@ -1,6 +1,6 @@ package crypto -when ODIN_OS != .Linux { +when ODIN_OS != .Linux && ODIN_OS != .OpenBSD { _rand_bytes :: proc (dst: []byte) { unimplemented("crypto: rand_bytes not supported on this OS") } diff --git a/core/crypto/rand_openbsd.odin b/core/crypto/rand_openbsd.odin new file mode 100644 index 000000000..bae97e8f0 --- /dev/null +++ b/core/crypto/rand_openbsd.odin @@ -0,0 +1,12 @@ +package crypto + +import "core:c" + +foreign import libc "system:c" +foreign libc { + arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) --- +} + +_rand_bytes :: proc (dst: []byte) { + arc4random_buf(raw_data(dst), len(dst)) +} diff --git a/core/dynlib/lib_unix.odin b/core/dynlib/lib_unix.odin index bb8affb79..e52ade153 100644 --- a/core/dynlib/lib_unix.odin +++ b/core/dynlib/lib_unix.odin @@ -1,4 +1,4 @@ -// +build linux, darwin, freebsd +// +build linux, darwin, freebsd, openbsd package dynlib import "core:os" diff --git a/core/os/dir_openbsd.odin b/core/os/dir_openbsd.odin new file mode 100644 index 000000000..465fd35ae --- /dev/null +++ b/core/os/dir_openbsd.odin @@ -0,0 +1,71 @@ +package os + +import "core:strings" +import "core:mem" + +read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { + dirp: Dir + dirp, err = _fdopendir(fd) + if err != ERROR_NONE { + return + } + + defer _closedir(dirp) + + // XXX OpenBSD + dirpath: string + dirpath, err = absolute_path_from_handle(fd) + + if err != ERROR_NONE { + return + } + + defer delete(dirpath) + + n := n + size := n + if n <= 0 { + n = -1 + size = 100 + } + + dfi := make([dynamic]File_Info, 0, size, allocator) + + for { + entry: Dirent + end_of_stream: bool + entry, err, end_of_stream = _readdir(dirp) + if err != ERROR_NONE { + for fi_ in dfi { + file_info_delete(fi_, allocator) + } + delete(dfi) + return + } else if end_of_stream { + break + } + + fi_: File_Info + filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) + + if filename == "." || filename == ".." { + continue + } + + fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) + defer delete(fullpath, context.temp_allocator) + + fi_, err = stat(fullpath, allocator) + if err != ERROR_NONE { + for fi__ in dfi { + file_info_delete(fi__, allocator) + } + delete(dfi) + return + } + + append(&dfi, fi_) + } + + return dfi[:], ERROR_NONE +} diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin new file mode 100644 index 000000000..3862851a1 --- /dev/null +++ b/core/os/os_openbsd.odin @@ -0,0 +1,706 @@ +package os + +foreign import libc "system:c" + +import "core:runtime" +import "core:strings" +import "core:c" + +Handle :: distinct i32 +Pid :: distinct i32 +File_Time :: distinct u64 +Errno :: distinct i32 + +INVALID_HANDLE :: ~Handle(0) + +ERROR_NONE: Errno: 0 + +EPERM: Errno: 1 +ENOENT: Errno: 2 +ESRCH: Errno: 3 +EINTR: Errno: 4 +EIO: Errno: 5 +ENXIO: Errno: 6 +E2BIG: Errno: 7 +ENOEXEC: Errno: 8 +EBADF: Errno: 9 +ECHILD: Errno: 10 +EDEADLK: Errno: 11 +ENOMEM: Errno: 12 +EACCES: Errno: 13 +EFAULT: Errno: 14 +ENOTBLK: Errno: 15 +EBUSY: Errno: 16 +EEXIST: Errno: 17 +EXDEV: Errno: 18 +ENODEV: Errno: 19 +ENOTDIR: Errno: 20 +EISDIR: Errno: 21 +EINVAL: Errno: 22 +ENFILE: Errno: 23 +EMFILE: Errno: 24 +ENOTTY: Errno: 25 +ETXTBSY: Errno: 26 +EFBIG: Errno: 27 +ENOSPC: Errno: 28 +ESPIPE: Errno: 29 +EROFS: Errno: 30 +EMLINK: Errno: 31 +EPIPE: Errno: 32 +EDOM: Errno: 33 +ERANGE: Errno: 34 +EAGAIN: Errno: 35 +EWOULDBLOCK: Errno: EAGAIN +EINPROGRESS: Errno: 36 +EALREADY: Errno: 37 +ENOTSOCK: Errno: 38 +EDESTADDRREQ: Errno: 39 +EMSGSIZE: Errno: 40 +EPROTOTYPE: Errno: 41 +ENOPROTOOPT: Errno: 42 +EPROTONOSUPPORT: Errno: 43 +ESOCKTNOSUPPORT: Errno: 44 +EOPNOTSUPP: Errno: 45 +EPFNOSUPPORT: Errno: 46 +EAFNOSUPPORT: Errno: 47 +EADDRINUSE: Errno: 48 +EADDRNOTAVAIL: Errno: 49 +ENETDOWN: Errno: 50 +ENETUNREACH: Errno: 51 +ENETRESET: Errno: 52 +ECONNABORTED: Errno: 53 +ECONNRESET: Errno: 54 +ENOBUFS: Errno: 55 +EISCONN: Errno: 56 +ENOTCONN: Errno: 57 +ESHUTDOWN: Errno: 58 +ETOOMANYREFS: Errno: 59 +ETIMEDOUT: Errno: 60 +ECONNREFUSED: Errno: 61 +ELOOP: Errno: 62 +ENAMETOOLONG: Errno: 63 +EHOSTDOWN: Errno: 64 +EHOSTUNREACH: Errno: 65 +ENOTEMPTY: Errno: 66 +EPROCLIM: Errno: 67 +EUSERS: Errno: 68 +EDQUOT: Errno: 69 +ESTALE: Errno: 70 +EREMOTE: Errno: 71 +EBADRPC: Errno: 72 +ERPCMISMATCH: Errno: 73 +EPROGUNAVAIL: Errno: 74 +EPROGMISMATCH: Errno: 75 +EPROCUNAVAIL: Errno: 76 +ENOLCK: Errno: 77 +ENOSYS: Errno: 78 +EFTYPE: Errno: 79 +EAUTH: Errno: 80 +ENEEDAUTH: Errno: 81 +EIPSEC: Errno: 82 +ENOATTR: Errno: 83 +EILSEQ: Errno: 84 +ENOMEDIUM: Errno: 85 +EMEDIUMTYPE: Errno: 86 +EOVERFLOW: Errno: 87 +ECANCELED: Errno: 88 +EIDRM: Errno: 89 +ENOMSG: Errno: 90 +ENOTSUP: Errno: 91 +EBADMSG: Errno: 92 +ENOTRECOVERABLE: Errno: 93 +EOWNERDEAD: Errno: 94 +EPROTO: Errno: 95 + +O_RDONLY :: 0x00000 +O_WRONLY :: 0x00001 +O_RDWR :: 0x00002 +O_NONBLOCK :: 0x00004 +O_APPEND :: 0x00008 +O_ASYNC :: 0x00040 +O_SYNC :: 0x00080 +O_CREATE :: 0x00200 +O_TRUNC :: 0x00400 +O_EXCL :: 0x00800 +O_NOCTTY :: 0x08000 +O_CLOEXEC :: 0x10000 + +SEEK_SET :: 0 +SEEK_CUR :: 1 +SEEK_END :: 2 + +RTLD_LAZY :: 0x001 +RTLD_NOW :: 0x002 +RTLD_LOCAL :: 0x000 +RTLD_GLOBAL :: 0x100 +RTLD_TRACE :: 0x200 +RTLD_NODELETE :: 0x400 + +MAX_PATH :: 1024 + +// "Argv" arguments converted to Odin strings +args := _alloc_command_line_arguments() + +pid_t :: i32 +time_t :: i64 +mode_t :: u32 +dev_t :: i32 +ino_t :: u64 +nlink_t :: u32 +uid_t :: u32 +gid_t :: u32 +off_t :: i64 +blkcnt_t :: u64 +blksize_t :: i32 + +Unix_File_Time :: struct { + seconds: time_t, + nanoseconds: c.long, +} + +OS_Stat :: struct { + mode: mode_t, // inode protection mode + device_id: dev_t, // inode's device + serial: ino_t, // inode's number + nlink: nlink_t, // number of hard links + uid: uid_t, // user ID of the file's owner + gid: gid_t, // group ID of the file's group + rdev: dev_t, // device type + + last_access: Unix_File_Time, // time of last access + modified: Unix_File_Time, // time of last data modification + status_change: Unix_File_Time, // time of last file status change + + size: off_t, // file size, in bytes + blocks: blkcnt_t, // blocks allocated for file + block_size: blksize_t, // optimal blocksize for I/O + + flags: u32, // user defined flags for file + gen: u32, // file generation number + birthtime: Unix_File_Time, // time of file creation +} + +MAXNAMLEN :: 255 + +// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above +Dirent :: struct { + ino: ino_t, // file number of entry + off: off_t, // offset after this entry + reclen: u16, // length of this record + type: u8, // file type + namlen: u8, // length of string in name + _padding: [4]u8, + name: [MAXNAMLEN + 1]byte, // name +} + +Dir :: distinct rawptr // DIR* + +// File type +S_IFMT :: 0o170000 // Type of file mask +S_IFIFO :: 0o010000 // Named pipe (fifo) +S_IFCHR :: 0o020000 // Character special +S_IFDIR :: 0o040000 // Directory +S_IFBLK :: 0o060000 // Block special +S_IFREG :: 0o100000 // Regular +S_IFLNK :: 0o120000 // Symbolic link +S_IFSOCK :: 0o140000 // Socket +S_ISVTX :: 0o001000 // Save swapped text even after use + +// File mode + // Read, write, execute/search by owner +S_IRWXU :: 0o0700 // RWX mask for owner +S_IRUSR :: 0o0400 // R for owner +S_IWUSR :: 0o0200 // W for owner +S_IXUSR :: 0o0100 // X for owner + + // Read, write, execute/search by group +S_IRWXG :: 0o0070 // RWX mask for group +S_IRGRP :: 0o0040 // R for group +S_IWGRP :: 0o0020 // W for group +S_IXGRP :: 0o0010 // X for group + + // Read, write, execute/search by others +S_IRWXO :: 0o0007 // RWX mask for other +S_IROTH :: 0o0004 // R for other +S_IWOTH :: 0o0002 // W for other +S_IXOTH :: 0o0001 // X for other + +S_ISUID :: 0o4000 // Set user id on execution +S_ISGID :: 0o2000 // Set group id on execution +S_ISTXT :: 0o1000 // Sticky bit + +S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } +S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } +S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } +S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } +S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } +S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } +S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } + +F_OK :: 0x00 // Test for file existance +X_OK :: 0x01 // Test for execute permission +W_OK :: 0x02 // Test for write permission +R_OK :: 0x04 // Test for read permission + +AT_FDCWD :: -100 +AT_EACCESS :: 0x01 +AT_SYMLINK_NOFOLLOW :: 0x02 +AT_SYMLINK_FOLLOW :: 0x04 +AT_REMOVEDIR :: 0x08 + +@(default_calling_convention="c") +foreign libc { + @(link_name="__errno") __errno :: proc() -> ^int --- + + @(link_name="fork") _unix_fork :: proc() -> pid_t --- + @(link_name="getthrid") _unix_getthrid :: proc() -> int --- + + @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- + @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- + @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- + @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- + @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t --- + @(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int --- + @(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int --- + @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int --- + @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t --- + @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int --- + @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- + @(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int --- + @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int --- + @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int --- + @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int --- + @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int --- + + @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- + @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- + @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- + @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- + @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- + + @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr --- + @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr --- + @(link_name="free") _unix_free :: proc(ptr: rawptr) --- + @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- + + @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + + @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- + + @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr --- + @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr --- + @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int --- + @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- +} + +is_path_separator :: proc(r: rune) -> bool { + return r == '/' +} + +get_last_error :: proc() -> int { + return __errno()^ +} + +fork :: proc() -> (Pid, Errno) { + pid := _unix_fork() + if pid == -1 { + return Pid(-1), Errno(get_last_error()) + } + return Pid(pid), ERROR_NONE +} + +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + handle := _unix_open(cstr, c.int(flags), c.int(mode)) + if handle == -1 { + return INVALID_HANDLE, Errno(get_last_error()) + } + return handle, ERROR_NONE +} + +close :: proc(fd: Handle) -> Errno { + result := _unix_close(fd) + if result == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +read :: proc(fd: Handle, data: []byte) -> (int, Errno) { + bytes_read := _unix_read(fd, &data[0], c.size_t(len(data))) + if bytes_read == -1 { + return -1, Errno(get_last_error()) + } + return int(bytes_read), ERROR_NONE +} + +write :: proc(fd: Handle, data: []byte) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + bytes_written := _unix_write(fd, &data[0], c.size_t(len(data))) + if bytes_written == -1 { + return -1, Errno(get_last_error()) + } + return int(bytes_written), ERROR_NONE +} + +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { + res := _unix_seek(fd, offset, c.int(whence)) + if res == -1 { + return -1, Errno(get_last_error()) + } + return res, ERROR_NONE +} + +file_size :: proc(fd: Handle) -> (i64, Errno) { + s, err := _fstat(fd) + if err != ERROR_NONE { + return -1, err + } + return s.size, ERROR_NONE +} + +rename :: proc(old_path, new_path: string) -> Errno { + old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) + new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) + res := _unix_rename(old_path_cstr, new_path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +remove :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_unlink(path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_mkdir(path_cstr, mode) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +remove_directory :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_rmdir(path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +is_file_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + +is_file_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + +is_dir_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_file :: proc {is_file_path, is_file_handle} +is_dir :: proc {is_dir_path, is_dir_handle} + +// NOTE(bill): Uses startup to initialize it + +stdin: Handle = 0 +stdout: Handle = 1 +stderr: Handle = 2 + +/* TODO(zangent): Implement these! +last_write_time :: proc(fd: Handle) -> File_Time {} +last_write_time_by_name :: proc(name: string) -> File_Time {} +*/ +last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { + s, err := _fstat(fd) + if err != ERROR_NONE { + return 0, err + } + modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds + return File_Time(modified), ERROR_NONE +} + +last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { + s, err := _stat(name) + if err != ERROR_NONE { + return 0, err + } + modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds + return File_Time(modified), ERROR_NONE +} + +@private +_stat :: proc(path: string) -> (OS_Stat, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + + // deliberately uninitialized + s: OS_Stat = --- + res := _unix_stat(cstr, &s) + if res == -1 { + return s, Errno(get_last_error()) + } + return s, ERROR_NONE +} + +@private +_lstat :: proc(path: string) -> (OS_Stat, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + + // deliberately uninitialized + s: OS_Stat = --- + res := _unix_lstat(cstr, &s) + if res == -1 { + return s, Errno(get_last_error()) + } + return s, ERROR_NONE +} + +@private +_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { + // deliberately uninitialized + s: OS_Stat = --- + res := _unix_fstat(fd, &s) + if res == -1 { + return s, Errno(get_last_error()) + } + return s, ERROR_NONE +} + +@private +_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { + dirp := _unix_fdopendir(fd) + if dirp == cast(Dir)nil { + return nil, Errno(get_last_error()) + } + return dirp, ERROR_NONE +} + +@private +_closedir :: proc(dirp: Dir) -> Errno { + rc := _unix_closedir(dirp) + if rc != 0 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +@private +_rewinddir :: proc(dirp: Dir) { + _unix_rewinddir(dirp) +} + +@private +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { + result: ^Dirent + rc := _unix_readdir_r(dirp, &entry, &result) + + if rc != 0 { + err = Errno(get_last_error()) + return + } + err = ERROR_NONE + + if result == nil { + end_of_stream = true + return + } + + return +} + +@private +_readlink :: proc(path: string) -> (string, Errno) { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + + bufsz : uint = MAX_PATH + buf := make([]byte, MAX_PATH) + for { + rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) + if rc == -1 { + delete(buf) + return "", Errno(get_last_error()) + } else if rc == int(bufsz) { + bufsz += MAX_PATH + delete(buf) + buf = make([]byte, bufsz) + } else { + return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + } + } + unreachable() +} + +// XXX OpenBSD +absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { + return "", Errno(ENOSYS) +} + +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { + rel := rel + if rel == "" { + rel = "." + } + + rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) + + path_ptr := _unix_realpath(rel_cstr, nil) + if path_ptr == nil { + return "", Errno(get_last_error()) + } + defer _unix_free(path_ptr) + + path_cstr := transmute(cstring)path_ptr + path = strings.clone( string(path_cstr) ) + + return path, ERROR_NONE +} + +access :: proc(path: string, mask: int) -> (bool, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_access(cstr, c.int(mask)) + if res == -1 { + return false, Errno(get_last_error()) + } + return true, ERROR_NONE +} + +heap_alloc :: proc(size: int) -> rawptr { + assert(size >= 0) + return _unix_calloc(1, c.size_t(size)) +} + +heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. + return _unix_realloc(ptr, c.size_t(new_size)) +} + +heap_free :: proc(ptr: rawptr) { + _unix_free(ptr) +} + +getenv :: proc(name: string) -> (string, bool) { + path_str := strings.clone_to_cstring(name, context.temp_allocator) + cstr := _unix_getenv(path_str) + if cstr == nil { + return "", false + } + return string(cstr), true +} + +get_current_directory :: proc() -> string { + buf := make([dynamic]u8, MAX_PATH) + for { + cwd := _unix_getcwd(cstring(raw_data(buf)), c.size_t(len(buf))) + if cwd != nil { + return string(cwd) + } + if Errno(get_last_error()) != ERANGE { + return "" + } + resize(&buf, len(buf) + MAX_PATH) + } + unreachable() +} + +set_current_directory :: proc(path: string) -> (err: Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_chdir(cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +exit :: proc "contextless" (code: int) -> ! { + _unix_exit(c.int(code)) +} + +current_thread_id :: proc "contextless" () -> int { + return _unix_getthrid() +} + +dlopen :: proc(filename: string, flags: int) -> rawptr { + cstr := strings.clone_to_cstring(filename, context.temp_allocator) + handle := _unix_dlopen(cstr, c.int(flags)) + return handle +} +dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { + assert(handle != nil) + cstr := strings.clone_to_cstring(symbol, context.temp_allocator) + proc_handle := _unix_dlsym(handle, cstr) + return proc_handle +} +dlclose :: proc(handle: rawptr) -> bool { + assert(handle != nil) + return _unix_dlclose(handle) == 0 +} +dlerror :: proc() -> string { + return string(_unix_dlerror()) +} + +get_page_size :: proc() -> int { + // NOTE(tetra): The page size never changes, so why do anything complicated + // if we don't have to. + @static page_size := -1 + if page_size != -1 { + return page_size + } + + page_size = int(_unix_getpagesize()) + return page_size +} + + +_alloc_command_line_arguments :: proc() -> []string { + res := make([]string, len(runtime.args__)) + for arg, i in runtime.args__ { + res[i] = string(arg) + } + return res +} diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin index 08c6f53c4..2aa9fc283 100644 --- a/core/os/stat_unix.odin +++ b/core/os/stat_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package os import "core:time" diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin index 3e49c4710..d0eaa3635 100644 --- a/core/path/filepath/path_unix.odin +++ b/core/path/filepath/path_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package filepath when ODIN_OS == .Darwin { @@ -59,6 +59,11 @@ when ODIN_OS == .Darwin { foreign libc { @(link_name="__error") __error :: proc() -> ^i32 --- } +} else when ODIN_OS == .OpenBSD { + @(private) + foreign libc { + @(link_name="__errno") __error :: proc() -> ^i32 --- + } } else { @(private) foreign libc { diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index dd1e06625..1a3def200 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -1,5 +1,5 @@ //+private -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package runtime import "core:intrinsics" diff --git a/core/sync/channel_unix.odin b/core/sync/channel_unix.odin index d6bac2d71..47aa46004 100644 --- a/core/sync/channel_unix.odin +++ b/core/sync/channel_unix.odin @@ -1,4 +1,4 @@ -// +build linux, darwin, freebsd +// +build linux, darwin, freebsd, openbsd package sync import "core:time" diff --git a/core/sync/sync2/futex_openbsd.odin b/core/sync/sync2/futex_openbsd.odin new file mode 100644 index 000000000..dbc80747b --- /dev/null +++ b/core/sync/sync2/futex_openbsd.odin @@ -0,0 +1,78 @@ +//+private +//+build openbsd +package sync2 + +import "core:c" +import "core:os" +import "core:time" + +FUTEX_WAIT :: 1 +FUTEX_WAKE :: 2 + +FUTEX_PRIVATE_FLAG :: 128 + +FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) + +foreign import libc "system:c" + +foreign libc { + @(link_name="futex") + _unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int --- +} + +_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { + res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil) + + if res != -1 { + return true + } + + if os.Errno(os.get_last_error()) == os.ETIMEDOUT { + return false + } + + panic("futex_wait failure") +} + +_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { + if duration <= 0 { + return false + } + + timespec_t :: struct { + tv_sec: c.long, + tv_nsec: c.long, + } + + res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, ×pec_t{ + tv_sec = (c.long)(duration/1e9), + tv_nsec = (c.long)(duration%1e9), + }) + + if res != -1 { + return true + } + + if os.Errno(os.get_last_error()) == os.ETIMEDOUT { + return false + } + + panic("futex_wait_with_timeout failure") +} + +_futex_signal :: proc(f: ^Futex) { + res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil) + + if res == -1 { + panic("futex_wake_single failure") + } +} + +_futex_broadcast :: proc(f: ^Futex) { + res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil) + + if res == -1 { + panic("_futex_wake_all failure") + } +} diff --git a/core/sync/sync2/primitives_openbsd.odin b/core/sync/sync2/primitives_openbsd.odin new file mode 100644 index 000000000..ef122b02e --- /dev/null +++ b/core/sync/sync2/primitives_openbsd.odin @@ -0,0 +1,9 @@ +//+build openbsd +//+private +package sync2 + +import "core:os" + +_current_thread_id :: proc "contextless" () -> int { + return os.current_thread_id() +} diff --git a/core/sync/sync2/primitives_pthreads.odin b/core/sync/sync2/primitives_pthreads.odin index 8d2c3986d..28053f9cc 100644 --- a/core/sync/sync2/primitives_pthreads.odin +++ b/core/sync/sync2/primitives_pthreads.odin @@ -1,4 +1,4 @@ -//+build linux, freebsd +//+build linux, freebsd, openbsd //+private package sync2 diff --git a/core/sync/sync_openbsd.odin b/core/sync/sync_openbsd.odin new file mode 100644 index 000000000..926655f5b --- /dev/null +++ b/core/sync/sync_openbsd.odin @@ -0,0 +1,36 @@ +package sync + +import "core:sys/unix" +import "core:os" + +current_thread_id :: proc "contextless" () -> int { + return os.current_thread_id() +} + +// The Darwin docs say it best: +// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously. +// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens, +// but when there are none left, a thread must wait until another thread returns one. +Semaphore :: struct #align 16 { + handle: unix.sem_t, +} + +semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { + assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0) +} + +semaphore_destroy :: proc(s: ^Semaphore) { + assert(unix.sem_destroy(&s.handle) == 0) + s.handle = {} +} + +semaphore_post :: proc(s: ^Semaphore, count := 1) { + // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop. + for in 0.. ^sem_t --- + + sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int --- + sem_destroy :: proc(sem: ^sem_t) -> c.int --- + sem_post :: proc(sem: ^sem_t) -> c.int --- + sem_wait :: proc(sem: ^sem_t) -> c.int --- + sem_trywait :: proc(sem: ^sem_t) -> c.int --- + //sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int --- + + // NOTE: unclear whether pthread_yield is well-supported on Linux systems, + // see https://linux.die.net/man/3/pthread_yield + pthread_yield :: proc() --- +} diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin index ccd8f7844..62e3701ab 100644 --- a/core/sys/unix/pthread_unix.odin +++ b/core/sys/unix/pthread_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package unix foreign import "system:pthread" diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 6cb91df86..b6679bbc2 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -1,4 +1,4 @@ -// +build linux, darwin, freebsd +// +build linux, darwin, freebsd, openbsd // +private package thread diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin index 9c5c5cc35..37fc1fd3e 100644 --- a/core/time/time_unix.odin +++ b/core/time/time_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package time IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC. @@ -22,16 +22,28 @@ TimeSpec :: struct { tv_nsec : i64, /* nanoseconds */ } -CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time. -CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep. -CLOCK_PROCESS_CPUTIME_ID :: 2 -CLOCK_THREAD_CPUTIME_ID :: 3 -CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. -CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained." -CLOCK_MONOTONIC_COARSE :: 6 -CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep. -CLOCK_REALTIME_ALARM :: 8 -CLOCK_BOOTTIME_ALARM :: 9 +when ODIN_OS == .OpenBSD { + CLOCK_REALTIME :: 0 + CLOCK_PROCESS_CPUTIME_ID :: 2 + CLOCK_MONOTONIC :: 3 + CLOCK_THREAD_CPUTIME_ID :: 4 + CLOCK_UPTIME :: 5 + CLOCK_BOOTTIME :: 6 + + // CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC + CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC +} else { + CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time. + CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep. + CLOCK_PROCESS_CPUTIME_ID :: 2 + CLOCK_THREAD_CPUTIME_ID :: 3 + CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. + CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained." + CLOCK_MONOTONIC_COARSE :: 6 + CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep. + CLOCK_REALTIME_ALARM :: 8 + CLOCK_BOOTTIME_ALARM :: 9 +} // TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants. // I do not know if Darwin programmers are used to the existance of these constants or not, so diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 4dd251f24..7f6b668e8 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -17,6 +17,10 @@ #include #endif +#if defined(GB_SYSTEM_OPENBSD) + #include +#endif + /* NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`. */ @@ -643,6 +647,14 @@ void print_bug_report_help() { } else { gb_printf("macOS: Unknown\n"); } + #elif defined(GB_SYSTEM_OPENBSD) + struct utsname un; + + if (uname(&un) != -1) { + gb_printf("%s %s %s %s\n", un.sysname, un.release, un.version, un.machine); + } else { + gb_printf("OpenBSD: Unknown\n"); + } #else gb_printf("Unknown\n"); @@ -657,4 +669,4 @@ void print_bug_report_help() { And RAM info. */ report_ram_info(); -} \ No newline at end of file +} diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 610e4f847..72a4b35cc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -16,6 +16,7 @@ enum TargetOsKind { TargetOs_linux, TargetOs_essence, TargetOs_freebsd, + TargetOs_openbsd, TargetOs_wasi, TargetOs_js, @@ -53,6 +54,7 @@ String target_os_names[TargetOs_COUNT] = { str_lit("linux"), str_lit("essence"), str_lit("freebsd"), + str_lit("openbsd"), str_lit("wasi"), str_lit("js"), @@ -354,6 +356,15 @@ gb_global TargetMetrics target_freebsd_amd64 = { str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; +gb_global TargetMetrics target_openbsd_amd64 = { + TargetOs_openbsd, + TargetArch_amd64, + 8, + 16, + str_lit("x86_64-unknown-openbsd-elf"), + str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"), +}; + gb_global TargetMetrics target_essence_amd64 = { TargetOs_essence, TargetArch_amd64, @@ -417,6 +428,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("windows_amd64"), &target_windows_amd64 }, { str_lit("freebsd_386"), &target_freebsd_386 }, { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, + { str_lit("openbsd_amd64"), &target_openbsd_amd64 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("js_wasm32"), &target_js_wasm32 }, @@ -723,6 +735,7 @@ String internal_odin_root_dir(void) { #elif defined(GB_SYSTEM_DRAGONFLYBSD) len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count); #else + // XXX OpenBSD len = readlink("/proc/self/exe", &path_buf[0], path_buf.count); #endif if(len == 0) { @@ -922,6 +935,8 @@ void init_build_context(TargetMetrics *cross_target) { #endif #elif defined(GB_SYSTEM_FREEBSD) metrics = &target_freebsd_amd64; + #elif defined(GB_SYSTEM_OPENBSD) + metrics = &target_openbsd_amd64; #elif defined(GB_CPU_ARM) metrics = &target_linux_arm64; #else @@ -980,6 +995,9 @@ void init_build_context(TargetMetrics *cross_target) { case TargetOs_freebsd: bc->link_flags = str_lit("-arch x86-64 "); break; + case TargetOs_openbsd: + bc->link_flags = str_lit("-arch x86-64 "); + break; } } else if (bc->metrics.arch == TargetArch_i386) { switch (bc->metrics.os) { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index eb9d7f293..69cc40de8 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3506,6 +3506,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case TargetOs_linux: case TargetOs_essence: case TargetOs_freebsd: + case TargetOs_openbsd: switch (build_context.metrics.arch) { case TargetArch_i386: case TargetArch_amd64: diff --git a/src/checker.cpp b/src/checker.cpp index f440b7c9a..5a7ece263 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -906,6 +906,7 @@ void init_universal(void) { {"Linux", TargetOs_linux}, {"Essence", TargetOs_essence}, {"FreeBSD", TargetOs_freebsd}, + {"OpenBSD", TargetOs_openbsd}, {"WASI", TargetOs_wasi}, {"JS", TargetOs_js}, {"Freestanding", TargetOs_freestanding}, diff --git a/src/common.cpp b/src/common.cpp index d3ee95b76..aaacda04b 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -848,7 +848,7 @@ ReadDirectoryError read_directory(String path, Array *fi) { return ReadDirectory_None; } -#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) +#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) #include diff --git a/src/gb/gb.h b/src/gb/gb.h index a9d6378c9..293e5063a 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -79,6 +79,10 @@ extern "C" { #ifndef GB_SYSTEM_FREEBSD #define GB_SYSTEM_FREEBSD 1 #endif + #elif defined(__OpenBSD__) + #ifndef GB_SYSTEM_OPENBSD + #define GB_SYSTEM_OPENBSD 1 + #endif #else #error This UNIX operating system is not supported #endif @@ -199,7 +203,7 @@ extern "C" { #endif #include // NOTE(bill): malloc on linux #include - #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) + #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #include #endif #include @@ -235,6 +239,15 @@ extern "C" { #define sendfile(out, in, offset, count) sendfile(out, in, offset, count, NULL, NULL, 0) #endif +#if defined(GB_SYSTEM_OPENBSD) + #include + #include + #define lseek64 lseek + + // XXX OpenBSD + #define sendfile(out, in, offset, count) (-1) +#endif + #if defined(GB_SYSTEM_UNIX) #include #endif @@ -783,6 +796,13 @@ typedef struct gbAffinity { isize thread_count; isize threads_per_core; } gbAffinity; +#elif defined(GB_SYSTEM_OPENBSD) +typedef struct gbAffinity { + b32 is_accurate; + isize core_count; + isize thread_count; + isize threads_per_core; +} gbAffinity; #else #error TODO(bill): Unknown system #endif @@ -3678,6 +3698,30 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { return true; } +isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { + GB_ASSERT(0 <= core && core < a->core_count); + return a->threads_per_core; +} + +#elif defined(GB_SYSTEM_OPENBSD) +#include + +void gb_affinity_init(gbAffinity *a) { + a->core_count = sysconf(_SC_NPROCESSORS_ONLN); + a->threads_per_core = 1; + a->is_accurate = a->core_count > 0; + a->core_count = a->is_accurate ? a->core_count : 1; + a->thread_count = a->core_count; +} + +void gb_affinity_destroy(gbAffinity *a) { + gb_unused(a); +} + +b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { + return true; +} + isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { GB_ASSERT(0 <= core && core < a->core_count); return a->threads_per_core; diff --git a/src/threading.cpp b/src/threading.cpp index 50d0dfed1..63e3415b2 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -486,7 +486,7 @@ void thread_set_name(Thread *t, char const *name) { #elif defined(GB_SYSTEM_OSX) // TODO(bill): Test if this works pthread_setname_np(name); -#elif defined(GB_SYSTEM_FREEBSD) +#elif defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) pthread_set_name_np(t->posix_handle, name); #else // TODO(bill): Test if this works From 00c138ce9f75b7c4911042a32fbc34a7335f2739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Fri, 25 Feb 2022 09:28:04 +0000 Subject: [PATCH 0263/1052] add RAM information inside report --- src/bug_report.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 7f6b668e8..02a2b1ba2 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -18,6 +18,7 @@ #endif #if defined(GB_SYSTEM_OPENBSD) + #include #include #endif @@ -246,6 +247,14 @@ void report_ram_info() { if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) { gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1)); } + #elif defined(GB_SYSTEM_OPENBSD) + uint64_t ram_amount; + size_t val_size = sizeof(ram_amount); + + int sysctls[] = { CTL_HW, HW_PHYSMEM64 }; + if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) { + gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1)); + } #else gb_printf("Unknown.\n"); #endif From 32988b03632912bbdb788e3dc319592a1dab9bfe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 25 Feb 2022 12:01:53 +0000 Subject: [PATCH 0264/1052] Correct internals for `os.read` on windows (read_console) for `os.stdin` (Fix #1556) --- core/os/file_windows.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 8a0f2ed64..5368f51cf 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -108,7 +108,8 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { buf8: [4*BUF_SIZE]u8 for n < len(b) && err == 0 { - max_read := u32(min(BUF_SIZE, len(b)/4)) + min_read := max(min(len(b), 4), len(b)/4) + max_read := u32(min(BUF_SIZE, min_read)) single_read_length: u32 ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) @@ -129,7 +130,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { b[n] = x n += 1 } - if ctrl_z || single_read_length < len(buf16) { + if ctrl_z || single_read_length < max_read { break } } From 47c79a2f25270969bbc3b0faac54ba1888f67b9d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 25 Feb 2022 12:02:41 +0000 Subject: [PATCH 0265/1052] Correct `os.read` on windows for `os.stdin` --- core/os/file_windows.odin | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 8a0f2ed64..062e2b8a5 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -108,17 +108,18 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { buf8: [4*BUF_SIZE]u8 for n < len(b) && err == 0 { - max_read := u32(min(BUF_SIZE, len(b)/4)) - + min_read := max(min(len(b), 4), len(b)/4) + max_read := u32(min(BUF_SIZE, min_read)) + single_read_length: u32 ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) if !ok { err = Errno(win32.GetLastError()) } - + buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length]) src := buf8[:buf8_len] - + ctrl_z := false for i := 0; i < len(src) && n+i < len(b); i += 1 { x := src[i] @@ -129,7 +130,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { b[n] = x n += 1 } - if ctrl_z || single_read_length < len(buf16) { + if ctrl_z || single_read_length < max_read { break } } From 0a9099440370c902a6d3a08493f6c02363874be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Fri, 25 Feb 2022 12:32:34 +0000 Subject: [PATCH 0266/1052] provide a simple gb_file_copy() implementation permit to not require sendfile(2) syscall for gb_file_copy() --- src/gb/gb.h | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/gb/gb.h b/src/gb/gb.h index 293e5063a..b72a893f7 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -243,9 +243,6 @@ extern "C" { #include #include #define lseek64 lseek - - // XXX OpenBSD - #define sendfile(out, in, offset, count) (-1) #endif #if defined(GB_SYSTEM_UNIX) @@ -6069,7 +6066,7 @@ gbFileTime gb_file_last_write_time(char const *filepath) { gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists) { #if defined(GB_SYSTEM_OSX) return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0; -#else +#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_FREEBSD) isize size; int existing_fd = open(existing_filename, O_RDONLY, 0); int new_fd = open(new_filename, O_WRONLY|O_CREAT, 0666); @@ -6085,6 +6082,49 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena close(new_fd); close(existing_fd); + return size == stat_existing.st_size; +#else + int new_flags = O_WRONLY | O_CREAT; + if (fail_if_exists) { + new_flags |= O_EXCL; + } + int existing_fd = open(existing_filename, O_RDONLY, 0); + int new_fd = open(new_filename, new_flags, 0666); + + struct stat stat_existing; + if (fstat(existing_fd, &stat_existing) == -1) { + return 0; + } + + size_t bsize = stat_existing.st_blksize > BUFSIZ ? stat_existing.st_blksize : BUFSIZ; + char *buf = (char *)malloc(bsize); + if (buf == NULL) { + close(new_fd); + close(existing_fd); + return 0; + } + + isize size = 0; + ssize_t nread, nwrite, offset; + while ((nread = read(existing_fd, buf, bsize)) != -1 && nread != 0) { + for (offset = 0; nread; nread -= nwrite, offset += nwrite) { + if ((nwrite = write(new_fd, buf + offset, nread)) == -1 || nwrite == 0) { + free(buf); + close(new_fd); + close(existing_fd); + return 0; + } + size += nwrite; + } + } + + free(buf); + close(new_fd); + close(existing_fd); + + if (nread == -1) { + return 0; + } return size == stat_existing.st_size; #endif } From 83523badb7cebd524170fdacffc4d49c217e2b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Fri, 25 Feb 2022 13:02:12 +0000 Subject: [PATCH 0267/1052] pass -ldl only on Darwin and Linux --- Makefile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 99c71ccd9..72c1c7b95 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ GIT_SHA=$(shell git rev-parse --short HEAD) DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value -LDFLAGS=-pthread -ldl -lm -lstdc++ +LDFLAGS=-pthread -lm -lstdc++ CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\" CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\" CC=clang @@ -8,7 +8,7 @@ CC=clang OS=$(shell uname) ifeq ($(OS), Darwin) - + ARCH=$(shell uname -m) LLVM_CONFIG= @@ -37,7 +37,7 @@ ifeq ($(OS), Darwin) endif endif - LDFLAGS:=$(LDFLAGS) -liconv + LDFLAGS:=$(LDFLAGS) -liconv -ldl CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) LDFLAGS:=$(LDFLAGS) -lLLVM-C endif @@ -55,14 +55,16 @@ ifeq ($(OS), Linux) endif endif + LDFLAGS:=$(LDFLAGS) -ldl CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) endif ifeq ($(OS), OpenBSD) LLVM_CONFIG=/usr/local/bin/llvm-config + LDFLAGS:=$(LDFLAGS) -liconv CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) - LDFLAGS:=$(LDFLAGS) -liconv $(shell $(LLVM_CONFIG) --libs core native --system-libs) + LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) endif all: debug demo From 0e5c7e08fcbddcb662732a301e917b642b79cfd9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 25 Feb 2022 14:54:35 +0000 Subject: [PATCH 0268/1052] Change `<` to `<=` --- core/os/file_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 062e2b8a5..fbdc83ce9 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -130,7 +130,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { b[n] = x n += 1 } - if ctrl_z || single_read_length < max_read { + if ctrl_z || single_read_length <= max_read { break } } From d97df080f926e945fde0587ea0f9d63f98fcff5d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 25 Feb 2022 15:08:02 +0000 Subject: [PATCH 0269/1052] Revert change --- core/os/file_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index fbdc83ce9..062e2b8a5 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -130,7 +130,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { b[n] = x n += 1 } - if ctrl_z || single_read_length <= max_read { + if ctrl_z || single_read_length < max_read { break } } From ed3004f8a015f740f2c1abbcb1b8b0ec4762723a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 25 Feb 2022 15:30:05 +0000 Subject: [PATCH 0270/1052] Correct `read_console` reading --- core/os/file_windows.odin | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 062e2b8a5..948b63fca 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -2,6 +2,7 @@ package os import win32 "core:sys/windows" import "core:intrinsics" +import "core:runtime" import "core:unicode/utf16" is_path_separator :: proc(c: byte) -> bool { @@ -106,10 +107,13 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { BUF_SIZE :: 386 buf16: [BUF_SIZE]u16 buf8: [4*BUF_SIZE]u8 - + for n < len(b) && err == 0 { - min_read := max(min(len(b), 4), len(b)/4) + min_read := max(len(b)/4, 1 if len(b) > 0 else 0) max_read := u32(min(BUF_SIZE, min_read)) + if max_read == 0 { + break + } single_read_length: u32 ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) @@ -133,6 +137,13 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { if ctrl_z || single_read_length < max_read { break } + + // NOTE(bill): if the last two values were a newline, then it is expected that + // this is the end of the input + if n >= 2 && single_read_length == max_read && string(b[n-2:n]) == "\r\n" { + break + } + } return From e9f901b82d5a3e5ee8b345b55df7b7d905680520 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 25 Feb 2022 15:30:24 +0000 Subject: [PATCH 0271/1052] Keep `-vet` happy --- core/os/file_windows.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 948b63fca..0626272d6 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -2,7 +2,6 @@ package os import win32 "core:sys/windows" import "core:intrinsics" -import "core:runtime" import "core:unicode/utf16" is_path_separator :: proc(c: byte) -> bool { From ffe17a471da0e1e9da47f343c6290794fc0f0905 Mon Sep 17 00:00:00 2001 From: Mohamed Akram Date: Fri, 25 Feb 2022 19:40:42 +0400 Subject: [PATCH 0272/1052] Allow custom LLVM_CONFIG --- Makefile | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d3d3c6a2d..7f1b07f6d 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ OS=$(shell uname) ifeq ($(OS), Darwin) ARCH=$(shell uname -m) - LLVM_CONFIG= + LLVM_CONFIG=llvm-config # allow for arm only llvm's with version 13 ifeq ($(ARCH), arm64) @@ -27,9 +27,7 @@ ifeq ($(OS), Darwin) LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR = $(subst ",,$(LLVM_VERSION_PATTERN_REMOVE_ELEMENTS)) LLVM_VERSION_PATTERN = "^(($(LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR)))" - ifneq ($(shell llvm-config --version | grep -E $(LLVM_VERSION_PATTERN)),) - LLVM_CONFIG=llvm-config - else + ifeq ($(shell $(LLVM_CONFIG) --version | grep -E $(LLVM_VERSION_PATTERN)),) ifeq ($(ARCH), arm64) $(error "Requirement: llvm-config must be base version 13 for arm64") else @@ -48,9 +46,7 @@ ifeq ($(OS), Linux) else ifneq ($(shell which llvm-config-11-64 2>/dev/null),) LLVM_CONFIG=llvm-config-11-64 else - ifneq ($(shell llvm-config --version | grep '^11\.'),) - LLVM_CONFIG=llvm-config - else + ifeq ($(shell $(LLVM_CONFIG) --version | grep '^11\.'),) $(error "Requirement: llvm-config must be version 11") endif endif From ae5cb09041f79a2fcda27ab14aa66c6a4e098f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Fri, 25 Feb 2022 17:59:57 +0000 Subject: [PATCH 0273/1052] internal_odin_root_dir: readlink could fail --- src/build_settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 72a4b35cc..6b22ab4e7 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -738,7 +738,7 @@ String internal_odin_root_dir(void) { // XXX OpenBSD len = readlink("/proc/self/exe", &path_buf[0], path_buf.count); #endif - if(len == 0) { + if(len == 0 || len == -1) { return make_string(nullptr, 0); } if (len < path_buf.count) { From 8e270d3a99fc4a2369c622ae2de6395d7bfeb0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 26 Feb 2022 08:19:41 +0000 Subject: [PATCH 0274/1052] openbsd: poor man implementation for getting executable path it tries to get executable path from argv[0]. it is unreliable and unsecure, but should be fine enough for the considered use-case. it still doesn't address all possible cases. --- src/build_settings.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 6b22ab4e7..c40a70069 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1,4 +1,4 @@ -#if defined(GB_SYSTEM_FREEBSD) +#if defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) #include #include #endif @@ -734,9 +734,36 @@ String internal_odin_root_dir(void) { len = readlink("/proc/curproc/exe", &path_buf[0], path_buf.count); #elif defined(GB_SYSTEM_DRAGONFLYBSD) len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count); -#else - // XXX OpenBSD +#elif defined(GB_SYSTEM_LINUX) len = readlink("/proc/self/exe", &path_buf[0], path_buf.count); +#elif defined(GB_SYSTEM_OPENBSD) + int error; + int mib[] = { + CTL_KERN, + KERN_PROC_ARGS, + getpid(), + KERN_PROC_ARGV, + }; + // get argv size + error = sysctl(mib, 4, NULL, (size_t *) &len, NULL, 0); + if (error == -1) { + // sysctl error + return make_string(nullptr, 0); + } + // get argv + char **argv = (char **)gb_malloc(len); + error = sysctl(mib, 4, argv, (size_t *) &len, NULL, 0); + if (error == -1) { + // sysctl error + gb_mfree(argv); + return make_string(nullptr, 0); + } + // copy argv[0] to path_buf + len = gb_strlen(argv[0]); + if(len < path_buf.count) { + gb_memmove(&path_buf[0], argv[0], len); + } + gb_mfree(argv); #endif if(len == 0 || len == -1) { return make_string(nullptr, 0); From 57862846a21a8da2a658e1bea97c52577ae4040a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 26 Feb 2022 08:21:46 +0000 Subject: [PATCH 0275/1052] tests/vendor: pass extra linker flags on OpenBSD, botan library is third-party and live in /usr/local which isn't a path included by default in linker. --- tests/vendor/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/vendor/Makefile b/tests/vendor/Makefile index f0a456bae..341067c6e 100644 --- a/tests/vendor/Makefile +++ b/tests/vendor/Makefile @@ -1,6 +1,13 @@ ODIN=../../odin +ODINFLAGS= + +OS=$(shell uname) + +ifeq ($(OS), OpenBSD) + ODINFLAGS:=$(ODINFLAGS) -extra-linker-flags:-L/usr/local/lib +endif all: botan_test botan_test: - $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check \ No newline at end of file + $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS) From 553292ffd0b518b5332355cd0c9695e3168b5285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 26 Feb 2022 08:47:58 +0000 Subject: [PATCH 0276/1052] vendor: botan: add OpenBSD support --- vendor/botan/bindings/botan.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 70311523d..3eaad0bc1 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -146,6 +146,8 @@ when ODIN_OS == .Windows { foreign import botan_lib "system:botan-2" } else when ODIN_OS == .Darwin { foreign import botan_lib "system:botan-2" +} else when ODIN_OS == .OpenBSD { + foreign import botan_lib "system:botan-2" } @(default_calling_convention="c") @@ -471,4 +473,4 @@ foreign botan_lib { fpe_destroy :: proc(fpe: fpe_t) -> c.int --- fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- -} \ No newline at end of file +} From 04297bb68034196a212b040990bdeb4dc006c340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 26 Feb 2022 14:18:37 +0000 Subject: [PATCH 0277/1052] ci: add check for OpenBSD amd64 --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c62fcd36b..788c59311 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,9 @@ jobs: cd tests/vendor make timeout-minutes: 10 + - name: Odin check examples/all for OpenBSD amd64 + run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64 + timeout-minutes: 10 build_macOS: runs-on: macos-latest steps: From c223fc17662da5a9ea3828e695bff41ae09c43f4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 12:06:35 +0000 Subject: [PATCH 0278/1052] Correct debug information for local variables --- src/llvm_backend_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index ff1c5c7dc..b91f32bfc 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -962,7 +962,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); - LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); + LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); } From 7681c43b144015278b75b2788b824a5630f6ccd6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 12:12:04 +0000 Subject: [PATCH 0279/1052] Show error message when something like this is done `test: proc() : {}` --- src/check_decl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 45d741532..3fdd944f9 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -174,6 +174,10 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { return; } + if (is_type_proc(e->type)) { + error(e->token, "Illegal declaration of a constant procedure value"); + } + e->parent_proc_decl = ctx->curr_proc_decl; e->Constant.value = operand->value; From ab9d1f99fdb776352352d882f49aefc80d0e9d58 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 12:36:21 +0000 Subject: [PATCH 0280/1052] Change `#c_vararg` checking to only disallow odin calling conventions --- src/check_type.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 64fb67723..c2324ee5a 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2031,10 +2031,14 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, if (param_count > 0) { Entity *end = params->Tuple.variables[param_count-1]; if (end->flags&EntityFlag_CVarArg) { - if (cc == ProcCC_StdCall || cc == ProcCC_CDecl) { + switch (cc) { + default: type->Proc.c_vararg = true; - } else { + break; + case ProcCC_Odin: + case ProcCC_Contextless: error(end->token, "Calling convention does not support #c_vararg"); + break; } } } From 37bba4c0a6b98f38a3160c9508bc55a6cb8ea7f1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 12:45:19 +0000 Subject: [PATCH 0281/1052] Reorganize error check procedures --- core/runtime/error_checks.odin | 339 ++++++++++++++++----------------- 1 file changed, 168 insertions(+), 171 deletions(-) diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index ad6902e2d..e4dd96d32 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -17,6 +17,23 @@ type_assertion_trap :: proc "contextless" () -> ! { } +bounds_check_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, index, count: int) { + bounds_check_error(file_path, line, column, index, count) +} + +slice_expr_error_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, hi: int, len: int) { + slice_expr_error_hi(file_path, line, column, hi, len) +} + +slice_expr_error_lo_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) { + slice_expr_error_lo_hi(file_path, line, column, lo, hi, len) +} + +dynamic_array_expr_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, low, high, max: int) { + dynamic_array_expr_error(file_path, line, column, low, high, max) +} + + when ODIN_FOREIGN_ERROR_PROCEDURES { foreign { bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) --- @@ -29,182 +46,182 @@ when ODIN_FOREIGN_ERROR_PROCEDURES { matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) --- type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) --- type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) --- - make_slice_error_loc :: proc "contextless" (loc := #caller_location, len: int) --- - make_dynamic_array_error_loc :: proc "contextless" (using loc := #caller_location, len, cap: int) --- - make_map_expr_error_loc :: proc "contextless" (loc := #caller_location, cap: int) --- } } else { - -bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { - if 0 <= index && index < count { - return + bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { + if 0 <= index && index < count { + return + } + handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Index ") + print_i64(i64(index)) + print_string(" is out of range 0..<") + print_i64(i64(count)) + print_byte('\n') + bounds_trap() + } + handle_error(file, line, column, index, count) } - handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { + + slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Index ") - print_i64(i64(index)) - print_string(" is out of range 0..<") - print_i64(i64(count)) - print_byte('\n') - bounds_trap() - } - handle_error(file, line, column, index, count) -} - -slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid slice indices ") - print_i64(i64(lo)) - print_string(":") - print_i64(i64(hi)) - print_string(" is out of range 0..<") - print_i64(i64(len)) - print_byte('\n') - bounds_trap() -} - -multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid slice indices ") - print_i64(i64(lo)) - print_string(":") - print_i64(i64(hi)) - print_byte('\n') - bounds_trap() -} - - -multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) { - if lo <= hi { - return - } - multi_pointer_slice_handle_error(file, line, column, lo, hi) -} - -slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) { - if 0 <= hi && hi <= len { - return - } - slice_handle_error(file, line, column, 0, hi, len) -} - -slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) { - if 0 <= lo && lo <= len && lo <= hi && hi <= len { - return - } - slice_handle_error(file, line, column, lo, hi, len) -} - -dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { - if 0 <= low && low <= high && high <= max { - return - } - handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid dynamic array indices ") - print_i64(i64(low)) + print_string(" Invalid slice indices ") + print_i64(i64(lo)) print_string(":") - print_i64(i64(high)) + print_i64(i64(hi)) print_string(" is out of range 0..<") - print_i64(i64(max)) + print_i64(i64(len)) print_byte('\n') bounds_trap() } - handle_error(file, line, column, low, high, max) -} - -matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { - if 0 <= row_index && row_index < row_count && - 0 <= column_index && column_index < column_count { - return - } - handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { + multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Matrix indices [") - print_i64(i64(row_index)) - print_string(", ") - print_i64(i64(column_index)) - print_string(" is out of range [0..<") - print_i64(i64(row_count)) - print_string(", 0..<") - print_i64(i64(column_count)) - print_string("]") + print_string(" Invalid slice indices ") + print_i64(i64(lo)) + print_string(":") + print_i64(i64(hi)) print_byte('\n') bounds_trap() } - handle_error(file, line, column, row_index, column_index, row_count, column_count) -} -type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) { - if ok { - return - } - handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid type assertion from ") - print_typeid(from) - print_string(" to ") - print_typeid(to) - print_byte('\n') - type_assertion_trap() - } - handle_error(file, line, column, from, to) -} - -type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) { - if ok { - return + multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) { + if lo <= hi { + return + } + multi_pointer_slice_handle_error(file, line, column, lo, hi) } - variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid { - if id == nil || data == nil { + slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) { + if 0 <= hi && hi <= len { + return + } + slice_handle_error(file, line, column, 0, hi, len) + } + + slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) { + if 0 <= lo && lo <= len && lo <= hi && hi <= len { + return + } + slice_handle_error(file, line, column, lo, hi, len) + } + + dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { + if 0 <= low && low <= high && high <= max { + return + } + handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid dynamic array indices ") + print_i64(i64(low)) + print_string(":") + print_i64(i64(high)) + print_string(" is out of range 0..<") + print_i64(i64(max)) + print_byte('\n') + bounds_trap() + } + handle_error(file, line, column, low, high, max) + } + + + matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { + if 0 <= row_index && row_index < row_count && + 0 <= column_index && column_index < column_count { + return + } + handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Matrix indices [") + print_i64(i64(row_index)) + print_string(", ") + print_i64(i64(column_index)) + print_string(" is out of range [0..<") + print_i64(i64(row_count)) + print_string(", 0..<") + print_i64(i64(column_count)) + print_string("]") + print_byte('\n') + bounds_trap() + } + handle_error(file, line, column, row_index, column_index, row_count, column_count) + } + + + type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) { + if ok { + return + } + handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid type assertion from ") + print_typeid(from) + print_string(" to ") + print_typeid(to) + print_byte('\n') + type_assertion_trap() + } + handle_error(file, line, column, from, to) + } + + type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) { + if ok { + return + } + + variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid { + if id == nil || data == nil { + return id + } + ti := type_info_base(type_info_of(id)) + #partial switch v in ti.variant { + case Type_Info_Any: + return (^any)(data).id + case Type_Info_Union: + tag_ptr := uintptr(data) + v.tag_offset + idx := 0 + switch v.tag_type.size { + case 1: idx = int((^u8)(tag_ptr)^) - 1 + case 2: idx = int((^u16)(tag_ptr)^) - 1 + case 4: idx = int((^u32)(tag_ptr)^) - 1 + case 8: idx = int((^u64)(tag_ptr)^) - 1 + case 16: idx = int((^u128)(tag_ptr)^) - 1 + } + if idx < 0 { + return nil + } else if idx < len(v.variants) { + return v.variants[idx].id + } + } return id } - ti := type_info_base(type_info_of(id)) - #partial switch v in ti.variant { - case Type_Info_Any: - return (^any)(data).id - case Type_Info_Union: - tag_ptr := uintptr(data) + v.tag_offset - idx := 0 - switch v.tag_type.size { - case 1: idx = int((^u8)(tag_ptr)^) - 1 - case 2: idx = int((^u16)(tag_ptr)^) - 1 - case 4: idx = int((^u32)(tag_ptr)^) - 1 - case 8: idx = int((^u64)(tag_ptr)^) - 1 - case 16: idx = int((^u128)(tag_ptr)^) - 1 - } - if idx < 0 { - return nil - } else if idx < len(v.variants) { - return v.variants[idx].id + + handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) { + + actual := variant_type(from, from_data) + + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid type assertion from ") + print_typeid(from) + print_string(" to ") + print_typeid(to) + if actual != from { + print_string(", actual type: ") + print_typeid(actual) } + print_byte('\n') + type_assertion_trap() } - return id + handle_error(file, line, column, from, to, from_data) } - - handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) { - - actual := variant_type(from, from_data) - - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid type assertion from ") - print_typeid(from) - print_string(" to ") - print_typeid(to) - if actual != from { - print_string(", actual type: ") - print_typeid(actual) - } - print_byte('\n') - type_assertion_trap() - } - handle_error(file, line, column, from, to, from_data) } +// `make` related procedures below + + make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_location, len: int) { if 0 <= len { return @@ -219,7 +236,7 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio handle_error(loc, len) } -make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, len, cap: int) { +make_dynamic_array_error_loc :: #force_inline proc "contextless" (loc := #caller_location, len, cap: int) { if 0 <= len && len <= cap { return } @@ -248,23 +265,3 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca } handle_error(loc, cap) } - -} - - - -bounds_check_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, index, count: int) { - bounds_check_error(file_path, line, column, index, count) -} - -slice_expr_error_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, hi: int, len: int) { - slice_expr_error_hi(file_path, line, column, hi, len) -} - -slice_expr_error_lo_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) { - slice_expr_error_lo_hi(file_path, line, column, lo, hi, len) -} - -dynamic_array_expr_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, low, high, max: int) { - dynamic_array_expr_error(file_path, line, column, low, high, max) -} From 3c72cb67d3f031a71152aadc480f5838d1833228 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 13:00:32 +0000 Subject: [PATCH 0282/1052] Remove `context.user_data` --- core/runtime/core.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 229d70417..8d315a238 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -351,7 +351,6 @@ Context :: struct { assertion_failure_proc: Assertion_Failure_Proc, logger: Logger, - user_data: any, user_ptr: rawptr, user_index: int, From 01162e08b55406578a2972d74c472de8a14f12b8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 13:35:29 +0000 Subject: [PATCH 0283/1052] Add `-disallow-rtti` --- core/runtime/core.odin | 20 +-- core/runtime/error_checks.odin | 277 ++++++++++++++++++--------------- core/runtime/print.odin | 16 +- 3 files changed, 172 insertions(+), 141 deletions(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 8d315a238..83a5418ed 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -508,16 +508,18 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check return &type_table[n] } -typeid_base :: proc "contextless" (id: typeid) -> typeid { - ti := type_info_of(id) - ti = type_info_base(ti) - return ti.id +when !ODIN_DISALLOW_RTTI { + typeid_base :: proc "contextless" (id: typeid) -> typeid { + ti := type_info_of(id) + ti = type_info_base(ti) + return ti.id + } + typeid_core :: proc "contextless" (id: typeid) -> typeid { + ti := type_info_core(type_info_of(id)) + return ti.id + } + typeid_base_without_enum :: typeid_core } -typeid_core :: proc "contextless" (id: typeid) -> typeid { - ti := type_info_core(type_info_of(id)) - return ti.id -} -typeid_base_without_enum :: typeid_core diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index e4dd96d32..0d0b39072 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -17,143 +17,143 @@ type_assertion_trap :: proc "contextless" () -> ! { } -bounds_check_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, index, count: int) { - bounds_check_error(file_path, line, column, index, count) +bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { + if 0 <= index && index < count { + return + } + @(cold) + handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Index ") + print_i64(i64(index)) + print_string(" is out of range 0..<") + print_i64(i64(count)) + print_byte('\n') + bounds_trap() + } + handle_error(file, line, column, index, count) } -slice_expr_error_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, hi: int, len: int) { - slice_expr_error_hi(file_path, line, column, hi, len) +slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid slice indices ") + print_i64(i64(lo)) + print_string(":") + print_i64(i64(hi)) + print_string(" is out of range 0..<") + print_i64(i64(len)) + print_byte('\n') + bounds_trap() } -slice_expr_error_lo_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) { - slice_expr_error_lo_hi(file_path, line, column, lo, hi, len) -} - -dynamic_array_expr_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, low, high, max: int) { - dynamic_array_expr_error(file_path, line, column, low, high, max) +multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid slice indices ") + print_i64(i64(lo)) + print_string(":") + print_i64(i64(hi)) + print_byte('\n') + bounds_trap() } -when ODIN_FOREIGN_ERROR_PROCEDURES { - foreign { - bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) --- - slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! --- - multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! --- - multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) --- - slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) --- - slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) --- - dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) --- - matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) --- - type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) --- - type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) --- +multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) { + if lo <= hi { + return + } + multi_pointer_slice_handle_error(file, line, column, lo, hi) +} + +slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) { + if 0 <= hi && hi <= len { + return + } + slice_handle_error(file, line, column, 0, hi, len) +} + +slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) { + if 0 <= lo && lo <= len && lo <= hi && hi <= len { + return + } + slice_handle_error(file, line, column, lo, hi, len) +} + +dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { + if 0 <= low && low <= high && high <= max { + return + } + @(cold) + handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid dynamic array indices ") + print_i64(i64(low)) + print_string(":") + print_i64(i64(high)) + print_string(" is out of range 0..<") + print_i64(i64(max)) + print_byte('\n') + bounds_trap() + } + handle_error(file, line, column, low, high, max) +} + + +matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { + if 0 <= row_index && row_index < row_count && + 0 <= column_index && column_index < column_count { + return + } + @(cold) + handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Matrix indices [") + print_i64(i64(row_index)) + print_string(", ") + print_i64(i64(column_index)) + print_string(" is out of range [0..<") + print_i64(i64(row_count)) + print_string(", 0..<") + print_i64(i64(column_count)) + print_string("]") + print_byte('\n') + bounds_trap() + } + handle_error(file, line, column, row_index, column_index, row_count, column_count) +} + + +when ODIN_DISALLOW_RTTI { + type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32) { + if ok { + return + } + @(cold) + handle_error :: proc "contextless" (file: string, line, column: i32) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid type assertion\n") + type_assertion_trap() + } + handle_error(file, line, column) + } + + type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32) { + if ok { + return + } + @(cold) + handle_error :: proc "contextless" (file: string, line, column: i32) { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid type assertion\n") + type_assertion_trap() + } + handle_error(file, line, column) } } else { - bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { - if 0 <= index && index < count { - return - } - handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Index ") - print_i64(i64(index)) - print_string(" is out of range 0..<") - print_i64(i64(count)) - print_byte('\n') - bounds_trap() - } - handle_error(file, line, column, index, count) - } - - slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid slice indices ") - print_i64(i64(lo)) - print_string(":") - print_i64(i64(hi)) - print_string(" is out of range 0..<") - print_i64(i64(len)) - print_byte('\n') - bounds_trap() - } - - multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid slice indices ") - print_i64(i64(lo)) - print_string(":") - print_i64(i64(hi)) - print_byte('\n') - bounds_trap() - } - - - multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) { - if lo <= hi { - return - } - multi_pointer_slice_handle_error(file, line, column, lo, hi) - } - - slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) { - if 0 <= hi && hi <= len { - return - } - slice_handle_error(file, line, column, 0, hi, len) - } - - slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) { - if 0 <= lo && lo <= len && lo <= hi && hi <= len { - return - } - slice_handle_error(file, line, column, lo, hi, len) - } - - dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { - if 0 <= low && low <= high && high <= max { - return - } - handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid dynamic array indices ") - print_i64(i64(low)) - print_string(":") - print_i64(i64(high)) - print_string(" is out of range 0..<") - print_i64(i64(max)) - print_byte('\n') - bounds_trap() - } - handle_error(file, line, column, low, high, max) - } - - - matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { - if 0 <= row_index && row_index < row_count && - 0 <= column_index && column_index < column_count { - return - } - handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Matrix indices [") - print_i64(i64(row_index)) - print_string(", ") - print_i64(i64(column_index)) - print_string(" is out of range [0..<") - print_i64(i64(row_count)) - print_string(", 0..<") - print_i64(i64(column_count)) - print_string("]") - print_byte('\n') - bounds_trap() - } - handle_error(file, line, column, row_index, column_index, row_count, column_count) - } - - type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) { if ok { return } + @(cold) handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Invalid type assertion from ") @@ -198,6 +198,7 @@ when ODIN_FOREIGN_ERROR_PROCEDURES { return id } + @(cold) handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) { actual := variant_type(from, from_data) @@ -219,13 +220,11 @@ when ODIN_FOREIGN_ERROR_PROCEDURES { } -// `make` related procedures below - - make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_location, len: int) { if 0 <= len { return } + @(cold) handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) { print_caller_location(loc) print_string(" Invalid slice length for make: ") @@ -236,10 +235,11 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio handle_error(loc, len) } -make_dynamic_array_error_loc :: #force_inline proc "contextless" (loc := #caller_location, len, cap: int) { +make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, len, cap: int) { if 0 <= len && len <= cap { return } + @(cold) handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) { print_caller_location(loc) print_string(" Invalid dynamic array parameters for make: ") @@ -256,6 +256,7 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca if 0 <= cap { return } + @(cold) handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) { print_caller_location(loc) print_string(" Invalid map capacity for make: ") @@ -265,3 +266,23 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca } handle_error(loc, cap) } + + + + + +bounds_check_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, index, count: int) { + bounds_check_error(file_path, line, column, index, count) +} + +slice_expr_error_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, hi: int, len: int) { + slice_expr_error_hi(file_path, line, column, hi, len) +} + +slice_expr_error_lo_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) { + slice_expr_error_lo_hi(file_path, line, column, lo, hi, len) +} + +dynamic_array_expr_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, low, high, max: int) { + dynamic_array_expr_error(file_path, line, column, low, high, max) +} diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 06740bc75..89c196fc2 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -160,11 +160,19 @@ print_caller_location :: proc "contextless" (using loc: Source_Code_Location) { } } print_typeid :: proc "contextless" (id: typeid) { - if id == nil { - print_string("nil") + when ODIN_DISALLOW_RTTI { + if id == nil { + print_string("nil") + } else { + print_string("") + } } else { - ti := type_info_of(id) - print_type(ti) + if id == nil { + print_string("nil") + } else { + ti := type_info_of(id) + print_type(ti) + } } } print_type :: proc "contextless" (ti: ^Type_Info) { From fda803b46ae7d9bf3eba33e2ae701c452e72477d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 13:39:27 +0000 Subject: [PATCH 0284/1052] Commit rest of code for `-disable-rtti` --- src/build_settings.cpp | 3 ++- src/check_builtin.cpp | 18 +++++++++++++----- src/check_decl.cpp | 2 ++ src/check_expr.cpp | 2 ++ src/check_type.cpp | 2 ++ src/checker.cpp | 25 ++++++++++++++++++++++++- src/llvm_backend.cpp | 6 +++++- src/llvm_backend_expr.cpp | 17 ++++++++++++++--- src/llvm_backend_type.cpp | 2 ++ src/llvm_backend_utility.cpp | 30 ++++++++++++++++++++++-------- src/main.cpp | 7 +++++++ 11 files changed, 95 insertions(+), 19 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d6cdd7006..b2d6c4f43 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -277,6 +277,8 @@ struct BuildContext { bool copy_file_contents; + bool disallow_rtti; + RelocMode reloc_mode; bool disable_red_zone; @@ -946,7 +948,6 @@ void init_build_context(TargetMetrics *cross_target) { } } - bc->copy_file_contents = true; TargetMetrics *metrics = nullptr; diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index eb9d7f293..5561da01b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1241,6 +1241,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (c->scope->flags&ScopeFlag_Global) { compiler_error("'type_info_of' Cannot be declared within the runtime package due to how the internals of the compiler works"); } + if (build_context.disallow_rtti) { + error(call, "'%.*s' has been disallowed", LIT(builtin_name)); + return false; + } // NOTE(bill): The type information may not be setup yet init_core_type_info(c->checker); @@ -1253,9 +1257,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Type *t = o.type; if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(t)) { if (is_type_polymorphic(t)) { - error(ce->args[0], "Invalid argument for 'type_info_of', unspecialized polymorphic type"); + error(ce->args[0], "Invalid argument for '%.*s', unspecialized polymorphic type", LIT(builtin_name)); } else { - error(ce->args[0], "Invalid argument for 'type_info_of'"); + error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name)); } return false; } @@ -1266,7 +1270,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (is_operand_value(o) && is_type_typeid(t)) { add_package_dependency(c, "runtime", "__type_info_of"); } else if (o.mode != Addressing_Type) { - error(expr, "Expected a type or typeid for 'type_info_of'"); + error(expr, "Expected a type or typeid for '%.*s'", LIT(builtin_name)); return false; } @@ -1280,6 +1284,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (c->scope->flags&ScopeFlag_Global) { compiler_error("'typeid_of' Cannot be declared within the runtime package due to how the internals of the compiler works"); } + if (build_context.disallow_rtti) { + error(call, "'%.*s' has been disallowed", LIT(builtin_name)); + return false; + } // NOTE(bill): The type information may not be setup yet init_core_type_info(c->checker); @@ -1291,7 +1299,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } Type *t = o.type; if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) { - error(ce->args[0], "Invalid argument for 'typeid_of'"); + error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name)); return false; } t = default_type(t); @@ -1299,7 +1307,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 add_type_info_type(c, t); if (o.mode != Addressing_Type) { - error(expr, "Expected a type for 'typeid_of'"); + error(expr, "Expected a type for '%.*s'", LIT(builtin_name)); return false; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3fdd944f9..b3b1e4474 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1205,6 +1205,8 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Operand o = {}; check_expr_with_type_hint(ctx, &o, init_expr, e->type); check_init_variable(ctx, e, &o, str_lit("variable declaration")); + + check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed"); } void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e07dc3d60..f1bcb4cd9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9352,6 +9352,8 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi if (o->type != nullptr && is_type_untyped(o->type)) { add_untyped(c, node, o->mode, o->type, o->value); } + check_rtti_type_disallowed(node, o->type, "An expression is using a type, %s, which has been disallowed"); + add_type_and_value(c->info, node, o->mode, o->type, o->value); return kind; } diff --git a/src/check_type.cpp b/src/check_type.cpp index c2324ee5a..ff2c3d6a6 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3031,5 +3031,7 @@ Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) { } set_base_type(named_type, type); + check_rtti_type_disallowed(e, type, "Use of a type, %s, which has been disallowed"); + return type; } diff --git a/src/checker.cpp b/src/checker.cpp index fe1d362fa..e6445d752 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -29,6 +29,23 @@ bool is_operand_undef(Operand o) { return o.mode == Addressing_Value && o.type == t_untyped_undef; } +bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) { + if (build_context.disallow_rtti && type) { + if (is_type_any(type)) { + gbString t = type_to_string(type); + error(token, format, t); + gb_string_free(t); + return true; + } + } + return false; +} + +bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *format) { + GB_ASSERT(expr != nullptr); + return check_rtti_type_disallowed(ast_token(expr), type, format); +} + void scope_reset(Scope *scope) { if (scope == nullptr) return; @@ -875,7 +892,8 @@ void init_universal(void) { // Types for (isize i = 0; i < gb_count_of(basic_types); i++) { - add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]); + String const &name = basic_types[i].Basic.name; + add_global_type_entity(name, &basic_types[i]); } add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]); @@ -977,6 +995,7 @@ void init_universal(void) { add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); add_global_bool_constant("ODIN_NO_ENTRY_POINT", bc->no_entry_point); add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES); + add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti); // Builtin Procedures @@ -1669,6 +1688,10 @@ void add_implicit_entity(CheckerContext *c, Ast *clause, Entity *e) { void add_type_info_type(CheckerContext *c, Type *t) { void add_type_info_type_internal(CheckerContext *c, Type *t); + if (build_context.disallow_rtti) { + return; + } + mutex_lock(&c->info->type_info_mutex); add_type_info_type_internal(c, t); mutex_unlock(&c->info->type_info_mutex); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6ca256c4b..04c3200f8 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1285,7 +1285,11 @@ void lb_generate_code(lbGenerator *gen) { // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL if (ODIN_LLVM_MINIMUM_VERSION_12) { - llvm_cpu = "x86-64-v2"; + if (build_context.metrics.os == TargetOs_freestanding) { + llvm_cpu = "x86-64"; + } else { + llvm_cpu = "x86-64-v2"; + } } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 844deb43c..18b66572d 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2809,16 +2809,25 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); dst_tag = lb_const_union_tag(p->module, src_type, dst_type); } + + + isize arg_count = 6; + if (build_context.disallow_rtti) { + arg_count = 4; + } + lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - auto args = array_make(permanent_allocator(), 6); + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); args[2] = lb_const_int(p->module, t_i32, pos.line); args[3] = lb_const_int(p->module, t_i32, pos.column); - args[4] = lb_typeid(p->module, src_type); - args[5] = lb_typeid(p->module, dst_type); + if (!build_context.disallow_rtti) { + args[4] = lb_typeid(p->module, src_type); + args[5] = lb_typeid(p->module, dst_type); + } lb_emit_runtime_call(p, "type_assertion_check", args); } @@ -2831,6 +2840,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { } lbValue data_ptr = lb_emit_struct_ev(p, v, 0); if ((p->state_flags & StateFlag_no_type_assert) == 0) { + GB_ASSERT(!build_context.disallow_rtti); + lbValue any_id = lb_emit_struct_ev(p, v, 1); lbValue id = lb_typeid(p->module, type); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 1d6297164..1aac75f9c 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -14,6 +14,8 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr } lbValue lb_typeid(lbModule *m, Type *type) { + GB_ASSERT(!build_context.disallow_rtti); + type = default_type(type); u64 id = cast(u64)lb_type_info_index(m->info, type); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 98b7e07f0..fb52a9bd6 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -676,17 +676,24 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p // NOTE(bill): Panic on invalid conversion Type *dst_type = tuple->Tuple.variables[0]->type; + isize arg_count = 7; + if (build_context.disallow_rtti) { + arg_count = 4; + } + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), 7); + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); args[2] = lb_const_int(m, t_i32, pos.line); args[3] = lb_const_int(m, t_i32, pos.column); - args[4] = lb_typeid(m, src_type); - args[5] = lb_typeid(m, dst_type); - args[6] = lb_emit_conv(p, value_, t_rawptr); + if (!build_context.disallow_rtti) { + args[4] = lb_typeid(m, src_type); + args[5] = lb_typeid(m, dst_type); + args[6] = lb_emit_conv(p, value_, t_rawptr); + } lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); @@ -744,16 +751,23 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos if (!is_tuple) { // NOTE(bill): Panic on invalid conversion lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), 7); + + isize arg_count = 7; + if (build_context.disallow_rtti) { + arg_count = 4; + } + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); args[2] = lb_const_int(m, t_i32, pos.line); args[3] = lb_const_int(m, t_i32, pos.column); - args[4] = any_typeid; - args[5] = dst_typeid; - args[6] = lb_emit_struct_ev(p, value, 0);; + if (!build_context.disallow_rtti) { + args[4] = any_typeid; + args[5] = dst_typeid; + args[6] = lb_emit_struct_ev(p, value, 0); + } lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); diff --git a/src/main.cpp b/src/main.cpp index 8f4155d39..d2263f5a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -638,6 +638,7 @@ enum BuildFlagKind { BuildFlag_StrictStyle, BuildFlag_StrictStyleInitOnly, BuildFlag_ForeignErrorProcedures, + BuildFlag_DisallowRTTI, BuildFlag_Compact, BuildFlag_GlobalDefinitions, @@ -796,6 +797,9 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check); + + add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query); @@ -1390,6 +1394,9 @@ bool parse_build_flags(Array args) { case BuildFlag_DisallowDo: build_context.disallow_do = true; break; + case BuildFlag_DisallowRTTI: + build_context.disallow_rtti = true; + break; case BuildFlag_DefaultToNilAllocator: build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true; break; From 278e239973ab1e680bd36f90c069ec798930e54b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 13:39:27 +0000 Subject: [PATCH 0285/1052] Commit rest of code for `-disallow-rtti` --- src/build_settings.cpp | 3 ++- src/check_builtin.cpp | 18 +++++++++++++----- src/check_decl.cpp | 2 ++ src/check_expr.cpp | 2 ++ src/check_type.cpp | 2 ++ src/checker.cpp | 25 ++++++++++++++++++++++++- src/llvm_backend.cpp | 6 +++++- src/llvm_backend_expr.cpp | 17 ++++++++++++++--- src/llvm_backend_type.cpp | 2 ++ src/llvm_backend_utility.cpp | 30 ++++++++++++++++++++++-------- src/main.cpp | 7 +++++++ 11 files changed, 95 insertions(+), 19 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d6cdd7006..b2d6c4f43 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -277,6 +277,8 @@ struct BuildContext { bool copy_file_contents; + bool disallow_rtti; + RelocMode reloc_mode; bool disable_red_zone; @@ -946,7 +948,6 @@ void init_build_context(TargetMetrics *cross_target) { } } - bc->copy_file_contents = true; TargetMetrics *metrics = nullptr; diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index eb9d7f293..5561da01b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1241,6 +1241,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (c->scope->flags&ScopeFlag_Global) { compiler_error("'type_info_of' Cannot be declared within the runtime package due to how the internals of the compiler works"); } + if (build_context.disallow_rtti) { + error(call, "'%.*s' has been disallowed", LIT(builtin_name)); + return false; + } // NOTE(bill): The type information may not be setup yet init_core_type_info(c->checker); @@ -1253,9 +1257,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Type *t = o.type; if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(t)) { if (is_type_polymorphic(t)) { - error(ce->args[0], "Invalid argument for 'type_info_of', unspecialized polymorphic type"); + error(ce->args[0], "Invalid argument for '%.*s', unspecialized polymorphic type", LIT(builtin_name)); } else { - error(ce->args[0], "Invalid argument for 'type_info_of'"); + error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name)); } return false; } @@ -1266,7 +1270,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (is_operand_value(o) && is_type_typeid(t)) { add_package_dependency(c, "runtime", "__type_info_of"); } else if (o.mode != Addressing_Type) { - error(expr, "Expected a type or typeid for 'type_info_of'"); + error(expr, "Expected a type or typeid for '%.*s'", LIT(builtin_name)); return false; } @@ -1280,6 +1284,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (c->scope->flags&ScopeFlag_Global) { compiler_error("'typeid_of' Cannot be declared within the runtime package due to how the internals of the compiler works"); } + if (build_context.disallow_rtti) { + error(call, "'%.*s' has been disallowed", LIT(builtin_name)); + return false; + } // NOTE(bill): The type information may not be setup yet init_core_type_info(c->checker); @@ -1291,7 +1299,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } Type *t = o.type; if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) { - error(ce->args[0], "Invalid argument for 'typeid_of'"); + error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name)); return false; } t = default_type(t); @@ -1299,7 +1307,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 add_type_info_type(c, t); if (o.mode != Addressing_Type) { - error(expr, "Expected a type for 'typeid_of'"); + error(expr, "Expected a type for '%.*s'", LIT(builtin_name)); return false; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3fdd944f9..b3b1e4474 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1205,6 +1205,8 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Operand o = {}; check_expr_with_type_hint(ctx, &o, init_expr, e->type); check_init_variable(ctx, e, &o, str_lit("variable declaration")); + + check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed"); } void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e07dc3d60..f1bcb4cd9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9352,6 +9352,8 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi if (o->type != nullptr && is_type_untyped(o->type)) { add_untyped(c, node, o->mode, o->type, o->value); } + check_rtti_type_disallowed(node, o->type, "An expression is using a type, %s, which has been disallowed"); + add_type_and_value(c->info, node, o->mode, o->type, o->value); return kind; } diff --git a/src/check_type.cpp b/src/check_type.cpp index c2324ee5a..ff2c3d6a6 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3031,5 +3031,7 @@ Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) { } set_base_type(named_type, type); + check_rtti_type_disallowed(e, type, "Use of a type, %s, which has been disallowed"); + return type; } diff --git a/src/checker.cpp b/src/checker.cpp index fe1d362fa..e6445d752 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -29,6 +29,23 @@ bool is_operand_undef(Operand o) { return o.mode == Addressing_Value && o.type == t_untyped_undef; } +bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) { + if (build_context.disallow_rtti && type) { + if (is_type_any(type)) { + gbString t = type_to_string(type); + error(token, format, t); + gb_string_free(t); + return true; + } + } + return false; +} + +bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *format) { + GB_ASSERT(expr != nullptr); + return check_rtti_type_disallowed(ast_token(expr), type, format); +} + void scope_reset(Scope *scope) { if (scope == nullptr) return; @@ -875,7 +892,8 @@ void init_universal(void) { // Types for (isize i = 0; i < gb_count_of(basic_types); i++) { - add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]); + String const &name = basic_types[i].Basic.name; + add_global_type_entity(name, &basic_types[i]); } add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]); @@ -977,6 +995,7 @@ void init_universal(void) { add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); add_global_bool_constant("ODIN_NO_ENTRY_POINT", bc->no_entry_point); add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES); + add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti); // Builtin Procedures @@ -1669,6 +1688,10 @@ void add_implicit_entity(CheckerContext *c, Ast *clause, Entity *e) { void add_type_info_type(CheckerContext *c, Type *t) { void add_type_info_type_internal(CheckerContext *c, Type *t); + if (build_context.disallow_rtti) { + return; + } + mutex_lock(&c->info->type_info_mutex); add_type_info_type_internal(c, t); mutex_unlock(&c->info->type_info_mutex); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6ca256c4b..04c3200f8 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1285,7 +1285,11 @@ void lb_generate_code(lbGenerator *gen) { // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL if (ODIN_LLVM_MINIMUM_VERSION_12) { - llvm_cpu = "x86-64-v2"; + if (build_context.metrics.os == TargetOs_freestanding) { + llvm_cpu = "x86-64"; + } else { + llvm_cpu = "x86-64-v2"; + } } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 844deb43c..18b66572d 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2809,16 +2809,25 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); dst_tag = lb_const_union_tag(p->module, src_type, dst_type); } + + + isize arg_count = 6; + if (build_context.disallow_rtti) { + arg_count = 4; + } + lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - auto args = array_make(permanent_allocator(), 6); + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); args[2] = lb_const_int(p->module, t_i32, pos.line); args[3] = lb_const_int(p->module, t_i32, pos.column); - args[4] = lb_typeid(p->module, src_type); - args[5] = lb_typeid(p->module, dst_type); + if (!build_context.disallow_rtti) { + args[4] = lb_typeid(p->module, src_type); + args[5] = lb_typeid(p->module, dst_type); + } lb_emit_runtime_call(p, "type_assertion_check", args); } @@ -2831,6 +2840,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { } lbValue data_ptr = lb_emit_struct_ev(p, v, 0); if ((p->state_flags & StateFlag_no_type_assert) == 0) { + GB_ASSERT(!build_context.disallow_rtti); + lbValue any_id = lb_emit_struct_ev(p, v, 1); lbValue id = lb_typeid(p->module, type); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 1d6297164..1aac75f9c 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -14,6 +14,8 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr } lbValue lb_typeid(lbModule *m, Type *type) { + GB_ASSERT(!build_context.disallow_rtti); + type = default_type(type); u64 id = cast(u64)lb_type_info_index(m->info, type); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 98b7e07f0..fb52a9bd6 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -676,17 +676,24 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p // NOTE(bill): Panic on invalid conversion Type *dst_type = tuple->Tuple.variables[0]->type; + isize arg_count = 7; + if (build_context.disallow_rtti) { + arg_count = 4; + } + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), 7); + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); args[2] = lb_const_int(m, t_i32, pos.line); args[3] = lb_const_int(m, t_i32, pos.column); - args[4] = lb_typeid(m, src_type); - args[5] = lb_typeid(m, dst_type); - args[6] = lb_emit_conv(p, value_, t_rawptr); + if (!build_context.disallow_rtti) { + args[4] = lb_typeid(m, src_type); + args[5] = lb_typeid(m, dst_type); + args[6] = lb_emit_conv(p, value_, t_rawptr); + } lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); @@ -744,16 +751,23 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos if (!is_tuple) { // NOTE(bill): Panic on invalid conversion lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), 7); + + isize arg_count = 7; + if (build_context.disallow_rtti) { + arg_count = 4; + } + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); args[2] = lb_const_int(m, t_i32, pos.line); args[3] = lb_const_int(m, t_i32, pos.column); - args[4] = any_typeid; - args[5] = dst_typeid; - args[6] = lb_emit_struct_ev(p, value, 0);; + if (!build_context.disallow_rtti) { + args[4] = any_typeid; + args[5] = dst_typeid; + args[6] = lb_emit_struct_ev(p, value, 0); + } lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); diff --git a/src/main.cpp b/src/main.cpp index 8f4155d39..d2263f5a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -638,6 +638,7 @@ enum BuildFlagKind { BuildFlag_StrictStyle, BuildFlag_StrictStyleInitOnly, BuildFlag_ForeignErrorProcedures, + BuildFlag_DisallowRTTI, BuildFlag_Compact, BuildFlag_GlobalDefinitions, @@ -796,6 +797,9 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check); + + add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query); @@ -1390,6 +1394,9 @@ bool parse_build_flags(Array args) { case BuildFlag_DisallowDo: build_context.disallow_do = true; break; + case BuildFlag_DisallowRTTI: + build_context.disallow_rtti = true; + break; case BuildFlag_DefaultToNilAllocator: build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true; break; From 882116e35819937206e14dbf02d1c9ad42037d93 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 14:00:44 +0000 Subject: [PATCH 0286/1052] Only allow `-disallow-rtti` on freestanding targets --- src/build_settings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b2d6c4f43..7beee8664 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1077,6 +1077,11 @@ void init_build_context(TargetMetrics *cross_target) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); + if (bc->disallow_rtti && bc->metrics.os != TargetOs_freestanding) { + gb_printf_err("-disallow-rtti is only allowed on freestanding targets\n"); + gb_exit(1); + } + #undef LINK_FLAG_X64 #undef LINK_FLAG_386 } From 2d89faa17cf88b76e183e35f4d50722271c76d20 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 14:35:38 +0000 Subject: [PATCH 0287/1052] Add extra checks for -disallow-rtti --- src/llvm_backend.cpp | 9 +++++++-- src/llvm_backend_type.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 04c3200f8..40c06c23a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -624,6 +624,9 @@ struct lbGlobalVariable { }; lbProcedure *lb_create_startup_type_info(lbModule *m) { + if (build_context.disallow_rtti) { + return nullptr; + } LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); @@ -711,7 +714,9 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_begin_procedure_body(p); - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + if (startup_type_info) { + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + } if (objc_names) { LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); @@ -1394,7 +1399,7 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Global Variables"); - { + if (!build_context.disallow_rtti) { lbModule *m = default_module; { // Add type info data diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 1aac75f9c..e245a8b40 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -90,6 +90,8 @@ lbValue lb_typeid(lbModule *m, Type *type) { } lbValue lb_type_info(lbModule *m, Type *type) { + GB_ASSERT(!build_context.disallow_rtti); + type = default_type(type); isize index = lb_type_info_index(m->info, type); @@ -108,6 +110,8 @@ lbValue lb_type_info(lbModule *m, Type *type) { } lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { + GB_ASSERT(!build_context.disallow_rtti); + i32 index = cast(i32)lb_type_info_index(m->info, type); GB_ASSERT(index >= 0); // gb_printf_err("%d %s\n", index, type_to_string(type)); @@ -157,6 +161,10 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) { void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data + if (build_context.disallow_rtti) { + return; + } + lbModule *m = p->module; CheckerInfo *info = m->info; From 09e4fff5b18a314876c5f5d79f01cdd90aed7362 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 15:08:50 +0000 Subject: [PATCH 0288/1052] `-target-features:` This just passes a string directly to the LLVM features string --- src/build_settings.cpp | 1 + src/llvm_backend.cpp | 4 ++++ src/main.cpp | 10 +++++++++- src/string.cpp | 8 -------- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 7beee8664..e94fade4e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -232,6 +232,7 @@ struct BuildContext { String extra_linker_flags; String extra_assembler_flags; String microarch; + String target_features; BuildModeKind build_mode; bool generate_docs; i32 optimization_level; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 40c06c23a..ed3ae7dfc 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1298,6 +1298,10 @@ void lb_generate_code(lbGenerator *gen) { } } + if (build_context.target_features.len != 0) { + llvm_features = alloc_cstring(permanent_allocator(), build_context.target_features); + } + // GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target)); LLVMCodeGenOptLevel code_gen_level = LLVMCodeGenLevelNone; diff --git a/src/main.cpp b/src/main.cpp index d2263f5a7..5a77e09d8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -626,6 +626,7 @@ enum BuildFlagKind { BuildFlag_ExtraLinkerFlags, BuildFlag_ExtraAssemblerFlags, BuildFlag_Microarch, + BuildFlag_TargetFeatures, BuildFlag_RelocMode, BuildFlag_DisableRedZone, @@ -783,7 +784,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); @@ -1351,6 +1353,12 @@ bool parse_build_flags(Array args) { string_to_lower(&build_context.microarch); break; } + case BuildFlag_TargetFeatures: { + GB_ASSERT(value.kind == ExactValue_String); + build_context.target_features = value.value_string; + string_to_lower(&build_context.target_features); + break; + } case BuildFlag_RelocMode: { GB_ASSERT(value.kind == ExactValue_String); String v = value.value_string; diff --git a/src/string.cpp b/src/string.cpp index bcaf23b9b..d3dbc6904 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -10,10 +10,6 @@ struct String { u8 * text; isize len; - // u8 &operator[](isize i) { - // GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); - // return text[i]; - // } u8 const &operator[](isize i) const { GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); return text[i]; @@ -33,10 +29,6 @@ struct String { struct String16 { wchar_t *text; isize len; - wchar_t &operator[](isize i) { - GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); - return text[i]; - } wchar_t const &operator[](isize i) const { GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); return text[i]; From 15d783e920abd0cabb918eed4a982efe577bfe54 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 15:13:41 +0000 Subject: [PATCH 0289/1052] Enforce `-no-entry-point` on freestanding targets --- src/build_settings.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index e94fade4e..c94f914dc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1006,12 +1006,20 @@ void init_build_context(TargetMetrics *cross_target) { #endif if (bc->disable_red_zone) { - if (!(bc->metrics.os == TargetOs_freestanding && !is_arch_wasm())) { + if (!!is_arch_wasm() && bc->metrics.os == TargetOs_freestanding) { gb_printf_err("-disable-red-zone is not support for this target"); gb_exit(1); } } + if (bc->metrics.os == TargetOs_freestanding) { + bc->no_entry_point = true; + } else { + if (bc->disallow_rtti) { + gb_printf_err("-disallow-rtti is only allowed on freestanding targets\n"); + gb_exit(1); + } + } // NOTE(zangent): The linker flags to set the build architecture are different // across OSs. It doesn't make sense to allocate extra data on the heap @@ -1063,14 +1071,14 @@ void init_build_context(TargetMetrics *cross_target) { if (bc->metrics.arch == TargetArch_wasm64) { link_flags = gb_string_appendc(link_flags, "-mwas64 "); } - if (bc->metrics.os == TargetOs_freestanding) { + if (bc->no_entry_point) { link_flags = gb_string_appendc(link_flags, "--no-entry "); } bc->link_flags = make_string_c(link_flags); // Disallow on wasm - build_context.use_separate_modules = false; + bc->use_separate_modules = false; } else { gb_printf_err("Compiler Error: Unsupported architecture\n"); gb_exit(1); @@ -1078,10 +1086,7 @@ void init_build_context(TargetMetrics *cross_target) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); - if (bc->disallow_rtti && bc->metrics.os != TargetOs_freestanding) { - gb_printf_err("-disallow-rtti is only allowed on freestanding targets\n"); - gb_exit(1); - } + #undef LINK_FLAG_X64 #undef LINK_FLAG_386 From f76f70c7cf369a7e247a52e0c36da2fbe8d960c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Mon, 28 Feb 2022 15:24:22 +0000 Subject: [PATCH 0290/1052] openbsd: defaults to PIE executable OpenBSD uses PIE code by default to allow the system to load the binary at a random location. don't pass -no-pie to preserve this behaviour, and build objects with -fPIC (LLVMRelocPIC). --- src/llvm_backend.cpp | 5 +++++ src/main.cpp | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 52c46cadc..3b11f95a2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1295,6 +1295,11 @@ void lb_generate_code(lbGenerator *gen) { reloc_mode = LLVMRelocPIC; } + if (build_context.metrics.os == TargetOs_openbsd) { + // Always use PIC for OpenBSD: it defaults to PIE + reloc_mode = LLVMRelocPIC; + } + for_array(i, gen->modules.entries) { target_machines[i] = LLVMCreateTargetMachine( target, target_triple, llvm_cpu, diff --git a/src/main.cpp b/src/main.cpp index c738b860d..f8a3e6f85 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -463,7 +463,8 @@ i32 linker_stage(lbGenerator *gen) { #endif link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); - } else { + } else if (build_context.metrics.os != TargetOs_openbsd) { + // OpenBSD defaults to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } if (build_context.out_filepath.len > 0) { From 4f3b5d8dcb3be98d7b11efd49f3aec758e51bd2a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 15:29:08 +0000 Subject: [PATCH 0291/1052] Clean up `generate_minimum_dependency_set` code --- src/checker.cpp | 75 +++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index e6445d752..660691276 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2204,21 +2204,25 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { ptr_set_init(&c->info.minimum_dependency_set, heap_allocator(), min_dep_set_cap); ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator()); - String required_runtime_entities[] = { +#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \ + if (condition) { \ + String entities[] = {__VA_ARGS__}; \ + for (isize i = 0; i < gb_count_of(entities); i++) { \ + force_add_dependency_entity(c, c->info.runtime_package->scope, entities[i]); \ + } \ + } \ +} while (0) + + // required runtime entities + FORCE_ADD_RUNTIME_ENTITIES(true, // Odin types - str_lit("Type_Info"), str_lit("Source_Code_Location"), str_lit("Context"), str_lit("Allocator"), str_lit("Logger"), - // Global variables - str_lit("args__"), - str_lit("type_table"), - // Odin internal procedures str_lit("__init_context"), - str_lit("__type_info_of"), str_lit("cstring_to_string"), str_lit("_cleanup_runtime"), @@ -2251,35 +2255,36 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { // WASM Specific str_lit("__ashlti3"), str_lit("__multi3"), - }; - for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { - force_add_dependency_entity(c, c->info.runtime_package->scope, required_runtime_entities[i]); - } + ); - if (build_context.no_crt) { - String required_no_crt_entities[] = { - // NOTE(bill): Only if these exist - str_lit("_tls_index"), - str_lit("_fltused"), - }; - for (isize i = 0; i < gb_count_of(required_no_crt_entities); i++) { - force_add_dependency_entity(c, c->info.runtime_package->scope, required_no_crt_entities[i]); - } - } + FORCE_ADD_RUNTIME_ENTITIES(!build_context.disallow_rtti, + // Odin types + str_lit("Type_Info"), - if (!build_context.no_bounds_check) { - String bounds_check_entities[] = { - // Bounds checking related procedures - str_lit("bounds_check_error"), - str_lit("matrix_bounds_check_error"), - str_lit("slice_expr_error_hi"), - str_lit("slice_expr_error_lo_hi"), - str_lit("multi_pointer_slice_expr_error"), - }; - for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) { - force_add_dependency_entity(c, c->info.runtime_package->scope, bounds_check_entities[i]); - } - } + // Global variables + str_lit("type_table"), + str_lit("__type_info_of"), + ); + + FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_entry_point, + // Global variables + str_lit("args__"), + ); + + FORCE_ADD_RUNTIME_ENTITIES(build_context.no_crt, + // NOTE(bill): Only if these exist + str_lit("_tls_index"), + str_lit("_fltused"), + ); + + FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_bounds_check, + // Bounds checking related procedures + str_lit("bounds_check_error"), + str_lit("matrix_bounds_check_error"), + str_lit("slice_expr_error_hi"), + str_lit("slice_expr_error_lo_hi"), + str_lit("multi_pointer_slice_expr_error"), + ); for_array(i, c->info.definitions) { Entity *e = c->info.definitions[i]; @@ -2401,6 +2406,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { start->flags |= EntityFlag_Used; add_dependency_to_set(c, start); } + +#undef FORCE_ADD_RUNTIME_ENTITIES } bool is_entity_a_dependency(Entity *e) { From fc4eb4152cd9e95ee1e020d60f89a2e245e8febe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 15:35:10 +0000 Subject: [PATCH 0292/1052] Correct calling convention for `_startup_runtime` --- core/runtime/core.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 83a5418ed..3f6b03107 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -451,7 +451,7 @@ Odin_Endian_Type :: type_of(ODIN_ENDIAN) // This is probably only useful for freestanding targets foreign { @(link_name="__$startup_runtime") - _startup_runtime :: proc() --- + _startup_runtime :: proc "odin" () --- } @(link_name="__$cleanup_runtime") From 0ae012ba08c1981952dc508ab2b6244331926ba1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 15:37:15 +0000 Subject: [PATCH 0293/1052] Correct comment --- src/check_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index ff2c3d6a6..ecb2c26ea 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2174,7 +2174,7 @@ void init_map_entry_type(Type *type) { /* struct { - hash: runtime.Map_Hash, + hash: uintptr, next: int, key: Key, value: Value, From 410b85b5c7f768543e03c9fc6f47f8c2efcd602b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 15:40:00 +0000 Subject: [PATCH 0294/1052] Disallow `@(thread_local)` on wasm targets --- src/check_decl.cpp | 4 ++++ src/check_stmt.cpp | 5 ++++- src/checker.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index b3b1e4474..12b0e43cb 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1130,6 +1130,10 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, } ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix); + if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { + error(e->token, "@(thread_local) is not supported for this target platform"); + } + String context_name = str_lit("variable declaration"); if (type_expr != nullptr) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 7cae1893f..f2c830c1b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2152,7 +2152,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { e->state = EntityState_Resolved; } ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix); - e->Variable.thread_local_model = ac.thread_local_model; if (ac.link_name.len > 0) { e->Variable.link_name = ac.link_name; @@ -2182,6 +2181,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } e->Variable.thread_local_model = ac.thread_local_model; } + + if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { + error(e->token, "@(thread_local) is not supported for this target platform"); + } if (ac.is_static && ac.thread_local_model != "") { diff --git a/src/checker.cpp b/src/checker.cpp index 660691276..b1abdcb8a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2271,7 +2271,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("args__"), ); - FORCE_ADD_RUNTIME_ENTITIES(build_context.no_crt, + FORCE_ADD_RUNTIME_ENTITIES((build_context.no_crt && !is_arch_wasm()), // NOTE(bill): Only if these exist str_lit("_tls_index"), str_lit("_fltused"), From cba3f1e374d6e41e41df8a659667049a22301133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Mon, 28 Feb 2022 16:17:14 +0000 Subject: [PATCH 0295/1052] ENet: add openbsd support --- vendor/ENet/unix.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/ENet/unix.odin b/vendor/ENet/unix.odin index ea6b84199..a86e9837c 100644 --- a/vendor/ENet/unix.odin +++ b/vendor/ENet/unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package ENet // When we implement the appropriate bindings for Unix, the section separated @@ -56,4 +56,4 @@ SOCKETSET_REMOVE :: #force_inline proc(sockset: ^SocketSet, socket: Socket) { SOCKSET_CHECK :: #force_inline proc(sockset: ^SocketSet, socket: Socket) -> bool { return FD_ISSET(i32(socket), cast(^fd_set)sockset) -} \ No newline at end of file +} From 737f440c7f835f400d616fff62f11afef38d7bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Mon, 28 Feb 2022 16:17:14 +0000 Subject: [PATCH 0296/1052] glfw: add openbsd support --- vendor/glfw/bindings/bindings.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index f4e39015e..fa9ef0776 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -5,6 +5,7 @@ import vk "vendor:vulkan" when ODIN_OS == .Linux { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux when ODIN_OS == .Darwin { foreign import glfw "system:glfw" } +when ODIN_OS == .OpenBSD { foreign import glfw "system:glfw" } when ODIN_OS == .Windows { foreign import glfw { "../lib/glfw3_mt.lib", From 37b4e0de6c80caeb78629a2a1a3d94bf1ed6df6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Mon, 28 Feb 2022 16:17:15 +0000 Subject: [PATCH 0297/1052] sdl2: add openbsd support --- vendor/sdl2/image/sdl_image.odin | 3 ++- vendor/sdl2/mixer/sdl_mixer.odin | 2 +- vendor/sdl2/net/sdl_net.odin | 3 ++- vendor/sdl2/sdl2.odin | 3 ++- vendor/sdl2/sdl_audio.odin | 1 + vendor/sdl2/sdl_blendmode.odin | 3 ++- vendor/sdl2/sdl_cpuinfo.odin | 3 ++- vendor/sdl2/sdl_events.odin | 3 ++- vendor/sdl2/sdl_gamecontroller.odin | 1 + vendor/sdl2/sdl_gesture_haptic.odin | 3 ++- vendor/sdl2/sdl_hints.odin | 3 ++- vendor/sdl2/sdl_joystick.odin | 3 ++- vendor/sdl2/sdl_keyboard.odin | 1 + vendor/sdl2/sdl_log.odin | 3 ++- vendor/sdl2/sdl_messagebox.odin | 1 + vendor/sdl2/sdl_metal.odin | 3 ++- vendor/sdl2/sdl_mouse.odin | 3 ++- vendor/sdl2/sdl_mutex.odin | 3 ++- vendor/sdl2/sdl_pixels.odin | 3 ++- vendor/sdl2/sdl_rect.odin | 3 ++- vendor/sdl2/sdl_render.odin | 3 ++- vendor/sdl2/sdl_rwops.odin | 3 ++- vendor/sdl2/sdl_stdinc.odin | 3 ++- vendor/sdl2/sdl_surface.odin | 3 ++- vendor/sdl2/sdl_system.odin | 3 ++- vendor/sdl2/sdl_syswm.odin | 3 ++- vendor/sdl2/sdl_thread.odin | 1 + vendor/sdl2/sdl_timer.odin | 3 ++- vendor/sdl2/sdl_touch.odin | 3 ++- vendor/sdl2/sdl_video.odin | 3 ++- vendor/sdl2/sdl_vulkan.odin | 3 ++- vendor/sdl2/ttf/sdl_ttf.odin | 3 ++- 32 files changed, 58 insertions(+), 27 deletions(-) diff --git a/vendor/sdl2/image/sdl_image.odin b/vendor/sdl2/image/sdl_image.odin index 30a7db6a8..ad939a63a 100644 --- a/vendor/sdl2/image/sdl_image.odin +++ b/vendor/sdl2/image/sdl_image.odin @@ -7,6 +7,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2_image.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2_image" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2_image" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_image" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_image" } bool :: SDL.bool @@ -119,4 +120,4 @@ foreign lib { /* Individual loading functions */ LoadGIFAnimation_RW :: proc(src: ^SDL.RWops) -> ^Animation --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/mixer/sdl_mixer.odin b/vendor/sdl2/mixer/sdl_mixer.odin index 7fa3f216f..ad7670598 100644 --- a/vendor/sdl2/mixer/sdl_mixer.odin +++ b/vendor/sdl2/mixer/sdl_mixer.odin @@ -7,7 +7,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2_mixer.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2_mixer" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2_mixer" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_mixer" } - +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_mixer" } MAJOR_VERSION :: 2 MINOR_VERSION :: 0 diff --git a/vendor/sdl2/net/sdl_net.odin b/vendor/sdl2/net/sdl_net.odin index b3e2c2e62..4aafe0bcf 100644 --- a/vendor/sdl2/net/sdl_net.odin +++ b/vendor/sdl2/net/sdl_net.odin @@ -7,6 +7,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2_net.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2_net" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2_net" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_net" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_net" } bool :: SDL.bool @@ -188,4 +189,4 @@ Read16 :: #force_inline proc "c" (areap: rawptr) -> u16 { Read32 :: #force_inline proc "c" (areap: rawptr) -> u32 { area := (^[4]u8)(areap) return u32(area[0])<<24 | u32(area[1])<<16 | u32(area[2])<<8 | u32(area[3]) -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl2.odin b/vendor/sdl2/sdl2.odin index e36c002dd..c270fc52f 100644 --- a/vendor/sdl2/sdl2.odin +++ b/vendor/sdl2/sdl2.odin @@ -29,6 +29,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } version :: struct { major: u8, /**< major version */ @@ -314,4 +315,4 @@ foreign lib { IsShapedWindow :: proc(window: ^Window) -> bool --- SetWindowShape :: proc(window: ^Window, shape: ^Surface, shape_mode: ^WindowShapeMode) -> c.int --- GetShapedWindowMode :: proc(window: ^Window, shape_mode: ^WindowShapeMode) -> c.int --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_audio.odin b/vendor/sdl2/sdl_audio.odin index a03031165..686f1994a 100644 --- a/vendor/sdl2/sdl_audio.odin +++ b/vendor/sdl2/sdl_audio.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } /** * \brief Audio format flags. diff --git a/vendor/sdl2/sdl_blendmode.odin b/vendor/sdl2/sdl_blendmode.odin index 525cf0f38..19e4b37aa 100644 --- a/vendor/sdl2/sdl_blendmode.odin +++ b/vendor/sdl2/sdl_blendmode.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } /** * \brief The blend mode used in SDL_RenderCopy() and drawing operations. @@ -62,4 +63,4 @@ BlendFactor :: enum c.int { foreign lib { ComposeCustomBlendMode :: proc(srcColorFactor, dstColorFactor: BlendFactor, colorOperation: BlendOperation, srcAlphaFactor, dstAlphaFactor: BlendFactor, alphaOperation: BlendOperation) -> BlendMode --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_cpuinfo.odin b/vendor/sdl2/sdl_cpuinfo.odin index 7d2e681fe..01a8d203a 100644 --- a/vendor/sdl2/sdl_cpuinfo.odin +++ b/vendor/sdl2/sdl_cpuinfo.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } /* This is a guess for the cacheline size used for padding. * Most x86 processors have a 64 byte cache line. @@ -41,4 +42,4 @@ foreign lib { SIMDAlloc :: proc(len: c.size_t) -> rawptr --- SIMDRealloc :: proc(mem: rawptr, len: c.size_t) -> rawptr --- SIMDFree :: proc(ptr: rawptr) --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_events.odin b/vendor/sdl2/sdl_events.odin index 3f58b51c3..45f9886a5 100644 --- a/vendor/sdl2/sdl_events.odin +++ b/vendor/sdl2/sdl_events.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } RELEASED :: 0 PRESSED :: 1 @@ -498,4 +499,4 @@ foreign lib { FilterEvents :: proc(filter: EventFilter, userdata: rawptr) --- EventState :: proc(type: EventType, state: c.int) -> u8 --- RegisterEvents :: proc(numevents: c.int) -> u32 --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_gamecontroller.odin b/vendor/sdl2/sdl_gamecontroller.odin index 9fef6b1ab..8c15cd779 100644 --- a/vendor/sdl2/sdl_gamecontroller.odin +++ b/vendor/sdl2/sdl_gamecontroller.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } GameController :: struct {} diff --git a/vendor/sdl2/sdl_gesture_haptic.odin b/vendor/sdl2/sdl_gesture_haptic.odin index 1c8616e99..961ae6ea6 100644 --- a/vendor/sdl2/sdl_gesture_haptic.odin +++ b/vendor/sdl2/sdl_gesture_haptic.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } // Gesture @@ -259,4 +260,4 @@ foreign lib { HapticRumbleInit :: proc(haptic: ^Haptic) -> c.int --- HapticRumblePlay :: proc(haptic: ^Haptic, strength: f32, length: u32) -> c.int --- HapticRumbleStop :: proc(haptic: ^Haptic) -> c.int --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_hints.odin b/vendor/sdl2/sdl_hints.odin index a84e5a090..150c8bcc6 100644 --- a/vendor/sdl2/sdl_hints.odin +++ b/vendor/sdl2/sdl_hints.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } HINT_ACCELEROMETER_AS_JOYSTICK :: "SDL_ACCELEROMETER_AS_JOYSTICK" HINT_ALLOW_ALT_TAB_WHILE_GRABBED :: "SDL_ALLOW_ALT_TAB_WHILE_GRABBED" @@ -146,4 +147,4 @@ foreign lib { AddHintCallback :: proc(name: cstring, callback: HintCallback, userdata: rawptr) --- DelHintCallback :: proc(name: cstring, callback: HintCallback, userdata: rawptr) --- ClearHints :: proc() --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_joystick.odin b/vendor/sdl2/sdl_joystick.odin index 1178eae24..f190c13e4 100644 --- a/vendor/sdl2/sdl_joystick.odin +++ b/vendor/sdl2/sdl_joystick.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } Joystick :: struct {} @@ -106,4 +107,4 @@ foreign lib { JoystickSendEffect :: proc(joystick: ^Joystick, data: rawptr, size: c.int) -> c.int --- JoystickClose :: proc(joystick: ^Joystick) --- JoystickCurrentPowerLevel :: proc(joystick: ^Joystick) -> JoystickPowerLevel --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_keyboard.odin b/vendor/sdl2/sdl_keyboard.odin index a68c644ab..abc6bb838 100644 --- a/vendor/sdl2/sdl_keyboard.odin +++ b/vendor/sdl2/sdl_keyboard.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } Keysym :: struct { scancode: Scancode, /**< SDL physical key code - see ::SDL_Scancode for details */ diff --git a/vendor/sdl2/sdl_log.odin b/vendor/sdl2/sdl_log.odin index d42d82b77..a496f5fbe 100644 --- a/vendor/sdl2/sdl_log.odin +++ b/vendor/sdl2/sdl_log.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } MAX_LOG_MESSAGE :: 4096 @@ -74,4 +75,4 @@ foreign lib { // LogMessageV :: proc(category: c.int, priority: LogPriority, fmt: cstring, ap: va_list) --- LogGetOutputFunction :: proc(callback: ^LogOutputFunction, userdata: ^rawptr) --- LogSetOutputFunction :: proc(callback: LogOutputFunction, userdata: rawptr) --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_messagebox.odin b/vendor/sdl2/sdl_messagebox.odin index c66cc4911..e14cc5463 100644 --- a/vendor/sdl2/sdl_messagebox.odin +++ b/vendor/sdl2/sdl_messagebox.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } MessageBoxFlag :: enum u32 { _ = 0, diff --git a/vendor/sdl2/sdl_metal.odin b/vendor/sdl2/sdl_metal.odin index 953c6d45f..c297113c6 100644 --- a/vendor/sdl2/sdl_metal.odin +++ b/vendor/sdl2/sdl_metal.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } MetalView :: distinct rawptr @@ -15,4 +16,4 @@ foreign lib { Metal_DestroyView :: proc(view: MetalView) --- Metal_GetLayer :: proc(view: MetalView) -> rawptr --- Metal_GetDrawableSize :: proc(window: ^Window, w, h: ^c.int) --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_mouse.odin b/vendor/sdl2/sdl_mouse.odin index 5ca8d9b5e..56478b6fb 100644 --- a/vendor/sdl2/sdl_mouse.odin +++ b/vendor/sdl2/sdl_mouse.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } Cursor :: struct {} @@ -61,4 +62,4 @@ foreign lib { GetDefaultCursor :: proc() -> ^Cursor --- FreeCursor :: proc(cursor: ^Cursor) --- ShowCursor :: proc(toggle: c.int) -> c.int --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_mutex.odin b/vendor/sdl2/sdl_mutex.odin index 6b9c96319..2ce004b52 100644 --- a/vendor/sdl2/sdl_mutex.odin +++ b/vendor/sdl2/sdl_mutex.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } MUTEX_TIMEDOUT :: 1 MUTEX_MAXWAIT :: ~u32(0) @@ -41,4 +42,4 @@ foreign lib { CondBroadcast :: proc(cv: ^cond) -> c.int --- CondWait :: proc(cv: ^cond, m: ^mutex) -> c.int --- CondWaitTimeout :: proc(cv: ^cond, m: ^mutex, ms: u32) -> c.int --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_pixels.odin b/vendor/sdl2/sdl_pixels.odin index 3cd2da5f4..34ff23b14 100644 --- a/vendor/sdl2/sdl_pixels.odin +++ b/vendor/sdl2/sdl_pixels.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } ALPHA_OPAQUE :: 255 ALPHA_TRANSPARENT :: 0 @@ -234,4 +235,4 @@ foreign lib { GetRGB :: proc(pixel: u32, format: ^PixelFormat, r, g, b: ^u8) --- GetRGBA :: proc(pixel: u32, format: ^PixelFormat, r, g, b, a: ^u8) --- CalculateGammaRamp :: proc(gamma: f32, ramp: ^[256]u16) --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_rect.odin b/vendor/sdl2/sdl_rect.odin index b0d6242be..fdf18aa65 100644 --- a/vendor/sdl2/sdl_rect.odin +++ b/vendor/sdl2/sdl_rect.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } Point :: struct { x: c.int, @@ -47,4 +48,4 @@ foreign lib { UnionRect :: proc(A, B: ^Rect, result: ^Rect) --- EnclosePoints :: proc(points: [^]Point, count: c.int, clip: ^Rect, result: ^Rect) -> bool --- IntersectRectAndLine :: proc(rect: ^Rect, X1, Y1, X2, Y2: ^c.int) -> bool --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_render.odin b/vendor/sdl2/sdl_render.odin index 435c40570..dd599f669 100644 --- a/vendor/sdl2/sdl_render.odin +++ b/vendor/sdl2/sdl_render.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } RendererFlag :: enum u32 { SOFTWARE = 0, /**< The renderer is a software fallback */ @@ -140,4 +141,4 @@ foreign lib { GL_UnbindTexture :: proc(texture: ^Texture) -> c.int --- RenderGetMetalLayer :: proc(renderer: ^Renderer) -> rawptr --- RenderGetMetalCommandEncoder :: proc(renderer: ^Renderer) -> rawptr --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_rwops.odin b/vendor/sdl2/sdl_rwops.odin index 3bee66290..fd7abc0c4 100644 --- a/vendor/sdl2/sdl_rwops.odin +++ b/vendor/sdl2/sdl_rwops.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } /* RWops Types */ RWOPS_UNKNOWN :: 0 /**< Unknown stream type */ @@ -105,4 +106,4 @@ foreign lib { WriteBE32 :: proc(dst: ^RWops, value: ^u32) -> c.size_t --- WriteLE64 :: proc(dst: ^RWops, value: ^u64) -> c.size_t --- WriteBE64 :: proc(dst: ^RWops, value: ^u64) -> c.size_t --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_stdinc.odin b/vendor/sdl2/sdl_stdinc.odin index 9bd5df4da..15446eb71 100644 --- a/vendor/sdl2/sdl_stdinc.odin +++ b/vendor/sdl2/sdl_stdinc.odin @@ -9,6 +9,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } bool :: distinct b32 #assert(size_of(bool) == size_of(c.int)) @@ -160,4 +161,4 @@ iconv_utf8_ucs2 :: proc "c" (s: string) -> [^]u16 { iconv_utf8_utf32 :: iconv_utf8_ucs4 iconv_utf8_ucs4 :: proc "c" (s: string) -> [^]rune { return cast([^]rune)iconv_string("UCS-4-INTERNAL", "UTF-8", cstring(raw_data(s)), len(s)+1) -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_surface.odin b/vendor/sdl2/sdl_surface.odin index e5a5da7ef..82545f1f9 100644 --- a/vendor/sdl2/sdl_surface.odin +++ b/vendor/sdl2/sdl_surface.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } SWSURFACE :: 0 /**< Just here for compatibility */ PREALLOC :: 0x00000001 /**< Surface uses preallocated memory */ @@ -108,4 +109,4 @@ foreign lib { SetYUVConversionMode :: proc(mode: YUV_CONVERSION_MODE) --- GetYUVConversionMode :: proc() -> YUV_CONVERSION_MODE --- GetYUVConversionModeForResolution :: proc(width, height: c.int) -> YUV_CONVERSION_MODE --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_system.odin b/vendor/sdl2/sdl_system.odin index 89ae4c707..cd08cfc47 100644 --- a/vendor/sdl2/sdl_system.odin +++ b/vendor/sdl2/sdl_system.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } // General @(default_calling_convention="c", link_prefix="SDL_") @@ -122,4 +123,4 @@ foreign lib { AndroidGetExternalStoragePath :: proc() -> cstring --- AndroidRequestPermission :: proc(permission: cstring) -> bool --- AndroidShowToast :: proc(message: cstring, duration, gravity, xoffset, yoffset: c.int) -> c.int --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_syswm.odin b/vendor/sdl2/sdl_syswm.odin index 37da1d298..f2b52529f 100644 --- a/vendor/sdl2/sdl_syswm.odin +++ b/vendor/sdl2/sdl_syswm.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } SYSWM_TYPE :: enum c.int { UNKNOWN, @@ -105,4 +106,4 @@ SysWMinfo :: struct { @(default_calling_convention="c", link_prefix="SDL_") foreign lib { GetWindowWMInfo :: proc(window: ^Window, info: ^SysWMinfo) -> bool --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_thread.odin b/vendor/sdl2/sdl_thread.odin index 98354438b..0d9d66d30 100644 --- a/vendor/sdl2/sdl_thread.odin +++ b/vendor/sdl2/sdl_thread.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } Thread :: struct {} diff --git a/vendor/sdl2/sdl_timer.odin b/vendor/sdl2/sdl_timer.odin index 357fdd437..13003b5b3 100644 --- a/vendor/sdl2/sdl_timer.odin +++ b/vendor/sdl2/sdl_timer.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } TimerCallback :: proc "c" (interval: u32, param: rawptr) -> u32 TimerID :: distinct c.int @@ -22,4 +23,4 @@ foreign lib { Delay :: proc(ms: u32) --- AddTimer :: proc(interval: u32, callback: TimerCallback, param: rawptr) -> TimerID --- RemoveTimer :: proc(id: TimerID) -> bool --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_touch.odin b/vendor/sdl2/sdl_touch.odin index d90939cb9..ffb91328a 100644 --- a/vendor/sdl2/sdl_touch.odin +++ b/vendor/sdl2/sdl_touch.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } TouchID :: distinct i64 FingerID :: distinct i64 @@ -34,4 +35,4 @@ foreign lib { GetTouchDeviceType :: proc(touchID: TouchID) -> TouchDeviceType --- GetNumTouchFingers :: proc(touchID: TouchID) -> c.int --- GetTouchFinger :: proc(touchID: TouchID, index: c.int) -> ^Finger --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_video.odin b/vendor/sdl2/sdl_video.odin index 01aaee1e7..d050e272d 100644 --- a/vendor/sdl2/sdl_video.odin +++ b/vendor/sdl2/sdl_video.odin @@ -6,6 +6,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } DisplayMode :: struct { format: u32, /**< pixel format */ @@ -310,4 +311,4 @@ foreign lib { // Used by vendor:OpenGL gl_set_proc_address :: proc(p: rawptr, name: cstring) { (^rawptr)(p)^ = GL_GetProcAddress(name) -} \ No newline at end of file +} diff --git a/vendor/sdl2/sdl_vulkan.odin b/vendor/sdl2/sdl_vulkan.odin index 66b054524..13e25f8c2 100644 --- a/vendor/sdl2/sdl_vulkan.odin +++ b/vendor/sdl2/sdl_vulkan.odin @@ -7,6 +7,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } VkInstance :: vk.Instance VkSurfaceKHR :: vk.SurfaceKHR @@ -22,4 +23,4 @@ foreign lib { Vulkan_GetInstanceExtensions :: proc(window: ^Window, pCount: ^c.uint, pNames: [^]cstring) -> bool --- Vulkan_CreateSurface :: proc(window: ^Window, instance: VkInstance, surface: ^VkSurfaceKHR) -> bool --- Vulkan_GetDrawableSize :: proc(window: ^Window, w, h: ^c.int) --- -} \ No newline at end of file +} diff --git a/vendor/sdl2/ttf/sdl_ttf.odin b/vendor/sdl2/ttf/sdl_ttf.odin index 8cd1df505..e84c89136 100644 --- a/vendor/sdl2/ttf/sdl_ttf.odin +++ b/vendor/sdl2/ttf/sdl_ttf.odin @@ -7,6 +7,7 @@ when ODIN_OS == .Windows { foreign import lib "SDL2_ttf.lib" } when ODIN_OS == .Linux { foreign import lib "system:SDL2_ttf" } when ODIN_OS == .Darwin { foreign import lib "system:SDL2_ttf" } when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_ttf" } +when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_ttf" } bool :: SDL.bool @@ -163,4 +164,4 @@ foreign lib { SetFontSDF :: proc(font: ^Font, on_off: bool) -> c.int --- GetFontSDF :: proc(font: ^Font) -> bool --- -} \ No newline at end of file +} From d4ccb69ccc56fb57cad48493a9e5e78ca3529a84 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 21:49:19 +0000 Subject: [PATCH 0298/1052] Check if directory exists with the same target executable name when building a directory --- src/parser.cpp | 16 ++++++++++++++++ src/parser.hpp | 1 + 2 files changed, 17 insertions(+) diff --git a/src/parser.cpp b/src/parser.cpp index 9659e8c18..f70afe346 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5719,6 +5719,22 @@ ParseFileError parse_packages(Parser *p, String init_filename) { error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); return ParseFile_WrongExtension; } + } else if (init_fullpath.len != 0) { + String path = init_fullpath; + if (path[path.len-1] == '/') { + path.len -= 1; + } + if ((build_context.command_kind & Command__does_build) && + build_context.build_mode == BuildMode_Executable) { + String short_path = filename_from_path(path); + char *cpath = alloc_cstring(heap_allocator(), short_path); + defer (gb_free(heap_allocator(), cpath)); + + if (gb_file_exists(cpath)) { + error_line("Please specify the executable name with -out: as a directory exists with the same name in the current working directory"); + return ParseFile_DirectoryAlreadyExists; + } + } } diff --git a/src/parser.hpp b/src/parser.hpp index f6791a291..c33d1520b 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -46,6 +46,7 @@ enum ParseFileError { ParseFile_InvalidToken, ParseFile_GeneralError, ParseFile_FileTooLarge, + ParseFile_DirectoryAlreadyExists, ParseFile_Count, }; From f971126183312f7229c24ea9fd7d36a6a7870404 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 1 Mar 2022 13:51:41 +0100 Subject: [PATCH 0299/1052] [mem] Add missing `\n` to tracking allocator example. --- core/mem/doc.odin | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/mem/doc.odin b/core/mem/doc.odin index 2a5ee06d3..fe53dee83 100644 --- a/core/mem/doc.odin +++ b/core/mem/doc.odin @@ -12,22 +12,22 @@ import "core:mem" import "core:fmt" _main :: proc() { - do stuff + do stuff } main :: proc() { - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) - _main() + _main() - for _, v in track.allocation_map { - fmt.printf("%v leaked %v bytes", v.location, v.size) - } - for bf in track.bad_free_array { - fmt.printf("%v allocation %p was freed badly", bf.location, bf.memory) - } + for _, leak in track.allocation_map { + fmt.printf("%v leaked %v bytes\n", leak.location, leak.size) + } + for bad_free in track.bad_free_array { + fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory) + } } ``` */ From 49fecbdc5e6579956346e484a418b9501dfddd71 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Mar 2022 14:49:05 +0000 Subject: [PATCH 0300/1052] Improve error message when there is "no field" found for a large anonymous struct --- src/check_builtin.cpp | 8 ++++---- src/check_expr.cpp | 8 ++++---- src/types.cpp | 39 ++++++++++++++++++++++++--------------- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 69cc40de8..aeeeb9e4d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1106,7 +1106,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "'%s' has no field named '%.*s'", type_str, LIT(field_name)); gb_string_free(type_str); @@ -1118,7 +1118,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } if (sel.indirect) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); gb_string_free(type_str); @@ -1179,7 +1179,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "'%s' has no field named '%.*s'", type_str, LIT(field_name)); gb_string_free(type_str); @@ -1191,7 +1191,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } if (sel.indirect) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); gb_string_free(type_str); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e07dc3d60..614da2368 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4470,7 +4470,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ if (entity == nullptr) { gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str); @@ -4511,7 +4511,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str); gb_string_free(sel_str); @@ -4536,7 +4536,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str); gb_string_free(sel_str); @@ -4549,7 +4549,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ if (expr_entity != nullptr && is_type_polymorphic(expr_entity->type)) { gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "Cannot access field '%s' from non-specialized polymorphic type '%s'", sel_str, op_str); gb_string_free(sel_str); diff --git a/src/types.cpp b/src/types.cpp index 74080334a..58ccdf5b9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -703,7 +703,7 @@ struct TypePath; i64 type_size_of (Type *t); i64 type_align_of (Type *t); i64 type_offset_of (Type *t, i32 index); -gbString type_to_string (Type *type); +gbString type_to_string (Type *type, bool shorthand=false); i64 type_size_of_internal(Type *t, TypePath *path); void init_map_internal_types(Type *type); Type * bit_set_to_int(Type *t); @@ -3936,7 +3936,7 @@ Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type -gbString write_type_to_string(gbString str, Type *type) { +gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { if (type == nullptr) { return gb_string_appendc(str, ""); } @@ -4051,15 +4051,21 @@ gbString write_type_to_string(gbString str, Type *type) { if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align); str = gb_string_appendc(str, " {"); - for_array(i, type->Struct.fields) { - Entity *f = type->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - str = gb_string_appendc(str, ", "); + + + if (shorthand && type->Struct.fields.count > 16) { + str = gb_string_append_fmt(str, "%lld fields...", cast(long long)type->Struct.fields.count); + } else { + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = gb_string_append_length(str, f->token.string.text, f->token.string.len); + str = gb_string_appendc(str, ": "); + str = write_type_to_string(str, f->type); } - str = gb_string_append_length(str, f->token.string.text, f->token.string.len); - str = gb_string_appendc(str, ": "); - str = write_type_to_string(str, f->type); } str = gb_string_append_rune(str, '}'); } break; @@ -4234,13 +4240,16 @@ gbString write_type_to_string(gbString str, Type *type) { } -gbString type_to_string(Type *type, gbAllocator allocator) { - return write_type_to_string(gb_string_make(allocator, ""), type); +gbString type_to_string(Type *type, gbAllocator allocator, bool shorthand=false) { + return write_type_to_string(gb_string_make(allocator, ""), type, shorthand); } -gbString type_to_string(Type *type) { - return write_type_to_string(gb_string_make(heap_allocator(), ""), type); +gbString type_to_string(Type *type, bool shorthand) { + return write_type_to_string(gb_string_make(heap_allocator(), ""), type, shorthand); +} + +gbString type_to_string_shorthand(Type *type) { + return type_to_string(type, true); } - From 18607e53cba060558b7618e2c12245b363ad2a7f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Mar 2022 15:38:04 +0000 Subject: [PATCH 0301/1052] Correct `alloc_from_memory_block` --- core/mem/virtual/virtual.odin | 40 ++++++++++++++++++-------- core/mem/virtual/virtual_platform.odin | 22 ++++++++++++-- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 38c654254..09d18b934 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -82,11 +82,13 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) pmblock := platform_memory_alloc(0, total_size) or_return pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset) - commit(pmblock.block.base, committed) or_return + commit_err := platform_memory_commit(pmblock, uint(base_offset) + committed) + assert(commit_err == nil) + // Should be zeroed assert(pmblock.block.used == 0) assert(pmblock.block.prev == nil) - if (do_protection) { + if do_protection { protect(rawptr(uintptr(pmblock) + protect_offset), page_size, Protect_No_Access) } @@ -115,23 +117,37 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) return alignment_offset } - + do_commit_if_necessary :: proc(block: ^Memory_Block, size: uint) -> (err: Allocator_Error) { + if block.committed - block.used < size { + pmblock := (^Platform_Memory_Block)(block) + base_offset := uint(uintptr(block) - uintptr(pmblock)) + platform_total_commit := base_offset + block.used + size + + assert(pmblock.committed <= pmblock.reserved) + assert(pmblock.committed < platform_total_commit) + + platform_memory_commit(pmblock, platform_total_commit) or_return + + pmblock.committed = platform_total_commit + block.committed = pmblock.committed - base_offset + } + return nil + } + + alignment_offset := calc_alignment_offset(block, uintptr(alignment)) - size := uint(min_size) + alignment_offset - + if block.used + size > block.reserved { err = .Out_Of_Memory return } - - ptr := block.base[block.used:] - ptr = ptr[alignment_offset:] - + assert(block.committed <= block.reserved) + do_commit_if_necessary(block, size) or_return + + data = block.base[block.used+alignment_offset:][:min_size] block.used += size - assert(block.used <= block.reserved) - - return ptr[:min_size], nil + return } diff --git a/core/mem/virtual/virtual_platform.odin b/core/mem/virtual/virtual_platform.odin index c4211ba5e..85caa6419 100644 --- a/core/mem/virtual/virtual_platform.odin +++ b/core/mem/virtual/virtual_platform.odin @@ -4,8 +4,9 @@ package mem_virtual import sync "core:sync/sync2" Platform_Memory_Block :: struct { - block: Memory_Block, - reserved: uint, + block: Memory_Block, + committed: uint, + reserved: uint, prev, next: ^Platform_Memory_Block, } @@ -20,7 +21,8 @@ platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_ commit(raw_data(data), to_commit) block = (^Platform_Memory_Block)(raw_data(data)) - block.reserved = to_reserve + block.committed = to_commit + block.reserved = to_reserve return } @@ -52,3 +54,17 @@ platform_memory_init :: proc() { global_platform_memory_block_sentinel_set = true } } + +platform_memory_commit :: proc(block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) { + if to_commit < block.committed { + return nil + } + if to_commit > block.reserved { + return .Out_Of_Memory + } + + + commit(block, to_commit) or_return + block.committed = to_commit + return nil +} From 7e5342f41fab561337ebd648407b753bd1813abf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Mar 2022 15:52:14 +0000 Subject: [PATCH 0302/1052] Use `contextless` where possible --- core/mem/virtual/virtual.odin | 14 +++++++------- core/mem/virtual/virtual_linux.odin | 10 +++++----- core/mem/virtual/virtual_platform.odin | 6 +++--- core/mem/virtual/virtual_windows.odin | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 09d18b934..2035171a7 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -6,25 +6,25 @@ DEFAULT_PAGE_SIZE := uint(4096) Allocator_Error :: mem.Allocator_Error -reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { +reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { return _reserve(size) } -commit :: proc(data: rawptr, size: uint) -> Allocator_Error { +commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { return _commit(data, size) } -reserve_and_commit :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { +reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { data = reserve(size) or_return commit(raw_data(data), size) or_return return } -decommit :: proc(data: rawptr, size: uint) { +decommit :: proc "contextless" (data: rawptr, size: uint) { _decommit(data, size) } -release :: proc(data: rawptr, size: uint) { +release :: proc "contextless" (data: rawptr, size: uint) { _release(data, size) } @@ -36,7 +36,7 @@ Protect_Flag :: enum u32 { Protect_Flags :: distinct bit_set[Protect_Flag; u32] Protect_No_Access :: Protect_Flags{} -protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool { +protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { return _protect(data, size, flags) } @@ -107,7 +107,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) } alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) { - calc_alignment_offset :: proc(block: ^Memory_Block, alignment: uintptr) -> uint { + calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint { alignment_offset := uint(0) ptr := uintptr(block.base[block.used:]) mask := alignment-1 diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin index 71a56e499..6ae926e47 100644 --- a/core/mem/virtual/virtual_linux.odin +++ b/core/mem/virtual/virtual_linux.odin @@ -58,7 +58,7 @@ madvise :: proc "contextless" (addr: rawptr, length: uint, advice: c.int) -> c.i } -_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { +_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { MAP_FAILED := rawptr(~uintptr(0)) result := mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) if result == MAP_FAILED { @@ -67,7 +67,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { return ([^]byte)(result)[:size], nil } -_commit :: proc(data: rawptr, size: uint) -> Allocator_Error { +_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { result := mprotect(data, size, PROT_READ|PROT_WRITE) if result != 0 { // TODO(bill): Handle error value correctly @@ -75,14 +75,14 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error { } return nil } -_decommit :: proc(data: rawptr, size: uint) { +_decommit :: proc "contextless" (data: rawptr, size: uint) { mprotect(data, size, PROT_NONE) madvise(data, size, MADV_FREE) } -_release :: proc(data: rawptr, size: uint) { +_release :: proc "contextless" (data: rawptr, size: uint) { munmap(data, size) } -_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool { +_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { pflags: c.int pflags = PROT_NONE if .Read in flags { pflags |= PROT_READ } diff --git a/core/mem/virtual/virtual_platform.odin b/core/mem/virtual/virtual_platform.odin index 85caa6419..d707bc427 100644 --- a/core/mem/virtual/virtual_platform.odin +++ b/core/mem/virtual/virtual_platform.odin @@ -10,7 +10,7 @@ Platform_Memory_Block :: struct { prev, next: ^Platform_Memory_Block, } -platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) { +platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) { to_commit, to_reserve := to_commit, to_reserve to_reserve = max(to_commit, to_reserve) @@ -27,7 +27,7 @@ platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_ } -platform_memory_free :: proc(block: ^Platform_Memory_Block) { +platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) { if block != nil { release(block, block.reserved) } @@ -55,7 +55,7 @@ platform_memory_init :: proc() { } } -platform_memory_commit :: proc(block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) { +platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) { if to_commit < block.committed { return nil } diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin index 623e8d469..ef0bf6f1a 100644 --- a/core/mem/virtual/virtual_windows.odin +++ b/core/mem/virtual/virtual_windows.odin @@ -62,7 +62,7 @@ foreign Kernel32 { } -_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { +_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE) if result == nil { err = .Out_Of_Memory @@ -72,7 +72,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { return } -_commit :: proc(data: rawptr, size: uint) -> Allocator_Error { +_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE) if result == nil { switch err := GetLastError(); err { @@ -85,13 +85,13 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error { } return nil } -_decommit :: proc(data: rawptr, size: uint) { +_decommit :: proc "contextless" (data: rawptr, size: uint) { VirtualFree(data, size, MEM_DECOMMIT) } -_release :: proc(data: rawptr, size: uint) { +_release :: proc "contextless" (data: rawptr, size: uint) { VirtualFree(data, 0, MEM_RELEASE) } -_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool { +_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { pflags: u32 pflags = PAGE_NOACCESS switch flags { From e9ee6f529165aa4883708cf94e4b10f538553ea5 Mon Sep 17 00:00:00 2001 From: Patric Dexheimer Date: Tue, 1 Mar 2022 16:00:18 -0300 Subject: [PATCH 0303/1052] Fixing bindings https://github.com/raysan5/raylib/blob/master/src/raylib.h#L1179 --- vendor/raylib/raylib.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 0c8248683..5e1b22b3d 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -1150,7 +1150,7 @@ foreign lib { DrawRectangleGradientH :: proc(posX, posY, width, height: c.int, color1: Color, color2: Color) --- // Draw a horizontal-gradient-filled rectangle DrawRectangleGradientEx :: proc(rec: Rectangle, col1, col2, col3, col4: Color) --- // Draw a gradient-filled rectangle with custom vertex colors DrawRectangleLines :: proc(posX, posY, width, height: c.int, color: Color) --- // Draw rectangle outline - DrawRectangleLinesEx :: proc(rec: Rectangle, lineThick: c.int, color: Color) --- // Draw rectangle outline with extended parameters + DrawRectangleLinesEx :: proc(rec: Rectangle, lineThick: f32, color: Color) --- // Draw rectangle outline with extended parameters DrawRectangleRounded :: proc(rec: Rectangle, roundness: f32, segments: c.int, color: Color) --- // Draw rectangle with rounded edges DrawRectangleRoundedLines :: proc(rec: Rectangle, roundness: f32, segments: c.int, lineThick: c.int, color: Color) --- // Draw rectangle with rounded edges outline DrawTriangle :: proc(v1, v2, v3: Vector2, color: Color) --- // Draw a color-filled triangle (vertex in counter-clockwise order!) From 524d23d45dc38b60e9a99c745fb4a6164c776138 Mon Sep 17 00:00:00 2001 From: Patric Dexheimer Date: Tue, 1 Mar 2022 16:55:34 -0300 Subject: [PATCH 0304/1052] Update raylib.odin --- vendor/raylib/raylib.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 5e1b22b3d..93cdf3f04 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -1152,7 +1152,7 @@ foreign lib { DrawRectangleLines :: proc(posX, posY, width, height: c.int, color: Color) --- // Draw rectangle outline DrawRectangleLinesEx :: proc(rec: Rectangle, lineThick: f32, color: Color) --- // Draw rectangle outline with extended parameters DrawRectangleRounded :: proc(rec: Rectangle, roundness: f32, segments: c.int, color: Color) --- // Draw rectangle with rounded edges - DrawRectangleRoundedLines :: proc(rec: Rectangle, roundness: f32, segments: c.int, lineThick: c.int, color: Color) --- // Draw rectangle with rounded edges outline + DrawRectangleRoundedLines :: proc(rec: Rectangle, roundness: f32, segments: c.int, lineThick: f32, color: Color) --- // Draw rectangle with rounded edges outline DrawTriangle :: proc(v1, v2, v3: Vector2, color: Color) --- // Draw a color-filled triangle (vertex in counter-clockwise order!) DrawTriangleLines :: proc(v1, v2, v3: Vector2, color: Color) --- // Draw triangle outline (vertex in counter-clockwise order!) DrawTriangleFan :: proc(points: [^]Vector2, pointsCount: c.int, color: Color) --- // Draw a triangle fan defined by points (first vertex is the center) From 507722954c0390840d1ff0b0e8770428c3252114 Mon Sep 17 00:00:00 2001 From: Lucas Perlind Date: Wed, 2 Mar 2022 16:15:53 +1100 Subject: [PATCH 0305/1052] Improve core:fmt formatting * Strings will respect widths smaller than the string's length * Strings are right justified by default like integers * Strings accept '-' flag to be left justified * Booleans will be formatted like strings * Enums will be formatted like strings --- core/fmt/fmt.odin | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index d6c1894b7..d006d0ef8 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -605,7 +605,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) { fmt_bool :: proc(using fi: ^Info, b: bool, verb: rune) { switch verb { case 't', 'v': - io.write_string(writer, b ? "true" : "false", &fi.n) + fmt_string(fi, b ? "true" : "false", 's') case: fmt_bad_verb(fi, verb) } @@ -943,11 +943,27 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { fmt_string :: proc(fi: ^Info, s: string, verb: rune) { switch verb { case 's', 'v': - io.write_string(fi.writer, s, &fi.n) - if fi.width_set && len(s) < fi.width { - for _ in 0.. len(s) { + if fi.minus { + io.write_string(fi.writer, s, &fi.n) + } + + for _ in 0.. Date: Wed, 2 Mar 2022 18:21:43 +0000 Subject: [PATCH 0307/1052] vendor: botan: simplify foreign import --- vendor/botan/bindings/botan.odin | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 3eaad0bc1..a12706e95 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -142,11 +142,7 @@ fpe_t :: ^fpe_struct when ODIN_OS == .Windows { foreign import botan_lib "botan.lib" -} else when ODIN_OS == .Linux { - foreign import botan_lib "system:botan-2" -} else when ODIN_OS == .Darwin { - foreign import botan_lib "system:botan-2" -} else when ODIN_OS == .OpenBSD { +} else { foreign import botan_lib "system:botan-2" } From 25430333ba89389c25acfdd78bfcf2b6e04af224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 2 Mar 2022 18:25:22 +0000 Subject: [PATCH 0308/1052] vendor: glfw: simplify foreign import --- vendor/glfw/bindings/bindings.odin | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index fa9ef0776..aa1578153 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -3,9 +3,6 @@ package glfw_bindings import "core:c" import vk "vendor:vulkan" -when ODIN_OS == .Linux { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux -when ODIN_OS == .Darwin { foreign import glfw "system:glfw" } -when ODIN_OS == .OpenBSD { foreign import glfw "system:glfw" } when ODIN_OS == .Windows { foreign import glfw { "../lib/glfw3_mt.lib", @@ -13,6 +10,11 @@ when ODIN_OS == .Windows { "system:gdi32.lib", "system:shell32.lib", } +} else when ODIN_OS == .Linux { + // TODO: Add the billion-or-so static libs to link to in linux + foreign import glfw "system:glfw" +} else { + foreign import glfw "system:glfw" } #assert(size_of(c.int) == size_of(b32)) From 3145935d6bb1ffc9ca4f3f8ebdb8dc3edcac3ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 2 Mar 2022 18:35:13 +0000 Subject: [PATCH 0309/1052] miniaudio - simplify foreign - enable SUPPORT_SNDIO on OpenBSD - correct ptr type for SUPPORT_PULSEAUDIO (Linux) and SUPPORT_COREAUDIO (Darwin) --- vendor/miniaudio/common.odin | 9 +++++++-- vendor/miniaudio/data_conversion.odin | 10 +++++++--- vendor/miniaudio/decoding.odin | 13 ++++++++----- vendor/miniaudio/device_io_procs.odin | 9 +++++++-- vendor/miniaudio/device_io_types.odin | 8 ++++---- vendor/miniaudio/encoding.odin | 11 ++++++++--- vendor/miniaudio/filtering.odin | 9 +++++++-- vendor/miniaudio/generation.odin | 11 ++++++++--- vendor/miniaudio/logging.odin | 11 ++++++++--- vendor/miniaudio/utilities.odin | 11 ++++++++--- vendor/miniaudio/vfs.odin | 9 +++++++-- 11 files changed, 79 insertions(+), 32 deletions(-) diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index 75b66101f..89e3d6bd2 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -2,8 +2,13 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} handle :: distinct rawptr diff --git a/vendor/miniaudio/data_conversion.odin b/vendor/miniaudio/data_conversion.odin index 8a53cc19e..7167270a1 100644 --- a/vendor/miniaudio/data_conversion.odin +++ b/vendor/miniaudio/data_conversion.odin @@ -2,9 +2,13 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } - +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* diff --git a/vendor/miniaudio/decoding.odin b/vendor/miniaudio/decoding.odin index 52b315f10..dcf3b7a1a 100644 --- a/vendor/miniaudio/decoding.odin +++ b/vendor/miniaudio/decoding.odin @@ -2,10 +2,13 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } - - +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} /************************************************************************************************************************************************************ @@ -164,4 +167,4 @@ foreign lib { decode_from_vfs :: proc(pVFS: ^vfs, pFilePath: cstring, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result --- decode_file :: proc(pFilePath: cstring, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result --- decode_memory :: proc(pData: rawptr, dataSize: c.size_t, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result --- -} \ No newline at end of file +} diff --git a/vendor/miniaudio/device_io_procs.odin b/vendor/miniaudio/device_io_procs.odin index 8d6609186..7cff3f621 100644 --- a/vendor/miniaudio/device_io_procs.odin +++ b/vendor/miniaudio/device_io_procs.odin @@ -1,7 +1,12 @@ package miniaudio -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} import "core:c" diff --git a/vendor/miniaudio/device_io_types.odin b/vendor/miniaudio/device_io_types.odin index 7778e85cf..e05f94665 100644 --- a/vendor/miniaudio/device_io_types.odin +++ b/vendor/miniaudio/device_io_types.odin @@ -6,7 +6,7 @@ SUPPORT_WASAPI :: ODIN_OS == .Windows SUPPORT_DSOUND :: ODIN_OS == .Windows SUPPORT_WINMM :: ODIN_OS == .Windows SUPPORT_COREAUDIO :: ODIN_OS == .Darwin -SUPPORT_SNDIO :: false // ODIN_OS == .OpenBSD +SUPPORT_SNDIO :: ODIN_OS == .OpenBSD SUPPORT_AUDIO4 :: false // ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD SUPPORT_OSS :: ODIN_OS == .FreeBSD SUPPORT_PULSEAUDIO :: ODIN_OS == .Linux @@ -739,8 +739,8 @@ context_type :: struct { pa_stream_writable_size: proc "system" (), pa_stream_readable_size: proc "system" (), - /*pa_mainloop**/ pMainLoop: ptr, - /*pa_context**/ pPulseContext: ptr, + /*pa_mainloop**/ pMainLoop: rawptr, + /*pa_context**/ pPulseContext: rawptr, } when SUPPORT_PULSEAUDIO else struct {}), jack: (struct { @@ -791,7 +791,7 @@ context_type :: struct { AudioUnitInitialize: proc "system" (), AudioUnitRender: proc "system" (), - /*AudioComponent*/ component: ptr, + /*AudioComponent*/ component: rawptr, noAudioSessionDeactivate: b32, /* For tracking whether or not the iOS audio session should be explicitly deactivated. Set from the config in ma_context_init__coreaudio(). */ } when SUPPORT_COREAUDIO else struct {}), diff --git a/vendor/miniaudio/encoding.odin b/vendor/miniaudio/encoding.odin index 83f9d5252..9b84108dc 100644 --- a/vendor/miniaudio/encoding.odin +++ b/vendor/miniaudio/encoding.odin @@ -2,8 +2,13 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} /************************************************************************************************************************************************************ @@ -49,4 +54,4 @@ foreign lib { encoder_init_file_w :: proc(pFilePath: [^]c.wchar_t, pConfig: ^encoder_config, pEncoder: ^encoder) -> result --- encoder_uninit :: proc(pEncoder: ^encoder) --- encoder_write_pcm_frames :: proc(pEncoder: ^encoder, FramesIn: rawptr, frameCount: u64) -> u64 --- -} \ No newline at end of file +} diff --git a/vendor/miniaudio/filtering.odin b/vendor/miniaudio/filtering.odin index 4956da173..9949f6338 100644 --- a/vendor/miniaudio/filtering.odin +++ b/vendor/miniaudio/filtering.odin @@ -1,7 +1,12 @@ package miniaudio -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} /************************************************************************************************************************************************************** diff --git a/vendor/miniaudio/generation.odin b/vendor/miniaudio/generation.odin index c241f00b1..97b7d453c 100644 --- a/vendor/miniaudio/generation.odin +++ b/vendor/miniaudio/generation.odin @@ -2,8 +2,13 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} waveform_type :: enum c.int { sine, @@ -82,4 +87,4 @@ foreign lib { noise_set_amplitude :: proc(pNoise: ^noise, amplitude: f64) -> result --- noise_set_seed :: proc(pNoise: ^noise, seed: i32) -> result --- noise_set_type :: proc(pNoise: ^noise, type: noise_type) -> result --- -} \ No newline at end of file +} diff --git a/vendor/miniaudio/logging.odin b/vendor/miniaudio/logging.odin index 35aa54bc9..0c14a10c2 100644 --- a/vendor/miniaudio/logging.odin +++ b/vendor/miniaudio/logging.odin @@ -2,8 +2,13 @@ package miniaudio import c "core:c/libc" -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} MAX_LOG_CALLBACKS :: 4 @@ -32,4 +37,4 @@ foreign lib { log_post :: proc(pLog: ^log, level: u32, pMessage: cstring) -> result --- log_postv :: proc(pLog: ^log, level: u32, pFormat: cstring, args: c.va_list) -> result --- log_postf :: proc(pLog: ^log, level: u32, pFormat: cstring, #c_vararg args: ..any) -> result --- -} \ No newline at end of file +} diff --git a/vendor/miniaudio/utilities.odin b/vendor/miniaudio/utilities.odin index 19307a77d..9ced019f5 100644 --- a/vendor/miniaudio/utilities.odin +++ b/vendor/miniaudio/utilities.odin @@ -1,7 +1,12 @@ package miniaudio -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} @(default_calling_convention="c", link_prefix="ma_") foreign lib { @@ -228,4 +233,4 @@ foreign lib { audio_buffer_get_cursor_in_pcm_frames :: proc(pAudioBuffer: ^audio_buffer, pCursor: ^u64) -> result --- audio_buffer_get_length_in_pcm_frames :: proc(pAudioBuffer: ^audio_buffer, pLength: ^u64) -> result --- audio_buffer_get_available_frames :: proc(pAudioBuffer: ^audio_buffer, pAvailableFrames: ^u64) -> result --- -} \ No newline at end of file +} diff --git a/vendor/miniaudio/vfs.odin b/vendor/miniaudio/vfs.odin index 547fbd265..85571341e 100644 --- a/vendor/miniaudio/vfs.odin +++ b/vendor/miniaudio/vfs.odin @@ -2,8 +2,13 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } -when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" } +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} /************************************************************************************************************************************************************ From d3f3528d1d545c581c368d5d0810c2b5cf061479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 2 Mar 2022 18:43:17 +0000 Subject: [PATCH 0310/1052] vendor: portmidi: simplify foreign import --- vendor/portmidi/portmidi.odin | 4 +++- vendor/portmidi/util.odin | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/vendor/portmidi/portmidi.odin b/vendor/portmidi/portmidi.odin index 40fd18b8b..a3db4191c 100644 --- a/vendor/portmidi/portmidi.odin +++ b/vendor/portmidi/portmidi.odin @@ -9,6 +9,8 @@ when ODIN_OS == .Windows { "system:Winmm.lib", "system:Advapi32.lib", } +} else { + foreign import lib "system:portmidi" } #assert(size_of(b32) == size_of(c.int)) @@ -519,4 +521,4 @@ foreign lib { WriteSysEx() writes a timestamped system-exclusive midi message. */ WriteSysEx :: proc(stream: Stream, whence: Timestamp, msg: cstring) -> Error --- -} \ No newline at end of file +} diff --git a/vendor/portmidi/util.odin b/vendor/portmidi/util.odin index ca2e1f4ca..caf73f8ad 100644 --- a/vendor/portmidi/util.odin +++ b/vendor/portmidi/util.odin @@ -7,7 +7,11 @@ package portmidi import "core:c" -when ODIN_OS == .Windows { foreign import lib "portmidi_s.lib" } +when ODIN_OS == .Windows { + foreign import lib "portmidi_s.lib" +} else { + foreign import lib "system:portmidi" +} Queue :: distinct rawptr @@ -118,4 +122,4 @@ foreign lib { state, returns .NoError if successfully set overflow state. */ SetOverflow :: proc(queue: Queue) -> Error --- -} \ No newline at end of file +} From 5b783d637674e6be8724dd0c458777e5162b1ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 2 Mar 2022 18:44:29 +0000 Subject: [PATCH 0311/1052] vendor: raylib: simplify foreign import --- vendor/raylib/raylib.odin | 8 +++++--- vendor/raylib/rlgl.odin | 10 +++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 0c8248683..e7c6532ef 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -99,15 +99,17 @@ when ODIN_OS == .Windows { "system:User32.lib", "system:Shell32.lib", } -} -when ODIN_OS == .Linux { +} else when ODIN_OS == .Linux { foreign import lib { "linux/libraylib.a", "system:dl", "system:pthread", } +} else when ODIN_OS == .Darwin { + foreign import lib "macos/libraylib.a" +} else { + foreign import lib "system:raylib" } -when ODIN_OS == .Darwin { foreign import lib "macos/libraylib.a" } VERSION :: "4.0" diff --git a/vendor/raylib/rlgl.odin b/vendor/raylib/rlgl.odin index 936a34765..7e7f2feea 100644 --- a/vendor/raylib/rlgl.odin +++ b/vendor/raylib/rlgl.odin @@ -10,9 +10,13 @@ when ODIN_OS == .Windows { "system:User32.lib", "system:Shell32.lib", } +} else when ODIN_OS == .Linux { + foreign import lib "linux/libraylib.a" +} else when ODIN_OS == .Darwin { + foreign import lib "macos/libraylib.a" +} else { + foreign import lib "system:raylib" } -when ODIN_OS == .Linux { foreign import lib "linux/libraylib.a" } -when ODIN_OS == .Darwin { foreign import lib "macos/libraylib.a" } GRAPHICS_API_OPENGL_11 :: false GRAPHICS_API_OPENGL_21 :: true @@ -378,4 +382,4 @@ foreign lib { // Quick and dirty cube/quad buffers load->draw->unload rlLoadDrawCube :: proc() --- // Load and draw a cube rlLoadDrawQuad :: proc() --- // Load and draw a quad -} \ No newline at end of file +} From 793117ed633a15a94d38be44658f381d03d2e0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 2 Mar 2022 18:50:37 +0000 Subject: [PATCH 0312/1052] vendor: sdl2: simplify foreign import --- vendor/sdl2/image/sdl_image.odin | 10 +++++----- vendor/sdl2/mixer/sdl_mixer.odin | 10 +++++----- vendor/sdl2/net/sdl_net.odin | 10 +++++----- vendor/sdl2/sdl2.odin | 10 +++++----- vendor/sdl2/sdl_audio.odin | 10 +++++----- vendor/sdl2/sdl_blendmode.odin | 10 +++++----- vendor/sdl2/sdl_cpuinfo.odin | 10 +++++----- vendor/sdl2/sdl_events.odin | 10 +++++----- vendor/sdl2/sdl_gamecontroller.odin | 10 +++++----- vendor/sdl2/sdl_gesture_haptic.odin | 10 +++++----- vendor/sdl2/sdl_hints.odin | 10 +++++----- vendor/sdl2/sdl_joystick.odin | 10 +++++----- vendor/sdl2/sdl_keyboard.odin | 10 +++++----- vendor/sdl2/sdl_log.odin | 10 +++++----- vendor/sdl2/sdl_messagebox.odin | 10 +++++----- vendor/sdl2/sdl_metal.odin | 10 +++++----- vendor/sdl2/sdl_mouse.odin | 10 +++++----- vendor/sdl2/sdl_mutex.odin | 10 +++++----- vendor/sdl2/sdl_pixels.odin | 10 +++++----- vendor/sdl2/sdl_rect.odin | 10 +++++----- vendor/sdl2/sdl_render.odin | 10 +++++----- vendor/sdl2/sdl_rwops.odin | 10 +++++----- vendor/sdl2/sdl_stdinc.odin | 10 +++++----- vendor/sdl2/sdl_surface.odin | 10 +++++----- vendor/sdl2/sdl_system.odin | 10 +++++----- vendor/sdl2/sdl_syswm.odin | 10 +++++----- vendor/sdl2/sdl_thread.odin | 10 +++++----- vendor/sdl2/sdl_timer.odin | 10 +++++----- vendor/sdl2/sdl_touch.odin | 10 +++++----- vendor/sdl2/sdl_video.odin | 10 +++++----- vendor/sdl2/sdl_vulkan.odin | 10 +++++----- vendor/sdl2/ttf/sdl_ttf.odin | 10 +++++----- 32 files changed, 160 insertions(+), 160 deletions(-) diff --git a/vendor/sdl2/image/sdl_image.odin b/vendor/sdl2/image/sdl_image.odin index ad939a63a..204ec9a0d 100644 --- a/vendor/sdl2/image/sdl_image.odin +++ b/vendor/sdl2/image/sdl_image.odin @@ -3,11 +3,11 @@ package sdl2_image import "core:c" import SDL ".." -when ODIN_OS == .Windows { foreign import lib "SDL2_image.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2_image" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2_image" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_image" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_image" } +when ODIN_OS == .Windows { + foreign import lib "SDL2_image.lib" +} else { + foreign import lib "system:SDL2_image" +} bool :: SDL.bool diff --git a/vendor/sdl2/mixer/sdl_mixer.odin b/vendor/sdl2/mixer/sdl_mixer.odin index ad7670598..b0c16871d 100644 --- a/vendor/sdl2/mixer/sdl_mixer.odin +++ b/vendor/sdl2/mixer/sdl_mixer.odin @@ -3,11 +3,11 @@ package sdl2_mixer import "core:c" import SDL ".." -when ODIN_OS == .Windows { foreign import lib "SDL2_mixer.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2_mixer" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2_mixer" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_mixer" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_mixer" } +when ODIN_OS == .Windows { + foreign import lib "SDL2_mixer.lib" +} else { + foreign import lib "system:SDL2_mixer" +} MAJOR_VERSION :: 2 MINOR_VERSION :: 0 diff --git a/vendor/sdl2/net/sdl_net.odin b/vendor/sdl2/net/sdl_net.odin index 4aafe0bcf..579f245e5 100644 --- a/vendor/sdl2/net/sdl_net.odin +++ b/vendor/sdl2/net/sdl_net.odin @@ -3,11 +3,11 @@ package sdl2_net import "core:c" import SDL ".." -when ODIN_OS == .Windows { foreign import lib "SDL2_net.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2_net" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2_net" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_net" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_net" } +when ODIN_OS == .Windows { + foreign import lib "SDL2_net.lib" +} else { + foreign import lib "system:SDL2_net" +} bool :: SDL.bool diff --git a/vendor/sdl2/sdl2.odin b/vendor/sdl2/sdl2.odin index c270fc52f..24ecc38e6 100644 --- a/vendor/sdl2/sdl2.odin +++ b/vendor/sdl2/sdl2.odin @@ -25,11 +25,11 @@ package sdl2 import "core:c" import "core:intrinsics" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} version :: struct { major: u8, /**< major version */ diff --git a/vendor/sdl2/sdl_audio.odin b/vendor/sdl2/sdl_audio.odin index 686f1994a..28a59d947 100644 --- a/vendor/sdl2/sdl_audio.odin +++ b/vendor/sdl2/sdl_audio.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} /** * \brief Audio format flags. diff --git a/vendor/sdl2/sdl_blendmode.odin b/vendor/sdl2/sdl_blendmode.odin index 19e4b37aa..4fde5111b 100644 --- a/vendor/sdl2/sdl_blendmode.odin +++ b/vendor/sdl2/sdl_blendmode.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} /** * \brief The blend mode used in SDL_RenderCopy() and drawing operations. diff --git a/vendor/sdl2/sdl_cpuinfo.odin b/vendor/sdl2/sdl_cpuinfo.odin index 01a8d203a..c5175e4d5 100644 --- a/vendor/sdl2/sdl_cpuinfo.odin +++ b/vendor/sdl2/sdl_cpuinfo.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} /* This is a guess for the cacheline size used for padding. * Most x86 processors have a 64 byte cache line. diff --git a/vendor/sdl2/sdl_events.odin b/vendor/sdl2/sdl_events.odin index 45f9886a5..29f6e8a43 100644 --- a/vendor/sdl2/sdl_events.odin +++ b/vendor/sdl2/sdl_events.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} RELEASED :: 0 PRESSED :: 1 diff --git a/vendor/sdl2/sdl_gamecontroller.odin b/vendor/sdl2/sdl_gamecontroller.odin index 8c15cd779..76e0b8966 100644 --- a/vendor/sdl2/sdl_gamecontroller.odin +++ b/vendor/sdl2/sdl_gamecontroller.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} GameController :: struct {} diff --git a/vendor/sdl2/sdl_gesture_haptic.odin b/vendor/sdl2/sdl_gesture_haptic.odin index 961ae6ea6..a21e0df06 100644 --- a/vendor/sdl2/sdl_gesture_haptic.odin +++ b/vendor/sdl2/sdl_gesture_haptic.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} // Gesture diff --git a/vendor/sdl2/sdl_hints.odin b/vendor/sdl2/sdl_hints.odin index 150c8bcc6..913d4ea12 100644 --- a/vendor/sdl2/sdl_hints.odin +++ b/vendor/sdl2/sdl_hints.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} HINT_ACCELEROMETER_AS_JOYSTICK :: "SDL_ACCELEROMETER_AS_JOYSTICK" HINT_ALLOW_ALT_TAB_WHILE_GRABBED :: "SDL_ALLOW_ALT_TAB_WHILE_GRABBED" diff --git a/vendor/sdl2/sdl_joystick.odin b/vendor/sdl2/sdl_joystick.odin index f190c13e4..35ca5cdcc 100644 --- a/vendor/sdl2/sdl_joystick.odin +++ b/vendor/sdl2/sdl_joystick.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} Joystick :: struct {} diff --git a/vendor/sdl2/sdl_keyboard.odin b/vendor/sdl2/sdl_keyboard.odin index abc6bb838..f880286aa 100644 --- a/vendor/sdl2/sdl_keyboard.odin +++ b/vendor/sdl2/sdl_keyboard.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} Keysym :: struct { scancode: Scancode, /**< SDL physical key code - see ::SDL_Scancode for details */ diff --git a/vendor/sdl2/sdl_log.odin b/vendor/sdl2/sdl_log.odin index a496f5fbe..09b7eaef0 100644 --- a/vendor/sdl2/sdl_log.odin +++ b/vendor/sdl2/sdl_log.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} MAX_LOG_MESSAGE :: 4096 diff --git a/vendor/sdl2/sdl_messagebox.odin b/vendor/sdl2/sdl_messagebox.odin index e14cc5463..6228704ac 100644 --- a/vendor/sdl2/sdl_messagebox.odin +++ b/vendor/sdl2/sdl_messagebox.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} MessageBoxFlag :: enum u32 { _ = 0, diff --git a/vendor/sdl2/sdl_metal.odin b/vendor/sdl2/sdl_metal.odin index c297113c6..1eccf7f5a 100644 --- a/vendor/sdl2/sdl_metal.odin +++ b/vendor/sdl2/sdl_metal.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} MetalView :: distinct rawptr diff --git a/vendor/sdl2/sdl_mouse.odin b/vendor/sdl2/sdl_mouse.odin index 56478b6fb..13220c94b 100644 --- a/vendor/sdl2/sdl_mouse.odin +++ b/vendor/sdl2/sdl_mouse.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} Cursor :: struct {} diff --git a/vendor/sdl2/sdl_mutex.odin b/vendor/sdl2/sdl_mutex.odin index 2ce004b52..1fd5849e0 100644 --- a/vendor/sdl2/sdl_mutex.odin +++ b/vendor/sdl2/sdl_mutex.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} MUTEX_TIMEDOUT :: 1 MUTEX_MAXWAIT :: ~u32(0) diff --git a/vendor/sdl2/sdl_pixels.odin b/vendor/sdl2/sdl_pixels.odin index 34ff23b14..8ee06aa1a 100644 --- a/vendor/sdl2/sdl_pixels.odin +++ b/vendor/sdl2/sdl_pixels.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} ALPHA_OPAQUE :: 255 ALPHA_TRANSPARENT :: 0 diff --git a/vendor/sdl2/sdl_rect.odin b/vendor/sdl2/sdl_rect.odin index fdf18aa65..852309cd2 100644 --- a/vendor/sdl2/sdl_rect.odin +++ b/vendor/sdl2/sdl_rect.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} Point :: struct { x: c.int, diff --git a/vendor/sdl2/sdl_render.odin b/vendor/sdl2/sdl_render.odin index dd599f669..57845235b 100644 --- a/vendor/sdl2/sdl_render.odin +++ b/vendor/sdl2/sdl_render.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} RendererFlag :: enum u32 { SOFTWARE = 0, /**< The renderer is a software fallback */ diff --git a/vendor/sdl2/sdl_rwops.odin b/vendor/sdl2/sdl_rwops.odin index fd7abc0c4..86fb23c75 100644 --- a/vendor/sdl2/sdl_rwops.odin +++ b/vendor/sdl2/sdl_rwops.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} /* RWops Types */ RWOPS_UNKNOWN :: 0 /**< Unknown stream type */ diff --git a/vendor/sdl2/sdl_stdinc.odin b/vendor/sdl2/sdl_stdinc.odin index 15446eb71..97722f4fe 100644 --- a/vendor/sdl2/sdl_stdinc.odin +++ b/vendor/sdl2/sdl_stdinc.odin @@ -5,11 +5,11 @@ import "core:intrinsics" import "core:runtime" _, _ :: intrinsics, runtime -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} bool :: distinct b32 #assert(size_of(bool) == size_of(c.int)) diff --git a/vendor/sdl2/sdl_surface.odin b/vendor/sdl2/sdl_surface.odin index 82545f1f9..f50de35f7 100644 --- a/vendor/sdl2/sdl_surface.odin +++ b/vendor/sdl2/sdl_surface.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} SWSURFACE :: 0 /**< Just here for compatibility */ PREALLOC :: 0x00000001 /**< Surface uses preallocated memory */ diff --git a/vendor/sdl2/sdl_system.odin b/vendor/sdl2/sdl_system.odin index cd08cfc47..d9b6b98df 100644 --- a/vendor/sdl2/sdl_system.odin +++ b/vendor/sdl2/sdl_system.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} // General @(default_calling_convention="c", link_prefix="SDL_") diff --git a/vendor/sdl2/sdl_syswm.odin b/vendor/sdl2/sdl_syswm.odin index f2b52529f..62ca9d628 100644 --- a/vendor/sdl2/sdl_syswm.odin +++ b/vendor/sdl2/sdl_syswm.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} SYSWM_TYPE :: enum c.int { UNKNOWN, diff --git a/vendor/sdl2/sdl_thread.odin b/vendor/sdl2/sdl_thread.odin index 0d9d66d30..5d1c0bd37 100644 --- a/vendor/sdl2/sdl_thread.odin +++ b/vendor/sdl2/sdl_thread.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} Thread :: struct {} diff --git a/vendor/sdl2/sdl_timer.odin b/vendor/sdl2/sdl_timer.odin index 13003b5b3..d71ed2da5 100644 --- a/vendor/sdl2/sdl_timer.odin +++ b/vendor/sdl2/sdl_timer.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} TimerCallback :: proc "c" (interval: u32, param: rawptr) -> u32 TimerID :: distinct c.int diff --git a/vendor/sdl2/sdl_touch.odin b/vendor/sdl2/sdl_touch.odin index ffb91328a..f2a8cc695 100644 --- a/vendor/sdl2/sdl_touch.odin +++ b/vendor/sdl2/sdl_touch.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} TouchID :: distinct i64 FingerID :: distinct i64 diff --git a/vendor/sdl2/sdl_video.odin b/vendor/sdl2/sdl_video.odin index d050e272d..86b564541 100644 --- a/vendor/sdl2/sdl_video.odin +++ b/vendor/sdl2/sdl_video.odin @@ -2,11 +2,11 @@ package sdl2 import "core:c" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} DisplayMode :: struct { format: u32, /**< pixel format */ diff --git a/vendor/sdl2/sdl_vulkan.odin b/vendor/sdl2/sdl_vulkan.odin index 13e25f8c2..33bb8e51c 100644 --- a/vendor/sdl2/sdl_vulkan.odin +++ b/vendor/sdl2/sdl_vulkan.odin @@ -3,11 +3,11 @@ package sdl2 import "core:c" import vk "vendor:vulkan" -when ODIN_OS == .Windows { foreign import lib "SDL2.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2" } +when ODIN_OS == .Windows { + foreign import lib "SDL2.lib" +} else { + foreign import lib "system:SDL2" +} VkInstance :: vk.Instance VkSurfaceKHR :: vk.SurfaceKHR diff --git a/vendor/sdl2/ttf/sdl_ttf.odin b/vendor/sdl2/ttf/sdl_ttf.odin index e84c89136..ca9beded0 100644 --- a/vendor/sdl2/ttf/sdl_ttf.odin +++ b/vendor/sdl2/ttf/sdl_ttf.odin @@ -3,11 +3,11 @@ package sdl2_ttf import "core:c" import SDL ".." -when ODIN_OS == .Windows { foreign import lib "SDL2_ttf.lib" } -when ODIN_OS == .Linux { foreign import lib "system:SDL2_ttf" } -when ODIN_OS == .Darwin { foreign import lib "system:SDL2_ttf" } -when ODIN_OS == .FreeBSD { foreign import lib "system:SDL2_ttf" } -when ODIN_OS == .OpenBSD { foreign import lib "system:SDL2_ttf" } +when ODIN_OS == .Windows { + foreign import lib "SDL2_ttf.lib" +} else { + foreign import lib "system:SDL2_ttf" +} bool :: SDL.bool From 562901aedf5a66c9d0664f223818617fa639a718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 2 Mar 2022 19:21:22 +0000 Subject: [PATCH 0313/1052] split all_vendor.odin create 3 files: - all_vendor.odin : no specific OS - all_vendor_directx.odin : directx vendor, windows-only - all_vendor_stb.odin : stb vendor, windows and linux only stb could technically be used on others OS. but it is shipped upstream as set of c-files without unified library name. --- examples/all/all_vendor.odin | 23 +---------------------- examples/all/all_vendor_directx.odin | 10 ++++++++++ examples/all/all_vendor_stl.odin | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 examples/all/all_vendor_directx.odin create mode 100644 examples/all/all_vendor_stl.odin diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 9aa109e5b..f83e906a2 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -1,4 +1,3 @@ -//+build windows package all import botan "vendor:botan" @@ -16,24 +15,12 @@ import IMG "vendor:sdl2/image" import MIX "vendor:sdl2/mixer" import TTF "vendor:sdl2/ttf" -import stb_easy_font "vendor:stb/easy_font" -import stbi "vendor:stb/image" -import stbrp "vendor:stb/rect_pack" -import stbtt "vendor:stb/truetype" -import stb_vorbis "vendor:stb/vorbis" - import vk "vendor:vulkan" -import D3D11 "vendor:directx/d3d11" -import D3D12 "vendor:directx/d3d12" -import DXGI "vendor:directx/dxgi" - -// note these are technicaly darwin only but they are added to aid with documentation generation import NS "vendor:darwin/Foundation" import MTL "vendor:darwin/Metal" import CA "vendor:darwin/QuartzCore" - _ :: botan _ :: ENet _ :: gl @@ -47,15 +34,7 @@ _ :: SDLNet _ :: IMG _ :: MIX _ :: TTF -_ :: stb_easy_font -_ :: stbi -_ :: stbrp -_ :: stbtt -_ :: stb_vorbis _ :: vk -_ :: D3D11 -_ :: D3D12 -_ :: DXGI _ :: NS _ :: MTL -_ :: CA \ No newline at end of file +_ :: CA diff --git a/examples/all/all_vendor_directx.odin b/examples/all/all_vendor_directx.odin new file mode 100644 index 000000000..2f10d92f8 --- /dev/null +++ b/examples/all/all_vendor_directx.odin @@ -0,0 +1,10 @@ +//+build windows +package all + +import D3D11 "vendor:directx/d3d11" +import D3D12 "vendor:directx/d3d12" +import DXGI "vendor:directx/dxgi" + +_ :: D3D11 +_ :: D3D12 +_ :: DXGI diff --git a/examples/all/all_vendor_stl.odin b/examples/all/all_vendor_stl.odin new file mode 100644 index 000000000..9faf53c63 --- /dev/null +++ b/examples/all/all_vendor_stl.odin @@ -0,0 +1,15 @@ +//+build windows, linux +package all + +import stb_easy_font "vendor:stb/easy_font" +import stbi "vendor:stb/image" +import stbrp "vendor:stb/rect_pack" +import stbtt "vendor:stb/truetype" +import stb_vorbis "vendor:stb/vorbis" + +_ :: stb_easy_font +_ :: stbi +_ :: stbrp +_ :: stbtt +_ :: stb_vorbis + From 3b4199a66977dff1c65f90de5270e7b0ef43206e Mon Sep 17 00:00:00 2001 From: zhibog Date: Wed, 2 Mar 2022 21:22:56 +0100 Subject: [PATCH 0314/1052] Added rand_bytes for Windows in core:crypto --- core/crypto/rand_generic.odin | 2 +- core/crypto/rand_windows.odin | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 core/crypto/rand_windows.odin diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin index 10edc1c8a..52abfe4d7 100644 --- a/core/crypto/rand_generic.odin +++ b/core/crypto/rand_generic.odin @@ -1,6 +1,6 @@ package crypto -when ODIN_OS != .Linux && ODIN_OS != .OpenBSD { +when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows { _rand_bytes :: proc (dst: []byte) { unimplemented("crypto: rand_bytes not supported on this OS") } diff --git a/core/crypto/rand_windows.odin b/core/crypto/rand_windows.odin new file mode 100644 index 000000000..53b58c776 --- /dev/null +++ b/core/crypto/rand_windows.odin @@ -0,0 +1,23 @@ +package crypto + +import win32 "core:sys/windows" +import "core:os" +import "core:fmt" + +_rand_bytes :: proc(dst: []byte) { + ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) + if ret != os.ERROR_NONE { + switch ret { + case os.ERROR_INVALID_HANDLE: + // The handle to the first parameter is invalid. + // This should not happen here, since we explicitly pass nil to it + panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm") + case os.ERROR_INVALID_PARAMETER: + // One of the parameters was invalid + panic("crypto: BCryptGenRandom Invalid parameter") + case: + // Unknown error + panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret)) + } + } +} From f126e050348f7a59f244ca24a5d6e9685bd9f696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 3 Mar 2022 07:36:47 +0000 Subject: [PATCH 0315/1052] stb, miniaudio: use default builtin variables of make for CC and AR --- vendor/miniaudio/src/Makefile | 6 +++--- vendor/stb/src/Makefile | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/vendor/miniaudio/src/Makefile b/vendor/miniaudio/src/Makefile index 7ff72ebdc..3c61b5e2f 100644 --- a/vendor/miniaudio/src/Makefile +++ b/vendor/miniaudio/src/Makefile @@ -1,6 +1,6 @@ all: mkdir -p ../lib - gcc -c -O2 -Os -fPIC miniaudio.c - ar rcs ../lib/miniaudio.a miniaudio.o - #gcc -fPIC -shared -Wl,-soname=miniaudio.so -o ../lib/miniaudio.so miniaudio.o + $(CC) -c -O2 -Os -fPIC miniaudio.c + $(AR) rcs ../lib/miniaudio.a miniaudio.o + #$(CC) -fPIC -shared -Wl,-soname=miniaudio.so -o ../lib/miniaudio.so miniaudio.o rm *.o diff --git a/vendor/stb/src/Makefile b/vendor/stb/src/Makefile index c65aa7263..5504fede9 100644 --- a/vendor/stb/src/Makefile +++ b/vendor/stb/src/Makefile @@ -1,16 +1,16 @@ all: mkdir -p ../lib - gcc -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c - ar rcs ../lib/stb_image.a stb_image.o - ar rcs ../lib/stb_image_write.a stb_image_write.o - ar rcs ../lib/stb_image_resize.a stb_image_resize.o - ar rcs ../lib/stb_truetype.a stb_truetype.o - ar rcs ../lib/stb_rect_pack.a stb_rect_pack.o - #ar rcs ../lib/stb_vorbis_pack.a stb_vorbis_pack.o - #gcc -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o - #gcc -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o - #gcc -fPIC -shared -Wl,-soname=stb_image_resize.so -o ../lib/stb_image_resize.so stb_image_resize.o - #gcc -fPIC -shared -Wl,-soname=stb_truetype.so -o ../lib/stb_truetype.so stb_image_truetype.o - #gcc -fPIC -shared -Wl,-soname=stb_rect_pack.so -o ../lib/stb_rect_pack.so stb_rect_packl.o - #gcc -fPIC -shared -Wl,-soname=stb_vorbis.so -o ../lib/stb_vorbis.so stb_vorbisl.o + $(CC) -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c + $(AR) rcs ../lib/stb_image.a stb_image.o + $(AR) rcs ../lib/stb_image_write.a stb_image_write.o + $(AR) rcs ../lib/stb_image_resize.a stb_image_resize.o + $(AR) rcs ../lib/stb_truetype.a stb_truetype.o + $(AR) rcs ../lib/stb_rect_pack.a stb_rect_pack.o + #$(AR) rcs ../lib/stb_vorbis_pack.a stb_vorbis_pack.o + #$(CC) -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o + #$(CC) -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o + #$(CC) -fPIC -shared -Wl,-soname=stb_image_resize.so -o ../lib/stb_image_resize.so stb_image_resize.o + #$(CC) -fPIC -shared -Wl,-soname=stb_truetype.so -o ../lib/stb_truetype.so stb_image_truetype.o + #$(CC) -fPIC -shared -Wl,-soname=stb_rect_pack.so -o ../lib/stb_rect_pack.so stb_rect_packl.o + #$(CC) -fPIC -shared -Wl,-soname=stb_vorbis.so -o ../lib/stb_vorbis.so stb_vorbisl.o rm *.o From 3dcea60f5b5b390b8cf95085a85e3e65af26133d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 3 Mar 2022 09:27:10 +0000 Subject: [PATCH 0316/1052] vendor: ENet: follow strict-style and remove optional semi-colon --- vendor/ENet/unix.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/ENet/unix.odin b/vendor/ENet/unix.odin index a86e9837c..05ce41e05 100644 --- a/vendor/ENet/unix.odin +++ b/vendor/ENet/unix.odin @@ -14,7 +14,7 @@ import "core:c" @(private="file") FD_ZERO :: #force_inline proc(s: ^fd_set) { for i := size_of(fd_set) / size_of(c.long); i != 0; i -= 1 { - s.fds_bits[i] = 0; + s.fds_bits[i] = 0 } } From ee28945e09bc49aa4217fffb6ba8dc2e82681e01 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 11:19:12 +0000 Subject: [PATCH 0317/1052] Update FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 89b7ffa10..885612f13 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,4 @@ # These are supported funding model platforms +github: odin-lang patreon: gingerbill From 96e36c7c395025a7db5f37675eddbf6d143f3fff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 13:54:23 +0000 Subject: [PATCH 0318/1052] Minor fix to strconv.unquote_string --- core/strconv/strconv.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 6ea8b39e6..65161a820 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -895,6 +895,7 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str if s == `""` { return "", false, true } + s = s[1:len(s)-1] if contains_rune(s, '\n') >= 0 { return s, false, false From bd1b54e0db0bb599f3118c60aac7fdaaaa0dacd4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 13:58:22 +0000 Subject: [PATCH 0319/1052] Fix #1503 --- core/odin/ast/clone.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 723f7b90d..1f2eee124 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -98,7 +98,7 @@ clone_node :: proc(node: ^Node) -> ^Node { reflect.set_union_value(res.derived, derived_expr) reflect.set_union_value(res.derived, derived_stmt) - switch r in res.derived { + if res.derived != nil do switch r in res.derived { case ^Package, ^File: case ^Bad_Expr: case ^Ident: @@ -313,7 +313,7 @@ clone_node :: proc(node: ^Node) -> ^Node { r.tag = clone(r.tag) r.type = clone(r.type) case: - fmt.panicf("Unhandled node kind: %T", r) + fmt.panicf("Unhandled node kind: %v", r) } return res From 2944969ca027f87d278233bb327f12b271522f62 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 14:01:37 +0000 Subject: [PATCH 0320/1052] Correct `clone_node` --- core/odin/ast/clone.odin | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 1f2eee124..b0d997091 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -68,12 +68,13 @@ clone_node :: proc(node: ^Node) -> ^Node { return nil } - size := size_of(Node) + size := size_of(Node) align := align_of(Node) ti := reflect.union_variant_type_info(node.derived) if ti != nil { - size = ti.size - align = ti.align + elem := ti.variant.(reflect.Type_Info_Pointer).elem + size = elem.size + align = elem.align } #partial switch in node.derived { From 8af08f2153294174075b569e81f421a2efd4b183 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 3 Mar 2022 15:10:19 +0100 Subject: [PATCH 0321/1052] [compress] 32-bit cleanness. --- core/compress/common.odin | 8 +++++++- core/compress/gzip/gzip.odin | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/compress/common.odin b/core/compress/common.odin index 5f5ef2413..8bc7d240d 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -139,7 +139,13 @@ Context_Memory_Input :: struct #packed { size_packed: i64, size_unpacked: i64, } -#assert(size_of(Context_Memory_Input) == 64) +when size_of(rawptr) == 8 { + #assert(size_of(Context_Memory_Input) == 64) +} else { + // e.g. `-target:windows_386` + #assert(size_of(Context_Memory_Input) == 52) +} + Context_Stream_Input :: struct #packed { input_data: []u8, diff --git a/core/compress/gzip/gzip.odin b/core/compress/gzip/gzip.odin index 96e9c49a0..4482d4a7e 100644 --- a/core/compress/gzip/gzip.odin +++ b/core/compress/gzip/gzip.odin @@ -100,7 +100,7 @@ E_GZIP :: compress.GZIP_Error E_ZLIB :: compress.ZLIB_Error E_Deflate :: compress.Deflate_Error -GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le)) +GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le)) load :: proc{load_from_slice, load_from_file, load_from_context} @@ -136,7 +136,7 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp z.output = buf - if expected_output_size > GZIP_MAX_PAYLOAD_SIZE { + if i64(expected_output_size) > i64(GZIP_MAX_PAYLOAD_SIZE) { return E_GZIP.Payload_Size_Exceeds_Max_Payload } From 6d9f84ba030c3903dbfb213ee0a0e7a83d410b71 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 3 Mar 2022 15:16:16 +0100 Subject: [PATCH 0322/1052] [tests] Make test runners exit with errorlevel 1 if a test fails. --- tests/core/compress/test_core_compress.odin | 3 +++ tests/core/crypto/test_core_crypto.odin | 4 ++++ tests/core/encoding/test_core_json.odin | 4 ++++ tests/core/hash/test_core_hash.odin | 4 ++++ tests/core/image/test_core_image.odin | 3 +++ tests/core/math/noise/test_core_math_noise.odin | 4 ++++ tests/core/odin/test_parser.odin | 5 ++++- tests/core/strings/test_core_strings.odin | 4 ++++ tests/vendor/botan/test_vendor_botan.odin | 4 ++++ tests/vendor/glfw/test_vendor_glfw.odin | 4 ++++ 10 files changed, 38 insertions(+), 1 deletion(-) diff --git a/tests/core/compress/test_core_compress.odin b/tests/core/compress/test_core_compress.odin index c925c0258..73c69445a 100644 --- a/tests/core/compress/test_core_compress.odin +++ b/tests/core/compress/test_core_compress.odin @@ -52,6 +52,9 @@ main :: proc() { gzip_test(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } @test diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 5682a6167..f2e5b48d9 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -37,6 +37,7 @@ import "core:crypto/jh" import "core:crypto/groestl" import "core:crypto/haval" import "core:crypto/siphash" +import "core:os" TEST_count := 0 TEST_fail := 0 @@ -127,6 +128,9 @@ main :: proc() { bench_modern(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } TestHash :: struct { diff --git a/tests/core/encoding/test_core_json.odin b/tests/core/encoding/test_core_json.odin index f536eb4c6..702086ea2 100644 --- a/tests/core/encoding/test_core_json.odin +++ b/tests/core/encoding/test_core_json.odin @@ -3,6 +3,7 @@ package test_core_json import "core:encoding/json" import "core:testing" import "core:fmt" +import "core:os" TEST_count := 0 TEST_fail := 0 @@ -34,6 +35,9 @@ main :: proc() { marshal_json(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } @test diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index 8baa604b6..f68767612 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -5,6 +5,7 @@ import "core:hash" import "core:time" import "core:testing" import "core:fmt" +import "core:os" TEST_count := 0 TEST_fail := 0 @@ -35,6 +36,9 @@ main :: proc() { test_xxhash_vectors(&t) test_crc64_vectors(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } /* diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 124166245..2171a0d92 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -57,6 +57,9 @@ main :: proc() { png_test(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } PNG_Test :: struct { diff --git a/tests/core/math/noise/test_core_math_noise.odin b/tests/core/math/noise/test_core_math_noise.odin index c3a3e4228..be89d076a 100644 --- a/tests/core/math/noise/test_core_math_noise.odin +++ b/tests/core/math/noise/test_core_math_noise.odin @@ -3,6 +3,7 @@ package test_core_math_noise import "core:testing" import "core:math/noise" import "core:fmt" +import "core:os" TEST_count := 0 TEST_fail := 0 @@ -35,6 +36,9 @@ main :: proc() { t := testing.T{} noise_test(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } Test_Vector :: struct { diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index 90d913d10..ef31f91db 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -2,7 +2,7 @@ package test_core_odin_parser import "core:testing" import "core:fmt" - +import "core:os" import "core:odin/parser" @@ -35,6 +35,9 @@ main :: proc() { test_parse_demo(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index fc1518349..c1f9603fd 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -3,6 +3,7 @@ package test_core_image import "core:strings" import "core:testing" import "core:fmt" +import "core:os" TEST_count := 0 TEST_fail := 0 @@ -35,6 +36,9 @@ main :: proc() { test_index_any_larger_string_found(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } @test diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 148eb03bd..f0ff44ac9 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -14,6 +14,7 @@ package test_vendor_botan import "core:testing" import "core:fmt" +import "core:os" import "vendor:botan/md4" import "vendor:botan/md5" @@ -86,6 +87,9 @@ main :: proc() { test_siphash_2_4(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } TestHash :: struct { diff --git a/tests/vendor/glfw/test_vendor_glfw.odin b/tests/vendor/glfw/test_vendor_glfw.odin index 252df2033..baf46aa7e 100644 --- a/tests/vendor/glfw/test_vendor_glfw.odin +++ b/tests/vendor/glfw/test_vendor_glfw.odin @@ -3,6 +3,7 @@ package test_vendor_glfw import "core:testing" import "core:fmt" import "vendor:glfw" +import "core:os" GLFW_MAJOR :: 3 GLFW_MINOR :: 3 @@ -36,6 +37,9 @@ main :: proc() { test_glfw(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } @(test) From 8c6f39a68d842cee2207eba23b97d17b33fbf36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 3 Mar 2022 15:08:34 +0000 Subject: [PATCH 0323/1052] CI: add linux i386, Darwin arm64 and Windows 386 --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 788c59311..107cdf455 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,9 @@ jobs: cd tests/vendor make timeout-minutes: 10 + - name: Odin check examples/all for Linux i386 + run: ./odin check examples/all -vet -strict-style -target:linux_386 + timeout-minutes: 10 - name: Odin check examples/all for OpenBSD amd64 run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64 timeout-minutes: 10 @@ -81,6 +84,9 @@ jobs: cd tests/vendor make timeout-minutes: 10 + - name: Odin check examples/all for Darwin arm64 + run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 + timeout-minutes: 10 build_windows: runs-on: windows-2019 steps: @@ -141,3 +147,9 @@ jobs: cd tests\core\math\big call build.bat timeout-minutes: 10 + - name: Odin check examples/all for Windows 32bits + shell: cmd + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat + odin check examples/all -strict-style -target:windows_386 + timeout-minutes: 10 From e51bb4ef12ff6e5cf900f266f6da9d132b7167eb Mon Sep 17 00:00:00 2001 From: CiD- Date: Thu, 3 Mar 2022 10:16:36 -0500 Subject: [PATCH 0324/1052] os2 linux begin --- core/os/os2/file_linux.odin | 236 ++++++++++++++++++++++++++++++ core/os/os2/stat_linux.odin | 116 +++++++++++++++ core/sys/unix/syscalls_linux.odin | 138 ++++++++++++++++- 3 files changed, 486 insertions(+), 4 deletions(-) create mode 100644 core/os/os2/file_linux.odin create mode 100644 core/os/os2/stat_linux.odin diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin new file mode 100644 index 000000000..75a71b22b --- /dev/null +++ b/core/os/os2/file_linux.odin @@ -0,0 +1,236 @@ +//+private +package os2 + +import "core:io" +import "core:time" +import "core:sys/unix" + + +_get_platform_error :: proc(res: int) -> Error { + errno := unix.get_errno(res) + return Platform_Error{i32(errno)} +} + +_ok_or_error :: proc(res: int) -> Error { + return res >= 0 ? nil : _get_platform_error(res) +} + +_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + handle := Handle(unix.sys_open(cstr, int(flags), int(perm))) + if handle < 0 { + return Handle(-1), _get_platform_error(int(handle)) + } + return handle, nil +} + +_close :: proc(fd: Handle) -> Error { + res := unix.sys_close(int(fd)) + return _ok_or_error(res) +} + +_name :: proc(fd: Handle, allocator := context.allocator) -> string { + //TODO + return "" +} + +_seek :: proc(fd: Handle, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) { + res := unix.sys_lseek(int(fd), offset, int(whence)) + if res < 0 { + return -1, _get_platform_error(int(res)) + } + return res, nil +} + +_read :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) { + if len(p) == 0 { + return 0, nil + } + n = unix.sys_read(fd, &data[0], c.size_t(len(data))) + if n < 0 { + return -1, unix.get_errno(n) + } + return bytes_read, nil +} + +_read_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) { + if offset < 0 { + return 0, .Invalid_Offset + } + + curr_offset, err := _seek(fd, 0, .Current) + if err != nil { + return 0, err + } + defer _seek(fd, curr_offset, .Start) + _seek(fd, offset, .Start) + + b := p + for len(b) > 0 { + m := _read(fd, b) or_return + n += m + b = b[m:] + } + return +} + +_read_from :: proc(fd: Handle, r: io.Reader) -> (n: i64, err: Error) { + //TODO + return +} + +_write :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) { + if len(p) == 0 { + return 0, nil + } + n = unix.sys_write(fd, &p[0], uint(len(p))) + if n < 0 { + return -1, _get_platform_error(n) + } + return int(n), nil +} + +_write_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) { + if offset < 0 { + return 0, .Invalid_Offset + } + + curr_offset, err := _seek(fd, 0, .Current) + if err != nil { + return 0, err + } + defer _seek(fd, curr_offset, .Start) + _seek(fd, offset, .Start) + + b := p + for len(b) > 0 { + m := _write(fd, b) or_return + n += m + b = b[m:] + } + return +} + +_write_to :: proc(fd: Handle, w: io.Writer) -> (n: i64, err: Error) { + //TODO + return +} + +_file_size :: proc(fd: Handle) -> (n: i64, err: Error) { + s, err := _fstat(fd) or_return + if err != nil { + return 0, err + } + return max(s.size, 0), nil +} + +_sync :: proc(fd: Handle) -> Error { + return _ok_or_error(unix.sys_fsync(int(fd))) +} + +_flush :: proc(fd: Handle) -> Error { + return _ok_or_error(unix.sys_fsync(int(fd))) +} + +_truncate :: proc(fd: Handle, size: i64) -> Error { + return _ok_or_error(unix.sys_ftruncate(int(fd), size)) +} + +_remove :: proc(name: string) -> Error { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + if _is_dir(name) { + return _ok_or_error(unix.sys_rmdir(path_cstr)) + } + return _ok_or_error(unix.sys_unlink(path_cstr)) +} + +_rename :: proc(old_path, new_path: string) -> Error { + old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) + new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) + return _ok_or_error(unix.sys_rename(old_path_cstr, new_path_cstr)) +} + +_link :: proc(old_name, new_name: string) -> Error { + old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) + new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) + return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr)) +} + +_symlink :: proc(old_name, new_name: string) -> Error { + old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) + new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) + return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr)) +} + +_read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) { + path_cstr := strings.clone_to_cstring(path) + defer delete(path_cstr) + + bufsz : uint = 256 + buf := make([]byte, bufsz, allocator) + for { + rc := unix.sys_readlink(path_cstr, &(buf[0]), bufsz) + if rc < 0 { + delete(buf) + return "", unix.get_errno(rc) + } else if rc == int(bufsz) { + bufsz *= 2 + delete(buf) + buf = make([]byte, bufsz, allocator) + } else { + return strings.string_from_ptr(&buf[0], rc), nil + } + } +} + +_unlink :: proc(path: string) -> Error { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + return _ok_or_error(unix.sys_unlink(path_cstr)) +} + +_chdir :: proc(fd: Handle) -> Error { + return _ok_or_error(unix.sys_fchdir(int(fd))) +} + +_chmod :: proc(fd: Handle, mode: File_Mode) -> Error { + //TODO + return nil +} + +_chown :: proc(fd: Handle, uid, gid: int) -> Error { + //TODO + return nil +} + +_lchown :: proc(name: string, uid, gid: int) -> Error { + //TODO + return nil +} + +_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { + //TODO + return nil +} + +_exists :: proc(path: string) -> bool { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + return unix.sys_access(path_cstr, F_OK) == 0 +} + +_is_file :: proc(fd: Handle) -> bool { + s: OS_Stat + res := unix.sys_fstat(int(fd), rawptr(&s)) + if res < 0 { // error + return false + } + return S_ISREG(s.mode) +} + +_is_dir :: proc(fd: Handle) -> bool { + s: OS_Stat + res := unix.sys_fstat(int(fd), rawptr(&s)) + if res < 0 { // error + return false + } + return S_ISDIR(s.mode) +} diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin new file mode 100644 index 000000000..7fce8fb9c --- /dev/null +++ b/core/os/os2/stat_linux.odin @@ -0,0 +1,116 @@ +//+private +package os2 + +import "core:time" +import "core:sys/unix" + +// File type +S_IFMT :: 0o170000 // Type of file mask +S_IFIFO :: 0o010000 // Named pipe (fifo) +S_IFCHR :: 0o020000 // Character special +S_IFDIR :: 0o040000 // Directory +S_IFBLK :: 0o060000 // Block special +S_IFREG :: 0o100000 // Regular +S_IFLNK :: 0o120000 // Symbolic link +S_IFSOCK :: 0o140000 // Socket + +// File mode +// Read, write, execute/search by owner +S_IRWXU :: 0o0700 // RWX mask for owner +S_IRUSR :: 0o0400 // R for owner +S_IWUSR :: 0o0200 // W for owner +S_IXUSR :: 0o0100 // X for owner + + // Read, write, execute/search by group +S_IRWXG :: 0o0070 // RWX mask for group +S_IRGRP :: 0o0040 // R for group +S_IWGRP :: 0o0020 // W for group +S_IXGRP :: 0o0010 // X for group + + // Read, write, execute/search by others +S_IRWXO :: 0o0007 // RWX mask for other +S_IROTH :: 0o0004 // R for other +S_IWOTH :: 0o0002 // W for other +S_IXOTH :: 0o0001 // X for other + +S_ISUID :: 0o4000 // Set user id on execution +S_ISGID :: 0o2000 // Set group id on execution +S_ISVTX :: 0o1000 // Directory restrcted delete + + +S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } +S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } +S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } +S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } +S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } +S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } +S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } + +F_OK :: 0 // Test for file existance +X_OK :: 1 // Test for execute permission +W_OK :: 2 // Test for write permission +R_OK :: 4 // Test for read permission + +@private +OS_Stat :: struct { + device_id: u64, // ID of device containing file + serial: u64, // File serial number + nlink: u64, // Number of hard links + mode: u32, // Mode of the file + uid: u32, // User ID of the file's owner + gid: u32, // Group ID of the file's group + _padding: i32, // 32 bits of padding + rdev: u64, // Device ID, if device + size: i64, // Size of the file, in bytes + block_size: i64, // Optimal bllocksize for I/O + blocks: i64, // Number of 512-byte blocks allocated + + last_access: Unix_File_Time, // Time of last access + modified: Unix_File_Time, // Time of last modification + status_change: Unix_File_Time, // Time of last status change + + _reserve1, + _reserve2, + _reserve3: i64, +} + +_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) { +} + +_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { +} + +_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { + cstr := strings.clone_to_cstring(path) + defer delete(cstr) + + s: OS_Stat + result := unix.sys_lstat(cstr, &s) + if result < 0 { + return {}, unix.get_errno(result) + } + + fi := File_Info { + fullpath = "", + name = "", + size = s.size, + mode = 0, + is_dir = S_ISDIR(s.mode), + creation_time = nil, // linux does not track this + //TODO + modification_time = nil, + access_time = nil, + } + + return fi, nil +} + +_same_file :: proc(fi1, fi2: File_Info) -> bool { + return fi1.fullpath == fi2.fullpath +} + +_stat_internal :: proc(name: string) -> (s: OS_Stat, res: int) { + name_cstr = strings.clone_to_cstring(name, context.temp_allocator) + res = unix.sys_stat(name_cstr, &s) + return +} diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 0082c7261..243f8accc 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -15,7 +15,7 @@ import "core:intrinsics" // 386: arch/x86/entry/syscalls/sycall_32.tbl // arm: arch/arm/tools/syscall.tbl -when ODIN_ARCH == .amd64 { +when ODIN_ARCH == "amd64" { SYS_read : uintptr : 0 SYS_write : uintptr : 1 SYS_open : uintptr : 2 @@ -374,7 +374,7 @@ when ODIN_ARCH == .amd64 { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when ODIN_ARCH == .arm64 { +} else when ODIN_ARCH == "arm64" { SYS_io_setup : uintptr : 0 SYS_io_destroy : uintptr : 1 SYS_io_submit : uintptr : 2 @@ -675,7 +675,7 @@ when ODIN_ARCH == .amd64 { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 -} else when ODIN_ARCH == .i386 { +} else when ODIN_ARCH == "386" { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 @@ -1112,7 +1112,7 @@ when ODIN_ARCH == .amd64 { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when false /*ODIN_ARCH == .arm*/ { // TODO +} else when ODIN_ARCH == "arm" { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 @@ -1516,6 +1516,10 @@ when ODIN_ARCH == .amd64 { #panic("Unsupported architecture") } +AT_FDCWD :: -100 +AT_REMOVEDIR :: uintptr(0x200) +AT_SYMLINK_NOFOLLOW :: uintptr(0x100) + sys_gettid :: proc "contextless" () -> int { return cast(int)intrinsics.syscall(SYS_gettid) } @@ -1523,3 +1527,129 @@ sys_gettid :: proc "contextless" () -> int { sys_getrandom :: proc "contextless" (buf: ^byte, buflen: int, flags: uint) -> int { return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags)) } + +sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { + when ODIN_ARCH != "arm64" { + res := int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) + } else { // NOTE: arm64 does not have open + res := int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) + } + return -1 if res < 0 else res +} + +sys_close :: proc(fd: int) -> int { + return int(intrinsics.syscall(SYS_close, uintptr(fd))) +} + +sys_read :: proc(fd: int, buf: rawptr, size: uint) -> int { + return int(intrinsics.syscall(SYS_read, uintptr(fd), uintptr(buf), uintptr(size))) +} + +sys_write :: proc(fd: int, buf: rawptr, size: uint) -> int { + return int(intrinsics.syscall(SYS_write, uintptr(fd), uintptr(buf), uintptr(size))) +} + +sys_lseek :: proc(fd: int, offset: i64, whence: int) -> i64 { + when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + return i64(intrinsics.syscall(SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) + } else { + low := uintptr(offset & 0xFFFFFFFF) + high := uintptr(offset >> 32) + result: i64 + res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence))) + return -1 if res < 0 else result + } +} + +sys_stat :: proc(path: cstring, stat: rawptr) -> int { + when ODIN_ARCH == "amd64" { + return int(intrinsics.syscall(SYS_stat, uintptr(rawptr(path)), uintptr(stat))) + } else when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) + } else { // NOTE: arm64 does not have stat + return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0)) + } +} + +sys_fstat :: proc(fd: int, stat: rawptr) -> int { + when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + return int(intrinsics.syscall(SYS_fstat, uintptr(fd), uintptr(stat))) + } else { + return int(intrinsics.syscall(SYS_fstat64, uintptr(fd), uintptr(stat))) + } +} + +sys_lstat :: proc(path: cstring, stat: rawptr) -> int { + when ODIN_ARCH == "amd64" { + return int(intrinsics.syscall(SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) + } else when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) + } else { // NOTE: arm64 does not have any lstat + return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) + } +} + +sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) + } else { // NOTE: arm64 does not have readlink + return int(intrinsics.syscall(SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) + } +} + +sys_access :: proc(path: cstring, mask: int) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_access, uintptr(rawptr(path)), uintptr(mask))) + } else { // NOTE: arm64 does not have access + return int(intrinsics.syscall(SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask))) + } +} + +sys_getcwd :: proc(buf: rawptr, size: uint) -> int { + return int(intrinsics.syscall(SYS_getcwd, uintptr(buf), uintptr(size))) +} + +sys_chdir :: proc(path: cstring) -> int { + return int(intrinsics.syscall(SYS_chdir, uintptr(rawptr(path)))) +} + +sys_rename :: proc(old, new: cstring) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) + } else { // NOTE: arm64 does not have rename + return int(intrinsics.syscall(SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new)))) + } +} + +sys_unlink :: proc(path: cstring) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_unlink, uintptr(rawptr(path)))) + } else { // NOTE: arm64 does not have unlink + return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0))) + } +} + +sys_rmdir :: proc(path: cstring) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path)))) + } else { // NOTE: arm64 does not have rmdir + return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR)) + } +} + +sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) + } else { // NOTE: arm64 does not have mkdir + return int(intrinsics.syscall(SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + } +} + +//TODO: ftruncate, symlink, readlink, fchdir, fchmod, chown, fchown, lchown + +get_errno :: proc(res: int) -> i32 { + if res < 0 && res > -4096 { + return i32(-res) + } + return 0 +} From 499c657ffa09868ef306087ff3e71a546ae42021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 3 Mar 2022 15:28:18 +0000 Subject: [PATCH 0325/1052] rename architecture from 386 to i386 --- .github/workflows/ci.yml | 4 ++-- core/compress/common.odin | 4 ++-- src/build_settings.cpp | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 107cdf455..412587b3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: make timeout-minutes: 10 - name: Odin check examples/all for Linux i386 - run: ./odin check examples/all -vet -strict-style -target:linux_386 + run: ./odin check examples/all -vet -strict-style -target:linux_i386 timeout-minutes: 10 - name: Odin check examples/all for OpenBSD amd64 run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64 @@ -151,5 +151,5 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin check examples/all -strict-style -target:windows_386 + odin check examples/all -strict-style -target:windows_i386 timeout-minutes: 10 diff --git a/core/compress/common.odin b/core/compress/common.odin index 8bc7d240d..c8e86a97e 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -142,7 +142,7 @@ Context_Memory_Input :: struct #packed { when size_of(rawptr) == 8 { #assert(size_of(Context_Memory_Input) == 64) } else { - // e.g. `-target:windows_386` + // e.g. `-target:windows_i386` #assert(size_of(Context_Memory_Input) == 52) } @@ -479,4 +479,4 @@ discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) { consume_bits_lsb(z, discard) } -discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}; \ No newline at end of file +discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}; diff --git a/src/build_settings.cpp b/src/build_settings.cpp index c40a70069..9cb281656 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -280,7 +280,7 @@ bool global_ignore_warnings(void) { } -gb_global TargetMetrics target_windows_386 = { +gb_global TargetMetrics target_windows_i386 = { TargetOs_windows, TargetArch_i386, 4, @@ -296,7 +296,7 @@ gb_global TargetMetrics target_windows_amd64 = { str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; -gb_global TargetMetrics target_linux_386 = { +gb_global TargetMetrics target_linux_i386 = { TargetOs_linux, TargetArch_i386, 4, @@ -339,7 +339,7 @@ gb_global TargetMetrics target_darwin_arm64 = { str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct? }; -gb_global TargetMetrics target_freebsd_386 = { +gb_global TargetMetrics target_freebsd_i386 = { TargetOs_freebsd, TargetArch_i386, 4, @@ -421,12 +421,12 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("darwin_amd64"), &target_darwin_amd64 }, { str_lit("darwin_arm64"), &target_darwin_arm64 }, { str_lit("essence_amd64"), &target_essence_amd64 }, - { str_lit("linux_386"), &target_linux_386 }, + { str_lit("linux_i386"), &target_linux_i386 }, { str_lit("linux_amd64"), &target_linux_amd64 }, { str_lit("linux_arm64"), &target_linux_arm64 }, - { str_lit("windows_386"), &target_windows_386 }, + { str_lit("windows_i386"), &target_windows_i386 }, { str_lit("windows_amd64"), &target_windows_amd64 }, - { str_lit("freebsd_386"), &target_freebsd_386 }, + { str_lit("freebsd_i386"), &target_freebsd_i386 }, { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, { str_lit("openbsd_amd64"), &target_openbsd_amd64 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, @@ -971,13 +971,13 @@ void init_build_context(TargetMetrics *cross_target) { #endif #else #if defined(GB_SYSTEM_WINDOWS) - metrics = &target_windows_386; + metrics = &target_windows_i386; #elif defined(GB_SYSTEM_OSX) #error "Build Error: Unsupported architecture" #elif defined(GB_SYSTEM_FREEBSD) - metrics = &target_freebsd_386; + metrics = &target_freebsd_i386; #else - metrics = &target_linux_386; + metrics = &target_linux_i386; #endif #endif From 832961d53921ea8084d7107ffacedd4021e7326b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 3 Mar 2022 15:36:04 +0000 Subject: [PATCH 0326/1052] semi-colons are deprecated in core --- core/compress/common.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/compress/common.odin b/core/compress/common.odin index c8e86a97e..fb0f74e95 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -479,4 +479,4 @@ discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) { consume_bits_lsb(z, discard) } -discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}; +discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream} From fad851d80c4d2ded5eba6b766ca00d90893c73aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 3 Mar 2022 15:57:51 +0000 Subject: [PATCH 0327/1052] check for semi-colon before EOF too --- src/parser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index f70afe346..94a585f35 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1538,7 +1538,7 @@ void fix_advance_to_next_stmt(AstFile *f) { Token expect_closing(AstFile *f, TokenKind kind, String context) { if (f->curr_token.kind != kind && f->curr_token.kind == Token_Semicolon && - f->curr_token.string == "\n") { + (f->curr_token.string == "\n" || f->curr_token.kind == Token_EOF)) { Token tok = f->prev_token; tok.pos.column += cast(i32)tok.string.len; syntax_error(tok, "Missing ',' before newline in %.*s", LIT(context)); @@ -1560,6 +1560,7 @@ void assign_removal_flag_to_semicolon(AstFile *f) { switch (curr_token->kind) { case Token_CloseBrace: case Token_CloseParen: + case Token_EOF: ok = true; break; } From dfe2c0a600aa3d78b56b5df54ba4c46620c59a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 3 Mar 2022 15:57:55 +0000 Subject: [PATCH 0328/1052] remove some leftover semi-colons before EOF --- core/compress/common.odin | 2 +- core/compress/zlib/zlib.odin | 2 +- vendor/sdl2/sdl_keycode.odin | 2 +- vendor/sdl2/sdl_scancode.odin | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/compress/common.odin b/core/compress/common.odin index 8bc7d240d..04fcd3478 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -479,4 +479,4 @@ discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) { consume_bits_lsb(z, discard) } -discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}; \ No newline at end of file +discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream} diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index d4c0f332c..d4b770929 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -677,4 +677,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals return inflate_raw(z=&ctx, expected_output_size=expected_output_size) } -inflate :: proc{inflate_from_context, inflate_from_byte_array}; \ No newline at end of file +inflate :: proc{inflate_from_context, inflate_from_byte_array} diff --git a/vendor/sdl2/sdl_keycode.odin b/vendor/sdl2/sdl_keycode.odin index 73637f072..c03fdc2a9 100644 --- a/vendor/sdl2/sdl_keycode.odin +++ b/vendor/sdl2/sdl_keycode.odin @@ -327,4 +327,4 @@ KMOD_RESERVED :: Keymod{.RESERVED} KMOD_CTRL :: Keymod{.LCTRL, .RCTRL} KMOD_SHIFT :: Keymod{.LSHIFT, .RSHIFT} KMOD_ALT :: Keymod{.LALT, .RALT} -KMOD_GUI :: Keymod{.LGUI, .RGUI}; \ No newline at end of file +KMOD_GUI :: Keymod{.LGUI, .RGUI} diff --git a/vendor/sdl2/sdl_scancode.odin b/vendor/sdl2/sdl_scancode.odin index d27bba7f7..ca2169778 100644 --- a/vendor/sdl2/sdl_scancode.odin +++ b/vendor/sdl2/sdl_scancode.odin @@ -539,4 +539,4 @@ SCANCODE_APP1 :: Scancode.APP1 SCANCODE_APP2 :: Scancode.APP2 SCANCODE_AUDIOREWIND :: Scancode.AUDIOREWIND -SCANCODE_AUDIOFASTFORWARD :: Scancode.AUDIOFASTFORWARD; \ No newline at end of file +SCANCODE_AUDIOFASTFORWARD :: Scancode.AUDIOFASTFORWARD From 913d802e3381f61d3bd6e9e67b91fbe991733c88 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 23:10:38 +0000 Subject: [PATCH 0329/1052] Fix `ast.clone_node` --- core/odin/ast/clone.odin | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index b0d997091..400c064f5 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -88,16 +88,20 @@ clone_node :: proc(node: ^Node) -> ^Node { src = (^rawptr)(&node.derived)^ } mem.copy(res, src, size) - res_any: any - res_any.data = res - res_any.id = ti.id + res_ptr_any: any + res_ptr_any.data = &res + res_ptr_any.id = ti.id - reflect.set_union_value(res.derived, res_any) + reflect.set_union_value(res.derived, res_ptr_any) - derived_expr := reflect.struct_field_value_by_name(res_any, "derived_expr", true) - derived_stmt := reflect.struct_field_value_by_name(res_any, "derived_stmt", true) - reflect.set_union_value(res.derived, derived_expr) - reflect.set_union_value(res.derived, derived_stmt) + res_ptr := reflect.deref(res_ptr_any) + + if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); de != nil { + reflect.set_union_value(de, res_ptr_any) + } + if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); ds != nil { + reflect.set_union_value(ds, res_ptr_any) + } if res.derived != nil do switch r in res.derived { case ^Package, ^File: From 1abd95094d0853fd9bcc5825ef3b63e8d26443bc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 23:25:22 +0000 Subject: [PATCH 0330/1052] Add `reflect.deref` --- core/reflect/reflect.odin | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 05b3a5da0..d05026532 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -365,6 +365,19 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any { return nil } +deref :: proc(val: any) -> any { + if val != nil { + ti := type_info_base(type_info_of(val.id)) + if info, ok := ti.variant.(Type_Info_Pointer); ok { + return any{ + (^rawptr)(val.data)^, + info.elem.id, + } + } + } + return val +} + // Struct_Tag represents the type of the string of a struct field @@ -680,7 +693,6 @@ union_variant_typeid :: proc(a: any) -> typeid { return nil } panic("expected a union to reflect.union_variant_typeid") - } get_union_variant_raw_tag :: proc(a: any) -> i64 { From 7e8b9862b9049f6ca1300c34857244828fae1102 Mon Sep 17 00:00:00 2001 From: WalterPlinge <22519813+WalterPlinge@users.noreply.github.com> Date: Thu, 3 Mar 2022 22:21:41 +0000 Subject: [PATCH 0331/1052] update vulkan generator change procedure file generation - group procedure types together - sort groups by procedure names - overload function `load_proc_addresses` - kept original as `custom` - added `global`, `instance`, and `device` variants for simpler loading - added `device_vtable` variant to support multiple devices --- .../vulkan/_gen/create_vulkan_odin_wrapper.py | 139 +- vendor/vulkan/procedures.odin | 4383 +++++++++++------ 2 files changed, 3110 insertions(+), 1412 deletions(-) diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index e7fb234c8..f1949f973 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -444,7 +444,7 @@ procedure_map = {} def parse_procedures(f): data = re.findall(r"typedef (\w+\*?) \(\w+ \*(\w+)\)\((.+?)\);", src, re.S) - ff = [] + group_ff = {"Loader":[], "Misc":[], "Instance":[], "Device":[]} for rt, name, fields in data: proc_name = no_vk(name) @@ -464,18 +464,32 @@ def parse_procedures(f): ts += " -> {}".format(rt_str) procedure_map[proc_name] = ts - ff.append( (proc_name, ts) ) - max_len = max(len(n) for n, t in ff) + fields_types_name = [do_type(t) for t in re.findall(r"(?:\s*|)(.+?)\s*\w+(?:,|$)", fields)] + table_name = fields_types_name[0] + nn = (proc_name, ts) + if table_name in ('Device', 'Queue', 'CommandBuffer') and proc_name != 'GetDeviceProcAddr': + group_ff["Device"].append(nn) + elif table_name in ('Instance', 'PhysicalDevice') or proc_name == 'GetDeviceProcAddr': + group_ff["Instance"].append(nn) + elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or proc_name == 'GetInstanceProcAddr': + group_ff["Misc"].append(nn) + else: + group_ff["Loader"].append(nn) + f.write("import \"core:c\"\n\n") - f.write("// Procedure Types\n\n"); - for n, t in ff: - f.write("{} :: #type {}\n".format(n.ljust(max_len), t.replace('"c"', '"system"'))) + for group_name, ff in group_ff.items(): + ff.sort() + f.write("// {} Procedure Types\n".format(group_name)) + max_len = max(len(n) for n, t in ff) + for n, t in ff: + f.write("{} :: #type {}\n".format(n.ljust(max_len), t.replace('"c"', '"system"'))) + f.write("\n") def group_functions(f): data = re.findall(r"typedef (\w+\*?) \(\w+ \*(\w+)\)\((.+?)\);", src, re.S) - group_map = {"Instance":[], "Device":[], "Loader":[]} + group_map = {"Loader":[], "Instance":[], "Device":[]} for rt, vkname, fields in data: fields_types_name = [do_type(t) for t in re.findall(r"(?:\s*|)(.+?)\s*\w+(?:,|$)", fields)] @@ -493,6 +507,8 @@ def group_functions(f): pass else: group_map["Loader"].append(nn) + for _, group in group_map.items(): + group.sort() for group_name, group_lines in group_map.items(): f.write("// {} Procedures\n".format(group_name)) @@ -502,7 +518,7 @@ def group_functions(f): f.write('{}: {}\n'.format(remove_prefix(name, "Proc"), name.rjust(max_len))) f.write("\n") - f.write("load_proc_addresses :: proc(set_proc_address: SetProcAddressType) {\n") + f.write("load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {\n") for group_name, group_lines in group_map.items(): f.write("\t// {} Procedures\n".format(group_name)) max_len = max(len(name) for name, _ in group_lines) @@ -514,7 +530,77 @@ def group_functions(f): remove_prefix(vk_name, 'Proc'), )) f.write("\n") - f.write("}\n") + f.write("}\n\n") + + f.write("// Device Procedure VTable\n") + f.write("Device_VTable :: struct {\n") + max_len = max(len(name) for name, _ in group_map["Device"]) + for name, vk_name in group_map["Device"]: + f.write('\t{}: {},\n'.format(remove_prefix(name, "Proc"), name.rjust(max_len))) + f.write("}\n\n") + + f.write("load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable) {\n") + for name, vk_name in group_map["Device"]: + k = max_len - len(name) + f.write('\tvtable.{}{} = auto_cast GetDeviceProcAddr(device, "vk{}")\n'.format( + remove_prefix(name, 'Proc'), + "".ljust(k), + remove_prefix(vk_name, 'Proc'), + )) + f.write("}\n\n") + + f.write("load_proc_addresses_device :: proc(device: Device) {\n") + max_len = max(len(name) for name, _ in group_map["Device"]) + for name, vk_name in group_map["Device"]: + k = max_len - len(name) + f.write('\t{}{} = auto_cast GetDeviceProcAddr(device, "vk{}")\n'.format( + remove_prefix(name, 'Proc'), + "".ljust(k), + remove_prefix(vk_name, 'Proc'), + )) + f.write("}\n\n") + + f.write("load_proc_addresses_instance :: proc(instance: Instance) {\n") + max_len = max(len(name) for name, _ in group_map["Instance"]) + for name, vk_name in group_map["Instance"]: + k = max_len - len(name) + f.write('\t{}{} = auto_cast GetInstanceProcAddr(instance, "vk{}")\n'.format( + remove_prefix(name, 'Proc'), + "".ljust(k), + remove_prefix(vk_name, 'Proc'), + )) + f.write("\n\t// Device Procedures (may call into dispatch)\n") + max_len = max(len(name) for name, _ in group_map["Device"]) + for name, vk_name in group_map["Device"]: + k = max_len - len(name) + f.write('\t{}{} = auto_cast GetInstanceProcAddr(instance, "vk{}")\n'.format( + remove_prefix(name, 'Proc'), + "".ljust(k), + remove_prefix(vk_name, 'Proc'), + )) + f.write("}\n\n") + + f.write("load_proc_addresses_global :: proc(vk_get_instance_proc_addr: rawptr) {\n") + f.write("\tGetInstanceProcAddr = auto_cast vk_get_instance_proc_addr\n\n") + max_len = max(len(name) for name, _ in group_map["Loader"]) + for name, vk_name in group_map["Loader"]: + k = max_len - len(name) + f.write('\t{}{} = auto_cast GetInstanceProcAddr(nil, "vk{}")\n'.format( + remove_prefix(name, 'Proc'), + "".ljust(k), + remove_prefix(vk_name, 'Proc'), + )) + f.write("}\n\n") + + f.write(""" +load_proc_addresses :: proc{ +\tload_proc_addresses_global, +\tload_proc_addresses_instance, +\tload_proc_addresses_device, +\tload_proc_addresses_device_vtable, +\tload_proc_addresses_custom, +}\n +"""[1::]) @@ -581,14 +667,14 @@ MAX_GLOBAL_PRIORITY_SIZE_EXT :: 16 parse_handles_def(f) f.write("\n\n") parse_flags_def(f) - with open("../enums.odin", 'w', encoding='utf-8') as f: - f.write(BASE) - f.write("\n") - parse_enums(f) - f.write("\n\n") - with open("../structs.odin", 'w', encoding='utf-8') as f: - f.write(BASE) - f.write(""" +with open("../enums.odin", 'w', encoding='utf-8') as f: + f.write(BASE) + f.write("\n") + parse_enums(f) + f.write("\n\n") +with open("../structs.odin", 'w', encoding='utf-8') as f: + f.write(BASE) + f.write(""" import "core:c" when ODIN_OS == .Windows { @@ -622,13 +708,12 @@ CAMetalLayer :: struct {} /********************************/ """) - f.write("\n") - parse_structs(f) - f.write("\n\n") - with open("../procedures.odin", 'w', encoding='utf-8') as f: - f.write(BASE) - f.write("\n") - parse_procedures(f) - f.write("\n") - group_functions(f) - f.write("\n\n") \ No newline at end of file + f.write("\n") + parse_structs(f) + f.write("\n\n") +with open("../procedures.odin", 'w', encoding='utf-8') as f: + f.write(BASE) + f.write("\n") + parse_procedures(f) + f.write("\n") + group_functions(f) diff --git a/vendor/vulkan/procedures.odin b/vendor/vulkan/procedures.odin index b40523b6d..7557d3c36 100644 --- a/vendor/vulkan/procedures.odin +++ b/vendor/vulkan/procedures.odin @@ -5,1412 +5,3025 @@ package vulkan import "core:c" -// Procedure Types +// Loader Procedure Types +ProcCreateInstance :: #type proc "system" (pCreateInfo: ^InstanceCreateInfo, pAllocator: ^AllocationCallbacks, pInstance: ^Instance) -> Result +ProcDebugUtilsMessengerCallbackEXT :: #type proc "system" (messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT, pUserData: rawptr) -> b32 +ProcDeviceMemoryReportCallbackEXT :: #type proc "system" (pCallbackData: ^DeviceMemoryReportCallbackDataEXT, pUserData: rawptr) +ProcEnumerateInstanceExtensionProperties :: #type proc "system" (pLayerName: cstring, pPropertyCount: ^u32, pProperties: [^]ExtensionProperties) -> Result +ProcEnumerateInstanceLayerProperties :: #type proc "system" (pPropertyCount: ^u32, pProperties: [^]LayerProperties) -> Result +ProcEnumerateInstanceVersion :: #type proc "system" (pApiVersion: ^u32) -> Result -ProcAllocationFunction :: #type proc "system" (pUserData: rawptr, size: int, alignment: int, allocationScope: SystemAllocationScope) -> rawptr -ProcFreeFunction :: #type proc "system" (pUserData: rawptr, pMemory: rawptr) -ProcInternalAllocationNotification :: #type proc "system" (pUserData: rawptr, size: int, allocationType: InternalAllocationType, allocationScope: SystemAllocationScope) -ProcInternalFreeNotification :: #type proc "system" (pUserData: rawptr, size: int, allocationType: InternalAllocationType, allocationScope: SystemAllocationScope) -ProcReallocationFunction :: #type proc "system" (pUserData: rawptr, pOriginal: rawptr, size: int, alignment: int, allocationScope: SystemAllocationScope) -> rawptr -ProcVoidFunction :: #type proc "system" () -ProcCreateInstance :: #type proc "system" (pCreateInfo: ^InstanceCreateInfo, pAllocator: ^AllocationCallbacks, pInstance: ^Instance) -> Result -ProcDestroyInstance :: #type proc "system" (instance: Instance, pAllocator: ^AllocationCallbacks) -ProcEnumeratePhysicalDevices :: #type proc "system" (instance: Instance, pPhysicalDeviceCount: ^u32, pPhysicalDevices: [^]PhysicalDevice) -> Result -ProcGetPhysicalDeviceFeatures :: #type proc "system" (physicalDevice: PhysicalDevice, pFeatures: [^]PhysicalDeviceFeatures) -ProcGetPhysicalDeviceFormatProperties :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, pFormatProperties: [^]FormatProperties) -ProcGetPhysicalDeviceImageFormatProperties :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, type: ImageType, tiling: ImageTiling, usage: ImageUsageFlags, flags: ImageCreateFlags, pImageFormatProperties: [^]ImageFormatProperties) -> Result -ProcGetPhysicalDeviceProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pProperties: [^]PhysicalDeviceProperties) -ProcGetPhysicalDeviceQueueFamilyProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pQueueFamilyPropertyCount: ^u32, pQueueFamilyProperties: [^]QueueFamilyProperties) -ProcGetPhysicalDeviceMemoryProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pMemoryProperties: [^]PhysicalDeviceMemoryProperties) -ProcGetInstanceProcAddr :: #type proc "system" (instance: Instance, pName: cstring) -> ProcVoidFunction -ProcGetDeviceProcAddr :: #type proc "system" (device: Device, pName: cstring) -> ProcVoidFunction -ProcCreateDevice :: #type proc "system" (physicalDevice: PhysicalDevice, pCreateInfo: ^DeviceCreateInfo, pAllocator: ^AllocationCallbacks, pDevice: ^Device) -> Result -ProcDestroyDevice :: #type proc "system" (device: Device, pAllocator: ^AllocationCallbacks) -ProcEnumerateInstanceExtensionProperties :: #type proc "system" (pLayerName: cstring, pPropertyCount: ^u32, pProperties: [^]ExtensionProperties) -> Result -ProcEnumerateDeviceExtensionProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pLayerName: cstring, pPropertyCount: ^u32, pProperties: [^]ExtensionProperties) -> Result -ProcEnumerateInstanceLayerProperties :: #type proc "system" (pPropertyCount: ^u32, pProperties: [^]LayerProperties) -> Result -ProcEnumerateDeviceLayerProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]LayerProperties) -> Result -ProcGetDeviceQueue :: #type proc "system" (device: Device, queueFamilyIndex: u32, queueIndex: u32, pQueue: ^Queue) -ProcQueueSubmit :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo, fence: Fence) -> Result -ProcQueueWaitIdle :: #type proc "system" (queue: Queue) -> Result -ProcDeviceWaitIdle :: #type proc "system" (device: Device) -> Result -ProcAllocateMemory :: #type proc "system" (device: Device, pAllocateInfo: ^MemoryAllocateInfo, pAllocator: ^AllocationCallbacks, pMemory: ^DeviceMemory) -> Result -ProcFreeMemory :: #type proc "system" (device: Device, memory: DeviceMemory, pAllocator: ^AllocationCallbacks) -ProcMapMemory :: #type proc "system" (device: Device, memory: DeviceMemory, offset: DeviceSize, size: DeviceSize, flags: MemoryMapFlags, ppData: ^rawptr) -> Result -ProcUnmapMemory :: #type proc "system" (device: Device, memory: DeviceMemory) -ProcFlushMappedMemoryRanges :: #type proc "system" (device: Device, memoryRangeCount: u32, pMemoryRanges: [^]MappedMemoryRange) -> Result -ProcInvalidateMappedMemoryRanges :: #type proc "system" (device: Device, memoryRangeCount: u32, pMemoryRanges: [^]MappedMemoryRange) -> Result -ProcGetDeviceMemoryCommitment :: #type proc "system" (device: Device, memory: DeviceMemory, pCommittedMemoryInBytes: [^]DeviceSize) -ProcBindBufferMemory :: #type proc "system" (device: Device, buffer: Buffer, memory: DeviceMemory, memoryOffset: DeviceSize) -> Result -ProcBindImageMemory :: #type proc "system" (device: Device, image: Image, memory: DeviceMemory, memoryOffset: DeviceSize) -> Result -ProcGetBufferMemoryRequirements :: #type proc "system" (device: Device, buffer: Buffer, pMemoryRequirements: [^]MemoryRequirements) -ProcGetImageMemoryRequirements :: #type proc "system" (device: Device, image: Image, pMemoryRequirements: [^]MemoryRequirements) -ProcGetImageSparseMemoryRequirements :: #type proc "system" (device: Device, image: Image, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements) -ProcGetPhysicalDeviceSparseImageFormatProperties :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, type: ImageType, samples: SampleCountFlags, usage: ImageUsageFlags, tiling: ImageTiling, pPropertyCount: ^u32, pProperties: [^]SparseImageFormatProperties) -ProcQueueBindSparse :: #type proc "system" (queue: Queue, bindInfoCount: u32, pBindInfo: ^BindSparseInfo, fence: Fence) -> Result -ProcCreateFence :: #type proc "system" (device: Device, pCreateInfo: ^FenceCreateInfo, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result -ProcDestroyFence :: #type proc "system" (device: Device, fence: Fence, pAllocator: ^AllocationCallbacks) -ProcResetFences :: #type proc "system" (device: Device, fenceCount: u32, pFences: [^]Fence) -> Result -ProcGetFenceStatus :: #type proc "system" (device: Device, fence: Fence) -> Result -ProcWaitForFences :: #type proc "system" (device: Device, fenceCount: u32, pFences: [^]Fence, waitAll: b32, timeout: u64) -> Result -ProcCreateSemaphore :: #type proc "system" (device: Device, pCreateInfo: ^SemaphoreCreateInfo, pAllocator: ^AllocationCallbacks, pSemaphore: ^Semaphore) -> Result -ProcDestroySemaphore :: #type proc "system" (device: Device, semaphore: Semaphore, pAllocator: ^AllocationCallbacks) -ProcCreateEvent :: #type proc "system" (device: Device, pCreateInfo: ^EventCreateInfo, pAllocator: ^AllocationCallbacks, pEvent: ^Event) -> Result -ProcDestroyEvent :: #type proc "system" (device: Device, event: Event, pAllocator: ^AllocationCallbacks) -ProcGetEventStatus :: #type proc "system" (device: Device, event: Event) -> Result -ProcSetEvent :: #type proc "system" (device: Device, event: Event) -> Result -ProcResetEvent :: #type proc "system" (device: Device, event: Event) -> Result -ProcCreateQueryPool :: #type proc "system" (device: Device, pCreateInfo: ^QueryPoolCreateInfo, pAllocator: ^AllocationCallbacks, pQueryPool: ^QueryPool) -> Result -ProcDestroyQueryPool :: #type proc "system" (device: Device, queryPool: QueryPool, pAllocator: ^AllocationCallbacks) -ProcGetQueryPoolResults :: #type proc "system" (device: Device, queryPool: QueryPool, firstQuery: u32, queryCount: u32, dataSize: int, pData: rawptr, stride: DeviceSize, flags: QueryResultFlags) -> Result -ProcCreateBuffer :: #type proc "system" (device: Device, pCreateInfo: ^BufferCreateInfo, pAllocator: ^AllocationCallbacks, pBuffer: ^Buffer) -> Result -ProcDestroyBuffer :: #type proc "system" (device: Device, buffer: Buffer, pAllocator: ^AllocationCallbacks) -ProcCreateBufferView :: #type proc "system" (device: Device, pCreateInfo: ^BufferViewCreateInfo, pAllocator: ^AllocationCallbacks, pView: ^BufferView) -> Result -ProcDestroyBufferView :: #type proc "system" (device: Device, bufferView: BufferView, pAllocator: ^AllocationCallbacks) -ProcCreateImage :: #type proc "system" (device: Device, pCreateInfo: ^ImageCreateInfo, pAllocator: ^AllocationCallbacks, pImage: ^Image) -> Result -ProcDestroyImage :: #type proc "system" (device: Device, image: Image, pAllocator: ^AllocationCallbacks) -ProcGetImageSubresourceLayout :: #type proc "system" (device: Device, image: Image, pSubresource: ^ImageSubresource, pLayout: ^SubresourceLayout) -ProcCreateImageView :: #type proc "system" (device: Device, pCreateInfo: ^ImageViewCreateInfo, pAllocator: ^AllocationCallbacks, pView: ^ImageView) -> Result -ProcDestroyImageView :: #type proc "system" (device: Device, imageView: ImageView, pAllocator: ^AllocationCallbacks) -ProcCreateShaderModule :: #type proc "system" (device: Device, pCreateInfo: ^ShaderModuleCreateInfo, pAllocator: ^AllocationCallbacks, pShaderModule: ^ShaderModule) -> Result -ProcDestroyShaderModule :: #type proc "system" (device: Device, shaderModule: ShaderModule, pAllocator: ^AllocationCallbacks) -ProcCreatePipelineCache :: #type proc "system" (device: Device, pCreateInfo: ^PipelineCacheCreateInfo, pAllocator: ^AllocationCallbacks, pPipelineCache: ^PipelineCache) -> Result -ProcDestroyPipelineCache :: #type proc "system" (device: Device, pipelineCache: PipelineCache, pAllocator: ^AllocationCallbacks) -ProcGetPipelineCacheData :: #type proc "system" (device: Device, pipelineCache: PipelineCache, pDataSize: ^int, pData: rawptr) -> Result -ProcMergePipelineCaches :: #type proc "system" (device: Device, dstCache: PipelineCache, srcCacheCount: u32, pSrcCaches: [^]PipelineCache) -> Result -ProcCreateGraphicsPipelines :: #type proc "system" (device: Device, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]GraphicsPipelineCreateInfo, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result -ProcCreateComputePipelines :: #type proc "system" (device: Device, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]ComputePipelineCreateInfo, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result -ProcDestroyPipeline :: #type proc "system" (device: Device, pipeline: Pipeline, pAllocator: ^AllocationCallbacks) -ProcCreatePipelineLayout :: #type proc "system" (device: Device, pCreateInfo: ^PipelineLayoutCreateInfo, pAllocator: ^AllocationCallbacks, pPipelineLayout: ^PipelineLayout) -> Result -ProcDestroyPipelineLayout :: #type proc "system" (device: Device, pipelineLayout: PipelineLayout, pAllocator: ^AllocationCallbacks) -ProcCreateSampler :: #type proc "system" (device: Device, pCreateInfo: ^SamplerCreateInfo, pAllocator: ^AllocationCallbacks, pSampler: ^Sampler) -> Result -ProcDestroySampler :: #type proc "system" (device: Device, sampler: Sampler, pAllocator: ^AllocationCallbacks) -ProcCreateDescriptorSetLayout :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pAllocator: ^AllocationCallbacks, pSetLayout: ^DescriptorSetLayout) -> Result -ProcDestroyDescriptorSetLayout :: #type proc "system" (device: Device, descriptorSetLayout: DescriptorSetLayout, pAllocator: ^AllocationCallbacks) -ProcCreateDescriptorPool :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorPoolCreateInfo, pAllocator: ^AllocationCallbacks, pDescriptorPool: ^DescriptorPool) -> Result -ProcDestroyDescriptorPool :: #type proc "system" (device: Device, descriptorPool: DescriptorPool, pAllocator: ^AllocationCallbacks) -ProcResetDescriptorPool :: #type proc "system" (device: Device, descriptorPool: DescriptorPool, flags: DescriptorPoolResetFlags) -> Result -ProcAllocateDescriptorSets :: #type proc "system" (device: Device, pAllocateInfo: ^DescriptorSetAllocateInfo, pDescriptorSets: [^]DescriptorSet) -> Result -ProcFreeDescriptorSets :: #type proc "system" (device: Device, descriptorPool: DescriptorPool, descriptorSetCount: u32, pDescriptorSets: [^]DescriptorSet) -> Result -ProcUpdateDescriptorSets :: #type proc "system" (device: Device, descriptorWriteCount: u32, pDescriptorWrites: [^]WriteDescriptorSet, descriptorCopyCount: u32, pDescriptorCopies: [^]CopyDescriptorSet) -ProcCreateFramebuffer :: #type proc "system" (device: Device, pCreateInfo: ^FramebufferCreateInfo, pAllocator: ^AllocationCallbacks, pFramebuffer: ^Framebuffer) -> Result -ProcDestroyFramebuffer :: #type proc "system" (device: Device, framebuffer: Framebuffer, pAllocator: ^AllocationCallbacks) -ProcCreateRenderPass :: #type proc "system" (device: Device, pCreateInfo: ^RenderPassCreateInfo, pAllocator: ^AllocationCallbacks, pRenderPass: [^]RenderPass) -> Result -ProcDestroyRenderPass :: #type proc "system" (device: Device, renderPass: RenderPass, pAllocator: ^AllocationCallbacks) -ProcGetRenderAreaGranularity :: #type proc "system" (device: Device, renderPass: RenderPass, pGranularity: ^Extent2D) -ProcCreateCommandPool :: #type proc "system" (device: Device, pCreateInfo: ^CommandPoolCreateInfo, pAllocator: ^AllocationCallbacks, pCommandPool: ^CommandPool) -> Result -ProcDestroyCommandPool :: #type proc "system" (device: Device, commandPool: CommandPool, pAllocator: ^AllocationCallbacks) -ProcResetCommandPool :: #type proc "system" (device: Device, commandPool: CommandPool, flags: CommandPoolResetFlags) -> Result -ProcAllocateCommandBuffers :: #type proc "system" (device: Device, pAllocateInfo: ^CommandBufferAllocateInfo, pCommandBuffers: [^]CommandBuffer) -> Result -ProcFreeCommandBuffers :: #type proc "system" (device: Device, commandPool: CommandPool, commandBufferCount: u32, pCommandBuffers: [^]CommandBuffer) -ProcBeginCommandBuffer :: #type proc "system" (commandBuffer: CommandBuffer, pBeginInfo: ^CommandBufferBeginInfo) -> Result -ProcEndCommandBuffer :: #type proc "system" (commandBuffer: CommandBuffer) -> Result -ProcResetCommandBuffer :: #type proc "system" (commandBuffer: CommandBuffer, flags: CommandBufferResetFlags) -> Result -ProcCmdBindPipeline :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, pipeline: Pipeline) -ProcCmdSetViewport :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pViewports: [^]Viewport) -ProcCmdSetScissor :: #type proc "system" (commandBuffer: CommandBuffer, firstScissor: u32, scissorCount: u32, pScissors: [^]Rect2D) -ProcCmdSetLineWidth :: #type proc "system" (commandBuffer: CommandBuffer, lineWidth: f32) -ProcCmdSetDepthBias :: #type proc "system" (commandBuffer: CommandBuffer, depthBiasConstantFactor: f32, depthBiasClamp: f32, depthBiasSlopeFactor: f32) -ProcCmdSetBlendConstants :: #type proc "system" (commandBuffer: CommandBuffer) -ProcCmdSetDepthBounds :: #type proc "system" (commandBuffer: CommandBuffer, minDepthBounds: f32, maxDepthBounds: f32) -ProcCmdSetStencilCompareMask :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, compareMask: u32) -ProcCmdSetStencilWriteMask :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, writeMask: u32) -ProcCmdSetStencilReference :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, reference: u32) -ProcCmdBindDescriptorSets :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, layout: PipelineLayout, firstSet: u32, descriptorSetCount: u32, pDescriptorSets: [^]DescriptorSet, dynamicOffsetCount: u32, pDynamicOffsets: [^]u32) -ProcCmdBindIndexBuffer :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, indexType: IndexType) -ProcCmdBindVertexBuffers :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize) -ProcCmdDraw :: #type proc "system" (commandBuffer: CommandBuffer, vertexCount: u32, instanceCount: u32, firstVertex: u32, firstInstance: u32) -ProcCmdDrawIndexed :: #type proc "system" (commandBuffer: CommandBuffer, indexCount: u32, instanceCount: u32, firstIndex: u32, vertexOffset: i32, firstInstance: u32) -ProcCmdDrawIndirect :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, drawCount: u32, stride: u32) -ProcCmdDrawIndexedIndirect :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, drawCount: u32, stride: u32) -ProcCmdDispatch :: #type proc "system" (commandBuffer: CommandBuffer, groupCountX: u32, groupCountY: u32, groupCountZ: u32) -ProcCmdDispatchIndirect :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize) -ProcCmdCopyBuffer :: #type proc "system" (commandBuffer: CommandBuffer, srcBuffer: Buffer, dstBuffer: Buffer, regionCount: u32, pRegions: [^]BufferCopy) -ProcCmdCopyImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageCopy) -ProcCmdBlitImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageBlit, filter: Filter) -ProcCmdCopyBufferToImage :: #type proc "system" (commandBuffer: CommandBuffer, srcBuffer: Buffer, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]BufferImageCopy) -ProcCmdCopyImageToBuffer :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstBuffer: Buffer, regionCount: u32, pRegions: [^]BufferImageCopy) -ProcCmdUpdateBuffer :: #type proc "system" (commandBuffer: CommandBuffer, dstBuffer: Buffer, dstOffset: DeviceSize, dataSize: DeviceSize, pData: rawptr) -ProcCmdFillBuffer :: #type proc "system" (commandBuffer: CommandBuffer, dstBuffer: Buffer, dstOffset: DeviceSize, size: DeviceSize, data: u32) -ProcCmdClearColorImage :: #type proc "system" (commandBuffer: CommandBuffer, image: Image, imageLayout: ImageLayout, pColor: ^ClearColorValue, rangeCount: u32, pRanges: [^]ImageSubresourceRange) -ProcCmdClearDepthStencilImage :: #type proc "system" (commandBuffer: CommandBuffer, image: Image, imageLayout: ImageLayout, pDepthStencil: ^ClearDepthStencilValue, rangeCount: u32, pRanges: [^]ImageSubresourceRange) -ProcCmdClearAttachments :: #type proc "system" (commandBuffer: CommandBuffer, attachmentCount: u32, pAttachments: [^]ClearAttachment, rectCount: u32, pRects: [^]ClearRect) -ProcCmdResolveImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageResolve) -ProcCmdSetEvent :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags) -ProcCmdResetEvent :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags) -ProcCmdWaitEvents :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, srcStageMask: PipelineStageFlags, dstStageMask: PipelineStageFlags, memoryBarrierCount: u32, pMemoryBarriers: [^]MemoryBarrier, bufferMemoryBarrierCount: u32, pBufferMemoryBarriers: [^]BufferMemoryBarrier, imageMemoryBarrierCount: u32, pImageMemoryBarriers: [^]ImageMemoryBarrier) -ProcCmdPipelineBarrier :: #type proc "system" (commandBuffer: CommandBuffer, srcStageMask: PipelineStageFlags, dstStageMask: PipelineStageFlags, dependencyFlags: DependencyFlags, memoryBarrierCount: u32, pMemoryBarriers: [^]MemoryBarrier, bufferMemoryBarrierCount: u32, pBufferMemoryBarriers: [^]BufferMemoryBarrier, imageMemoryBarrierCount: u32, pImageMemoryBarriers: [^]ImageMemoryBarrier) -ProcCmdBeginQuery :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32, flags: QueryControlFlags) -ProcCmdEndQuery :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32) -ProcCmdResetQueryPool :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, firstQuery: u32, queryCount: u32) -ProcCmdWriteTimestamp :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStage: PipelineStageFlags, queryPool: QueryPool, query: u32) -ProcCmdCopyQueryPoolResults :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, firstQuery: u32, queryCount: u32, dstBuffer: Buffer, dstOffset: DeviceSize, stride: DeviceSize, flags: QueryResultFlags) -ProcCmdPushConstants :: #type proc "system" (commandBuffer: CommandBuffer, layout: PipelineLayout, stageFlags: ShaderStageFlags, offset: u32, size: u32, pValues: rawptr) -ProcCmdBeginRenderPass :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, contents: SubpassContents) -ProcCmdNextSubpass :: #type proc "system" (commandBuffer: CommandBuffer, contents: SubpassContents) -ProcCmdEndRenderPass :: #type proc "system" (commandBuffer: CommandBuffer) -ProcCmdExecuteCommands :: #type proc "system" (commandBuffer: CommandBuffer, commandBufferCount: u32, pCommandBuffers: [^]CommandBuffer) -ProcEnumerateInstanceVersion :: #type proc "system" (pApiVersion: ^u32) -> Result -ProcBindBufferMemory2 :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindBufferMemoryInfo) -> Result -ProcBindImageMemory2 :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindImageMemoryInfo) -> Result -ProcGetDeviceGroupPeerMemoryFeatures :: #type proc "system" (device: Device, heapIndex: u32, localDeviceIndex: u32, remoteDeviceIndex: u32, pPeerMemoryFeatures: [^]PeerMemoryFeatureFlags) -ProcCmdSetDeviceMask :: #type proc "system" (commandBuffer: CommandBuffer, deviceMask: u32) -ProcCmdDispatchBase :: #type proc "system" (commandBuffer: CommandBuffer, baseGroupX: u32, baseGroupY: u32, baseGroupZ: u32, groupCountX: u32, groupCountY: u32, groupCountZ: u32) -ProcEnumeratePhysicalDeviceGroups :: #type proc "system" (instance: Instance, pPhysicalDeviceGroupCount: ^u32, pPhysicalDeviceGroupProperties: [^]PhysicalDeviceGroupProperties) -> Result -ProcGetImageMemoryRequirements2 :: #type proc "system" (device: Device, pInfo: ^ImageMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) -ProcGetBufferMemoryRequirements2 :: #type proc "system" (device: Device, pInfo: ^BufferMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) -ProcGetImageSparseMemoryRequirements2 :: #type proc "system" (device: Device, pInfo: ^ImageSparseMemoryRequirementsInfo2, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements2) -ProcGetPhysicalDeviceFeatures2 :: #type proc "system" (physicalDevice: PhysicalDevice, pFeatures: [^]PhysicalDeviceFeatures2) -ProcGetPhysicalDeviceProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pProperties: [^]PhysicalDeviceProperties2) -ProcGetPhysicalDeviceFormatProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, pFormatProperties: [^]FormatProperties2) -ProcGetPhysicalDeviceImageFormatProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pImageFormatInfo: ^PhysicalDeviceImageFormatInfo2, pImageFormatProperties: [^]ImageFormatProperties2) -> Result -ProcGetPhysicalDeviceQueueFamilyProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pQueueFamilyPropertyCount: ^u32, pQueueFamilyProperties: [^]QueueFamilyProperties2) -ProcGetPhysicalDeviceMemoryProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pMemoryProperties: [^]PhysicalDeviceMemoryProperties2) -ProcGetPhysicalDeviceSparseImageFormatProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pFormatInfo: ^PhysicalDeviceSparseImageFormatInfo2, pPropertyCount: ^u32, pProperties: [^]SparseImageFormatProperties2) -ProcTrimCommandPool :: #type proc "system" (device: Device, commandPool: CommandPool, flags: CommandPoolTrimFlags) -ProcGetDeviceQueue2 :: #type proc "system" (device: Device, pQueueInfo: ^DeviceQueueInfo2, pQueue: ^Queue) -ProcCreateSamplerYcbcrConversion :: #type proc "system" (device: Device, pCreateInfo: ^SamplerYcbcrConversionCreateInfo, pAllocator: ^AllocationCallbacks, pYcbcrConversion: ^SamplerYcbcrConversion) -> Result -ProcDestroySamplerYcbcrConversion :: #type proc "system" (device: Device, ycbcrConversion: SamplerYcbcrConversion, pAllocator: ^AllocationCallbacks) -ProcCreateDescriptorUpdateTemplate :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorUpdateTemplateCreateInfo, pAllocator: ^AllocationCallbacks, pDescriptorUpdateTemplate: ^DescriptorUpdateTemplate) -> Result -ProcDestroyDescriptorUpdateTemplate :: #type proc "system" (device: Device, descriptorUpdateTemplate: DescriptorUpdateTemplate, pAllocator: ^AllocationCallbacks) -ProcUpdateDescriptorSetWithTemplate :: #type proc "system" (device: Device, descriptorSet: DescriptorSet, descriptorUpdateTemplate: DescriptorUpdateTemplate, pData: rawptr) -ProcGetPhysicalDeviceExternalBufferProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalBufferInfo: ^PhysicalDeviceExternalBufferInfo, pExternalBufferProperties: [^]ExternalBufferProperties) -ProcGetPhysicalDeviceExternalFenceProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalFenceInfo: ^PhysicalDeviceExternalFenceInfo, pExternalFenceProperties: [^]ExternalFenceProperties) -ProcGetPhysicalDeviceExternalSemaphoreProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalSemaphoreInfo: ^PhysicalDeviceExternalSemaphoreInfo, pExternalSemaphoreProperties: [^]ExternalSemaphoreProperties) -ProcGetDescriptorSetLayoutSupport :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pSupport: ^DescriptorSetLayoutSupport) -ProcCmdDrawIndirectCount :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) -ProcCmdDrawIndexedIndirectCount :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) -ProcCreateRenderPass2 :: #type proc "system" (device: Device, pCreateInfo: ^RenderPassCreateInfo2, pAllocator: ^AllocationCallbacks, pRenderPass: [^]RenderPass) -> Result -ProcCmdBeginRenderPass2 :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, pSubpassBeginInfo: ^SubpassBeginInfo) -ProcCmdNextSubpass2 :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassBeginInfo: ^SubpassBeginInfo, pSubpassEndInfo: ^SubpassEndInfo) -ProcCmdEndRenderPass2 :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassEndInfo: ^SubpassEndInfo) -ProcResetQueryPool :: #type proc "system" (device: Device, queryPool: QueryPool, firstQuery: u32, queryCount: u32) -ProcGetSemaphoreCounterValue :: #type proc "system" (device: Device, semaphore: Semaphore, pValue: ^u64) -> Result -ProcWaitSemaphores :: #type proc "system" (device: Device, pWaitInfo: ^SemaphoreWaitInfo, timeout: u64) -> Result -ProcSignalSemaphore :: #type proc "system" (device: Device, pSignalInfo: ^SemaphoreSignalInfo) -> Result -ProcGetBufferDeviceAddress :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> DeviceAddress -ProcGetBufferOpaqueCaptureAddress :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> u64 -ProcGetDeviceMemoryOpaqueCaptureAddress :: #type proc "system" (device: Device, pInfo: ^DeviceMemoryOpaqueCaptureAddressInfo) -> u64 -ProcDestroySurfaceKHR :: #type proc "system" (instance: Instance, surface: SurfaceKHR, pAllocator: ^AllocationCallbacks) -ProcGetPhysicalDeviceSurfaceSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, surface: SurfaceKHR, pSupported: ^b32) -> Result -ProcGetPhysicalDeviceSurfaceCapabilitiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pSurfaceCapabilities: [^]SurfaceCapabilitiesKHR) -> Result -ProcGetPhysicalDeviceSurfaceFormatsKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pSurfaceFormatCount: ^u32, pSurfaceFormats: [^]SurfaceFormatKHR) -> Result -ProcGetPhysicalDeviceSurfacePresentModesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pPresentModeCount: ^u32, pPresentModes: [^]PresentModeKHR) -> Result -ProcCreateSwapchainKHR :: #type proc "system" (device: Device, pCreateInfo: ^SwapchainCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSwapchain: ^SwapchainKHR) -> Result -ProcDestroySwapchainKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pAllocator: ^AllocationCallbacks) -ProcGetSwapchainImagesKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pSwapchainImageCount: ^u32, pSwapchainImages: [^]Image) -> Result -ProcAcquireNextImageKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, timeout: u64, semaphore: Semaphore, fence: Fence, pImageIndex: ^u32) -> Result -ProcQueuePresentKHR :: #type proc "system" (queue: Queue, pPresentInfo: ^PresentInfoKHR) -> Result -ProcGetDeviceGroupPresentCapabilitiesKHR :: #type proc "system" (device: Device, pDeviceGroupPresentCapabilities: [^]DeviceGroupPresentCapabilitiesKHR) -> Result -ProcGetDeviceGroupSurfacePresentModesKHR :: #type proc "system" (device: Device, surface: SurfaceKHR, pModes: [^]DeviceGroupPresentModeFlagsKHR) -> Result -ProcGetPhysicalDevicePresentRectanglesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pRectCount: ^u32, pRects: [^]Rect2D) -> Result -ProcAcquireNextImage2KHR :: #type proc "system" (device: Device, pAcquireInfo: ^AcquireNextImageInfoKHR, pImageIndex: ^u32) -> Result -ProcGetPhysicalDeviceDisplayPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayPropertiesKHR) -> Result -ProcGetPhysicalDeviceDisplayPlanePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayPlanePropertiesKHR) -> Result -ProcGetDisplayPlaneSupportedDisplaysKHR :: #type proc "system" (physicalDevice: PhysicalDevice, planeIndex: u32, pDisplayCount: ^u32, pDisplays: [^]DisplayKHR) -> Result -ProcGetDisplayModePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR, pPropertyCount: ^u32, pProperties: [^]DisplayModePropertiesKHR) -> Result -ProcCreateDisplayModeKHR :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR, pCreateInfo: ^DisplayModeCreateInfoKHR, pAllocator: ^AllocationCallbacks, pMode: ^DisplayModeKHR) -> Result -ProcGetDisplayPlaneCapabilitiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, mode: DisplayModeKHR, planeIndex: u32, pCapabilities: [^]DisplayPlaneCapabilitiesKHR) -> Result -ProcCreateDisplayPlaneSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^DisplaySurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result -ProcCreateSharedSwapchainsKHR :: #type proc "system" (device: Device, swapchainCount: u32, pCreateInfos: [^]SwapchainCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSwapchains: [^]SwapchainKHR) -> Result -ProcGetPhysicalDeviceFeatures2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pFeatures: [^]PhysicalDeviceFeatures2) -ProcGetPhysicalDeviceProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pProperties: [^]PhysicalDeviceProperties2) -ProcGetPhysicalDeviceFormatProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, pFormatProperties: [^]FormatProperties2) -ProcGetPhysicalDeviceImageFormatProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pImageFormatInfo: ^PhysicalDeviceImageFormatInfo2, pImageFormatProperties: [^]ImageFormatProperties2) -> Result -ProcGetPhysicalDeviceQueueFamilyProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pQueueFamilyPropertyCount: ^u32, pQueueFamilyProperties: [^]QueueFamilyProperties2) -ProcGetPhysicalDeviceMemoryProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pMemoryProperties: [^]PhysicalDeviceMemoryProperties2) -ProcGetPhysicalDeviceSparseImageFormatProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pFormatInfo: ^PhysicalDeviceSparseImageFormatInfo2, pPropertyCount: ^u32, pProperties: [^]SparseImageFormatProperties2) -ProcGetDeviceGroupPeerMemoryFeaturesKHR :: #type proc "system" (device: Device, heapIndex: u32, localDeviceIndex: u32, remoteDeviceIndex: u32, pPeerMemoryFeatures: [^]PeerMemoryFeatureFlags) -ProcCmdSetDeviceMaskKHR :: #type proc "system" (commandBuffer: CommandBuffer, deviceMask: u32) -ProcCmdDispatchBaseKHR :: #type proc "system" (commandBuffer: CommandBuffer, baseGroupX: u32, baseGroupY: u32, baseGroupZ: u32, groupCountX: u32, groupCountY: u32, groupCountZ: u32) -ProcTrimCommandPoolKHR :: #type proc "system" (device: Device, commandPool: CommandPool, flags: CommandPoolTrimFlags) -ProcEnumeratePhysicalDeviceGroupsKHR :: #type proc "system" (instance: Instance, pPhysicalDeviceGroupCount: ^u32, pPhysicalDeviceGroupProperties: [^]PhysicalDeviceGroupProperties) -> Result -ProcGetPhysicalDeviceExternalBufferPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalBufferInfo: ^PhysicalDeviceExternalBufferInfo, pExternalBufferProperties: [^]ExternalBufferProperties) -ProcGetMemoryFdKHR :: #type proc "system" (device: Device, pGetFdInfo: ^MemoryGetFdInfoKHR, pFd: ^c.int) -> Result -ProcGetMemoryFdPropertiesKHR :: #type proc "system" (device: Device, handleType: ExternalMemoryHandleTypeFlags, fd: c.int, pMemoryFdProperties: [^]MemoryFdPropertiesKHR) -> Result -ProcGetPhysicalDeviceExternalSemaphorePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalSemaphoreInfo: ^PhysicalDeviceExternalSemaphoreInfo, pExternalSemaphoreProperties: [^]ExternalSemaphoreProperties) -ProcImportSemaphoreFdKHR :: #type proc "system" (device: Device, pImportSemaphoreFdInfo: ^ImportSemaphoreFdInfoKHR) -> Result -ProcGetSemaphoreFdKHR :: #type proc "system" (device: Device, pGetFdInfo: ^SemaphoreGetFdInfoKHR, pFd: ^c.int) -> Result -ProcCmdPushDescriptorSetKHR :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, layout: PipelineLayout, set: u32, descriptorWriteCount: u32, pDescriptorWrites: [^]WriteDescriptorSet) -ProcCmdPushDescriptorSetWithTemplateKHR :: #type proc "system" (commandBuffer: CommandBuffer, descriptorUpdateTemplate: DescriptorUpdateTemplate, layout: PipelineLayout, set: u32, pData: rawptr) -ProcCreateDescriptorUpdateTemplateKHR :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorUpdateTemplateCreateInfo, pAllocator: ^AllocationCallbacks, pDescriptorUpdateTemplate: ^DescriptorUpdateTemplate) -> Result -ProcDestroyDescriptorUpdateTemplateKHR :: #type proc "system" (device: Device, descriptorUpdateTemplate: DescriptorUpdateTemplate, pAllocator: ^AllocationCallbacks) -ProcUpdateDescriptorSetWithTemplateKHR :: #type proc "system" (device: Device, descriptorSet: DescriptorSet, descriptorUpdateTemplate: DescriptorUpdateTemplate, pData: rawptr) -ProcCreateRenderPass2KHR :: #type proc "system" (device: Device, pCreateInfo: ^RenderPassCreateInfo2, pAllocator: ^AllocationCallbacks, pRenderPass: [^]RenderPass) -> Result -ProcCmdBeginRenderPass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, pSubpassBeginInfo: ^SubpassBeginInfo) -ProcCmdNextSubpass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassBeginInfo: ^SubpassBeginInfo, pSubpassEndInfo: ^SubpassEndInfo) -ProcCmdEndRenderPass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassEndInfo: ^SubpassEndInfo) -ProcGetSwapchainStatusKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR) -> Result -ProcGetPhysicalDeviceExternalFencePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalFenceInfo: ^PhysicalDeviceExternalFenceInfo, pExternalFenceProperties: [^]ExternalFenceProperties) -ProcImportFenceFdKHR :: #type proc "system" (device: Device, pImportFenceFdInfo: ^ImportFenceFdInfoKHR) -> Result -ProcGetFenceFdKHR :: #type proc "system" (device: Device, pGetFdInfo: ^FenceGetFdInfoKHR, pFd: ^c.int) -> Result -ProcEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, pCounterCount: ^u32, pCounters: [^]PerformanceCounterKHR, pCounterDescriptions: [^]PerformanceCounterDescriptionKHR) -> Result -ProcGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPerformanceQueryCreateInfo: ^QueryPoolPerformanceCreateInfoKHR, pNumPasses: [^]u32) -ProcAcquireProfilingLockKHR :: #type proc "system" (device: Device, pInfo: ^AcquireProfilingLockInfoKHR) -> Result -ProcReleaseProfilingLockKHR :: #type proc "system" (device: Device) -ProcGetPhysicalDeviceSurfaceCapabilities2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pSurfaceCapabilities: [^]SurfaceCapabilities2KHR) -> Result -ProcGetPhysicalDeviceSurfaceFormats2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pSurfaceFormatCount: ^u32, pSurfaceFormats: [^]SurfaceFormat2KHR) -> Result -ProcGetPhysicalDeviceDisplayProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayProperties2KHR) -> Result -ProcGetPhysicalDeviceDisplayPlaneProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayPlaneProperties2KHR) -> Result -ProcGetDisplayModeProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR, pPropertyCount: ^u32, pProperties: [^]DisplayModeProperties2KHR) -> Result -ProcGetDisplayPlaneCapabilities2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pDisplayPlaneInfo: ^DisplayPlaneInfo2KHR, pCapabilities: [^]DisplayPlaneCapabilities2KHR) -> Result -ProcGetImageMemoryRequirements2KHR :: #type proc "system" (device: Device, pInfo: ^ImageMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) -ProcGetBufferMemoryRequirements2KHR :: #type proc "system" (device: Device, pInfo: ^BufferMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) -ProcGetImageSparseMemoryRequirements2KHR :: #type proc "system" (device: Device, pInfo: ^ImageSparseMemoryRequirementsInfo2, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements2) -ProcCreateSamplerYcbcrConversionKHR :: #type proc "system" (device: Device, pCreateInfo: ^SamplerYcbcrConversionCreateInfo, pAllocator: ^AllocationCallbacks, pYcbcrConversion: ^SamplerYcbcrConversion) -> Result -ProcDestroySamplerYcbcrConversionKHR :: #type proc "system" (device: Device, ycbcrConversion: SamplerYcbcrConversion, pAllocator: ^AllocationCallbacks) -ProcBindBufferMemory2KHR :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindBufferMemoryInfo) -> Result -ProcBindImageMemory2KHR :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindImageMemoryInfo) -> Result -ProcGetDescriptorSetLayoutSupportKHR :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pSupport: ^DescriptorSetLayoutSupport) -ProcCmdDrawIndirectCountKHR :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) -ProcCmdDrawIndexedIndirectCountKHR :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) -ProcGetSemaphoreCounterValueKHR :: #type proc "system" (device: Device, semaphore: Semaphore, pValue: ^u64) -> Result -ProcWaitSemaphoresKHR :: #type proc "system" (device: Device, pWaitInfo: ^SemaphoreWaitInfo, timeout: u64) -> Result -ProcSignalSemaphoreKHR :: #type proc "system" (device: Device, pSignalInfo: ^SemaphoreSignalInfo) -> Result -ProcGetPhysicalDeviceFragmentShadingRatesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pFragmentShadingRateCount: ^u32, pFragmentShadingRates: [^]PhysicalDeviceFragmentShadingRateKHR) -> Result -ProcCmdSetFragmentShadingRateKHR :: #type proc "system" (commandBuffer: CommandBuffer, pFragmentSize: ^Extent2D) -ProcWaitForPresentKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, presentId: u64, timeout: u64) -> Result -ProcGetBufferDeviceAddressKHR :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> DeviceAddress -ProcGetBufferOpaqueCaptureAddressKHR :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> u64 -ProcGetDeviceMemoryOpaqueCaptureAddressKHR :: #type proc "system" (device: Device, pInfo: ^DeviceMemoryOpaqueCaptureAddressInfo) -> u64 -ProcCreateDeferredOperationKHR :: #type proc "system" (device: Device, pAllocator: ^AllocationCallbacks, pDeferredOperation: ^DeferredOperationKHR) -> Result -ProcDestroyDeferredOperationKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR, pAllocator: ^AllocationCallbacks) -ProcGetDeferredOperationMaxConcurrencyKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> u32 -ProcGetDeferredOperationResultKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> Result -ProcDeferredOperationJoinKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> Result -ProcGetPipelineExecutablePropertiesKHR :: #type proc "system" (device: Device, pPipelineInfo: ^PipelineInfoKHR, pExecutableCount: ^u32, pProperties: [^]PipelineExecutablePropertiesKHR) -> Result -ProcGetPipelineExecutableStatisticsKHR :: #type proc "system" (device: Device, pExecutableInfo: ^PipelineExecutableInfoKHR, pStatisticCount: ^u32, pStatistics: [^]PipelineExecutableStatisticKHR) -> Result -ProcGetPipelineExecutableInternalRepresentationsKHR :: #type proc "system" (device: Device, pExecutableInfo: ^PipelineExecutableInfoKHR, pInternalRepresentationCount: ^u32, pInternalRepresentations: [^]PipelineExecutableInternalRepresentationKHR) -> Result -ProcCmdSetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, pDependencyInfo: ^DependencyInfoKHR) -ProcCmdResetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags2KHR) -ProcCmdWaitEvents2KHR :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, pDependencyInfos: [^]DependencyInfoKHR) -ProcCmdPipelineBarrier2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pDependencyInfo: ^DependencyInfoKHR) -ProcCmdWriteTimestamp2KHR :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2KHR, queryPool: QueryPool, query: u32) -ProcQueueSubmit2KHR :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo2KHR, fence: Fence) -> Result -ProcCmdWriteBufferMarker2AMD :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2KHR, dstBuffer: Buffer, dstOffset: DeviceSize, marker: u32) -ProcGetQueueCheckpointData2NV :: #type proc "system" (queue: Queue, pCheckpointDataCount: ^u32, pCheckpointData: ^CheckpointData2NV) -ProcCmdCopyBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferInfo: ^CopyBufferInfo2KHR) -ProcCmdCopyImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageInfo: ^CopyImageInfo2KHR) -ProcCmdCopyBufferToImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferToImageInfo: ^CopyBufferToImageInfo2KHR) -ProcCmdCopyImageToBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageToBufferInfo: ^CopyImageToBufferInfo2KHR) -ProcCmdBlitImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pBlitImageInfo: ^BlitImageInfo2KHR) -ProcCmdResolveImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pResolveImageInfo: ^ResolveImageInfo2KHR) -ProcDebugReportCallbackEXT :: #type proc "system" (flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring, pUserData: rawptr) -> b32 -ProcCreateDebugReportCallbackEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^DebugReportCallbackCreateInfoEXT, pAllocator: ^AllocationCallbacks, pCallback: ^DebugReportCallbackEXT) -> Result -ProcDestroyDebugReportCallbackEXT :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks) -ProcDebugReportMessageEXT :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring) -ProcDebugMarkerSetObjectTagEXT :: #type proc "system" (device: Device, pTagInfo: ^DebugMarkerObjectTagInfoEXT) -> Result -ProcDebugMarkerSetObjectNameEXT :: #type proc "system" (device: Device, pNameInfo: ^DebugMarkerObjectNameInfoEXT) -> Result -ProcCmdDebugMarkerBeginEXT :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^DebugMarkerMarkerInfoEXT) -ProcCmdDebugMarkerEndEXT :: #type proc "system" (commandBuffer: CommandBuffer) -ProcCmdDebugMarkerInsertEXT :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^DebugMarkerMarkerInfoEXT) -ProcCmdBindTransformFeedbackBuffersEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize, pSizes: [^]DeviceSize) -ProcCmdBeginTransformFeedbackEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstCounterBuffer: u32, counterBufferCount: u32, pCounterBuffers: [^]Buffer, pCounterBufferOffsets: [^]DeviceSize) -ProcCmdEndTransformFeedbackEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstCounterBuffer: u32, counterBufferCount: u32, pCounterBuffers: [^]Buffer, pCounterBufferOffsets: [^]DeviceSize) -ProcCmdBeginQueryIndexedEXT :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32, flags: QueryControlFlags, index: u32) -ProcCmdEndQueryIndexedEXT :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32, index: u32) -ProcCmdDrawIndirectByteCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, instanceCount: u32, firstInstance: u32, counterBuffer: Buffer, counterBufferOffset: DeviceSize, counterOffset: u32, vertexStride: u32) -ProcCreateCuModuleNVX :: #type proc "system" (device: Device, pCreateInfo: ^CuModuleCreateInfoNVX, pAllocator: ^AllocationCallbacks, pModule: ^CuModuleNVX) -> Result -ProcCreateCuFunctionNVX :: #type proc "system" (device: Device, pCreateInfo: ^CuFunctionCreateInfoNVX, pAllocator: ^AllocationCallbacks, pFunction: ^CuFunctionNVX) -> Result -ProcDestroyCuModuleNVX :: #type proc "system" (device: Device, module: CuModuleNVX, pAllocator: ^AllocationCallbacks) -ProcDestroyCuFunctionNVX :: #type proc "system" (device: Device, function: CuFunctionNVX, pAllocator: ^AllocationCallbacks) -ProcCmdCuLaunchKernelNVX :: #type proc "system" (commandBuffer: CommandBuffer, pLaunchInfo: ^CuLaunchInfoNVX) -ProcGetImageViewHandleNVX :: #type proc "system" (device: Device, pInfo: ^ImageViewHandleInfoNVX) -> u32 -ProcGetImageViewAddressNVX :: #type proc "system" (device: Device, imageView: ImageView, pProperties: [^]ImageViewAddressPropertiesNVX) -> Result -ProcCmdDrawIndirectCountAMD :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) -ProcCmdDrawIndexedIndirectCountAMD :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) -ProcGetShaderInfoAMD :: #type proc "system" (device: Device, pipeline: Pipeline, shaderStage: ShaderStageFlags, infoType: ShaderInfoTypeAMD, pInfoSize: ^int, pInfo: rawptr) -> Result -ProcGetPhysicalDeviceExternalImageFormatPropertiesNV :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, type: ImageType, tiling: ImageTiling, usage: ImageUsageFlags, flags: ImageCreateFlags, externalHandleType: ExternalMemoryHandleTypeFlagsNV, pExternalImageFormatProperties: [^]ExternalImageFormatPropertiesNV) -> Result -ProcCmdBeginConditionalRenderingEXT :: #type proc "system" (commandBuffer: CommandBuffer, pConditionalRenderingBegin: ^ConditionalRenderingBeginInfoEXT) -ProcCmdEndConditionalRenderingEXT :: #type proc "system" (commandBuffer: CommandBuffer) -ProcCmdSetViewportWScalingNV :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pViewportWScalings: [^]ViewportWScalingNV) -ProcReleaseDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result -ProcGetPhysicalDeviceSurfaceCapabilities2EXT :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pSurfaceCapabilities: [^]SurfaceCapabilities2EXT) -> Result -ProcDisplayPowerControlEXT :: #type proc "system" (device: Device, display: DisplayKHR, pDisplayPowerInfo: ^DisplayPowerInfoEXT) -> Result -ProcRegisterDeviceEventEXT :: #type proc "system" (device: Device, pDeviceEventInfo: ^DeviceEventInfoEXT, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result -ProcRegisterDisplayEventEXT :: #type proc "system" (device: Device, display: DisplayKHR, pDisplayEventInfo: ^DisplayEventInfoEXT, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result -ProcGetSwapchainCounterEXT :: #type proc "system" (device: Device, swapchain: SwapchainKHR, counter: SurfaceCounterFlagsEXT, pCounterValue: ^u64) -> Result -ProcGetRefreshCycleDurationGOOGLE :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pDisplayTimingProperties: [^]RefreshCycleDurationGOOGLE) -> Result -ProcGetPastPresentationTimingGOOGLE :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pPresentationTimingCount: ^u32, pPresentationTimings: [^]PastPresentationTimingGOOGLE) -> Result -ProcCmdSetDiscardRectangleEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstDiscardRectangle: u32, discardRectangleCount: u32, pDiscardRectangles: [^]Rect2D) -ProcSetHdrMetadataEXT :: #type proc "system" (device: Device, swapchainCount: u32, pSwapchains: [^]SwapchainKHR, pMetadata: ^HdrMetadataEXT) -ProcDebugUtilsMessengerCallbackEXT :: #type proc "system" (messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT, pUserData: rawptr) -> b32 -ProcSetDebugUtilsObjectNameEXT :: #type proc "system" (device: Device, pNameInfo: ^DebugUtilsObjectNameInfoEXT) -> Result -ProcSetDebugUtilsObjectTagEXT :: #type proc "system" (device: Device, pTagInfo: ^DebugUtilsObjectTagInfoEXT) -> Result -ProcQueueBeginDebugUtilsLabelEXT :: #type proc "system" (queue: Queue, pLabelInfo: ^DebugUtilsLabelEXT) -ProcQueueEndDebugUtilsLabelEXT :: #type proc "system" (queue: Queue) -ProcQueueInsertDebugUtilsLabelEXT :: #type proc "system" (queue: Queue, pLabelInfo: ^DebugUtilsLabelEXT) -ProcCmdBeginDebugUtilsLabelEXT :: #type proc "system" (commandBuffer: CommandBuffer, pLabelInfo: ^DebugUtilsLabelEXT) -ProcCmdEndDebugUtilsLabelEXT :: #type proc "system" (commandBuffer: CommandBuffer) -ProcCmdInsertDebugUtilsLabelEXT :: #type proc "system" (commandBuffer: CommandBuffer, pLabelInfo: ^DebugUtilsLabelEXT) -ProcCreateDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^DebugUtilsMessengerCreateInfoEXT, pAllocator: ^AllocationCallbacks, pMessenger: ^DebugUtilsMessengerEXT) -> Result -ProcDestroyDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks) -ProcSubmitDebugUtilsMessageEXT :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT) -ProcCmdSetSampleLocationsEXT :: #type proc "system" (commandBuffer: CommandBuffer, pSampleLocationsInfo: ^SampleLocationsInfoEXT) -ProcGetPhysicalDeviceMultisamplePropertiesEXT :: #type proc "system" (physicalDevice: PhysicalDevice, samples: SampleCountFlags, pMultisampleProperties: [^]MultisamplePropertiesEXT) -ProcGetImageDrmFormatModifierPropertiesEXT :: #type proc "system" (device: Device, image: Image, pProperties: [^]ImageDrmFormatModifierPropertiesEXT) -> Result -ProcCreateValidationCacheEXT :: #type proc "system" (device: Device, pCreateInfo: ^ValidationCacheCreateInfoEXT, pAllocator: ^AllocationCallbacks, pValidationCache: ^ValidationCacheEXT) -> Result -ProcDestroyValidationCacheEXT :: #type proc "system" (device: Device, validationCache: ValidationCacheEXT, pAllocator: ^AllocationCallbacks) -ProcMergeValidationCachesEXT :: #type proc "system" (device: Device, dstCache: ValidationCacheEXT, srcCacheCount: u32, pSrcCaches: [^]ValidationCacheEXT) -> Result -ProcGetValidationCacheDataEXT :: #type proc "system" (device: Device, validationCache: ValidationCacheEXT, pDataSize: ^int, pData: rawptr) -> Result -ProcCmdBindShadingRateImageNV :: #type proc "system" (commandBuffer: CommandBuffer, imageView: ImageView, imageLayout: ImageLayout) -ProcCmdSetViewportShadingRatePaletteNV :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pShadingRatePalettes: [^]ShadingRatePaletteNV) -ProcCmdSetCoarseSampleOrderNV :: #type proc "system" (commandBuffer: CommandBuffer, sampleOrderType: CoarseSampleOrderTypeNV, customSampleOrderCount: u32, pCustomSampleOrders: [^]CoarseSampleOrderCustomNV) -ProcCreateAccelerationStructureNV :: #type proc "system" (device: Device, pCreateInfo: ^AccelerationStructureCreateInfoNV, pAllocator: ^AllocationCallbacks, pAccelerationStructure: ^AccelerationStructureNV) -> Result -ProcDestroyAccelerationStructureNV :: #type proc "system" (device: Device, accelerationStructure: AccelerationStructureNV, pAllocator: ^AllocationCallbacks) -ProcGetAccelerationStructureMemoryRequirementsNV :: #type proc "system" (device: Device, pInfo: ^AccelerationStructureMemoryRequirementsInfoNV, pMemoryRequirements: [^]MemoryRequirements2KHR) -ProcBindAccelerationStructureMemoryNV :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindAccelerationStructureMemoryInfoNV) -> Result -ProcCmdBuildAccelerationStructureNV :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^AccelerationStructureInfoNV, instanceData: Buffer, instanceOffset: DeviceSize, update: b32, dst: AccelerationStructureNV, src: AccelerationStructureNV, scratch: Buffer, scratchOffset: DeviceSize) -ProcCmdCopyAccelerationStructureNV :: #type proc "system" (commandBuffer: CommandBuffer, dst: AccelerationStructureNV, src: AccelerationStructureNV, mode: CopyAccelerationStructureModeKHR) -ProcCmdTraceRaysNV :: #type proc "system" (commandBuffer: CommandBuffer, raygenShaderBindingTableBuffer: Buffer, raygenShaderBindingOffset: DeviceSize, missShaderBindingTableBuffer: Buffer, missShaderBindingOffset: DeviceSize, missShaderBindingStride: DeviceSize, hitShaderBindingTableBuffer: Buffer, hitShaderBindingOffset: DeviceSize, hitShaderBindingStride: DeviceSize, callableShaderBindingTableBuffer: Buffer, callableShaderBindingOffset: DeviceSize, callableShaderBindingStride: DeviceSize, width: u32, height: u32, depth: u32) -ProcCreateRayTracingPipelinesNV :: #type proc "system" (device: Device, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]RayTracingPipelineCreateInfoNV, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result -ProcGetRayTracingShaderGroupHandlesKHR :: #type proc "system" (device: Device, pipeline: Pipeline, firstGroup: u32, groupCount: u32, dataSize: int, pData: rawptr) -> Result -ProcGetRayTracingShaderGroupHandlesNV :: #type proc "system" (device: Device, pipeline: Pipeline, firstGroup: u32, groupCount: u32, dataSize: int, pData: rawptr) -> Result -ProcGetAccelerationStructureHandleNV :: #type proc "system" (device: Device, accelerationStructure: AccelerationStructureNV, dataSize: int, pData: rawptr) -> Result -ProcCmdWriteAccelerationStructuresPropertiesNV :: #type proc "system" (commandBuffer: CommandBuffer, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureNV, queryType: QueryType, queryPool: QueryPool, firstQuery: u32) -ProcCompileDeferredNV :: #type proc "system" (device: Device, pipeline: Pipeline, shader: u32) -> Result -ProcGetMemoryHostPointerPropertiesEXT :: #type proc "system" (device: Device, handleType: ExternalMemoryHandleTypeFlags, pHostPointer: rawptr, pMemoryHostPointerProperties: [^]MemoryHostPointerPropertiesEXT) -> Result -ProcCmdWriteBufferMarkerAMD :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStage: PipelineStageFlags, dstBuffer: Buffer, dstOffset: DeviceSize, marker: u32) -ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT :: #type proc "system" (physicalDevice: PhysicalDevice, pTimeDomainCount: ^u32, pTimeDomains: [^]TimeDomainEXT) -> Result -ProcGetCalibratedTimestampsEXT :: #type proc "system" (device: Device, timestampCount: u32, pTimestampInfos: [^]CalibratedTimestampInfoEXT, pTimestamps: [^]u64, pMaxDeviation: ^u64) -> Result -ProcCmdDrawMeshTasksNV :: #type proc "system" (commandBuffer: CommandBuffer, taskCount: u32, firstTask: u32) -ProcCmdDrawMeshTasksIndirectNV :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, drawCount: u32, stride: u32) -ProcCmdDrawMeshTasksIndirectCountNV :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) -ProcCmdSetExclusiveScissorNV :: #type proc "system" (commandBuffer: CommandBuffer, firstExclusiveScissor: u32, exclusiveScissorCount: u32, pExclusiveScissors: [^]Rect2D) -ProcCmdSetCheckpointNV :: #type proc "system" (commandBuffer: CommandBuffer, pCheckpointMarker: rawptr) -ProcGetQueueCheckpointDataNV :: #type proc "system" (queue: Queue, pCheckpointDataCount: ^u32, pCheckpointData: ^CheckpointDataNV) -ProcInitializePerformanceApiINTEL :: #type proc "system" (device: Device, pInitializeInfo: ^InitializePerformanceApiInfoINTEL) -> Result -ProcUninitializePerformanceApiINTEL :: #type proc "system" (device: Device) -ProcCmdSetPerformanceMarkerINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^PerformanceMarkerInfoINTEL) -> Result -ProcCmdSetPerformanceStreamMarkerINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^PerformanceStreamMarkerInfoINTEL) -> Result -ProcCmdSetPerformanceOverrideINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pOverrideInfo: ^PerformanceOverrideInfoINTEL) -> Result -ProcAcquirePerformanceConfigurationINTEL :: #type proc "system" (device: Device, pAcquireInfo: ^PerformanceConfigurationAcquireInfoINTEL, pConfiguration: ^PerformanceConfigurationINTEL) -> Result -ProcReleasePerformanceConfigurationINTEL :: #type proc "system" (device: Device, configuration: PerformanceConfigurationINTEL) -> Result -ProcQueueSetPerformanceConfigurationINTEL :: #type proc "system" (queue: Queue, configuration: PerformanceConfigurationINTEL) -> Result -ProcGetPerformanceParameterINTEL :: #type proc "system" (device: Device, parameter: PerformanceParameterTypeINTEL, pValue: ^PerformanceValueINTEL) -> Result -ProcSetLocalDimmingAMD :: #type proc "system" (device: Device, swapChain: SwapchainKHR, localDimmingEnable: b32) -ProcGetBufferDeviceAddressEXT :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> DeviceAddress -ProcGetPhysicalDeviceToolPropertiesEXT :: #type proc "system" (physicalDevice: PhysicalDevice, pToolCount: ^u32, pToolProperties: [^]PhysicalDeviceToolPropertiesEXT) -> Result -ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]CooperativeMatrixPropertiesNV) -> Result -ProcGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV :: #type proc "system" (physicalDevice: PhysicalDevice, pCombinationCount: ^u32, pCombinations: [^]FramebufferMixedSamplesCombinationNV) -> Result -ProcCreateHeadlessSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^HeadlessSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result -ProcCmdSetLineStippleEXT :: #type proc "system" (commandBuffer: CommandBuffer, lineStippleFactor: u32, lineStipplePattern: u16) -ProcResetQueryPoolEXT :: #type proc "system" (device: Device, queryPool: QueryPool, firstQuery: u32, queryCount: u32) -ProcCmdSetCullModeEXT :: #type proc "system" (commandBuffer: CommandBuffer, cullMode: CullModeFlags) -ProcCmdSetFrontFaceEXT :: #type proc "system" (commandBuffer: CommandBuffer, frontFace: FrontFace) -ProcCmdSetPrimitiveTopologyEXT :: #type proc "system" (commandBuffer: CommandBuffer, primitiveTopology: PrimitiveTopology) -ProcCmdSetViewportWithCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, viewportCount: u32, pViewports: [^]Viewport) -ProcCmdSetScissorWithCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, scissorCount: u32, pScissors: [^]Rect2D) -ProcCmdBindVertexBuffers2EXT :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize, pSizes: [^]DeviceSize, pStrides: [^]DeviceSize) -ProcCmdSetDepthTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthTestEnable: b32) -ProcCmdSetDepthWriteEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthWriteEnable: b32) -ProcCmdSetDepthCompareOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthCompareOp: CompareOp) -ProcCmdSetDepthBoundsTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthBoundsTestEnable: b32) -ProcCmdSetStencilTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, stencilTestEnable: b32) -ProcCmdSetStencilOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, failOp: StencilOp, passOp: StencilOp, depthFailOp: StencilOp, compareOp: CompareOp) -ProcGetGeneratedCommandsMemoryRequirementsNV :: #type proc "system" (device: Device, pInfo: ^GeneratedCommandsMemoryRequirementsInfoNV, pMemoryRequirements: [^]MemoryRequirements2) -ProcCmdPreprocessGeneratedCommandsNV :: #type proc "system" (commandBuffer: CommandBuffer, pGeneratedCommandsInfo: ^GeneratedCommandsInfoNV) -ProcCmdExecuteGeneratedCommandsNV :: #type proc "system" (commandBuffer: CommandBuffer, isPreprocessed: b32, pGeneratedCommandsInfo: ^GeneratedCommandsInfoNV) -ProcCmdBindPipelineShaderGroupNV :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, pipeline: Pipeline, groupIndex: u32) -ProcCreateIndirectCommandsLayoutNV :: #type proc "system" (device: Device, pCreateInfo: ^IndirectCommandsLayoutCreateInfoNV, pAllocator: ^AllocationCallbacks, pIndirectCommandsLayout: ^IndirectCommandsLayoutNV) -> Result -ProcDestroyIndirectCommandsLayoutNV :: #type proc "system" (device: Device, indirectCommandsLayout: IndirectCommandsLayoutNV, pAllocator: ^AllocationCallbacks) -ProcDeviceMemoryReportCallbackEXT :: #type proc "system" (pCallbackData: ^DeviceMemoryReportCallbackDataEXT, pUserData: rawptr) +// Misc Procedure Types +ProcAllocationFunction :: #type proc "system" (pUserData: rawptr, size: int, alignment: int, allocationScope: SystemAllocationScope) -> rawptr +ProcDebugReportCallbackEXT :: #type proc "system" (flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring, pUserData: rawptr) -> b32 +ProcFreeFunction :: #type proc "system" (pUserData: rawptr, pMemory: rawptr) +ProcInternalAllocationNotification :: #type proc "system" (pUserData: rawptr, size: int, allocationType: InternalAllocationType, allocationScope: SystemAllocationScope) +ProcInternalFreeNotification :: #type proc "system" (pUserData: rawptr, size: int, allocationType: InternalAllocationType, allocationScope: SystemAllocationScope) +ProcReallocationFunction :: #type proc "system" (pUserData: rawptr, pOriginal: rawptr, size: int, alignment: int, allocationScope: SystemAllocationScope) -> rawptr +ProcVoidFunction :: #type proc "system" () + +// Instance Procedure Types ProcAcquireDrmDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, drmFd: i32, display: DisplayKHR) -> Result -ProcGetDrmDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, drmFd: i32, connectorId: u32, display: ^DisplayKHR) -> Result -ProcCreatePrivateDataSlotEXT :: #type proc "system" (device: Device, pCreateInfo: ^PrivateDataSlotCreateInfoEXT, pAllocator: ^AllocationCallbacks, pPrivateDataSlot: ^PrivateDataSlotEXT) -> Result -ProcDestroyPrivateDataSlotEXT :: #type proc "system" (device: Device, privateDataSlot: PrivateDataSlotEXT, pAllocator: ^AllocationCallbacks) -ProcSetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlotEXT, data: u64) -> Result -ProcGetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlotEXT, pData: ^u64) -ProcCmdSetFragmentShadingRateEnumNV :: #type proc "system" (commandBuffer: CommandBuffer, shadingRate: FragmentShadingRateNV) ProcAcquireWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result -ProcGetWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result -ProcCmdSetVertexInputEXT :: #type proc "system" (commandBuffer: CommandBuffer, vertexBindingDescriptionCount: u32, pVertexBindingDescriptions: [^]VertexInputBindingDescription2EXT, vertexAttributeDescriptionCount: u32, pVertexAttributeDescriptions: [^]VertexInputAttributeDescription2EXT) -ProcGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI :: #type proc "system" (device: Device, renderpass: RenderPass, pMaxWorkgroupSize: ^Extent2D) -> Result -ProcCmdSubpassShadingHUAWEI :: #type proc "system" (commandBuffer: CommandBuffer) -ProcCmdBindInvocationMaskHUAWEI :: #type proc "system" (commandBuffer: CommandBuffer, imageView: ImageView, imageLayout: ImageLayout) -ProcGetMemoryRemoteAddressNV :: #type proc "system" (device: Device, pMemoryGetRemoteAddressInfo: ^MemoryGetRemoteAddressInfoNV, pAddress: [^]RemoteAddressNV) -> Result -ProcCmdSetPatchControlPointsEXT :: #type proc "system" (commandBuffer: CommandBuffer, patchControlPoints: u32) -ProcCmdSetRasterizerDiscardEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, rasterizerDiscardEnable: b32) -ProcCmdSetDepthBiasEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthBiasEnable: b32) -ProcCmdSetLogicOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, logicOp: LogicOp) -ProcCmdSetPrimitiveRestartEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, primitiveRestartEnable: b32) -ProcCmdDrawMultiEXT :: #type proc "system" (commandBuffer: CommandBuffer, drawCount: u32, pVertexInfo: ^MultiDrawInfoEXT, instanceCount: u32, firstInstance: u32, stride: u32) -ProcCmdDrawMultiIndexedEXT :: #type proc "system" (commandBuffer: CommandBuffer, drawCount: u32, pIndexInfo: ^MultiDrawIndexedInfoEXT, instanceCount: u32, firstInstance: u32, stride: u32, pVertexOffset: ^i32) -ProcSetDeviceMemoryPriorityEXT :: #type proc "system" (device: Device, memory: DeviceMemory, priority: f32) -ProcCreateAccelerationStructureKHR :: #type proc "system" (device: Device, pCreateInfo: ^AccelerationStructureCreateInfoKHR, pAllocator: ^AllocationCallbacks, pAccelerationStructure: ^AccelerationStructureKHR) -> Result -ProcDestroyAccelerationStructureKHR :: #type proc "system" (device: Device, accelerationStructure: AccelerationStructureKHR, pAllocator: ^AllocationCallbacks) -ProcCmdBuildAccelerationStructuresKHR :: #type proc "system" (commandBuffer: CommandBuffer, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, ppBuildRangeInfos: ^[^]AccelerationStructureBuildRangeInfoKHR) -ProcCmdBuildAccelerationStructuresIndirectKHR :: #type proc "system" (commandBuffer: CommandBuffer, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, pIndirectDeviceAddresses: [^]DeviceAddress, pIndirectStrides: [^]u32, ppMaxPrimitiveCounts: ^[^]u32) -ProcBuildAccelerationStructuresKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, ppBuildRangeInfos: ^[^]AccelerationStructureBuildRangeInfoKHR) -> Result -ProcCopyAccelerationStructureKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyAccelerationStructureInfoKHR) -> Result -ProcCopyAccelerationStructureToMemoryKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyAccelerationStructureToMemoryInfoKHR) -> Result -ProcCopyMemoryToAccelerationStructureKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyMemoryToAccelerationStructureInfoKHR) -> Result -ProcWriteAccelerationStructuresPropertiesKHR :: #type proc "system" (device: Device, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureKHR, queryType: QueryType, dataSize: int, pData: rawptr, stride: int) -> Result -ProcCmdCopyAccelerationStructureKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyAccelerationStructureInfoKHR) -ProcCmdCopyAccelerationStructureToMemoryKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyAccelerationStructureToMemoryInfoKHR) -ProcCmdCopyMemoryToAccelerationStructureKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyMemoryToAccelerationStructureInfoKHR) -ProcGetAccelerationStructureDeviceAddressKHR :: #type proc "system" (device: Device, pInfo: ^AccelerationStructureDeviceAddressInfoKHR) -> DeviceAddress -ProcCmdWriteAccelerationStructuresPropertiesKHR :: #type proc "system" (commandBuffer: CommandBuffer, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureKHR, queryType: QueryType, queryPool: QueryPool, firstQuery: u32) -ProcGetDeviceAccelerationStructureCompatibilityKHR :: #type proc "system" (device: Device, pVersionInfo: ^AccelerationStructureVersionInfoKHR, pCompatibility: ^AccelerationStructureCompatibilityKHR) -ProcGetAccelerationStructureBuildSizesKHR :: #type proc "system" (device: Device, buildType: AccelerationStructureBuildTypeKHR, pBuildInfo: ^AccelerationStructureBuildGeometryInfoKHR, pMaxPrimitiveCounts: [^]u32, pSizeInfo: ^AccelerationStructureBuildSizesInfoKHR) -ProcCmdTraceRaysKHR :: #type proc "system" (commandBuffer: CommandBuffer, pRaygenShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pMissShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pHitShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pCallableShaderBindingTable: [^]StridedDeviceAddressRegionKHR, width: u32, height: u32, depth: u32) -ProcCreateRayTracingPipelinesKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]RayTracingPipelineCreateInfoKHR, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result -ProcGetRayTracingCaptureReplayShaderGroupHandlesKHR :: #type proc "system" (device: Device, pipeline: Pipeline, firstGroup: u32, groupCount: u32, dataSize: int, pData: rawptr) -> Result -ProcCmdTraceRaysIndirectKHR :: #type proc "system" (commandBuffer: CommandBuffer, pRaygenShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pMissShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pHitShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pCallableShaderBindingTable: [^]StridedDeviceAddressRegionKHR, indirectDeviceAddress: DeviceAddress) -ProcGetRayTracingShaderGroupStackSizeKHR :: #type proc "system" (device: Device, pipeline: Pipeline, group: u32, groupShader: ShaderGroupShaderKHR) -> DeviceSize -ProcCmdSetRayTracingPipelineStackSizeKHR :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStackSize: u32) -ProcCreateWin32SurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result -ProcGetPhysicalDeviceWin32PresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32 -ProcGetMemoryWin32HandleKHR :: #type proc "system" (device: Device, pGetWin32HandleInfo: ^MemoryGetWin32HandleInfoKHR, pHandle: ^HANDLE) -> Result -ProcGetMemoryWin32HandlePropertiesKHR :: #type proc "system" (device: Device, handleType: ExternalMemoryHandleTypeFlags, handle: HANDLE, pMemoryWin32HandleProperties: [^]MemoryWin32HandlePropertiesKHR) -> Result -ProcImportSemaphoreWin32HandleKHR :: #type proc "system" (device: Device, pImportSemaphoreWin32HandleInfo: ^ImportSemaphoreWin32HandleInfoKHR) -> Result -ProcGetSemaphoreWin32HandleKHR :: #type proc "system" (device: Device, pGetWin32HandleInfo: ^SemaphoreGetWin32HandleInfoKHR, pHandle: ^HANDLE) -> Result -ProcImportFenceWin32HandleKHR :: #type proc "system" (device: Device, pImportFenceWin32HandleInfo: ^ImportFenceWin32HandleInfoKHR) -> Result -ProcGetFenceWin32HandleKHR :: #type proc "system" (device: Device, pGetWin32HandleInfo: ^FenceGetWin32HandleInfoKHR, pHandle: ^HANDLE) -> Result -ProcGetMemoryWin32HandleNV :: #type proc "system" (device: Device, memory: DeviceMemory, handleType: ExternalMemoryHandleTypeFlagsNV, pHandle: ^HANDLE) -> Result -ProcGetPhysicalDeviceSurfacePresentModes2EXT :: #type proc "system" (physicalDevice: PhysicalDevice, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pPresentModeCount: ^u32, pPresentModes: [^]PresentModeKHR) -> Result -ProcAcquireFullScreenExclusiveModeEXT :: #type proc "system" (device: Device, swapchain: SwapchainKHR) -> Result -ProcReleaseFullScreenExclusiveModeEXT :: #type proc "system" (device: Device, swapchain: SwapchainKHR) -> Result -ProcGetDeviceGroupSurfacePresentModes2EXT :: #type proc "system" (device: Device, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pModes: [^]DeviceGroupPresentModeFlagsKHR) -> Result -ProcCreateMetalSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result -ProcCreateMacOSSurfaceMVK :: #type proc "system" (instance: Instance, pCreateInfo: ^MacOSSurfaceCreateInfoMVK, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateDebugReportCallbackEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^DebugReportCallbackCreateInfoEXT, pAllocator: ^AllocationCallbacks, pCallback: ^DebugReportCallbackEXT) -> Result +ProcCreateDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^DebugUtilsMessengerCreateInfoEXT, pAllocator: ^AllocationCallbacks, pMessenger: ^DebugUtilsMessengerEXT) -> Result +ProcCreateDevice :: #type proc "system" (physicalDevice: PhysicalDevice, pCreateInfo: ^DeviceCreateInfo, pAllocator: ^AllocationCallbacks, pDevice: ^Device) -> Result +ProcCreateDisplayModeKHR :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR, pCreateInfo: ^DisplayModeCreateInfoKHR, pAllocator: ^AllocationCallbacks, pMode: ^DisplayModeKHR) -> Result +ProcCreateDisplayPlaneSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^DisplaySurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateHeadlessSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^HeadlessSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateIOSSurfaceMVK :: #type proc "system" (instance: Instance, pCreateInfo: ^IOSSurfaceCreateInfoMVK, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateMacOSSurfaceMVK :: #type proc "system" (instance: Instance, pCreateInfo: ^MacOSSurfaceCreateInfoMVK, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateMetalSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateWin32SurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcDebugReportMessageEXT :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring) +ProcDestroyDebugReportCallbackEXT :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks) +ProcDestroyDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks) +ProcDestroyInstance :: #type proc "system" (instance: Instance, pAllocator: ^AllocationCallbacks) +ProcDestroySurfaceKHR :: #type proc "system" (instance: Instance, surface: SurfaceKHR, pAllocator: ^AllocationCallbacks) +ProcEnumerateDeviceExtensionProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pLayerName: cstring, pPropertyCount: ^u32, pProperties: [^]ExtensionProperties) -> Result +ProcEnumerateDeviceLayerProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]LayerProperties) -> Result +ProcEnumeratePhysicalDeviceGroups :: #type proc "system" (instance: Instance, pPhysicalDeviceGroupCount: ^u32, pPhysicalDeviceGroupProperties: [^]PhysicalDeviceGroupProperties) -> Result +ProcEnumeratePhysicalDeviceGroupsKHR :: #type proc "system" (instance: Instance, pPhysicalDeviceGroupCount: ^u32, pPhysicalDeviceGroupProperties: [^]PhysicalDeviceGroupProperties) -> Result +ProcEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, pCounterCount: ^u32, pCounters: [^]PerformanceCounterKHR, pCounterDescriptions: [^]PerformanceCounterDescriptionKHR) -> Result +ProcEnumeratePhysicalDevices :: #type proc "system" (instance: Instance, pPhysicalDeviceCount: ^u32, pPhysicalDevices: [^]PhysicalDevice) -> Result +ProcGetDisplayModeProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR, pPropertyCount: ^u32, pProperties: [^]DisplayModeProperties2KHR) -> Result +ProcGetDisplayModePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR, pPropertyCount: ^u32, pProperties: [^]DisplayModePropertiesKHR) -> Result +ProcGetDisplayPlaneCapabilities2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pDisplayPlaneInfo: ^DisplayPlaneInfo2KHR, pCapabilities: [^]DisplayPlaneCapabilities2KHR) -> Result +ProcGetDisplayPlaneCapabilitiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, mode: DisplayModeKHR, planeIndex: u32, pCapabilities: [^]DisplayPlaneCapabilitiesKHR) -> Result +ProcGetDisplayPlaneSupportedDisplaysKHR :: #type proc "system" (physicalDevice: PhysicalDevice, planeIndex: u32, pDisplayCount: ^u32, pDisplays: [^]DisplayKHR) -> Result +ProcGetDrmDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, drmFd: i32, connectorId: u32, display: ^DisplayKHR) -> Result +ProcGetInstanceProcAddr :: #type proc "system" (instance: Instance, pName: cstring) -> ProcVoidFunction +ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT :: #type proc "system" (physicalDevice: PhysicalDevice, pTimeDomainCount: ^u32, pTimeDomains: [^]TimeDomainEXT) -> Result +ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]CooperativeMatrixPropertiesNV) -> Result +ProcGetPhysicalDeviceDisplayPlaneProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayPlaneProperties2KHR) -> Result +ProcGetPhysicalDeviceDisplayPlanePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayPlanePropertiesKHR) -> Result +ProcGetPhysicalDeviceDisplayProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayProperties2KHR) -> Result +ProcGetPhysicalDeviceDisplayPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPropertyCount: ^u32, pProperties: [^]DisplayPropertiesKHR) -> Result +ProcGetPhysicalDeviceExternalBufferProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalBufferInfo: ^PhysicalDeviceExternalBufferInfo, pExternalBufferProperties: [^]ExternalBufferProperties) +ProcGetPhysicalDeviceExternalBufferPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalBufferInfo: ^PhysicalDeviceExternalBufferInfo, pExternalBufferProperties: [^]ExternalBufferProperties) +ProcGetPhysicalDeviceExternalFenceProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalFenceInfo: ^PhysicalDeviceExternalFenceInfo, pExternalFenceProperties: [^]ExternalFenceProperties) +ProcGetPhysicalDeviceExternalFencePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalFenceInfo: ^PhysicalDeviceExternalFenceInfo, pExternalFenceProperties: [^]ExternalFenceProperties) +ProcGetPhysicalDeviceExternalImageFormatPropertiesNV :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, type: ImageType, tiling: ImageTiling, usage: ImageUsageFlags, flags: ImageCreateFlags, externalHandleType: ExternalMemoryHandleTypeFlagsNV, pExternalImageFormatProperties: [^]ExternalImageFormatPropertiesNV) -> Result +ProcGetPhysicalDeviceExternalSemaphoreProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalSemaphoreInfo: ^PhysicalDeviceExternalSemaphoreInfo, pExternalSemaphoreProperties: [^]ExternalSemaphoreProperties) +ProcGetPhysicalDeviceExternalSemaphorePropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pExternalSemaphoreInfo: ^PhysicalDeviceExternalSemaphoreInfo, pExternalSemaphoreProperties: [^]ExternalSemaphoreProperties) +ProcGetPhysicalDeviceFeatures :: #type proc "system" (physicalDevice: PhysicalDevice, pFeatures: [^]PhysicalDeviceFeatures) +ProcGetPhysicalDeviceFeatures2 :: #type proc "system" (physicalDevice: PhysicalDevice, pFeatures: [^]PhysicalDeviceFeatures2) +ProcGetPhysicalDeviceFeatures2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pFeatures: [^]PhysicalDeviceFeatures2) +ProcGetPhysicalDeviceFormatProperties :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, pFormatProperties: [^]FormatProperties) +ProcGetPhysicalDeviceFormatProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, pFormatProperties: [^]FormatProperties2) +ProcGetPhysicalDeviceFormatProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, pFormatProperties: [^]FormatProperties2) +ProcGetPhysicalDeviceFragmentShadingRatesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pFragmentShadingRateCount: ^u32, pFragmentShadingRates: [^]PhysicalDeviceFragmentShadingRateKHR) -> Result +ProcGetPhysicalDeviceImageFormatProperties :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, type: ImageType, tiling: ImageTiling, usage: ImageUsageFlags, flags: ImageCreateFlags, pImageFormatProperties: [^]ImageFormatProperties) -> Result +ProcGetPhysicalDeviceImageFormatProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pImageFormatInfo: ^PhysicalDeviceImageFormatInfo2, pImageFormatProperties: [^]ImageFormatProperties2) -> Result +ProcGetPhysicalDeviceImageFormatProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pImageFormatInfo: ^PhysicalDeviceImageFormatInfo2, pImageFormatProperties: [^]ImageFormatProperties2) -> Result +ProcGetPhysicalDeviceMemoryProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pMemoryProperties: [^]PhysicalDeviceMemoryProperties) +ProcGetPhysicalDeviceMemoryProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pMemoryProperties: [^]PhysicalDeviceMemoryProperties2) +ProcGetPhysicalDeviceMemoryProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pMemoryProperties: [^]PhysicalDeviceMemoryProperties2) +ProcGetPhysicalDeviceMultisamplePropertiesEXT :: #type proc "system" (physicalDevice: PhysicalDevice, samples: SampleCountFlags, pMultisampleProperties: [^]MultisamplePropertiesEXT) +ProcGetPhysicalDevicePresentRectanglesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pRectCount: ^u32, pRects: [^]Rect2D) -> Result +ProcGetPhysicalDeviceProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pProperties: [^]PhysicalDeviceProperties) +ProcGetPhysicalDeviceProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pProperties: [^]PhysicalDeviceProperties2) +ProcGetPhysicalDeviceProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pProperties: [^]PhysicalDeviceProperties2) +ProcGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pPerformanceQueryCreateInfo: ^QueryPoolPerformanceCreateInfoKHR, pNumPasses: [^]u32) +ProcGetPhysicalDeviceQueueFamilyProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pQueueFamilyPropertyCount: ^u32, pQueueFamilyProperties: [^]QueueFamilyProperties) +ProcGetPhysicalDeviceQueueFamilyProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pQueueFamilyPropertyCount: ^u32, pQueueFamilyProperties: [^]QueueFamilyProperties2) +ProcGetPhysicalDeviceQueueFamilyProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pQueueFamilyPropertyCount: ^u32, pQueueFamilyProperties: [^]QueueFamilyProperties2) +ProcGetPhysicalDeviceSparseImageFormatProperties :: #type proc "system" (physicalDevice: PhysicalDevice, format: Format, type: ImageType, samples: SampleCountFlags, usage: ImageUsageFlags, tiling: ImageTiling, pPropertyCount: ^u32, pProperties: [^]SparseImageFormatProperties) +ProcGetPhysicalDeviceSparseImageFormatProperties2 :: #type proc "system" (physicalDevice: PhysicalDevice, pFormatInfo: ^PhysicalDeviceSparseImageFormatInfo2, pPropertyCount: ^u32, pProperties: [^]SparseImageFormatProperties2) +ProcGetPhysicalDeviceSparseImageFormatProperties2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pFormatInfo: ^PhysicalDeviceSparseImageFormatInfo2, pPropertyCount: ^u32, pProperties: [^]SparseImageFormatProperties2) +ProcGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV :: #type proc "system" (physicalDevice: PhysicalDevice, pCombinationCount: ^u32, pCombinations: [^]FramebufferMixedSamplesCombinationNV) -> Result +ProcGetPhysicalDeviceSurfaceCapabilities2EXT :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pSurfaceCapabilities: [^]SurfaceCapabilities2EXT) -> Result +ProcGetPhysicalDeviceSurfaceCapabilities2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pSurfaceCapabilities: [^]SurfaceCapabilities2KHR) -> Result +ProcGetPhysicalDeviceSurfaceCapabilitiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pSurfaceCapabilities: [^]SurfaceCapabilitiesKHR) -> Result +ProcGetPhysicalDeviceSurfaceFormats2KHR :: #type proc "system" (physicalDevice: PhysicalDevice, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pSurfaceFormatCount: ^u32, pSurfaceFormats: [^]SurfaceFormat2KHR) -> Result +ProcGetPhysicalDeviceSurfaceFormatsKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pSurfaceFormatCount: ^u32, pSurfaceFormats: [^]SurfaceFormatKHR) -> Result +ProcGetPhysicalDeviceSurfacePresentModes2EXT :: #type proc "system" (physicalDevice: PhysicalDevice, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pPresentModeCount: ^u32, pPresentModes: [^]PresentModeKHR) -> Result +ProcGetPhysicalDeviceSurfacePresentModesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pPresentModeCount: ^u32, pPresentModes: [^]PresentModeKHR) -> Result +ProcGetPhysicalDeviceSurfaceSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, surface: SurfaceKHR, pSupported: ^b32) -> Result +ProcGetPhysicalDeviceToolPropertiesEXT :: #type proc "system" (physicalDevice: PhysicalDevice, pToolCount: ^u32, pToolProperties: [^]PhysicalDeviceToolPropertiesEXT) -> Result +ProcGetPhysicalDeviceWin32PresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32 +ProcGetWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result +ProcReleaseDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result +ProcSubmitDebugUtilsMessageEXT :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT) -// Instance Procedures -DestroyInstance: ProcDestroyInstance -EnumeratePhysicalDevices: ProcEnumeratePhysicalDevices -GetPhysicalDeviceFeatures: ProcGetPhysicalDeviceFeatures -GetPhysicalDeviceFormatProperties: ProcGetPhysicalDeviceFormatProperties -GetPhysicalDeviceImageFormatProperties: ProcGetPhysicalDeviceImageFormatProperties -GetPhysicalDeviceProperties: ProcGetPhysicalDeviceProperties -GetPhysicalDeviceQueueFamilyProperties: ProcGetPhysicalDeviceQueueFamilyProperties -GetPhysicalDeviceMemoryProperties: ProcGetPhysicalDeviceMemoryProperties -GetInstanceProcAddr: ProcGetInstanceProcAddr -CreateDevice: ProcCreateDevice -EnumerateDeviceExtensionProperties: ProcEnumerateDeviceExtensionProperties -EnumerateDeviceLayerProperties: ProcEnumerateDeviceLayerProperties -GetPhysicalDeviceSparseImageFormatProperties: ProcGetPhysicalDeviceSparseImageFormatProperties -EnumeratePhysicalDeviceGroups: ProcEnumeratePhysicalDeviceGroups -GetPhysicalDeviceFeatures2: ProcGetPhysicalDeviceFeatures2 -GetPhysicalDeviceProperties2: ProcGetPhysicalDeviceProperties2 -GetPhysicalDeviceFormatProperties2: ProcGetPhysicalDeviceFormatProperties2 -GetPhysicalDeviceImageFormatProperties2: ProcGetPhysicalDeviceImageFormatProperties2 -GetPhysicalDeviceQueueFamilyProperties2: ProcGetPhysicalDeviceQueueFamilyProperties2 -GetPhysicalDeviceMemoryProperties2: ProcGetPhysicalDeviceMemoryProperties2 -GetPhysicalDeviceSparseImageFormatProperties2: ProcGetPhysicalDeviceSparseImageFormatProperties2 -GetPhysicalDeviceExternalBufferProperties: ProcGetPhysicalDeviceExternalBufferProperties -GetPhysicalDeviceExternalFenceProperties: ProcGetPhysicalDeviceExternalFenceProperties -GetPhysicalDeviceExternalSemaphoreProperties: ProcGetPhysicalDeviceExternalSemaphoreProperties -DestroySurfaceKHR: ProcDestroySurfaceKHR -GetPhysicalDeviceSurfaceSupportKHR: ProcGetPhysicalDeviceSurfaceSupportKHR -GetPhysicalDeviceSurfaceCapabilitiesKHR: ProcGetPhysicalDeviceSurfaceCapabilitiesKHR -GetPhysicalDeviceSurfaceFormatsKHR: ProcGetPhysicalDeviceSurfaceFormatsKHR -GetPhysicalDeviceSurfacePresentModesKHR: ProcGetPhysicalDeviceSurfacePresentModesKHR -GetPhysicalDevicePresentRectanglesKHR: ProcGetPhysicalDevicePresentRectanglesKHR -GetPhysicalDeviceDisplayPropertiesKHR: ProcGetPhysicalDeviceDisplayPropertiesKHR -GetPhysicalDeviceDisplayPlanePropertiesKHR: ProcGetPhysicalDeviceDisplayPlanePropertiesKHR -GetDisplayPlaneSupportedDisplaysKHR: ProcGetDisplayPlaneSupportedDisplaysKHR -GetDisplayModePropertiesKHR: ProcGetDisplayModePropertiesKHR -CreateDisplayModeKHR: ProcCreateDisplayModeKHR -GetDisplayPlaneCapabilitiesKHR: ProcGetDisplayPlaneCapabilitiesKHR -CreateDisplayPlaneSurfaceKHR: ProcCreateDisplayPlaneSurfaceKHR -GetPhysicalDeviceFeatures2KHR: ProcGetPhysicalDeviceFeatures2KHR -GetPhysicalDeviceProperties2KHR: ProcGetPhysicalDeviceProperties2KHR -GetPhysicalDeviceFormatProperties2KHR: ProcGetPhysicalDeviceFormatProperties2KHR -GetPhysicalDeviceImageFormatProperties2KHR: ProcGetPhysicalDeviceImageFormatProperties2KHR -GetPhysicalDeviceQueueFamilyProperties2KHR: ProcGetPhysicalDeviceQueueFamilyProperties2KHR -GetPhysicalDeviceMemoryProperties2KHR: ProcGetPhysicalDeviceMemoryProperties2KHR -GetPhysicalDeviceSparseImageFormatProperties2KHR: ProcGetPhysicalDeviceSparseImageFormatProperties2KHR -EnumeratePhysicalDeviceGroupsKHR: ProcEnumeratePhysicalDeviceGroupsKHR -GetPhysicalDeviceExternalBufferPropertiesKHR: ProcGetPhysicalDeviceExternalBufferPropertiesKHR -GetPhysicalDeviceExternalSemaphorePropertiesKHR: ProcGetPhysicalDeviceExternalSemaphorePropertiesKHR -GetPhysicalDeviceExternalFencePropertiesKHR: ProcGetPhysicalDeviceExternalFencePropertiesKHR -EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR: ProcEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR -GetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR: ProcGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR -GetPhysicalDeviceSurfaceCapabilities2KHR: ProcGetPhysicalDeviceSurfaceCapabilities2KHR -GetPhysicalDeviceSurfaceFormats2KHR: ProcGetPhysicalDeviceSurfaceFormats2KHR -GetPhysicalDeviceDisplayProperties2KHR: ProcGetPhysicalDeviceDisplayProperties2KHR -GetPhysicalDeviceDisplayPlaneProperties2KHR: ProcGetPhysicalDeviceDisplayPlaneProperties2KHR -GetDisplayModeProperties2KHR: ProcGetDisplayModeProperties2KHR -GetDisplayPlaneCapabilities2KHR: ProcGetDisplayPlaneCapabilities2KHR -GetPhysicalDeviceFragmentShadingRatesKHR: ProcGetPhysicalDeviceFragmentShadingRatesKHR -CreateDebugReportCallbackEXT: ProcCreateDebugReportCallbackEXT -DestroyDebugReportCallbackEXT: ProcDestroyDebugReportCallbackEXT -DebugReportMessageEXT: ProcDebugReportMessageEXT -GetPhysicalDeviceExternalImageFormatPropertiesNV: ProcGetPhysicalDeviceExternalImageFormatPropertiesNV -ReleaseDisplayEXT: ProcReleaseDisplayEXT -GetPhysicalDeviceSurfaceCapabilities2EXT: ProcGetPhysicalDeviceSurfaceCapabilities2EXT -CreateDebugUtilsMessengerEXT: ProcCreateDebugUtilsMessengerEXT -DestroyDebugUtilsMessengerEXT: ProcDestroyDebugUtilsMessengerEXT -SubmitDebugUtilsMessageEXT: ProcSubmitDebugUtilsMessageEXT -GetPhysicalDeviceMultisamplePropertiesEXT: ProcGetPhysicalDeviceMultisamplePropertiesEXT -GetPhysicalDeviceCalibrateableTimeDomainsEXT: ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT -GetPhysicalDeviceToolPropertiesEXT: ProcGetPhysicalDeviceToolPropertiesEXT -GetPhysicalDeviceCooperativeMatrixPropertiesNV: ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV -GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV: ProcGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV -CreateHeadlessSurfaceEXT: ProcCreateHeadlessSurfaceEXT -AcquireDrmDisplayEXT: ProcAcquireDrmDisplayEXT -GetDrmDisplayEXT: ProcGetDrmDisplayEXT -AcquireWinrtDisplayNV: ProcAcquireWinrtDisplayNV -GetWinrtDisplayNV: ProcGetWinrtDisplayNV -CreateWin32SurfaceKHR: ProcCreateWin32SurfaceKHR -GetPhysicalDeviceWin32PresentationSupportKHR: ProcGetPhysicalDeviceWin32PresentationSupportKHR -GetPhysicalDeviceSurfacePresentModes2EXT: ProcGetPhysicalDeviceSurfacePresentModes2EXT -CreateMetalSurfaceEXT: ProcCreateMetalSurfaceEXT -CreateMacOSSurfaceMVK: ProcCreateMacOSSurfaceMVK -CreateIOSSurfaceMVK: ProcCreateIOSSurfaceMVK +// Device Procedure Types +ProcAcquireFullScreenExclusiveModeEXT :: #type proc "system" (device: Device, swapchain: SwapchainKHR) -> Result +ProcAcquireNextImage2KHR :: #type proc "system" (device: Device, pAcquireInfo: ^AcquireNextImageInfoKHR, pImageIndex: ^u32) -> Result +ProcAcquireNextImageKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, timeout: u64, semaphore: Semaphore, fence: Fence, pImageIndex: ^u32) -> Result +ProcAcquirePerformanceConfigurationINTEL :: #type proc "system" (device: Device, pAcquireInfo: ^PerformanceConfigurationAcquireInfoINTEL, pConfiguration: ^PerformanceConfigurationINTEL) -> Result +ProcAcquireProfilingLockKHR :: #type proc "system" (device: Device, pInfo: ^AcquireProfilingLockInfoKHR) -> Result +ProcAllocateCommandBuffers :: #type proc "system" (device: Device, pAllocateInfo: ^CommandBufferAllocateInfo, pCommandBuffers: [^]CommandBuffer) -> Result +ProcAllocateDescriptorSets :: #type proc "system" (device: Device, pAllocateInfo: ^DescriptorSetAllocateInfo, pDescriptorSets: [^]DescriptorSet) -> Result +ProcAllocateMemory :: #type proc "system" (device: Device, pAllocateInfo: ^MemoryAllocateInfo, pAllocator: ^AllocationCallbacks, pMemory: ^DeviceMemory) -> Result +ProcBeginCommandBuffer :: #type proc "system" (commandBuffer: CommandBuffer, pBeginInfo: ^CommandBufferBeginInfo) -> Result +ProcBindAccelerationStructureMemoryNV :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindAccelerationStructureMemoryInfoNV) -> Result +ProcBindBufferMemory :: #type proc "system" (device: Device, buffer: Buffer, memory: DeviceMemory, memoryOffset: DeviceSize) -> Result +ProcBindBufferMemory2 :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindBufferMemoryInfo) -> Result +ProcBindBufferMemory2KHR :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindBufferMemoryInfo) -> Result +ProcBindImageMemory :: #type proc "system" (device: Device, image: Image, memory: DeviceMemory, memoryOffset: DeviceSize) -> Result +ProcBindImageMemory2 :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindImageMemoryInfo) -> Result +ProcBindImageMemory2KHR :: #type proc "system" (device: Device, bindInfoCount: u32, pBindInfos: [^]BindImageMemoryInfo) -> Result +ProcBuildAccelerationStructuresKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, ppBuildRangeInfos: ^[^]AccelerationStructureBuildRangeInfoKHR) -> Result +ProcCmdBeginConditionalRenderingEXT :: #type proc "system" (commandBuffer: CommandBuffer, pConditionalRenderingBegin: ^ConditionalRenderingBeginInfoEXT) +ProcCmdBeginDebugUtilsLabelEXT :: #type proc "system" (commandBuffer: CommandBuffer, pLabelInfo: ^DebugUtilsLabelEXT) +ProcCmdBeginQuery :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32, flags: QueryControlFlags) +ProcCmdBeginQueryIndexedEXT :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32, flags: QueryControlFlags, index: u32) +ProcCmdBeginRenderPass :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, contents: SubpassContents) +ProcCmdBeginRenderPass2 :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, pSubpassBeginInfo: ^SubpassBeginInfo) +ProcCmdBeginRenderPass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, pSubpassBeginInfo: ^SubpassBeginInfo) +ProcCmdBeginTransformFeedbackEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstCounterBuffer: u32, counterBufferCount: u32, pCounterBuffers: [^]Buffer, pCounterBufferOffsets: [^]DeviceSize) +ProcCmdBindDescriptorSets :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, layout: PipelineLayout, firstSet: u32, descriptorSetCount: u32, pDescriptorSets: [^]DescriptorSet, dynamicOffsetCount: u32, pDynamicOffsets: [^]u32) +ProcCmdBindIndexBuffer :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, indexType: IndexType) +ProcCmdBindInvocationMaskHUAWEI :: #type proc "system" (commandBuffer: CommandBuffer, imageView: ImageView, imageLayout: ImageLayout) +ProcCmdBindPipeline :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, pipeline: Pipeline) +ProcCmdBindPipelineShaderGroupNV :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, pipeline: Pipeline, groupIndex: u32) +ProcCmdBindShadingRateImageNV :: #type proc "system" (commandBuffer: CommandBuffer, imageView: ImageView, imageLayout: ImageLayout) +ProcCmdBindTransformFeedbackBuffersEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize, pSizes: [^]DeviceSize) +ProcCmdBindVertexBuffers :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize) +ProcCmdBindVertexBuffers2EXT :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize, pSizes: [^]DeviceSize, pStrides: [^]DeviceSize) +ProcCmdBlitImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageBlit, filter: Filter) +ProcCmdBlitImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pBlitImageInfo: ^BlitImageInfo2KHR) +ProcCmdBuildAccelerationStructureNV :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^AccelerationStructureInfoNV, instanceData: Buffer, instanceOffset: DeviceSize, update: b32, dst: AccelerationStructureNV, src: AccelerationStructureNV, scratch: Buffer, scratchOffset: DeviceSize) +ProcCmdBuildAccelerationStructuresIndirectKHR :: #type proc "system" (commandBuffer: CommandBuffer, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, pIndirectDeviceAddresses: [^]DeviceAddress, pIndirectStrides: [^]u32, ppMaxPrimitiveCounts: ^[^]u32) +ProcCmdBuildAccelerationStructuresKHR :: #type proc "system" (commandBuffer: CommandBuffer, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, ppBuildRangeInfos: ^[^]AccelerationStructureBuildRangeInfoKHR) +ProcCmdClearAttachments :: #type proc "system" (commandBuffer: CommandBuffer, attachmentCount: u32, pAttachments: [^]ClearAttachment, rectCount: u32, pRects: [^]ClearRect) +ProcCmdClearColorImage :: #type proc "system" (commandBuffer: CommandBuffer, image: Image, imageLayout: ImageLayout, pColor: ^ClearColorValue, rangeCount: u32, pRanges: [^]ImageSubresourceRange) +ProcCmdClearDepthStencilImage :: #type proc "system" (commandBuffer: CommandBuffer, image: Image, imageLayout: ImageLayout, pDepthStencil: ^ClearDepthStencilValue, rangeCount: u32, pRanges: [^]ImageSubresourceRange) +ProcCmdCopyAccelerationStructureKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyAccelerationStructureInfoKHR) +ProcCmdCopyAccelerationStructureNV :: #type proc "system" (commandBuffer: CommandBuffer, dst: AccelerationStructureNV, src: AccelerationStructureNV, mode: CopyAccelerationStructureModeKHR) +ProcCmdCopyAccelerationStructureToMemoryKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyAccelerationStructureToMemoryInfoKHR) +ProcCmdCopyBuffer :: #type proc "system" (commandBuffer: CommandBuffer, srcBuffer: Buffer, dstBuffer: Buffer, regionCount: u32, pRegions: [^]BufferCopy) +ProcCmdCopyBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferInfo: ^CopyBufferInfo2KHR) +ProcCmdCopyBufferToImage :: #type proc "system" (commandBuffer: CommandBuffer, srcBuffer: Buffer, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]BufferImageCopy) +ProcCmdCopyBufferToImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferToImageInfo: ^CopyBufferToImageInfo2KHR) +ProcCmdCopyImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageCopy) +ProcCmdCopyImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageInfo: ^CopyImageInfo2KHR) +ProcCmdCopyImageToBuffer :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstBuffer: Buffer, regionCount: u32, pRegions: [^]BufferImageCopy) +ProcCmdCopyImageToBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageToBufferInfo: ^CopyImageToBufferInfo2KHR) +ProcCmdCopyMemoryToAccelerationStructureKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyMemoryToAccelerationStructureInfoKHR) +ProcCmdCopyQueryPoolResults :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, firstQuery: u32, queryCount: u32, dstBuffer: Buffer, dstOffset: DeviceSize, stride: DeviceSize, flags: QueryResultFlags) +ProcCmdCuLaunchKernelNVX :: #type proc "system" (commandBuffer: CommandBuffer, pLaunchInfo: ^CuLaunchInfoNVX) +ProcCmdDebugMarkerBeginEXT :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^DebugMarkerMarkerInfoEXT) +ProcCmdDebugMarkerEndEXT :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdDebugMarkerInsertEXT :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^DebugMarkerMarkerInfoEXT) +ProcCmdDispatch :: #type proc "system" (commandBuffer: CommandBuffer, groupCountX: u32, groupCountY: u32, groupCountZ: u32) +ProcCmdDispatchBase :: #type proc "system" (commandBuffer: CommandBuffer, baseGroupX: u32, baseGroupY: u32, baseGroupZ: u32, groupCountX: u32, groupCountY: u32, groupCountZ: u32) +ProcCmdDispatchBaseKHR :: #type proc "system" (commandBuffer: CommandBuffer, baseGroupX: u32, baseGroupY: u32, baseGroupZ: u32, groupCountX: u32, groupCountY: u32, groupCountZ: u32) +ProcCmdDispatchIndirect :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize) +ProcCmdDraw :: #type proc "system" (commandBuffer: CommandBuffer, vertexCount: u32, instanceCount: u32, firstVertex: u32, firstInstance: u32) +ProcCmdDrawIndexed :: #type proc "system" (commandBuffer: CommandBuffer, indexCount: u32, instanceCount: u32, firstIndex: u32, vertexOffset: i32, firstInstance: u32) +ProcCmdDrawIndexedIndirect :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, drawCount: u32, stride: u32) +ProcCmdDrawIndexedIndirectCount :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) +ProcCmdDrawIndexedIndirectCountAMD :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) +ProcCmdDrawIndexedIndirectCountKHR :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) +ProcCmdDrawIndirect :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, drawCount: u32, stride: u32) +ProcCmdDrawIndirectByteCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, instanceCount: u32, firstInstance: u32, counterBuffer: Buffer, counterBufferOffset: DeviceSize, counterOffset: u32, vertexStride: u32) +ProcCmdDrawIndirectCount :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) +ProcCmdDrawIndirectCountAMD :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) +ProcCmdDrawIndirectCountKHR :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) +ProcCmdDrawMeshTasksIndirectCountNV :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, countBuffer: Buffer, countBufferOffset: DeviceSize, maxDrawCount: u32, stride: u32) +ProcCmdDrawMeshTasksIndirectNV :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, drawCount: u32, stride: u32) +ProcCmdDrawMeshTasksNV :: #type proc "system" (commandBuffer: CommandBuffer, taskCount: u32, firstTask: u32) +ProcCmdDrawMultiEXT :: #type proc "system" (commandBuffer: CommandBuffer, drawCount: u32, pVertexInfo: ^MultiDrawInfoEXT, instanceCount: u32, firstInstance: u32, stride: u32) +ProcCmdDrawMultiIndexedEXT :: #type proc "system" (commandBuffer: CommandBuffer, drawCount: u32, pIndexInfo: ^MultiDrawIndexedInfoEXT, instanceCount: u32, firstInstance: u32, stride: u32, pVertexOffset: ^i32) +ProcCmdEndConditionalRenderingEXT :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdEndDebugUtilsLabelEXT :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdEndQuery :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32) +ProcCmdEndQueryIndexedEXT :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, query: u32, index: u32) +ProcCmdEndRenderPass :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdEndRenderPass2 :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassEndInfo: ^SubpassEndInfo) +ProcCmdEndRenderPass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassEndInfo: ^SubpassEndInfo) +ProcCmdEndTransformFeedbackEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstCounterBuffer: u32, counterBufferCount: u32, pCounterBuffers: [^]Buffer, pCounterBufferOffsets: [^]DeviceSize) +ProcCmdExecuteCommands :: #type proc "system" (commandBuffer: CommandBuffer, commandBufferCount: u32, pCommandBuffers: [^]CommandBuffer) +ProcCmdExecuteGeneratedCommandsNV :: #type proc "system" (commandBuffer: CommandBuffer, isPreprocessed: b32, pGeneratedCommandsInfo: ^GeneratedCommandsInfoNV) +ProcCmdFillBuffer :: #type proc "system" (commandBuffer: CommandBuffer, dstBuffer: Buffer, dstOffset: DeviceSize, size: DeviceSize, data: u32) +ProcCmdInsertDebugUtilsLabelEXT :: #type proc "system" (commandBuffer: CommandBuffer, pLabelInfo: ^DebugUtilsLabelEXT) +ProcCmdNextSubpass :: #type proc "system" (commandBuffer: CommandBuffer, contents: SubpassContents) +ProcCmdNextSubpass2 :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassBeginInfo: ^SubpassBeginInfo, pSubpassEndInfo: ^SubpassEndInfo) +ProcCmdNextSubpass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassBeginInfo: ^SubpassBeginInfo, pSubpassEndInfo: ^SubpassEndInfo) +ProcCmdPipelineBarrier :: #type proc "system" (commandBuffer: CommandBuffer, srcStageMask: PipelineStageFlags, dstStageMask: PipelineStageFlags, dependencyFlags: DependencyFlags, memoryBarrierCount: u32, pMemoryBarriers: [^]MemoryBarrier, bufferMemoryBarrierCount: u32, pBufferMemoryBarriers: [^]BufferMemoryBarrier, imageMemoryBarrierCount: u32, pImageMemoryBarriers: [^]ImageMemoryBarrier) +ProcCmdPipelineBarrier2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pDependencyInfo: ^DependencyInfoKHR) +ProcCmdPreprocessGeneratedCommandsNV :: #type proc "system" (commandBuffer: CommandBuffer, pGeneratedCommandsInfo: ^GeneratedCommandsInfoNV) +ProcCmdPushConstants :: #type proc "system" (commandBuffer: CommandBuffer, layout: PipelineLayout, stageFlags: ShaderStageFlags, offset: u32, size: u32, pValues: rawptr) +ProcCmdPushDescriptorSetKHR :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, layout: PipelineLayout, set: u32, descriptorWriteCount: u32, pDescriptorWrites: [^]WriteDescriptorSet) +ProcCmdPushDescriptorSetWithTemplateKHR :: #type proc "system" (commandBuffer: CommandBuffer, descriptorUpdateTemplate: DescriptorUpdateTemplate, layout: PipelineLayout, set: u32, pData: rawptr) +ProcCmdResetEvent :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags) +ProcCmdResetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags2KHR) +ProcCmdResetQueryPool :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, firstQuery: u32, queryCount: u32) +ProcCmdResolveImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageResolve) +ProcCmdResolveImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pResolveImageInfo: ^ResolveImageInfo2KHR) +ProcCmdSetBlendConstants :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdSetCheckpointNV :: #type proc "system" (commandBuffer: CommandBuffer, pCheckpointMarker: rawptr) +ProcCmdSetCoarseSampleOrderNV :: #type proc "system" (commandBuffer: CommandBuffer, sampleOrderType: CoarseSampleOrderTypeNV, customSampleOrderCount: u32, pCustomSampleOrders: [^]CoarseSampleOrderCustomNV) +ProcCmdSetCullModeEXT :: #type proc "system" (commandBuffer: CommandBuffer, cullMode: CullModeFlags) +ProcCmdSetDepthBias :: #type proc "system" (commandBuffer: CommandBuffer, depthBiasConstantFactor: f32, depthBiasClamp: f32, depthBiasSlopeFactor: f32) +ProcCmdSetDepthBiasEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthBiasEnable: b32) +ProcCmdSetDepthBounds :: #type proc "system" (commandBuffer: CommandBuffer, minDepthBounds: f32, maxDepthBounds: f32) +ProcCmdSetDepthBoundsTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthBoundsTestEnable: b32) +ProcCmdSetDepthCompareOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthCompareOp: CompareOp) +ProcCmdSetDepthTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthTestEnable: b32) +ProcCmdSetDepthWriteEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthWriteEnable: b32) +ProcCmdSetDeviceMask :: #type proc "system" (commandBuffer: CommandBuffer, deviceMask: u32) +ProcCmdSetDeviceMaskKHR :: #type proc "system" (commandBuffer: CommandBuffer, deviceMask: u32) +ProcCmdSetDiscardRectangleEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstDiscardRectangle: u32, discardRectangleCount: u32, pDiscardRectangles: [^]Rect2D) +ProcCmdSetEvent :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags) +ProcCmdSetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, pDependencyInfo: ^DependencyInfoKHR) +ProcCmdSetExclusiveScissorNV :: #type proc "system" (commandBuffer: CommandBuffer, firstExclusiveScissor: u32, exclusiveScissorCount: u32, pExclusiveScissors: [^]Rect2D) +ProcCmdSetFragmentShadingRateEnumNV :: #type proc "system" (commandBuffer: CommandBuffer, shadingRate: FragmentShadingRateNV) +ProcCmdSetFragmentShadingRateKHR :: #type proc "system" (commandBuffer: CommandBuffer, pFragmentSize: ^Extent2D) +ProcCmdSetFrontFaceEXT :: #type proc "system" (commandBuffer: CommandBuffer, frontFace: FrontFace) +ProcCmdSetLineStippleEXT :: #type proc "system" (commandBuffer: CommandBuffer, lineStippleFactor: u32, lineStipplePattern: u16) +ProcCmdSetLineWidth :: #type proc "system" (commandBuffer: CommandBuffer, lineWidth: f32) +ProcCmdSetLogicOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, logicOp: LogicOp) +ProcCmdSetPatchControlPointsEXT :: #type proc "system" (commandBuffer: CommandBuffer, patchControlPoints: u32) +ProcCmdSetPerformanceMarkerINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^PerformanceMarkerInfoINTEL) -> Result +ProcCmdSetPerformanceOverrideINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pOverrideInfo: ^PerformanceOverrideInfoINTEL) -> Result +ProcCmdSetPerformanceStreamMarkerINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^PerformanceStreamMarkerInfoINTEL) -> Result +ProcCmdSetPrimitiveRestartEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, primitiveRestartEnable: b32) +ProcCmdSetPrimitiveTopologyEXT :: #type proc "system" (commandBuffer: CommandBuffer, primitiveTopology: PrimitiveTopology) +ProcCmdSetRasterizerDiscardEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, rasterizerDiscardEnable: b32) +ProcCmdSetRayTracingPipelineStackSizeKHR :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStackSize: u32) +ProcCmdSetSampleLocationsEXT :: #type proc "system" (commandBuffer: CommandBuffer, pSampleLocationsInfo: ^SampleLocationsInfoEXT) +ProcCmdSetScissor :: #type proc "system" (commandBuffer: CommandBuffer, firstScissor: u32, scissorCount: u32, pScissors: [^]Rect2D) +ProcCmdSetScissorWithCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, scissorCount: u32, pScissors: [^]Rect2D) +ProcCmdSetStencilCompareMask :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, compareMask: u32) +ProcCmdSetStencilOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, failOp: StencilOp, passOp: StencilOp, depthFailOp: StencilOp, compareOp: CompareOp) +ProcCmdSetStencilReference :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, reference: u32) +ProcCmdSetStencilTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, stencilTestEnable: b32) +ProcCmdSetStencilWriteMask :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, writeMask: u32) +ProcCmdSetVertexInputEXT :: #type proc "system" (commandBuffer: CommandBuffer, vertexBindingDescriptionCount: u32, pVertexBindingDescriptions: [^]VertexInputBindingDescription2EXT, vertexAttributeDescriptionCount: u32, pVertexAttributeDescriptions: [^]VertexInputAttributeDescription2EXT) +ProcCmdSetViewport :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pViewports: [^]Viewport) +ProcCmdSetViewportShadingRatePaletteNV :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pShadingRatePalettes: [^]ShadingRatePaletteNV) +ProcCmdSetViewportWScalingNV :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pViewportWScalings: [^]ViewportWScalingNV) +ProcCmdSetViewportWithCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, viewportCount: u32, pViewports: [^]Viewport) +ProcCmdSubpassShadingHUAWEI :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdTraceRaysIndirectKHR :: #type proc "system" (commandBuffer: CommandBuffer, pRaygenShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pMissShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pHitShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pCallableShaderBindingTable: [^]StridedDeviceAddressRegionKHR, indirectDeviceAddress: DeviceAddress) +ProcCmdTraceRaysKHR :: #type proc "system" (commandBuffer: CommandBuffer, pRaygenShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pMissShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pHitShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pCallableShaderBindingTable: [^]StridedDeviceAddressRegionKHR, width: u32, height: u32, depth: u32) +ProcCmdTraceRaysNV :: #type proc "system" (commandBuffer: CommandBuffer, raygenShaderBindingTableBuffer: Buffer, raygenShaderBindingOffset: DeviceSize, missShaderBindingTableBuffer: Buffer, missShaderBindingOffset: DeviceSize, missShaderBindingStride: DeviceSize, hitShaderBindingTableBuffer: Buffer, hitShaderBindingOffset: DeviceSize, hitShaderBindingStride: DeviceSize, callableShaderBindingTableBuffer: Buffer, callableShaderBindingOffset: DeviceSize, callableShaderBindingStride: DeviceSize, width: u32, height: u32, depth: u32) +ProcCmdUpdateBuffer :: #type proc "system" (commandBuffer: CommandBuffer, dstBuffer: Buffer, dstOffset: DeviceSize, dataSize: DeviceSize, pData: rawptr) +ProcCmdWaitEvents :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, srcStageMask: PipelineStageFlags, dstStageMask: PipelineStageFlags, memoryBarrierCount: u32, pMemoryBarriers: [^]MemoryBarrier, bufferMemoryBarrierCount: u32, pBufferMemoryBarriers: [^]BufferMemoryBarrier, imageMemoryBarrierCount: u32, pImageMemoryBarriers: [^]ImageMemoryBarrier) +ProcCmdWaitEvents2KHR :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, pDependencyInfos: [^]DependencyInfoKHR) +ProcCmdWriteAccelerationStructuresPropertiesKHR :: #type proc "system" (commandBuffer: CommandBuffer, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureKHR, queryType: QueryType, queryPool: QueryPool, firstQuery: u32) +ProcCmdWriteAccelerationStructuresPropertiesNV :: #type proc "system" (commandBuffer: CommandBuffer, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureNV, queryType: QueryType, queryPool: QueryPool, firstQuery: u32) +ProcCmdWriteBufferMarker2AMD :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2KHR, dstBuffer: Buffer, dstOffset: DeviceSize, marker: u32) +ProcCmdWriteBufferMarkerAMD :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStage: PipelineStageFlags, dstBuffer: Buffer, dstOffset: DeviceSize, marker: u32) +ProcCmdWriteTimestamp :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStage: PipelineStageFlags, queryPool: QueryPool, query: u32) +ProcCmdWriteTimestamp2KHR :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2KHR, queryPool: QueryPool, query: u32) +ProcCompileDeferredNV :: #type proc "system" (device: Device, pipeline: Pipeline, shader: u32) -> Result +ProcCopyAccelerationStructureKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyAccelerationStructureInfoKHR) -> Result +ProcCopyAccelerationStructureToMemoryKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyAccelerationStructureToMemoryInfoKHR) -> Result +ProcCopyMemoryToAccelerationStructureKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyMemoryToAccelerationStructureInfoKHR) -> Result +ProcCreateAccelerationStructureKHR :: #type proc "system" (device: Device, pCreateInfo: ^AccelerationStructureCreateInfoKHR, pAllocator: ^AllocationCallbacks, pAccelerationStructure: ^AccelerationStructureKHR) -> Result +ProcCreateAccelerationStructureNV :: #type proc "system" (device: Device, pCreateInfo: ^AccelerationStructureCreateInfoNV, pAllocator: ^AllocationCallbacks, pAccelerationStructure: ^AccelerationStructureNV) -> Result +ProcCreateBuffer :: #type proc "system" (device: Device, pCreateInfo: ^BufferCreateInfo, pAllocator: ^AllocationCallbacks, pBuffer: ^Buffer) -> Result +ProcCreateBufferView :: #type proc "system" (device: Device, pCreateInfo: ^BufferViewCreateInfo, pAllocator: ^AllocationCallbacks, pView: ^BufferView) -> Result +ProcCreateCommandPool :: #type proc "system" (device: Device, pCreateInfo: ^CommandPoolCreateInfo, pAllocator: ^AllocationCallbacks, pCommandPool: ^CommandPool) -> Result +ProcCreateComputePipelines :: #type proc "system" (device: Device, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]ComputePipelineCreateInfo, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result +ProcCreateCuFunctionNVX :: #type proc "system" (device: Device, pCreateInfo: ^CuFunctionCreateInfoNVX, pAllocator: ^AllocationCallbacks, pFunction: ^CuFunctionNVX) -> Result +ProcCreateCuModuleNVX :: #type proc "system" (device: Device, pCreateInfo: ^CuModuleCreateInfoNVX, pAllocator: ^AllocationCallbacks, pModule: ^CuModuleNVX) -> Result +ProcCreateDeferredOperationKHR :: #type proc "system" (device: Device, pAllocator: ^AllocationCallbacks, pDeferredOperation: ^DeferredOperationKHR) -> Result +ProcCreateDescriptorPool :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorPoolCreateInfo, pAllocator: ^AllocationCallbacks, pDescriptorPool: ^DescriptorPool) -> Result +ProcCreateDescriptorSetLayout :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pAllocator: ^AllocationCallbacks, pSetLayout: ^DescriptorSetLayout) -> Result +ProcCreateDescriptorUpdateTemplate :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorUpdateTemplateCreateInfo, pAllocator: ^AllocationCallbacks, pDescriptorUpdateTemplate: ^DescriptorUpdateTemplate) -> Result +ProcCreateDescriptorUpdateTemplateKHR :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorUpdateTemplateCreateInfo, pAllocator: ^AllocationCallbacks, pDescriptorUpdateTemplate: ^DescriptorUpdateTemplate) -> Result +ProcCreateEvent :: #type proc "system" (device: Device, pCreateInfo: ^EventCreateInfo, pAllocator: ^AllocationCallbacks, pEvent: ^Event) -> Result +ProcCreateFence :: #type proc "system" (device: Device, pCreateInfo: ^FenceCreateInfo, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result +ProcCreateFramebuffer :: #type proc "system" (device: Device, pCreateInfo: ^FramebufferCreateInfo, pAllocator: ^AllocationCallbacks, pFramebuffer: ^Framebuffer) -> Result +ProcCreateGraphicsPipelines :: #type proc "system" (device: Device, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]GraphicsPipelineCreateInfo, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result +ProcCreateImage :: #type proc "system" (device: Device, pCreateInfo: ^ImageCreateInfo, pAllocator: ^AllocationCallbacks, pImage: ^Image) -> Result +ProcCreateImageView :: #type proc "system" (device: Device, pCreateInfo: ^ImageViewCreateInfo, pAllocator: ^AllocationCallbacks, pView: ^ImageView) -> Result +ProcCreateIndirectCommandsLayoutNV :: #type proc "system" (device: Device, pCreateInfo: ^IndirectCommandsLayoutCreateInfoNV, pAllocator: ^AllocationCallbacks, pIndirectCommandsLayout: ^IndirectCommandsLayoutNV) -> Result +ProcCreatePipelineCache :: #type proc "system" (device: Device, pCreateInfo: ^PipelineCacheCreateInfo, pAllocator: ^AllocationCallbacks, pPipelineCache: ^PipelineCache) -> Result +ProcCreatePipelineLayout :: #type proc "system" (device: Device, pCreateInfo: ^PipelineLayoutCreateInfo, pAllocator: ^AllocationCallbacks, pPipelineLayout: ^PipelineLayout) -> Result +ProcCreatePrivateDataSlotEXT :: #type proc "system" (device: Device, pCreateInfo: ^PrivateDataSlotCreateInfoEXT, pAllocator: ^AllocationCallbacks, pPrivateDataSlot: ^PrivateDataSlotEXT) -> Result +ProcCreateQueryPool :: #type proc "system" (device: Device, pCreateInfo: ^QueryPoolCreateInfo, pAllocator: ^AllocationCallbacks, pQueryPool: ^QueryPool) -> Result +ProcCreateRayTracingPipelinesKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]RayTracingPipelineCreateInfoKHR, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result +ProcCreateRayTracingPipelinesNV :: #type proc "system" (device: Device, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]RayTracingPipelineCreateInfoNV, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result +ProcCreateRenderPass :: #type proc "system" (device: Device, pCreateInfo: ^RenderPassCreateInfo, pAllocator: ^AllocationCallbacks, pRenderPass: [^]RenderPass) -> Result +ProcCreateRenderPass2 :: #type proc "system" (device: Device, pCreateInfo: ^RenderPassCreateInfo2, pAllocator: ^AllocationCallbacks, pRenderPass: [^]RenderPass) -> Result +ProcCreateRenderPass2KHR :: #type proc "system" (device: Device, pCreateInfo: ^RenderPassCreateInfo2, pAllocator: ^AllocationCallbacks, pRenderPass: [^]RenderPass) -> Result +ProcCreateSampler :: #type proc "system" (device: Device, pCreateInfo: ^SamplerCreateInfo, pAllocator: ^AllocationCallbacks, pSampler: ^Sampler) -> Result +ProcCreateSamplerYcbcrConversion :: #type proc "system" (device: Device, pCreateInfo: ^SamplerYcbcrConversionCreateInfo, pAllocator: ^AllocationCallbacks, pYcbcrConversion: ^SamplerYcbcrConversion) -> Result +ProcCreateSamplerYcbcrConversionKHR :: #type proc "system" (device: Device, pCreateInfo: ^SamplerYcbcrConversionCreateInfo, pAllocator: ^AllocationCallbacks, pYcbcrConversion: ^SamplerYcbcrConversion) -> Result +ProcCreateSemaphore :: #type proc "system" (device: Device, pCreateInfo: ^SemaphoreCreateInfo, pAllocator: ^AllocationCallbacks, pSemaphore: ^Semaphore) -> Result +ProcCreateShaderModule :: #type proc "system" (device: Device, pCreateInfo: ^ShaderModuleCreateInfo, pAllocator: ^AllocationCallbacks, pShaderModule: ^ShaderModule) -> Result +ProcCreateSharedSwapchainsKHR :: #type proc "system" (device: Device, swapchainCount: u32, pCreateInfos: [^]SwapchainCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSwapchains: [^]SwapchainKHR) -> Result +ProcCreateSwapchainKHR :: #type proc "system" (device: Device, pCreateInfo: ^SwapchainCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSwapchain: ^SwapchainKHR) -> Result +ProcCreateValidationCacheEXT :: #type proc "system" (device: Device, pCreateInfo: ^ValidationCacheCreateInfoEXT, pAllocator: ^AllocationCallbacks, pValidationCache: ^ValidationCacheEXT) -> Result +ProcDebugMarkerSetObjectNameEXT :: #type proc "system" (device: Device, pNameInfo: ^DebugMarkerObjectNameInfoEXT) -> Result +ProcDebugMarkerSetObjectTagEXT :: #type proc "system" (device: Device, pTagInfo: ^DebugMarkerObjectTagInfoEXT) -> Result +ProcDeferredOperationJoinKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> Result +ProcDestroyAccelerationStructureKHR :: #type proc "system" (device: Device, accelerationStructure: AccelerationStructureKHR, pAllocator: ^AllocationCallbacks) +ProcDestroyAccelerationStructureNV :: #type proc "system" (device: Device, accelerationStructure: AccelerationStructureNV, pAllocator: ^AllocationCallbacks) +ProcDestroyBuffer :: #type proc "system" (device: Device, buffer: Buffer, pAllocator: ^AllocationCallbacks) +ProcDestroyBufferView :: #type proc "system" (device: Device, bufferView: BufferView, pAllocator: ^AllocationCallbacks) +ProcDestroyCommandPool :: #type proc "system" (device: Device, commandPool: CommandPool, pAllocator: ^AllocationCallbacks) +ProcDestroyCuFunctionNVX :: #type proc "system" (device: Device, function: CuFunctionNVX, pAllocator: ^AllocationCallbacks) +ProcDestroyCuModuleNVX :: #type proc "system" (device: Device, module: CuModuleNVX, pAllocator: ^AllocationCallbacks) +ProcDestroyDeferredOperationKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR, pAllocator: ^AllocationCallbacks) +ProcDestroyDescriptorPool :: #type proc "system" (device: Device, descriptorPool: DescriptorPool, pAllocator: ^AllocationCallbacks) +ProcDestroyDescriptorSetLayout :: #type proc "system" (device: Device, descriptorSetLayout: DescriptorSetLayout, pAllocator: ^AllocationCallbacks) +ProcDestroyDescriptorUpdateTemplate :: #type proc "system" (device: Device, descriptorUpdateTemplate: DescriptorUpdateTemplate, pAllocator: ^AllocationCallbacks) +ProcDestroyDescriptorUpdateTemplateKHR :: #type proc "system" (device: Device, descriptorUpdateTemplate: DescriptorUpdateTemplate, pAllocator: ^AllocationCallbacks) +ProcDestroyDevice :: #type proc "system" (device: Device, pAllocator: ^AllocationCallbacks) +ProcDestroyEvent :: #type proc "system" (device: Device, event: Event, pAllocator: ^AllocationCallbacks) +ProcDestroyFence :: #type proc "system" (device: Device, fence: Fence, pAllocator: ^AllocationCallbacks) +ProcDestroyFramebuffer :: #type proc "system" (device: Device, framebuffer: Framebuffer, pAllocator: ^AllocationCallbacks) +ProcDestroyImage :: #type proc "system" (device: Device, image: Image, pAllocator: ^AllocationCallbacks) +ProcDestroyImageView :: #type proc "system" (device: Device, imageView: ImageView, pAllocator: ^AllocationCallbacks) +ProcDestroyIndirectCommandsLayoutNV :: #type proc "system" (device: Device, indirectCommandsLayout: IndirectCommandsLayoutNV, pAllocator: ^AllocationCallbacks) +ProcDestroyPipeline :: #type proc "system" (device: Device, pipeline: Pipeline, pAllocator: ^AllocationCallbacks) +ProcDestroyPipelineCache :: #type proc "system" (device: Device, pipelineCache: PipelineCache, pAllocator: ^AllocationCallbacks) +ProcDestroyPipelineLayout :: #type proc "system" (device: Device, pipelineLayout: PipelineLayout, pAllocator: ^AllocationCallbacks) +ProcDestroyPrivateDataSlotEXT :: #type proc "system" (device: Device, privateDataSlot: PrivateDataSlotEXT, pAllocator: ^AllocationCallbacks) +ProcDestroyQueryPool :: #type proc "system" (device: Device, queryPool: QueryPool, pAllocator: ^AllocationCallbacks) +ProcDestroyRenderPass :: #type proc "system" (device: Device, renderPass: RenderPass, pAllocator: ^AllocationCallbacks) +ProcDestroySampler :: #type proc "system" (device: Device, sampler: Sampler, pAllocator: ^AllocationCallbacks) +ProcDestroySamplerYcbcrConversion :: #type proc "system" (device: Device, ycbcrConversion: SamplerYcbcrConversion, pAllocator: ^AllocationCallbacks) +ProcDestroySamplerYcbcrConversionKHR :: #type proc "system" (device: Device, ycbcrConversion: SamplerYcbcrConversion, pAllocator: ^AllocationCallbacks) +ProcDestroySemaphore :: #type proc "system" (device: Device, semaphore: Semaphore, pAllocator: ^AllocationCallbacks) +ProcDestroyShaderModule :: #type proc "system" (device: Device, shaderModule: ShaderModule, pAllocator: ^AllocationCallbacks) +ProcDestroySwapchainKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pAllocator: ^AllocationCallbacks) +ProcDestroyValidationCacheEXT :: #type proc "system" (device: Device, validationCache: ValidationCacheEXT, pAllocator: ^AllocationCallbacks) +ProcDeviceWaitIdle :: #type proc "system" (device: Device) -> Result +ProcDisplayPowerControlEXT :: #type proc "system" (device: Device, display: DisplayKHR, pDisplayPowerInfo: ^DisplayPowerInfoEXT) -> Result +ProcEndCommandBuffer :: #type proc "system" (commandBuffer: CommandBuffer) -> Result +ProcFlushMappedMemoryRanges :: #type proc "system" (device: Device, memoryRangeCount: u32, pMemoryRanges: [^]MappedMemoryRange) -> Result +ProcFreeCommandBuffers :: #type proc "system" (device: Device, commandPool: CommandPool, commandBufferCount: u32, pCommandBuffers: [^]CommandBuffer) +ProcFreeDescriptorSets :: #type proc "system" (device: Device, descriptorPool: DescriptorPool, descriptorSetCount: u32, pDescriptorSets: [^]DescriptorSet) -> Result +ProcFreeMemory :: #type proc "system" (device: Device, memory: DeviceMemory, pAllocator: ^AllocationCallbacks) +ProcGetAccelerationStructureBuildSizesKHR :: #type proc "system" (device: Device, buildType: AccelerationStructureBuildTypeKHR, pBuildInfo: ^AccelerationStructureBuildGeometryInfoKHR, pMaxPrimitiveCounts: [^]u32, pSizeInfo: ^AccelerationStructureBuildSizesInfoKHR) +ProcGetAccelerationStructureDeviceAddressKHR :: #type proc "system" (device: Device, pInfo: ^AccelerationStructureDeviceAddressInfoKHR) -> DeviceAddress +ProcGetAccelerationStructureHandleNV :: #type proc "system" (device: Device, accelerationStructure: AccelerationStructureNV, dataSize: int, pData: rawptr) -> Result +ProcGetAccelerationStructureMemoryRequirementsNV :: #type proc "system" (device: Device, pInfo: ^AccelerationStructureMemoryRequirementsInfoNV, pMemoryRequirements: [^]MemoryRequirements2KHR) +ProcGetBufferDeviceAddress :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> DeviceAddress +ProcGetBufferDeviceAddressEXT :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> DeviceAddress +ProcGetBufferDeviceAddressKHR :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> DeviceAddress +ProcGetBufferMemoryRequirements :: #type proc "system" (device: Device, buffer: Buffer, pMemoryRequirements: [^]MemoryRequirements) +ProcGetBufferMemoryRequirements2 :: #type proc "system" (device: Device, pInfo: ^BufferMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetBufferMemoryRequirements2KHR :: #type proc "system" (device: Device, pInfo: ^BufferMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetBufferOpaqueCaptureAddress :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> u64 +ProcGetBufferOpaqueCaptureAddressKHR :: #type proc "system" (device: Device, pInfo: ^BufferDeviceAddressInfo) -> u64 +ProcGetCalibratedTimestampsEXT :: #type proc "system" (device: Device, timestampCount: u32, pTimestampInfos: [^]CalibratedTimestampInfoEXT, pTimestamps: [^]u64, pMaxDeviation: ^u64) -> Result +ProcGetDeferredOperationMaxConcurrencyKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> u32 +ProcGetDeferredOperationResultKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> Result +ProcGetDescriptorSetLayoutSupport :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pSupport: ^DescriptorSetLayoutSupport) +ProcGetDescriptorSetLayoutSupportKHR :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pSupport: ^DescriptorSetLayoutSupport) +ProcGetDeviceAccelerationStructureCompatibilityKHR :: #type proc "system" (device: Device, pVersionInfo: ^AccelerationStructureVersionInfoKHR, pCompatibility: ^AccelerationStructureCompatibilityKHR) +ProcGetDeviceGroupPeerMemoryFeatures :: #type proc "system" (device: Device, heapIndex: u32, localDeviceIndex: u32, remoteDeviceIndex: u32, pPeerMemoryFeatures: [^]PeerMemoryFeatureFlags) +ProcGetDeviceGroupPeerMemoryFeaturesKHR :: #type proc "system" (device: Device, heapIndex: u32, localDeviceIndex: u32, remoteDeviceIndex: u32, pPeerMemoryFeatures: [^]PeerMemoryFeatureFlags) +ProcGetDeviceGroupPresentCapabilitiesKHR :: #type proc "system" (device: Device, pDeviceGroupPresentCapabilities: [^]DeviceGroupPresentCapabilitiesKHR) -> Result +ProcGetDeviceGroupSurfacePresentModes2EXT :: #type proc "system" (device: Device, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pModes: [^]DeviceGroupPresentModeFlagsKHR) -> Result +ProcGetDeviceGroupSurfacePresentModesKHR :: #type proc "system" (device: Device, surface: SurfaceKHR, pModes: [^]DeviceGroupPresentModeFlagsKHR) -> Result +ProcGetDeviceMemoryCommitment :: #type proc "system" (device: Device, memory: DeviceMemory, pCommittedMemoryInBytes: [^]DeviceSize) +ProcGetDeviceMemoryOpaqueCaptureAddress :: #type proc "system" (device: Device, pInfo: ^DeviceMemoryOpaqueCaptureAddressInfo) -> u64 +ProcGetDeviceMemoryOpaqueCaptureAddressKHR :: #type proc "system" (device: Device, pInfo: ^DeviceMemoryOpaqueCaptureAddressInfo) -> u64 +ProcGetDeviceProcAddr :: #type proc "system" (device: Device, pName: cstring) -> ProcVoidFunction +ProcGetDeviceQueue :: #type proc "system" (device: Device, queueFamilyIndex: u32, queueIndex: u32, pQueue: ^Queue) +ProcGetDeviceQueue2 :: #type proc "system" (device: Device, pQueueInfo: ^DeviceQueueInfo2, pQueue: ^Queue) +ProcGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI :: #type proc "system" (device: Device, renderpass: RenderPass, pMaxWorkgroupSize: ^Extent2D) -> Result +ProcGetEventStatus :: #type proc "system" (device: Device, event: Event) -> Result +ProcGetFenceFdKHR :: #type proc "system" (device: Device, pGetFdInfo: ^FenceGetFdInfoKHR, pFd: ^c.int) -> Result +ProcGetFenceStatus :: #type proc "system" (device: Device, fence: Fence) -> Result +ProcGetFenceWin32HandleKHR :: #type proc "system" (device: Device, pGetWin32HandleInfo: ^FenceGetWin32HandleInfoKHR, pHandle: ^HANDLE) -> Result +ProcGetGeneratedCommandsMemoryRequirementsNV :: #type proc "system" (device: Device, pInfo: ^GeneratedCommandsMemoryRequirementsInfoNV, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetImageDrmFormatModifierPropertiesEXT :: #type proc "system" (device: Device, image: Image, pProperties: [^]ImageDrmFormatModifierPropertiesEXT) -> Result +ProcGetImageMemoryRequirements :: #type proc "system" (device: Device, image: Image, pMemoryRequirements: [^]MemoryRequirements) +ProcGetImageMemoryRequirements2 :: #type proc "system" (device: Device, pInfo: ^ImageMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetImageMemoryRequirements2KHR :: #type proc "system" (device: Device, pInfo: ^ImageMemoryRequirementsInfo2, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetImageSparseMemoryRequirements :: #type proc "system" (device: Device, image: Image, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements) +ProcGetImageSparseMemoryRequirements2 :: #type proc "system" (device: Device, pInfo: ^ImageSparseMemoryRequirementsInfo2, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements2) +ProcGetImageSparseMemoryRequirements2KHR :: #type proc "system" (device: Device, pInfo: ^ImageSparseMemoryRequirementsInfo2, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements2) +ProcGetImageSubresourceLayout :: #type proc "system" (device: Device, image: Image, pSubresource: ^ImageSubresource, pLayout: ^SubresourceLayout) +ProcGetImageViewAddressNVX :: #type proc "system" (device: Device, imageView: ImageView, pProperties: [^]ImageViewAddressPropertiesNVX) -> Result +ProcGetImageViewHandleNVX :: #type proc "system" (device: Device, pInfo: ^ImageViewHandleInfoNVX) -> u32 +ProcGetMemoryFdKHR :: #type proc "system" (device: Device, pGetFdInfo: ^MemoryGetFdInfoKHR, pFd: ^c.int) -> Result +ProcGetMemoryFdPropertiesKHR :: #type proc "system" (device: Device, handleType: ExternalMemoryHandleTypeFlags, fd: c.int, pMemoryFdProperties: [^]MemoryFdPropertiesKHR) -> Result +ProcGetMemoryHostPointerPropertiesEXT :: #type proc "system" (device: Device, handleType: ExternalMemoryHandleTypeFlags, pHostPointer: rawptr, pMemoryHostPointerProperties: [^]MemoryHostPointerPropertiesEXT) -> Result +ProcGetMemoryRemoteAddressNV :: #type proc "system" (device: Device, pMemoryGetRemoteAddressInfo: ^MemoryGetRemoteAddressInfoNV, pAddress: [^]RemoteAddressNV) -> Result +ProcGetMemoryWin32HandleKHR :: #type proc "system" (device: Device, pGetWin32HandleInfo: ^MemoryGetWin32HandleInfoKHR, pHandle: ^HANDLE) -> Result +ProcGetMemoryWin32HandleNV :: #type proc "system" (device: Device, memory: DeviceMemory, handleType: ExternalMemoryHandleTypeFlagsNV, pHandle: ^HANDLE) -> Result +ProcGetMemoryWin32HandlePropertiesKHR :: #type proc "system" (device: Device, handleType: ExternalMemoryHandleTypeFlags, handle: HANDLE, pMemoryWin32HandleProperties: [^]MemoryWin32HandlePropertiesKHR) -> Result +ProcGetPastPresentationTimingGOOGLE :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pPresentationTimingCount: ^u32, pPresentationTimings: [^]PastPresentationTimingGOOGLE) -> Result +ProcGetPerformanceParameterINTEL :: #type proc "system" (device: Device, parameter: PerformanceParameterTypeINTEL, pValue: ^PerformanceValueINTEL) -> Result +ProcGetPipelineCacheData :: #type proc "system" (device: Device, pipelineCache: PipelineCache, pDataSize: ^int, pData: rawptr) -> Result +ProcGetPipelineExecutableInternalRepresentationsKHR :: #type proc "system" (device: Device, pExecutableInfo: ^PipelineExecutableInfoKHR, pInternalRepresentationCount: ^u32, pInternalRepresentations: [^]PipelineExecutableInternalRepresentationKHR) -> Result +ProcGetPipelineExecutablePropertiesKHR :: #type proc "system" (device: Device, pPipelineInfo: ^PipelineInfoKHR, pExecutableCount: ^u32, pProperties: [^]PipelineExecutablePropertiesKHR) -> Result +ProcGetPipelineExecutableStatisticsKHR :: #type proc "system" (device: Device, pExecutableInfo: ^PipelineExecutableInfoKHR, pStatisticCount: ^u32, pStatistics: [^]PipelineExecutableStatisticKHR) -> Result +ProcGetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlotEXT, pData: ^u64) +ProcGetQueryPoolResults :: #type proc "system" (device: Device, queryPool: QueryPool, firstQuery: u32, queryCount: u32, dataSize: int, pData: rawptr, stride: DeviceSize, flags: QueryResultFlags) -> Result +ProcGetQueueCheckpointData2NV :: #type proc "system" (queue: Queue, pCheckpointDataCount: ^u32, pCheckpointData: ^CheckpointData2NV) +ProcGetQueueCheckpointDataNV :: #type proc "system" (queue: Queue, pCheckpointDataCount: ^u32, pCheckpointData: ^CheckpointDataNV) +ProcGetRayTracingCaptureReplayShaderGroupHandlesKHR :: #type proc "system" (device: Device, pipeline: Pipeline, firstGroup: u32, groupCount: u32, dataSize: int, pData: rawptr) -> Result +ProcGetRayTracingShaderGroupHandlesKHR :: #type proc "system" (device: Device, pipeline: Pipeline, firstGroup: u32, groupCount: u32, dataSize: int, pData: rawptr) -> Result +ProcGetRayTracingShaderGroupHandlesNV :: #type proc "system" (device: Device, pipeline: Pipeline, firstGroup: u32, groupCount: u32, dataSize: int, pData: rawptr) -> Result +ProcGetRayTracingShaderGroupStackSizeKHR :: #type proc "system" (device: Device, pipeline: Pipeline, group: u32, groupShader: ShaderGroupShaderKHR) -> DeviceSize +ProcGetRefreshCycleDurationGOOGLE :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pDisplayTimingProperties: [^]RefreshCycleDurationGOOGLE) -> Result +ProcGetRenderAreaGranularity :: #type proc "system" (device: Device, renderPass: RenderPass, pGranularity: ^Extent2D) +ProcGetSemaphoreCounterValue :: #type proc "system" (device: Device, semaphore: Semaphore, pValue: ^u64) -> Result +ProcGetSemaphoreCounterValueKHR :: #type proc "system" (device: Device, semaphore: Semaphore, pValue: ^u64) -> Result +ProcGetSemaphoreFdKHR :: #type proc "system" (device: Device, pGetFdInfo: ^SemaphoreGetFdInfoKHR, pFd: ^c.int) -> Result +ProcGetSemaphoreWin32HandleKHR :: #type proc "system" (device: Device, pGetWin32HandleInfo: ^SemaphoreGetWin32HandleInfoKHR, pHandle: ^HANDLE) -> Result +ProcGetShaderInfoAMD :: #type proc "system" (device: Device, pipeline: Pipeline, shaderStage: ShaderStageFlags, infoType: ShaderInfoTypeAMD, pInfoSize: ^int, pInfo: rawptr) -> Result +ProcGetSwapchainCounterEXT :: #type proc "system" (device: Device, swapchain: SwapchainKHR, counter: SurfaceCounterFlagsEXT, pCounterValue: ^u64) -> Result +ProcGetSwapchainImagesKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, pSwapchainImageCount: ^u32, pSwapchainImages: [^]Image) -> Result +ProcGetSwapchainStatusKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR) -> Result +ProcGetValidationCacheDataEXT :: #type proc "system" (device: Device, validationCache: ValidationCacheEXT, pDataSize: ^int, pData: rawptr) -> Result +ProcImportFenceFdKHR :: #type proc "system" (device: Device, pImportFenceFdInfo: ^ImportFenceFdInfoKHR) -> Result +ProcImportFenceWin32HandleKHR :: #type proc "system" (device: Device, pImportFenceWin32HandleInfo: ^ImportFenceWin32HandleInfoKHR) -> Result +ProcImportSemaphoreFdKHR :: #type proc "system" (device: Device, pImportSemaphoreFdInfo: ^ImportSemaphoreFdInfoKHR) -> Result +ProcImportSemaphoreWin32HandleKHR :: #type proc "system" (device: Device, pImportSemaphoreWin32HandleInfo: ^ImportSemaphoreWin32HandleInfoKHR) -> Result +ProcInitializePerformanceApiINTEL :: #type proc "system" (device: Device, pInitializeInfo: ^InitializePerformanceApiInfoINTEL) -> Result +ProcInvalidateMappedMemoryRanges :: #type proc "system" (device: Device, memoryRangeCount: u32, pMemoryRanges: [^]MappedMemoryRange) -> Result +ProcMapMemory :: #type proc "system" (device: Device, memory: DeviceMemory, offset: DeviceSize, size: DeviceSize, flags: MemoryMapFlags, ppData: ^rawptr) -> Result +ProcMergePipelineCaches :: #type proc "system" (device: Device, dstCache: PipelineCache, srcCacheCount: u32, pSrcCaches: [^]PipelineCache) -> Result +ProcMergeValidationCachesEXT :: #type proc "system" (device: Device, dstCache: ValidationCacheEXT, srcCacheCount: u32, pSrcCaches: [^]ValidationCacheEXT) -> Result +ProcQueueBeginDebugUtilsLabelEXT :: #type proc "system" (queue: Queue, pLabelInfo: ^DebugUtilsLabelEXT) +ProcQueueBindSparse :: #type proc "system" (queue: Queue, bindInfoCount: u32, pBindInfo: ^BindSparseInfo, fence: Fence) -> Result +ProcQueueEndDebugUtilsLabelEXT :: #type proc "system" (queue: Queue) +ProcQueueInsertDebugUtilsLabelEXT :: #type proc "system" (queue: Queue, pLabelInfo: ^DebugUtilsLabelEXT) +ProcQueuePresentKHR :: #type proc "system" (queue: Queue, pPresentInfo: ^PresentInfoKHR) -> Result +ProcQueueSetPerformanceConfigurationINTEL :: #type proc "system" (queue: Queue, configuration: PerformanceConfigurationINTEL) -> Result +ProcQueueSubmit :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo, fence: Fence) -> Result +ProcQueueSubmit2KHR :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo2KHR, fence: Fence) -> Result +ProcQueueWaitIdle :: #type proc "system" (queue: Queue) -> Result +ProcRegisterDeviceEventEXT :: #type proc "system" (device: Device, pDeviceEventInfo: ^DeviceEventInfoEXT, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result +ProcRegisterDisplayEventEXT :: #type proc "system" (device: Device, display: DisplayKHR, pDisplayEventInfo: ^DisplayEventInfoEXT, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result +ProcReleaseFullScreenExclusiveModeEXT :: #type proc "system" (device: Device, swapchain: SwapchainKHR) -> Result +ProcReleasePerformanceConfigurationINTEL :: #type proc "system" (device: Device, configuration: PerformanceConfigurationINTEL) -> Result +ProcReleaseProfilingLockKHR :: #type proc "system" (device: Device) +ProcResetCommandBuffer :: #type proc "system" (commandBuffer: CommandBuffer, flags: CommandBufferResetFlags) -> Result +ProcResetCommandPool :: #type proc "system" (device: Device, commandPool: CommandPool, flags: CommandPoolResetFlags) -> Result +ProcResetDescriptorPool :: #type proc "system" (device: Device, descriptorPool: DescriptorPool, flags: DescriptorPoolResetFlags) -> Result +ProcResetEvent :: #type proc "system" (device: Device, event: Event) -> Result +ProcResetFences :: #type proc "system" (device: Device, fenceCount: u32, pFences: [^]Fence) -> Result +ProcResetQueryPool :: #type proc "system" (device: Device, queryPool: QueryPool, firstQuery: u32, queryCount: u32) +ProcResetQueryPoolEXT :: #type proc "system" (device: Device, queryPool: QueryPool, firstQuery: u32, queryCount: u32) +ProcSetDebugUtilsObjectNameEXT :: #type proc "system" (device: Device, pNameInfo: ^DebugUtilsObjectNameInfoEXT) -> Result +ProcSetDebugUtilsObjectTagEXT :: #type proc "system" (device: Device, pTagInfo: ^DebugUtilsObjectTagInfoEXT) -> Result +ProcSetDeviceMemoryPriorityEXT :: #type proc "system" (device: Device, memory: DeviceMemory, priority: f32) +ProcSetEvent :: #type proc "system" (device: Device, event: Event) -> Result +ProcSetHdrMetadataEXT :: #type proc "system" (device: Device, swapchainCount: u32, pSwapchains: [^]SwapchainKHR, pMetadata: ^HdrMetadataEXT) +ProcSetLocalDimmingAMD :: #type proc "system" (device: Device, swapChain: SwapchainKHR, localDimmingEnable: b32) +ProcSetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlotEXT, data: u64) -> Result +ProcSignalSemaphore :: #type proc "system" (device: Device, pSignalInfo: ^SemaphoreSignalInfo) -> Result +ProcSignalSemaphoreKHR :: #type proc "system" (device: Device, pSignalInfo: ^SemaphoreSignalInfo) -> Result +ProcTrimCommandPool :: #type proc "system" (device: Device, commandPool: CommandPool, flags: CommandPoolTrimFlags) +ProcTrimCommandPoolKHR :: #type proc "system" (device: Device, commandPool: CommandPool, flags: CommandPoolTrimFlags) +ProcUninitializePerformanceApiINTEL :: #type proc "system" (device: Device) +ProcUnmapMemory :: #type proc "system" (device: Device, memory: DeviceMemory) +ProcUpdateDescriptorSetWithTemplate :: #type proc "system" (device: Device, descriptorSet: DescriptorSet, descriptorUpdateTemplate: DescriptorUpdateTemplate, pData: rawptr) +ProcUpdateDescriptorSetWithTemplateKHR :: #type proc "system" (device: Device, descriptorSet: DescriptorSet, descriptorUpdateTemplate: DescriptorUpdateTemplate, pData: rawptr) +ProcUpdateDescriptorSets :: #type proc "system" (device: Device, descriptorWriteCount: u32, pDescriptorWrites: [^]WriteDescriptorSet, descriptorCopyCount: u32, pDescriptorCopies: [^]CopyDescriptorSet) +ProcWaitForFences :: #type proc "system" (device: Device, fenceCount: u32, pFences: [^]Fence, waitAll: b32, timeout: u64) -> Result +ProcWaitForPresentKHR :: #type proc "system" (device: Device, swapchain: SwapchainKHR, presentId: u64, timeout: u64) -> Result +ProcWaitSemaphores :: #type proc "system" (device: Device, pWaitInfo: ^SemaphoreWaitInfo, timeout: u64) -> Result +ProcWaitSemaphoresKHR :: #type proc "system" (device: Device, pWaitInfo: ^SemaphoreWaitInfo, timeout: u64) -> Result +ProcWriteAccelerationStructuresPropertiesKHR :: #type proc "system" (device: Device, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureKHR, queryType: QueryType, dataSize: int, pData: rawptr, stride: int) -> Result -// Device Procedures -GetDeviceProcAddr: ProcGetDeviceProcAddr -DestroyDevice: ProcDestroyDevice -GetDeviceQueue: ProcGetDeviceQueue -QueueSubmit: ProcQueueSubmit -QueueWaitIdle: ProcQueueWaitIdle -DeviceWaitIdle: ProcDeviceWaitIdle -AllocateMemory: ProcAllocateMemory -FreeMemory: ProcFreeMemory -MapMemory: ProcMapMemory -UnmapMemory: ProcUnmapMemory -FlushMappedMemoryRanges: ProcFlushMappedMemoryRanges -InvalidateMappedMemoryRanges: ProcInvalidateMappedMemoryRanges -GetDeviceMemoryCommitment: ProcGetDeviceMemoryCommitment -BindBufferMemory: ProcBindBufferMemory -BindImageMemory: ProcBindImageMemory -GetBufferMemoryRequirements: ProcGetBufferMemoryRequirements -GetImageMemoryRequirements: ProcGetImageMemoryRequirements -GetImageSparseMemoryRequirements: ProcGetImageSparseMemoryRequirements -QueueBindSparse: ProcQueueBindSparse -CreateFence: ProcCreateFence -DestroyFence: ProcDestroyFence -ResetFences: ProcResetFences -GetFenceStatus: ProcGetFenceStatus -WaitForFences: ProcWaitForFences -CreateSemaphore: ProcCreateSemaphore -DestroySemaphore: ProcDestroySemaphore -CreateEvent: ProcCreateEvent -DestroyEvent: ProcDestroyEvent -GetEventStatus: ProcGetEventStatus -SetEvent: ProcSetEvent -ResetEvent: ProcResetEvent -CreateQueryPool: ProcCreateQueryPool -DestroyQueryPool: ProcDestroyQueryPool -GetQueryPoolResults: ProcGetQueryPoolResults -CreateBuffer: ProcCreateBuffer -DestroyBuffer: ProcDestroyBuffer -CreateBufferView: ProcCreateBufferView -DestroyBufferView: ProcDestroyBufferView -CreateImage: ProcCreateImage -DestroyImage: ProcDestroyImage -GetImageSubresourceLayout: ProcGetImageSubresourceLayout -CreateImageView: ProcCreateImageView -DestroyImageView: ProcDestroyImageView -CreateShaderModule: ProcCreateShaderModule -DestroyShaderModule: ProcDestroyShaderModule -CreatePipelineCache: ProcCreatePipelineCache -DestroyPipelineCache: ProcDestroyPipelineCache -GetPipelineCacheData: ProcGetPipelineCacheData -MergePipelineCaches: ProcMergePipelineCaches -CreateGraphicsPipelines: ProcCreateGraphicsPipelines -CreateComputePipelines: ProcCreateComputePipelines -DestroyPipeline: ProcDestroyPipeline -CreatePipelineLayout: ProcCreatePipelineLayout -DestroyPipelineLayout: ProcDestroyPipelineLayout -CreateSampler: ProcCreateSampler -DestroySampler: ProcDestroySampler -CreateDescriptorSetLayout: ProcCreateDescriptorSetLayout -DestroyDescriptorSetLayout: ProcDestroyDescriptorSetLayout -CreateDescriptorPool: ProcCreateDescriptorPool -DestroyDescriptorPool: ProcDestroyDescriptorPool -ResetDescriptorPool: ProcResetDescriptorPool -AllocateDescriptorSets: ProcAllocateDescriptorSets -FreeDescriptorSets: ProcFreeDescriptorSets -UpdateDescriptorSets: ProcUpdateDescriptorSets -CreateFramebuffer: ProcCreateFramebuffer -DestroyFramebuffer: ProcDestroyFramebuffer -CreateRenderPass: ProcCreateRenderPass -DestroyRenderPass: ProcDestroyRenderPass -GetRenderAreaGranularity: ProcGetRenderAreaGranularity -CreateCommandPool: ProcCreateCommandPool -DestroyCommandPool: ProcDestroyCommandPool -ResetCommandPool: ProcResetCommandPool -AllocateCommandBuffers: ProcAllocateCommandBuffers -FreeCommandBuffers: ProcFreeCommandBuffers -BeginCommandBuffer: ProcBeginCommandBuffer -EndCommandBuffer: ProcEndCommandBuffer -ResetCommandBuffer: ProcResetCommandBuffer -CmdBindPipeline: ProcCmdBindPipeline -CmdSetViewport: ProcCmdSetViewport -CmdSetScissor: ProcCmdSetScissor -CmdSetLineWidth: ProcCmdSetLineWidth -CmdSetDepthBias: ProcCmdSetDepthBias -CmdSetBlendConstants: ProcCmdSetBlendConstants -CmdSetDepthBounds: ProcCmdSetDepthBounds -CmdSetStencilCompareMask: ProcCmdSetStencilCompareMask -CmdSetStencilWriteMask: ProcCmdSetStencilWriteMask -CmdSetStencilReference: ProcCmdSetStencilReference -CmdBindDescriptorSets: ProcCmdBindDescriptorSets -CmdBindIndexBuffer: ProcCmdBindIndexBuffer -CmdBindVertexBuffers: ProcCmdBindVertexBuffers -CmdDraw: ProcCmdDraw -CmdDrawIndexed: ProcCmdDrawIndexed -CmdDrawIndirect: ProcCmdDrawIndirect -CmdDrawIndexedIndirect: ProcCmdDrawIndexedIndirect -CmdDispatch: ProcCmdDispatch -CmdDispatchIndirect: ProcCmdDispatchIndirect -CmdCopyBuffer: ProcCmdCopyBuffer -CmdCopyImage: ProcCmdCopyImage -CmdBlitImage: ProcCmdBlitImage -CmdCopyBufferToImage: ProcCmdCopyBufferToImage -CmdCopyImageToBuffer: ProcCmdCopyImageToBuffer -CmdUpdateBuffer: ProcCmdUpdateBuffer -CmdFillBuffer: ProcCmdFillBuffer -CmdClearColorImage: ProcCmdClearColorImage -CmdClearDepthStencilImage: ProcCmdClearDepthStencilImage -CmdClearAttachments: ProcCmdClearAttachments -CmdResolveImage: ProcCmdResolveImage -CmdSetEvent: ProcCmdSetEvent -CmdResetEvent: ProcCmdResetEvent -CmdWaitEvents: ProcCmdWaitEvents -CmdPipelineBarrier: ProcCmdPipelineBarrier -CmdBeginQuery: ProcCmdBeginQuery -CmdEndQuery: ProcCmdEndQuery -CmdResetQueryPool: ProcCmdResetQueryPool -CmdWriteTimestamp: ProcCmdWriteTimestamp -CmdCopyQueryPoolResults: ProcCmdCopyQueryPoolResults -CmdPushConstants: ProcCmdPushConstants -CmdBeginRenderPass: ProcCmdBeginRenderPass -CmdNextSubpass: ProcCmdNextSubpass -CmdEndRenderPass: ProcCmdEndRenderPass -CmdExecuteCommands: ProcCmdExecuteCommands -BindBufferMemory2: ProcBindBufferMemory2 -BindImageMemory2: ProcBindImageMemory2 -GetDeviceGroupPeerMemoryFeatures: ProcGetDeviceGroupPeerMemoryFeatures -CmdSetDeviceMask: ProcCmdSetDeviceMask -CmdDispatchBase: ProcCmdDispatchBase -GetImageMemoryRequirements2: ProcGetImageMemoryRequirements2 -GetBufferMemoryRequirements2: ProcGetBufferMemoryRequirements2 -GetImageSparseMemoryRequirements2: ProcGetImageSparseMemoryRequirements2 -TrimCommandPool: ProcTrimCommandPool -GetDeviceQueue2: ProcGetDeviceQueue2 -CreateSamplerYcbcrConversion: ProcCreateSamplerYcbcrConversion -DestroySamplerYcbcrConversion: ProcDestroySamplerYcbcrConversion -CreateDescriptorUpdateTemplate: ProcCreateDescriptorUpdateTemplate -DestroyDescriptorUpdateTemplate: ProcDestroyDescriptorUpdateTemplate -UpdateDescriptorSetWithTemplate: ProcUpdateDescriptorSetWithTemplate -GetDescriptorSetLayoutSupport: ProcGetDescriptorSetLayoutSupport -CmdDrawIndirectCount: ProcCmdDrawIndirectCount -CmdDrawIndexedIndirectCount: ProcCmdDrawIndexedIndirectCount -CreateRenderPass2: ProcCreateRenderPass2 -CmdBeginRenderPass2: ProcCmdBeginRenderPass2 -CmdNextSubpass2: ProcCmdNextSubpass2 -CmdEndRenderPass2: ProcCmdEndRenderPass2 -ResetQueryPool: ProcResetQueryPool -GetSemaphoreCounterValue: ProcGetSemaphoreCounterValue -WaitSemaphores: ProcWaitSemaphores -SignalSemaphore: ProcSignalSemaphore -GetBufferDeviceAddress: ProcGetBufferDeviceAddress -GetBufferOpaqueCaptureAddress: ProcGetBufferOpaqueCaptureAddress -GetDeviceMemoryOpaqueCaptureAddress: ProcGetDeviceMemoryOpaqueCaptureAddress -CreateSwapchainKHR: ProcCreateSwapchainKHR -DestroySwapchainKHR: ProcDestroySwapchainKHR -GetSwapchainImagesKHR: ProcGetSwapchainImagesKHR -AcquireNextImageKHR: ProcAcquireNextImageKHR -QueuePresentKHR: ProcQueuePresentKHR -GetDeviceGroupPresentCapabilitiesKHR: ProcGetDeviceGroupPresentCapabilitiesKHR -GetDeviceGroupSurfacePresentModesKHR: ProcGetDeviceGroupSurfacePresentModesKHR -AcquireNextImage2KHR: ProcAcquireNextImage2KHR -CreateSharedSwapchainsKHR: ProcCreateSharedSwapchainsKHR -GetDeviceGroupPeerMemoryFeaturesKHR: ProcGetDeviceGroupPeerMemoryFeaturesKHR -CmdSetDeviceMaskKHR: ProcCmdSetDeviceMaskKHR -CmdDispatchBaseKHR: ProcCmdDispatchBaseKHR -TrimCommandPoolKHR: ProcTrimCommandPoolKHR -GetMemoryFdKHR: ProcGetMemoryFdKHR -GetMemoryFdPropertiesKHR: ProcGetMemoryFdPropertiesKHR -ImportSemaphoreFdKHR: ProcImportSemaphoreFdKHR -GetSemaphoreFdKHR: ProcGetSemaphoreFdKHR -CmdPushDescriptorSetKHR: ProcCmdPushDescriptorSetKHR -CmdPushDescriptorSetWithTemplateKHR: ProcCmdPushDescriptorSetWithTemplateKHR -CreateDescriptorUpdateTemplateKHR: ProcCreateDescriptorUpdateTemplateKHR -DestroyDescriptorUpdateTemplateKHR: ProcDestroyDescriptorUpdateTemplateKHR -UpdateDescriptorSetWithTemplateKHR: ProcUpdateDescriptorSetWithTemplateKHR -CreateRenderPass2KHR: ProcCreateRenderPass2KHR -CmdBeginRenderPass2KHR: ProcCmdBeginRenderPass2KHR -CmdNextSubpass2KHR: ProcCmdNextSubpass2KHR -CmdEndRenderPass2KHR: ProcCmdEndRenderPass2KHR -GetSwapchainStatusKHR: ProcGetSwapchainStatusKHR -ImportFenceFdKHR: ProcImportFenceFdKHR -GetFenceFdKHR: ProcGetFenceFdKHR -AcquireProfilingLockKHR: ProcAcquireProfilingLockKHR -ReleaseProfilingLockKHR: ProcReleaseProfilingLockKHR -GetImageMemoryRequirements2KHR: ProcGetImageMemoryRequirements2KHR -GetBufferMemoryRequirements2KHR: ProcGetBufferMemoryRequirements2KHR -GetImageSparseMemoryRequirements2KHR: ProcGetImageSparseMemoryRequirements2KHR -CreateSamplerYcbcrConversionKHR: ProcCreateSamplerYcbcrConversionKHR -DestroySamplerYcbcrConversionKHR: ProcDestroySamplerYcbcrConversionKHR -BindBufferMemory2KHR: ProcBindBufferMemory2KHR -BindImageMemory2KHR: ProcBindImageMemory2KHR -GetDescriptorSetLayoutSupportKHR: ProcGetDescriptorSetLayoutSupportKHR -CmdDrawIndirectCountKHR: ProcCmdDrawIndirectCountKHR -CmdDrawIndexedIndirectCountKHR: ProcCmdDrawIndexedIndirectCountKHR -GetSemaphoreCounterValueKHR: ProcGetSemaphoreCounterValueKHR -WaitSemaphoresKHR: ProcWaitSemaphoresKHR -SignalSemaphoreKHR: ProcSignalSemaphoreKHR -CmdSetFragmentShadingRateKHR: ProcCmdSetFragmentShadingRateKHR -WaitForPresentKHR: ProcWaitForPresentKHR -GetBufferDeviceAddressKHR: ProcGetBufferDeviceAddressKHR -GetBufferOpaqueCaptureAddressKHR: ProcGetBufferOpaqueCaptureAddressKHR -GetDeviceMemoryOpaqueCaptureAddressKHR: ProcGetDeviceMemoryOpaqueCaptureAddressKHR -CreateDeferredOperationKHR: ProcCreateDeferredOperationKHR -DestroyDeferredOperationKHR: ProcDestroyDeferredOperationKHR -GetDeferredOperationMaxConcurrencyKHR: ProcGetDeferredOperationMaxConcurrencyKHR -GetDeferredOperationResultKHR: ProcGetDeferredOperationResultKHR -DeferredOperationJoinKHR: ProcDeferredOperationJoinKHR -GetPipelineExecutablePropertiesKHR: ProcGetPipelineExecutablePropertiesKHR -GetPipelineExecutableStatisticsKHR: ProcGetPipelineExecutableStatisticsKHR -GetPipelineExecutableInternalRepresentationsKHR: ProcGetPipelineExecutableInternalRepresentationsKHR -CmdSetEvent2KHR: ProcCmdSetEvent2KHR -CmdResetEvent2KHR: ProcCmdResetEvent2KHR -CmdWaitEvents2KHR: ProcCmdWaitEvents2KHR -CmdPipelineBarrier2KHR: ProcCmdPipelineBarrier2KHR -CmdWriteTimestamp2KHR: ProcCmdWriteTimestamp2KHR -QueueSubmit2KHR: ProcQueueSubmit2KHR -CmdWriteBufferMarker2AMD: ProcCmdWriteBufferMarker2AMD -GetQueueCheckpointData2NV: ProcGetQueueCheckpointData2NV -CmdCopyBuffer2KHR: ProcCmdCopyBuffer2KHR -CmdCopyImage2KHR: ProcCmdCopyImage2KHR -CmdCopyBufferToImage2KHR: ProcCmdCopyBufferToImage2KHR -CmdCopyImageToBuffer2KHR: ProcCmdCopyImageToBuffer2KHR -CmdBlitImage2KHR: ProcCmdBlitImage2KHR -CmdResolveImage2KHR: ProcCmdResolveImage2KHR -DebugMarkerSetObjectTagEXT: ProcDebugMarkerSetObjectTagEXT -DebugMarkerSetObjectNameEXT: ProcDebugMarkerSetObjectNameEXT -CmdDebugMarkerBeginEXT: ProcCmdDebugMarkerBeginEXT -CmdDebugMarkerEndEXT: ProcCmdDebugMarkerEndEXT -CmdDebugMarkerInsertEXT: ProcCmdDebugMarkerInsertEXT -CmdBindTransformFeedbackBuffersEXT: ProcCmdBindTransformFeedbackBuffersEXT -CmdBeginTransformFeedbackEXT: ProcCmdBeginTransformFeedbackEXT -CmdEndTransformFeedbackEXT: ProcCmdEndTransformFeedbackEXT -CmdBeginQueryIndexedEXT: ProcCmdBeginQueryIndexedEXT -CmdEndQueryIndexedEXT: ProcCmdEndQueryIndexedEXT -CmdDrawIndirectByteCountEXT: ProcCmdDrawIndirectByteCountEXT -CreateCuModuleNVX: ProcCreateCuModuleNVX -CreateCuFunctionNVX: ProcCreateCuFunctionNVX -DestroyCuModuleNVX: ProcDestroyCuModuleNVX -DestroyCuFunctionNVX: ProcDestroyCuFunctionNVX -CmdCuLaunchKernelNVX: ProcCmdCuLaunchKernelNVX -GetImageViewHandleNVX: ProcGetImageViewHandleNVX -GetImageViewAddressNVX: ProcGetImageViewAddressNVX -CmdDrawIndirectCountAMD: ProcCmdDrawIndirectCountAMD -CmdDrawIndexedIndirectCountAMD: ProcCmdDrawIndexedIndirectCountAMD -GetShaderInfoAMD: ProcGetShaderInfoAMD -CmdBeginConditionalRenderingEXT: ProcCmdBeginConditionalRenderingEXT -CmdEndConditionalRenderingEXT: ProcCmdEndConditionalRenderingEXT -CmdSetViewportWScalingNV: ProcCmdSetViewportWScalingNV -DisplayPowerControlEXT: ProcDisplayPowerControlEXT -RegisterDeviceEventEXT: ProcRegisterDeviceEventEXT -RegisterDisplayEventEXT: ProcRegisterDisplayEventEXT -GetSwapchainCounterEXT: ProcGetSwapchainCounterEXT -GetRefreshCycleDurationGOOGLE: ProcGetRefreshCycleDurationGOOGLE -GetPastPresentationTimingGOOGLE: ProcGetPastPresentationTimingGOOGLE -CmdSetDiscardRectangleEXT: ProcCmdSetDiscardRectangleEXT -SetHdrMetadataEXT: ProcSetHdrMetadataEXT -SetDebugUtilsObjectNameEXT: ProcSetDebugUtilsObjectNameEXT -SetDebugUtilsObjectTagEXT: ProcSetDebugUtilsObjectTagEXT -QueueBeginDebugUtilsLabelEXT: ProcQueueBeginDebugUtilsLabelEXT -QueueEndDebugUtilsLabelEXT: ProcQueueEndDebugUtilsLabelEXT -QueueInsertDebugUtilsLabelEXT: ProcQueueInsertDebugUtilsLabelEXT -CmdBeginDebugUtilsLabelEXT: ProcCmdBeginDebugUtilsLabelEXT -CmdEndDebugUtilsLabelEXT: ProcCmdEndDebugUtilsLabelEXT -CmdInsertDebugUtilsLabelEXT: ProcCmdInsertDebugUtilsLabelEXT -CmdSetSampleLocationsEXT: ProcCmdSetSampleLocationsEXT -GetImageDrmFormatModifierPropertiesEXT: ProcGetImageDrmFormatModifierPropertiesEXT -CreateValidationCacheEXT: ProcCreateValidationCacheEXT -DestroyValidationCacheEXT: ProcDestroyValidationCacheEXT -MergeValidationCachesEXT: ProcMergeValidationCachesEXT -GetValidationCacheDataEXT: ProcGetValidationCacheDataEXT -CmdBindShadingRateImageNV: ProcCmdBindShadingRateImageNV -CmdSetViewportShadingRatePaletteNV: ProcCmdSetViewportShadingRatePaletteNV -CmdSetCoarseSampleOrderNV: ProcCmdSetCoarseSampleOrderNV -CreateAccelerationStructureNV: ProcCreateAccelerationStructureNV -DestroyAccelerationStructureNV: ProcDestroyAccelerationStructureNV -GetAccelerationStructureMemoryRequirementsNV: ProcGetAccelerationStructureMemoryRequirementsNV -BindAccelerationStructureMemoryNV: ProcBindAccelerationStructureMemoryNV -CmdBuildAccelerationStructureNV: ProcCmdBuildAccelerationStructureNV -CmdCopyAccelerationStructureNV: ProcCmdCopyAccelerationStructureNV -CmdTraceRaysNV: ProcCmdTraceRaysNV -CreateRayTracingPipelinesNV: ProcCreateRayTracingPipelinesNV -GetRayTracingShaderGroupHandlesKHR: ProcGetRayTracingShaderGroupHandlesKHR -GetRayTracingShaderGroupHandlesNV: ProcGetRayTracingShaderGroupHandlesNV -GetAccelerationStructureHandleNV: ProcGetAccelerationStructureHandleNV -CmdWriteAccelerationStructuresPropertiesNV: ProcCmdWriteAccelerationStructuresPropertiesNV -CompileDeferredNV: ProcCompileDeferredNV -GetMemoryHostPointerPropertiesEXT: ProcGetMemoryHostPointerPropertiesEXT -CmdWriteBufferMarkerAMD: ProcCmdWriteBufferMarkerAMD -GetCalibratedTimestampsEXT: ProcGetCalibratedTimestampsEXT -CmdDrawMeshTasksNV: ProcCmdDrawMeshTasksNV -CmdDrawMeshTasksIndirectNV: ProcCmdDrawMeshTasksIndirectNV -CmdDrawMeshTasksIndirectCountNV: ProcCmdDrawMeshTasksIndirectCountNV -CmdSetExclusiveScissorNV: ProcCmdSetExclusiveScissorNV -CmdSetCheckpointNV: ProcCmdSetCheckpointNV -GetQueueCheckpointDataNV: ProcGetQueueCheckpointDataNV -InitializePerformanceApiINTEL: ProcInitializePerformanceApiINTEL -UninitializePerformanceApiINTEL: ProcUninitializePerformanceApiINTEL -CmdSetPerformanceMarkerINTEL: ProcCmdSetPerformanceMarkerINTEL -CmdSetPerformanceStreamMarkerINTEL: ProcCmdSetPerformanceStreamMarkerINTEL -CmdSetPerformanceOverrideINTEL: ProcCmdSetPerformanceOverrideINTEL -AcquirePerformanceConfigurationINTEL: ProcAcquirePerformanceConfigurationINTEL -ReleasePerformanceConfigurationINTEL: ProcReleasePerformanceConfigurationINTEL -QueueSetPerformanceConfigurationINTEL: ProcQueueSetPerformanceConfigurationINTEL -GetPerformanceParameterINTEL: ProcGetPerformanceParameterINTEL -SetLocalDimmingAMD: ProcSetLocalDimmingAMD -GetBufferDeviceAddressEXT: ProcGetBufferDeviceAddressEXT -CmdSetLineStippleEXT: ProcCmdSetLineStippleEXT -ResetQueryPoolEXT: ProcResetQueryPoolEXT -CmdSetCullModeEXT: ProcCmdSetCullModeEXT -CmdSetFrontFaceEXT: ProcCmdSetFrontFaceEXT -CmdSetPrimitiveTopologyEXT: ProcCmdSetPrimitiveTopologyEXT -CmdSetViewportWithCountEXT: ProcCmdSetViewportWithCountEXT -CmdSetScissorWithCountEXT: ProcCmdSetScissorWithCountEXT -CmdBindVertexBuffers2EXT: ProcCmdBindVertexBuffers2EXT -CmdSetDepthTestEnableEXT: ProcCmdSetDepthTestEnableEXT -CmdSetDepthWriteEnableEXT: ProcCmdSetDepthWriteEnableEXT -CmdSetDepthCompareOpEXT: ProcCmdSetDepthCompareOpEXT -CmdSetDepthBoundsTestEnableEXT: ProcCmdSetDepthBoundsTestEnableEXT -CmdSetStencilTestEnableEXT: ProcCmdSetStencilTestEnableEXT -CmdSetStencilOpEXT: ProcCmdSetStencilOpEXT -GetGeneratedCommandsMemoryRequirementsNV: ProcGetGeneratedCommandsMemoryRequirementsNV -CmdPreprocessGeneratedCommandsNV: ProcCmdPreprocessGeneratedCommandsNV -CmdExecuteGeneratedCommandsNV: ProcCmdExecuteGeneratedCommandsNV -CmdBindPipelineShaderGroupNV: ProcCmdBindPipelineShaderGroupNV -CreateIndirectCommandsLayoutNV: ProcCreateIndirectCommandsLayoutNV -DestroyIndirectCommandsLayoutNV: ProcDestroyIndirectCommandsLayoutNV -CreatePrivateDataSlotEXT: ProcCreatePrivateDataSlotEXT -DestroyPrivateDataSlotEXT: ProcDestroyPrivateDataSlotEXT -SetPrivateDataEXT: ProcSetPrivateDataEXT -GetPrivateDataEXT: ProcGetPrivateDataEXT -CmdSetFragmentShadingRateEnumNV: ProcCmdSetFragmentShadingRateEnumNV -CmdSetVertexInputEXT: ProcCmdSetVertexInputEXT -GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI: ProcGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI -CmdSubpassShadingHUAWEI: ProcCmdSubpassShadingHUAWEI -CmdBindInvocationMaskHUAWEI: ProcCmdBindInvocationMaskHUAWEI -GetMemoryRemoteAddressNV: ProcGetMemoryRemoteAddressNV -CmdSetPatchControlPointsEXT: ProcCmdSetPatchControlPointsEXT -CmdSetRasterizerDiscardEnableEXT: ProcCmdSetRasterizerDiscardEnableEXT -CmdSetDepthBiasEnableEXT: ProcCmdSetDepthBiasEnableEXT -CmdSetLogicOpEXT: ProcCmdSetLogicOpEXT -CmdSetPrimitiveRestartEnableEXT: ProcCmdSetPrimitiveRestartEnableEXT -CmdDrawMultiEXT: ProcCmdDrawMultiEXT -CmdDrawMultiIndexedEXT: ProcCmdDrawMultiIndexedEXT -SetDeviceMemoryPriorityEXT: ProcSetDeviceMemoryPriorityEXT -CreateAccelerationStructureKHR: ProcCreateAccelerationStructureKHR -DestroyAccelerationStructureKHR: ProcDestroyAccelerationStructureKHR -CmdBuildAccelerationStructuresKHR: ProcCmdBuildAccelerationStructuresKHR -CmdBuildAccelerationStructuresIndirectKHR: ProcCmdBuildAccelerationStructuresIndirectKHR -BuildAccelerationStructuresKHR: ProcBuildAccelerationStructuresKHR -CopyAccelerationStructureKHR: ProcCopyAccelerationStructureKHR -CopyAccelerationStructureToMemoryKHR: ProcCopyAccelerationStructureToMemoryKHR -CopyMemoryToAccelerationStructureKHR: ProcCopyMemoryToAccelerationStructureKHR -WriteAccelerationStructuresPropertiesKHR: ProcWriteAccelerationStructuresPropertiesKHR -CmdCopyAccelerationStructureKHR: ProcCmdCopyAccelerationStructureKHR -CmdCopyAccelerationStructureToMemoryKHR: ProcCmdCopyAccelerationStructureToMemoryKHR -CmdCopyMemoryToAccelerationStructureKHR: ProcCmdCopyMemoryToAccelerationStructureKHR -GetAccelerationStructureDeviceAddressKHR: ProcGetAccelerationStructureDeviceAddressKHR -CmdWriteAccelerationStructuresPropertiesKHR: ProcCmdWriteAccelerationStructuresPropertiesKHR -GetDeviceAccelerationStructureCompatibilityKHR: ProcGetDeviceAccelerationStructureCompatibilityKHR -GetAccelerationStructureBuildSizesKHR: ProcGetAccelerationStructureBuildSizesKHR -CmdTraceRaysKHR: ProcCmdTraceRaysKHR -CreateRayTracingPipelinesKHR: ProcCreateRayTracingPipelinesKHR -GetRayTracingCaptureReplayShaderGroupHandlesKHR: ProcGetRayTracingCaptureReplayShaderGroupHandlesKHR -CmdTraceRaysIndirectKHR: ProcCmdTraceRaysIndirectKHR -GetRayTracingShaderGroupStackSizeKHR: ProcGetRayTracingShaderGroupStackSizeKHR -CmdSetRayTracingPipelineStackSizeKHR: ProcCmdSetRayTracingPipelineStackSizeKHR -GetMemoryWin32HandleKHR: ProcGetMemoryWin32HandleKHR -GetMemoryWin32HandlePropertiesKHR: ProcGetMemoryWin32HandlePropertiesKHR -ImportSemaphoreWin32HandleKHR: ProcImportSemaphoreWin32HandleKHR -GetSemaphoreWin32HandleKHR: ProcGetSemaphoreWin32HandleKHR -ImportFenceWin32HandleKHR: ProcImportFenceWin32HandleKHR -GetFenceWin32HandleKHR: ProcGetFenceWin32HandleKHR -GetMemoryWin32HandleNV: ProcGetMemoryWin32HandleNV -AcquireFullScreenExclusiveModeEXT: ProcAcquireFullScreenExclusiveModeEXT -ReleaseFullScreenExclusiveModeEXT: ProcReleaseFullScreenExclusiveModeEXT -GetDeviceGroupSurfacePresentModes2EXT: ProcGetDeviceGroupSurfacePresentModes2EXT // Loader Procedures CreateInstance: ProcCreateInstance +DebugUtilsMessengerCallbackEXT: ProcDebugUtilsMessengerCallbackEXT +DeviceMemoryReportCallbackEXT: ProcDeviceMemoryReportCallbackEXT EnumerateInstanceExtensionProperties: ProcEnumerateInstanceExtensionProperties EnumerateInstanceLayerProperties: ProcEnumerateInstanceLayerProperties EnumerateInstanceVersion: ProcEnumerateInstanceVersion -DebugUtilsMessengerCallbackEXT: ProcDebugUtilsMessengerCallbackEXT -DeviceMemoryReportCallbackEXT: ProcDeviceMemoryReportCallbackEXT -load_proc_addresses :: proc(set_proc_address: SetProcAddressType) { - // Instance Procedures - set_proc_address(&DestroyInstance, "vkDestroyInstance") - set_proc_address(&EnumeratePhysicalDevices, "vkEnumeratePhysicalDevices") - set_proc_address(&GetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures") - set_proc_address(&GetPhysicalDeviceFormatProperties, "vkGetPhysicalDeviceFormatProperties") - set_proc_address(&GetPhysicalDeviceImageFormatProperties, "vkGetPhysicalDeviceImageFormatProperties") - set_proc_address(&GetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties") - set_proc_address(&GetPhysicalDeviceQueueFamilyProperties, "vkGetPhysicalDeviceQueueFamilyProperties") - set_proc_address(&GetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties") - set_proc_address(&GetInstanceProcAddr, "vkGetInstanceProcAddr") - set_proc_address(&CreateDevice, "vkCreateDevice") - set_proc_address(&EnumerateDeviceExtensionProperties, "vkEnumerateDeviceExtensionProperties") - set_proc_address(&EnumerateDeviceLayerProperties, "vkEnumerateDeviceLayerProperties") - set_proc_address(&GetPhysicalDeviceSparseImageFormatProperties, "vkGetPhysicalDeviceSparseImageFormatProperties") - set_proc_address(&EnumeratePhysicalDeviceGroups, "vkEnumeratePhysicalDeviceGroups") - set_proc_address(&GetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2") - set_proc_address(&GetPhysicalDeviceProperties2, "vkGetPhysicalDeviceProperties2") - set_proc_address(&GetPhysicalDeviceFormatProperties2, "vkGetPhysicalDeviceFormatProperties2") - set_proc_address(&GetPhysicalDeviceImageFormatProperties2, "vkGetPhysicalDeviceImageFormatProperties2") - set_proc_address(&GetPhysicalDeviceQueueFamilyProperties2, "vkGetPhysicalDeviceQueueFamilyProperties2") - set_proc_address(&GetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2") - set_proc_address(&GetPhysicalDeviceSparseImageFormatProperties2, "vkGetPhysicalDeviceSparseImageFormatProperties2") - set_proc_address(&GetPhysicalDeviceExternalBufferProperties, "vkGetPhysicalDeviceExternalBufferProperties") - set_proc_address(&GetPhysicalDeviceExternalFenceProperties, "vkGetPhysicalDeviceExternalFenceProperties") - set_proc_address(&GetPhysicalDeviceExternalSemaphoreProperties, "vkGetPhysicalDeviceExternalSemaphoreProperties") - set_proc_address(&DestroySurfaceKHR, "vkDestroySurfaceKHR") - set_proc_address(&GetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR") - set_proc_address(&GetPhysicalDeviceSurfaceCapabilitiesKHR, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") - set_proc_address(&GetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR") - set_proc_address(&GetPhysicalDeviceSurfacePresentModesKHR, "vkGetPhysicalDeviceSurfacePresentModesKHR") - set_proc_address(&GetPhysicalDevicePresentRectanglesKHR, "vkGetPhysicalDevicePresentRectanglesKHR") - set_proc_address(&GetPhysicalDeviceDisplayPropertiesKHR, "vkGetPhysicalDeviceDisplayPropertiesKHR") - set_proc_address(&GetPhysicalDeviceDisplayPlanePropertiesKHR, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR") - set_proc_address(&GetDisplayPlaneSupportedDisplaysKHR, "vkGetDisplayPlaneSupportedDisplaysKHR") - set_proc_address(&GetDisplayModePropertiesKHR, "vkGetDisplayModePropertiesKHR") - set_proc_address(&CreateDisplayModeKHR, "vkCreateDisplayModeKHR") - set_proc_address(&GetDisplayPlaneCapabilitiesKHR, "vkGetDisplayPlaneCapabilitiesKHR") - set_proc_address(&CreateDisplayPlaneSurfaceKHR, "vkCreateDisplayPlaneSurfaceKHR") - set_proc_address(&GetPhysicalDeviceFeatures2KHR, "vkGetPhysicalDeviceFeatures2KHR") - set_proc_address(&GetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2KHR") - set_proc_address(&GetPhysicalDeviceFormatProperties2KHR, "vkGetPhysicalDeviceFormatProperties2KHR") - set_proc_address(&GetPhysicalDeviceImageFormatProperties2KHR, "vkGetPhysicalDeviceImageFormatProperties2KHR") - set_proc_address(&GetPhysicalDeviceQueueFamilyProperties2KHR, "vkGetPhysicalDeviceQueueFamilyProperties2KHR") - set_proc_address(&GetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR") - set_proc_address(&GetPhysicalDeviceSparseImageFormatProperties2KHR, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR") - set_proc_address(&EnumeratePhysicalDeviceGroupsKHR, "vkEnumeratePhysicalDeviceGroupsKHR") - set_proc_address(&GetPhysicalDeviceExternalBufferPropertiesKHR, "vkGetPhysicalDeviceExternalBufferPropertiesKHR") - set_proc_address(&GetPhysicalDeviceExternalSemaphorePropertiesKHR, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR") - set_proc_address(&GetPhysicalDeviceExternalFencePropertiesKHR, "vkGetPhysicalDeviceExternalFencePropertiesKHR") - set_proc_address(&EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR") - set_proc_address(&GetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR") - set_proc_address(&GetPhysicalDeviceSurfaceCapabilities2KHR, "vkGetPhysicalDeviceSurfaceCapabilities2KHR") - set_proc_address(&GetPhysicalDeviceSurfaceFormats2KHR, "vkGetPhysicalDeviceSurfaceFormats2KHR") - set_proc_address(&GetPhysicalDeviceDisplayProperties2KHR, "vkGetPhysicalDeviceDisplayProperties2KHR") - set_proc_address(&GetPhysicalDeviceDisplayPlaneProperties2KHR, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR") - set_proc_address(&GetDisplayModeProperties2KHR, "vkGetDisplayModeProperties2KHR") - set_proc_address(&GetDisplayPlaneCapabilities2KHR, "vkGetDisplayPlaneCapabilities2KHR") - set_proc_address(&GetPhysicalDeviceFragmentShadingRatesKHR, "vkGetPhysicalDeviceFragmentShadingRatesKHR") - set_proc_address(&CreateDebugReportCallbackEXT, "vkCreateDebugReportCallbackEXT") - set_proc_address(&DestroyDebugReportCallbackEXT, "vkDestroyDebugReportCallbackEXT") - set_proc_address(&DebugReportMessageEXT, "vkDebugReportMessageEXT") - set_proc_address(&GetPhysicalDeviceExternalImageFormatPropertiesNV, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV") - set_proc_address(&ReleaseDisplayEXT, "vkReleaseDisplayEXT") - set_proc_address(&GetPhysicalDeviceSurfaceCapabilities2EXT, "vkGetPhysicalDeviceSurfaceCapabilities2EXT") - set_proc_address(&CreateDebugUtilsMessengerEXT, "vkCreateDebugUtilsMessengerEXT") - set_proc_address(&DestroyDebugUtilsMessengerEXT, "vkDestroyDebugUtilsMessengerEXT") - set_proc_address(&SubmitDebugUtilsMessageEXT, "vkSubmitDebugUtilsMessageEXT") - set_proc_address(&GetPhysicalDeviceMultisamplePropertiesEXT, "vkGetPhysicalDeviceMultisamplePropertiesEXT") - set_proc_address(&GetPhysicalDeviceCalibrateableTimeDomainsEXT, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT") - set_proc_address(&GetPhysicalDeviceToolPropertiesEXT, "vkGetPhysicalDeviceToolPropertiesEXT") - set_proc_address(&GetPhysicalDeviceCooperativeMatrixPropertiesNV, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV") - set_proc_address(&GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV") - set_proc_address(&CreateHeadlessSurfaceEXT, "vkCreateHeadlessSurfaceEXT") - set_proc_address(&AcquireDrmDisplayEXT, "vkAcquireDrmDisplayEXT") - set_proc_address(&GetDrmDisplayEXT, "vkGetDrmDisplayEXT") - set_proc_address(&AcquireWinrtDisplayNV, "vkAcquireWinrtDisplayNV") - set_proc_address(&GetWinrtDisplayNV, "vkGetWinrtDisplayNV") - set_proc_address(&CreateWin32SurfaceKHR, "vkCreateWin32SurfaceKHR") - set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR") - set_proc_address(&GetPhysicalDeviceSurfacePresentModes2EXT, "vkGetPhysicalDeviceSurfacePresentModes2EXT") - set_proc_address(&CreateMetalSurfaceEXT, "vkCreateMetalSurfaceEXT") - set_proc_address(&CreateMacOSSurfaceMVK, "vkCreateMacOSSurfaceMVK") - set_proc_address(&CreateIOSSurfaceMVK, "vkCreateIOSSurfaceMVK") +// Instance Procedures +AcquireDrmDisplayEXT: ProcAcquireDrmDisplayEXT +AcquireWinrtDisplayNV: ProcAcquireWinrtDisplayNV +CreateDebugReportCallbackEXT: ProcCreateDebugReportCallbackEXT +CreateDebugUtilsMessengerEXT: ProcCreateDebugUtilsMessengerEXT +CreateDevice: ProcCreateDevice +CreateDisplayModeKHR: ProcCreateDisplayModeKHR +CreateDisplayPlaneSurfaceKHR: ProcCreateDisplayPlaneSurfaceKHR +CreateHeadlessSurfaceEXT: ProcCreateHeadlessSurfaceEXT +CreateIOSSurfaceMVK: ProcCreateIOSSurfaceMVK +CreateMacOSSurfaceMVK: ProcCreateMacOSSurfaceMVK +CreateMetalSurfaceEXT: ProcCreateMetalSurfaceEXT +CreateWin32SurfaceKHR: ProcCreateWin32SurfaceKHR +DebugReportMessageEXT: ProcDebugReportMessageEXT +DestroyDebugReportCallbackEXT: ProcDestroyDebugReportCallbackEXT +DestroyDebugUtilsMessengerEXT: ProcDestroyDebugUtilsMessengerEXT +DestroyInstance: ProcDestroyInstance +DestroySurfaceKHR: ProcDestroySurfaceKHR +EnumerateDeviceExtensionProperties: ProcEnumerateDeviceExtensionProperties +EnumerateDeviceLayerProperties: ProcEnumerateDeviceLayerProperties +EnumeratePhysicalDeviceGroups: ProcEnumeratePhysicalDeviceGroups +EnumeratePhysicalDeviceGroupsKHR: ProcEnumeratePhysicalDeviceGroupsKHR +EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR: ProcEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR +EnumeratePhysicalDevices: ProcEnumeratePhysicalDevices +GetDisplayModeProperties2KHR: ProcGetDisplayModeProperties2KHR +GetDisplayModePropertiesKHR: ProcGetDisplayModePropertiesKHR +GetDisplayPlaneCapabilities2KHR: ProcGetDisplayPlaneCapabilities2KHR +GetDisplayPlaneCapabilitiesKHR: ProcGetDisplayPlaneCapabilitiesKHR +GetDisplayPlaneSupportedDisplaysKHR: ProcGetDisplayPlaneSupportedDisplaysKHR +GetDrmDisplayEXT: ProcGetDrmDisplayEXT +GetInstanceProcAddr: ProcGetInstanceProcAddr +GetPhysicalDeviceCalibrateableTimeDomainsEXT: ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT +GetPhysicalDeviceCooperativeMatrixPropertiesNV: ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV +GetPhysicalDeviceDisplayPlaneProperties2KHR: ProcGetPhysicalDeviceDisplayPlaneProperties2KHR +GetPhysicalDeviceDisplayPlanePropertiesKHR: ProcGetPhysicalDeviceDisplayPlanePropertiesKHR +GetPhysicalDeviceDisplayProperties2KHR: ProcGetPhysicalDeviceDisplayProperties2KHR +GetPhysicalDeviceDisplayPropertiesKHR: ProcGetPhysicalDeviceDisplayPropertiesKHR +GetPhysicalDeviceExternalBufferProperties: ProcGetPhysicalDeviceExternalBufferProperties +GetPhysicalDeviceExternalBufferPropertiesKHR: ProcGetPhysicalDeviceExternalBufferPropertiesKHR +GetPhysicalDeviceExternalFenceProperties: ProcGetPhysicalDeviceExternalFenceProperties +GetPhysicalDeviceExternalFencePropertiesKHR: ProcGetPhysicalDeviceExternalFencePropertiesKHR +GetPhysicalDeviceExternalImageFormatPropertiesNV: ProcGetPhysicalDeviceExternalImageFormatPropertiesNV +GetPhysicalDeviceExternalSemaphoreProperties: ProcGetPhysicalDeviceExternalSemaphoreProperties +GetPhysicalDeviceExternalSemaphorePropertiesKHR: ProcGetPhysicalDeviceExternalSemaphorePropertiesKHR +GetPhysicalDeviceFeatures: ProcGetPhysicalDeviceFeatures +GetPhysicalDeviceFeatures2: ProcGetPhysicalDeviceFeatures2 +GetPhysicalDeviceFeatures2KHR: ProcGetPhysicalDeviceFeatures2KHR +GetPhysicalDeviceFormatProperties: ProcGetPhysicalDeviceFormatProperties +GetPhysicalDeviceFormatProperties2: ProcGetPhysicalDeviceFormatProperties2 +GetPhysicalDeviceFormatProperties2KHR: ProcGetPhysicalDeviceFormatProperties2KHR +GetPhysicalDeviceFragmentShadingRatesKHR: ProcGetPhysicalDeviceFragmentShadingRatesKHR +GetPhysicalDeviceImageFormatProperties: ProcGetPhysicalDeviceImageFormatProperties +GetPhysicalDeviceImageFormatProperties2: ProcGetPhysicalDeviceImageFormatProperties2 +GetPhysicalDeviceImageFormatProperties2KHR: ProcGetPhysicalDeviceImageFormatProperties2KHR +GetPhysicalDeviceMemoryProperties: ProcGetPhysicalDeviceMemoryProperties +GetPhysicalDeviceMemoryProperties2: ProcGetPhysicalDeviceMemoryProperties2 +GetPhysicalDeviceMemoryProperties2KHR: ProcGetPhysicalDeviceMemoryProperties2KHR +GetPhysicalDeviceMultisamplePropertiesEXT: ProcGetPhysicalDeviceMultisamplePropertiesEXT +GetPhysicalDevicePresentRectanglesKHR: ProcGetPhysicalDevicePresentRectanglesKHR +GetPhysicalDeviceProperties: ProcGetPhysicalDeviceProperties +GetPhysicalDeviceProperties2: ProcGetPhysicalDeviceProperties2 +GetPhysicalDeviceProperties2KHR: ProcGetPhysicalDeviceProperties2KHR +GetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR: ProcGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR +GetPhysicalDeviceQueueFamilyProperties: ProcGetPhysicalDeviceQueueFamilyProperties +GetPhysicalDeviceQueueFamilyProperties2: ProcGetPhysicalDeviceQueueFamilyProperties2 +GetPhysicalDeviceQueueFamilyProperties2KHR: ProcGetPhysicalDeviceQueueFamilyProperties2KHR +GetPhysicalDeviceSparseImageFormatProperties: ProcGetPhysicalDeviceSparseImageFormatProperties +GetPhysicalDeviceSparseImageFormatProperties2: ProcGetPhysicalDeviceSparseImageFormatProperties2 +GetPhysicalDeviceSparseImageFormatProperties2KHR: ProcGetPhysicalDeviceSparseImageFormatProperties2KHR +GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV: ProcGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV +GetPhysicalDeviceSurfaceCapabilities2EXT: ProcGetPhysicalDeviceSurfaceCapabilities2EXT +GetPhysicalDeviceSurfaceCapabilities2KHR: ProcGetPhysicalDeviceSurfaceCapabilities2KHR +GetPhysicalDeviceSurfaceCapabilitiesKHR: ProcGetPhysicalDeviceSurfaceCapabilitiesKHR +GetPhysicalDeviceSurfaceFormats2KHR: ProcGetPhysicalDeviceSurfaceFormats2KHR +GetPhysicalDeviceSurfaceFormatsKHR: ProcGetPhysicalDeviceSurfaceFormatsKHR +GetPhysicalDeviceSurfacePresentModes2EXT: ProcGetPhysicalDeviceSurfacePresentModes2EXT +GetPhysicalDeviceSurfacePresentModesKHR: ProcGetPhysicalDeviceSurfacePresentModesKHR +GetPhysicalDeviceSurfaceSupportKHR: ProcGetPhysicalDeviceSurfaceSupportKHR +GetPhysicalDeviceToolPropertiesEXT: ProcGetPhysicalDeviceToolPropertiesEXT +GetPhysicalDeviceWin32PresentationSupportKHR: ProcGetPhysicalDeviceWin32PresentationSupportKHR +GetWinrtDisplayNV: ProcGetWinrtDisplayNV +ReleaseDisplayEXT: ProcReleaseDisplayEXT +SubmitDebugUtilsMessageEXT: ProcSubmitDebugUtilsMessageEXT - // Device Procedures - set_proc_address(&GetDeviceProcAddr, "vkGetDeviceProcAddr") - set_proc_address(&DestroyDevice, "vkDestroyDevice") - set_proc_address(&GetDeviceQueue, "vkGetDeviceQueue") - set_proc_address(&QueueSubmit, "vkQueueSubmit") - set_proc_address(&QueueWaitIdle, "vkQueueWaitIdle") - set_proc_address(&DeviceWaitIdle, "vkDeviceWaitIdle") - set_proc_address(&AllocateMemory, "vkAllocateMemory") - set_proc_address(&FreeMemory, "vkFreeMemory") - set_proc_address(&MapMemory, "vkMapMemory") - set_proc_address(&UnmapMemory, "vkUnmapMemory") - set_proc_address(&FlushMappedMemoryRanges, "vkFlushMappedMemoryRanges") - set_proc_address(&InvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges") - set_proc_address(&GetDeviceMemoryCommitment, "vkGetDeviceMemoryCommitment") - set_proc_address(&BindBufferMemory, "vkBindBufferMemory") - set_proc_address(&BindImageMemory, "vkBindImageMemory") - set_proc_address(&GetBufferMemoryRequirements, "vkGetBufferMemoryRequirements") - set_proc_address(&GetImageMemoryRequirements, "vkGetImageMemoryRequirements") - set_proc_address(&GetImageSparseMemoryRequirements, "vkGetImageSparseMemoryRequirements") - set_proc_address(&QueueBindSparse, "vkQueueBindSparse") - set_proc_address(&CreateFence, "vkCreateFence") - set_proc_address(&DestroyFence, "vkDestroyFence") - set_proc_address(&ResetFences, "vkResetFences") - set_proc_address(&GetFenceStatus, "vkGetFenceStatus") - set_proc_address(&WaitForFences, "vkWaitForFences") - set_proc_address(&CreateSemaphore, "vkCreateSemaphore") - set_proc_address(&DestroySemaphore, "vkDestroySemaphore") - set_proc_address(&CreateEvent, "vkCreateEvent") - set_proc_address(&DestroyEvent, "vkDestroyEvent") - set_proc_address(&GetEventStatus, "vkGetEventStatus") - set_proc_address(&SetEvent, "vkSetEvent") - set_proc_address(&ResetEvent, "vkResetEvent") - set_proc_address(&CreateQueryPool, "vkCreateQueryPool") - set_proc_address(&DestroyQueryPool, "vkDestroyQueryPool") - set_proc_address(&GetQueryPoolResults, "vkGetQueryPoolResults") - set_proc_address(&CreateBuffer, "vkCreateBuffer") - set_proc_address(&DestroyBuffer, "vkDestroyBuffer") - set_proc_address(&CreateBufferView, "vkCreateBufferView") - set_proc_address(&DestroyBufferView, "vkDestroyBufferView") - set_proc_address(&CreateImage, "vkCreateImage") - set_proc_address(&DestroyImage, "vkDestroyImage") - set_proc_address(&GetImageSubresourceLayout, "vkGetImageSubresourceLayout") - set_proc_address(&CreateImageView, "vkCreateImageView") - set_proc_address(&DestroyImageView, "vkDestroyImageView") - set_proc_address(&CreateShaderModule, "vkCreateShaderModule") - set_proc_address(&DestroyShaderModule, "vkDestroyShaderModule") - set_proc_address(&CreatePipelineCache, "vkCreatePipelineCache") - set_proc_address(&DestroyPipelineCache, "vkDestroyPipelineCache") - set_proc_address(&GetPipelineCacheData, "vkGetPipelineCacheData") - set_proc_address(&MergePipelineCaches, "vkMergePipelineCaches") - set_proc_address(&CreateGraphicsPipelines, "vkCreateGraphicsPipelines") - set_proc_address(&CreateComputePipelines, "vkCreateComputePipelines") - set_proc_address(&DestroyPipeline, "vkDestroyPipeline") - set_proc_address(&CreatePipelineLayout, "vkCreatePipelineLayout") - set_proc_address(&DestroyPipelineLayout, "vkDestroyPipelineLayout") - set_proc_address(&CreateSampler, "vkCreateSampler") - set_proc_address(&DestroySampler, "vkDestroySampler") - set_proc_address(&CreateDescriptorSetLayout, "vkCreateDescriptorSetLayout") - set_proc_address(&DestroyDescriptorSetLayout, "vkDestroyDescriptorSetLayout") - set_proc_address(&CreateDescriptorPool, "vkCreateDescriptorPool") - set_proc_address(&DestroyDescriptorPool, "vkDestroyDescriptorPool") - set_proc_address(&ResetDescriptorPool, "vkResetDescriptorPool") - set_proc_address(&AllocateDescriptorSets, "vkAllocateDescriptorSets") - set_proc_address(&FreeDescriptorSets, "vkFreeDescriptorSets") - set_proc_address(&UpdateDescriptorSets, "vkUpdateDescriptorSets") - set_proc_address(&CreateFramebuffer, "vkCreateFramebuffer") - set_proc_address(&DestroyFramebuffer, "vkDestroyFramebuffer") - set_proc_address(&CreateRenderPass, "vkCreateRenderPass") - set_proc_address(&DestroyRenderPass, "vkDestroyRenderPass") - set_proc_address(&GetRenderAreaGranularity, "vkGetRenderAreaGranularity") - set_proc_address(&CreateCommandPool, "vkCreateCommandPool") - set_proc_address(&DestroyCommandPool, "vkDestroyCommandPool") - set_proc_address(&ResetCommandPool, "vkResetCommandPool") - set_proc_address(&AllocateCommandBuffers, "vkAllocateCommandBuffers") - set_proc_address(&FreeCommandBuffers, "vkFreeCommandBuffers") - set_proc_address(&BeginCommandBuffer, "vkBeginCommandBuffer") - set_proc_address(&EndCommandBuffer, "vkEndCommandBuffer") - set_proc_address(&ResetCommandBuffer, "vkResetCommandBuffer") - set_proc_address(&CmdBindPipeline, "vkCmdBindPipeline") - set_proc_address(&CmdSetViewport, "vkCmdSetViewport") - set_proc_address(&CmdSetScissor, "vkCmdSetScissor") - set_proc_address(&CmdSetLineWidth, "vkCmdSetLineWidth") - set_proc_address(&CmdSetDepthBias, "vkCmdSetDepthBias") - set_proc_address(&CmdSetBlendConstants, "vkCmdSetBlendConstants") - set_proc_address(&CmdSetDepthBounds, "vkCmdSetDepthBounds") - set_proc_address(&CmdSetStencilCompareMask, "vkCmdSetStencilCompareMask") - set_proc_address(&CmdSetStencilWriteMask, "vkCmdSetStencilWriteMask") - set_proc_address(&CmdSetStencilReference, "vkCmdSetStencilReference") - set_proc_address(&CmdBindDescriptorSets, "vkCmdBindDescriptorSets") - set_proc_address(&CmdBindIndexBuffer, "vkCmdBindIndexBuffer") - set_proc_address(&CmdBindVertexBuffers, "vkCmdBindVertexBuffers") - set_proc_address(&CmdDraw, "vkCmdDraw") - set_proc_address(&CmdDrawIndexed, "vkCmdDrawIndexed") - set_proc_address(&CmdDrawIndirect, "vkCmdDrawIndirect") - set_proc_address(&CmdDrawIndexedIndirect, "vkCmdDrawIndexedIndirect") - set_proc_address(&CmdDispatch, "vkCmdDispatch") - set_proc_address(&CmdDispatchIndirect, "vkCmdDispatchIndirect") - set_proc_address(&CmdCopyBuffer, "vkCmdCopyBuffer") - set_proc_address(&CmdCopyImage, "vkCmdCopyImage") - set_proc_address(&CmdBlitImage, "vkCmdBlitImage") - set_proc_address(&CmdCopyBufferToImage, "vkCmdCopyBufferToImage") - set_proc_address(&CmdCopyImageToBuffer, "vkCmdCopyImageToBuffer") - set_proc_address(&CmdUpdateBuffer, "vkCmdUpdateBuffer") - set_proc_address(&CmdFillBuffer, "vkCmdFillBuffer") - set_proc_address(&CmdClearColorImage, "vkCmdClearColorImage") - set_proc_address(&CmdClearDepthStencilImage, "vkCmdClearDepthStencilImage") - set_proc_address(&CmdClearAttachments, "vkCmdClearAttachments") - set_proc_address(&CmdResolveImage, "vkCmdResolveImage") - set_proc_address(&CmdSetEvent, "vkCmdSetEvent") - set_proc_address(&CmdResetEvent, "vkCmdResetEvent") - set_proc_address(&CmdWaitEvents, "vkCmdWaitEvents") - set_proc_address(&CmdPipelineBarrier, "vkCmdPipelineBarrier") - set_proc_address(&CmdBeginQuery, "vkCmdBeginQuery") - set_proc_address(&CmdEndQuery, "vkCmdEndQuery") - set_proc_address(&CmdResetQueryPool, "vkCmdResetQueryPool") - set_proc_address(&CmdWriteTimestamp, "vkCmdWriteTimestamp") - set_proc_address(&CmdCopyQueryPoolResults, "vkCmdCopyQueryPoolResults") - set_proc_address(&CmdPushConstants, "vkCmdPushConstants") - set_proc_address(&CmdBeginRenderPass, "vkCmdBeginRenderPass") - set_proc_address(&CmdNextSubpass, "vkCmdNextSubpass") - set_proc_address(&CmdEndRenderPass, "vkCmdEndRenderPass") - set_proc_address(&CmdExecuteCommands, "vkCmdExecuteCommands") - set_proc_address(&BindBufferMemory2, "vkBindBufferMemory2") - set_proc_address(&BindImageMemory2, "vkBindImageMemory2") - set_proc_address(&GetDeviceGroupPeerMemoryFeatures, "vkGetDeviceGroupPeerMemoryFeatures") - set_proc_address(&CmdSetDeviceMask, "vkCmdSetDeviceMask") - set_proc_address(&CmdDispatchBase, "vkCmdDispatchBase") - set_proc_address(&GetImageMemoryRequirements2, "vkGetImageMemoryRequirements2") - set_proc_address(&GetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2") - set_proc_address(&GetImageSparseMemoryRequirements2, "vkGetImageSparseMemoryRequirements2") - set_proc_address(&TrimCommandPool, "vkTrimCommandPool") - set_proc_address(&GetDeviceQueue2, "vkGetDeviceQueue2") - set_proc_address(&CreateSamplerYcbcrConversion, "vkCreateSamplerYcbcrConversion") - set_proc_address(&DestroySamplerYcbcrConversion, "vkDestroySamplerYcbcrConversion") - set_proc_address(&CreateDescriptorUpdateTemplate, "vkCreateDescriptorUpdateTemplate") - set_proc_address(&DestroyDescriptorUpdateTemplate, "vkDestroyDescriptorUpdateTemplate") - set_proc_address(&UpdateDescriptorSetWithTemplate, "vkUpdateDescriptorSetWithTemplate") - set_proc_address(&GetDescriptorSetLayoutSupport, "vkGetDescriptorSetLayoutSupport") - set_proc_address(&CmdDrawIndirectCount, "vkCmdDrawIndirectCount") - set_proc_address(&CmdDrawIndexedIndirectCount, "vkCmdDrawIndexedIndirectCount") - set_proc_address(&CreateRenderPass2, "vkCreateRenderPass2") - set_proc_address(&CmdBeginRenderPass2, "vkCmdBeginRenderPass2") - set_proc_address(&CmdNextSubpass2, "vkCmdNextSubpass2") - set_proc_address(&CmdEndRenderPass2, "vkCmdEndRenderPass2") - set_proc_address(&ResetQueryPool, "vkResetQueryPool") - set_proc_address(&GetSemaphoreCounterValue, "vkGetSemaphoreCounterValue") - set_proc_address(&WaitSemaphores, "vkWaitSemaphores") - set_proc_address(&SignalSemaphore, "vkSignalSemaphore") - set_proc_address(&GetBufferDeviceAddress, "vkGetBufferDeviceAddress") - set_proc_address(&GetBufferOpaqueCaptureAddress, "vkGetBufferOpaqueCaptureAddress") - set_proc_address(&GetDeviceMemoryOpaqueCaptureAddress, "vkGetDeviceMemoryOpaqueCaptureAddress") - set_proc_address(&CreateSwapchainKHR, "vkCreateSwapchainKHR") - set_proc_address(&DestroySwapchainKHR, "vkDestroySwapchainKHR") - set_proc_address(&GetSwapchainImagesKHR, "vkGetSwapchainImagesKHR") - set_proc_address(&AcquireNextImageKHR, "vkAcquireNextImageKHR") - set_proc_address(&QueuePresentKHR, "vkQueuePresentKHR") - set_proc_address(&GetDeviceGroupPresentCapabilitiesKHR, "vkGetDeviceGroupPresentCapabilitiesKHR") - set_proc_address(&GetDeviceGroupSurfacePresentModesKHR, "vkGetDeviceGroupSurfacePresentModesKHR") - set_proc_address(&AcquireNextImage2KHR, "vkAcquireNextImage2KHR") - set_proc_address(&CreateSharedSwapchainsKHR, "vkCreateSharedSwapchainsKHR") - set_proc_address(&GetDeviceGroupPeerMemoryFeaturesKHR, "vkGetDeviceGroupPeerMemoryFeaturesKHR") - set_proc_address(&CmdSetDeviceMaskKHR, "vkCmdSetDeviceMaskKHR") - set_proc_address(&CmdDispatchBaseKHR, "vkCmdDispatchBaseKHR") - set_proc_address(&TrimCommandPoolKHR, "vkTrimCommandPoolKHR") - set_proc_address(&GetMemoryFdKHR, "vkGetMemoryFdKHR") - set_proc_address(&GetMemoryFdPropertiesKHR, "vkGetMemoryFdPropertiesKHR") - set_proc_address(&ImportSemaphoreFdKHR, "vkImportSemaphoreFdKHR") - set_proc_address(&GetSemaphoreFdKHR, "vkGetSemaphoreFdKHR") - set_proc_address(&CmdPushDescriptorSetKHR, "vkCmdPushDescriptorSetKHR") - set_proc_address(&CmdPushDescriptorSetWithTemplateKHR, "vkCmdPushDescriptorSetWithTemplateKHR") - set_proc_address(&CreateDescriptorUpdateTemplateKHR, "vkCreateDescriptorUpdateTemplateKHR") - set_proc_address(&DestroyDescriptorUpdateTemplateKHR, "vkDestroyDescriptorUpdateTemplateKHR") - set_proc_address(&UpdateDescriptorSetWithTemplateKHR, "vkUpdateDescriptorSetWithTemplateKHR") - set_proc_address(&CreateRenderPass2KHR, "vkCreateRenderPass2KHR") - set_proc_address(&CmdBeginRenderPass2KHR, "vkCmdBeginRenderPass2KHR") - set_proc_address(&CmdNextSubpass2KHR, "vkCmdNextSubpass2KHR") - set_proc_address(&CmdEndRenderPass2KHR, "vkCmdEndRenderPass2KHR") - set_proc_address(&GetSwapchainStatusKHR, "vkGetSwapchainStatusKHR") - set_proc_address(&ImportFenceFdKHR, "vkImportFenceFdKHR") - set_proc_address(&GetFenceFdKHR, "vkGetFenceFdKHR") - set_proc_address(&AcquireProfilingLockKHR, "vkAcquireProfilingLockKHR") - set_proc_address(&ReleaseProfilingLockKHR, "vkReleaseProfilingLockKHR") - set_proc_address(&GetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR") - set_proc_address(&GetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR") - set_proc_address(&GetImageSparseMemoryRequirements2KHR, "vkGetImageSparseMemoryRequirements2KHR") - set_proc_address(&CreateSamplerYcbcrConversionKHR, "vkCreateSamplerYcbcrConversionKHR") - set_proc_address(&DestroySamplerYcbcrConversionKHR, "vkDestroySamplerYcbcrConversionKHR") - set_proc_address(&BindBufferMemory2KHR, "vkBindBufferMemory2KHR") - set_proc_address(&BindImageMemory2KHR, "vkBindImageMemory2KHR") - set_proc_address(&GetDescriptorSetLayoutSupportKHR, "vkGetDescriptorSetLayoutSupportKHR") - set_proc_address(&CmdDrawIndirectCountKHR, "vkCmdDrawIndirectCountKHR") - set_proc_address(&CmdDrawIndexedIndirectCountKHR, "vkCmdDrawIndexedIndirectCountKHR") - set_proc_address(&GetSemaphoreCounterValueKHR, "vkGetSemaphoreCounterValueKHR") - set_proc_address(&WaitSemaphoresKHR, "vkWaitSemaphoresKHR") - set_proc_address(&SignalSemaphoreKHR, "vkSignalSemaphoreKHR") - set_proc_address(&CmdSetFragmentShadingRateKHR, "vkCmdSetFragmentShadingRateKHR") - set_proc_address(&WaitForPresentKHR, "vkWaitForPresentKHR") - set_proc_address(&GetBufferDeviceAddressKHR, "vkGetBufferDeviceAddressKHR") - set_proc_address(&GetBufferOpaqueCaptureAddressKHR, "vkGetBufferOpaqueCaptureAddressKHR") - set_proc_address(&GetDeviceMemoryOpaqueCaptureAddressKHR, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") - set_proc_address(&CreateDeferredOperationKHR, "vkCreateDeferredOperationKHR") - set_proc_address(&DestroyDeferredOperationKHR, "vkDestroyDeferredOperationKHR") - set_proc_address(&GetDeferredOperationMaxConcurrencyKHR, "vkGetDeferredOperationMaxConcurrencyKHR") - set_proc_address(&GetDeferredOperationResultKHR, "vkGetDeferredOperationResultKHR") - set_proc_address(&DeferredOperationJoinKHR, "vkDeferredOperationJoinKHR") - set_proc_address(&GetPipelineExecutablePropertiesKHR, "vkGetPipelineExecutablePropertiesKHR") - set_proc_address(&GetPipelineExecutableStatisticsKHR, "vkGetPipelineExecutableStatisticsKHR") - set_proc_address(&GetPipelineExecutableInternalRepresentationsKHR, "vkGetPipelineExecutableInternalRepresentationsKHR") - set_proc_address(&CmdSetEvent2KHR, "vkCmdSetEvent2KHR") - set_proc_address(&CmdResetEvent2KHR, "vkCmdResetEvent2KHR") - set_proc_address(&CmdWaitEvents2KHR, "vkCmdWaitEvents2KHR") - set_proc_address(&CmdPipelineBarrier2KHR, "vkCmdPipelineBarrier2KHR") - set_proc_address(&CmdWriteTimestamp2KHR, "vkCmdWriteTimestamp2KHR") - set_proc_address(&QueueSubmit2KHR, "vkQueueSubmit2KHR") - set_proc_address(&CmdWriteBufferMarker2AMD, "vkCmdWriteBufferMarker2AMD") - set_proc_address(&GetQueueCheckpointData2NV, "vkGetQueueCheckpointData2NV") - set_proc_address(&CmdCopyBuffer2KHR, "vkCmdCopyBuffer2KHR") - set_proc_address(&CmdCopyImage2KHR, "vkCmdCopyImage2KHR") - set_proc_address(&CmdCopyBufferToImage2KHR, "vkCmdCopyBufferToImage2KHR") - set_proc_address(&CmdCopyImageToBuffer2KHR, "vkCmdCopyImageToBuffer2KHR") - set_proc_address(&CmdBlitImage2KHR, "vkCmdBlitImage2KHR") - set_proc_address(&CmdResolveImage2KHR, "vkCmdResolveImage2KHR") - set_proc_address(&DebugMarkerSetObjectTagEXT, "vkDebugMarkerSetObjectTagEXT") - set_proc_address(&DebugMarkerSetObjectNameEXT, "vkDebugMarkerSetObjectNameEXT") - set_proc_address(&CmdDebugMarkerBeginEXT, "vkCmdDebugMarkerBeginEXT") - set_proc_address(&CmdDebugMarkerEndEXT, "vkCmdDebugMarkerEndEXT") - set_proc_address(&CmdDebugMarkerInsertEXT, "vkCmdDebugMarkerInsertEXT") - set_proc_address(&CmdBindTransformFeedbackBuffersEXT, "vkCmdBindTransformFeedbackBuffersEXT") - set_proc_address(&CmdBeginTransformFeedbackEXT, "vkCmdBeginTransformFeedbackEXT") - set_proc_address(&CmdEndTransformFeedbackEXT, "vkCmdEndTransformFeedbackEXT") - set_proc_address(&CmdBeginQueryIndexedEXT, "vkCmdBeginQueryIndexedEXT") - set_proc_address(&CmdEndQueryIndexedEXT, "vkCmdEndQueryIndexedEXT") - set_proc_address(&CmdDrawIndirectByteCountEXT, "vkCmdDrawIndirectByteCountEXT") - set_proc_address(&CreateCuModuleNVX, "vkCreateCuModuleNVX") - set_proc_address(&CreateCuFunctionNVX, "vkCreateCuFunctionNVX") - set_proc_address(&DestroyCuModuleNVX, "vkDestroyCuModuleNVX") - set_proc_address(&DestroyCuFunctionNVX, "vkDestroyCuFunctionNVX") - set_proc_address(&CmdCuLaunchKernelNVX, "vkCmdCuLaunchKernelNVX") - set_proc_address(&GetImageViewHandleNVX, "vkGetImageViewHandleNVX") - set_proc_address(&GetImageViewAddressNVX, "vkGetImageViewAddressNVX") - set_proc_address(&CmdDrawIndirectCountAMD, "vkCmdDrawIndirectCountAMD") - set_proc_address(&CmdDrawIndexedIndirectCountAMD, "vkCmdDrawIndexedIndirectCountAMD") - set_proc_address(&GetShaderInfoAMD, "vkGetShaderInfoAMD") - set_proc_address(&CmdBeginConditionalRenderingEXT, "vkCmdBeginConditionalRenderingEXT") - set_proc_address(&CmdEndConditionalRenderingEXT, "vkCmdEndConditionalRenderingEXT") - set_proc_address(&CmdSetViewportWScalingNV, "vkCmdSetViewportWScalingNV") - set_proc_address(&DisplayPowerControlEXT, "vkDisplayPowerControlEXT") - set_proc_address(&RegisterDeviceEventEXT, "vkRegisterDeviceEventEXT") - set_proc_address(&RegisterDisplayEventEXT, "vkRegisterDisplayEventEXT") - set_proc_address(&GetSwapchainCounterEXT, "vkGetSwapchainCounterEXT") - set_proc_address(&GetRefreshCycleDurationGOOGLE, "vkGetRefreshCycleDurationGOOGLE") - set_proc_address(&GetPastPresentationTimingGOOGLE, "vkGetPastPresentationTimingGOOGLE") - set_proc_address(&CmdSetDiscardRectangleEXT, "vkCmdSetDiscardRectangleEXT") - set_proc_address(&SetHdrMetadataEXT, "vkSetHdrMetadataEXT") - set_proc_address(&SetDebugUtilsObjectNameEXT, "vkSetDebugUtilsObjectNameEXT") - set_proc_address(&SetDebugUtilsObjectTagEXT, "vkSetDebugUtilsObjectTagEXT") - set_proc_address(&QueueBeginDebugUtilsLabelEXT, "vkQueueBeginDebugUtilsLabelEXT") - set_proc_address(&QueueEndDebugUtilsLabelEXT, "vkQueueEndDebugUtilsLabelEXT") - set_proc_address(&QueueInsertDebugUtilsLabelEXT, "vkQueueInsertDebugUtilsLabelEXT") - set_proc_address(&CmdBeginDebugUtilsLabelEXT, "vkCmdBeginDebugUtilsLabelEXT") - set_proc_address(&CmdEndDebugUtilsLabelEXT, "vkCmdEndDebugUtilsLabelEXT") - set_proc_address(&CmdInsertDebugUtilsLabelEXT, "vkCmdInsertDebugUtilsLabelEXT") - set_proc_address(&CmdSetSampleLocationsEXT, "vkCmdSetSampleLocationsEXT") - set_proc_address(&GetImageDrmFormatModifierPropertiesEXT, "vkGetImageDrmFormatModifierPropertiesEXT") - set_proc_address(&CreateValidationCacheEXT, "vkCreateValidationCacheEXT") - set_proc_address(&DestroyValidationCacheEXT, "vkDestroyValidationCacheEXT") - set_proc_address(&MergeValidationCachesEXT, "vkMergeValidationCachesEXT") - set_proc_address(&GetValidationCacheDataEXT, "vkGetValidationCacheDataEXT") - set_proc_address(&CmdBindShadingRateImageNV, "vkCmdBindShadingRateImageNV") - set_proc_address(&CmdSetViewportShadingRatePaletteNV, "vkCmdSetViewportShadingRatePaletteNV") - set_proc_address(&CmdSetCoarseSampleOrderNV, "vkCmdSetCoarseSampleOrderNV") - set_proc_address(&CreateAccelerationStructureNV, "vkCreateAccelerationStructureNV") - set_proc_address(&DestroyAccelerationStructureNV, "vkDestroyAccelerationStructureNV") - set_proc_address(&GetAccelerationStructureMemoryRequirementsNV, "vkGetAccelerationStructureMemoryRequirementsNV") - set_proc_address(&BindAccelerationStructureMemoryNV, "vkBindAccelerationStructureMemoryNV") - set_proc_address(&CmdBuildAccelerationStructureNV, "vkCmdBuildAccelerationStructureNV") - set_proc_address(&CmdCopyAccelerationStructureNV, "vkCmdCopyAccelerationStructureNV") - set_proc_address(&CmdTraceRaysNV, "vkCmdTraceRaysNV") - set_proc_address(&CreateRayTracingPipelinesNV, "vkCreateRayTracingPipelinesNV") - set_proc_address(&GetRayTracingShaderGroupHandlesKHR, "vkGetRayTracingShaderGroupHandlesKHR") - set_proc_address(&GetRayTracingShaderGroupHandlesNV, "vkGetRayTracingShaderGroupHandlesNV") - set_proc_address(&GetAccelerationStructureHandleNV, "vkGetAccelerationStructureHandleNV") - set_proc_address(&CmdWriteAccelerationStructuresPropertiesNV, "vkCmdWriteAccelerationStructuresPropertiesNV") - set_proc_address(&CompileDeferredNV, "vkCompileDeferredNV") - set_proc_address(&GetMemoryHostPointerPropertiesEXT, "vkGetMemoryHostPointerPropertiesEXT") - set_proc_address(&CmdWriteBufferMarkerAMD, "vkCmdWriteBufferMarkerAMD") - set_proc_address(&GetCalibratedTimestampsEXT, "vkGetCalibratedTimestampsEXT") - set_proc_address(&CmdDrawMeshTasksNV, "vkCmdDrawMeshTasksNV") - set_proc_address(&CmdDrawMeshTasksIndirectNV, "vkCmdDrawMeshTasksIndirectNV") - set_proc_address(&CmdDrawMeshTasksIndirectCountNV, "vkCmdDrawMeshTasksIndirectCountNV") - set_proc_address(&CmdSetExclusiveScissorNV, "vkCmdSetExclusiveScissorNV") - set_proc_address(&CmdSetCheckpointNV, "vkCmdSetCheckpointNV") - set_proc_address(&GetQueueCheckpointDataNV, "vkGetQueueCheckpointDataNV") - set_proc_address(&InitializePerformanceApiINTEL, "vkInitializePerformanceApiINTEL") - set_proc_address(&UninitializePerformanceApiINTEL, "vkUninitializePerformanceApiINTEL") - set_proc_address(&CmdSetPerformanceMarkerINTEL, "vkCmdSetPerformanceMarkerINTEL") - set_proc_address(&CmdSetPerformanceStreamMarkerINTEL, "vkCmdSetPerformanceStreamMarkerINTEL") - set_proc_address(&CmdSetPerformanceOverrideINTEL, "vkCmdSetPerformanceOverrideINTEL") - set_proc_address(&AcquirePerformanceConfigurationINTEL, "vkAcquirePerformanceConfigurationINTEL") - set_proc_address(&ReleasePerformanceConfigurationINTEL, "vkReleasePerformanceConfigurationINTEL") - set_proc_address(&QueueSetPerformanceConfigurationINTEL, "vkQueueSetPerformanceConfigurationINTEL") - set_proc_address(&GetPerformanceParameterINTEL, "vkGetPerformanceParameterINTEL") - set_proc_address(&SetLocalDimmingAMD, "vkSetLocalDimmingAMD") - set_proc_address(&GetBufferDeviceAddressEXT, "vkGetBufferDeviceAddressEXT") - set_proc_address(&CmdSetLineStippleEXT, "vkCmdSetLineStippleEXT") - set_proc_address(&ResetQueryPoolEXT, "vkResetQueryPoolEXT") - set_proc_address(&CmdSetCullModeEXT, "vkCmdSetCullModeEXT") - set_proc_address(&CmdSetFrontFaceEXT, "vkCmdSetFrontFaceEXT") - set_proc_address(&CmdSetPrimitiveTopologyEXT, "vkCmdSetPrimitiveTopologyEXT") - set_proc_address(&CmdSetViewportWithCountEXT, "vkCmdSetViewportWithCountEXT") - set_proc_address(&CmdSetScissorWithCountEXT, "vkCmdSetScissorWithCountEXT") - set_proc_address(&CmdBindVertexBuffers2EXT, "vkCmdBindVertexBuffers2EXT") - set_proc_address(&CmdSetDepthTestEnableEXT, "vkCmdSetDepthTestEnableEXT") - set_proc_address(&CmdSetDepthWriteEnableEXT, "vkCmdSetDepthWriteEnableEXT") - set_proc_address(&CmdSetDepthCompareOpEXT, "vkCmdSetDepthCompareOpEXT") - set_proc_address(&CmdSetDepthBoundsTestEnableEXT, "vkCmdSetDepthBoundsTestEnableEXT") - set_proc_address(&CmdSetStencilTestEnableEXT, "vkCmdSetStencilTestEnableEXT") - set_proc_address(&CmdSetStencilOpEXT, "vkCmdSetStencilOpEXT") - set_proc_address(&GetGeneratedCommandsMemoryRequirementsNV, "vkGetGeneratedCommandsMemoryRequirementsNV") - set_proc_address(&CmdPreprocessGeneratedCommandsNV, "vkCmdPreprocessGeneratedCommandsNV") - set_proc_address(&CmdExecuteGeneratedCommandsNV, "vkCmdExecuteGeneratedCommandsNV") - set_proc_address(&CmdBindPipelineShaderGroupNV, "vkCmdBindPipelineShaderGroupNV") - set_proc_address(&CreateIndirectCommandsLayoutNV, "vkCreateIndirectCommandsLayoutNV") - set_proc_address(&DestroyIndirectCommandsLayoutNV, "vkDestroyIndirectCommandsLayoutNV") - set_proc_address(&CreatePrivateDataSlotEXT, "vkCreatePrivateDataSlotEXT") - set_proc_address(&DestroyPrivateDataSlotEXT, "vkDestroyPrivateDataSlotEXT") - set_proc_address(&SetPrivateDataEXT, "vkSetPrivateDataEXT") - set_proc_address(&GetPrivateDataEXT, "vkGetPrivateDataEXT") - set_proc_address(&CmdSetFragmentShadingRateEnumNV, "vkCmdSetFragmentShadingRateEnumNV") - set_proc_address(&CmdSetVertexInputEXT, "vkCmdSetVertexInputEXT") - set_proc_address(&GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI") - set_proc_address(&CmdSubpassShadingHUAWEI, "vkCmdSubpassShadingHUAWEI") - set_proc_address(&CmdBindInvocationMaskHUAWEI, "vkCmdBindInvocationMaskHUAWEI") - set_proc_address(&GetMemoryRemoteAddressNV, "vkGetMemoryRemoteAddressNV") - set_proc_address(&CmdSetPatchControlPointsEXT, "vkCmdSetPatchControlPointsEXT") - set_proc_address(&CmdSetRasterizerDiscardEnableEXT, "vkCmdSetRasterizerDiscardEnableEXT") - set_proc_address(&CmdSetDepthBiasEnableEXT, "vkCmdSetDepthBiasEnableEXT") - set_proc_address(&CmdSetLogicOpEXT, "vkCmdSetLogicOpEXT") - set_proc_address(&CmdSetPrimitiveRestartEnableEXT, "vkCmdSetPrimitiveRestartEnableEXT") - set_proc_address(&CmdDrawMultiEXT, "vkCmdDrawMultiEXT") - set_proc_address(&CmdDrawMultiIndexedEXT, "vkCmdDrawMultiIndexedEXT") - set_proc_address(&SetDeviceMemoryPriorityEXT, "vkSetDeviceMemoryPriorityEXT") - set_proc_address(&CreateAccelerationStructureKHR, "vkCreateAccelerationStructureKHR") - set_proc_address(&DestroyAccelerationStructureKHR, "vkDestroyAccelerationStructureKHR") - set_proc_address(&CmdBuildAccelerationStructuresKHR, "vkCmdBuildAccelerationStructuresKHR") - set_proc_address(&CmdBuildAccelerationStructuresIndirectKHR, "vkCmdBuildAccelerationStructuresIndirectKHR") - set_proc_address(&BuildAccelerationStructuresKHR, "vkBuildAccelerationStructuresKHR") - set_proc_address(&CopyAccelerationStructureKHR, "vkCopyAccelerationStructureKHR") - set_proc_address(&CopyAccelerationStructureToMemoryKHR, "vkCopyAccelerationStructureToMemoryKHR") - set_proc_address(&CopyMemoryToAccelerationStructureKHR, "vkCopyMemoryToAccelerationStructureKHR") - set_proc_address(&WriteAccelerationStructuresPropertiesKHR, "vkWriteAccelerationStructuresPropertiesKHR") - set_proc_address(&CmdCopyAccelerationStructureKHR, "vkCmdCopyAccelerationStructureKHR") - set_proc_address(&CmdCopyAccelerationStructureToMemoryKHR, "vkCmdCopyAccelerationStructureToMemoryKHR") - set_proc_address(&CmdCopyMemoryToAccelerationStructureKHR, "vkCmdCopyMemoryToAccelerationStructureKHR") - set_proc_address(&GetAccelerationStructureDeviceAddressKHR, "vkGetAccelerationStructureDeviceAddressKHR") - set_proc_address(&CmdWriteAccelerationStructuresPropertiesKHR, "vkCmdWriteAccelerationStructuresPropertiesKHR") - set_proc_address(&GetDeviceAccelerationStructureCompatibilityKHR, "vkGetDeviceAccelerationStructureCompatibilityKHR") - set_proc_address(&GetAccelerationStructureBuildSizesKHR, "vkGetAccelerationStructureBuildSizesKHR") - set_proc_address(&CmdTraceRaysKHR, "vkCmdTraceRaysKHR") - set_proc_address(&CreateRayTracingPipelinesKHR, "vkCreateRayTracingPipelinesKHR") - set_proc_address(&GetRayTracingCaptureReplayShaderGroupHandlesKHR, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR") - set_proc_address(&CmdTraceRaysIndirectKHR, "vkCmdTraceRaysIndirectKHR") - set_proc_address(&GetRayTracingShaderGroupStackSizeKHR, "vkGetRayTracingShaderGroupStackSizeKHR") - set_proc_address(&CmdSetRayTracingPipelineStackSizeKHR, "vkCmdSetRayTracingPipelineStackSizeKHR") - set_proc_address(&GetMemoryWin32HandleKHR, "vkGetMemoryWin32HandleKHR") - set_proc_address(&GetMemoryWin32HandlePropertiesKHR, "vkGetMemoryWin32HandlePropertiesKHR") - set_proc_address(&ImportSemaphoreWin32HandleKHR, "vkImportSemaphoreWin32HandleKHR") - set_proc_address(&GetSemaphoreWin32HandleKHR, "vkGetSemaphoreWin32HandleKHR") - set_proc_address(&ImportFenceWin32HandleKHR, "vkImportFenceWin32HandleKHR") - set_proc_address(&GetFenceWin32HandleKHR, "vkGetFenceWin32HandleKHR") - set_proc_address(&GetMemoryWin32HandleNV, "vkGetMemoryWin32HandleNV") - set_proc_address(&AcquireFullScreenExclusiveModeEXT, "vkAcquireFullScreenExclusiveModeEXT") - set_proc_address(&ReleaseFullScreenExclusiveModeEXT, "vkReleaseFullScreenExclusiveModeEXT") - set_proc_address(&GetDeviceGroupSurfacePresentModes2EXT, "vkGetDeviceGroupSurfacePresentModes2EXT") +// Device Procedures +AcquireFullScreenExclusiveModeEXT: ProcAcquireFullScreenExclusiveModeEXT +AcquireNextImage2KHR: ProcAcquireNextImage2KHR +AcquireNextImageKHR: ProcAcquireNextImageKHR +AcquirePerformanceConfigurationINTEL: ProcAcquirePerformanceConfigurationINTEL +AcquireProfilingLockKHR: ProcAcquireProfilingLockKHR +AllocateCommandBuffers: ProcAllocateCommandBuffers +AllocateDescriptorSets: ProcAllocateDescriptorSets +AllocateMemory: ProcAllocateMemory +BeginCommandBuffer: ProcBeginCommandBuffer +BindAccelerationStructureMemoryNV: ProcBindAccelerationStructureMemoryNV +BindBufferMemory: ProcBindBufferMemory +BindBufferMemory2: ProcBindBufferMemory2 +BindBufferMemory2KHR: ProcBindBufferMemory2KHR +BindImageMemory: ProcBindImageMemory +BindImageMemory2: ProcBindImageMemory2 +BindImageMemory2KHR: ProcBindImageMemory2KHR +BuildAccelerationStructuresKHR: ProcBuildAccelerationStructuresKHR +CmdBeginConditionalRenderingEXT: ProcCmdBeginConditionalRenderingEXT +CmdBeginDebugUtilsLabelEXT: ProcCmdBeginDebugUtilsLabelEXT +CmdBeginQuery: ProcCmdBeginQuery +CmdBeginQueryIndexedEXT: ProcCmdBeginQueryIndexedEXT +CmdBeginRenderPass: ProcCmdBeginRenderPass +CmdBeginRenderPass2: ProcCmdBeginRenderPass2 +CmdBeginRenderPass2KHR: ProcCmdBeginRenderPass2KHR +CmdBeginTransformFeedbackEXT: ProcCmdBeginTransformFeedbackEXT +CmdBindDescriptorSets: ProcCmdBindDescriptorSets +CmdBindIndexBuffer: ProcCmdBindIndexBuffer +CmdBindInvocationMaskHUAWEI: ProcCmdBindInvocationMaskHUAWEI +CmdBindPipeline: ProcCmdBindPipeline +CmdBindPipelineShaderGroupNV: ProcCmdBindPipelineShaderGroupNV +CmdBindShadingRateImageNV: ProcCmdBindShadingRateImageNV +CmdBindTransformFeedbackBuffersEXT: ProcCmdBindTransformFeedbackBuffersEXT +CmdBindVertexBuffers: ProcCmdBindVertexBuffers +CmdBindVertexBuffers2EXT: ProcCmdBindVertexBuffers2EXT +CmdBlitImage: ProcCmdBlitImage +CmdBlitImage2KHR: ProcCmdBlitImage2KHR +CmdBuildAccelerationStructureNV: ProcCmdBuildAccelerationStructureNV +CmdBuildAccelerationStructuresIndirectKHR: ProcCmdBuildAccelerationStructuresIndirectKHR +CmdBuildAccelerationStructuresKHR: ProcCmdBuildAccelerationStructuresKHR +CmdClearAttachments: ProcCmdClearAttachments +CmdClearColorImage: ProcCmdClearColorImage +CmdClearDepthStencilImage: ProcCmdClearDepthStencilImage +CmdCopyAccelerationStructureKHR: ProcCmdCopyAccelerationStructureKHR +CmdCopyAccelerationStructureNV: ProcCmdCopyAccelerationStructureNV +CmdCopyAccelerationStructureToMemoryKHR: ProcCmdCopyAccelerationStructureToMemoryKHR +CmdCopyBuffer: ProcCmdCopyBuffer +CmdCopyBuffer2KHR: ProcCmdCopyBuffer2KHR +CmdCopyBufferToImage: ProcCmdCopyBufferToImage +CmdCopyBufferToImage2KHR: ProcCmdCopyBufferToImage2KHR +CmdCopyImage: ProcCmdCopyImage +CmdCopyImage2KHR: ProcCmdCopyImage2KHR +CmdCopyImageToBuffer: ProcCmdCopyImageToBuffer +CmdCopyImageToBuffer2KHR: ProcCmdCopyImageToBuffer2KHR +CmdCopyMemoryToAccelerationStructureKHR: ProcCmdCopyMemoryToAccelerationStructureKHR +CmdCopyQueryPoolResults: ProcCmdCopyQueryPoolResults +CmdCuLaunchKernelNVX: ProcCmdCuLaunchKernelNVX +CmdDebugMarkerBeginEXT: ProcCmdDebugMarkerBeginEXT +CmdDebugMarkerEndEXT: ProcCmdDebugMarkerEndEXT +CmdDebugMarkerInsertEXT: ProcCmdDebugMarkerInsertEXT +CmdDispatch: ProcCmdDispatch +CmdDispatchBase: ProcCmdDispatchBase +CmdDispatchBaseKHR: ProcCmdDispatchBaseKHR +CmdDispatchIndirect: ProcCmdDispatchIndirect +CmdDraw: ProcCmdDraw +CmdDrawIndexed: ProcCmdDrawIndexed +CmdDrawIndexedIndirect: ProcCmdDrawIndexedIndirect +CmdDrawIndexedIndirectCount: ProcCmdDrawIndexedIndirectCount +CmdDrawIndexedIndirectCountAMD: ProcCmdDrawIndexedIndirectCountAMD +CmdDrawIndexedIndirectCountKHR: ProcCmdDrawIndexedIndirectCountKHR +CmdDrawIndirect: ProcCmdDrawIndirect +CmdDrawIndirectByteCountEXT: ProcCmdDrawIndirectByteCountEXT +CmdDrawIndirectCount: ProcCmdDrawIndirectCount +CmdDrawIndirectCountAMD: ProcCmdDrawIndirectCountAMD +CmdDrawIndirectCountKHR: ProcCmdDrawIndirectCountKHR +CmdDrawMeshTasksIndirectCountNV: ProcCmdDrawMeshTasksIndirectCountNV +CmdDrawMeshTasksIndirectNV: ProcCmdDrawMeshTasksIndirectNV +CmdDrawMeshTasksNV: ProcCmdDrawMeshTasksNV +CmdDrawMultiEXT: ProcCmdDrawMultiEXT +CmdDrawMultiIndexedEXT: ProcCmdDrawMultiIndexedEXT +CmdEndConditionalRenderingEXT: ProcCmdEndConditionalRenderingEXT +CmdEndDebugUtilsLabelEXT: ProcCmdEndDebugUtilsLabelEXT +CmdEndQuery: ProcCmdEndQuery +CmdEndQueryIndexedEXT: ProcCmdEndQueryIndexedEXT +CmdEndRenderPass: ProcCmdEndRenderPass +CmdEndRenderPass2: ProcCmdEndRenderPass2 +CmdEndRenderPass2KHR: ProcCmdEndRenderPass2KHR +CmdEndTransformFeedbackEXT: ProcCmdEndTransformFeedbackEXT +CmdExecuteCommands: ProcCmdExecuteCommands +CmdExecuteGeneratedCommandsNV: ProcCmdExecuteGeneratedCommandsNV +CmdFillBuffer: ProcCmdFillBuffer +CmdInsertDebugUtilsLabelEXT: ProcCmdInsertDebugUtilsLabelEXT +CmdNextSubpass: ProcCmdNextSubpass +CmdNextSubpass2: ProcCmdNextSubpass2 +CmdNextSubpass2KHR: ProcCmdNextSubpass2KHR +CmdPipelineBarrier: ProcCmdPipelineBarrier +CmdPipelineBarrier2KHR: ProcCmdPipelineBarrier2KHR +CmdPreprocessGeneratedCommandsNV: ProcCmdPreprocessGeneratedCommandsNV +CmdPushConstants: ProcCmdPushConstants +CmdPushDescriptorSetKHR: ProcCmdPushDescriptorSetKHR +CmdPushDescriptorSetWithTemplateKHR: ProcCmdPushDescriptorSetWithTemplateKHR +CmdResetEvent: ProcCmdResetEvent +CmdResetEvent2KHR: ProcCmdResetEvent2KHR +CmdResetQueryPool: ProcCmdResetQueryPool +CmdResolveImage: ProcCmdResolveImage +CmdResolveImage2KHR: ProcCmdResolveImage2KHR +CmdSetBlendConstants: ProcCmdSetBlendConstants +CmdSetCheckpointNV: ProcCmdSetCheckpointNV +CmdSetCoarseSampleOrderNV: ProcCmdSetCoarseSampleOrderNV +CmdSetCullModeEXT: ProcCmdSetCullModeEXT +CmdSetDepthBias: ProcCmdSetDepthBias +CmdSetDepthBiasEnableEXT: ProcCmdSetDepthBiasEnableEXT +CmdSetDepthBounds: ProcCmdSetDepthBounds +CmdSetDepthBoundsTestEnableEXT: ProcCmdSetDepthBoundsTestEnableEXT +CmdSetDepthCompareOpEXT: ProcCmdSetDepthCompareOpEXT +CmdSetDepthTestEnableEXT: ProcCmdSetDepthTestEnableEXT +CmdSetDepthWriteEnableEXT: ProcCmdSetDepthWriteEnableEXT +CmdSetDeviceMask: ProcCmdSetDeviceMask +CmdSetDeviceMaskKHR: ProcCmdSetDeviceMaskKHR +CmdSetDiscardRectangleEXT: ProcCmdSetDiscardRectangleEXT +CmdSetEvent: ProcCmdSetEvent +CmdSetEvent2KHR: ProcCmdSetEvent2KHR +CmdSetExclusiveScissorNV: ProcCmdSetExclusiveScissorNV +CmdSetFragmentShadingRateEnumNV: ProcCmdSetFragmentShadingRateEnumNV +CmdSetFragmentShadingRateKHR: ProcCmdSetFragmentShadingRateKHR +CmdSetFrontFaceEXT: ProcCmdSetFrontFaceEXT +CmdSetLineStippleEXT: ProcCmdSetLineStippleEXT +CmdSetLineWidth: ProcCmdSetLineWidth +CmdSetLogicOpEXT: ProcCmdSetLogicOpEXT +CmdSetPatchControlPointsEXT: ProcCmdSetPatchControlPointsEXT +CmdSetPerformanceMarkerINTEL: ProcCmdSetPerformanceMarkerINTEL +CmdSetPerformanceOverrideINTEL: ProcCmdSetPerformanceOverrideINTEL +CmdSetPerformanceStreamMarkerINTEL: ProcCmdSetPerformanceStreamMarkerINTEL +CmdSetPrimitiveRestartEnableEXT: ProcCmdSetPrimitiveRestartEnableEXT +CmdSetPrimitiveTopologyEXT: ProcCmdSetPrimitiveTopologyEXT +CmdSetRasterizerDiscardEnableEXT: ProcCmdSetRasterizerDiscardEnableEXT +CmdSetRayTracingPipelineStackSizeKHR: ProcCmdSetRayTracingPipelineStackSizeKHR +CmdSetSampleLocationsEXT: ProcCmdSetSampleLocationsEXT +CmdSetScissor: ProcCmdSetScissor +CmdSetScissorWithCountEXT: ProcCmdSetScissorWithCountEXT +CmdSetStencilCompareMask: ProcCmdSetStencilCompareMask +CmdSetStencilOpEXT: ProcCmdSetStencilOpEXT +CmdSetStencilReference: ProcCmdSetStencilReference +CmdSetStencilTestEnableEXT: ProcCmdSetStencilTestEnableEXT +CmdSetStencilWriteMask: ProcCmdSetStencilWriteMask +CmdSetVertexInputEXT: ProcCmdSetVertexInputEXT +CmdSetViewport: ProcCmdSetViewport +CmdSetViewportShadingRatePaletteNV: ProcCmdSetViewportShadingRatePaletteNV +CmdSetViewportWScalingNV: ProcCmdSetViewportWScalingNV +CmdSetViewportWithCountEXT: ProcCmdSetViewportWithCountEXT +CmdSubpassShadingHUAWEI: ProcCmdSubpassShadingHUAWEI +CmdTraceRaysIndirectKHR: ProcCmdTraceRaysIndirectKHR +CmdTraceRaysKHR: ProcCmdTraceRaysKHR +CmdTraceRaysNV: ProcCmdTraceRaysNV +CmdUpdateBuffer: ProcCmdUpdateBuffer +CmdWaitEvents: ProcCmdWaitEvents +CmdWaitEvents2KHR: ProcCmdWaitEvents2KHR +CmdWriteAccelerationStructuresPropertiesKHR: ProcCmdWriteAccelerationStructuresPropertiesKHR +CmdWriteAccelerationStructuresPropertiesNV: ProcCmdWriteAccelerationStructuresPropertiesNV +CmdWriteBufferMarker2AMD: ProcCmdWriteBufferMarker2AMD +CmdWriteBufferMarkerAMD: ProcCmdWriteBufferMarkerAMD +CmdWriteTimestamp: ProcCmdWriteTimestamp +CmdWriteTimestamp2KHR: ProcCmdWriteTimestamp2KHR +CompileDeferredNV: ProcCompileDeferredNV +CopyAccelerationStructureKHR: ProcCopyAccelerationStructureKHR +CopyAccelerationStructureToMemoryKHR: ProcCopyAccelerationStructureToMemoryKHR +CopyMemoryToAccelerationStructureKHR: ProcCopyMemoryToAccelerationStructureKHR +CreateAccelerationStructureKHR: ProcCreateAccelerationStructureKHR +CreateAccelerationStructureNV: ProcCreateAccelerationStructureNV +CreateBuffer: ProcCreateBuffer +CreateBufferView: ProcCreateBufferView +CreateCommandPool: ProcCreateCommandPool +CreateComputePipelines: ProcCreateComputePipelines +CreateCuFunctionNVX: ProcCreateCuFunctionNVX +CreateCuModuleNVX: ProcCreateCuModuleNVX +CreateDeferredOperationKHR: ProcCreateDeferredOperationKHR +CreateDescriptorPool: ProcCreateDescriptorPool +CreateDescriptorSetLayout: ProcCreateDescriptorSetLayout +CreateDescriptorUpdateTemplate: ProcCreateDescriptorUpdateTemplate +CreateDescriptorUpdateTemplateKHR: ProcCreateDescriptorUpdateTemplateKHR +CreateEvent: ProcCreateEvent +CreateFence: ProcCreateFence +CreateFramebuffer: ProcCreateFramebuffer +CreateGraphicsPipelines: ProcCreateGraphicsPipelines +CreateImage: ProcCreateImage +CreateImageView: ProcCreateImageView +CreateIndirectCommandsLayoutNV: ProcCreateIndirectCommandsLayoutNV +CreatePipelineCache: ProcCreatePipelineCache +CreatePipelineLayout: ProcCreatePipelineLayout +CreatePrivateDataSlotEXT: ProcCreatePrivateDataSlotEXT +CreateQueryPool: ProcCreateQueryPool +CreateRayTracingPipelinesKHR: ProcCreateRayTracingPipelinesKHR +CreateRayTracingPipelinesNV: ProcCreateRayTracingPipelinesNV +CreateRenderPass: ProcCreateRenderPass +CreateRenderPass2: ProcCreateRenderPass2 +CreateRenderPass2KHR: ProcCreateRenderPass2KHR +CreateSampler: ProcCreateSampler +CreateSamplerYcbcrConversion: ProcCreateSamplerYcbcrConversion +CreateSamplerYcbcrConversionKHR: ProcCreateSamplerYcbcrConversionKHR +CreateSemaphore: ProcCreateSemaphore +CreateShaderModule: ProcCreateShaderModule +CreateSharedSwapchainsKHR: ProcCreateSharedSwapchainsKHR +CreateSwapchainKHR: ProcCreateSwapchainKHR +CreateValidationCacheEXT: ProcCreateValidationCacheEXT +DebugMarkerSetObjectNameEXT: ProcDebugMarkerSetObjectNameEXT +DebugMarkerSetObjectTagEXT: ProcDebugMarkerSetObjectTagEXT +DeferredOperationJoinKHR: ProcDeferredOperationJoinKHR +DestroyAccelerationStructureKHR: ProcDestroyAccelerationStructureKHR +DestroyAccelerationStructureNV: ProcDestroyAccelerationStructureNV +DestroyBuffer: ProcDestroyBuffer +DestroyBufferView: ProcDestroyBufferView +DestroyCommandPool: ProcDestroyCommandPool +DestroyCuFunctionNVX: ProcDestroyCuFunctionNVX +DestroyCuModuleNVX: ProcDestroyCuModuleNVX +DestroyDeferredOperationKHR: ProcDestroyDeferredOperationKHR +DestroyDescriptorPool: ProcDestroyDescriptorPool +DestroyDescriptorSetLayout: ProcDestroyDescriptorSetLayout +DestroyDescriptorUpdateTemplate: ProcDestroyDescriptorUpdateTemplate +DestroyDescriptorUpdateTemplateKHR: ProcDestroyDescriptorUpdateTemplateKHR +DestroyDevice: ProcDestroyDevice +DestroyEvent: ProcDestroyEvent +DestroyFence: ProcDestroyFence +DestroyFramebuffer: ProcDestroyFramebuffer +DestroyImage: ProcDestroyImage +DestroyImageView: ProcDestroyImageView +DestroyIndirectCommandsLayoutNV: ProcDestroyIndirectCommandsLayoutNV +DestroyPipeline: ProcDestroyPipeline +DestroyPipelineCache: ProcDestroyPipelineCache +DestroyPipelineLayout: ProcDestroyPipelineLayout +DestroyPrivateDataSlotEXT: ProcDestroyPrivateDataSlotEXT +DestroyQueryPool: ProcDestroyQueryPool +DestroyRenderPass: ProcDestroyRenderPass +DestroySampler: ProcDestroySampler +DestroySamplerYcbcrConversion: ProcDestroySamplerYcbcrConversion +DestroySamplerYcbcrConversionKHR: ProcDestroySamplerYcbcrConversionKHR +DestroySemaphore: ProcDestroySemaphore +DestroyShaderModule: ProcDestroyShaderModule +DestroySwapchainKHR: ProcDestroySwapchainKHR +DestroyValidationCacheEXT: ProcDestroyValidationCacheEXT +DeviceWaitIdle: ProcDeviceWaitIdle +DisplayPowerControlEXT: ProcDisplayPowerControlEXT +EndCommandBuffer: ProcEndCommandBuffer +FlushMappedMemoryRanges: ProcFlushMappedMemoryRanges +FreeCommandBuffers: ProcFreeCommandBuffers +FreeDescriptorSets: ProcFreeDescriptorSets +FreeMemory: ProcFreeMemory +GetAccelerationStructureBuildSizesKHR: ProcGetAccelerationStructureBuildSizesKHR +GetAccelerationStructureDeviceAddressKHR: ProcGetAccelerationStructureDeviceAddressKHR +GetAccelerationStructureHandleNV: ProcGetAccelerationStructureHandleNV +GetAccelerationStructureMemoryRequirementsNV: ProcGetAccelerationStructureMemoryRequirementsNV +GetBufferDeviceAddress: ProcGetBufferDeviceAddress +GetBufferDeviceAddressEXT: ProcGetBufferDeviceAddressEXT +GetBufferDeviceAddressKHR: ProcGetBufferDeviceAddressKHR +GetBufferMemoryRequirements: ProcGetBufferMemoryRequirements +GetBufferMemoryRequirements2: ProcGetBufferMemoryRequirements2 +GetBufferMemoryRequirements2KHR: ProcGetBufferMemoryRequirements2KHR +GetBufferOpaqueCaptureAddress: ProcGetBufferOpaqueCaptureAddress +GetBufferOpaqueCaptureAddressKHR: ProcGetBufferOpaqueCaptureAddressKHR +GetCalibratedTimestampsEXT: ProcGetCalibratedTimestampsEXT +GetDeferredOperationMaxConcurrencyKHR: ProcGetDeferredOperationMaxConcurrencyKHR +GetDeferredOperationResultKHR: ProcGetDeferredOperationResultKHR +GetDescriptorSetLayoutSupport: ProcGetDescriptorSetLayoutSupport +GetDescriptorSetLayoutSupportKHR: ProcGetDescriptorSetLayoutSupportKHR +GetDeviceAccelerationStructureCompatibilityKHR: ProcGetDeviceAccelerationStructureCompatibilityKHR +GetDeviceGroupPeerMemoryFeatures: ProcGetDeviceGroupPeerMemoryFeatures +GetDeviceGroupPeerMemoryFeaturesKHR: ProcGetDeviceGroupPeerMemoryFeaturesKHR +GetDeviceGroupPresentCapabilitiesKHR: ProcGetDeviceGroupPresentCapabilitiesKHR +GetDeviceGroupSurfacePresentModes2EXT: ProcGetDeviceGroupSurfacePresentModes2EXT +GetDeviceGroupSurfacePresentModesKHR: ProcGetDeviceGroupSurfacePresentModesKHR +GetDeviceMemoryCommitment: ProcGetDeviceMemoryCommitment +GetDeviceMemoryOpaqueCaptureAddress: ProcGetDeviceMemoryOpaqueCaptureAddress +GetDeviceMemoryOpaqueCaptureAddressKHR: ProcGetDeviceMemoryOpaqueCaptureAddressKHR +GetDeviceProcAddr: ProcGetDeviceProcAddr +GetDeviceQueue: ProcGetDeviceQueue +GetDeviceQueue2: ProcGetDeviceQueue2 +GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI: ProcGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI +GetEventStatus: ProcGetEventStatus +GetFenceFdKHR: ProcGetFenceFdKHR +GetFenceStatus: ProcGetFenceStatus +GetFenceWin32HandleKHR: ProcGetFenceWin32HandleKHR +GetGeneratedCommandsMemoryRequirementsNV: ProcGetGeneratedCommandsMemoryRequirementsNV +GetImageDrmFormatModifierPropertiesEXT: ProcGetImageDrmFormatModifierPropertiesEXT +GetImageMemoryRequirements: ProcGetImageMemoryRequirements +GetImageMemoryRequirements2: ProcGetImageMemoryRequirements2 +GetImageMemoryRequirements2KHR: ProcGetImageMemoryRequirements2KHR +GetImageSparseMemoryRequirements: ProcGetImageSparseMemoryRequirements +GetImageSparseMemoryRequirements2: ProcGetImageSparseMemoryRequirements2 +GetImageSparseMemoryRequirements2KHR: ProcGetImageSparseMemoryRequirements2KHR +GetImageSubresourceLayout: ProcGetImageSubresourceLayout +GetImageViewAddressNVX: ProcGetImageViewAddressNVX +GetImageViewHandleNVX: ProcGetImageViewHandleNVX +GetMemoryFdKHR: ProcGetMemoryFdKHR +GetMemoryFdPropertiesKHR: ProcGetMemoryFdPropertiesKHR +GetMemoryHostPointerPropertiesEXT: ProcGetMemoryHostPointerPropertiesEXT +GetMemoryRemoteAddressNV: ProcGetMemoryRemoteAddressNV +GetMemoryWin32HandleKHR: ProcGetMemoryWin32HandleKHR +GetMemoryWin32HandleNV: ProcGetMemoryWin32HandleNV +GetMemoryWin32HandlePropertiesKHR: ProcGetMemoryWin32HandlePropertiesKHR +GetPastPresentationTimingGOOGLE: ProcGetPastPresentationTimingGOOGLE +GetPerformanceParameterINTEL: ProcGetPerformanceParameterINTEL +GetPipelineCacheData: ProcGetPipelineCacheData +GetPipelineExecutableInternalRepresentationsKHR: ProcGetPipelineExecutableInternalRepresentationsKHR +GetPipelineExecutablePropertiesKHR: ProcGetPipelineExecutablePropertiesKHR +GetPipelineExecutableStatisticsKHR: ProcGetPipelineExecutableStatisticsKHR +GetPrivateDataEXT: ProcGetPrivateDataEXT +GetQueryPoolResults: ProcGetQueryPoolResults +GetQueueCheckpointData2NV: ProcGetQueueCheckpointData2NV +GetQueueCheckpointDataNV: ProcGetQueueCheckpointDataNV +GetRayTracingCaptureReplayShaderGroupHandlesKHR: ProcGetRayTracingCaptureReplayShaderGroupHandlesKHR +GetRayTracingShaderGroupHandlesKHR: ProcGetRayTracingShaderGroupHandlesKHR +GetRayTracingShaderGroupHandlesNV: ProcGetRayTracingShaderGroupHandlesNV +GetRayTracingShaderGroupStackSizeKHR: ProcGetRayTracingShaderGroupStackSizeKHR +GetRefreshCycleDurationGOOGLE: ProcGetRefreshCycleDurationGOOGLE +GetRenderAreaGranularity: ProcGetRenderAreaGranularity +GetSemaphoreCounterValue: ProcGetSemaphoreCounterValue +GetSemaphoreCounterValueKHR: ProcGetSemaphoreCounterValueKHR +GetSemaphoreFdKHR: ProcGetSemaphoreFdKHR +GetSemaphoreWin32HandleKHR: ProcGetSemaphoreWin32HandleKHR +GetShaderInfoAMD: ProcGetShaderInfoAMD +GetSwapchainCounterEXT: ProcGetSwapchainCounterEXT +GetSwapchainImagesKHR: ProcGetSwapchainImagesKHR +GetSwapchainStatusKHR: ProcGetSwapchainStatusKHR +GetValidationCacheDataEXT: ProcGetValidationCacheDataEXT +ImportFenceFdKHR: ProcImportFenceFdKHR +ImportFenceWin32HandleKHR: ProcImportFenceWin32HandleKHR +ImportSemaphoreFdKHR: ProcImportSemaphoreFdKHR +ImportSemaphoreWin32HandleKHR: ProcImportSemaphoreWin32HandleKHR +InitializePerformanceApiINTEL: ProcInitializePerformanceApiINTEL +InvalidateMappedMemoryRanges: ProcInvalidateMappedMemoryRanges +MapMemory: ProcMapMemory +MergePipelineCaches: ProcMergePipelineCaches +MergeValidationCachesEXT: ProcMergeValidationCachesEXT +QueueBeginDebugUtilsLabelEXT: ProcQueueBeginDebugUtilsLabelEXT +QueueBindSparse: ProcQueueBindSparse +QueueEndDebugUtilsLabelEXT: ProcQueueEndDebugUtilsLabelEXT +QueueInsertDebugUtilsLabelEXT: ProcQueueInsertDebugUtilsLabelEXT +QueuePresentKHR: ProcQueuePresentKHR +QueueSetPerformanceConfigurationINTEL: ProcQueueSetPerformanceConfigurationINTEL +QueueSubmit: ProcQueueSubmit +QueueSubmit2KHR: ProcQueueSubmit2KHR +QueueWaitIdle: ProcQueueWaitIdle +RegisterDeviceEventEXT: ProcRegisterDeviceEventEXT +RegisterDisplayEventEXT: ProcRegisterDisplayEventEXT +ReleaseFullScreenExclusiveModeEXT: ProcReleaseFullScreenExclusiveModeEXT +ReleasePerformanceConfigurationINTEL: ProcReleasePerformanceConfigurationINTEL +ReleaseProfilingLockKHR: ProcReleaseProfilingLockKHR +ResetCommandBuffer: ProcResetCommandBuffer +ResetCommandPool: ProcResetCommandPool +ResetDescriptorPool: ProcResetDescriptorPool +ResetEvent: ProcResetEvent +ResetFences: ProcResetFences +ResetQueryPool: ProcResetQueryPool +ResetQueryPoolEXT: ProcResetQueryPoolEXT +SetDebugUtilsObjectNameEXT: ProcSetDebugUtilsObjectNameEXT +SetDebugUtilsObjectTagEXT: ProcSetDebugUtilsObjectTagEXT +SetDeviceMemoryPriorityEXT: ProcSetDeviceMemoryPriorityEXT +SetEvent: ProcSetEvent +SetHdrMetadataEXT: ProcSetHdrMetadataEXT +SetLocalDimmingAMD: ProcSetLocalDimmingAMD +SetPrivateDataEXT: ProcSetPrivateDataEXT +SignalSemaphore: ProcSignalSemaphore +SignalSemaphoreKHR: ProcSignalSemaphoreKHR +TrimCommandPool: ProcTrimCommandPool +TrimCommandPoolKHR: ProcTrimCommandPoolKHR +UninitializePerformanceApiINTEL: ProcUninitializePerformanceApiINTEL +UnmapMemory: ProcUnmapMemory +UpdateDescriptorSetWithTemplate: ProcUpdateDescriptorSetWithTemplate +UpdateDescriptorSetWithTemplateKHR: ProcUpdateDescriptorSetWithTemplateKHR +UpdateDescriptorSets: ProcUpdateDescriptorSets +WaitForFences: ProcWaitForFences +WaitForPresentKHR: ProcWaitForPresentKHR +WaitSemaphores: ProcWaitSemaphores +WaitSemaphoresKHR: ProcWaitSemaphoresKHR +WriteAccelerationStructuresPropertiesKHR: ProcWriteAccelerationStructuresPropertiesKHR +load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { // Loader Procedures set_proc_address(&CreateInstance, "vkCreateInstance") + set_proc_address(&DebugUtilsMessengerCallbackEXT, "vkDebugUtilsMessengerCallbackEXT") + set_proc_address(&DeviceMemoryReportCallbackEXT, "vkDeviceMemoryReportCallbackEXT") set_proc_address(&EnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties") set_proc_address(&EnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties") set_proc_address(&EnumerateInstanceVersion, "vkEnumerateInstanceVersion") - set_proc_address(&DebugUtilsMessengerCallbackEXT, "vkDebugUtilsMessengerCallbackEXT") - set_proc_address(&DeviceMemoryReportCallbackEXT, "vkDeviceMemoryReportCallbackEXT") + + // Instance Procedures + set_proc_address(&AcquireDrmDisplayEXT, "vkAcquireDrmDisplayEXT") + set_proc_address(&AcquireWinrtDisplayNV, "vkAcquireWinrtDisplayNV") + set_proc_address(&CreateDebugReportCallbackEXT, "vkCreateDebugReportCallbackEXT") + set_proc_address(&CreateDebugUtilsMessengerEXT, "vkCreateDebugUtilsMessengerEXT") + set_proc_address(&CreateDevice, "vkCreateDevice") + set_proc_address(&CreateDisplayModeKHR, "vkCreateDisplayModeKHR") + set_proc_address(&CreateDisplayPlaneSurfaceKHR, "vkCreateDisplayPlaneSurfaceKHR") + set_proc_address(&CreateHeadlessSurfaceEXT, "vkCreateHeadlessSurfaceEXT") + set_proc_address(&CreateIOSSurfaceMVK, "vkCreateIOSSurfaceMVK") + set_proc_address(&CreateMacOSSurfaceMVK, "vkCreateMacOSSurfaceMVK") + set_proc_address(&CreateMetalSurfaceEXT, "vkCreateMetalSurfaceEXT") + set_proc_address(&CreateWin32SurfaceKHR, "vkCreateWin32SurfaceKHR") + set_proc_address(&DebugReportMessageEXT, "vkDebugReportMessageEXT") + set_proc_address(&DestroyDebugReportCallbackEXT, "vkDestroyDebugReportCallbackEXT") + set_proc_address(&DestroyDebugUtilsMessengerEXT, "vkDestroyDebugUtilsMessengerEXT") + set_proc_address(&DestroyInstance, "vkDestroyInstance") + set_proc_address(&DestroySurfaceKHR, "vkDestroySurfaceKHR") + set_proc_address(&EnumerateDeviceExtensionProperties, "vkEnumerateDeviceExtensionProperties") + set_proc_address(&EnumerateDeviceLayerProperties, "vkEnumerateDeviceLayerProperties") + set_proc_address(&EnumeratePhysicalDeviceGroups, "vkEnumeratePhysicalDeviceGroups") + set_proc_address(&EnumeratePhysicalDeviceGroupsKHR, "vkEnumeratePhysicalDeviceGroupsKHR") + set_proc_address(&EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR") + set_proc_address(&EnumeratePhysicalDevices, "vkEnumeratePhysicalDevices") + set_proc_address(&GetDisplayModeProperties2KHR, "vkGetDisplayModeProperties2KHR") + set_proc_address(&GetDisplayModePropertiesKHR, "vkGetDisplayModePropertiesKHR") + set_proc_address(&GetDisplayPlaneCapabilities2KHR, "vkGetDisplayPlaneCapabilities2KHR") + set_proc_address(&GetDisplayPlaneCapabilitiesKHR, "vkGetDisplayPlaneCapabilitiesKHR") + set_proc_address(&GetDisplayPlaneSupportedDisplaysKHR, "vkGetDisplayPlaneSupportedDisplaysKHR") + set_proc_address(&GetDrmDisplayEXT, "vkGetDrmDisplayEXT") + set_proc_address(&GetInstanceProcAddr, "vkGetInstanceProcAddr") + set_proc_address(&GetPhysicalDeviceCalibrateableTimeDomainsEXT, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT") + set_proc_address(&GetPhysicalDeviceCooperativeMatrixPropertiesNV, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV") + set_proc_address(&GetPhysicalDeviceDisplayPlaneProperties2KHR, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR") + set_proc_address(&GetPhysicalDeviceDisplayPlanePropertiesKHR, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR") + set_proc_address(&GetPhysicalDeviceDisplayProperties2KHR, "vkGetPhysicalDeviceDisplayProperties2KHR") + set_proc_address(&GetPhysicalDeviceDisplayPropertiesKHR, "vkGetPhysicalDeviceDisplayPropertiesKHR") + set_proc_address(&GetPhysicalDeviceExternalBufferProperties, "vkGetPhysicalDeviceExternalBufferProperties") + set_proc_address(&GetPhysicalDeviceExternalBufferPropertiesKHR, "vkGetPhysicalDeviceExternalBufferPropertiesKHR") + set_proc_address(&GetPhysicalDeviceExternalFenceProperties, "vkGetPhysicalDeviceExternalFenceProperties") + set_proc_address(&GetPhysicalDeviceExternalFencePropertiesKHR, "vkGetPhysicalDeviceExternalFencePropertiesKHR") + set_proc_address(&GetPhysicalDeviceExternalImageFormatPropertiesNV, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV") + set_proc_address(&GetPhysicalDeviceExternalSemaphoreProperties, "vkGetPhysicalDeviceExternalSemaphoreProperties") + set_proc_address(&GetPhysicalDeviceExternalSemaphorePropertiesKHR, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR") + set_proc_address(&GetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures") + set_proc_address(&GetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2") + set_proc_address(&GetPhysicalDeviceFeatures2KHR, "vkGetPhysicalDeviceFeatures2KHR") + set_proc_address(&GetPhysicalDeviceFormatProperties, "vkGetPhysicalDeviceFormatProperties") + set_proc_address(&GetPhysicalDeviceFormatProperties2, "vkGetPhysicalDeviceFormatProperties2") + set_proc_address(&GetPhysicalDeviceFormatProperties2KHR, "vkGetPhysicalDeviceFormatProperties2KHR") + set_proc_address(&GetPhysicalDeviceFragmentShadingRatesKHR, "vkGetPhysicalDeviceFragmentShadingRatesKHR") + set_proc_address(&GetPhysicalDeviceImageFormatProperties, "vkGetPhysicalDeviceImageFormatProperties") + set_proc_address(&GetPhysicalDeviceImageFormatProperties2, "vkGetPhysicalDeviceImageFormatProperties2") + set_proc_address(&GetPhysicalDeviceImageFormatProperties2KHR, "vkGetPhysicalDeviceImageFormatProperties2KHR") + set_proc_address(&GetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties") + set_proc_address(&GetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2") + set_proc_address(&GetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR") + set_proc_address(&GetPhysicalDeviceMultisamplePropertiesEXT, "vkGetPhysicalDeviceMultisamplePropertiesEXT") + set_proc_address(&GetPhysicalDevicePresentRectanglesKHR, "vkGetPhysicalDevicePresentRectanglesKHR") + set_proc_address(&GetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties") + set_proc_address(&GetPhysicalDeviceProperties2, "vkGetPhysicalDeviceProperties2") + set_proc_address(&GetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2KHR") + set_proc_address(&GetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR") + set_proc_address(&GetPhysicalDeviceQueueFamilyProperties, "vkGetPhysicalDeviceQueueFamilyProperties") + set_proc_address(&GetPhysicalDeviceQueueFamilyProperties2, "vkGetPhysicalDeviceQueueFamilyProperties2") + set_proc_address(&GetPhysicalDeviceQueueFamilyProperties2KHR, "vkGetPhysicalDeviceQueueFamilyProperties2KHR") + set_proc_address(&GetPhysicalDeviceSparseImageFormatProperties, "vkGetPhysicalDeviceSparseImageFormatProperties") + set_proc_address(&GetPhysicalDeviceSparseImageFormatProperties2, "vkGetPhysicalDeviceSparseImageFormatProperties2") + set_proc_address(&GetPhysicalDeviceSparseImageFormatProperties2KHR, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR") + set_proc_address(&GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV") + set_proc_address(&GetPhysicalDeviceSurfaceCapabilities2EXT, "vkGetPhysicalDeviceSurfaceCapabilities2EXT") + set_proc_address(&GetPhysicalDeviceSurfaceCapabilities2KHR, "vkGetPhysicalDeviceSurfaceCapabilities2KHR") + set_proc_address(&GetPhysicalDeviceSurfaceCapabilitiesKHR, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") + set_proc_address(&GetPhysicalDeviceSurfaceFormats2KHR, "vkGetPhysicalDeviceSurfaceFormats2KHR") + set_proc_address(&GetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR") + set_proc_address(&GetPhysicalDeviceSurfacePresentModes2EXT, "vkGetPhysicalDeviceSurfacePresentModes2EXT") + set_proc_address(&GetPhysicalDeviceSurfacePresentModesKHR, "vkGetPhysicalDeviceSurfacePresentModesKHR") + set_proc_address(&GetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR") + set_proc_address(&GetPhysicalDeviceToolPropertiesEXT, "vkGetPhysicalDeviceToolPropertiesEXT") + set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR") + set_proc_address(&GetWinrtDisplayNV, "vkGetWinrtDisplayNV") + set_proc_address(&ReleaseDisplayEXT, "vkReleaseDisplayEXT") + set_proc_address(&SubmitDebugUtilsMessageEXT, "vkSubmitDebugUtilsMessageEXT") + + // Device Procedures + set_proc_address(&AcquireFullScreenExclusiveModeEXT, "vkAcquireFullScreenExclusiveModeEXT") + set_proc_address(&AcquireNextImage2KHR, "vkAcquireNextImage2KHR") + set_proc_address(&AcquireNextImageKHR, "vkAcquireNextImageKHR") + set_proc_address(&AcquirePerformanceConfigurationINTEL, "vkAcquirePerformanceConfigurationINTEL") + set_proc_address(&AcquireProfilingLockKHR, "vkAcquireProfilingLockKHR") + set_proc_address(&AllocateCommandBuffers, "vkAllocateCommandBuffers") + set_proc_address(&AllocateDescriptorSets, "vkAllocateDescriptorSets") + set_proc_address(&AllocateMemory, "vkAllocateMemory") + set_proc_address(&BeginCommandBuffer, "vkBeginCommandBuffer") + set_proc_address(&BindAccelerationStructureMemoryNV, "vkBindAccelerationStructureMemoryNV") + set_proc_address(&BindBufferMemory, "vkBindBufferMemory") + set_proc_address(&BindBufferMemory2, "vkBindBufferMemory2") + set_proc_address(&BindBufferMemory2KHR, "vkBindBufferMemory2KHR") + set_proc_address(&BindImageMemory, "vkBindImageMemory") + set_proc_address(&BindImageMemory2, "vkBindImageMemory2") + set_proc_address(&BindImageMemory2KHR, "vkBindImageMemory2KHR") + set_proc_address(&BuildAccelerationStructuresKHR, "vkBuildAccelerationStructuresKHR") + set_proc_address(&CmdBeginConditionalRenderingEXT, "vkCmdBeginConditionalRenderingEXT") + set_proc_address(&CmdBeginDebugUtilsLabelEXT, "vkCmdBeginDebugUtilsLabelEXT") + set_proc_address(&CmdBeginQuery, "vkCmdBeginQuery") + set_proc_address(&CmdBeginQueryIndexedEXT, "vkCmdBeginQueryIndexedEXT") + set_proc_address(&CmdBeginRenderPass, "vkCmdBeginRenderPass") + set_proc_address(&CmdBeginRenderPass2, "vkCmdBeginRenderPass2") + set_proc_address(&CmdBeginRenderPass2KHR, "vkCmdBeginRenderPass2KHR") + set_proc_address(&CmdBeginTransformFeedbackEXT, "vkCmdBeginTransformFeedbackEXT") + set_proc_address(&CmdBindDescriptorSets, "vkCmdBindDescriptorSets") + set_proc_address(&CmdBindIndexBuffer, "vkCmdBindIndexBuffer") + set_proc_address(&CmdBindInvocationMaskHUAWEI, "vkCmdBindInvocationMaskHUAWEI") + set_proc_address(&CmdBindPipeline, "vkCmdBindPipeline") + set_proc_address(&CmdBindPipelineShaderGroupNV, "vkCmdBindPipelineShaderGroupNV") + set_proc_address(&CmdBindShadingRateImageNV, "vkCmdBindShadingRateImageNV") + set_proc_address(&CmdBindTransformFeedbackBuffersEXT, "vkCmdBindTransformFeedbackBuffersEXT") + set_proc_address(&CmdBindVertexBuffers, "vkCmdBindVertexBuffers") + set_proc_address(&CmdBindVertexBuffers2EXT, "vkCmdBindVertexBuffers2EXT") + set_proc_address(&CmdBlitImage, "vkCmdBlitImage") + set_proc_address(&CmdBlitImage2KHR, "vkCmdBlitImage2KHR") + set_proc_address(&CmdBuildAccelerationStructureNV, "vkCmdBuildAccelerationStructureNV") + set_proc_address(&CmdBuildAccelerationStructuresIndirectKHR, "vkCmdBuildAccelerationStructuresIndirectKHR") + set_proc_address(&CmdBuildAccelerationStructuresKHR, "vkCmdBuildAccelerationStructuresKHR") + set_proc_address(&CmdClearAttachments, "vkCmdClearAttachments") + set_proc_address(&CmdClearColorImage, "vkCmdClearColorImage") + set_proc_address(&CmdClearDepthStencilImage, "vkCmdClearDepthStencilImage") + set_proc_address(&CmdCopyAccelerationStructureKHR, "vkCmdCopyAccelerationStructureKHR") + set_proc_address(&CmdCopyAccelerationStructureNV, "vkCmdCopyAccelerationStructureNV") + set_proc_address(&CmdCopyAccelerationStructureToMemoryKHR, "vkCmdCopyAccelerationStructureToMemoryKHR") + set_proc_address(&CmdCopyBuffer, "vkCmdCopyBuffer") + set_proc_address(&CmdCopyBuffer2KHR, "vkCmdCopyBuffer2KHR") + set_proc_address(&CmdCopyBufferToImage, "vkCmdCopyBufferToImage") + set_proc_address(&CmdCopyBufferToImage2KHR, "vkCmdCopyBufferToImage2KHR") + set_proc_address(&CmdCopyImage, "vkCmdCopyImage") + set_proc_address(&CmdCopyImage2KHR, "vkCmdCopyImage2KHR") + set_proc_address(&CmdCopyImageToBuffer, "vkCmdCopyImageToBuffer") + set_proc_address(&CmdCopyImageToBuffer2KHR, "vkCmdCopyImageToBuffer2KHR") + set_proc_address(&CmdCopyMemoryToAccelerationStructureKHR, "vkCmdCopyMemoryToAccelerationStructureKHR") + set_proc_address(&CmdCopyQueryPoolResults, "vkCmdCopyQueryPoolResults") + set_proc_address(&CmdCuLaunchKernelNVX, "vkCmdCuLaunchKernelNVX") + set_proc_address(&CmdDebugMarkerBeginEXT, "vkCmdDebugMarkerBeginEXT") + set_proc_address(&CmdDebugMarkerEndEXT, "vkCmdDebugMarkerEndEXT") + set_proc_address(&CmdDebugMarkerInsertEXT, "vkCmdDebugMarkerInsertEXT") + set_proc_address(&CmdDispatch, "vkCmdDispatch") + set_proc_address(&CmdDispatchBase, "vkCmdDispatchBase") + set_proc_address(&CmdDispatchBaseKHR, "vkCmdDispatchBaseKHR") + set_proc_address(&CmdDispatchIndirect, "vkCmdDispatchIndirect") + set_proc_address(&CmdDraw, "vkCmdDraw") + set_proc_address(&CmdDrawIndexed, "vkCmdDrawIndexed") + set_proc_address(&CmdDrawIndexedIndirect, "vkCmdDrawIndexedIndirect") + set_proc_address(&CmdDrawIndexedIndirectCount, "vkCmdDrawIndexedIndirectCount") + set_proc_address(&CmdDrawIndexedIndirectCountAMD, "vkCmdDrawIndexedIndirectCountAMD") + set_proc_address(&CmdDrawIndexedIndirectCountKHR, "vkCmdDrawIndexedIndirectCountKHR") + set_proc_address(&CmdDrawIndirect, "vkCmdDrawIndirect") + set_proc_address(&CmdDrawIndirectByteCountEXT, "vkCmdDrawIndirectByteCountEXT") + set_proc_address(&CmdDrawIndirectCount, "vkCmdDrawIndirectCount") + set_proc_address(&CmdDrawIndirectCountAMD, "vkCmdDrawIndirectCountAMD") + set_proc_address(&CmdDrawIndirectCountKHR, "vkCmdDrawIndirectCountKHR") + set_proc_address(&CmdDrawMeshTasksIndirectCountNV, "vkCmdDrawMeshTasksIndirectCountNV") + set_proc_address(&CmdDrawMeshTasksIndirectNV, "vkCmdDrawMeshTasksIndirectNV") + set_proc_address(&CmdDrawMeshTasksNV, "vkCmdDrawMeshTasksNV") + set_proc_address(&CmdDrawMultiEXT, "vkCmdDrawMultiEXT") + set_proc_address(&CmdDrawMultiIndexedEXT, "vkCmdDrawMultiIndexedEXT") + set_proc_address(&CmdEndConditionalRenderingEXT, "vkCmdEndConditionalRenderingEXT") + set_proc_address(&CmdEndDebugUtilsLabelEXT, "vkCmdEndDebugUtilsLabelEXT") + set_proc_address(&CmdEndQuery, "vkCmdEndQuery") + set_proc_address(&CmdEndQueryIndexedEXT, "vkCmdEndQueryIndexedEXT") + set_proc_address(&CmdEndRenderPass, "vkCmdEndRenderPass") + set_proc_address(&CmdEndRenderPass2, "vkCmdEndRenderPass2") + set_proc_address(&CmdEndRenderPass2KHR, "vkCmdEndRenderPass2KHR") + set_proc_address(&CmdEndTransformFeedbackEXT, "vkCmdEndTransformFeedbackEXT") + set_proc_address(&CmdExecuteCommands, "vkCmdExecuteCommands") + set_proc_address(&CmdExecuteGeneratedCommandsNV, "vkCmdExecuteGeneratedCommandsNV") + set_proc_address(&CmdFillBuffer, "vkCmdFillBuffer") + set_proc_address(&CmdInsertDebugUtilsLabelEXT, "vkCmdInsertDebugUtilsLabelEXT") + set_proc_address(&CmdNextSubpass, "vkCmdNextSubpass") + set_proc_address(&CmdNextSubpass2, "vkCmdNextSubpass2") + set_proc_address(&CmdNextSubpass2KHR, "vkCmdNextSubpass2KHR") + set_proc_address(&CmdPipelineBarrier, "vkCmdPipelineBarrier") + set_proc_address(&CmdPipelineBarrier2KHR, "vkCmdPipelineBarrier2KHR") + set_proc_address(&CmdPreprocessGeneratedCommandsNV, "vkCmdPreprocessGeneratedCommandsNV") + set_proc_address(&CmdPushConstants, "vkCmdPushConstants") + set_proc_address(&CmdPushDescriptorSetKHR, "vkCmdPushDescriptorSetKHR") + set_proc_address(&CmdPushDescriptorSetWithTemplateKHR, "vkCmdPushDescriptorSetWithTemplateKHR") + set_proc_address(&CmdResetEvent, "vkCmdResetEvent") + set_proc_address(&CmdResetEvent2KHR, "vkCmdResetEvent2KHR") + set_proc_address(&CmdResetQueryPool, "vkCmdResetQueryPool") + set_proc_address(&CmdResolveImage, "vkCmdResolveImage") + set_proc_address(&CmdResolveImage2KHR, "vkCmdResolveImage2KHR") + set_proc_address(&CmdSetBlendConstants, "vkCmdSetBlendConstants") + set_proc_address(&CmdSetCheckpointNV, "vkCmdSetCheckpointNV") + set_proc_address(&CmdSetCoarseSampleOrderNV, "vkCmdSetCoarseSampleOrderNV") + set_proc_address(&CmdSetCullModeEXT, "vkCmdSetCullModeEXT") + set_proc_address(&CmdSetDepthBias, "vkCmdSetDepthBias") + set_proc_address(&CmdSetDepthBiasEnableEXT, "vkCmdSetDepthBiasEnableEXT") + set_proc_address(&CmdSetDepthBounds, "vkCmdSetDepthBounds") + set_proc_address(&CmdSetDepthBoundsTestEnableEXT, "vkCmdSetDepthBoundsTestEnableEXT") + set_proc_address(&CmdSetDepthCompareOpEXT, "vkCmdSetDepthCompareOpEXT") + set_proc_address(&CmdSetDepthTestEnableEXT, "vkCmdSetDepthTestEnableEXT") + set_proc_address(&CmdSetDepthWriteEnableEXT, "vkCmdSetDepthWriteEnableEXT") + set_proc_address(&CmdSetDeviceMask, "vkCmdSetDeviceMask") + set_proc_address(&CmdSetDeviceMaskKHR, "vkCmdSetDeviceMaskKHR") + set_proc_address(&CmdSetDiscardRectangleEXT, "vkCmdSetDiscardRectangleEXT") + set_proc_address(&CmdSetEvent, "vkCmdSetEvent") + set_proc_address(&CmdSetEvent2KHR, "vkCmdSetEvent2KHR") + set_proc_address(&CmdSetExclusiveScissorNV, "vkCmdSetExclusiveScissorNV") + set_proc_address(&CmdSetFragmentShadingRateEnumNV, "vkCmdSetFragmentShadingRateEnumNV") + set_proc_address(&CmdSetFragmentShadingRateKHR, "vkCmdSetFragmentShadingRateKHR") + set_proc_address(&CmdSetFrontFaceEXT, "vkCmdSetFrontFaceEXT") + set_proc_address(&CmdSetLineStippleEXT, "vkCmdSetLineStippleEXT") + set_proc_address(&CmdSetLineWidth, "vkCmdSetLineWidth") + set_proc_address(&CmdSetLogicOpEXT, "vkCmdSetLogicOpEXT") + set_proc_address(&CmdSetPatchControlPointsEXT, "vkCmdSetPatchControlPointsEXT") + set_proc_address(&CmdSetPerformanceMarkerINTEL, "vkCmdSetPerformanceMarkerINTEL") + set_proc_address(&CmdSetPerformanceOverrideINTEL, "vkCmdSetPerformanceOverrideINTEL") + set_proc_address(&CmdSetPerformanceStreamMarkerINTEL, "vkCmdSetPerformanceStreamMarkerINTEL") + set_proc_address(&CmdSetPrimitiveRestartEnableEXT, "vkCmdSetPrimitiveRestartEnableEXT") + set_proc_address(&CmdSetPrimitiveTopologyEXT, "vkCmdSetPrimitiveTopologyEXT") + set_proc_address(&CmdSetRasterizerDiscardEnableEXT, "vkCmdSetRasterizerDiscardEnableEXT") + set_proc_address(&CmdSetRayTracingPipelineStackSizeKHR, "vkCmdSetRayTracingPipelineStackSizeKHR") + set_proc_address(&CmdSetSampleLocationsEXT, "vkCmdSetSampleLocationsEXT") + set_proc_address(&CmdSetScissor, "vkCmdSetScissor") + set_proc_address(&CmdSetScissorWithCountEXT, "vkCmdSetScissorWithCountEXT") + set_proc_address(&CmdSetStencilCompareMask, "vkCmdSetStencilCompareMask") + set_proc_address(&CmdSetStencilOpEXT, "vkCmdSetStencilOpEXT") + set_proc_address(&CmdSetStencilReference, "vkCmdSetStencilReference") + set_proc_address(&CmdSetStencilTestEnableEXT, "vkCmdSetStencilTestEnableEXT") + set_proc_address(&CmdSetStencilWriteMask, "vkCmdSetStencilWriteMask") + set_proc_address(&CmdSetVertexInputEXT, "vkCmdSetVertexInputEXT") + set_proc_address(&CmdSetViewport, "vkCmdSetViewport") + set_proc_address(&CmdSetViewportShadingRatePaletteNV, "vkCmdSetViewportShadingRatePaletteNV") + set_proc_address(&CmdSetViewportWScalingNV, "vkCmdSetViewportWScalingNV") + set_proc_address(&CmdSetViewportWithCountEXT, "vkCmdSetViewportWithCountEXT") + set_proc_address(&CmdSubpassShadingHUAWEI, "vkCmdSubpassShadingHUAWEI") + set_proc_address(&CmdTraceRaysIndirectKHR, "vkCmdTraceRaysIndirectKHR") + set_proc_address(&CmdTraceRaysKHR, "vkCmdTraceRaysKHR") + set_proc_address(&CmdTraceRaysNV, "vkCmdTraceRaysNV") + set_proc_address(&CmdUpdateBuffer, "vkCmdUpdateBuffer") + set_proc_address(&CmdWaitEvents, "vkCmdWaitEvents") + set_proc_address(&CmdWaitEvents2KHR, "vkCmdWaitEvents2KHR") + set_proc_address(&CmdWriteAccelerationStructuresPropertiesKHR, "vkCmdWriteAccelerationStructuresPropertiesKHR") + set_proc_address(&CmdWriteAccelerationStructuresPropertiesNV, "vkCmdWriteAccelerationStructuresPropertiesNV") + set_proc_address(&CmdWriteBufferMarker2AMD, "vkCmdWriteBufferMarker2AMD") + set_proc_address(&CmdWriteBufferMarkerAMD, "vkCmdWriteBufferMarkerAMD") + set_proc_address(&CmdWriteTimestamp, "vkCmdWriteTimestamp") + set_proc_address(&CmdWriteTimestamp2KHR, "vkCmdWriteTimestamp2KHR") + set_proc_address(&CompileDeferredNV, "vkCompileDeferredNV") + set_proc_address(&CopyAccelerationStructureKHR, "vkCopyAccelerationStructureKHR") + set_proc_address(&CopyAccelerationStructureToMemoryKHR, "vkCopyAccelerationStructureToMemoryKHR") + set_proc_address(&CopyMemoryToAccelerationStructureKHR, "vkCopyMemoryToAccelerationStructureKHR") + set_proc_address(&CreateAccelerationStructureKHR, "vkCreateAccelerationStructureKHR") + set_proc_address(&CreateAccelerationStructureNV, "vkCreateAccelerationStructureNV") + set_proc_address(&CreateBuffer, "vkCreateBuffer") + set_proc_address(&CreateBufferView, "vkCreateBufferView") + set_proc_address(&CreateCommandPool, "vkCreateCommandPool") + set_proc_address(&CreateComputePipelines, "vkCreateComputePipelines") + set_proc_address(&CreateCuFunctionNVX, "vkCreateCuFunctionNVX") + set_proc_address(&CreateCuModuleNVX, "vkCreateCuModuleNVX") + set_proc_address(&CreateDeferredOperationKHR, "vkCreateDeferredOperationKHR") + set_proc_address(&CreateDescriptorPool, "vkCreateDescriptorPool") + set_proc_address(&CreateDescriptorSetLayout, "vkCreateDescriptorSetLayout") + set_proc_address(&CreateDescriptorUpdateTemplate, "vkCreateDescriptorUpdateTemplate") + set_proc_address(&CreateDescriptorUpdateTemplateKHR, "vkCreateDescriptorUpdateTemplateKHR") + set_proc_address(&CreateEvent, "vkCreateEvent") + set_proc_address(&CreateFence, "vkCreateFence") + set_proc_address(&CreateFramebuffer, "vkCreateFramebuffer") + set_proc_address(&CreateGraphicsPipelines, "vkCreateGraphicsPipelines") + set_proc_address(&CreateImage, "vkCreateImage") + set_proc_address(&CreateImageView, "vkCreateImageView") + set_proc_address(&CreateIndirectCommandsLayoutNV, "vkCreateIndirectCommandsLayoutNV") + set_proc_address(&CreatePipelineCache, "vkCreatePipelineCache") + set_proc_address(&CreatePipelineLayout, "vkCreatePipelineLayout") + set_proc_address(&CreatePrivateDataSlotEXT, "vkCreatePrivateDataSlotEXT") + set_proc_address(&CreateQueryPool, "vkCreateQueryPool") + set_proc_address(&CreateRayTracingPipelinesKHR, "vkCreateRayTracingPipelinesKHR") + set_proc_address(&CreateRayTracingPipelinesNV, "vkCreateRayTracingPipelinesNV") + set_proc_address(&CreateRenderPass, "vkCreateRenderPass") + set_proc_address(&CreateRenderPass2, "vkCreateRenderPass2") + set_proc_address(&CreateRenderPass2KHR, "vkCreateRenderPass2KHR") + set_proc_address(&CreateSampler, "vkCreateSampler") + set_proc_address(&CreateSamplerYcbcrConversion, "vkCreateSamplerYcbcrConversion") + set_proc_address(&CreateSamplerYcbcrConversionKHR, "vkCreateSamplerYcbcrConversionKHR") + set_proc_address(&CreateSemaphore, "vkCreateSemaphore") + set_proc_address(&CreateShaderModule, "vkCreateShaderModule") + set_proc_address(&CreateSharedSwapchainsKHR, "vkCreateSharedSwapchainsKHR") + set_proc_address(&CreateSwapchainKHR, "vkCreateSwapchainKHR") + set_proc_address(&CreateValidationCacheEXT, "vkCreateValidationCacheEXT") + set_proc_address(&DebugMarkerSetObjectNameEXT, "vkDebugMarkerSetObjectNameEXT") + set_proc_address(&DebugMarkerSetObjectTagEXT, "vkDebugMarkerSetObjectTagEXT") + set_proc_address(&DeferredOperationJoinKHR, "vkDeferredOperationJoinKHR") + set_proc_address(&DestroyAccelerationStructureKHR, "vkDestroyAccelerationStructureKHR") + set_proc_address(&DestroyAccelerationStructureNV, "vkDestroyAccelerationStructureNV") + set_proc_address(&DestroyBuffer, "vkDestroyBuffer") + set_proc_address(&DestroyBufferView, "vkDestroyBufferView") + set_proc_address(&DestroyCommandPool, "vkDestroyCommandPool") + set_proc_address(&DestroyCuFunctionNVX, "vkDestroyCuFunctionNVX") + set_proc_address(&DestroyCuModuleNVX, "vkDestroyCuModuleNVX") + set_proc_address(&DestroyDeferredOperationKHR, "vkDestroyDeferredOperationKHR") + set_proc_address(&DestroyDescriptorPool, "vkDestroyDescriptorPool") + set_proc_address(&DestroyDescriptorSetLayout, "vkDestroyDescriptorSetLayout") + set_proc_address(&DestroyDescriptorUpdateTemplate, "vkDestroyDescriptorUpdateTemplate") + set_proc_address(&DestroyDescriptorUpdateTemplateKHR, "vkDestroyDescriptorUpdateTemplateKHR") + set_proc_address(&DestroyDevice, "vkDestroyDevice") + set_proc_address(&DestroyEvent, "vkDestroyEvent") + set_proc_address(&DestroyFence, "vkDestroyFence") + set_proc_address(&DestroyFramebuffer, "vkDestroyFramebuffer") + set_proc_address(&DestroyImage, "vkDestroyImage") + set_proc_address(&DestroyImageView, "vkDestroyImageView") + set_proc_address(&DestroyIndirectCommandsLayoutNV, "vkDestroyIndirectCommandsLayoutNV") + set_proc_address(&DestroyPipeline, "vkDestroyPipeline") + set_proc_address(&DestroyPipelineCache, "vkDestroyPipelineCache") + set_proc_address(&DestroyPipelineLayout, "vkDestroyPipelineLayout") + set_proc_address(&DestroyPrivateDataSlotEXT, "vkDestroyPrivateDataSlotEXT") + set_proc_address(&DestroyQueryPool, "vkDestroyQueryPool") + set_proc_address(&DestroyRenderPass, "vkDestroyRenderPass") + set_proc_address(&DestroySampler, "vkDestroySampler") + set_proc_address(&DestroySamplerYcbcrConversion, "vkDestroySamplerYcbcrConversion") + set_proc_address(&DestroySamplerYcbcrConversionKHR, "vkDestroySamplerYcbcrConversionKHR") + set_proc_address(&DestroySemaphore, "vkDestroySemaphore") + set_proc_address(&DestroyShaderModule, "vkDestroyShaderModule") + set_proc_address(&DestroySwapchainKHR, "vkDestroySwapchainKHR") + set_proc_address(&DestroyValidationCacheEXT, "vkDestroyValidationCacheEXT") + set_proc_address(&DeviceWaitIdle, "vkDeviceWaitIdle") + set_proc_address(&DisplayPowerControlEXT, "vkDisplayPowerControlEXT") + set_proc_address(&EndCommandBuffer, "vkEndCommandBuffer") + set_proc_address(&FlushMappedMemoryRanges, "vkFlushMappedMemoryRanges") + set_proc_address(&FreeCommandBuffers, "vkFreeCommandBuffers") + set_proc_address(&FreeDescriptorSets, "vkFreeDescriptorSets") + set_proc_address(&FreeMemory, "vkFreeMemory") + set_proc_address(&GetAccelerationStructureBuildSizesKHR, "vkGetAccelerationStructureBuildSizesKHR") + set_proc_address(&GetAccelerationStructureDeviceAddressKHR, "vkGetAccelerationStructureDeviceAddressKHR") + set_proc_address(&GetAccelerationStructureHandleNV, "vkGetAccelerationStructureHandleNV") + set_proc_address(&GetAccelerationStructureMemoryRequirementsNV, "vkGetAccelerationStructureMemoryRequirementsNV") + set_proc_address(&GetBufferDeviceAddress, "vkGetBufferDeviceAddress") + set_proc_address(&GetBufferDeviceAddressEXT, "vkGetBufferDeviceAddressEXT") + set_proc_address(&GetBufferDeviceAddressKHR, "vkGetBufferDeviceAddressKHR") + set_proc_address(&GetBufferMemoryRequirements, "vkGetBufferMemoryRequirements") + set_proc_address(&GetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2") + set_proc_address(&GetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR") + set_proc_address(&GetBufferOpaqueCaptureAddress, "vkGetBufferOpaqueCaptureAddress") + set_proc_address(&GetBufferOpaqueCaptureAddressKHR, "vkGetBufferOpaqueCaptureAddressKHR") + set_proc_address(&GetCalibratedTimestampsEXT, "vkGetCalibratedTimestampsEXT") + set_proc_address(&GetDeferredOperationMaxConcurrencyKHR, "vkGetDeferredOperationMaxConcurrencyKHR") + set_proc_address(&GetDeferredOperationResultKHR, "vkGetDeferredOperationResultKHR") + set_proc_address(&GetDescriptorSetLayoutSupport, "vkGetDescriptorSetLayoutSupport") + set_proc_address(&GetDescriptorSetLayoutSupportKHR, "vkGetDescriptorSetLayoutSupportKHR") + set_proc_address(&GetDeviceAccelerationStructureCompatibilityKHR, "vkGetDeviceAccelerationStructureCompatibilityKHR") + set_proc_address(&GetDeviceGroupPeerMemoryFeatures, "vkGetDeviceGroupPeerMemoryFeatures") + set_proc_address(&GetDeviceGroupPeerMemoryFeaturesKHR, "vkGetDeviceGroupPeerMemoryFeaturesKHR") + set_proc_address(&GetDeviceGroupPresentCapabilitiesKHR, "vkGetDeviceGroupPresentCapabilitiesKHR") + set_proc_address(&GetDeviceGroupSurfacePresentModes2EXT, "vkGetDeviceGroupSurfacePresentModes2EXT") + set_proc_address(&GetDeviceGroupSurfacePresentModesKHR, "vkGetDeviceGroupSurfacePresentModesKHR") + set_proc_address(&GetDeviceMemoryCommitment, "vkGetDeviceMemoryCommitment") + set_proc_address(&GetDeviceMemoryOpaqueCaptureAddress, "vkGetDeviceMemoryOpaqueCaptureAddress") + set_proc_address(&GetDeviceMemoryOpaqueCaptureAddressKHR, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") + set_proc_address(&GetDeviceProcAddr, "vkGetDeviceProcAddr") + set_proc_address(&GetDeviceQueue, "vkGetDeviceQueue") + set_proc_address(&GetDeviceQueue2, "vkGetDeviceQueue2") + set_proc_address(&GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI") + set_proc_address(&GetEventStatus, "vkGetEventStatus") + set_proc_address(&GetFenceFdKHR, "vkGetFenceFdKHR") + set_proc_address(&GetFenceStatus, "vkGetFenceStatus") + set_proc_address(&GetFenceWin32HandleKHR, "vkGetFenceWin32HandleKHR") + set_proc_address(&GetGeneratedCommandsMemoryRequirementsNV, "vkGetGeneratedCommandsMemoryRequirementsNV") + set_proc_address(&GetImageDrmFormatModifierPropertiesEXT, "vkGetImageDrmFormatModifierPropertiesEXT") + set_proc_address(&GetImageMemoryRequirements, "vkGetImageMemoryRequirements") + set_proc_address(&GetImageMemoryRequirements2, "vkGetImageMemoryRequirements2") + set_proc_address(&GetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR") + set_proc_address(&GetImageSparseMemoryRequirements, "vkGetImageSparseMemoryRequirements") + set_proc_address(&GetImageSparseMemoryRequirements2, "vkGetImageSparseMemoryRequirements2") + set_proc_address(&GetImageSparseMemoryRequirements2KHR, "vkGetImageSparseMemoryRequirements2KHR") + set_proc_address(&GetImageSubresourceLayout, "vkGetImageSubresourceLayout") + set_proc_address(&GetImageViewAddressNVX, "vkGetImageViewAddressNVX") + set_proc_address(&GetImageViewHandleNVX, "vkGetImageViewHandleNVX") + set_proc_address(&GetMemoryFdKHR, "vkGetMemoryFdKHR") + set_proc_address(&GetMemoryFdPropertiesKHR, "vkGetMemoryFdPropertiesKHR") + set_proc_address(&GetMemoryHostPointerPropertiesEXT, "vkGetMemoryHostPointerPropertiesEXT") + set_proc_address(&GetMemoryRemoteAddressNV, "vkGetMemoryRemoteAddressNV") + set_proc_address(&GetMemoryWin32HandleKHR, "vkGetMemoryWin32HandleKHR") + set_proc_address(&GetMemoryWin32HandleNV, "vkGetMemoryWin32HandleNV") + set_proc_address(&GetMemoryWin32HandlePropertiesKHR, "vkGetMemoryWin32HandlePropertiesKHR") + set_proc_address(&GetPastPresentationTimingGOOGLE, "vkGetPastPresentationTimingGOOGLE") + set_proc_address(&GetPerformanceParameterINTEL, "vkGetPerformanceParameterINTEL") + set_proc_address(&GetPipelineCacheData, "vkGetPipelineCacheData") + set_proc_address(&GetPipelineExecutableInternalRepresentationsKHR, "vkGetPipelineExecutableInternalRepresentationsKHR") + set_proc_address(&GetPipelineExecutablePropertiesKHR, "vkGetPipelineExecutablePropertiesKHR") + set_proc_address(&GetPipelineExecutableStatisticsKHR, "vkGetPipelineExecutableStatisticsKHR") + set_proc_address(&GetPrivateDataEXT, "vkGetPrivateDataEXT") + set_proc_address(&GetQueryPoolResults, "vkGetQueryPoolResults") + set_proc_address(&GetQueueCheckpointData2NV, "vkGetQueueCheckpointData2NV") + set_proc_address(&GetQueueCheckpointDataNV, "vkGetQueueCheckpointDataNV") + set_proc_address(&GetRayTracingCaptureReplayShaderGroupHandlesKHR, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR") + set_proc_address(&GetRayTracingShaderGroupHandlesKHR, "vkGetRayTracingShaderGroupHandlesKHR") + set_proc_address(&GetRayTracingShaderGroupHandlesNV, "vkGetRayTracingShaderGroupHandlesNV") + set_proc_address(&GetRayTracingShaderGroupStackSizeKHR, "vkGetRayTracingShaderGroupStackSizeKHR") + set_proc_address(&GetRefreshCycleDurationGOOGLE, "vkGetRefreshCycleDurationGOOGLE") + set_proc_address(&GetRenderAreaGranularity, "vkGetRenderAreaGranularity") + set_proc_address(&GetSemaphoreCounterValue, "vkGetSemaphoreCounterValue") + set_proc_address(&GetSemaphoreCounterValueKHR, "vkGetSemaphoreCounterValueKHR") + set_proc_address(&GetSemaphoreFdKHR, "vkGetSemaphoreFdKHR") + set_proc_address(&GetSemaphoreWin32HandleKHR, "vkGetSemaphoreWin32HandleKHR") + set_proc_address(&GetShaderInfoAMD, "vkGetShaderInfoAMD") + set_proc_address(&GetSwapchainCounterEXT, "vkGetSwapchainCounterEXT") + set_proc_address(&GetSwapchainImagesKHR, "vkGetSwapchainImagesKHR") + set_proc_address(&GetSwapchainStatusKHR, "vkGetSwapchainStatusKHR") + set_proc_address(&GetValidationCacheDataEXT, "vkGetValidationCacheDataEXT") + set_proc_address(&ImportFenceFdKHR, "vkImportFenceFdKHR") + set_proc_address(&ImportFenceWin32HandleKHR, "vkImportFenceWin32HandleKHR") + set_proc_address(&ImportSemaphoreFdKHR, "vkImportSemaphoreFdKHR") + set_proc_address(&ImportSemaphoreWin32HandleKHR, "vkImportSemaphoreWin32HandleKHR") + set_proc_address(&InitializePerformanceApiINTEL, "vkInitializePerformanceApiINTEL") + set_proc_address(&InvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges") + set_proc_address(&MapMemory, "vkMapMemory") + set_proc_address(&MergePipelineCaches, "vkMergePipelineCaches") + set_proc_address(&MergeValidationCachesEXT, "vkMergeValidationCachesEXT") + set_proc_address(&QueueBeginDebugUtilsLabelEXT, "vkQueueBeginDebugUtilsLabelEXT") + set_proc_address(&QueueBindSparse, "vkQueueBindSparse") + set_proc_address(&QueueEndDebugUtilsLabelEXT, "vkQueueEndDebugUtilsLabelEXT") + set_proc_address(&QueueInsertDebugUtilsLabelEXT, "vkQueueInsertDebugUtilsLabelEXT") + set_proc_address(&QueuePresentKHR, "vkQueuePresentKHR") + set_proc_address(&QueueSetPerformanceConfigurationINTEL, "vkQueueSetPerformanceConfigurationINTEL") + set_proc_address(&QueueSubmit, "vkQueueSubmit") + set_proc_address(&QueueSubmit2KHR, "vkQueueSubmit2KHR") + set_proc_address(&QueueWaitIdle, "vkQueueWaitIdle") + set_proc_address(&RegisterDeviceEventEXT, "vkRegisterDeviceEventEXT") + set_proc_address(&RegisterDisplayEventEXT, "vkRegisterDisplayEventEXT") + set_proc_address(&ReleaseFullScreenExclusiveModeEXT, "vkReleaseFullScreenExclusiveModeEXT") + set_proc_address(&ReleasePerformanceConfigurationINTEL, "vkReleasePerformanceConfigurationINTEL") + set_proc_address(&ReleaseProfilingLockKHR, "vkReleaseProfilingLockKHR") + set_proc_address(&ResetCommandBuffer, "vkResetCommandBuffer") + set_proc_address(&ResetCommandPool, "vkResetCommandPool") + set_proc_address(&ResetDescriptorPool, "vkResetDescriptorPool") + set_proc_address(&ResetEvent, "vkResetEvent") + set_proc_address(&ResetFences, "vkResetFences") + set_proc_address(&ResetQueryPool, "vkResetQueryPool") + set_proc_address(&ResetQueryPoolEXT, "vkResetQueryPoolEXT") + set_proc_address(&SetDebugUtilsObjectNameEXT, "vkSetDebugUtilsObjectNameEXT") + set_proc_address(&SetDebugUtilsObjectTagEXT, "vkSetDebugUtilsObjectTagEXT") + set_proc_address(&SetDeviceMemoryPriorityEXT, "vkSetDeviceMemoryPriorityEXT") + set_proc_address(&SetEvent, "vkSetEvent") + set_proc_address(&SetHdrMetadataEXT, "vkSetHdrMetadataEXT") + set_proc_address(&SetLocalDimmingAMD, "vkSetLocalDimmingAMD") + set_proc_address(&SetPrivateDataEXT, "vkSetPrivateDataEXT") + set_proc_address(&SignalSemaphore, "vkSignalSemaphore") + set_proc_address(&SignalSemaphoreKHR, "vkSignalSemaphoreKHR") + set_proc_address(&TrimCommandPool, "vkTrimCommandPool") + set_proc_address(&TrimCommandPoolKHR, "vkTrimCommandPoolKHR") + set_proc_address(&UninitializePerformanceApiINTEL, "vkUninitializePerformanceApiINTEL") + set_proc_address(&UnmapMemory, "vkUnmapMemory") + set_proc_address(&UpdateDescriptorSetWithTemplate, "vkUpdateDescriptorSetWithTemplate") + set_proc_address(&UpdateDescriptorSetWithTemplateKHR, "vkUpdateDescriptorSetWithTemplateKHR") + set_proc_address(&UpdateDescriptorSets, "vkUpdateDescriptorSets") + set_proc_address(&WaitForFences, "vkWaitForFences") + set_proc_address(&WaitForPresentKHR, "vkWaitForPresentKHR") + set_proc_address(&WaitSemaphores, "vkWaitSemaphores") + set_proc_address(&WaitSemaphoresKHR, "vkWaitSemaphoresKHR") + set_proc_address(&WriteAccelerationStructuresPropertiesKHR, "vkWriteAccelerationStructuresPropertiesKHR") } +// Device Procedure VTable +Device_VTable :: struct { + AcquireFullScreenExclusiveModeEXT: ProcAcquireFullScreenExclusiveModeEXT, + AcquireNextImage2KHR: ProcAcquireNextImage2KHR, + AcquireNextImageKHR: ProcAcquireNextImageKHR, + AcquirePerformanceConfigurationINTEL: ProcAcquirePerformanceConfigurationINTEL, + AcquireProfilingLockKHR: ProcAcquireProfilingLockKHR, + AllocateCommandBuffers: ProcAllocateCommandBuffers, + AllocateDescriptorSets: ProcAllocateDescriptorSets, + AllocateMemory: ProcAllocateMemory, + BeginCommandBuffer: ProcBeginCommandBuffer, + BindAccelerationStructureMemoryNV: ProcBindAccelerationStructureMemoryNV, + BindBufferMemory: ProcBindBufferMemory, + BindBufferMemory2: ProcBindBufferMemory2, + BindBufferMemory2KHR: ProcBindBufferMemory2KHR, + BindImageMemory: ProcBindImageMemory, + BindImageMemory2: ProcBindImageMemory2, + BindImageMemory2KHR: ProcBindImageMemory2KHR, + BuildAccelerationStructuresKHR: ProcBuildAccelerationStructuresKHR, + CmdBeginConditionalRenderingEXT: ProcCmdBeginConditionalRenderingEXT, + CmdBeginDebugUtilsLabelEXT: ProcCmdBeginDebugUtilsLabelEXT, + CmdBeginQuery: ProcCmdBeginQuery, + CmdBeginQueryIndexedEXT: ProcCmdBeginQueryIndexedEXT, + CmdBeginRenderPass: ProcCmdBeginRenderPass, + CmdBeginRenderPass2: ProcCmdBeginRenderPass2, + CmdBeginRenderPass2KHR: ProcCmdBeginRenderPass2KHR, + CmdBeginTransformFeedbackEXT: ProcCmdBeginTransformFeedbackEXT, + CmdBindDescriptorSets: ProcCmdBindDescriptorSets, + CmdBindIndexBuffer: ProcCmdBindIndexBuffer, + CmdBindInvocationMaskHUAWEI: ProcCmdBindInvocationMaskHUAWEI, + CmdBindPipeline: ProcCmdBindPipeline, + CmdBindPipelineShaderGroupNV: ProcCmdBindPipelineShaderGroupNV, + CmdBindShadingRateImageNV: ProcCmdBindShadingRateImageNV, + CmdBindTransformFeedbackBuffersEXT: ProcCmdBindTransformFeedbackBuffersEXT, + CmdBindVertexBuffers: ProcCmdBindVertexBuffers, + CmdBindVertexBuffers2EXT: ProcCmdBindVertexBuffers2EXT, + CmdBlitImage: ProcCmdBlitImage, + CmdBlitImage2KHR: ProcCmdBlitImage2KHR, + CmdBuildAccelerationStructureNV: ProcCmdBuildAccelerationStructureNV, + CmdBuildAccelerationStructuresIndirectKHR: ProcCmdBuildAccelerationStructuresIndirectKHR, + CmdBuildAccelerationStructuresKHR: ProcCmdBuildAccelerationStructuresKHR, + CmdClearAttachments: ProcCmdClearAttachments, + CmdClearColorImage: ProcCmdClearColorImage, + CmdClearDepthStencilImage: ProcCmdClearDepthStencilImage, + CmdCopyAccelerationStructureKHR: ProcCmdCopyAccelerationStructureKHR, + CmdCopyAccelerationStructureNV: ProcCmdCopyAccelerationStructureNV, + CmdCopyAccelerationStructureToMemoryKHR: ProcCmdCopyAccelerationStructureToMemoryKHR, + CmdCopyBuffer: ProcCmdCopyBuffer, + CmdCopyBuffer2KHR: ProcCmdCopyBuffer2KHR, + CmdCopyBufferToImage: ProcCmdCopyBufferToImage, + CmdCopyBufferToImage2KHR: ProcCmdCopyBufferToImage2KHR, + CmdCopyImage: ProcCmdCopyImage, + CmdCopyImage2KHR: ProcCmdCopyImage2KHR, + CmdCopyImageToBuffer: ProcCmdCopyImageToBuffer, + CmdCopyImageToBuffer2KHR: ProcCmdCopyImageToBuffer2KHR, + CmdCopyMemoryToAccelerationStructureKHR: ProcCmdCopyMemoryToAccelerationStructureKHR, + CmdCopyQueryPoolResults: ProcCmdCopyQueryPoolResults, + CmdCuLaunchKernelNVX: ProcCmdCuLaunchKernelNVX, + CmdDebugMarkerBeginEXT: ProcCmdDebugMarkerBeginEXT, + CmdDebugMarkerEndEXT: ProcCmdDebugMarkerEndEXT, + CmdDebugMarkerInsertEXT: ProcCmdDebugMarkerInsertEXT, + CmdDispatch: ProcCmdDispatch, + CmdDispatchBase: ProcCmdDispatchBase, + CmdDispatchBaseKHR: ProcCmdDispatchBaseKHR, + CmdDispatchIndirect: ProcCmdDispatchIndirect, + CmdDraw: ProcCmdDraw, + CmdDrawIndexed: ProcCmdDrawIndexed, + CmdDrawIndexedIndirect: ProcCmdDrawIndexedIndirect, + CmdDrawIndexedIndirectCount: ProcCmdDrawIndexedIndirectCount, + CmdDrawIndexedIndirectCountAMD: ProcCmdDrawIndexedIndirectCountAMD, + CmdDrawIndexedIndirectCountKHR: ProcCmdDrawIndexedIndirectCountKHR, + CmdDrawIndirect: ProcCmdDrawIndirect, + CmdDrawIndirectByteCountEXT: ProcCmdDrawIndirectByteCountEXT, + CmdDrawIndirectCount: ProcCmdDrawIndirectCount, + CmdDrawIndirectCountAMD: ProcCmdDrawIndirectCountAMD, + CmdDrawIndirectCountKHR: ProcCmdDrawIndirectCountKHR, + CmdDrawMeshTasksIndirectCountNV: ProcCmdDrawMeshTasksIndirectCountNV, + CmdDrawMeshTasksIndirectNV: ProcCmdDrawMeshTasksIndirectNV, + CmdDrawMeshTasksNV: ProcCmdDrawMeshTasksNV, + CmdDrawMultiEXT: ProcCmdDrawMultiEXT, + CmdDrawMultiIndexedEXT: ProcCmdDrawMultiIndexedEXT, + CmdEndConditionalRenderingEXT: ProcCmdEndConditionalRenderingEXT, + CmdEndDebugUtilsLabelEXT: ProcCmdEndDebugUtilsLabelEXT, + CmdEndQuery: ProcCmdEndQuery, + CmdEndQueryIndexedEXT: ProcCmdEndQueryIndexedEXT, + CmdEndRenderPass: ProcCmdEndRenderPass, + CmdEndRenderPass2: ProcCmdEndRenderPass2, + CmdEndRenderPass2KHR: ProcCmdEndRenderPass2KHR, + CmdEndTransformFeedbackEXT: ProcCmdEndTransformFeedbackEXT, + CmdExecuteCommands: ProcCmdExecuteCommands, + CmdExecuteGeneratedCommandsNV: ProcCmdExecuteGeneratedCommandsNV, + CmdFillBuffer: ProcCmdFillBuffer, + CmdInsertDebugUtilsLabelEXT: ProcCmdInsertDebugUtilsLabelEXT, + CmdNextSubpass: ProcCmdNextSubpass, + CmdNextSubpass2: ProcCmdNextSubpass2, + CmdNextSubpass2KHR: ProcCmdNextSubpass2KHR, + CmdPipelineBarrier: ProcCmdPipelineBarrier, + CmdPipelineBarrier2KHR: ProcCmdPipelineBarrier2KHR, + CmdPreprocessGeneratedCommandsNV: ProcCmdPreprocessGeneratedCommandsNV, + CmdPushConstants: ProcCmdPushConstants, + CmdPushDescriptorSetKHR: ProcCmdPushDescriptorSetKHR, + CmdPushDescriptorSetWithTemplateKHR: ProcCmdPushDescriptorSetWithTemplateKHR, + CmdResetEvent: ProcCmdResetEvent, + CmdResetEvent2KHR: ProcCmdResetEvent2KHR, + CmdResetQueryPool: ProcCmdResetQueryPool, + CmdResolveImage: ProcCmdResolveImage, + CmdResolveImage2KHR: ProcCmdResolveImage2KHR, + CmdSetBlendConstants: ProcCmdSetBlendConstants, + CmdSetCheckpointNV: ProcCmdSetCheckpointNV, + CmdSetCoarseSampleOrderNV: ProcCmdSetCoarseSampleOrderNV, + CmdSetCullModeEXT: ProcCmdSetCullModeEXT, + CmdSetDepthBias: ProcCmdSetDepthBias, + CmdSetDepthBiasEnableEXT: ProcCmdSetDepthBiasEnableEXT, + CmdSetDepthBounds: ProcCmdSetDepthBounds, + CmdSetDepthBoundsTestEnableEXT: ProcCmdSetDepthBoundsTestEnableEXT, + CmdSetDepthCompareOpEXT: ProcCmdSetDepthCompareOpEXT, + CmdSetDepthTestEnableEXT: ProcCmdSetDepthTestEnableEXT, + CmdSetDepthWriteEnableEXT: ProcCmdSetDepthWriteEnableEXT, + CmdSetDeviceMask: ProcCmdSetDeviceMask, + CmdSetDeviceMaskKHR: ProcCmdSetDeviceMaskKHR, + CmdSetDiscardRectangleEXT: ProcCmdSetDiscardRectangleEXT, + CmdSetEvent: ProcCmdSetEvent, + CmdSetEvent2KHR: ProcCmdSetEvent2KHR, + CmdSetExclusiveScissorNV: ProcCmdSetExclusiveScissorNV, + CmdSetFragmentShadingRateEnumNV: ProcCmdSetFragmentShadingRateEnumNV, + CmdSetFragmentShadingRateKHR: ProcCmdSetFragmentShadingRateKHR, + CmdSetFrontFaceEXT: ProcCmdSetFrontFaceEXT, + CmdSetLineStippleEXT: ProcCmdSetLineStippleEXT, + CmdSetLineWidth: ProcCmdSetLineWidth, + CmdSetLogicOpEXT: ProcCmdSetLogicOpEXT, + CmdSetPatchControlPointsEXT: ProcCmdSetPatchControlPointsEXT, + CmdSetPerformanceMarkerINTEL: ProcCmdSetPerformanceMarkerINTEL, + CmdSetPerformanceOverrideINTEL: ProcCmdSetPerformanceOverrideINTEL, + CmdSetPerformanceStreamMarkerINTEL: ProcCmdSetPerformanceStreamMarkerINTEL, + CmdSetPrimitiveRestartEnableEXT: ProcCmdSetPrimitiveRestartEnableEXT, + CmdSetPrimitiveTopologyEXT: ProcCmdSetPrimitiveTopologyEXT, + CmdSetRasterizerDiscardEnableEXT: ProcCmdSetRasterizerDiscardEnableEXT, + CmdSetRayTracingPipelineStackSizeKHR: ProcCmdSetRayTracingPipelineStackSizeKHR, + CmdSetSampleLocationsEXT: ProcCmdSetSampleLocationsEXT, + CmdSetScissor: ProcCmdSetScissor, + CmdSetScissorWithCountEXT: ProcCmdSetScissorWithCountEXT, + CmdSetStencilCompareMask: ProcCmdSetStencilCompareMask, + CmdSetStencilOpEXT: ProcCmdSetStencilOpEXT, + CmdSetStencilReference: ProcCmdSetStencilReference, + CmdSetStencilTestEnableEXT: ProcCmdSetStencilTestEnableEXT, + CmdSetStencilWriteMask: ProcCmdSetStencilWriteMask, + CmdSetVertexInputEXT: ProcCmdSetVertexInputEXT, + CmdSetViewport: ProcCmdSetViewport, + CmdSetViewportShadingRatePaletteNV: ProcCmdSetViewportShadingRatePaletteNV, + CmdSetViewportWScalingNV: ProcCmdSetViewportWScalingNV, + CmdSetViewportWithCountEXT: ProcCmdSetViewportWithCountEXT, + CmdSubpassShadingHUAWEI: ProcCmdSubpassShadingHUAWEI, + CmdTraceRaysIndirectKHR: ProcCmdTraceRaysIndirectKHR, + CmdTraceRaysKHR: ProcCmdTraceRaysKHR, + CmdTraceRaysNV: ProcCmdTraceRaysNV, + CmdUpdateBuffer: ProcCmdUpdateBuffer, + CmdWaitEvents: ProcCmdWaitEvents, + CmdWaitEvents2KHR: ProcCmdWaitEvents2KHR, + CmdWriteAccelerationStructuresPropertiesKHR: ProcCmdWriteAccelerationStructuresPropertiesKHR, + CmdWriteAccelerationStructuresPropertiesNV: ProcCmdWriteAccelerationStructuresPropertiesNV, + CmdWriteBufferMarker2AMD: ProcCmdWriteBufferMarker2AMD, + CmdWriteBufferMarkerAMD: ProcCmdWriteBufferMarkerAMD, + CmdWriteTimestamp: ProcCmdWriteTimestamp, + CmdWriteTimestamp2KHR: ProcCmdWriteTimestamp2KHR, + CompileDeferredNV: ProcCompileDeferredNV, + CopyAccelerationStructureKHR: ProcCopyAccelerationStructureKHR, + CopyAccelerationStructureToMemoryKHR: ProcCopyAccelerationStructureToMemoryKHR, + CopyMemoryToAccelerationStructureKHR: ProcCopyMemoryToAccelerationStructureKHR, + CreateAccelerationStructureKHR: ProcCreateAccelerationStructureKHR, + CreateAccelerationStructureNV: ProcCreateAccelerationStructureNV, + CreateBuffer: ProcCreateBuffer, + CreateBufferView: ProcCreateBufferView, + CreateCommandPool: ProcCreateCommandPool, + CreateComputePipelines: ProcCreateComputePipelines, + CreateCuFunctionNVX: ProcCreateCuFunctionNVX, + CreateCuModuleNVX: ProcCreateCuModuleNVX, + CreateDeferredOperationKHR: ProcCreateDeferredOperationKHR, + CreateDescriptorPool: ProcCreateDescriptorPool, + CreateDescriptorSetLayout: ProcCreateDescriptorSetLayout, + CreateDescriptorUpdateTemplate: ProcCreateDescriptorUpdateTemplate, + CreateDescriptorUpdateTemplateKHR: ProcCreateDescriptorUpdateTemplateKHR, + CreateEvent: ProcCreateEvent, + CreateFence: ProcCreateFence, + CreateFramebuffer: ProcCreateFramebuffer, + CreateGraphicsPipelines: ProcCreateGraphicsPipelines, + CreateImage: ProcCreateImage, + CreateImageView: ProcCreateImageView, + CreateIndirectCommandsLayoutNV: ProcCreateIndirectCommandsLayoutNV, + CreatePipelineCache: ProcCreatePipelineCache, + CreatePipelineLayout: ProcCreatePipelineLayout, + CreatePrivateDataSlotEXT: ProcCreatePrivateDataSlotEXT, + CreateQueryPool: ProcCreateQueryPool, + CreateRayTracingPipelinesKHR: ProcCreateRayTracingPipelinesKHR, + CreateRayTracingPipelinesNV: ProcCreateRayTracingPipelinesNV, + CreateRenderPass: ProcCreateRenderPass, + CreateRenderPass2: ProcCreateRenderPass2, + CreateRenderPass2KHR: ProcCreateRenderPass2KHR, + CreateSampler: ProcCreateSampler, + CreateSamplerYcbcrConversion: ProcCreateSamplerYcbcrConversion, + CreateSamplerYcbcrConversionKHR: ProcCreateSamplerYcbcrConversionKHR, + CreateSemaphore: ProcCreateSemaphore, + CreateShaderModule: ProcCreateShaderModule, + CreateSharedSwapchainsKHR: ProcCreateSharedSwapchainsKHR, + CreateSwapchainKHR: ProcCreateSwapchainKHR, + CreateValidationCacheEXT: ProcCreateValidationCacheEXT, + DebugMarkerSetObjectNameEXT: ProcDebugMarkerSetObjectNameEXT, + DebugMarkerSetObjectTagEXT: ProcDebugMarkerSetObjectTagEXT, + DeferredOperationJoinKHR: ProcDeferredOperationJoinKHR, + DestroyAccelerationStructureKHR: ProcDestroyAccelerationStructureKHR, + DestroyAccelerationStructureNV: ProcDestroyAccelerationStructureNV, + DestroyBuffer: ProcDestroyBuffer, + DestroyBufferView: ProcDestroyBufferView, + DestroyCommandPool: ProcDestroyCommandPool, + DestroyCuFunctionNVX: ProcDestroyCuFunctionNVX, + DestroyCuModuleNVX: ProcDestroyCuModuleNVX, + DestroyDeferredOperationKHR: ProcDestroyDeferredOperationKHR, + DestroyDescriptorPool: ProcDestroyDescriptorPool, + DestroyDescriptorSetLayout: ProcDestroyDescriptorSetLayout, + DestroyDescriptorUpdateTemplate: ProcDestroyDescriptorUpdateTemplate, + DestroyDescriptorUpdateTemplateKHR: ProcDestroyDescriptorUpdateTemplateKHR, + DestroyDevice: ProcDestroyDevice, + DestroyEvent: ProcDestroyEvent, + DestroyFence: ProcDestroyFence, + DestroyFramebuffer: ProcDestroyFramebuffer, + DestroyImage: ProcDestroyImage, + DestroyImageView: ProcDestroyImageView, + DestroyIndirectCommandsLayoutNV: ProcDestroyIndirectCommandsLayoutNV, + DestroyPipeline: ProcDestroyPipeline, + DestroyPipelineCache: ProcDestroyPipelineCache, + DestroyPipelineLayout: ProcDestroyPipelineLayout, + DestroyPrivateDataSlotEXT: ProcDestroyPrivateDataSlotEXT, + DestroyQueryPool: ProcDestroyQueryPool, + DestroyRenderPass: ProcDestroyRenderPass, + DestroySampler: ProcDestroySampler, + DestroySamplerYcbcrConversion: ProcDestroySamplerYcbcrConversion, + DestroySamplerYcbcrConversionKHR: ProcDestroySamplerYcbcrConversionKHR, + DestroySemaphore: ProcDestroySemaphore, + DestroyShaderModule: ProcDestroyShaderModule, + DestroySwapchainKHR: ProcDestroySwapchainKHR, + DestroyValidationCacheEXT: ProcDestroyValidationCacheEXT, + DeviceWaitIdle: ProcDeviceWaitIdle, + DisplayPowerControlEXT: ProcDisplayPowerControlEXT, + EndCommandBuffer: ProcEndCommandBuffer, + FlushMappedMemoryRanges: ProcFlushMappedMemoryRanges, + FreeCommandBuffers: ProcFreeCommandBuffers, + FreeDescriptorSets: ProcFreeDescriptorSets, + FreeMemory: ProcFreeMemory, + GetAccelerationStructureBuildSizesKHR: ProcGetAccelerationStructureBuildSizesKHR, + GetAccelerationStructureDeviceAddressKHR: ProcGetAccelerationStructureDeviceAddressKHR, + GetAccelerationStructureHandleNV: ProcGetAccelerationStructureHandleNV, + GetAccelerationStructureMemoryRequirementsNV: ProcGetAccelerationStructureMemoryRequirementsNV, + GetBufferDeviceAddress: ProcGetBufferDeviceAddress, + GetBufferDeviceAddressEXT: ProcGetBufferDeviceAddressEXT, + GetBufferDeviceAddressKHR: ProcGetBufferDeviceAddressKHR, + GetBufferMemoryRequirements: ProcGetBufferMemoryRequirements, + GetBufferMemoryRequirements2: ProcGetBufferMemoryRequirements2, + GetBufferMemoryRequirements2KHR: ProcGetBufferMemoryRequirements2KHR, + GetBufferOpaqueCaptureAddress: ProcGetBufferOpaqueCaptureAddress, + GetBufferOpaqueCaptureAddressKHR: ProcGetBufferOpaqueCaptureAddressKHR, + GetCalibratedTimestampsEXT: ProcGetCalibratedTimestampsEXT, + GetDeferredOperationMaxConcurrencyKHR: ProcGetDeferredOperationMaxConcurrencyKHR, + GetDeferredOperationResultKHR: ProcGetDeferredOperationResultKHR, + GetDescriptorSetLayoutSupport: ProcGetDescriptorSetLayoutSupport, + GetDescriptorSetLayoutSupportKHR: ProcGetDescriptorSetLayoutSupportKHR, + GetDeviceAccelerationStructureCompatibilityKHR: ProcGetDeviceAccelerationStructureCompatibilityKHR, + GetDeviceGroupPeerMemoryFeatures: ProcGetDeviceGroupPeerMemoryFeatures, + GetDeviceGroupPeerMemoryFeaturesKHR: ProcGetDeviceGroupPeerMemoryFeaturesKHR, + GetDeviceGroupPresentCapabilitiesKHR: ProcGetDeviceGroupPresentCapabilitiesKHR, + GetDeviceGroupSurfacePresentModes2EXT: ProcGetDeviceGroupSurfacePresentModes2EXT, + GetDeviceGroupSurfacePresentModesKHR: ProcGetDeviceGroupSurfacePresentModesKHR, + GetDeviceMemoryCommitment: ProcGetDeviceMemoryCommitment, + GetDeviceMemoryOpaqueCaptureAddress: ProcGetDeviceMemoryOpaqueCaptureAddress, + GetDeviceMemoryOpaqueCaptureAddressKHR: ProcGetDeviceMemoryOpaqueCaptureAddressKHR, + GetDeviceProcAddr: ProcGetDeviceProcAddr, + GetDeviceQueue: ProcGetDeviceQueue, + GetDeviceQueue2: ProcGetDeviceQueue2, + GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI: ProcGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, + GetEventStatus: ProcGetEventStatus, + GetFenceFdKHR: ProcGetFenceFdKHR, + GetFenceStatus: ProcGetFenceStatus, + GetFenceWin32HandleKHR: ProcGetFenceWin32HandleKHR, + GetGeneratedCommandsMemoryRequirementsNV: ProcGetGeneratedCommandsMemoryRequirementsNV, + GetImageDrmFormatModifierPropertiesEXT: ProcGetImageDrmFormatModifierPropertiesEXT, + GetImageMemoryRequirements: ProcGetImageMemoryRequirements, + GetImageMemoryRequirements2: ProcGetImageMemoryRequirements2, + GetImageMemoryRequirements2KHR: ProcGetImageMemoryRequirements2KHR, + GetImageSparseMemoryRequirements: ProcGetImageSparseMemoryRequirements, + GetImageSparseMemoryRequirements2: ProcGetImageSparseMemoryRequirements2, + GetImageSparseMemoryRequirements2KHR: ProcGetImageSparseMemoryRequirements2KHR, + GetImageSubresourceLayout: ProcGetImageSubresourceLayout, + GetImageViewAddressNVX: ProcGetImageViewAddressNVX, + GetImageViewHandleNVX: ProcGetImageViewHandleNVX, + GetMemoryFdKHR: ProcGetMemoryFdKHR, + GetMemoryFdPropertiesKHR: ProcGetMemoryFdPropertiesKHR, + GetMemoryHostPointerPropertiesEXT: ProcGetMemoryHostPointerPropertiesEXT, + GetMemoryRemoteAddressNV: ProcGetMemoryRemoteAddressNV, + GetMemoryWin32HandleKHR: ProcGetMemoryWin32HandleKHR, + GetMemoryWin32HandleNV: ProcGetMemoryWin32HandleNV, + GetMemoryWin32HandlePropertiesKHR: ProcGetMemoryWin32HandlePropertiesKHR, + GetPastPresentationTimingGOOGLE: ProcGetPastPresentationTimingGOOGLE, + GetPerformanceParameterINTEL: ProcGetPerformanceParameterINTEL, + GetPipelineCacheData: ProcGetPipelineCacheData, + GetPipelineExecutableInternalRepresentationsKHR: ProcGetPipelineExecutableInternalRepresentationsKHR, + GetPipelineExecutablePropertiesKHR: ProcGetPipelineExecutablePropertiesKHR, + GetPipelineExecutableStatisticsKHR: ProcGetPipelineExecutableStatisticsKHR, + GetPrivateDataEXT: ProcGetPrivateDataEXT, + GetQueryPoolResults: ProcGetQueryPoolResults, + GetQueueCheckpointData2NV: ProcGetQueueCheckpointData2NV, + GetQueueCheckpointDataNV: ProcGetQueueCheckpointDataNV, + GetRayTracingCaptureReplayShaderGroupHandlesKHR: ProcGetRayTracingCaptureReplayShaderGroupHandlesKHR, + GetRayTracingShaderGroupHandlesKHR: ProcGetRayTracingShaderGroupHandlesKHR, + GetRayTracingShaderGroupHandlesNV: ProcGetRayTracingShaderGroupHandlesNV, + GetRayTracingShaderGroupStackSizeKHR: ProcGetRayTracingShaderGroupStackSizeKHR, + GetRefreshCycleDurationGOOGLE: ProcGetRefreshCycleDurationGOOGLE, + GetRenderAreaGranularity: ProcGetRenderAreaGranularity, + GetSemaphoreCounterValue: ProcGetSemaphoreCounterValue, + GetSemaphoreCounterValueKHR: ProcGetSemaphoreCounterValueKHR, + GetSemaphoreFdKHR: ProcGetSemaphoreFdKHR, + GetSemaphoreWin32HandleKHR: ProcGetSemaphoreWin32HandleKHR, + GetShaderInfoAMD: ProcGetShaderInfoAMD, + GetSwapchainCounterEXT: ProcGetSwapchainCounterEXT, + GetSwapchainImagesKHR: ProcGetSwapchainImagesKHR, + GetSwapchainStatusKHR: ProcGetSwapchainStatusKHR, + GetValidationCacheDataEXT: ProcGetValidationCacheDataEXT, + ImportFenceFdKHR: ProcImportFenceFdKHR, + ImportFenceWin32HandleKHR: ProcImportFenceWin32HandleKHR, + ImportSemaphoreFdKHR: ProcImportSemaphoreFdKHR, + ImportSemaphoreWin32HandleKHR: ProcImportSemaphoreWin32HandleKHR, + InitializePerformanceApiINTEL: ProcInitializePerformanceApiINTEL, + InvalidateMappedMemoryRanges: ProcInvalidateMappedMemoryRanges, + MapMemory: ProcMapMemory, + MergePipelineCaches: ProcMergePipelineCaches, + MergeValidationCachesEXT: ProcMergeValidationCachesEXT, + QueueBeginDebugUtilsLabelEXT: ProcQueueBeginDebugUtilsLabelEXT, + QueueBindSparse: ProcQueueBindSparse, + QueueEndDebugUtilsLabelEXT: ProcQueueEndDebugUtilsLabelEXT, + QueueInsertDebugUtilsLabelEXT: ProcQueueInsertDebugUtilsLabelEXT, + QueuePresentKHR: ProcQueuePresentKHR, + QueueSetPerformanceConfigurationINTEL: ProcQueueSetPerformanceConfigurationINTEL, + QueueSubmit: ProcQueueSubmit, + QueueSubmit2KHR: ProcQueueSubmit2KHR, + QueueWaitIdle: ProcQueueWaitIdle, + RegisterDeviceEventEXT: ProcRegisterDeviceEventEXT, + RegisterDisplayEventEXT: ProcRegisterDisplayEventEXT, + ReleaseFullScreenExclusiveModeEXT: ProcReleaseFullScreenExclusiveModeEXT, + ReleasePerformanceConfigurationINTEL: ProcReleasePerformanceConfigurationINTEL, + ReleaseProfilingLockKHR: ProcReleaseProfilingLockKHR, + ResetCommandBuffer: ProcResetCommandBuffer, + ResetCommandPool: ProcResetCommandPool, + ResetDescriptorPool: ProcResetDescriptorPool, + ResetEvent: ProcResetEvent, + ResetFences: ProcResetFences, + ResetQueryPool: ProcResetQueryPool, + ResetQueryPoolEXT: ProcResetQueryPoolEXT, + SetDebugUtilsObjectNameEXT: ProcSetDebugUtilsObjectNameEXT, + SetDebugUtilsObjectTagEXT: ProcSetDebugUtilsObjectTagEXT, + SetDeviceMemoryPriorityEXT: ProcSetDeviceMemoryPriorityEXT, + SetEvent: ProcSetEvent, + SetHdrMetadataEXT: ProcSetHdrMetadataEXT, + SetLocalDimmingAMD: ProcSetLocalDimmingAMD, + SetPrivateDataEXT: ProcSetPrivateDataEXT, + SignalSemaphore: ProcSignalSemaphore, + SignalSemaphoreKHR: ProcSignalSemaphoreKHR, + TrimCommandPool: ProcTrimCommandPool, + TrimCommandPoolKHR: ProcTrimCommandPoolKHR, + UninitializePerformanceApiINTEL: ProcUninitializePerformanceApiINTEL, + UnmapMemory: ProcUnmapMemory, + UpdateDescriptorSetWithTemplate: ProcUpdateDescriptorSetWithTemplate, + UpdateDescriptorSetWithTemplateKHR: ProcUpdateDescriptorSetWithTemplateKHR, + UpdateDescriptorSets: ProcUpdateDescriptorSets, + WaitForFences: ProcWaitForFences, + WaitForPresentKHR: ProcWaitForPresentKHR, + WaitSemaphores: ProcWaitSemaphores, + WaitSemaphoresKHR: ProcWaitSemaphoresKHR, + WriteAccelerationStructuresPropertiesKHR: ProcWriteAccelerationStructuresPropertiesKHR, +} + +load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable) { + vtable.AcquireFullScreenExclusiveModeEXT = auto_cast GetDeviceProcAddr(device, "vkAcquireFullScreenExclusiveModeEXT") + vtable.AcquireNextImage2KHR = auto_cast GetDeviceProcAddr(device, "vkAcquireNextImage2KHR") + vtable.AcquireNextImageKHR = auto_cast GetDeviceProcAddr(device, "vkAcquireNextImageKHR") + vtable.AcquirePerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkAcquirePerformanceConfigurationINTEL") + vtable.AcquireProfilingLockKHR = auto_cast GetDeviceProcAddr(device, "vkAcquireProfilingLockKHR") + vtable.AllocateCommandBuffers = auto_cast GetDeviceProcAddr(device, "vkAllocateCommandBuffers") + vtable.AllocateDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkAllocateDescriptorSets") + vtable.AllocateMemory = auto_cast GetDeviceProcAddr(device, "vkAllocateMemory") + vtable.BeginCommandBuffer = auto_cast GetDeviceProcAddr(device, "vkBeginCommandBuffer") + vtable.BindAccelerationStructureMemoryNV = auto_cast GetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryNV") + vtable.BindBufferMemory = auto_cast GetDeviceProcAddr(device, "vkBindBufferMemory") + vtable.BindBufferMemory2 = auto_cast GetDeviceProcAddr(device, "vkBindBufferMemory2") + vtable.BindBufferMemory2KHR = auto_cast GetDeviceProcAddr(device, "vkBindBufferMemory2KHR") + vtable.BindImageMemory = auto_cast GetDeviceProcAddr(device, "vkBindImageMemory") + vtable.BindImageMemory2 = auto_cast GetDeviceProcAddr(device, "vkBindImageMemory2") + vtable.BindImageMemory2KHR = auto_cast GetDeviceProcAddr(device, "vkBindImageMemory2KHR") + vtable.BuildAccelerationStructuresKHR = auto_cast GetDeviceProcAddr(device, "vkBuildAccelerationStructuresKHR") + vtable.CmdBeginConditionalRenderingEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginConditionalRenderingEXT") + vtable.CmdBeginDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginDebugUtilsLabelEXT") + vtable.CmdBeginQuery = auto_cast GetDeviceProcAddr(device, "vkCmdBeginQuery") + vtable.CmdBeginQueryIndexedEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginQueryIndexedEXT") + vtable.CmdBeginRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass") + vtable.CmdBeginRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2") + vtable.CmdBeginRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2KHR") + vtable.CmdBeginTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginTransformFeedbackEXT") + vtable.CmdBindDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkCmdBindDescriptorSets") + vtable.CmdBindIndexBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdBindIndexBuffer") + vtable.CmdBindInvocationMaskHUAWEI = auto_cast GetDeviceProcAddr(device, "vkCmdBindInvocationMaskHUAWEI") + vtable.CmdBindPipeline = auto_cast GetDeviceProcAddr(device, "vkCmdBindPipeline") + vtable.CmdBindPipelineShaderGroupNV = auto_cast GetDeviceProcAddr(device, "vkCmdBindPipelineShaderGroupNV") + vtable.CmdBindShadingRateImageNV = auto_cast GetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV") + vtable.CmdBindTransformFeedbackBuffersEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindTransformFeedbackBuffersEXT") + vtable.CmdBindVertexBuffers = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers") + vtable.CmdBindVertexBuffers2EXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers2EXT") + vtable.CmdBlitImage = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage") + vtable.CmdBlitImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage2KHR") + vtable.CmdBuildAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV") + vtable.CmdBuildAccelerationStructuresIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresIndirectKHR") + vtable.CmdBuildAccelerationStructuresKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresKHR") + vtable.CmdClearAttachments = auto_cast GetDeviceProcAddr(device, "vkCmdClearAttachments") + vtable.CmdClearColorImage = auto_cast GetDeviceProcAddr(device, "vkCmdClearColorImage") + vtable.CmdClearDepthStencilImage = auto_cast GetDeviceProcAddr(device, "vkCmdClearDepthStencilImage") + vtable.CmdCopyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureKHR") + vtable.CmdCopyAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureNV") + vtable.CmdCopyAccelerationStructureToMemoryKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureToMemoryKHR") + vtable.CmdCopyBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer") + vtable.CmdCopyBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer2KHR") + vtable.CmdCopyBufferToImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage") + vtable.CmdCopyBufferToImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage2KHR") + vtable.CmdCopyImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage") + vtable.CmdCopyImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage2KHR") + vtable.CmdCopyImageToBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer") + vtable.CmdCopyImageToBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer2KHR") + vtable.CmdCopyMemoryToAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyMemoryToAccelerationStructureKHR") + vtable.CmdCopyQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkCmdCopyQueryPoolResults") + vtable.CmdCuLaunchKernelNVX = auto_cast GetDeviceProcAddr(device, "vkCmdCuLaunchKernelNVX") + vtable.CmdDebugMarkerBeginEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDebugMarkerBeginEXT") + vtable.CmdDebugMarkerEndEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDebugMarkerEndEXT") + vtable.CmdDebugMarkerInsertEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDebugMarkerInsertEXT") + vtable.CmdDispatch = auto_cast GetDeviceProcAddr(device, "vkCmdDispatch") + vtable.CmdDispatchBase = auto_cast GetDeviceProcAddr(device, "vkCmdDispatchBase") + vtable.CmdDispatchBaseKHR = auto_cast GetDeviceProcAddr(device, "vkCmdDispatchBaseKHR") + vtable.CmdDispatchIndirect = auto_cast GetDeviceProcAddr(device, "vkCmdDispatchIndirect") + vtable.CmdDraw = auto_cast GetDeviceProcAddr(device, "vkCmdDraw") + vtable.CmdDrawIndexed = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexed") + vtable.CmdDrawIndexedIndirect = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirect") + vtable.CmdDrawIndexedIndirectCount = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirectCount") + vtable.CmdDrawIndexedIndirectCountAMD = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirectCountAMD") + vtable.CmdDrawIndexedIndirectCountKHR = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirectCountKHR") + vtable.CmdDrawIndirect = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirect") + vtable.CmdDrawIndirectByteCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectByteCountEXT") + vtable.CmdDrawIndirectCount = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectCount") + vtable.CmdDrawIndirectCountAMD = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectCountAMD") + vtable.CmdDrawIndirectCountKHR = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectCountKHR") + vtable.CmdDrawMeshTasksIndirectCountNV = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMeshTasksIndirectCountNV") + vtable.CmdDrawMeshTasksIndirectNV = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMeshTasksIndirectNV") + vtable.CmdDrawMeshTasksNV = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMeshTasksNV") + vtable.CmdDrawMultiEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMultiEXT") + vtable.CmdDrawMultiIndexedEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMultiIndexedEXT") + vtable.CmdEndConditionalRenderingEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndConditionalRenderingEXT") + vtable.CmdEndDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndDebugUtilsLabelEXT") + vtable.CmdEndQuery = auto_cast GetDeviceProcAddr(device, "vkCmdEndQuery") + vtable.CmdEndQueryIndexedEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndQueryIndexedEXT") + vtable.CmdEndRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass") + vtable.CmdEndRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2") + vtable.CmdEndRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2KHR") + vtable.CmdEndTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndTransformFeedbackEXT") + vtable.CmdExecuteCommands = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteCommands") + vtable.CmdExecuteGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteGeneratedCommandsNV") + vtable.CmdFillBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdFillBuffer") + vtable.CmdInsertDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkCmdInsertDebugUtilsLabelEXT") + vtable.CmdNextSubpass = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass") + vtable.CmdNextSubpass2 = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2") + vtable.CmdNextSubpass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2KHR") + vtable.CmdPipelineBarrier = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier") + vtable.CmdPipelineBarrier2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier2KHR") + vtable.CmdPreprocessGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdPreprocessGeneratedCommandsNV") + vtable.CmdPushConstants = auto_cast GetDeviceProcAddr(device, "vkCmdPushConstants") + vtable.CmdPushDescriptorSetKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetKHR") + vtable.CmdPushDescriptorSetWithTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetWithTemplateKHR") + vtable.CmdResetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent") + vtable.CmdResetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent2KHR") + vtable.CmdResetQueryPool = auto_cast GetDeviceProcAddr(device, "vkCmdResetQueryPool") + vtable.CmdResolveImage = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage") + vtable.CmdResolveImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage2KHR") + vtable.CmdSetBlendConstants = auto_cast GetDeviceProcAddr(device, "vkCmdSetBlendConstants") + vtable.CmdSetCheckpointNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCheckpointNV") + vtable.CmdSetCoarseSampleOrderNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCoarseSampleOrderNV") + vtable.CmdSetCullModeEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetCullModeEXT") + vtable.CmdSetDepthBias = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBias") + vtable.CmdSetDepthBiasEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBiasEnableEXT") + vtable.CmdSetDepthBounds = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBounds") + vtable.CmdSetDepthBoundsTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnableEXT") + vtable.CmdSetDepthCompareOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthCompareOpEXT") + vtable.CmdSetDepthTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthTestEnableEXT") + vtable.CmdSetDepthWriteEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthWriteEnableEXT") + vtable.CmdSetDeviceMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMask") + vtable.CmdSetDeviceMaskKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMaskKHR") + vtable.CmdSetDiscardRectangleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDiscardRectangleEXT") + vtable.CmdSetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent") + vtable.CmdSetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent2KHR") + vtable.CmdSetExclusiveScissorNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetExclusiveScissorNV") + vtable.CmdSetFragmentShadingRateEnumNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateEnumNV") + vtable.CmdSetFragmentShadingRateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateKHR") + vtable.CmdSetFrontFaceEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetFrontFaceEXT") + vtable.CmdSetLineStippleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineStippleEXT") + vtable.CmdSetLineWidth = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineWidth") + vtable.CmdSetLogicOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetLogicOpEXT") + vtable.CmdSetPatchControlPointsEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPatchControlPointsEXT") + vtable.CmdSetPerformanceMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceMarkerINTEL") + vtable.CmdSetPerformanceOverrideINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceOverrideINTEL") + vtable.CmdSetPerformanceStreamMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceStreamMarkerINTEL") + vtable.CmdSetPrimitiveRestartEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveRestartEnableEXT") + vtable.CmdSetPrimitiveTopologyEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveTopologyEXT") + vtable.CmdSetRasterizerDiscardEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetRasterizerDiscardEnableEXT") + vtable.CmdSetRayTracingPipelineStackSizeKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetRayTracingPipelineStackSizeKHR") + vtable.CmdSetSampleLocationsEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetSampleLocationsEXT") + vtable.CmdSetScissor = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissor") + vtable.CmdSetScissorWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissorWithCountEXT") + vtable.CmdSetStencilCompareMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilCompareMask") + vtable.CmdSetStencilOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilOpEXT") + vtable.CmdSetStencilReference = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilReference") + vtable.CmdSetStencilTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT") + vtable.CmdSetStencilWriteMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilWriteMask") + vtable.CmdSetVertexInputEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetVertexInputEXT") + vtable.CmdSetViewport = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewport") + vtable.CmdSetViewportShadingRatePaletteNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportShadingRatePaletteNV") + vtable.CmdSetViewportWScalingNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWScalingNV") + vtable.CmdSetViewportWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT") + vtable.CmdSubpassShadingHUAWEI = auto_cast GetDeviceProcAddr(device, "vkCmdSubpassShadingHUAWEI") + vtable.CmdTraceRaysIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysIndirectKHR") + vtable.CmdTraceRaysKHR = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysKHR") + vtable.CmdTraceRaysNV = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysNV") + vtable.CmdUpdateBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdUpdateBuffer") + vtable.CmdWaitEvents = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents") + vtable.CmdWaitEvents2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents2KHR") + vtable.CmdWriteAccelerationStructuresPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesKHR") + vtable.CmdWriteAccelerationStructuresPropertiesNV = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesNV") + vtable.CmdWriteBufferMarker2AMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarker2AMD") + vtable.CmdWriteBufferMarkerAMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarkerAMD") + vtable.CmdWriteTimestamp = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp") + vtable.CmdWriteTimestamp2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp2KHR") + vtable.CompileDeferredNV = auto_cast GetDeviceProcAddr(device, "vkCompileDeferredNV") + vtable.CopyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCopyAccelerationStructureKHR") + vtable.CopyAccelerationStructureToMemoryKHR = auto_cast GetDeviceProcAddr(device, "vkCopyAccelerationStructureToMemoryKHR") + vtable.CopyMemoryToAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCopyMemoryToAccelerationStructureKHR") + vtable.CreateAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR") + vtable.CreateAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCreateAccelerationStructureNV") + vtable.CreateBuffer = auto_cast GetDeviceProcAddr(device, "vkCreateBuffer") + vtable.CreateBufferView = auto_cast GetDeviceProcAddr(device, "vkCreateBufferView") + vtable.CreateCommandPool = auto_cast GetDeviceProcAddr(device, "vkCreateCommandPool") + vtable.CreateComputePipelines = auto_cast GetDeviceProcAddr(device, "vkCreateComputePipelines") + vtable.CreateCuFunctionNVX = auto_cast GetDeviceProcAddr(device, "vkCreateCuFunctionNVX") + vtable.CreateCuModuleNVX = auto_cast GetDeviceProcAddr(device, "vkCreateCuModuleNVX") + vtable.CreateDeferredOperationKHR = auto_cast GetDeviceProcAddr(device, "vkCreateDeferredOperationKHR") + vtable.CreateDescriptorPool = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorPool") + vtable.CreateDescriptorSetLayout = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorSetLayout") + vtable.CreateDescriptorUpdateTemplate = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorUpdateTemplate") + vtable.CreateDescriptorUpdateTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorUpdateTemplateKHR") + vtable.CreateEvent = auto_cast GetDeviceProcAddr(device, "vkCreateEvent") + vtable.CreateFence = auto_cast GetDeviceProcAddr(device, "vkCreateFence") + vtable.CreateFramebuffer = auto_cast GetDeviceProcAddr(device, "vkCreateFramebuffer") + vtable.CreateGraphicsPipelines = auto_cast GetDeviceProcAddr(device, "vkCreateGraphicsPipelines") + vtable.CreateImage = auto_cast GetDeviceProcAddr(device, "vkCreateImage") + vtable.CreateImageView = auto_cast GetDeviceProcAddr(device, "vkCreateImageView") + vtable.CreateIndirectCommandsLayoutNV = auto_cast GetDeviceProcAddr(device, "vkCreateIndirectCommandsLayoutNV") + vtable.CreatePipelineCache = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineCache") + vtable.CreatePipelineLayout = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineLayout") + vtable.CreatePrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkCreatePrivateDataSlotEXT") + vtable.CreateQueryPool = auto_cast GetDeviceProcAddr(device, "vkCreateQueryPool") + vtable.CreateRayTracingPipelinesKHR = auto_cast GetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR") + vtable.CreateRayTracingPipelinesNV = auto_cast GetDeviceProcAddr(device, "vkCreateRayTracingPipelinesNV") + vtable.CreateRenderPass = auto_cast GetDeviceProcAddr(device, "vkCreateRenderPass") + vtable.CreateRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCreateRenderPass2") + vtable.CreateRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCreateRenderPass2KHR") + vtable.CreateSampler = auto_cast GetDeviceProcAddr(device, "vkCreateSampler") + vtable.CreateSamplerYcbcrConversion = auto_cast GetDeviceProcAddr(device, "vkCreateSamplerYcbcrConversion") + vtable.CreateSamplerYcbcrConversionKHR = auto_cast GetDeviceProcAddr(device, "vkCreateSamplerYcbcrConversionKHR") + vtable.CreateSemaphore = auto_cast GetDeviceProcAddr(device, "vkCreateSemaphore") + vtable.CreateShaderModule = auto_cast GetDeviceProcAddr(device, "vkCreateShaderModule") + vtable.CreateSharedSwapchainsKHR = auto_cast GetDeviceProcAddr(device, "vkCreateSharedSwapchainsKHR") + vtable.CreateSwapchainKHR = auto_cast GetDeviceProcAddr(device, "vkCreateSwapchainKHR") + vtable.CreateValidationCacheEXT = auto_cast GetDeviceProcAddr(device, "vkCreateValidationCacheEXT") + vtable.DebugMarkerSetObjectNameEXT = auto_cast GetDeviceProcAddr(device, "vkDebugMarkerSetObjectNameEXT") + vtable.DebugMarkerSetObjectTagEXT = auto_cast GetDeviceProcAddr(device, "vkDebugMarkerSetObjectTagEXT") + vtable.DeferredOperationJoinKHR = auto_cast GetDeviceProcAddr(device, "vkDeferredOperationJoinKHR") + vtable.DestroyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR") + vtable.DestroyAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkDestroyAccelerationStructureNV") + vtable.DestroyBuffer = auto_cast GetDeviceProcAddr(device, "vkDestroyBuffer") + vtable.DestroyBufferView = auto_cast GetDeviceProcAddr(device, "vkDestroyBufferView") + vtable.DestroyCommandPool = auto_cast GetDeviceProcAddr(device, "vkDestroyCommandPool") + vtable.DestroyCuFunctionNVX = auto_cast GetDeviceProcAddr(device, "vkDestroyCuFunctionNVX") + vtable.DestroyCuModuleNVX = auto_cast GetDeviceProcAddr(device, "vkDestroyCuModuleNVX") + vtable.DestroyDeferredOperationKHR = auto_cast GetDeviceProcAddr(device, "vkDestroyDeferredOperationKHR") + vtable.DestroyDescriptorPool = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorPool") + vtable.DestroyDescriptorSetLayout = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorSetLayout") + vtable.DestroyDescriptorUpdateTemplate = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorUpdateTemplate") + vtable.DestroyDescriptorUpdateTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorUpdateTemplateKHR") + vtable.DestroyDevice = auto_cast GetDeviceProcAddr(device, "vkDestroyDevice") + vtable.DestroyEvent = auto_cast GetDeviceProcAddr(device, "vkDestroyEvent") + vtable.DestroyFence = auto_cast GetDeviceProcAddr(device, "vkDestroyFence") + vtable.DestroyFramebuffer = auto_cast GetDeviceProcAddr(device, "vkDestroyFramebuffer") + vtable.DestroyImage = auto_cast GetDeviceProcAddr(device, "vkDestroyImage") + vtable.DestroyImageView = auto_cast GetDeviceProcAddr(device, "vkDestroyImageView") + vtable.DestroyIndirectCommandsLayoutNV = auto_cast GetDeviceProcAddr(device, "vkDestroyIndirectCommandsLayoutNV") + vtable.DestroyPipeline = auto_cast GetDeviceProcAddr(device, "vkDestroyPipeline") + vtable.DestroyPipelineCache = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineCache") + vtable.DestroyPipelineLayout = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineLayout") + vtable.DestroyPrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkDestroyPrivateDataSlotEXT") + vtable.DestroyQueryPool = auto_cast GetDeviceProcAddr(device, "vkDestroyQueryPool") + vtable.DestroyRenderPass = auto_cast GetDeviceProcAddr(device, "vkDestroyRenderPass") + vtable.DestroySampler = auto_cast GetDeviceProcAddr(device, "vkDestroySampler") + vtable.DestroySamplerYcbcrConversion = auto_cast GetDeviceProcAddr(device, "vkDestroySamplerYcbcrConversion") + vtable.DestroySamplerYcbcrConversionKHR = auto_cast GetDeviceProcAddr(device, "vkDestroySamplerYcbcrConversionKHR") + vtable.DestroySemaphore = auto_cast GetDeviceProcAddr(device, "vkDestroySemaphore") + vtable.DestroyShaderModule = auto_cast GetDeviceProcAddr(device, "vkDestroyShaderModule") + vtable.DestroySwapchainKHR = auto_cast GetDeviceProcAddr(device, "vkDestroySwapchainKHR") + vtable.DestroyValidationCacheEXT = auto_cast GetDeviceProcAddr(device, "vkDestroyValidationCacheEXT") + vtable.DeviceWaitIdle = auto_cast GetDeviceProcAddr(device, "vkDeviceWaitIdle") + vtable.DisplayPowerControlEXT = auto_cast GetDeviceProcAddr(device, "vkDisplayPowerControlEXT") + vtable.EndCommandBuffer = auto_cast GetDeviceProcAddr(device, "vkEndCommandBuffer") + vtable.FlushMappedMemoryRanges = auto_cast GetDeviceProcAddr(device, "vkFlushMappedMemoryRanges") + vtable.FreeCommandBuffers = auto_cast GetDeviceProcAddr(device, "vkFreeCommandBuffers") + vtable.FreeDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkFreeDescriptorSets") + vtable.FreeMemory = auto_cast GetDeviceProcAddr(device, "vkFreeMemory") + vtable.GetAccelerationStructureBuildSizesKHR = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureBuildSizesKHR") + vtable.GetAccelerationStructureDeviceAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR") + vtable.GetAccelerationStructureHandleNV = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureHandleNV") + vtable.GetAccelerationStructureMemoryRequirementsNV = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsNV") + vtable.GetBufferDeviceAddress = auto_cast GetDeviceProcAddr(device, "vkGetBufferDeviceAddress") + vtable.GetBufferDeviceAddressEXT = auto_cast GetDeviceProcAddr(device, "vkGetBufferDeviceAddressEXT") + vtable.GetBufferDeviceAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR") + vtable.GetBufferMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetBufferMemoryRequirements") + vtable.GetBufferMemoryRequirements2 = auto_cast GetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2") + vtable.GetBufferMemoryRequirements2KHR = auto_cast GetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2KHR") + vtable.GetBufferOpaqueCaptureAddress = auto_cast GetDeviceProcAddr(device, "vkGetBufferOpaqueCaptureAddress") + vtable.GetBufferOpaqueCaptureAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetBufferOpaqueCaptureAddressKHR") + vtable.GetCalibratedTimestampsEXT = auto_cast GetDeviceProcAddr(device, "vkGetCalibratedTimestampsEXT") + vtable.GetDeferredOperationMaxConcurrencyKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationMaxConcurrencyKHR") + vtable.GetDeferredOperationResultKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationResultKHR") + vtable.GetDescriptorSetLayoutSupport = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupport") + vtable.GetDescriptorSetLayoutSupportKHR = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupportKHR") + vtable.GetDeviceAccelerationStructureCompatibilityKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceAccelerationStructureCompatibilityKHR") + vtable.GetDeviceGroupPeerMemoryFeatures = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeatures") + vtable.GetDeviceGroupPeerMemoryFeaturesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeaturesKHR") + vtable.GetDeviceGroupPresentCapabilitiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPresentCapabilitiesKHR") + vtable.GetDeviceGroupSurfacePresentModes2EXT = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModes2EXT") + vtable.GetDeviceGroupSurfacePresentModesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModesKHR") + vtable.GetDeviceMemoryCommitment = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryCommitment") + vtable.GetDeviceMemoryOpaqueCaptureAddress = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddress") + vtable.GetDeviceMemoryOpaqueCaptureAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") + vtable.GetDeviceProcAddr = auto_cast GetDeviceProcAddr(device, "vkGetDeviceProcAddr") + vtable.GetDeviceQueue = auto_cast GetDeviceProcAddr(device, "vkGetDeviceQueue") + vtable.GetDeviceQueue2 = auto_cast GetDeviceProcAddr(device, "vkGetDeviceQueue2") + vtable.GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = auto_cast GetDeviceProcAddr(device, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI") + vtable.GetEventStatus = auto_cast GetDeviceProcAddr(device, "vkGetEventStatus") + vtable.GetFenceFdKHR = auto_cast GetDeviceProcAddr(device, "vkGetFenceFdKHR") + vtable.GetFenceStatus = auto_cast GetDeviceProcAddr(device, "vkGetFenceStatus") + vtable.GetFenceWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkGetFenceWin32HandleKHR") + vtable.GetGeneratedCommandsMemoryRequirementsNV = auto_cast GetDeviceProcAddr(device, "vkGetGeneratedCommandsMemoryRequirementsNV") + vtable.GetImageDrmFormatModifierPropertiesEXT = auto_cast GetDeviceProcAddr(device, "vkGetImageDrmFormatModifierPropertiesEXT") + vtable.GetImageMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetImageMemoryRequirements") + vtable.GetImageMemoryRequirements2 = auto_cast GetDeviceProcAddr(device, "vkGetImageMemoryRequirements2") + vtable.GetImageMemoryRequirements2KHR = auto_cast GetDeviceProcAddr(device, "vkGetImageMemoryRequirements2KHR") + vtable.GetImageSparseMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetImageSparseMemoryRequirements") + vtable.GetImageSparseMemoryRequirements2 = auto_cast GetDeviceProcAddr(device, "vkGetImageSparseMemoryRequirements2") + vtable.GetImageSparseMemoryRequirements2KHR = auto_cast GetDeviceProcAddr(device, "vkGetImageSparseMemoryRequirements2KHR") + vtable.GetImageSubresourceLayout = auto_cast GetDeviceProcAddr(device, "vkGetImageSubresourceLayout") + vtable.GetImageViewAddressNVX = auto_cast GetDeviceProcAddr(device, "vkGetImageViewAddressNVX") + vtable.GetImageViewHandleNVX = auto_cast GetDeviceProcAddr(device, "vkGetImageViewHandleNVX") + vtable.GetMemoryFdKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryFdKHR") + vtable.GetMemoryFdPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryFdPropertiesKHR") + vtable.GetMemoryHostPointerPropertiesEXT = auto_cast GetDeviceProcAddr(device, "vkGetMemoryHostPointerPropertiesEXT") + vtable.GetMemoryRemoteAddressNV = auto_cast GetDeviceProcAddr(device, "vkGetMemoryRemoteAddressNV") + vtable.GetMemoryWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryWin32HandleKHR") + vtable.GetMemoryWin32HandleNV = auto_cast GetDeviceProcAddr(device, "vkGetMemoryWin32HandleNV") + vtable.GetMemoryWin32HandlePropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryWin32HandlePropertiesKHR") + vtable.GetPastPresentationTimingGOOGLE = auto_cast GetDeviceProcAddr(device, "vkGetPastPresentationTimingGOOGLE") + vtable.GetPerformanceParameterINTEL = auto_cast GetDeviceProcAddr(device, "vkGetPerformanceParameterINTEL") + vtable.GetPipelineCacheData = auto_cast GetDeviceProcAddr(device, "vkGetPipelineCacheData") + vtable.GetPipelineExecutableInternalRepresentationsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableInternalRepresentationsKHR") + vtable.GetPipelineExecutablePropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutablePropertiesKHR") + vtable.GetPipelineExecutableStatisticsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableStatisticsKHR") + vtable.GetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkGetPrivateDataEXT") + vtable.GetQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkGetQueryPoolResults") + vtable.GetQueueCheckpointData2NV = auto_cast GetDeviceProcAddr(device, "vkGetQueueCheckpointData2NV") + vtable.GetQueueCheckpointDataNV = auto_cast GetDeviceProcAddr(device, "vkGetQueueCheckpointDataNV") + vtable.GetRayTracingCaptureReplayShaderGroupHandlesKHR = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR") + vtable.GetRayTracingShaderGroupHandlesKHR = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR") + vtable.GetRayTracingShaderGroupHandlesNV = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesNV") + vtable.GetRayTracingShaderGroupStackSizeKHR = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingShaderGroupStackSizeKHR") + vtable.GetRefreshCycleDurationGOOGLE = auto_cast GetDeviceProcAddr(device, "vkGetRefreshCycleDurationGOOGLE") + vtable.GetRenderAreaGranularity = auto_cast GetDeviceProcAddr(device, "vkGetRenderAreaGranularity") + vtable.GetSemaphoreCounterValue = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreCounterValue") + vtable.GetSemaphoreCounterValueKHR = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreCounterValueKHR") + vtable.GetSemaphoreFdKHR = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreFdKHR") + vtable.GetSemaphoreWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreWin32HandleKHR") + vtable.GetShaderInfoAMD = auto_cast GetDeviceProcAddr(device, "vkGetShaderInfoAMD") + vtable.GetSwapchainCounterEXT = auto_cast GetDeviceProcAddr(device, "vkGetSwapchainCounterEXT") + vtable.GetSwapchainImagesKHR = auto_cast GetDeviceProcAddr(device, "vkGetSwapchainImagesKHR") + vtable.GetSwapchainStatusKHR = auto_cast GetDeviceProcAddr(device, "vkGetSwapchainStatusKHR") + vtable.GetValidationCacheDataEXT = auto_cast GetDeviceProcAddr(device, "vkGetValidationCacheDataEXT") + vtable.ImportFenceFdKHR = auto_cast GetDeviceProcAddr(device, "vkImportFenceFdKHR") + vtable.ImportFenceWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkImportFenceWin32HandleKHR") + vtable.ImportSemaphoreFdKHR = auto_cast GetDeviceProcAddr(device, "vkImportSemaphoreFdKHR") + vtable.ImportSemaphoreWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkImportSemaphoreWin32HandleKHR") + vtable.InitializePerformanceApiINTEL = auto_cast GetDeviceProcAddr(device, "vkInitializePerformanceApiINTEL") + vtable.InvalidateMappedMemoryRanges = auto_cast GetDeviceProcAddr(device, "vkInvalidateMappedMemoryRanges") + vtable.MapMemory = auto_cast GetDeviceProcAddr(device, "vkMapMemory") + vtable.MergePipelineCaches = auto_cast GetDeviceProcAddr(device, "vkMergePipelineCaches") + vtable.MergeValidationCachesEXT = auto_cast GetDeviceProcAddr(device, "vkMergeValidationCachesEXT") + vtable.QueueBeginDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkQueueBeginDebugUtilsLabelEXT") + vtable.QueueBindSparse = auto_cast GetDeviceProcAddr(device, "vkQueueBindSparse") + vtable.QueueEndDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkQueueEndDebugUtilsLabelEXT") + vtable.QueueInsertDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkQueueInsertDebugUtilsLabelEXT") + vtable.QueuePresentKHR = auto_cast GetDeviceProcAddr(device, "vkQueuePresentKHR") + vtable.QueueSetPerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkQueueSetPerformanceConfigurationINTEL") + vtable.QueueSubmit = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit") + vtable.QueueSubmit2KHR = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit2KHR") + vtable.QueueWaitIdle = auto_cast GetDeviceProcAddr(device, "vkQueueWaitIdle") + vtable.RegisterDeviceEventEXT = auto_cast GetDeviceProcAddr(device, "vkRegisterDeviceEventEXT") + vtable.RegisterDisplayEventEXT = auto_cast GetDeviceProcAddr(device, "vkRegisterDisplayEventEXT") + vtable.ReleaseFullScreenExclusiveModeEXT = auto_cast GetDeviceProcAddr(device, "vkReleaseFullScreenExclusiveModeEXT") + vtable.ReleasePerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkReleasePerformanceConfigurationINTEL") + vtable.ReleaseProfilingLockKHR = auto_cast GetDeviceProcAddr(device, "vkReleaseProfilingLockKHR") + vtable.ResetCommandBuffer = auto_cast GetDeviceProcAddr(device, "vkResetCommandBuffer") + vtable.ResetCommandPool = auto_cast GetDeviceProcAddr(device, "vkResetCommandPool") + vtable.ResetDescriptorPool = auto_cast GetDeviceProcAddr(device, "vkResetDescriptorPool") + vtable.ResetEvent = auto_cast GetDeviceProcAddr(device, "vkResetEvent") + vtable.ResetFences = auto_cast GetDeviceProcAddr(device, "vkResetFences") + vtable.ResetQueryPool = auto_cast GetDeviceProcAddr(device, "vkResetQueryPool") + vtable.ResetQueryPoolEXT = auto_cast GetDeviceProcAddr(device, "vkResetQueryPoolEXT") + vtable.SetDebugUtilsObjectNameEXT = auto_cast GetDeviceProcAddr(device, "vkSetDebugUtilsObjectNameEXT") + vtable.SetDebugUtilsObjectTagEXT = auto_cast GetDeviceProcAddr(device, "vkSetDebugUtilsObjectTagEXT") + vtable.SetDeviceMemoryPriorityEXT = auto_cast GetDeviceProcAddr(device, "vkSetDeviceMemoryPriorityEXT") + vtable.SetEvent = auto_cast GetDeviceProcAddr(device, "vkSetEvent") + vtable.SetHdrMetadataEXT = auto_cast GetDeviceProcAddr(device, "vkSetHdrMetadataEXT") + vtable.SetLocalDimmingAMD = auto_cast GetDeviceProcAddr(device, "vkSetLocalDimmingAMD") + vtable.SetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkSetPrivateDataEXT") + vtable.SignalSemaphore = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphore") + vtable.SignalSemaphoreKHR = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphoreKHR") + vtable.TrimCommandPool = auto_cast GetDeviceProcAddr(device, "vkTrimCommandPool") + vtable.TrimCommandPoolKHR = auto_cast GetDeviceProcAddr(device, "vkTrimCommandPoolKHR") + vtable.UninitializePerformanceApiINTEL = auto_cast GetDeviceProcAddr(device, "vkUninitializePerformanceApiINTEL") + vtable.UnmapMemory = auto_cast GetDeviceProcAddr(device, "vkUnmapMemory") + vtable.UpdateDescriptorSetWithTemplate = auto_cast GetDeviceProcAddr(device, "vkUpdateDescriptorSetWithTemplate") + vtable.UpdateDescriptorSetWithTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkUpdateDescriptorSetWithTemplateKHR") + vtable.UpdateDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkUpdateDescriptorSets") + vtable.WaitForFences = auto_cast GetDeviceProcAddr(device, "vkWaitForFences") + vtable.WaitForPresentKHR = auto_cast GetDeviceProcAddr(device, "vkWaitForPresentKHR") + vtable.WaitSemaphores = auto_cast GetDeviceProcAddr(device, "vkWaitSemaphores") + vtable.WaitSemaphoresKHR = auto_cast GetDeviceProcAddr(device, "vkWaitSemaphoresKHR") + vtable.WriteAccelerationStructuresPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkWriteAccelerationStructuresPropertiesKHR") +} + +load_proc_addresses_device :: proc(device: Device) { + AcquireFullScreenExclusiveModeEXT = auto_cast GetDeviceProcAddr(device, "vkAcquireFullScreenExclusiveModeEXT") + AcquireNextImage2KHR = auto_cast GetDeviceProcAddr(device, "vkAcquireNextImage2KHR") + AcquireNextImageKHR = auto_cast GetDeviceProcAddr(device, "vkAcquireNextImageKHR") + AcquirePerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkAcquirePerformanceConfigurationINTEL") + AcquireProfilingLockKHR = auto_cast GetDeviceProcAddr(device, "vkAcquireProfilingLockKHR") + AllocateCommandBuffers = auto_cast GetDeviceProcAddr(device, "vkAllocateCommandBuffers") + AllocateDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkAllocateDescriptorSets") + AllocateMemory = auto_cast GetDeviceProcAddr(device, "vkAllocateMemory") + BeginCommandBuffer = auto_cast GetDeviceProcAddr(device, "vkBeginCommandBuffer") + BindAccelerationStructureMemoryNV = auto_cast GetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryNV") + BindBufferMemory = auto_cast GetDeviceProcAddr(device, "vkBindBufferMemory") + BindBufferMemory2 = auto_cast GetDeviceProcAddr(device, "vkBindBufferMemory2") + BindBufferMemory2KHR = auto_cast GetDeviceProcAddr(device, "vkBindBufferMemory2KHR") + BindImageMemory = auto_cast GetDeviceProcAddr(device, "vkBindImageMemory") + BindImageMemory2 = auto_cast GetDeviceProcAddr(device, "vkBindImageMemory2") + BindImageMemory2KHR = auto_cast GetDeviceProcAddr(device, "vkBindImageMemory2KHR") + BuildAccelerationStructuresKHR = auto_cast GetDeviceProcAddr(device, "vkBuildAccelerationStructuresKHR") + CmdBeginConditionalRenderingEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginConditionalRenderingEXT") + CmdBeginDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginDebugUtilsLabelEXT") + CmdBeginQuery = auto_cast GetDeviceProcAddr(device, "vkCmdBeginQuery") + CmdBeginQueryIndexedEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginQueryIndexedEXT") + CmdBeginRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass") + CmdBeginRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2") + CmdBeginRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2KHR") + CmdBeginTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginTransformFeedbackEXT") + CmdBindDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkCmdBindDescriptorSets") + CmdBindIndexBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdBindIndexBuffer") + CmdBindInvocationMaskHUAWEI = auto_cast GetDeviceProcAddr(device, "vkCmdBindInvocationMaskHUAWEI") + CmdBindPipeline = auto_cast GetDeviceProcAddr(device, "vkCmdBindPipeline") + CmdBindPipelineShaderGroupNV = auto_cast GetDeviceProcAddr(device, "vkCmdBindPipelineShaderGroupNV") + CmdBindShadingRateImageNV = auto_cast GetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV") + CmdBindTransformFeedbackBuffersEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindTransformFeedbackBuffersEXT") + CmdBindVertexBuffers = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers") + CmdBindVertexBuffers2EXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers2EXT") + CmdBlitImage = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage") + CmdBlitImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage2KHR") + CmdBuildAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV") + CmdBuildAccelerationStructuresIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresIndirectKHR") + CmdBuildAccelerationStructuresKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresKHR") + CmdClearAttachments = auto_cast GetDeviceProcAddr(device, "vkCmdClearAttachments") + CmdClearColorImage = auto_cast GetDeviceProcAddr(device, "vkCmdClearColorImage") + CmdClearDepthStencilImage = auto_cast GetDeviceProcAddr(device, "vkCmdClearDepthStencilImage") + CmdCopyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureKHR") + CmdCopyAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureNV") + CmdCopyAccelerationStructureToMemoryKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureToMemoryKHR") + CmdCopyBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer") + CmdCopyBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer2KHR") + CmdCopyBufferToImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage") + CmdCopyBufferToImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage2KHR") + CmdCopyImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage") + CmdCopyImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage2KHR") + CmdCopyImageToBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer") + CmdCopyImageToBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer2KHR") + CmdCopyMemoryToAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyMemoryToAccelerationStructureKHR") + CmdCopyQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkCmdCopyQueryPoolResults") + CmdCuLaunchKernelNVX = auto_cast GetDeviceProcAddr(device, "vkCmdCuLaunchKernelNVX") + CmdDebugMarkerBeginEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDebugMarkerBeginEXT") + CmdDebugMarkerEndEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDebugMarkerEndEXT") + CmdDebugMarkerInsertEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDebugMarkerInsertEXT") + CmdDispatch = auto_cast GetDeviceProcAddr(device, "vkCmdDispatch") + CmdDispatchBase = auto_cast GetDeviceProcAddr(device, "vkCmdDispatchBase") + CmdDispatchBaseKHR = auto_cast GetDeviceProcAddr(device, "vkCmdDispatchBaseKHR") + CmdDispatchIndirect = auto_cast GetDeviceProcAddr(device, "vkCmdDispatchIndirect") + CmdDraw = auto_cast GetDeviceProcAddr(device, "vkCmdDraw") + CmdDrawIndexed = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexed") + CmdDrawIndexedIndirect = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirect") + CmdDrawIndexedIndirectCount = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirectCount") + CmdDrawIndexedIndirectCountAMD = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirectCountAMD") + CmdDrawIndexedIndirectCountKHR = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndexedIndirectCountKHR") + CmdDrawIndirect = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirect") + CmdDrawIndirectByteCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectByteCountEXT") + CmdDrawIndirectCount = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectCount") + CmdDrawIndirectCountAMD = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectCountAMD") + CmdDrawIndirectCountKHR = auto_cast GetDeviceProcAddr(device, "vkCmdDrawIndirectCountKHR") + CmdDrawMeshTasksIndirectCountNV = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMeshTasksIndirectCountNV") + CmdDrawMeshTasksIndirectNV = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMeshTasksIndirectNV") + CmdDrawMeshTasksNV = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMeshTasksNV") + CmdDrawMultiEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMultiEXT") + CmdDrawMultiIndexedEXT = auto_cast GetDeviceProcAddr(device, "vkCmdDrawMultiIndexedEXT") + CmdEndConditionalRenderingEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndConditionalRenderingEXT") + CmdEndDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndDebugUtilsLabelEXT") + CmdEndQuery = auto_cast GetDeviceProcAddr(device, "vkCmdEndQuery") + CmdEndQueryIndexedEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndQueryIndexedEXT") + CmdEndRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass") + CmdEndRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2") + CmdEndRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2KHR") + CmdEndTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndTransformFeedbackEXT") + CmdExecuteCommands = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteCommands") + CmdExecuteGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteGeneratedCommandsNV") + CmdFillBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdFillBuffer") + CmdInsertDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkCmdInsertDebugUtilsLabelEXT") + CmdNextSubpass = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass") + CmdNextSubpass2 = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2") + CmdNextSubpass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2KHR") + CmdPipelineBarrier = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier") + CmdPipelineBarrier2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier2KHR") + CmdPreprocessGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdPreprocessGeneratedCommandsNV") + CmdPushConstants = auto_cast GetDeviceProcAddr(device, "vkCmdPushConstants") + CmdPushDescriptorSetKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetKHR") + CmdPushDescriptorSetWithTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetWithTemplateKHR") + CmdResetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent") + CmdResetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent2KHR") + CmdResetQueryPool = auto_cast GetDeviceProcAddr(device, "vkCmdResetQueryPool") + CmdResolveImage = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage") + CmdResolveImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage2KHR") + CmdSetBlendConstants = auto_cast GetDeviceProcAddr(device, "vkCmdSetBlendConstants") + CmdSetCheckpointNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCheckpointNV") + CmdSetCoarseSampleOrderNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCoarseSampleOrderNV") + CmdSetCullModeEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetCullModeEXT") + CmdSetDepthBias = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBias") + CmdSetDepthBiasEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBiasEnableEXT") + CmdSetDepthBounds = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBounds") + CmdSetDepthBoundsTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnableEXT") + CmdSetDepthCompareOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthCompareOpEXT") + CmdSetDepthTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthTestEnableEXT") + CmdSetDepthWriteEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthWriteEnableEXT") + CmdSetDeviceMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMask") + CmdSetDeviceMaskKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMaskKHR") + CmdSetDiscardRectangleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDiscardRectangleEXT") + CmdSetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent") + CmdSetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent2KHR") + CmdSetExclusiveScissorNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetExclusiveScissorNV") + CmdSetFragmentShadingRateEnumNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateEnumNV") + CmdSetFragmentShadingRateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateKHR") + CmdSetFrontFaceEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetFrontFaceEXT") + CmdSetLineStippleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineStippleEXT") + CmdSetLineWidth = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineWidth") + CmdSetLogicOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetLogicOpEXT") + CmdSetPatchControlPointsEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPatchControlPointsEXT") + CmdSetPerformanceMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceMarkerINTEL") + CmdSetPerformanceOverrideINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceOverrideINTEL") + CmdSetPerformanceStreamMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceStreamMarkerINTEL") + CmdSetPrimitiveRestartEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveRestartEnableEXT") + CmdSetPrimitiveTopologyEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveTopologyEXT") + CmdSetRasterizerDiscardEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetRasterizerDiscardEnableEXT") + CmdSetRayTracingPipelineStackSizeKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetRayTracingPipelineStackSizeKHR") + CmdSetSampleLocationsEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetSampleLocationsEXT") + CmdSetScissor = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissor") + CmdSetScissorWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissorWithCountEXT") + CmdSetStencilCompareMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilCompareMask") + CmdSetStencilOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilOpEXT") + CmdSetStencilReference = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilReference") + CmdSetStencilTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT") + CmdSetStencilWriteMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilWriteMask") + CmdSetVertexInputEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetVertexInputEXT") + CmdSetViewport = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewport") + CmdSetViewportShadingRatePaletteNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportShadingRatePaletteNV") + CmdSetViewportWScalingNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWScalingNV") + CmdSetViewportWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT") + CmdSubpassShadingHUAWEI = auto_cast GetDeviceProcAddr(device, "vkCmdSubpassShadingHUAWEI") + CmdTraceRaysIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysIndirectKHR") + CmdTraceRaysKHR = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysKHR") + CmdTraceRaysNV = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysNV") + CmdUpdateBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdUpdateBuffer") + CmdWaitEvents = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents") + CmdWaitEvents2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents2KHR") + CmdWriteAccelerationStructuresPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesKHR") + CmdWriteAccelerationStructuresPropertiesNV = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesNV") + CmdWriteBufferMarker2AMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarker2AMD") + CmdWriteBufferMarkerAMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarkerAMD") + CmdWriteTimestamp = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp") + CmdWriteTimestamp2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp2KHR") + CompileDeferredNV = auto_cast GetDeviceProcAddr(device, "vkCompileDeferredNV") + CopyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCopyAccelerationStructureKHR") + CopyAccelerationStructureToMemoryKHR = auto_cast GetDeviceProcAddr(device, "vkCopyAccelerationStructureToMemoryKHR") + CopyMemoryToAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCopyMemoryToAccelerationStructureKHR") + CreateAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR") + CreateAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCreateAccelerationStructureNV") + CreateBuffer = auto_cast GetDeviceProcAddr(device, "vkCreateBuffer") + CreateBufferView = auto_cast GetDeviceProcAddr(device, "vkCreateBufferView") + CreateCommandPool = auto_cast GetDeviceProcAddr(device, "vkCreateCommandPool") + CreateComputePipelines = auto_cast GetDeviceProcAddr(device, "vkCreateComputePipelines") + CreateCuFunctionNVX = auto_cast GetDeviceProcAddr(device, "vkCreateCuFunctionNVX") + CreateCuModuleNVX = auto_cast GetDeviceProcAddr(device, "vkCreateCuModuleNVX") + CreateDeferredOperationKHR = auto_cast GetDeviceProcAddr(device, "vkCreateDeferredOperationKHR") + CreateDescriptorPool = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorPool") + CreateDescriptorSetLayout = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorSetLayout") + CreateDescriptorUpdateTemplate = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorUpdateTemplate") + CreateDescriptorUpdateTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkCreateDescriptorUpdateTemplateKHR") + CreateEvent = auto_cast GetDeviceProcAddr(device, "vkCreateEvent") + CreateFence = auto_cast GetDeviceProcAddr(device, "vkCreateFence") + CreateFramebuffer = auto_cast GetDeviceProcAddr(device, "vkCreateFramebuffer") + CreateGraphicsPipelines = auto_cast GetDeviceProcAddr(device, "vkCreateGraphicsPipelines") + CreateImage = auto_cast GetDeviceProcAddr(device, "vkCreateImage") + CreateImageView = auto_cast GetDeviceProcAddr(device, "vkCreateImageView") + CreateIndirectCommandsLayoutNV = auto_cast GetDeviceProcAddr(device, "vkCreateIndirectCommandsLayoutNV") + CreatePipelineCache = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineCache") + CreatePipelineLayout = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineLayout") + CreatePrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkCreatePrivateDataSlotEXT") + CreateQueryPool = auto_cast GetDeviceProcAddr(device, "vkCreateQueryPool") + CreateRayTracingPipelinesKHR = auto_cast GetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR") + CreateRayTracingPipelinesNV = auto_cast GetDeviceProcAddr(device, "vkCreateRayTracingPipelinesNV") + CreateRenderPass = auto_cast GetDeviceProcAddr(device, "vkCreateRenderPass") + CreateRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCreateRenderPass2") + CreateRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCreateRenderPass2KHR") + CreateSampler = auto_cast GetDeviceProcAddr(device, "vkCreateSampler") + CreateSamplerYcbcrConversion = auto_cast GetDeviceProcAddr(device, "vkCreateSamplerYcbcrConversion") + CreateSamplerYcbcrConversionKHR = auto_cast GetDeviceProcAddr(device, "vkCreateSamplerYcbcrConversionKHR") + CreateSemaphore = auto_cast GetDeviceProcAddr(device, "vkCreateSemaphore") + CreateShaderModule = auto_cast GetDeviceProcAddr(device, "vkCreateShaderModule") + CreateSharedSwapchainsKHR = auto_cast GetDeviceProcAddr(device, "vkCreateSharedSwapchainsKHR") + CreateSwapchainKHR = auto_cast GetDeviceProcAddr(device, "vkCreateSwapchainKHR") + CreateValidationCacheEXT = auto_cast GetDeviceProcAddr(device, "vkCreateValidationCacheEXT") + DebugMarkerSetObjectNameEXT = auto_cast GetDeviceProcAddr(device, "vkDebugMarkerSetObjectNameEXT") + DebugMarkerSetObjectTagEXT = auto_cast GetDeviceProcAddr(device, "vkDebugMarkerSetObjectTagEXT") + DeferredOperationJoinKHR = auto_cast GetDeviceProcAddr(device, "vkDeferredOperationJoinKHR") + DestroyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR") + DestroyAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkDestroyAccelerationStructureNV") + DestroyBuffer = auto_cast GetDeviceProcAddr(device, "vkDestroyBuffer") + DestroyBufferView = auto_cast GetDeviceProcAddr(device, "vkDestroyBufferView") + DestroyCommandPool = auto_cast GetDeviceProcAddr(device, "vkDestroyCommandPool") + DestroyCuFunctionNVX = auto_cast GetDeviceProcAddr(device, "vkDestroyCuFunctionNVX") + DestroyCuModuleNVX = auto_cast GetDeviceProcAddr(device, "vkDestroyCuModuleNVX") + DestroyDeferredOperationKHR = auto_cast GetDeviceProcAddr(device, "vkDestroyDeferredOperationKHR") + DestroyDescriptorPool = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorPool") + DestroyDescriptorSetLayout = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorSetLayout") + DestroyDescriptorUpdateTemplate = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorUpdateTemplate") + DestroyDescriptorUpdateTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkDestroyDescriptorUpdateTemplateKHR") + DestroyDevice = auto_cast GetDeviceProcAddr(device, "vkDestroyDevice") + DestroyEvent = auto_cast GetDeviceProcAddr(device, "vkDestroyEvent") + DestroyFence = auto_cast GetDeviceProcAddr(device, "vkDestroyFence") + DestroyFramebuffer = auto_cast GetDeviceProcAddr(device, "vkDestroyFramebuffer") + DestroyImage = auto_cast GetDeviceProcAddr(device, "vkDestroyImage") + DestroyImageView = auto_cast GetDeviceProcAddr(device, "vkDestroyImageView") + DestroyIndirectCommandsLayoutNV = auto_cast GetDeviceProcAddr(device, "vkDestroyIndirectCommandsLayoutNV") + DestroyPipeline = auto_cast GetDeviceProcAddr(device, "vkDestroyPipeline") + DestroyPipelineCache = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineCache") + DestroyPipelineLayout = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineLayout") + DestroyPrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkDestroyPrivateDataSlotEXT") + DestroyQueryPool = auto_cast GetDeviceProcAddr(device, "vkDestroyQueryPool") + DestroyRenderPass = auto_cast GetDeviceProcAddr(device, "vkDestroyRenderPass") + DestroySampler = auto_cast GetDeviceProcAddr(device, "vkDestroySampler") + DestroySamplerYcbcrConversion = auto_cast GetDeviceProcAddr(device, "vkDestroySamplerYcbcrConversion") + DestroySamplerYcbcrConversionKHR = auto_cast GetDeviceProcAddr(device, "vkDestroySamplerYcbcrConversionKHR") + DestroySemaphore = auto_cast GetDeviceProcAddr(device, "vkDestroySemaphore") + DestroyShaderModule = auto_cast GetDeviceProcAddr(device, "vkDestroyShaderModule") + DestroySwapchainKHR = auto_cast GetDeviceProcAddr(device, "vkDestroySwapchainKHR") + DestroyValidationCacheEXT = auto_cast GetDeviceProcAddr(device, "vkDestroyValidationCacheEXT") + DeviceWaitIdle = auto_cast GetDeviceProcAddr(device, "vkDeviceWaitIdle") + DisplayPowerControlEXT = auto_cast GetDeviceProcAddr(device, "vkDisplayPowerControlEXT") + EndCommandBuffer = auto_cast GetDeviceProcAddr(device, "vkEndCommandBuffer") + FlushMappedMemoryRanges = auto_cast GetDeviceProcAddr(device, "vkFlushMappedMemoryRanges") + FreeCommandBuffers = auto_cast GetDeviceProcAddr(device, "vkFreeCommandBuffers") + FreeDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkFreeDescriptorSets") + FreeMemory = auto_cast GetDeviceProcAddr(device, "vkFreeMemory") + GetAccelerationStructureBuildSizesKHR = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureBuildSizesKHR") + GetAccelerationStructureDeviceAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR") + GetAccelerationStructureHandleNV = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureHandleNV") + GetAccelerationStructureMemoryRequirementsNV = auto_cast GetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsNV") + GetBufferDeviceAddress = auto_cast GetDeviceProcAddr(device, "vkGetBufferDeviceAddress") + GetBufferDeviceAddressEXT = auto_cast GetDeviceProcAddr(device, "vkGetBufferDeviceAddressEXT") + GetBufferDeviceAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR") + GetBufferMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetBufferMemoryRequirements") + GetBufferMemoryRequirements2 = auto_cast GetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2") + GetBufferMemoryRequirements2KHR = auto_cast GetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2KHR") + GetBufferOpaqueCaptureAddress = auto_cast GetDeviceProcAddr(device, "vkGetBufferOpaqueCaptureAddress") + GetBufferOpaqueCaptureAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetBufferOpaqueCaptureAddressKHR") + GetCalibratedTimestampsEXT = auto_cast GetDeviceProcAddr(device, "vkGetCalibratedTimestampsEXT") + GetDeferredOperationMaxConcurrencyKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationMaxConcurrencyKHR") + GetDeferredOperationResultKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationResultKHR") + GetDescriptorSetLayoutSupport = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupport") + GetDescriptorSetLayoutSupportKHR = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupportKHR") + GetDeviceAccelerationStructureCompatibilityKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceAccelerationStructureCompatibilityKHR") + GetDeviceGroupPeerMemoryFeatures = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeatures") + GetDeviceGroupPeerMemoryFeaturesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeaturesKHR") + GetDeviceGroupPresentCapabilitiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPresentCapabilitiesKHR") + GetDeviceGroupSurfacePresentModes2EXT = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModes2EXT") + GetDeviceGroupSurfacePresentModesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModesKHR") + GetDeviceMemoryCommitment = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryCommitment") + GetDeviceMemoryOpaqueCaptureAddress = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddress") + GetDeviceMemoryOpaqueCaptureAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") + GetDeviceProcAddr = auto_cast GetDeviceProcAddr(device, "vkGetDeviceProcAddr") + GetDeviceQueue = auto_cast GetDeviceProcAddr(device, "vkGetDeviceQueue") + GetDeviceQueue2 = auto_cast GetDeviceProcAddr(device, "vkGetDeviceQueue2") + GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = auto_cast GetDeviceProcAddr(device, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI") + GetEventStatus = auto_cast GetDeviceProcAddr(device, "vkGetEventStatus") + GetFenceFdKHR = auto_cast GetDeviceProcAddr(device, "vkGetFenceFdKHR") + GetFenceStatus = auto_cast GetDeviceProcAddr(device, "vkGetFenceStatus") + GetFenceWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkGetFenceWin32HandleKHR") + GetGeneratedCommandsMemoryRequirementsNV = auto_cast GetDeviceProcAddr(device, "vkGetGeneratedCommandsMemoryRequirementsNV") + GetImageDrmFormatModifierPropertiesEXT = auto_cast GetDeviceProcAddr(device, "vkGetImageDrmFormatModifierPropertiesEXT") + GetImageMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetImageMemoryRequirements") + GetImageMemoryRequirements2 = auto_cast GetDeviceProcAddr(device, "vkGetImageMemoryRequirements2") + GetImageMemoryRequirements2KHR = auto_cast GetDeviceProcAddr(device, "vkGetImageMemoryRequirements2KHR") + GetImageSparseMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetImageSparseMemoryRequirements") + GetImageSparseMemoryRequirements2 = auto_cast GetDeviceProcAddr(device, "vkGetImageSparseMemoryRequirements2") + GetImageSparseMemoryRequirements2KHR = auto_cast GetDeviceProcAddr(device, "vkGetImageSparseMemoryRequirements2KHR") + GetImageSubresourceLayout = auto_cast GetDeviceProcAddr(device, "vkGetImageSubresourceLayout") + GetImageViewAddressNVX = auto_cast GetDeviceProcAddr(device, "vkGetImageViewAddressNVX") + GetImageViewHandleNVX = auto_cast GetDeviceProcAddr(device, "vkGetImageViewHandleNVX") + GetMemoryFdKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryFdKHR") + GetMemoryFdPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryFdPropertiesKHR") + GetMemoryHostPointerPropertiesEXT = auto_cast GetDeviceProcAddr(device, "vkGetMemoryHostPointerPropertiesEXT") + GetMemoryRemoteAddressNV = auto_cast GetDeviceProcAddr(device, "vkGetMemoryRemoteAddressNV") + GetMemoryWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryWin32HandleKHR") + GetMemoryWin32HandleNV = auto_cast GetDeviceProcAddr(device, "vkGetMemoryWin32HandleNV") + GetMemoryWin32HandlePropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetMemoryWin32HandlePropertiesKHR") + GetPastPresentationTimingGOOGLE = auto_cast GetDeviceProcAddr(device, "vkGetPastPresentationTimingGOOGLE") + GetPerformanceParameterINTEL = auto_cast GetDeviceProcAddr(device, "vkGetPerformanceParameterINTEL") + GetPipelineCacheData = auto_cast GetDeviceProcAddr(device, "vkGetPipelineCacheData") + GetPipelineExecutableInternalRepresentationsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableInternalRepresentationsKHR") + GetPipelineExecutablePropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutablePropertiesKHR") + GetPipelineExecutableStatisticsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableStatisticsKHR") + GetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkGetPrivateDataEXT") + GetQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkGetQueryPoolResults") + GetQueueCheckpointData2NV = auto_cast GetDeviceProcAddr(device, "vkGetQueueCheckpointData2NV") + GetQueueCheckpointDataNV = auto_cast GetDeviceProcAddr(device, "vkGetQueueCheckpointDataNV") + GetRayTracingCaptureReplayShaderGroupHandlesKHR = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR") + GetRayTracingShaderGroupHandlesKHR = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR") + GetRayTracingShaderGroupHandlesNV = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesNV") + GetRayTracingShaderGroupStackSizeKHR = auto_cast GetDeviceProcAddr(device, "vkGetRayTracingShaderGroupStackSizeKHR") + GetRefreshCycleDurationGOOGLE = auto_cast GetDeviceProcAddr(device, "vkGetRefreshCycleDurationGOOGLE") + GetRenderAreaGranularity = auto_cast GetDeviceProcAddr(device, "vkGetRenderAreaGranularity") + GetSemaphoreCounterValue = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreCounterValue") + GetSemaphoreCounterValueKHR = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreCounterValueKHR") + GetSemaphoreFdKHR = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreFdKHR") + GetSemaphoreWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkGetSemaphoreWin32HandleKHR") + GetShaderInfoAMD = auto_cast GetDeviceProcAddr(device, "vkGetShaderInfoAMD") + GetSwapchainCounterEXT = auto_cast GetDeviceProcAddr(device, "vkGetSwapchainCounterEXT") + GetSwapchainImagesKHR = auto_cast GetDeviceProcAddr(device, "vkGetSwapchainImagesKHR") + GetSwapchainStatusKHR = auto_cast GetDeviceProcAddr(device, "vkGetSwapchainStatusKHR") + GetValidationCacheDataEXT = auto_cast GetDeviceProcAddr(device, "vkGetValidationCacheDataEXT") + ImportFenceFdKHR = auto_cast GetDeviceProcAddr(device, "vkImportFenceFdKHR") + ImportFenceWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkImportFenceWin32HandleKHR") + ImportSemaphoreFdKHR = auto_cast GetDeviceProcAddr(device, "vkImportSemaphoreFdKHR") + ImportSemaphoreWin32HandleKHR = auto_cast GetDeviceProcAddr(device, "vkImportSemaphoreWin32HandleKHR") + InitializePerformanceApiINTEL = auto_cast GetDeviceProcAddr(device, "vkInitializePerformanceApiINTEL") + InvalidateMappedMemoryRanges = auto_cast GetDeviceProcAddr(device, "vkInvalidateMappedMemoryRanges") + MapMemory = auto_cast GetDeviceProcAddr(device, "vkMapMemory") + MergePipelineCaches = auto_cast GetDeviceProcAddr(device, "vkMergePipelineCaches") + MergeValidationCachesEXT = auto_cast GetDeviceProcAddr(device, "vkMergeValidationCachesEXT") + QueueBeginDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkQueueBeginDebugUtilsLabelEXT") + QueueBindSparse = auto_cast GetDeviceProcAddr(device, "vkQueueBindSparse") + QueueEndDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkQueueEndDebugUtilsLabelEXT") + QueueInsertDebugUtilsLabelEXT = auto_cast GetDeviceProcAddr(device, "vkQueueInsertDebugUtilsLabelEXT") + QueuePresentKHR = auto_cast GetDeviceProcAddr(device, "vkQueuePresentKHR") + QueueSetPerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkQueueSetPerformanceConfigurationINTEL") + QueueSubmit = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit") + QueueSubmit2KHR = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit2KHR") + QueueWaitIdle = auto_cast GetDeviceProcAddr(device, "vkQueueWaitIdle") + RegisterDeviceEventEXT = auto_cast GetDeviceProcAddr(device, "vkRegisterDeviceEventEXT") + RegisterDisplayEventEXT = auto_cast GetDeviceProcAddr(device, "vkRegisterDisplayEventEXT") + ReleaseFullScreenExclusiveModeEXT = auto_cast GetDeviceProcAddr(device, "vkReleaseFullScreenExclusiveModeEXT") + ReleasePerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkReleasePerformanceConfigurationINTEL") + ReleaseProfilingLockKHR = auto_cast GetDeviceProcAddr(device, "vkReleaseProfilingLockKHR") + ResetCommandBuffer = auto_cast GetDeviceProcAddr(device, "vkResetCommandBuffer") + ResetCommandPool = auto_cast GetDeviceProcAddr(device, "vkResetCommandPool") + ResetDescriptorPool = auto_cast GetDeviceProcAddr(device, "vkResetDescriptorPool") + ResetEvent = auto_cast GetDeviceProcAddr(device, "vkResetEvent") + ResetFences = auto_cast GetDeviceProcAddr(device, "vkResetFences") + ResetQueryPool = auto_cast GetDeviceProcAddr(device, "vkResetQueryPool") + ResetQueryPoolEXT = auto_cast GetDeviceProcAddr(device, "vkResetQueryPoolEXT") + SetDebugUtilsObjectNameEXT = auto_cast GetDeviceProcAddr(device, "vkSetDebugUtilsObjectNameEXT") + SetDebugUtilsObjectTagEXT = auto_cast GetDeviceProcAddr(device, "vkSetDebugUtilsObjectTagEXT") + SetDeviceMemoryPriorityEXT = auto_cast GetDeviceProcAddr(device, "vkSetDeviceMemoryPriorityEXT") + SetEvent = auto_cast GetDeviceProcAddr(device, "vkSetEvent") + SetHdrMetadataEXT = auto_cast GetDeviceProcAddr(device, "vkSetHdrMetadataEXT") + SetLocalDimmingAMD = auto_cast GetDeviceProcAddr(device, "vkSetLocalDimmingAMD") + SetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkSetPrivateDataEXT") + SignalSemaphore = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphore") + SignalSemaphoreKHR = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphoreKHR") + TrimCommandPool = auto_cast GetDeviceProcAddr(device, "vkTrimCommandPool") + TrimCommandPoolKHR = auto_cast GetDeviceProcAddr(device, "vkTrimCommandPoolKHR") + UninitializePerformanceApiINTEL = auto_cast GetDeviceProcAddr(device, "vkUninitializePerformanceApiINTEL") + UnmapMemory = auto_cast GetDeviceProcAddr(device, "vkUnmapMemory") + UpdateDescriptorSetWithTemplate = auto_cast GetDeviceProcAddr(device, "vkUpdateDescriptorSetWithTemplate") + UpdateDescriptorSetWithTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkUpdateDescriptorSetWithTemplateKHR") + UpdateDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkUpdateDescriptorSets") + WaitForFences = auto_cast GetDeviceProcAddr(device, "vkWaitForFences") + WaitForPresentKHR = auto_cast GetDeviceProcAddr(device, "vkWaitForPresentKHR") + WaitSemaphores = auto_cast GetDeviceProcAddr(device, "vkWaitSemaphores") + WaitSemaphoresKHR = auto_cast GetDeviceProcAddr(device, "vkWaitSemaphoresKHR") + WriteAccelerationStructuresPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkWriteAccelerationStructuresPropertiesKHR") +} + +load_proc_addresses_instance :: proc(instance: Instance) { + AcquireDrmDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkAcquireDrmDisplayEXT") + AcquireWinrtDisplayNV = auto_cast GetInstanceProcAddr(instance, "vkAcquireWinrtDisplayNV") + CreateDebugReportCallbackEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT") + CreateDebugUtilsMessengerEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT") + CreateDevice = auto_cast GetInstanceProcAddr(instance, "vkCreateDevice") + CreateDisplayModeKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateDisplayModeKHR") + CreateDisplayPlaneSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateDisplayPlaneSurfaceKHR") + CreateHeadlessSurfaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT") + CreateIOSSurfaceMVK = auto_cast GetInstanceProcAddr(instance, "vkCreateIOSSurfaceMVK") + CreateMacOSSurfaceMVK = auto_cast GetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK") + CreateMetalSurfaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT") + CreateWin32SurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR") + DebugReportMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkDebugReportMessageEXT") + DestroyDebugReportCallbackEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT") + DestroyDebugUtilsMessengerEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT") + DestroyInstance = auto_cast GetInstanceProcAddr(instance, "vkDestroyInstance") + DestroySurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkDestroySurfaceKHR") + EnumerateDeviceExtensionProperties = auto_cast GetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties") + EnumerateDeviceLayerProperties = auto_cast GetInstanceProcAddr(instance, "vkEnumerateDeviceLayerProperties") + EnumeratePhysicalDeviceGroups = auto_cast GetInstanceProcAddr(instance, "vkEnumeratePhysicalDeviceGroups") + EnumeratePhysicalDeviceGroupsKHR = auto_cast GetInstanceProcAddr(instance, "vkEnumeratePhysicalDeviceGroupsKHR") + EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR = auto_cast GetInstanceProcAddr(instance, "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR") + EnumeratePhysicalDevices = auto_cast GetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices") + GetDisplayModeProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayModeProperties2KHR") + GetDisplayModePropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR") + GetDisplayPlaneCapabilities2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilities2KHR") + GetDisplayPlaneCapabilitiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR") + GetDisplayPlaneSupportedDisplaysKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR") + GetDrmDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkGetDrmDisplayEXT") + GetInstanceProcAddr = auto_cast GetInstanceProcAddr(instance, "vkGetInstanceProcAddr") + GetPhysicalDeviceCalibrateableTimeDomainsEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT") + GetPhysicalDeviceCooperativeMatrixPropertiesNV = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV") + GetPhysicalDeviceDisplayPlaneProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR") + GetPhysicalDeviceDisplayPlanePropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR") + GetPhysicalDeviceDisplayProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayProperties2KHR") + GetPhysicalDeviceDisplayPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR") + GetPhysicalDeviceExternalBufferProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferProperties") + GetPhysicalDeviceExternalBufferPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR") + GetPhysicalDeviceExternalFenceProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFenceProperties") + GetPhysicalDeviceExternalFencePropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFencePropertiesKHR") + GetPhysicalDeviceExternalImageFormatPropertiesNV = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV") + GetPhysicalDeviceExternalSemaphoreProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphoreProperties") + GetPhysicalDeviceExternalSemaphorePropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR") + GetPhysicalDeviceFeatures = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures") + GetPhysicalDeviceFeatures2 = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2") + GetPhysicalDeviceFeatures2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR") + GetPhysicalDeviceFormatProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties") + GetPhysicalDeviceFormatProperties2 = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2") + GetPhysicalDeviceFormatProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2KHR") + GetPhysicalDeviceFragmentShadingRatesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFragmentShadingRatesKHR") + GetPhysicalDeviceImageFormatProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties") + GetPhysicalDeviceImageFormatProperties2 = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2") + GetPhysicalDeviceImageFormatProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2KHR") + GetPhysicalDeviceMemoryProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties") + GetPhysicalDeviceMemoryProperties2 = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2") + GetPhysicalDeviceMemoryProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2KHR") + GetPhysicalDeviceMultisamplePropertiesEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMultisamplePropertiesEXT") + GetPhysicalDevicePresentRectanglesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDevicePresentRectanglesKHR") + GetPhysicalDeviceProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties") + GetPhysicalDeviceProperties2 = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2") + GetPhysicalDeviceProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR") + GetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR") + GetPhysicalDeviceQueueFamilyProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties") + GetPhysicalDeviceQueueFamilyProperties2 = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2") + GetPhysicalDeviceQueueFamilyProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR") + GetPhysicalDeviceSparseImageFormatProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties") + GetPhysicalDeviceSparseImageFormatProperties2 = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2") + GetPhysicalDeviceSparseImageFormatProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR") + GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV") + GetPhysicalDeviceSurfaceCapabilities2EXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilities2EXT") + GetPhysicalDeviceSurfaceCapabilities2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilities2KHR") + GetPhysicalDeviceSurfaceCapabilitiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") + GetPhysicalDeviceSurfaceFormats2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormats2KHR") + GetPhysicalDeviceSurfaceFormatsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR") + GetPhysicalDeviceSurfacePresentModes2EXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModes2EXT") + GetPhysicalDeviceSurfacePresentModesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR") + GetPhysicalDeviceSurfaceSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR") + GetPhysicalDeviceToolPropertiesEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceToolPropertiesEXT") + GetPhysicalDeviceWin32PresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR") + GetWinrtDisplayNV = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV") + ReleaseDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkReleaseDisplayEXT") + SubmitDebugUtilsMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT") + + // Device Procedures (may call into dispatch) + AcquireFullScreenExclusiveModeEXT = auto_cast GetInstanceProcAddr(instance, "vkAcquireFullScreenExclusiveModeEXT") + AcquireNextImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkAcquireNextImage2KHR") + AcquireNextImageKHR = auto_cast GetInstanceProcAddr(instance, "vkAcquireNextImageKHR") + AcquirePerformanceConfigurationINTEL = auto_cast GetInstanceProcAddr(instance, "vkAcquirePerformanceConfigurationINTEL") + AcquireProfilingLockKHR = auto_cast GetInstanceProcAddr(instance, "vkAcquireProfilingLockKHR") + AllocateCommandBuffers = auto_cast GetInstanceProcAddr(instance, "vkAllocateCommandBuffers") + AllocateDescriptorSets = auto_cast GetInstanceProcAddr(instance, "vkAllocateDescriptorSets") + AllocateMemory = auto_cast GetInstanceProcAddr(instance, "vkAllocateMemory") + BeginCommandBuffer = auto_cast GetInstanceProcAddr(instance, "vkBeginCommandBuffer") + BindAccelerationStructureMemoryNV = auto_cast GetInstanceProcAddr(instance, "vkBindAccelerationStructureMemoryNV") + BindBufferMemory = auto_cast GetInstanceProcAddr(instance, "vkBindBufferMemory") + BindBufferMemory2 = auto_cast GetInstanceProcAddr(instance, "vkBindBufferMemory2") + BindBufferMemory2KHR = auto_cast GetInstanceProcAddr(instance, "vkBindBufferMemory2KHR") + BindImageMemory = auto_cast GetInstanceProcAddr(instance, "vkBindImageMemory") + BindImageMemory2 = auto_cast GetInstanceProcAddr(instance, "vkBindImageMemory2") + BindImageMemory2KHR = auto_cast GetInstanceProcAddr(instance, "vkBindImageMemory2KHR") + BuildAccelerationStructuresKHR = auto_cast GetInstanceProcAddr(instance, "vkBuildAccelerationStructuresKHR") + CmdBeginConditionalRenderingEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginConditionalRenderingEXT") + CmdBeginDebugUtilsLabelEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT") + CmdBeginQuery = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginQuery") + CmdBeginQueryIndexedEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginQueryIndexedEXT") + CmdBeginRenderPass = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRenderPass") + CmdBeginRenderPass2 = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRenderPass2") + CmdBeginRenderPass2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRenderPass2KHR") + CmdBeginTransformFeedbackEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginTransformFeedbackEXT") + CmdBindDescriptorSets = auto_cast GetInstanceProcAddr(instance, "vkCmdBindDescriptorSets") + CmdBindIndexBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdBindIndexBuffer") + CmdBindInvocationMaskHUAWEI = auto_cast GetInstanceProcAddr(instance, "vkCmdBindInvocationMaskHUAWEI") + CmdBindPipeline = auto_cast GetInstanceProcAddr(instance, "vkCmdBindPipeline") + CmdBindPipelineShaderGroupNV = auto_cast GetInstanceProcAddr(instance, "vkCmdBindPipelineShaderGroupNV") + CmdBindShadingRateImageNV = auto_cast GetInstanceProcAddr(instance, "vkCmdBindShadingRateImageNV") + CmdBindTransformFeedbackBuffersEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBindTransformFeedbackBuffersEXT") + CmdBindVertexBuffers = auto_cast GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers") + CmdBindVertexBuffers2EXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers2EXT") + CmdBlitImage = auto_cast GetInstanceProcAddr(instance, "vkCmdBlitImage") + CmdBlitImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBlitImage2KHR") + CmdBuildAccelerationStructureNV = auto_cast GetInstanceProcAddr(instance, "vkCmdBuildAccelerationStructureNV") + CmdBuildAccelerationStructuresIndirectKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBuildAccelerationStructuresIndirectKHR") + CmdBuildAccelerationStructuresKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBuildAccelerationStructuresKHR") + CmdClearAttachments = auto_cast GetInstanceProcAddr(instance, "vkCmdClearAttachments") + CmdClearColorImage = auto_cast GetInstanceProcAddr(instance, "vkCmdClearColorImage") + CmdClearDepthStencilImage = auto_cast GetInstanceProcAddr(instance, "vkCmdClearDepthStencilImage") + CmdCopyAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyAccelerationStructureKHR") + CmdCopyAccelerationStructureNV = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyAccelerationStructureNV") + CmdCopyAccelerationStructureToMemoryKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyAccelerationStructureToMemoryKHR") + CmdCopyBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBuffer") + CmdCopyBuffer2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBuffer2KHR") + CmdCopyBufferToImage = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage") + CmdCopyBufferToImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage2KHR") + CmdCopyImage = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImage") + CmdCopyImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImage2KHR") + CmdCopyImageToBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer") + CmdCopyImageToBuffer2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer2KHR") + CmdCopyMemoryToAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyMemoryToAccelerationStructureKHR") + CmdCopyQueryPoolResults = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyQueryPoolResults") + CmdCuLaunchKernelNVX = auto_cast GetInstanceProcAddr(instance, "vkCmdCuLaunchKernelNVX") + CmdDebugMarkerBeginEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdDebugMarkerBeginEXT") + CmdDebugMarkerEndEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdDebugMarkerEndEXT") + CmdDebugMarkerInsertEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdDebugMarkerInsertEXT") + CmdDispatch = auto_cast GetInstanceProcAddr(instance, "vkCmdDispatch") + CmdDispatchBase = auto_cast GetInstanceProcAddr(instance, "vkCmdDispatchBase") + CmdDispatchBaseKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdDispatchBaseKHR") + CmdDispatchIndirect = auto_cast GetInstanceProcAddr(instance, "vkCmdDispatchIndirect") + CmdDraw = auto_cast GetInstanceProcAddr(instance, "vkCmdDraw") + CmdDrawIndexed = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndexed") + CmdDrawIndexedIndirect = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirect") + CmdDrawIndexedIndirectCount = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirectCount") + CmdDrawIndexedIndirectCountAMD = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirectCountAMD") + CmdDrawIndexedIndirectCountKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirectCountKHR") + CmdDrawIndirect = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndirect") + CmdDrawIndirectByteCountEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndirectByteCountEXT") + CmdDrawIndirectCount = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndirectCount") + CmdDrawIndirectCountAMD = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndirectCountAMD") + CmdDrawIndirectCountKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawIndirectCountKHR") + CmdDrawMeshTasksIndirectCountNV = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawMeshTasksIndirectCountNV") + CmdDrawMeshTasksIndirectNV = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawMeshTasksIndirectNV") + CmdDrawMeshTasksNV = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawMeshTasksNV") + CmdDrawMultiEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawMultiEXT") + CmdDrawMultiIndexedEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdDrawMultiIndexedEXT") + CmdEndConditionalRenderingEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdEndConditionalRenderingEXT") + CmdEndDebugUtilsLabelEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT") + CmdEndQuery = auto_cast GetInstanceProcAddr(instance, "vkCmdEndQuery") + CmdEndQueryIndexedEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdEndQueryIndexedEXT") + CmdEndRenderPass = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRenderPass") + CmdEndRenderPass2 = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRenderPass2") + CmdEndRenderPass2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRenderPass2KHR") + CmdEndTransformFeedbackEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdEndTransformFeedbackEXT") + CmdExecuteCommands = auto_cast GetInstanceProcAddr(instance, "vkCmdExecuteCommands") + CmdExecuteGeneratedCommandsNV = auto_cast GetInstanceProcAddr(instance, "vkCmdExecuteGeneratedCommandsNV") + CmdFillBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdFillBuffer") + CmdInsertDebugUtilsLabelEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdInsertDebugUtilsLabelEXT") + CmdNextSubpass = auto_cast GetInstanceProcAddr(instance, "vkCmdNextSubpass") + CmdNextSubpass2 = auto_cast GetInstanceProcAddr(instance, "vkCmdNextSubpass2") + CmdNextSubpass2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdNextSubpass2KHR") + CmdPipelineBarrier = auto_cast GetInstanceProcAddr(instance, "vkCmdPipelineBarrier") + CmdPipelineBarrier2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdPipelineBarrier2KHR") + CmdPreprocessGeneratedCommandsNV = auto_cast GetInstanceProcAddr(instance, "vkCmdPreprocessGeneratedCommandsNV") + CmdPushConstants = auto_cast GetInstanceProcAddr(instance, "vkCmdPushConstants") + CmdPushDescriptorSetKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdPushDescriptorSetKHR") + CmdPushDescriptorSetWithTemplateKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdPushDescriptorSetWithTemplateKHR") + CmdResetEvent = auto_cast GetInstanceProcAddr(instance, "vkCmdResetEvent") + CmdResetEvent2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdResetEvent2KHR") + CmdResetQueryPool = auto_cast GetInstanceProcAddr(instance, "vkCmdResetQueryPool") + CmdResolveImage = auto_cast GetInstanceProcAddr(instance, "vkCmdResolveImage") + CmdResolveImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdResolveImage2KHR") + CmdSetBlendConstants = auto_cast GetInstanceProcAddr(instance, "vkCmdSetBlendConstants") + CmdSetCheckpointNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetCheckpointNV") + CmdSetCoarseSampleOrderNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetCoarseSampleOrderNV") + CmdSetCullModeEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetCullModeEXT") + CmdSetDepthBias = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBias") + CmdSetDepthBiasEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBiasEnableEXT") + CmdSetDepthBounds = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBounds") + CmdSetDepthBoundsTestEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBoundsTestEnableEXT") + CmdSetDepthCompareOpEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthCompareOpEXT") + CmdSetDepthTestEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthTestEnableEXT") + CmdSetDepthWriteEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthWriteEnableEXT") + CmdSetDeviceMask = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDeviceMask") + CmdSetDeviceMaskKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDeviceMaskKHR") + CmdSetDiscardRectangleEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDiscardRectangleEXT") + CmdSetEvent = auto_cast GetInstanceProcAddr(instance, "vkCmdSetEvent") + CmdSetEvent2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetEvent2KHR") + CmdSetExclusiveScissorNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetExclusiveScissorNV") + CmdSetFragmentShadingRateEnumNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetFragmentShadingRateEnumNV") + CmdSetFragmentShadingRateKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetFragmentShadingRateKHR") + CmdSetFrontFaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetFrontFaceEXT") + CmdSetLineStippleEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetLineStippleEXT") + CmdSetLineWidth = auto_cast GetInstanceProcAddr(instance, "vkCmdSetLineWidth") + CmdSetLogicOpEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetLogicOpEXT") + CmdSetPatchControlPointsEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPatchControlPointsEXT") + CmdSetPerformanceMarkerINTEL = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPerformanceMarkerINTEL") + CmdSetPerformanceOverrideINTEL = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPerformanceOverrideINTEL") + CmdSetPerformanceStreamMarkerINTEL = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPerformanceStreamMarkerINTEL") + CmdSetPrimitiveRestartEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPrimitiveRestartEnableEXT") + CmdSetPrimitiveTopologyEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPrimitiveTopologyEXT") + CmdSetRasterizerDiscardEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetRasterizerDiscardEnableEXT") + CmdSetRayTracingPipelineStackSizeKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetRayTracingPipelineStackSizeKHR") + CmdSetSampleLocationsEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetSampleLocationsEXT") + CmdSetScissor = auto_cast GetInstanceProcAddr(instance, "vkCmdSetScissor") + CmdSetScissorWithCountEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetScissorWithCountEXT") + CmdSetStencilCompareMask = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilCompareMask") + CmdSetStencilOpEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilOpEXT") + CmdSetStencilReference = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilReference") + CmdSetStencilTestEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilTestEnableEXT") + CmdSetStencilWriteMask = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilWriteMask") + CmdSetVertexInputEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetVertexInputEXT") + CmdSetViewport = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewport") + CmdSetViewportShadingRatePaletteNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewportShadingRatePaletteNV") + CmdSetViewportWScalingNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewportWScalingNV") + CmdSetViewportWithCountEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewportWithCountEXT") + CmdSubpassShadingHUAWEI = auto_cast GetInstanceProcAddr(instance, "vkCmdSubpassShadingHUAWEI") + CmdTraceRaysIndirectKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdTraceRaysIndirectKHR") + CmdTraceRaysKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdTraceRaysKHR") + CmdTraceRaysNV = auto_cast GetInstanceProcAddr(instance, "vkCmdTraceRaysNV") + CmdUpdateBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdUpdateBuffer") + CmdWaitEvents = auto_cast GetInstanceProcAddr(instance, "vkCmdWaitEvents") + CmdWaitEvents2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdWaitEvents2KHR") + CmdWriteAccelerationStructuresPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteAccelerationStructuresPropertiesKHR") + CmdWriteAccelerationStructuresPropertiesNV = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteAccelerationStructuresPropertiesNV") + CmdWriteBufferMarker2AMD = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteBufferMarker2AMD") + CmdWriteBufferMarkerAMD = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteBufferMarkerAMD") + CmdWriteTimestamp = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteTimestamp") + CmdWriteTimestamp2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteTimestamp2KHR") + CompileDeferredNV = auto_cast GetInstanceProcAddr(instance, "vkCompileDeferredNV") + CopyAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkCopyAccelerationStructureKHR") + CopyAccelerationStructureToMemoryKHR = auto_cast GetInstanceProcAddr(instance, "vkCopyAccelerationStructureToMemoryKHR") + CopyMemoryToAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkCopyMemoryToAccelerationStructureKHR") + CreateAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateAccelerationStructureKHR") + CreateAccelerationStructureNV = auto_cast GetInstanceProcAddr(instance, "vkCreateAccelerationStructureNV") + CreateBuffer = auto_cast GetInstanceProcAddr(instance, "vkCreateBuffer") + CreateBufferView = auto_cast GetInstanceProcAddr(instance, "vkCreateBufferView") + CreateCommandPool = auto_cast GetInstanceProcAddr(instance, "vkCreateCommandPool") + CreateComputePipelines = auto_cast GetInstanceProcAddr(instance, "vkCreateComputePipelines") + CreateCuFunctionNVX = auto_cast GetInstanceProcAddr(instance, "vkCreateCuFunctionNVX") + CreateCuModuleNVX = auto_cast GetInstanceProcAddr(instance, "vkCreateCuModuleNVX") + CreateDeferredOperationKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateDeferredOperationKHR") + CreateDescriptorPool = auto_cast GetInstanceProcAddr(instance, "vkCreateDescriptorPool") + CreateDescriptorSetLayout = auto_cast GetInstanceProcAddr(instance, "vkCreateDescriptorSetLayout") + CreateDescriptorUpdateTemplate = auto_cast GetInstanceProcAddr(instance, "vkCreateDescriptorUpdateTemplate") + CreateDescriptorUpdateTemplateKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateDescriptorUpdateTemplateKHR") + CreateEvent = auto_cast GetInstanceProcAddr(instance, "vkCreateEvent") + CreateFence = auto_cast GetInstanceProcAddr(instance, "vkCreateFence") + CreateFramebuffer = auto_cast GetInstanceProcAddr(instance, "vkCreateFramebuffer") + CreateGraphicsPipelines = auto_cast GetInstanceProcAddr(instance, "vkCreateGraphicsPipelines") + CreateImage = auto_cast GetInstanceProcAddr(instance, "vkCreateImage") + CreateImageView = auto_cast GetInstanceProcAddr(instance, "vkCreateImageView") + CreateIndirectCommandsLayoutNV = auto_cast GetInstanceProcAddr(instance, "vkCreateIndirectCommandsLayoutNV") + CreatePipelineCache = auto_cast GetInstanceProcAddr(instance, "vkCreatePipelineCache") + CreatePipelineLayout = auto_cast GetInstanceProcAddr(instance, "vkCreatePipelineLayout") + CreatePrivateDataSlotEXT = auto_cast GetInstanceProcAddr(instance, "vkCreatePrivateDataSlotEXT") + CreateQueryPool = auto_cast GetInstanceProcAddr(instance, "vkCreateQueryPool") + CreateRayTracingPipelinesKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateRayTracingPipelinesKHR") + CreateRayTracingPipelinesNV = auto_cast GetInstanceProcAddr(instance, "vkCreateRayTracingPipelinesNV") + CreateRenderPass = auto_cast GetInstanceProcAddr(instance, "vkCreateRenderPass") + CreateRenderPass2 = auto_cast GetInstanceProcAddr(instance, "vkCreateRenderPass2") + CreateRenderPass2KHR = auto_cast GetInstanceProcAddr(instance, "vkCreateRenderPass2KHR") + CreateSampler = auto_cast GetInstanceProcAddr(instance, "vkCreateSampler") + CreateSamplerYcbcrConversion = auto_cast GetInstanceProcAddr(instance, "vkCreateSamplerYcbcrConversion") + CreateSamplerYcbcrConversionKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateSamplerYcbcrConversionKHR") + CreateSemaphore = auto_cast GetInstanceProcAddr(instance, "vkCreateSemaphore") + CreateShaderModule = auto_cast GetInstanceProcAddr(instance, "vkCreateShaderModule") + CreateSharedSwapchainsKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateSharedSwapchainsKHR") + CreateSwapchainKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateSwapchainKHR") + CreateValidationCacheEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateValidationCacheEXT") + DebugMarkerSetObjectNameEXT = auto_cast GetInstanceProcAddr(instance, "vkDebugMarkerSetObjectNameEXT") + DebugMarkerSetObjectTagEXT = auto_cast GetInstanceProcAddr(instance, "vkDebugMarkerSetObjectTagEXT") + DeferredOperationJoinKHR = auto_cast GetInstanceProcAddr(instance, "vkDeferredOperationJoinKHR") + DestroyAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkDestroyAccelerationStructureKHR") + DestroyAccelerationStructureNV = auto_cast GetInstanceProcAddr(instance, "vkDestroyAccelerationStructureNV") + DestroyBuffer = auto_cast GetInstanceProcAddr(instance, "vkDestroyBuffer") + DestroyBufferView = auto_cast GetInstanceProcAddr(instance, "vkDestroyBufferView") + DestroyCommandPool = auto_cast GetInstanceProcAddr(instance, "vkDestroyCommandPool") + DestroyCuFunctionNVX = auto_cast GetInstanceProcAddr(instance, "vkDestroyCuFunctionNVX") + DestroyCuModuleNVX = auto_cast GetInstanceProcAddr(instance, "vkDestroyCuModuleNVX") + DestroyDeferredOperationKHR = auto_cast GetInstanceProcAddr(instance, "vkDestroyDeferredOperationKHR") + DestroyDescriptorPool = auto_cast GetInstanceProcAddr(instance, "vkDestroyDescriptorPool") + DestroyDescriptorSetLayout = auto_cast GetInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout") + DestroyDescriptorUpdateTemplate = auto_cast GetInstanceProcAddr(instance, "vkDestroyDescriptorUpdateTemplate") + DestroyDescriptorUpdateTemplateKHR = auto_cast GetInstanceProcAddr(instance, "vkDestroyDescriptorUpdateTemplateKHR") + DestroyDevice = auto_cast GetInstanceProcAddr(instance, "vkDestroyDevice") + DestroyEvent = auto_cast GetInstanceProcAddr(instance, "vkDestroyEvent") + DestroyFence = auto_cast GetInstanceProcAddr(instance, "vkDestroyFence") + DestroyFramebuffer = auto_cast GetInstanceProcAddr(instance, "vkDestroyFramebuffer") + DestroyImage = auto_cast GetInstanceProcAddr(instance, "vkDestroyImage") + DestroyImageView = auto_cast GetInstanceProcAddr(instance, "vkDestroyImageView") + DestroyIndirectCommandsLayoutNV = auto_cast GetInstanceProcAddr(instance, "vkDestroyIndirectCommandsLayoutNV") + DestroyPipeline = auto_cast GetInstanceProcAddr(instance, "vkDestroyPipeline") + DestroyPipelineCache = auto_cast GetInstanceProcAddr(instance, "vkDestroyPipelineCache") + DestroyPipelineLayout = auto_cast GetInstanceProcAddr(instance, "vkDestroyPipelineLayout") + DestroyPrivateDataSlotEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyPrivateDataSlotEXT") + DestroyQueryPool = auto_cast GetInstanceProcAddr(instance, "vkDestroyQueryPool") + DestroyRenderPass = auto_cast GetInstanceProcAddr(instance, "vkDestroyRenderPass") + DestroySampler = auto_cast GetInstanceProcAddr(instance, "vkDestroySampler") + DestroySamplerYcbcrConversion = auto_cast GetInstanceProcAddr(instance, "vkDestroySamplerYcbcrConversion") + DestroySamplerYcbcrConversionKHR = auto_cast GetInstanceProcAddr(instance, "vkDestroySamplerYcbcrConversionKHR") + DestroySemaphore = auto_cast GetInstanceProcAddr(instance, "vkDestroySemaphore") + DestroyShaderModule = auto_cast GetInstanceProcAddr(instance, "vkDestroyShaderModule") + DestroySwapchainKHR = auto_cast GetInstanceProcAddr(instance, "vkDestroySwapchainKHR") + DestroyValidationCacheEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyValidationCacheEXT") + DeviceWaitIdle = auto_cast GetInstanceProcAddr(instance, "vkDeviceWaitIdle") + DisplayPowerControlEXT = auto_cast GetInstanceProcAddr(instance, "vkDisplayPowerControlEXT") + EndCommandBuffer = auto_cast GetInstanceProcAddr(instance, "vkEndCommandBuffer") + FlushMappedMemoryRanges = auto_cast GetInstanceProcAddr(instance, "vkFlushMappedMemoryRanges") + FreeCommandBuffers = auto_cast GetInstanceProcAddr(instance, "vkFreeCommandBuffers") + FreeDescriptorSets = auto_cast GetInstanceProcAddr(instance, "vkFreeDescriptorSets") + FreeMemory = auto_cast GetInstanceProcAddr(instance, "vkFreeMemory") + GetAccelerationStructureBuildSizesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetAccelerationStructureBuildSizesKHR") + GetAccelerationStructureDeviceAddressKHR = auto_cast GetInstanceProcAddr(instance, "vkGetAccelerationStructureDeviceAddressKHR") + GetAccelerationStructureHandleNV = auto_cast GetInstanceProcAddr(instance, "vkGetAccelerationStructureHandleNV") + GetAccelerationStructureMemoryRequirementsNV = auto_cast GetInstanceProcAddr(instance, "vkGetAccelerationStructureMemoryRequirementsNV") + GetBufferDeviceAddress = auto_cast GetInstanceProcAddr(instance, "vkGetBufferDeviceAddress") + GetBufferDeviceAddressEXT = auto_cast GetInstanceProcAddr(instance, "vkGetBufferDeviceAddressEXT") + GetBufferDeviceAddressKHR = auto_cast GetInstanceProcAddr(instance, "vkGetBufferDeviceAddressKHR") + GetBufferMemoryRequirements = auto_cast GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements") + GetBufferMemoryRequirements2 = auto_cast GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements2") + GetBufferMemoryRequirements2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements2KHR") + GetBufferOpaqueCaptureAddress = auto_cast GetInstanceProcAddr(instance, "vkGetBufferOpaqueCaptureAddress") + GetBufferOpaqueCaptureAddressKHR = auto_cast GetInstanceProcAddr(instance, "vkGetBufferOpaqueCaptureAddressKHR") + GetCalibratedTimestampsEXT = auto_cast GetInstanceProcAddr(instance, "vkGetCalibratedTimestampsEXT") + GetDeferredOperationMaxConcurrencyKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeferredOperationMaxConcurrencyKHR") + GetDeferredOperationResultKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeferredOperationResultKHR") + GetDescriptorSetLayoutSupport = auto_cast GetInstanceProcAddr(instance, "vkGetDescriptorSetLayoutSupport") + GetDescriptorSetLayoutSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDescriptorSetLayoutSupportKHR") + GetDeviceAccelerationStructureCompatibilityKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceAccelerationStructureCompatibilityKHR") + GetDeviceGroupPeerMemoryFeatures = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupPeerMemoryFeatures") + GetDeviceGroupPeerMemoryFeaturesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupPeerMemoryFeaturesKHR") + GetDeviceGroupPresentCapabilitiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupPresentCapabilitiesKHR") + GetDeviceGroupSurfacePresentModes2EXT = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupSurfacePresentModes2EXT") + GetDeviceGroupSurfacePresentModesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupSurfacePresentModesKHR") + GetDeviceMemoryCommitment = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceMemoryCommitment") + GetDeviceMemoryOpaqueCaptureAddress = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceMemoryOpaqueCaptureAddress") + GetDeviceMemoryOpaqueCaptureAddressKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") + GetDeviceProcAddr = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceProcAddr") + GetDeviceQueue = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceQueue") + GetDeviceQueue2 = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceQueue2") + GetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI") + GetEventStatus = auto_cast GetInstanceProcAddr(instance, "vkGetEventStatus") + GetFenceFdKHR = auto_cast GetInstanceProcAddr(instance, "vkGetFenceFdKHR") + GetFenceStatus = auto_cast GetInstanceProcAddr(instance, "vkGetFenceStatus") + GetFenceWin32HandleKHR = auto_cast GetInstanceProcAddr(instance, "vkGetFenceWin32HandleKHR") + GetGeneratedCommandsMemoryRequirementsNV = auto_cast GetInstanceProcAddr(instance, "vkGetGeneratedCommandsMemoryRequirementsNV") + GetImageDrmFormatModifierPropertiesEXT = auto_cast GetInstanceProcAddr(instance, "vkGetImageDrmFormatModifierPropertiesEXT") + GetImageMemoryRequirements = auto_cast GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements") + GetImageMemoryRequirements2 = auto_cast GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements2") + GetImageMemoryRequirements2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements2KHR") + GetImageSparseMemoryRequirements = auto_cast GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements") + GetImageSparseMemoryRequirements2 = auto_cast GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements2") + GetImageSparseMemoryRequirements2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements2KHR") + GetImageSubresourceLayout = auto_cast GetInstanceProcAddr(instance, "vkGetImageSubresourceLayout") + GetImageViewAddressNVX = auto_cast GetInstanceProcAddr(instance, "vkGetImageViewAddressNVX") + GetImageViewHandleNVX = auto_cast GetInstanceProcAddr(instance, "vkGetImageViewHandleNVX") + GetMemoryFdKHR = auto_cast GetInstanceProcAddr(instance, "vkGetMemoryFdKHR") + GetMemoryFdPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetMemoryFdPropertiesKHR") + GetMemoryHostPointerPropertiesEXT = auto_cast GetInstanceProcAddr(instance, "vkGetMemoryHostPointerPropertiesEXT") + GetMemoryRemoteAddressNV = auto_cast GetInstanceProcAddr(instance, "vkGetMemoryRemoteAddressNV") + GetMemoryWin32HandleKHR = auto_cast GetInstanceProcAddr(instance, "vkGetMemoryWin32HandleKHR") + GetMemoryWin32HandleNV = auto_cast GetInstanceProcAddr(instance, "vkGetMemoryWin32HandleNV") + GetMemoryWin32HandlePropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetMemoryWin32HandlePropertiesKHR") + GetPastPresentationTimingGOOGLE = auto_cast GetInstanceProcAddr(instance, "vkGetPastPresentationTimingGOOGLE") + GetPerformanceParameterINTEL = auto_cast GetInstanceProcAddr(instance, "vkGetPerformanceParameterINTEL") + GetPipelineCacheData = auto_cast GetInstanceProcAddr(instance, "vkGetPipelineCacheData") + GetPipelineExecutableInternalRepresentationsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPipelineExecutableInternalRepresentationsKHR") + GetPipelineExecutablePropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPipelineExecutablePropertiesKHR") + GetPipelineExecutableStatisticsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPipelineExecutableStatisticsKHR") + GetPrivateDataEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPrivateDataEXT") + GetQueryPoolResults = auto_cast GetInstanceProcAddr(instance, "vkGetQueryPoolResults") + GetQueueCheckpointData2NV = auto_cast GetInstanceProcAddr(instance, "vkGetQueueCheckpointData2NV") + GetQueueCheckpointDataNV = auto_cast GetInstanceProcAddr(instance, "vkGetQueueCheckpointDataNV") + GetRayTracingCaptureReplayShaderGroupHandlesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR") + GetRayTracingShaderGroupHandlesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetRayTracingShaderGroupHandlesKHR") + GetRayTracingShaderGroupHandlesNV = auto_cast GetInstanceProcAddr(instance, "vkGetRayTracingShaderGroupHandlesNV") + GetRayTracingShaderGroupStackSizeKHR = auto_cast GetInstanceProcAddr(instance, "vkGetRayTracingShaderGroupStackSizeKHR") + GetRefreshCycleDurationGOOGLE = auto_cast GetInstanceProcAddr(instance, "vkGetRefreshCycleDurationGOOGLE") + GetRenderAreaGranularity = auto_cast GetInstanceProcAddr(instance, "vkGetRenderAreaGranularity") + GetSemaphoreCounterValue = auto_cast GetInstanceProcAddr(instance, "vkGetSemaphoreCounterValue") + GetSemaphoreCounterValueKHR = auto_cast GetInstanceProcAddr(instance, "vkGetSemaphoreCounterValueKHR") + GetSemaphoreFdKHR = auto_cast GetInstanceProcAddr(instance, "vkGetSemaphoreFdKHR") + GetSemaphoreWin32HandleKHR = auto_cast GetInstanceProcAddr(instance, "vkGetSemaphoreWin32HandleKHR") + GetShaderInfoAMD = auto_cast GetInstanceProcAddr(instance, "vkGetShaderInfoAMD") + GetSwapchainCounterEXT = auto_cast GetInstanceProcAddr(instance, "vkGetSwapchainCounterEXT") + GetSwapchainImagesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetSwapchainImagesKHR") + GetSwapchainStatusKHR = auto_cast GetInstanceProcAddr(instance, "vkGetSwapchainStatusKHR") + GetValidationCacheDataEXT = auto_cast GetInstanceProcAddr(instance, "vkGetValidationCacheDataEXT") + ImportFenceFdKHR = auto_cast GetInstanceProcAddr(instance, "vkImportFenceFdKHR") + ImportFenceWin32HandleKHR = auto_cast GetInstanceProcAddr(instance, "vkImportFenceWin32HandleKHR") + ImportSemaphoreFdKHR = auto_cast GetInstanceProcAddr(instance, "vkImportSemaphoreFdKHR") + ImportSemaphoreWin32HandleKHR = auto_cast GetInstanceProcAddr(instance, "vkImportSemaphoreWin32HandleKHR") + InitializePerformanceApiINTEL = auto_cast GetInstanceProcAddr(instance, "vkInitializePerformanceApiINTEL") + InvalidateMappedMemoryRanges = auto_cast GetInstanceProcAddr(instance, "vkInvalidateMappedMemoryRanges") + MapMemory = auto_cast GetInstanceProcAddr(instance, "vkMapMemory") + MergePipelineCaches = auto_cast GetInstanceProcAddr(instance, "vkMergePipelineCaches") + MergeValidationCachesEXT = auto_cast GetInstanceProcAddr(instance, "vkMergeValidationCachesEXT") + QueueBeginDebugUtilsLabelEXT = auto_cast GetInstanceProcAddr(instance, "vkQueueBeginDebugUtilsLabelEXT") + QueueBindSparse = auto_cast GetInstanceProcAddr(instance, "vkQueueBindSparse") + QueueEndDebugUtilsLabelEXT = auto_cast GetInstanceProcAddr(instance, "vkQueueEndDebugUtilsLabelEXT") + QueueInsertDebugUtilsLabelEXT = auto_cast GetInstanceProcAddr(instance, "vkQueueInsertDebugUtilsLabelEXT") + QueuePresentKHR = auto_cast GetInstanceProcAddr(instance, "vkQueuePresentKHR") + QueueSetPerformanceConfigurationINTEL = auto_cast GetInstanceProcAddr(instance, "vkQueueSetPerformanceConfigurationINTEL") + QueueSubmit = auto_cast GetInstanceProcAddr(instance, "vkQueueSubmit") + QueueSubmit2KHR = auto_cast GetInstanceProcAddr(instance, "vkQueueSubmit2KHR") + QueueWaitIdle = auto_cast GetInstanceProcAddr(instance, "vkQueueWaitIdle") + RegisterDeviceEventEXT = auto_cast GetInstanceProcAddr(instance, "vkRegisterDeviceEventEXT") + RegisterDisplayEventEXT = auto_cast GetInstanceProcAddr(instance, "vkRegisterDisplayEventEXT") + ReleaseFullScreenExclusiveModeEXT = auto_cast GetInstanceProcAddr(instance, "vkReleaseFullScreenExclusiveModeEXT") + ReleasePerformanceConfigurationINTEL = auto_cast GetInstanceProcAddr(instance, "vkReleasePerformanceConfigurationINTEL") + ReleaseProfilingLockKHR = auto_cast GetInstanceProcAddr(instance, "vkReleaseProfilingLockKHR") + ResetCommandBuffer = auto_cast GetInstanceProcAddr(instance, "vkResetCommandBuffer") + ResetCommandPool = auto_cast GetInstanceProcAddr(instance, "vkResetCommandPool") + ResetDescriptorPool = auto_cast GetInstanceProcAddr(instance, "vkResetDescriptorPool") + ResetEvent = auto_cast GetInstanceProcAddr(instance, "vkResetEvent") + ResetFences = auto_cast GetInstanceProcAddr(instance, "vkResetFences") + ResetQueryPool = auto_cast GetInstanceProcAddr(instance, "vkResetQueryPool") + ResetQueryPoolEXT = auto_cast GetInstanceProcAddr(instance, "vkResetQueryPoolEXT") + SetDebugUtilsObjectNameEXT = auto_cast GetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT") + SetDebugUtilsObjectTagEXT = auto_cast GetInstanceProcAddr(instance, "vkSetDebugUtilsObjectTagEXT") + SetDeviceMemoryPriorityEXT = auto_cast GetInstanceProcAddr(instance, "vkSetDeviceMemoryPriorityEXT") + SetEvent = auto_cast GetInstanceProcAddr(instance, "vkSetEvent") + SetHdrMetadataEXT = auto_cast GetInstanceProcAddr(instance, "vkSetHdrMetadataEXT") + SetLocalDimmingAMD = auto_cast GetInstanceProcAddr(instance, "vkSetLocalDimmingAMD") + SetPrivateDataEXT = auto_cast GetInstanceProcAddr(instance, "vkSetPrivateDataEXT") + SignalSemaphore = auto_cast GetInstanceProcAddr(instance, "vkSignalSemaphore") + SignalSemaphoreKHR = auto_cast GetInstanceProcAddr(instance, "vkSignalSemaphoreKHR") + TrimCommandPool = auto_cast GetInstanceProcAddr(instance, "vkTrimCommandPool") + TrimCommandPoolKHR = auto_cast GetInstanceProcAddr(instance, "vkTrimCommandPoolKHR") + UninitializePerformanceApiINTEL = auto_cast GetInstanceProcAddr(instance, "vkUninitializePerformanceApiINTEL") + UnmapMemory = auto_cast GetInstanceProcAddr(instance, "vkUnmapMemory") + UpdateDescriptorSetWithTemplate = auto_cast GetInstanceProcAddr(instance, "vkUpdateDescriptorSetWithTemplate") + UpdateDescriptorSetWithTemplateKHR = auto_cast GetInstanceProcAddr(instance, "vkUpdateDescriptorSetWithTemplateKHR") + UpdateDescriptorSets = auto_cast GetInstanceProcAddr(instance, "vkUpdateDescriptorSets") + WaitForFences = auto_cast GetInstanceProcAddr(instance, "vkWaitForFences") + WaitForPresentKHR = auto_cast GetInstanceProcAddr(instance, "vkWaitForPresentKHR") + WaitSemaphores = auto_cast GetInstanceProcAddr(instance, "vkWaitSemaphores") + WaitSemaphoresKHR = auto_cast GetInstanceProcAddr(instance, "vkWaitSemaphoresKHR") + WriteAccelerationStructuresPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkWriteAccelerationStructuresPropertiesKHR") +} + +load_proc_addresses_global :: proc(vk_get_instance_proc_addr: rawptr) { + GetInstanceProcAddr = auto_cast vk_get_instance_proc_addr + + CreateInstance = auto_cast GetInstanceProcAddr(nil, "vkCreateInstance") + DebugUtilsMessengerCallbackEXT = auto_cast GetInstanceProcAddr(nil, "vkDebugUtilsMessengerCallbackEXT") + DeviceMemoryReportCallbackEXT = auto_cast GetInstanceProcAddr(nil, "vkDeviceMemoryReportCallbackEXT") + EnumerateInstanceExtensionProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceExtensionProperties") + EnumerateInstanceLayerProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceLayerProperties") + EnumerateInstanceVersion = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceVersion") +} + +load_proc_addresses :: proc{ + load_proc_addresses_global, + load_proc_addresses_instance, + load_proc_addresses_device, + load_proc_addresses_device_vtable, + load_proc_addresses_custom, +} From 658a605c75c32746f248dc8e8e367c6b5dae976e Mon Sep 17 00:00:00 2001 From: jasonkercher Date: Fri, 4 Mar 2022 17:11:53 -0500 Subject: [PATCH 0332/1052] compiles --- core/os/os2/env_linux.odin | 28 +++++ core/os/os2/errors_linux.odin | 134 +++++++++++++++++++++++ core/os/os2/file.odin | 4 + core/os/os2/file_linux.odin | 169 ++++++++++++++++++++---------- core/os/os2/file_windows.odin | 5 + core/os/os2/heap_linux.odin | 27 +++++ core/os/os2/path_linux.odin | 85 +++++++++++++++ core/os/os2/pipe_linux.odin | 7 ++ core/os/os2/stat_linux.odin | 22 ++-- core/os/os2/temp_file_linux.odin | 18 ++++ core/sys/unix/syscalls_linux.odin | 146 +++++++++++++++++++++----- 11 files changed, 557 insertions(+), 88 deletions(-) create mode 100644 core/os/os2/env_linux.odin create mode 100644 core/os/os2/errors_linux.odin create mode 100644 core/os/os2/heap_linux.odin create mode 100644 core/os/os2/path_linux.odin create mode 100644 core/os/os2/pipe_linux.odin create mode 100644 core/os/os2/temp_file_linux.odin diff --git a/core/os/os2/env_linux.odin b/core/os/os2/env_linux.odin new file mode 100644 index 000000000..1833ac4dc --- /dev/null +++ b/core/os/os2/env_linux.odin @@ -0,0 +1,28 @@ +//+private +package os2 + +_get_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + //TODO + return +} + +_set_env :: proc(key, value: string) -> bool { + //TODO + return false +} + +_unset_env :: proc(key: string) -> bool { + //TODO + return false +} + +_clear_env :: proc() { + //TODO +} + +_environ :: proc(allocator := context.allocator) -> []string { + //TODO + return nil +} + + diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin new file mode 100644 index 000000000..f074c7c86 --- /dev/null +++ b/core/os/os2/errors_linux.odin @@ -0,0 +1,134 @@ +//+private +package os2 + +EPERM :: 1 +ENOENT :: 2 +ESRCH :: 3 +EINTR :: 4 +EIO :: 5 +ENXIO :: 6 +EBADF :: 9 +EAGAIN :: 11 +ENOMEM :: 12 +EACCES :: 13 +EFAULT :: 14 +EEXIST :: 17 +ENODEV :: 19 +ENOTDIR :: 20 +EISDIR :: 21 +EINVAL :: 22 +ENFILE :: 23 +EMFILE :: 24 +ETXTBSY :: 26 +EFBIG :: 27 +ENOSPC :: 28 +ESPIPE :: 29 +EROFS :: 30 +EPIPE :: 32 +ERANGE :: 34 /* Result too large */ +EDEADLK :: 35 /* Resource deadlock would occur */ +ENAMETOOLONG :: 36 /* File name too long */ +ENOLCK :: 37 /* No record locks available */ +ENOSYS :: 38 /* Invalid system call number */ +ENOTEMPTY :: 39 /* Directory not empty */ +ELOOP :: 40 /* Too many symbolic links encountered */ +EWOULDBLOCK :: EAGAIN /* Operation would block */ +ENOMSG :: 42 /* No message of desired type */ +EIDRM :: 43 /* Identifier removed */ +ECHRNG :: 44 /* Channel number out of range */ +EL2NSYNC :: 45 /* Level 2 not synchronized */ +EL3HLT :: 46 /* Level 3 halted */ +EL3RST :: 47 /* Level 3 reset */ +ELNRNG :: 48 /* Link number out of range */ +EUNATCH :: 49 /* Protocol driver not attached */ +ENOCSI :: 50 /* No CSI structure available */ +EL2HLT :: 51 /* Level 2 halted */ +EBADE :: 52 /* Invalid exchange */ +EBADR :: 53 /* Invalid request descriptor */ +EXFULL :: 54 /* Exchange full */ +ENOANO :: 55 /* No anode */ +EBADRQC :: 56 /* Invalid request code */ +EBADSLT :: 57 /* Invalid slot */ +EDEADLOCK :: EDEADLK +EBFONT :: 59 /* Bad font file format */ +ENOSTR :: 60 /* Device not a stream */ +ENODATA :: 61 /* No data available */ +ETIME :: 62 /* Timer expired */ +ENOSR :: 63 /* Out of streams resources */ +ENONET :: 64 /* Machine is not on the network */ +ENOPKG :: 65 /* Package not installed */ +EREMOTE :: 66 /* Object is remote */ +ENOLINK :: 67 /* Link has been severed */ +EADV :: 68 /* Advertise error */ +ESRMNT :: 69 /* Srmount error */ +ECOMM :: 70 /* Communication error on send */ +EPROTO :: 71 /* Protocol error */ +EMULTIHOP :: 72 /* Multihop attempted */ +EDOTDOT :: 73 /* RFS specific error */ +EBADMSG :: 74 /* Not a data message */ +EOVERFLOW :: 75 /* Value too large for defined data type */ +ENOTUNIQ :: 76 /* Name not unique on network */ +EBADFD :: 77 /* File descriptor in bad state */ +EREMCHG :: 78 /* Remote address changed */ +ELIBACC :: 79 /* Can not access a needed shared library */ +ELIBBAD :: 80 /* Accessing a corrupted shared library */ +ELIBSCN :: 81 /* .lib section in a.out corrupted */ +ELIBMAX :: 82 /* Attempting to link in too many shared libraries */ +ELIBEXEC :: 83 /* Cannot exec a shared library directly */ +EILSEQ :: 84 /* Illegal byte sequence */ +ERESTART :: 85 /* Interrupted system call should be restarted */ +ESTRPIPE :: 86 /* Streams pipe error */ +EUSERS :: 87 /* Too many users */ +ENOTSOCK :: 88 /* Socket operation on non-socket */ +EDESTADDRREQ :: 89 /* Destination address required */ +EMSGSIZE :: 90 /* Message too long */ +EPROTOTYPE :: 91 /* Protocol wrong type for socket */ +ENOPROTOOPT :: 92 /* Protocol not available */ +EPROTONOSUPPORT:: 93 /* Protocol not supported */ +ESOCKTNOSUPPORT:: 94 /* Socket type not supported */ +EOPNOTSUPP :: 95 /* Operation not supported on transport endpoint */ +EPFNOSUPPORT :: 96 /* Protocol family not supported */ +EAFNOSUPPORT :: 97 /* Address family not supported by protocol */ +EADDRINUSE :: 98 /* Address already in use */ +EADDRNOTAVAIL :: 99 /* Cannot assign requested address */ +ENETDOWN :: 100 /* Network is down */ +ENETUNREACH :: 101 /* Network is unreachable */ +ENETRESET :: 102 /* Network dropped connection because of reset */ +ECONNABORTED :: 103 /* Software caused connection abort */ +ECONNRESET :: 104 /* Connection reset by peer */ +ENOBUFS :: 105 /* No buffer space available */ +EISCONN :: 106 /* Transport endpoint is already connected */ +ENOTCONN :: 107 /* Transport endpoint is not connected */ +ESHUTDOWN :: 108 /* Cannot send after transport endpoint shutdown */ +ETOOMANYREFS :: 109 /* Too many references: cannot splice */ +ETIMEDOUT :: 110 /* Connection timed out */ +ECONNREFUSED :: 111 /* Connection refused */ +EHOSTDOWN :: 112 /* Host is down */ +EHOSTUNREACH :: 113 /* No route to host */ +EALREADY :: 114 /* Operation already in progress */ +EINPROGRESS :: 115 /* Operation now in progress */ +ESTALE :: 116 /* Stale file handle */ +EUCLEAN :: 117 /* Structure needs cleaning */ +ENOTNAM :: 118 /* Not a XENIX named type file */ +ENAVAIL :: 119 /* No XENIX semaphores available */ +EISNAM :: 120 /* Is a named type file */ +EREMOTEIO :: 121 /* Remote I/O error */ +EDQUOT :: 122 /* Quota exceeded */ +ENOMEDIUM :: 123 /* No medium found */ +EMEDIUMTYPE :: 124 /* Wrong medium type */ +ECANCELED :: 125 /* Operation Canceled */ +ENOKEY :: 126 /* Required key not available */ +EKEYEXPIRED :: 127 /* Key has expired */ +EKEYREVOKED :: 128 /* Key has been revoked */ +EKEYREJECTED :: 129 /* Key was rejected by service */ +EOWNERDEAD :: 130 /* Owner died */ +ENOTRECOVERABLE:: 131 /* State not recoverable */ +ERFKILL :: 132 /* Operation not possible due to RF-kill */ +EHWPOISON :: 133 /* Memory page has hardware error */ + +_error_string :: proc(errno: i32) -> string { + if errno == 0 { + return "" + } + return "Error" +} diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 707df37a2..09e1e8daf 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -61,6 +61,10 @@ create :: proc(name: string, perm: File_Mode = 0) -> (Handle, Error) { return open(name, {.Read, .Write, .Create}, perm) } +opendir :: proc(name: string) -> (Handle, Error) { + return _opendir(name) +} + open :: proc(name: string, flags := File_Flags{.Read}, perm: File_Mode = 0) -> (Handle, Error) { flags := flags if .Write not_in flags { diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 75a71b22b..72fbdcb56 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -3,6 +3,7 @@ package os2 import "core:io" import "core:time" +import "core:strings" import "core:sys/unix" @@ -15,13 +16,64 @@ _ok_or_error :: proc(res: int) -> Error { return res >= 0 ? nil : _get_platform_error(res) } -_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { - cstr := strings.clone_to_cstring(path, context.temp_allocator) - handle := Handle(unix.sys_open(cstr, int(flags), int(perm))) - if handle < 0 { - return Handle(-1), _get_platform_error(int(handle)) +_std_handle :: proc(kind: Std_Handle_Kind) -> Handle { + switch kind { + case .stdin: return Handle(0) + case .stdout: return Handle(1) + case .stderr: return Handle(2) } - return handle, nil + unreachable() +} + +_O_RDONLY :: 0o0 +_O_WRONLY :: 0o1 +_O_RDWR :: 0o2 +_O_CREAT :: 0o100 +_O_EXCL :: 0o200 +_O_TRUNC :: 0o1000 +_O_APPEND :: 0o2000 +_O_NONBLOCK :: 0o4000 +_O_LARGEFILE :: 0o100000 +_O_DIRECTORY :: 0o200000 +_O_SYNC :: 0o4010000 +_O_CLOEXEC :: 0o2000000 + +_opendir :: proc(name: string) -> (Handle, Error) { + cstr := strings.clone_to_cstring(name, context.temp_allocator) + + flags := _O_RDONLY|_O_NONBLOCK|_O_DIRECTORY|_O_LARGEFILE|_O_CLOEXEC + + handle_i := unix.sys_open(cstr, flags) + if handle_i < 0 { + return INVALID_HANDLE, _get_platform_error(handle_i) + } + + return Handle(handle_i), nil +} + +_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { + cstr := strings.clone_to_cstring(name, context.temp_allocator) + + flags_i: int + switch flags & O_RDONLY|O_WRONLY|O_RDWR { + case O_RDONLY: flags_i = _O_RDONLY + case O_WRONLY: flags_i = _O_WRONLY + case O_RDWR: flags_i = _O_RDWR + } + + flags_i |= (_O_APPEND * int(.Append in flags)) + flags_i |= (_O_CREAT * int(.Create in flags)) + flags_i |= (_O_EXCL * int(.Excl in flags)) + flags_i |= (_O_SYNC * int(.Sync in flags)) + flags_i |= (_O_TRUNC * int(.Trunc in flags)) + flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags)) + + handle_i := unix.sys_open(cstr, flags_i, int(perm)) + if handle_i < 0 { + return INVALID_HANDLE, _get_platform_error(handle_i) + } + + return Handle(handle_i), nil } _close :: proc(fd: Handle) -> Error { @@ -46,30 +98,27 @@ _read :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) { if len(p) == 0 { return 0, nil } - n = unix.sys_read(fd, &data[0], c.size_t(len(data))) + n = unix.sys_read(int(fd), &p[0], len(p)) if n < 0 { - return -1, unix.get_errno(n) + return -1, _get_platform_error(int(unix.get_errno(n))) } - return bytes_read, nil + return n, nil } _read_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { return 0, .Invalid_Offset } - - curr_offset, err := _seek(fd, 0, .Current) - if err != nil { - return 0, err - } - defer _seek(fd, curr_offset, .Start) - _seek(fd, offset, .Start) - b := p + b, offset := p, offset for len(b) > 0 { - m := _read(fd, b) or_return + m := unix.sys_pread(int(fd), &b[0], len(b), offset) + if m < 0 { + return -1, _get_platform_error(m) + } n += m b = b[m:] + offset += i64(m) } return } @@ -83,7 +132,7 @@ _write :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) { if len(p) == 0 { return 0, nil } - n = unix.sys_write(fd, &p[0], uint(len(p))) + n = unix.sys_write(int(fd), &p[0], uint(len(p))) if n < 0 { return -1, _get_platform_error(n) } @@ -94,19 +143,16 @@ _write_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { return 0, .Invalid_Offset } - - curr_offset, err := _seek(fd, 0, .Current) - if err != nil { - return 0, err - } - defer _seek(fd, curr_offset, .Start) - _seek(fd, offset, .Start) - b := p + b, offset := p, offset for len(b) > 0 { - m := _write(fd, b) or_return + m := unix.sys_pwrite(int(fd), &b[0], len(b), offset) + if m < 0 { + return -1, _get_platform_error(m) + } n += m b = b[m:] + offset += i64(m) } return } @@ -117,11 +163,12 @@ _write_to :: proc(fd: Handle, w: io.Writer) -> (n: i64, err: Error) { } _file_size :: proc(fd: Handle) -> (n: i64, err: Error) { - s, err := _fstat(fd) or_return - if err != nil { - return 0, err + s: OS_Stat = --- + res := unix.sys_fstat(int(fd), &s) + if res < 0 { + return -1, _get_platform_error(res) } - return max(s.size, 0), nil + return s.size, nil } _sync :: proc(fd: Handle) -> Error { @@ -137,17 +184,25 @@ _truncate :: proc(fd: Handle, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - if _is_dir(name) { - return _ok_or_error(unix.sys_rmdir(path_cstr)) + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + + handle_i := unix.sys_open(name_cstr, int(File_Flags.Read)) + if handle_i < 0 { + return _get_platform_error(handle_i) } - return _ok_or_error(unix.sys_unlink(path_cstr)) + defer unix.sys_close(handle_i) + + /* TODO: THIS WILL NOT WORK */ + if _is_dir(Handle(handle_i)) { + return _ok_or_error(unix.sys_rmdir(name_cstr)) + } + return _ok_or_error(unix.sys_unlink(name_cstr)) } -_rename :: proc(old_path, new_path: string) -> Error { - old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) - new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) - return _ok_or_error(unix.sys_rename(old_path_cstr, new_path_cstr)) +_rename :: proc(old_name, new_name: string) -> Error { + old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) + new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) + return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr)) } _link :: proc(old_name, new_name: string) -> Error { @@ -163,16 +218,16 @@ _symlink :: proc(old_name, new_name: string) -> Error { } _read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) { - path_cstr := strings.clone_to_cstring(path) - defer delete(path_cstr) + name_cstr := strings.clone_to_cstring(name) + defer delete(name_cstr) bufsz : uint = 256 buf := make([]byte, bufsz, allocator) for { - rc := unix.sys_readlink(path_cstr, &(buf[0]), bufsz) + rc := unix.sys_readlink(name_cstr, &(buf[0]), bufsz) if rc < 0 { delete(buf) - return "", unix.get_errno(rc) + return "", _get_platform_error(int(unix.get_errno(rc))) } else if rc == int(bufsz) { bufsz *= 2 delete(buf) @@ -183,9 +238,9 @@ _read_link :: proc(name: string, allocator := context.allocator) -> (string, Err } } -_unlink :: proc(path: string) -> Error { - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _ok_or_error(unix.sys_unlink(path_cstr)) +_unlink :: proc(name: string) -> Error { + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return _ok_or_error(unix.sys_unlink(name_cstr)) } _chdir :: proc(fd: Handle) -> Error { @@ -193,18 +248,16 @@ _chdir :: proc(fd: Handle) -> Error { } _chmod :: proc(fd: Handle, mode: File_Mode) -> Error { - //TODO - return nil + return _ok_or_error(unix.sys_fchmod(int(fd), int(mode))) } _chown :: proc(fd: Handle, uid, gid: int) -> Error { - //TODO - return nil + return _ok_or_error(unix.sys_fchown(int(fd), uid, gid)) } _lchown :: proc(name: string, uid, gid: int) -> Error { - //TODO - return nil + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid)) } _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { @@ -212,14 +265,14 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { return nil } -_exists :: proc(path: string) -> bool { - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return unix.sys_access(path_cstr, F_OK) == 0 +_exists :: proc(name: string) -> bool { + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return unix.sys_access(name_cstr, F_OK) == 0 } _is_file :: proc(fd: Handle) -> bool { s: OS_Stat - res := unix.sys_fstat(int(fd), rawptr(&s)) + res := unix.sys_fstat(int(fd), &s) if res < 0 { // error return false } @@ -228,7 +281,7 @@ _is_file :: proc(fd: Handle) -> bool { _is_dir :: proc(fd: Handle) -> bool { s: OS_Stat - res := unix.sys_fstat(int(fd), rawptr(&s)) + res := unix.sys_fstat(int(fd), &s) if res < 0 { // error return false } diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index 9fdbd9a5a..dd33d8a53 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -36,6 +36,11 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { unreachable() } +_opendir :: proc(path: string) -> (handle: Handle, err: Error) { + return INVALID_HANDLE, .Invalid_Argument +} + + _open :: proc(path: string, flags: File_Flags, perm: File_Mode) -> (handle: Handle, err: Error) { handle = INVALID_HANDLE if len(path) == 0 { diff --git a/core/os/os2/heap_linux.odin b/core/os/os2/heap_linux.odin new file mode 100644 index 000000000..f617f8cc8 --- /dev/null +++ b/core/os/os2/heap_linux.odin @@ -0,0 +1,27 @@ +//+private +package os2 + +import "core:mem" + +heap_alloc :: proc(size: int) -> rawptr { + // TODO + return nil +} + +heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // TODO + return nil +} +heap_free :: proc(ptr: rawptr) { + if ptr == nil { + return + } + // TODO +} + +_heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) { + // TODO + return nil, nil +} diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin new file mode 100644 index 000000000..b45d6e976 --- /dev/null +++ b/core/os/os2/path_linux.odin @@ -0,0 +1,85 @@ +//+private +package os2 + +import "core:fmt" +import "core:strings" +import "core:sys/unix" +import "core:path/filepath" + +_Path_Separator :: '/' +_Path_List_Separator :: ':' + +_is_path_separator :: proc(c: byte) -> bool { + return c == '/' +} + +_mkdir :: proc(path: string, perm: File_Mode) -> Error { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + //TODO file_mode + return _ok_or_error(unix.sys_mkdir(path_cstr)) +} + +_mkdir_all :: proc(path: string, perm: File_Mode) -> Error { + _mkdir_all_stat :: proc(path: string, s: ^OS_Stat, perm: File_Mode) -> Error { + if len(path) == 0 { + return nil + } + + path := path[len(path)-1] == '/' ? path[:len(path)-1] : path + dir, _ := filepath.split(path) + + if len(dir) == 0 { + return _mkdir(path, perm) + } + + dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) + errno := int(unix.get_errno(unix.sys_stat(dir_cstr, s))) + switch errno { + case 0: + if !S_ISDIR(s.mode) { + return .Exist + } + return _mkdir(path, perm) + case ENOENT: + _mkdir_all_stat(dir, s, perm) or_return + return _mkdir(path, perm) + case: + return _get_platform_error(errno) + } + unreachable() + } + // OS_Stat is fat. Make one and re-use it. + s: OS_Stat = --- + return _mkdir_all_stat(path, &s, perm) +} + +_remove_all :: proc(path: string) -> Error { + // TODO + return nil +} + +_getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { + // NOTE(tetra): I would use PATH_MAX here, but I was not able to find + // an authoritative value for it across all systems. + // The largest value I could find was 4096, so might as well use the page size. + // NOTE(jason): Avoiding libc, so just use 4096 directly + PATH_MAX :: 4096 + buf := make([dynamic]u8, PATH_MAX, allocator) + for { + #no_bounds_check res := unix.sys_getcwd(&buf[0], uint(len(buf))) + + if res >= 0 { + return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)), nil + } + if errno := int(unix.get_errno(res)); errno != ERANGE { + return "", _get_platform_error(errno) + } + resize(&buf, len(buf)+PATH_MAX) + } + unreachable() +} + +_setwd :: proc(dir: string) -> (err: Error) { + dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) + return _ok_or_error(unix.sys_chdir(dir_cstr)) +} diff --git a/core/os/os2/pipe_linux.odin b/core/os/os2/pipe_linux.odin new file mode 100644 index 000000000..0699c5720 --- /dev/null +++ b/core/os/os2/pipe_linux.odin @@ -0,0 +1,7 @@ +//+private +package os2 + +_pipe :: proc() -> (r, w: Handle, err: Error) { + return INVALID_HANDLE, INVALID_HANDLE, nil +} + diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index 7fce8fb9c..c4cc5fe8d 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -2,7 +2,9 @@ package os2 import "core:time" +import "core:strings" import "core:sys/unix" +import "core:path/filepath" // File type S_IFMT :: 0o170000 // Type of file mask @@ -51,6 +53,12 @@ X_OK :: 1 // Test for execute permission W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission +@private +Unix_File_Time :: struct { + seconds: i64, + nanoseconds: i64, +} + @private OS_Stat :: struct { device_id: u64, // ID of device containing file @@ -75,19 +83,21 @@ OS_Stat :: struct { } _fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) { + return File_Info{}, nil } _stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { + return File_Info{}, nil } _lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { - cstr := strings.clone_to_cstring(path) + cstr := strings.clone_to_cstring(name) defer delete(cstr) s: OS_Stat result := unix.sys_lstat(cstr, &s) if result < 0 { - return {}, unix.get_errno(result) + return {}, _get_platform_error(int(unix.get_errno(result))) } fi := File_Info { @@ -96,10 +106,10 @@ _lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Erro size = s.size, mode = 0, is_dir = S_ISDIR(s.mode), - creation_time = nil, // linux does not track this + creation_time = time.Time{0}, // linux does not track this //TODO - modification_time = nil, - access_time = nil, + modification_time = time.Time{0}, + access_time = time.Time{0}, } return fi, nil @@ -110,7 +120,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool { } _stat_internal :: proc(name: string) -> (s: OS_Stat, res: int) { - name_cstr = strings.clone_to_cstring(name, context.temp_allocator) + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) res = unix.sys_stat(name_cstr, &s) return } diff --git a/core/os/os2/temp_file_linux.odin b/core/os/os2/temp_file_linux.odin new file mode 100644 index 000000000..d56bc34d3 --- /dev/null +++ b/core/os/os2/temp_file_linux.odin @@ -0,0 +1,18 @@ +//+private +package os2 + + +_create_temp :: proc(dir, pattern: string) -> (Handle, Error) { + //TODO + return 0, nil +} + +_mkdir_temp :: proc(dir, pattern: string, allocator := context.allocator) -> (string, Error) { + //TODO + return "", nil +} + +_temp_dir :: proc(allocator := context.allocator) -> string { + //TODO + return "" +} diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 243f8accc..ccd8a75e6 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -15,7 +15,7 @@ import "core:intrinsics" // 386: arch/x86/entry/syscalls/sycall_32.tbl // arm: arch/arm/tools/syscall.tbl -when ODIN_ARCH == "amd64" { +when ODIN_ARCH == .amd64 { SYS_read : uintptr : 0 SYS_write : uintptr : 1 SYS_open : uintptr : 2 @@ -33,8 +33,8 @@ when ODIN_ARCH == "amd64" { SYS_rt_sigprocmask : uintptr : 14 SYS_rt_sigreturn : uintptr : 15 SYS_ioctl : uintptr : 16 - SYS_pread : uintptr : 17 - SYS_pwrite : uintptr : 18 + SYS_pread64 : uintptr : 17 + SYS_pwrite64 : uintptr : 18 SYS_readv : uintptr : 19 SYS_writev : uintptr : 20 SYS_access : uintptr : 21 @@ -374,7 +374,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when ODIN_ARCH == "arm64" { +} else when ODIN_ARCH == .arm64 { SYS_io_setup : uintptr : 0 SYS_io_destroy : uintptr : 1 SYS_io_submit : uintptr : 2 @@ -675,7 +675,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 -} else when ODIN_ARCH == "386" { +} else when ODIN_ARCH == .i386 { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 @@ -1112,7 +1112,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when ODIN_ARCH == "arm" { +} else when ODIN_ARCH == .arm { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 @@ -1518,6 +1518,7 @@ when ODIN_ARCH == "amd64" { AT_FDCWD :: -100 AT_REMOVEDIR :: uintptr(0x200) +AT_SYMLINK_FOLLOW :: uintptr(0x400) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) sys_gettid :: proc "contextless" () -> int { @@ -1529,12 +1530,11 @@ sys_getrandom :: proc "contextless" (buf: ^byte, buflen: int, flags: uint) -> in } sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { - when ODIN_ARCH != "arm64" { - res := int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open - res := int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) + return int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) } - return -1 if res < 0 else res } sys_close :: proc(fd: int) -> int { @@ -1545,26 +1545,46 @@ sys_read :: proc(fd: int, buf: rawptr, size: uint) -> int { return int(intrinsics.syscall(SYS_read, uintptr(fd), uintptr(buf), uintptr(size))) } +sys_pread :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_pread64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) + } else { + low := uintptr(offset & 0xFFFFFFFF) + high := uintptr(offset >> 32) + return int(intrinsics.syscall(SYS_pread64, uintptr(fd), uintptr(buf), uintptr(size), high, low)) + } +} + sys_write :: proc(fd: int, buf: rawptr, size: uint) -> int { return int(intrinsics.syscall(SYS_write, uintptr(fd), uintptr(buf), uintptr(size))) } +sys_pwrite :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_pwrite64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) + } else { + low := uintptr(offset & 0xFFFFFFFF) + high := uintptr(offset >> 32) + return int(intrinsics.syscall(SYS_pwrite64, uintptr(fd), uintptr(buf), uintptr(size), high, low)) + } +} + sys_lseek :: proc(fd: int, offset: i64, whence: int) -> i64 { - when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return i64(intrinsics.syscall(SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) } else { low := uintptr(offset & 0xFFFFFFFF) high := uintptr(offset >> 32) result: i64 res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence))) - return -1 if res < 0 else result + return res if res < 0 else result } } sys_stat :: proc(path: cstring, stat: rawptr) -> int { - when ODIN_ARCH == "amd64" { + when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_stat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != "arm64" { + } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have stat return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0)) @@ -1572,7 +1592,7 @@ sys_stat :: proc(path: cstring, stat: rawptr) -> int { } sys_fstat :: proc(fd: int, stat: rawptr) -> int { - when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_fstat, uintptr(fd), uintptr(stat))) } else { return int(intrinsics.syscall(SYS_fstat64, uintptr(fd), uintptr(stat))) @@ -1580,9 +1600,9 @@ sys_fstat :: proc(fd: int, stat: rawptr) -> int { } sys_lstat :: proc(path: cstring, stat: rawptr) -> int { - when ODIN_ARCH == "amd64" { + when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != "arm64" { + } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have any lstat return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) @@ -1590,15 +1610,23 @@ sys_lstat :: proc(path: cstring, stat: rawptr) -> int { } sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } else { // NOTE: arm64 does not have readlink return int(intrinsics.syscall(SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } } +sys_symlink :: proc(old_name: cstring, new_name: cstring) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_symlink, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) + } else { // NOTE: arm64 does not have symlink + return int(intrinsics.syscall(SYS_symlinkat, uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)))) + } +} + sys_access :: proc(path: cstring, mask: int) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_access, uintptr(rawptr(path)), uintptr(mask))) } else { // NOTE: arm64 does not have access return int(intrinsics.syscall(SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask))) @@ -1613,16 +1641,60 @@ sys_chdir :: proc(path: cstring) -> int { return int(intrinsics.syscall(SYS_chdir, uintptr(rawptr(path)))) } +sys_fchdir :: proc(fd: int) -> int { + return int(intrinsics.syscall(SYS_fchdir, uintptr(fd))) +} + +sys_chmod :: proc(path: cstring, mode: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) + } else { // NOTE: arm64 does not have chmod + return int(intrinsics.syscall(SYS_fchmodat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + } +} + +sys_fchmod :: proc(fd: int, mode: int) -> int { + return int(intrinsics.syscall(SYS_fchmod, uintptr(fd), uintptr(mode))) +} + +sys_chown :: proc(path: cstring, user: int, group: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_chown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) + } else { // NOTE: arm64 does not have chown + return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), 0)) + } +} + +sys_fchown :: proc(fd: int, user: int, group: int) -> int { + return int(intrinsics.syscall(SYS_fchown, uintptr(fd), uintptr(user), uintptr(group))) +} + +sys_lchown :: proc(path: cstring, user: int, group: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_lchown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) + } else { // NOTE: arm64 does not have lchown + return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), AT_SYMLINK_NOFOLLOW)) + } +} + sys_rename :: proc(old, new: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) } else { // NOTE: arm64 does not have rename return int(intrinsics.syscall(SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new)))) } } +sys_link :: proc(old_name: cstring, new_name: cstring) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_link, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) + } else { // NOTE: arm64 does not have link + return int(intrinsics.syscall(SYS_linkat, uintptr(AT_FDCWD), uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)), AT_SYMLINK_FOLLOW)) + } +} + sys_unlink :: proc(path: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_unlink, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have unlink return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0))) @@ -1630,7 +1702,7 @@ sys_unlink :: proc(path: cstring) -> int { } sys_rmdir :: proc(path: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have rmdir return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR)) @@ -1638,14 +1710,40 @@ sys_rmdir :: proc(path: cstring) -> int { } sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir return int(intrinsics.syscall(SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) } } -//TODO: ftruncate, symlink, readlink, fchdir, fchmod, chown, fchown, lchown +sys_truncate :: proc(path: cstring, length: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_truncate, uintptr(rawptr(path)), uintptr(length))) + } else { + low := uintptr(length & 0xFFFFFFFF) + high := uintptr(length >> 32) + return int(intrinsics.syscall(SYS_truncate64, uintptr(rawptr(path)), high, low)) + } +} + +sys_ftruncate :: proc(fd: int, length: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_ftruncate, uintptr(fd), uintptr(length))) + } else { + low := uintptr(length & 0xFFFFFFFF) + high := uintptr(length >> 32) + return int(intrinsics.syscall(SYS_ftruncate64, uintptr(fd), high, low)) + } +} + +sys_fsync :: proc(fd: int) -> int { + return int(intrinsics.syscall(SYS_fsync, uintptr(fd))) +} + +sys_getdents64 :: proc(fd: int, dirent: rawptr, count: int) -> int { + return int(intrinsics.syscall(SYS_getdents64, uintptr(fd), uintptr(dirent), uintptr(count))) +} get_errno :: proc(res: int) -> i32 { if res < 0 && res > -4096 { From 1cd89b2da36134fc43e0cc2fe25a1dc9bfb9932a Mon Sep 17 00:00:00 2001 From: kstrb <(none)> Date: Sat, 5 Mar 2022 17:28:34 +0100 Subject: [PATCH 0333/1052] Linux: allow 'foreign import' of object files --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f8a3e6f85..8db3a09ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -406,8 +406,8 @@ i32 linker_stage(lbGenerator *gen) { // available at runtime wherever the executable is run, so we make require those to be // local to the executable (unless the system collection is used, in which case we search // the system library paths for the library file). - if (string_ends_with(lib, str_lit(".a"))) { - // static libs, absolute full path relative to the file in which the lib was imported from + if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) { + // static libs and object files, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); } else if (string_ends_with(lib, str_lit(".so"))) { // dynamic lib, relative path to executable From bff3426d254bf728b330c6f93fac97339cc41c67 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Sun, 6 Mar 2022 10:21:46 +0100 Subject: [PATCH 0334/1052] Fix leak in `core:container/bit_array` calling `clear` on a `bit_array` no longer leaks the previous allocation, instead it sets all bits to `false` preserving the same backing dynamic array. --- core/container/bit_array/bit_array.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 5eebe1bcb..0016ca105 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -1,6 +1,7 @@ package dynamic_bit_array import "core:intrinsics" +import "core:mem" /* Note that these constants are dependent on the backing being a u64. @@ -206,7 +207,7 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) - */ clear :: proc(ba: ^Bit_Array) { if ba == nil { return } - ba.bits = {} + mem.zero_slice(ba.bits[:]) } /* From ce057ff755d2fe852cb83e4025686d9efd3053d7 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 6 Mar 2022 12:29:17 +0100 Subject: [PATCH 0335/1052] [bit_array] Really fix the leak. --- core/container/bit_array/bit_array.odin | 26 ++++++++++++++----------- core/container/bit_array/doc.odin | 13 +++++++------ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 0016ca105..98ef4b542 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -16,15 +16,16 @@ INDEX_MASK :: 63 NUM_BITS :: 64 Bit_Array :: struct { - bits: [dynamic]u64, - bias: int, - max_index: int, + bits: [dynamic]u64, + bias: int, + max_index: int, + free_pointer: bool, } Bit_Array_Iterator :: struct { - array: ^Bit_Array, + array: ^Bit_Array, word_idx: int, - bit_idx: uint, + bit_idx: uint, } /* @@ -187,7 +188,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator /* A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative). */ -create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: Bit_Array, ok: bool) #optional_ok { +create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok { context.allocator = allocator size_in_bits := max_index - min_index @@ -195,11 +196,11 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) - legs := size_in_bits >> INDEX_SHIFT - res = Bit_Array{ - bias = min_index, - max_index = max_index, - } - return res, resize_if_needed(&res, legs) + res = new(Bit_Array) + res.bias = min_index + res.max_index = max_index + res.free_pointer = true + return res, resize_if_needed(res, legs) } /* @@ -216,6 +217,9 @@ clear :: proc(ba: ^Bit_Array) { destroy :: proc(ba: ^Bit_Array) { if ba == nil { return } delete(ba.bits) + if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack. + free(ba) + } } /* diff --git a/core/container/bit_array/doc.odin b/core/container/bit_array/doc.odin index 91e1362dd..52e252d8a 100644 --- a/core/container/bit_array/doc.odin +++ b/core/container/bit_array/doc.odin @@ -21,6 +21,7 @@ package dynamic_bit_array // returns `false`, `false`, because this Bit Array wasn't created to allow negative indices. was_set, was_retrieved := get(&bits, -1) fmt.println(was_set, was_retrieved) + destroy(&bits) } -- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation: @@ -40,13 +41,13 @@ package dynamic_bit_array using bit_array bits := create(int(max(Foo)), int(min(Foo))) - defer destroy(&bits) + defer destroy(bits) - fmt.printf("Set(Bar): %v\n", set(&bits, Foo.Bar)) - fmt.printf("Get(Bar): %v, %v\n", get(&bits, Foo.Bar)) - fmt.printf("Set(Negative_Test): %v\n", set(&bits, Foo.Negative_Test)) - fmt.printf("Get(Leaves): %v, %v\n", get(&bits, Foo.Leaves)) - fmt.printf("Get(Negative_Test): %v, %v\n", get(&bits, Foo.Negative_Test)) + fmt.printf("Set(Bar): %v\n", set(bits, Foo.Bar)) + fmt.printf("Get(Bar): %v, %v\n", get(bits, Foo.Bar)) + fmt.printf("Set(Negative_Test): %v\n", set(bits, Foo.Negative_Test)) + fmt.printf("Get(Leaves): %v, %v\n", get(bits, Foo.Leaves)) + fmt.printf("Get(Negative_Test): %v, %v\n", get(bits, Foo.Negative_Test)) fmt.printf("Freed.\n") } */ \ No newline at end of file From a6c5143993e503b3892d41b7266aa450c03b8bd6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 6 Mar 2022 14:46:20 +0100 Subject: [PATCH 0336/1052] [intrinsics] Add existing `unaligned_load`. --- core/intrinsics/intrinsics.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 803b04d17..0196786ec 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -41,6 +41,7 @@ mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) --- mem_zero :: proc(ptr: rawptr, len: int) --- mem_zero_volatile :: proc(ptr: rawptr, len: int) --- +unaligned_load :: proc(ptr: ^$T) -> T --- fixed_point_mul :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) --- fixed_point_div :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) --- From deed20dea6114c6a15bccb83dc53855e560f4565 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 6 Mar 2022 14:53:06 +0100 Subject: [PATCH 0337/1052] [intrinsics] Add `unaligned_store`. --- core/intrinsics/intrinsics.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 0196786ec..c3ef787bc 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -41,7 +41,8 @@ mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) --- mem_zero :: proc(ptr: rawptr, len: int) --- mem_zero_volatile :: proc(ptr: rawptr, len: int) --- -unaligned_load :: proc(ptr: ^$T) -> T --- +unaligned_load :: proc(src: ^$T) -> T --- +unaligned_store :: proc(dst: ^$T, val: T) -> T --- fixed_point_mul :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) --- fixed_point_div :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) --- From 1f19610fd67b00b49cc9d726af2e8d9ac5f4807b Mon Sep 17 00:00:00 2001 From: jasonkercher Date: Mon, 7 Mar 2022 17:16:03 -0500 Subject: [PATCH 0338/1052] added _remove_all --- core/os/os2/file_linux.odin | 44 ++++++------- core/os/os2/path_linux.odin | 101 ++++++++++++++++++++++++++++-- core/sys/unix/syscalls_linux.odin | 8 +++ 3 files changed, 126 insertions(+), 27 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 72fbdcb56..a88515b0e 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -25,23 +25,23 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { unreachable() } -_O_RDONLY :: 0o0 -_O_WRONLY :: 0o1 -_O_RDWR :: 0o2 -_O_CREAT :: 0o100 -_O_EXCL :: 0o200 -_O_TRUNC :: 0o1000 -_O_APPEND :: 0o2000 -_O_NONBLOCK :: 0o4000 -_O_LARGEFILE :: 0o100000 -_O_DIRECTORY :: 0o200000 -_O_SYNC :: 0o4010000 -_O_CLOEXEC :: 0o2000000 +__O_RDONLY :: 0o0 +__O_WRONLY :: 0o1 +__O_RDWR :: 0o2 +__O_CREAT :: 0o100 +__O_EXCL :: 0o200 +__O_TRUNC :: 0o1000 +__O_APPEND :: 0o2000 +__O_NONBLOCK :: 0o4000 +__O_LARGEFILE :: 0o100000 +__O_DIRECTORY :: 0o200000 +__O_SYNC :: 0o4010000 +__O_CLOEXEC :: 0o2000000 _opendir :: proc(name: string) -> (Handle, Error) { cstr := strings.clone_to_cstring(name, context.temp_allocator) - flags := _O_RDONLY|_O_NONBLOCK|_O_DIRECTORY|_O_LARGEFILE|_O_CLOEXEC + flags := __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC handle_i := unix.sys_open(cstr, flags) if handle_i < 0 { @@ -56,17 +56,17 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Erro flags_i: int switch flags & O_RDONLY|O_WRONLY|O_RDWR { - case O_RDONLY: flags_i = _O_RDONLY - case O_WRONLY: flags_i = _O_WRONLY - case O_RDWR: flags_i = _O_RDWR + case O_RDONLY: flags_i = __O_RDONLY + case O_WRONLY: flags_i = __O_WRONLY + case O_RDWR: flags_i = __O_RDWR } - flags_i |= (_O_APPEND * int(.Append in flags)) - flags_i |= (_O_CREAT * int(.Create in flags)) - flags_i |= (_O_EXCL * int(.Excl in flags)) - flags_i |= (_O_SYNC * int(.Sync in flags)) - flags_i |= (_O_TRUNC * int(.Trunc in flags)) - flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags)) + flags_i |= (__O_APPEND * int(.Append in flags)) + flags_i |= (__O_CREAT * int(.Create in flags)) + flags_i |= (__O_EXCL * int(.Excl in flags)) + flags_i |= (__O_SYNC * int(.Sync in flags)) + flags_i |= (__O_TRUNC * int(.Trunc in flags)) + flags_i |= (__O_CLOEXEC * int(.Close_On_Exec in flags)) handle_i := unix.sys_open(cstr, flags_i, int(perm)) if handle_i < 0 { diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index b45d6e976..31abf5bf8 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -1,7 +1,6 @@ //+private package os2 -import "core:fmt" import "core:strings" import "core:sys/unix" import "core:path/filepath" @@ -9,6 +8,8 @@ import "core:path/filepath" _Path_Separator :: '/' _Path_List_Separator :: ':' +DIRECTORY_FLAGS :: __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC + _is_path_separator :: proc(c: byte) -> bool { return c == '/' } @@ -53,9 +54,99 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { return _mkdir_all_stat(path, &s, perm) } +dirent64 :: struct { + d_ino: u64, + d_off: u64, + d_reclen: u16, + d_type: u8, + d_name: [1]u8, +} + +DT_UNKNOWN :: 0 +DT_FIFO :: 1 +DT_CHR :: 2 +DT_DIR :: 4 +DT_BLK :: 6 +DT_REG :: 8 +DT_LNK :: 10 +DT_SOCK :: 12 +DT_WHT :: 14 + _remove_all :: proc(path: string) -> Error { - // TODO - return nil + _remove_all_dir :: proc(dfd: Handle) -> Error { + n := 64 + buf := make([]u8, n) + defer delete(buf) + + loop: for { + res := unix.sys_getdents64(int(dfd), &buf[0], n) + switch res { + case -22: //-EINVAL + n *= 2 + buf = make([]u8, n) + continue loop + case -4096..<0: + return _get_platform_error(res) + case 0: + break loop + } + + d: ^dirent64 + + for i := 0; i < res; i += int(d.d_reclen) { + description: string + d = (^dirent64)(rawptr(&buf[i])) + d_name_cstr := cstring(&d.d_name[0]) + + buf_len := uintptr(d.d_reclen) - offset_of(d.d_name) + + /* check for current directory (.) */ + #no_bounds_check if buf_len > 1 && d.d_name[0] == '.' && d.d_name[1] == 0 { + continue + } + + /* check for parent directory (..) */ + #no_bounds_check if buf_len > 2 && d.d_name[0] == '.' && d.d_name[1] == '.' && d.d_name[2] == 0 { + continue + } + + res: int + + switch d.d_type { + case DT_DIR: + handle_i := unix.sys_openat(int(dfd), d_name_cstr, DIRECTORY_FLAGS) + if handle_i < 0 { + return _get_platform_error(handle_i) + } + defer unix.sys_close(handle_i) + _remove_all_dir(Handle(handle_i)) or_return + res = unix.sys_unlinkat(int(dfd), d_name_cstr, int(unix.AT_REMOVEDIR)) + case: + res = unix.sys_unlinkat(int(dfd), d_name_cstr) + } + + if res < 0 { + return _get_platform_error(res) + } + } + } + return nil + } + + cstr := strings.clone_to_cstring(path, context.temp_allocator) + + handle_i := unix.sys_open(cstr, DIRECTORY_FLAGS) + switch handle_i { + case -ENOTDIR: + return _ok_or_error(unix.sys_unlink(cstr)) + case -4096..<0: + return _get_platform_error(handle_i) + } + + fd := Handle(handle_i) + defer close(fd) + _remove_all_dir(fd) or_return + return _ok_or_error(unix.sys_rmdir(cstr)) } _getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { @@ -71,8 +162,8 @@ _getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { if res >= 0 { return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)), nil } - if errno := int(unix.get_errno(res)); errno != ERANGE { - return "", _get_platform_error(errno) + if res != -ERANGE { + return "", _get_platform_error(res) } resize(&buf, len(buf)+PATH_MAX) } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index ccd8a75e6..889dd3b90 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1537,6 +1537,10 @@ sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { } } +sys_openat :: proc(dfd: int, path: cstring, flags: int, mode: int = 0o000) -> int { + return int(intrinsics.syscall(SYS_openat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) +} + sys_close :: proc(fd: int) -> int { return int(intrinsics.syscall(SYS_close, uintptr(fd))) } @@ -1701,6 +1705,10 @@ sys_unlink :: proc(path: cstring) -> int { } } +sys_unlinkat :: proc(dfd: int, path: cstring, flag: int = 0) -> int { + return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), flag)) +} + sys_rmdir :: proc(path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path)))) From 31959b07514e22c2ea9ec34abf781887df885af5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Mar 2022 10:01:44 +0000 Subject: [PATCH 0339/1052] Correct `cleanpath_from_handle` for `os.fstat` --- core/os/stat_windows.odin | 43 +++++++++------------------------------ 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 2d9f98fd4..964625315 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -132,26 +132,11 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { @(private) cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) { - if fd == 0 { - return "", ERROR_INVALID_HANDLE + buf, err := cleanpath_from_handle_u16(fd) + if err != 0 { + return "", err } - h := win32.HANDLE(fd) - - MAX_PATH := win32.DWORD(260) + 1 - buf: []u16 - for { - buf = make([]u16, MAX_PATH, context.temp_allocator) - err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0) - switch Errno(err) { - case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER: - return "", Errno(err) - case ERROR_NOT_ENOUGH_MEMORY: - MAX_PATH = MAX_PATH*2 + 1 - continue - } - break - } - return cleanpath_from_buf(buf), ERROR_NONE + return win32.utf16_to_utf8(buf, context.allocator), err } @(private) cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) { @@ -160,21 +145,13 @@ cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) { } h := win32.HANDLE(fd) - MAX_PATH := win32.DWORD(260) + 1 - buf: []u16 - for { - buf = make([]u16, MAX_PATH, context.temp_allocator) - err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0) - switch Errno(err) { - case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER: - return nil, Errno(err) - case ERROR_NOT_ENOUGH_MEMORY: - MAX_PATH = MAX_PATH*2 + 1 - continue - } - break + n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) + if n == 0 { + return nil, Errno(win32.GetLastError()) } - return cleanpath_strip_prefix(buf), ERROR_NONE + buf := make([]u16, max(n, win32.DWORD(260))+1, context.temp_allocator) + buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) + return buf[:buf_len], ERROR_NONE } @(private) cleanpath_from_buf :: proc(buf: []u16) -> string { From 29e660b16f18df2c3d6781fef5d1baa3faac0c94 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Mar 2022 10:02:40 +0000 Subject: [PATCH 0340/1052] Add more things to `package slice` min_max any_of(_proc) none_of(_proc) all_of(_proc) count(_proc) --- core/slice/slice.odin | 101 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 5 deletions(-) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 5fecc76b1..520e3e1e0 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -304,7 +304,7 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) - return r[:] } -scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U)->V, allocator := context.allocator) -> []V { +scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> []V { if len(s) == 0 { return {} } res := make([]V, len(s), allocator) @@ -344,15 +344,106 @@ max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T return } +min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) { + if len(s) != 0 { + min, max = s[0], s[0] + ok = true + for v in s[1:] { + min = builtin.min(min, v) + max = builtin.max(max, v) + } + } + return +} -dot_product :: proc(a, b: $S/[]$T) -> T +any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { + for v in s { + if v == value { + return true + } + } + return false +} + +none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { + for v in s { + if v == value { + return false + } + } + return true +} + +all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { + if len(s) == 0 { + return false + } + for v in s { + if v != value { + return false + } + } + return true +} + + +any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { + for v in s { + if f(v) { + return true + } + } + return false +} + +none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { + for v in s { + if f(v) { + return false + } + } + return true +} + +all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { + if len(s) == 0 { + return false + } + for v in s { + if !f(v) { + return false + } + } + return true +} + + +count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) { + for v in s { + if v == value { + n += 1 + } + } + return +} + +count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) { + for v in s { + if f(v) { + n += 1 + } + } + return +} + + +dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool) where intrinsics.type_is_numeric(T) { if len(a) != len(b) { - panic("slice.dot_product: slices of unequal length") + return } - r: T #no_bounds_check for _, i in a { r += a[i] * b[i] } - return r + return r, true } From 17dab044224c8c464cbbc5840ab1592d59f0a6a0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Mar 2022 11:13:59 +0000 Subject: [PATCH 0341/1052] Refactor link flag creation for nix systems --- src/main.cpp | 57 ++++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8db3a09ec..1e1e957cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -475,34 +475,39 @@ i32 linker_stage(lbGenerator *gen) { } } - result = system_exec_command_line_app("ld-link", - "clang -Wno-unused-command-line-argument %s -o \"%.*s%.*s\" %s " - " %s " - " %.*s " - " %.*s " - " %s " - #if defined(GB_SYSTEM_OSX) - // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. - // NOTE: If you change this (although this minimum is as low as you can go with Odin working) - // make sure to also change the 'mtriple' param passed to 'opt' - #if defined(GB_CPU_ARM) - " -mmacosx-version-min=12.0.0 " - #else - " -mmacosx-version-min=10.8.0 " - #endif - // This points the linker to where the entry point is - " -e _main " - #endif - , object_files, LIT(output_base), LIT(output_ext), - #if defined(GB_SYSTEM_OSX) - "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib", + gbString platform_lib_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(platform_lib_str)); + #if defined(GB_SYSTEM_OSX) + platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib"); + #else + platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm"); + #endif + + #if defined(GB_SYSTEM_OSX) + // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. + // NOTE: If you change this (although this minimum is as low as you can go with Odin working) + // make sure to also change the 'mtriple' param passed to 'opt' + #if defined(GB_CPU_ARM) + link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 "); #else - "-lc -lm", + link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.8.0 "); #endif - lib_str, - LIT(build_context.link_flags), - LIT(build_context.extra_linker_flags), - link_settings); + // This points the linker to where the entry point is + link_settings = gb_string_appendc(link_settings, " -e _main "); + #endif + + gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument "); + defer (gb_string_free(link_command_line)); + + link_command_line = gb_string_appendc(link_command_line, object_files); + link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s%.*s\" ", LIT(output_base), LIT(output_ext)); + link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str); + link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str); + link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags)); + link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags)); + link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings); + + result = system_exec_command_line_app("ld-link", link_command_line); if (result) { return result; From 6d7217f37a241c688e4734d7b8f6904299cadd2b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 8 Mar 2022 15:40:00 +0100 Subject: [PATCH 0342/1052] [varint] Add LEB128 decoding + tests Also make tests in general less spammy: Don't print [PASS] for each successful test, only report failures and progress. --- core/encoding/varint/leb128.odin | 67 + tests/core/Makefile | 8 +- tests/core/build.bat | 3 +- tests/core/compress/test_core_compress.odin | 4 +- tests/core/crypto/test_core_crypto.odin | 1766 ++++++++--------- tests/core/crypto_hash | Bin 0 -> 621648 bytes .../encoding/{ => json}/test_core_json.odin | 36 +- .../encoding/varint/test_core_varint.odin | 81 + tests/core/hash/test_core_hash.odin | 4 +- tests/core/image/test_core_image.odin | 30 +- .../core/math/noise/test_core_math_noise.odin | 30 +- tests/core/odin/test_parser.odin | 45 +- tests/core/strings/test_core_strings.odin | 66 +- 13 files changed, 1138 insertions(+), 1002 deletions(-) create mode 100644 core/encoding/varint/leb128.odin create mode 100644 tests/core/crypto_hash rename tests/core/encoding/{ => json}/test_core_json.odin (64%) create mode 100644 tests/core/encoding/varint/test_core_varint.odin diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin new file mode 100644 index 000000000..0c314b3f8 --- /dev/null +++ b/core/encoding/varint/leb128.odin @@ -0,0 +1,67 @@ +/* + Copyright 2022 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ + +// package varint implements variable length integer encoding and decoding +// using the LEB128 format as used by DWARF debug and other file formats +package varint + +// Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used. +// Returns `size` == 0 for an invalid value, empty slice, or a varint > 16 bytes. +// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file. +decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int) { + more := true + + for v, i in buf { + size = i + 1 + + if size > size_of(u128) { + return + } + + val |= u128(v & 0x7f) << uint(i * 7) + + if v < 128 { + more = false + break + } + } + + // If the buffer runs out before the number ends, return an error. + if more { + return 0, 0 + } + return +} + +// Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used. +// Returns `size` == 0 for an invalid value, empty slice, or a varint > 16 bytes. +// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file. +decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int) { + shift: uint + + if len(buf) == 0 { + return + } + + for v in buf { + size += 1 + if size > size_of(i128) { + return + } + + val |= i128(v & 0x7f) << shift + shift += 7 + + if v < 128 { break } + } + + if buf[size - 1] & 0x40 == 0x40 { + val |= max(i128) << shift + } + return +} \ No newline at end of file diff --git a/tests/core/Makefile b/tests/core/Makefile index 1c2cee6bd..fac5b6203 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,7 +1,7 @@ ODIN=../../odin PYTHON=$(shell which python3) -all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test +all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test download_test_assets: $(PYTHON) download_assets.py @@ -22,4 +22,8 @@ crypto_test: $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check noise_test: - $(ODIN) run math/noise -out=test_noise \ No newline at end of file + $(ODIN) run math/noise -out=test_noise + +encoding_test: + $(ODIN) run encoding/json -out=test_json + $(ODIN) run encoding/varint -out=test_varint \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index 6af39e688..0227ac6bb 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -35,7 +35,8 @@ echo --- echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding %COMMON% +%PATH_TO_ODIN% run encoding/json %COMMON% +%PATH_TO_ODIN% run encoding/varint %COMMON% echo --- echo Running core:math/noise tests diff --git a/tests/core/compress/test_core_compress.odin b/tests/core/compress/test_core_compress.odin index 73c69445a..51952a568 100644 --- a/tests/core/compress/test_core_compress.odin +++ b/tests/core/compress/test_core_compress.odin @@ -30,14 +30,12 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(message) + fmt.printf("[%v] %v\n", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { fmt.printf("[%v] ", loc) diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index f2e5b48d9..636632d71 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -1,15 +1,15 @@ package test_core_crypto /* - Copyright 2021 zhibog - Made available under the BSD-3 license. + Copyright 2021 zhibog + Made available under the BSD-3 license. - List of contributors: - zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Test runner setup. + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Test runner setup. - Tests for the hashing algorithms within the crypto library. - Where possible, the official test vectors are used to validate the implementation. + Tests for the hashing algorithms within the crypto library. + Where possible, the official test vectors are used to validate the implementation. */ import "core:testing" @@ -43,1110 +43,1108 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } main :: proc() { - t := testing.T{} - test_md2(&t) - test_md4(&t) - test_md5(&t) - test_sha1(&t) - test_sha224(&t) - test_sha256(&t) - test_sha384(&t) - test_sha512(&t) - test_sha3_224(&t) - test_sha3_256(&t) - test_sha3_384(&t) - test_sha3_512(&t) - test_shake_128(&t) - test_shake_256(&t) - test_keccak_224(&t) - test_keccak_256(&t) - test_keccak_384(&t) - test_keccak_512(&t) - test_whirlpool(&t) - test_gost(&t) - test_streebog_256(&t) - test_streebog_512(&t) - test_blake_224(&t) - test_blake_256(&t) - test_blake_384(&t) - test_blake_512(&t) - test_blake2b(&t) - test_blake2s(&t) - test_ripemd_128(&t) - test_ripemd_160(&t) - test_ripemd_256(&t) - test_ripemd_320(&t) - test_tiger_128(&t) - test_tiger_160(&t) - test_tiger_192(&t) - test_tiger2_128(&t) - test_tiger2_160(&t) - test_tiger2_192(&t) - test_sm3(&t) - test_jh_224(&t) - test_jh_256(&t) - test_jh_384(&t) - test_jh_512(&t) - test_groestl_224(&t) - test_groestl_256(&t) - test_groestl_384(&t) - test_groestl_512(&t) - test_haval_128(&t) - test_haval_160(&t) - test_haval_192(&t) - test_haval_224(&t) - test_haval_256(&t) - test_siphash_2_4(&t) + t := testing.T{} + test_md2(&t) + test_md4(&t) + test_md5(&t) + test_sha1(&t) + test_sha224(&t) + test_sha256(&t) + test_sha384(&t) + test_sha512(&t) + test_sha3_224(&t) + test_sha3_256(&t) + test_sha3_384(&t) + test_sha3_512(&t) + test_shake_128(&t) + test_shake_256(&t) + test_keccak_224(&t) + test_keccak_256(&t) + test_keccak_384(&t) + test_keccak_512(&t) + test_whirlpool(&t) + test_gost(&t) + test_streebog_256(&t) + test_streebog_512(&t) + test_blake_224(&t) + test_blake_256(&t) + test_blake_384(&t) + test_blake_512(&t) + test_blake2b(&t) + test_blake2s(&t) + test_ripemd_128(&t) + test_ripemd_160(&t) + test_ripemd_256(&t) + test_ripemd_320(&t) + test_tiger_128(&t) + test_tiger_160(&t) + test_tiger_192(&t) + test_tiger2_128(&t) + test_tiger2_160(&t) + test_tiger2_192(&t) + test_sm3(&t) + test_jh_224(&t) + test_jh_256(&t) + test_jh_384(&t) + test_jh_512(&t) + test_groestl_224(&t) + test_groestl_256(&t) + test_groestl_384(&t) + test_groestl_512(&t) + test_haval_128(&t) + test_haval_160(&t) + test_haval_192(&t) + test_haval_224(&t) + test_haval_256(&t) + test_siphash_2_4(&t) - // "modern" crypto tests - test_chacha20(&t) - test_poly1305(&t) - test_chacha20poly1305(&t) - test_x25519(&t) - test_rand_bytes(&t) + // "modern" crypto tests + test_chacha20(&t) + test_poly1305(&t) + test_chacha20poly1305(&t) + test_x25519(&t) + test_rand_bytes(&t) - bench_modern(&t) + bench_modern(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } TestHash :: struct { - hash: string, - str: string, + hash: string, + str: string, } hex_string :: proc(bytes: []byte, allocator := context.temp_allocator) -> string { - lut: [16]byte = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} - buf := make([]byte, len(bytes) * 2, allocator) - for i := 0; i < len(bytes); i += 1 { - buf[i * 2 + 0] = lut[bytes[i] >> 4 & 0xf] - buf[i * 2 + 1] = lut[bytes[i] & 0xf] - } - return string(buf) + lut: [16]byte = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} + buf := make([]byte, len(bytes) * 2, allocator) + for i := 0; i < len(bytes); i += 1 { + buf[i * 2 + 0] = lut[bytes[i] >> 4 & 0xf] + buf[i * 2 + 1] = lut[bytes[i] & 0xf] + } + return string(buf) } @(test) test_md2 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 - test_vectors := [?]TestHash { - TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, - TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, - TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, - TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, - TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md2.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 + test_vectors := [?]TestHash { + TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, + TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, + TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, + TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, + TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md2.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_md4 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 - test_vectors := [?]TestHash { - TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, - TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, - TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, - TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, - TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md4.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 + test_vectors := [?]TestHash { + TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, + TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, + TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, + TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, + TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md4.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_md5 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 - test_vectors := [?]TestHash { - TestHash{"d41d8cd98f00b204e9800998ecf8427e", ""}, - TestHash{"0cc175b9c0f1b6a831c399e269772661", "a"}, - TestHash{"900150983cd24fb0d6963f7d28e17f72", "abc"}, - TestHash{"f96b697d7cb7938d525a2f31aaf161d0", "message digest"}, - TestHash{"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md5.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 + test_vectors := [?]TestHash { + TestHash{"d41d8cd98f00b204e9800998ecf8427e", ""}, + TestHash{"0cc175b9c0f1b6a831c399e269772661", "a"}, + TestHash{"900150983cd24fb0d6963f7d28e17f72", "abc"}, + TestHash{"f96b697d7cb7938d525a2f31aaf161d0", "message digest"}, + TestHash{"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md5.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha1 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, - TestHash{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, - TestHash{"f9537c23893d2014f365adf8ffe33b8eb0297ed1", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"346fb528a24b48f563cb061470bcfd23740427ad", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, - TestHash{"c729c8996ee0a6f74f4f3248e8957edf704fb624", "01234567012345670123456701234567"}, - TestHash{"84983e441c3bd26ebaae4aa1f95129e5e54670f1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha1.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, + TestHash{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, + TestHash{"f9537c23893d2014f365adf8ffe33b8eb0297ed1", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"346fb528a24b48f563cb061470bcfd23740427ad", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, + TestHash{"c729c8996ee0a6f74f4f3248e8957edf704fb624", "01234567012345670123456701234567"}, + TestHash{"84983e441c3bd26ebaae4aa1f95129e5e54670f1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha1.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, - TestHash{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, - TestHash{"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, + TestHash{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, + TestHash{"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, - TestHash{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, - TestHash{"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, + TestHash{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, + TestHash{"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, - TestHash{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, - TestHash{"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, + TestHash{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, + TestHash{"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, - TestHash{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, - TestHash{"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, + TestHash{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, + TestHash{"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""}, - TestHash{"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"}, - TestHash{"10241ac5187380bd501192e4e56b5280908727dd8fe0d10d4e5ad91e", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"fd645fe07d814c397e85e85f92fe58b949f55efa4d3468b2468da45a", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", "a"}, - TestHash{"6961f694b2ff3ed6f0c830d2c66da0c5e7ca9445f7c0dca679171112", "01234567012345670123456701234567"}, - TestHash{"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""}, + TestHash{"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"}, + TestHash{"10241ac5187380bd501192e4e56b5280908727dd8fe0d10d4e5ad91e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"fd645fe07d814c397e85e85f92fe58b949f55efa4d3468b2468da45a", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", "a"}, + TestHash{"6961f694b2ff3ed6f0c830d2c66da0c5e7ca9445f7c0dca679171112", "01234567012345670123456701234567"}, + TestHash{"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", ""}, - TestHash{"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"}, - TestHash{"565ada1ced21278cfaffdde00dea0107964121ac25e4e978abc59412be74550a", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"8cc1709d520f495ce972ece48b0d2e1f74ec80d53bc5c47457142158fae15d98", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "a"}, - TestHash{"e4786de5f88f7d374b7288f225ea9f2f7654da200bab5d417e1fb52d49202767", "01234567012345670123456701234567"}, - TestHash{"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", ""}, + TestHash{"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"}, + TestHash{"565ada1ced21278cfaffdde00dea0107964121ac25e4e978abc59412be74550a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"8cc1709d520f495ce972ece48b0d2e1f74ec80d53bc5c47457142158fae15d98", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "a"}, + TestHash{"e4786de5f88f7d374b7288f225ea9f2f7654da200bab5d417e1fb52d49202767", "01234567012345670123456701234567"}, + TestHash{"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", ""}, - TestHash{"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", "abc"}, - TestHash{"9aa92dbb716ebb573def0d5e3cdd28d6add38ada310b602b8916e690a3257b7144e5ddd3d0dbbc559c48480d34d57a9a", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"77c90323d7392bcdee8a3e7f74f19f47b7d1b1a825ac6a2d8d882a72317879cc26597035f1fc24fe65090b125a691282", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", "a"}, - TestHash{"51072590ad4c51b27ff8265590d74f92de7cc55284168e414ca960087c693285b08a283c6b19d77632994cb9eb93f1be", "01234567012345670123456701234567"}, - TestHash{"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", ""}, + TestHash{"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", "abc"}, + TestHash{"9aa92dbb716ebb573def0d5e3cdd28d6add38ada310b602b8916e690a3257b7144e5ddd3d0dbbc559c48480d34d57a9a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"77c90323d7392bcdee8a3e7f74f19f47b7d1b1a825ac6a2d8d882a72317879cc26597035f1fc24fe65090b125a691282", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", "a"}, + TestHash{"51072590ad4c51b27ff8265590d74f92de7cc55284168e414ca960087c693285b08a283c6b19d77632994cb9eb93f1be", "01234567012345670123456701234567"}, + TestHash{"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", ""}, - TestHash{"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", "abc"}, - TestHash{"9f9a327944a35988d67effc4fa748b3c07744f736ac70b479d8e12a3d10d6884d00a7ef593690305462e9e9030a67c51636fd346fd8fa0ee28a5ac2aee103d2e", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"dbb124a0deda966eb4d199d0844fa0beb0770ea1ccddabcd335a7939a931ac6fb4fa6aebc6573f462ced2e4e7178277803be0d24d8bc2864626d9603109b7891", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", "a"}, - TestHash{"5679e353bc8eeea3e801ca60448b249bcfd3ac4a6c3abe429a807bcbd4c9cd12da87a5a9dc74fde64c0d44718632cae966b078397c6f9ec155c6a238f2347cf1", "01234567012345670123456701234567"}, - TestHash{"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", ""}, + TestHash{"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", "abc"}, + TestHash{"9f9a327944a35988d67effc4fa748b3c07744f736ac70b479d8e12a3d10d6884d00a7ef593690305462e9e9030a67c51636fd346fd8fa0ee28a5ac2aee103d2e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"dbb124a0deda966eb4d199d0844fa0beb0770ea1ccddabcd335a7939a931ac6fb4fa6aebc6573f462ced2e4e7178277803be0d24d8bc2864626d9603109b7891", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", "a"}, + TestHash{"5679e353bc8eeea3e801ca60448b249bcfd3ac4a6c3abe429a807bcbd4c9cd12da87a5a9dc74fde64c0d44718632cae966b078397c6f9ec155c6a238f2347cf1", "01234567012345670123456701234567"}, + TestHash{"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_shake_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"7f9c2ba4e88f827d616045507605853e", ""}, - TestHash{"f4202e3c5852f9182a0430fd8144f0a7", "The quick brown fox jumps over the lazy dog"}, - TestHash{"853f4538be0db9621a6cea659a06c110", "The quick brown fox jumps over the lazy dof"}, - } - for v, _ in test_vectors { - computed := shake.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"7f9c2ba4e88f827d616045507605853e", ""}, + TestHash{"f4202e3c5852f9182a0430fd8144f0a7", "The quick brown fox jumps over the lazy dog"}, + TestHash{"853f4538be0db9621a6cea659a06c110", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_shake_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", ""}, - TestHash{"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca", "The quick brown fox jumps over the lazy dog"}, - TestHash{"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401", "The quick brown fox jumps over the lazy dof"}, - } - for v, _ in test_vectors { - computed := shake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", ""}, + TestHash{"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca", "The quick brown fox jumps over the lazy dog"}, + TestHash{"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", ""}, - TestHash{"c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", ""}, + TestHash{"c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", ""}, - TestHash{"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", ""}, + TestHash{"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", ""}, - TestHash{"f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", ""}, + TestHash{"f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", ""}, - TestHash{"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", ""}, + TestHash{"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_whirlpool :: proc(t: ^testing.T) { - // Test vectors from - // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html - test_vectors := [?]TestHash { - TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, - TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, - TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, - TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, - TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, - TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, - TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, - TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, - TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, - TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, - TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, - TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, - TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, - } - for v, _ in test_vectors { - computed := whirlpool.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html + test_vectors := [?]TestHash { + TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, + TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, + TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, + TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, + TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, + TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, + TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, + TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, + TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, + TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, + TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, + TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, + TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, + } + for v, _ in test_vectors { + computed := whirlpool.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_gost :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, - TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, - TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, - TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, - TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, - TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, - TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, - } - for v, _ in test_vectors { - computed := gost.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, + TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, + TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, + TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, + TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, + TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, + TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, + } + for v, _ in test_vectors { + computed := gost.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_streebog_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, - TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, - TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, + TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, + TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_streebog_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, - TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, - TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, + TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, + TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, - TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, - TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, + TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, + TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, - TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, - TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, + TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, + TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, - TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, - TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, + TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, + TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, - TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, - TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, + TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, + TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake2b :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", ""}, - TestHash{"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := blake2b.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", ""}, + TestHash{"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2b.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake2s :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9", ""}, - TestHash{"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := blake2s.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9", ""}, + TestHash{"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2s.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_128 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, - TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, - TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, - TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, - TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, + TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, + TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, + TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, + TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_160 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, - TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, - TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, - TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, - TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, + TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, + TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, + TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, + TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, - TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, - TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, - TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, - TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, + TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, + TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, + TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, + TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_320 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, - TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, - TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, - TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, - TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_320(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, + TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, + TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, + TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, + TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_320(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b92", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b92", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sm3 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", ""}, - TestHash{"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", "abc"}, - TestHash{"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, - TestHash{"5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea", "The quick brown fox jumps over the lazy dog"}, - TestHash{"ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := sm3.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", ""}, + TestHash{"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", "abc"}, + TestHash{"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, + TestHash{"5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea", "The quick brown fox jumps over the lazy dog"}, + TestHash{"ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := sm3.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, - TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, - TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, + TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, + TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, - TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, - TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, + TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, + TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, - TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, - TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, + TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, + TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, - TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, - TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, + TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, + TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, - TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, - TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, + TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, + TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, - TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, - TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, + TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, + TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, - TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, - TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, + TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, + TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, - TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, - TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, + TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, + TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_128 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, - TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, - TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, - TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, - TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_128_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, - TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_128_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, - TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_128_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, + TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, + TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, + TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, + TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_128_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, + TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_128_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, + TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_128_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_160 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, - TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, - TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, - TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, - TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_160_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, - TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_160_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, - TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_160_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, + TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, + TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, + TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, + TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_160_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, + TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_160_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, + TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_160_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_192 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, - TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_192_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, - TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_192_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, - TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_192_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, + TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_192_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, + TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_192_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, + TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_192_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_224 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, - TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_224_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, - TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_224_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, - TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_224_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, + TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_224_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, + TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_224_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, + TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_224_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_256 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, - TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_256_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, - TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_256_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, - TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_256_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, + TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_256_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, + TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_256_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, + TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_256_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_siphash_2_4 :: proc(t: ^testing.T) { - // Test vectors from - // https://github.com/veorq/SipHash/blob/master/vectors.h - test_vectors := [?]u64 { - 0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d, - 0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137, - 0x93f5f5799a932462, 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7, - 0x751e8fbc860ee5fb, 0x14ea5627c0843d90, 0xf723ca908e7af2ee, 0xa129ca6149be45e5, - 0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, 0xbb6dc91da77961bd, - 0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8, - 0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad, - 0xde4daaaca71dc9a5, 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342, - 0x7127512f72f27cce, 0xa7f32346f95978e3, 0x12e0b01abb051238, 0x15e034d40fa197ae, - 0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, 0x9abfd8766a33735c, - 0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95, - 0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb, - 0xe612a3cb9ecba951, 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a, - 0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, 0x7fa8220ba3b2ecea, 0x245731c13ca42499, - 0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, 0x6606d7e446282b93, - 0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572, - } + // Test vectors from + // https://github.com/veorq/SipHash/blob/master/vectors.h + test_vectors := [?]u64 { + 0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d, + 0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137, + 0x93f5f5799a932462, 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7, + 0x751e8fbc860ee5fb, 0x14ea5627c0843d90, 0xf723ca908e7af2ee, 0xa129ca6149be45e5, + 0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, 0xbb6dc91da77961bd, + 0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8, + 0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad, + 0xde4daaaca71dc9a5, 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342, + 0x7127512f72f27cce, 0xa7f32346f95978e3, 0x12e0b01abb051238, 0x15e034d40fa197ae, + 0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, 0x9abfd8766a33735c, + 0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95, + 0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb, + 0xe612a3cb9ecba951, 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a, + 0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, 0x7fa8220ba3b2ecea, 0x245731c13ca42499, + 0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, 0x6606d7e446282b93, + 0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572, + } - key: [16]byte - for i in 0..<16 { - key[i] = byte(i) - } + key: [16]byte + for i in 0..<16 { + key[i] = byte(i) + } - for i in 0..bW8EMSp7Qw|AOrFSH{)UB5#v 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


Y1k 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

4sXI3yv_?U4zQR*J*Y#sn1T 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

Y4eLEBY*o3 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

LXIOS(Um^YXBIwpbr!=j#TMvbnesmq) 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 E0a8N0TL1t6 From 860583378193efead071332b28be6ac426a99ece Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Mon, 14 Mar 2022 05:23:48 -0700 Subject: [PATCH 0394/1052] core out Makefile, add freebsd building --- Makefile | 81 ++++----------------------------------------------- build_odin.sh | 10 +++++++ 2 files changed, 15 insertions(+), 76 deletions(-) diff --git a/Makefile b/Makefile index bea0569a9..77a30b46a 100644 --- a/Makefile +++ b/Makefile @@ -1,90 +1,19 @@ -GIT_SHA=$(shell git rev-parse --short HEAD) -DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value -LDFLAGS=-pthread -lm -lstdc++ -CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\" -CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\" -CC=clang - -OS=$(shell uname) - -ifeq ($(OS), Darwin) - - ARCH=$(shell uname -m) - LLVM_CONFIG=llvm-config - - # allow for arm only llvm's with version 13 - ifeq ($(ARCH), arm64) - LLVM_VERSIONS = "13.%.%" - else - # allow for x86 / amd64 all llvm versions begining from 11 - LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0" - endif - - LLVM_VERSION_PATTERN_SEPERATOR = )|( - LLVM_VERSION_PATTERNS_ESCAPED_DOT = $(subst .,\.,$(LLVM_VERSIONS)) - LLVM_VERSION_PATTERNS_REPLACE_PERCENT = $(subst %,.*,$(LLVM_VERSION_PATTERNS_ESCAPED_DOT)) - LLVM_VERSION_PATTERN_REMOVE_ELEMENTS = $(subst " ",$(LLVM_VERSION_PATTERN_SEPERATOR),$(LLVM_VERSION_PATTERNS_REPLACE_PERCENT)) - LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR = $(subst ",,$(LLVM_VERSION_PATTERN_REMOVE_ELEMENTS)) - LLVM_VERSION_PATTERN = "^(($(LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR)))" - - ifeq ($(shell $(LLVM_CONFIG) --version | grep -E $(LLVM_VERSION_PATTERN)),) - ifeq ($(ARCH), arm64) - $(error "Requirement: llvm-config must be base version 13 for arm64") - else - $(error "Requirement: llvm-config must be base version greater than 11 for amd64/x86") - endif - endif - - LDFLAGS:=$(LDFLAGS) -liconv -ldl - CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) - LDFLAGS:=$(LDFLAGS) -lLLVM-C -endif -ifeq ($(OS), Linux) - LLVM_CONFIG=llvm-config-11 - ifneq ($(shell which llvm-config-11 2>/dev/null),) - LLVM_CONFIG=llvm-config-11 - else ifneq ($(shell which llvm-config-11-64 2>/dev/null),) - LLVM_CONFIG=llvm-config-11-64 - else - ifeq ($(shell $(LLVM_CONFIG) --version | grep '^11\.'),) - $(error "Requirement: llvm-config must be version 11") - endif - endif - - LDFLAGS:=$(LDFLAGS) -ldl - CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) - LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) -endif -ifeq ($(OS), OpenBSD) - LLVM_CONFIG=/usr/local/bin/llvm-config - - LDFLAGS:=$(LDFLAGS) -liconv - CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) - LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) -endif -ifeq ($(OS), FreeBSD) - LLVM_CONFIG=/usr/local/bin/llvm-config11 - - CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) - LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) -endif - all: debug demo demo: ./odin run examples/demo/demo.odin report: - ./odin report + ./odin.sh report debug: - $(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin + ./build_odin.sh debug release: - $(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 $(LDFLAGS) -o odin + ./build_odin.sh release release_native: - $(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin + ./build_odin.sh release-native nightly: - $(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin + ./build_odin.sh nightly diff --git a/build_odin.sh b/build_odin.sh index a323782a1..dd2725f5d 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -41,6 +41,13 @@ config_darwin() { LDFLAGS="$LDFLAGS -lLLVM-C" } +config_freebsd() { + LLVM_CONFIG=/usr/local/bin/llvm-config11 + + CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" +} + config_openbsd() { LLVM_CONFIG=/usr/local/bin/llvm-config @@ -108,6 +115,9 @@ Darwin) OpenBSD) config_openbsd ;; +FreeBSD) + config_freebsd + ;; *) panic "Platform unsupported!" esac From ffe6d81ecd3169d2cadd112fa878872ed5acd8bf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Mar 2022 12:24:10 +0000 Subject: [PATCH 0395/1052] Remove comments --- examples/demo/demo.odin | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 4d4490446..8c2321dae 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1715,7 +1715,6 @@ deprecated_attribute :: proc() { } range_statements_with_multiple_return_values :: proc() { - // IMPORTANT NOTE(bill, 2019-11-02): This feature is subject to be changed/removed fmt.println("\n#range statements with multiple return values") My_Iterator :: struct { index: int, @@ -2005,7 +2004,6 @@ relative_data_types :: proc() { or_else_operator :: proc() { fmt.println("\n#'or_else'") - // IMPORTANT NOTE: 'or_else' is an experimental feature and subject to change/removal { m: map[string]int i: int @@ -2036,8 +2034,6 @@ or_else_operator :: proc() { or_return_operator :: proc() { fmt.println("\n#'or_return'") - // IMPORTANT NOTE: 'or_return' is an experimental feature and subject to change/removal - // // The concept of 'or_return' will work by popping off the end value in a multiple // valued expression and checking whether it was not 'nil' or 'false', and if so, // set the end return value to value if possible. If the procedure only has one From 34727f99e33c1503a2714653b0186a1a358a4a8c Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Mon, 14 Mar 2022 05:27:08 -0700 Subject: [PATCH 0396/1052] oops, fix report --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77a30b46a..82150c6a2 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ demo: ./odin run examples/demo/demo.odin report: - ./odin.sh report + ./odin report debug: ./build_odin.sh debug From 286549693eb2e7b216effba01d9aa192eab78d12 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Mar 2022 12:28:28 +0000 Subject: [PATCH 0397/1052] Fix `#1609` --- src/check_decl.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 12b0e43cb..d4a320f03 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -440,6 +440,12 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, if (type_expr) { e->type = check_type(ctx, type_expr); + if (are_types_identical(e->type, t_typeid)) { + e->type = nullptr; + e->kind = Entity_TypeName; + check_type_decl(ctx, e, init, named_type); + return; + } } Operand operand = {}; From 6ea9ba16e72df9ae45d6ff77664d4af9a7197852 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Mar 2022 12:38:56 +0000 Subject: [PATCH 0398/1052] Fix #1610 --- src/parser.cpp | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 94a585f35..a435d1317 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1577,7 +1577,7 @@ void assign_removal_flag_to_semicolon(AstFile *f) { } } -void expect_semicolon(AstFile *f, Ast *s) { +void expect_semicolon(AstFile *f) { Token prev_token = {}; if (allow_token(f, Token_Semicolon)) { @@ -1602,17 +1602,17 @@ void expect_semicolon(AstFile *f, Ast *s) { if (f->curr_token.kind == Token_EOF) { return; } - - if (s != nullptr) { - return; - } switch (f->curr_token.kind) { case Token_EOF: return; } - String p = token_to_string(f->curr_token); - syntax_error(prev_token, "Expected ';', got %.*s", LIT(p)); - fix_advance_to_next_stmt(f); + + if (f->curr_token.pos.line == f->prev_token.pos.line) { + String p = token_to_string(f->curr_token); + prev_token.pos = token_pos_end(prev_token); + syntax_error(prev_token, "Expected ';', got %.*s", LIT(p)); + fix_advance_to_next_stmt(f); + } } @@ -3181,7 +3181,7 @@ Ast *parse_foreign_block(AstFile *f, Token token) { Ast *body = ast_block_stmt(f, decls, open, close); Ast *decl = ast_foreign_block_decl(f, token, foreign_library, body, docs); - expect_semicolon(f, decl); + expect_semicolon(f); return decl; } @@ -3227,15 +3227,11 @@ Ast *parse_value_decl(AstFile *f, Array names, CommentGroup *docs) { } if (f->expr_level >= 0) { - Ast *end = nullptr; - if (!is_mutable && values.count > 0) { - end = values[values.count-1]; - } if (f->curr_token.kind == Token_CloseBrace && f->curr_token.pos.line == f->prev_token.pos.line) { } else { - expect_semicolon(f, end); + expect_semicolon(f); } } @@ -4143,11 +4139,7 @@ Ast *parse_return_stmt(AstFile *f) { advance_token(f); } - Ast *end = nullptr; - if (results.count > 0) { - end = results[results.count-1]; - } - expect_semicolon(f, end); + expect_semicolon(f); return ast_return_stmt(f, token, results); } @@ -4398,7 +4390,7 @@ Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) { syntax_error(import_name, "'using import' is not allowed, please use the import name explicitly"); } - expect_semicolon(f, s); + expect_semicolon(f); return s; } @@ -4456,7 +4448,7 @@ Ast *parse_foreign_decl(AstFile *f) { } else { s = ast_foreign_import_decl(f, token, filepaths, lib_name, docs, f->line_comment); } - expect_semicolon(f, s); + expect_semicolon(f); return s; } } @@ -4595,7 +4587,7 @@ Ast *parse_stmt(AstFile *f) { case Token_Not: case Token_And: s = parse_simple_stmt(f, StmtAllowFlag_Label); - expect_semicolon(f, s); + expect_semicolon(f); return s; @@ -4623,7 +4615,7 @@ Ast *parse_stmt(AstFile *f) { label = parse_ident(f); } s = ast_branch_stmt(f, token, label); - expect_semicolon(f, s); + expect_semicolon(f); return s; } @@ -4638,12 +4630,12 @@ Ast *parse_stmt(AstFile *f) { Array list = parse_lhs_expr_list(f); if (list.count == 0) { syntax_error(token, "Illegal use of 'using' statement"); - expect_semicolon(f, nullptr); + expect_semicolon(f); return ast_bad_stmt(f, token, f->curr_token); } if (f->curr_token.kind != Token_Colon) { - expect_semicolon(f, list[list.count-1]); + expect_semicolon(f); return ast_using_stmt(f, token, list); } expect_token_after(f, Token_Colon, "identifier list"); @@ -4700,13 +4692,13 @@ Ast *parse_stmt(AstFile *f) { } else if (tag == "assert" || tag == "panic") { Ast *t = ast_basic_directive(f, hash_token, name); Ast *stmt = ast_expr_stmt(f, parse_call_expr(f, t)); - expect_semicolon(f, stmt); + expect_semicolon(f); return stmt; } else if (name.string == "force_inline" || name.string == "force_no_inline") { Ast *expr = parse_force_inlining_operand(f, name); Ast *stmt = ast_expr_stmt(f, expr); - expect_semicolon(f, stmt); + expect_semicolon(f); return stmt; } else if (tag == "unroll") { return parse_unrolled_for_loop(f, name); @@ -4728,7 +4720,7 @@ Ast *parse_stmt(AstFile *f) { case Token_Semicolon: s = ast_empty_stmt(f, token); - expect_semicolon(f, nullptr); + expect_semicolon(f); return s; } @@ -5586,7 +5578,7 @@ bool parse_file(Parser *p, AstFile *f) { } Ast *pd = ast_package_decl(f, f->package_token, package_name, docs, f->line_comment); - expect_semicolon(f, pd); + expect_semicolon(f); f->pkg_decl = pd; if (f->error_count == 0) { From 1d147ba99339afbef47bf689a0e0d7591a33c633 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Mar 2022 12:44:35 +0000 Subject: [PATCH 0399/1052] Fix typo --- vendor/directx/d3d12/d3d12_constants.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vendor/directx/d3d12/d3d12_constants.odin b/vendor/directx/d3d12/d3d12_constants.odin index 3f83dca6b..a30296cc1 100644 --- a/vendor/directx/d3d12/d3d12_constants.odin +++ b/vendor/directx/d3d12/d3d12_constants.odin @@ -292,7 +292,8 @@ MAX_DEPTH :: 1.0 MAX_LIVE_STATIC_SAMPLERS :: 2032 MAX_MAXANISOTROPY :: 16 MAX_MULTISAMPLE_SAMPLE_COUNT :: 32 -MAX_POSITION_VALUE :: 3.402823466e+34D3D12_MAX_ROOT_COST :: 64 +MAX_POSITION_VALUE :: 3.402823466e+34 +MAX_ROOT_COST :: 64 MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1 :: 1000000 MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2 :: 1000000 MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE :: 2048 From c293e88f2e31bfed896ddba701bdc2629497005a Mon Sep 17 00:00:00 2001 From: CiD- Date: Mon, 14 Mar 2022 13:34:06 -0400 Subject: [PATCH 0400/1052] commit to merge upstream/master --- core/os/os2/file_linux.odin | 43 +++++++------ core/os/os2/path_linux.odin | 72 ++++++++-------------- core/sys/unix/syscalls_linux.odin | 10 +++- tests/core/crypto_hash | Bin 621648 -> 0 bytes tests/core/os2/test_os2.odin | 96 +++++++++++++++++++++++------- 5 files changed, 129 insertions(+), 92 deletions(-) delete mode 100644 tests/core/crypto_hash diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index db0e2efa8..9030d265d 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -11,35 +11,35 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { return Handle(kind) } -__O_RDONLY :: 0o0 -__O_WRONLY :: 0o1 -__O_RDWR :: 0o2 -__O_CREAT :: 0o100 -__O_EXCL :: 0o200 -__O_TRUNC :: 0o1000 -__O_APPEND :: 0o2000 -__O_NONBLOCK :: 0o4000 -__O_LARGEFILE :: 0o100000 -__O_DIRECTORY :: 0o200000 -__O_SYNC :: 0o4010000 -__O_CLOEXEC :: 0o2000000 +_O_RDONLY :: 0o0 +_O_WRONLY :: 0o1 +_O_RDWR :: 0o2 +_O_CREAT :: 0o100 +_O_EXCL :: 0o200 +_O_TRUNC :: 0o1000 +_O_APPEND :: 0o2000 +_O_NONBLOCK :: 0o4000 +_O_LARGEFILE :: 0o100000 +_O_DIRECTORY :: 0o200000 +_O_SYNC :: 0o4010000 +_O_CLOEXEC :: 0o2000000 _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { cstr := strings.clone_to_cstring(name, context.temp_allocator) flags_i: int switch flags & O_RDONLY|O_WRONLY|O_RDWR { - case O_RDONLY: flags_i = __O_RDONLY - case O_WRONLY: flags_i = __O_WRONLY - case O_RDWR: flags_i = __O_RDWR + case O_RDONLY: flags_i = _O_RDONLY + case O_WRONLY: flags_i = _O_WRONLY + case O_RDWR: flags_i = _O_RDWR } - flags_i |= (__O_APPEND * int(.Append in flags)) - flags_i |= (__O_CREAT * int(.Create in flags)) - flags_i |= (__O_EXCL * int(.Excl in flags)) - flags_i |= (__O_SYNC * int(.Sync in flags)) - flags_i |= (__O_TRUNC * int(.Trunc in flags)) - flags_i |= (__O_CLOEXEC * int(.Close_On_Exec in flags)) + flags_i |= (_O_APPEND * int(.Append in flags)) + flags_i |= (_O_CREAT * int(.Create in flags)) + flags_i |= (_O_EXCL * int(.Excl in flags)) + flags_i |= (_O_SYNC * int(.Sync in flags)) + flags_i |= (_O_TRUNC * int(.Trunc in flags)) + flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags)) handle_i := unix.sys_open(cstr, flags_i, int(perm)) if handle_i < 0 { @@ -165,7 +165,6 @@ _remove :: proc(name: string) -> Error { } defer unix.sys_close(handle_i) - /* TODO: THIS WILL NOT WORK */ if _is_dir(Handle(handle_i)) { return _ok_or_error(unix.sys_rmdir(name_cstr)) } diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 31abf5bf8..b474ae207 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -8,7 +8,16 @@ import "core:path/filepath" _Path_Separator :: '/' _Path_List_Separator :: ':' -DIRECTORY_FLAGS :: __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC +_S_IFMT :: 0o170000 // Type of file mask +_S_IFIFO :: 0o010000 // Named pipe (fifo) +_S_IFCHR :: 0o020000 // Character special +_S_IFDIR :: 0o040000 // Directory +_S_IFBLK :: 0o060000 // Block special +_S_IFREG :: 0o100000 // Regular +_S_IFLNK :: 0o120000 // Symbolic link +_S_IFSOCK :: 0o140000 // Socket + +_OPENDIR_FLAGS :: _O_RDONLY|_O_NONBLOCK|_O_DIRECTORY|_O_LARGEFILE|_O_CLOEXEC _is_path_separator :: proc(c: byte) -> bool { return c == '/' @@ -16,42 +25,17 @@ _is_path_separator :: proc(c: byte) -> bool { _mkdir :: proc(path: string, perm: File_Mode) -> Error { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - //TODO file_mode - return _ok_or_error(unix.sys_mkdir(path_cstr)) + perm_i: int + if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { + return .Invalid_Argument + } + + return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777))) } +// TODO _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { - _mkdir_all_stat :: proc(path: string, s: ^OS_Stat, perm: File_Mode) -> Error { - if len(path) == 0 { - return nil - } - - path := path[len(path)-1] == '/' ? path[:len(path)-1] : path - dir, _ := filepath.split(path) - - if len(dir) == 0 { - return _mkdir(path, perm) - } - - dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) - errno := int(unix.get_errno(unix.sys_stat(dir_cstr, s))) - switch errno { - case 0: - if !S_ISDIR(s.mode) { - return .Exist - } - return _mkdir(path, perm) - case ENOENT: - _mkdir_all_stat(dir, s, perm) or_return - return _mkdir(path, perm) - case: - return _get_platform_error(errno) - } - unreachable() - } - // OS_Stat is fat. Make one and re-use it. - s: OS_Stat = --- - return _mkdir_all_stat(path, &s, perm) + return nil } dirent64 :: struct { @@ -62,17 +46,9 @@ dirent64 :: struct { d_name: [1]u8, } -DT_UNKNOWN :: 0 -DT_FIFO :: 1 -DT_CHR :: 2 -DT_DIR :: 4 -DT_BLK :: 6 -DT_REG :: 8 -DT_LNK :: 10 -DT_SOCK :: 12 -DT_WHT :: 14 - _remove_all :: proc(path: string) -> Error { + DT_DIR :: 4 + _remove_all_dir :: proc(dfd: Handle) -> Error { n := 64 buf := make([]u8, n) @@ -114,7 +90,7 @@ _remove_all :: proc(path: string) -> Error { switch d.d_type { case DT_DIR: - handle_i := unix.sys_openat(int(dfd), d_name_cstr, DIRECTORY_FLAGS) + handle_i := unix.sys_openat(int(dfd), d_name_cstr, _OPENDIR_FLAGS) if handle_i < 0 { return _get_platform_error(handle_i) } @@ -135,7 +111,7 @@ _remove_all :: proc(path: string) -> Error { cstr := strings.clone_to_cstring(path, context.temp_allocator) - handle_i := unix.sys_open(cstr, DIRECTORY_FLAGS) + handle_i := unix.sys_open(cstr, _OPENDIR_FLAGS) switch handle_i { case -ENOTDIR: return _ok_or_error(unix.sys_unlink(cstr)) @@ -149,7 +125,7 @@ _remove_all :: proc(path: string) -> Error { return _ok_or_error(unix.sys_rmdir(cstr)) } -_getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { +_getwd :: proc(allocator := context.allocator) -> (string, Error) { // NOTE(tetra): I would use PATH_MAX here, but I was not able to find // an authoritative value for it across all systems. // The largest value I could find was 4096, so might as well use the page size. @@ -170,7 +146,7 @@ _getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { unreachable() } -_setwd :: proc(dir: string) -> (err: Error) { +_setwd :: proc(dir: string) -> Error { dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) return _ok_or_error(unix.sys_chdir(dir_cstr)) } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 889dd3b90..926e69691 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1717,7 +1717,7 @@ sys_rmdir :: proc(path: cstring) -> int { } } -sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int { +sys_mkdir :: proc(path: cstring, mode: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir @@ -1725,6 +1725,14 @@ sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int { } } +sys_mknod :: proc(path: cstring, mode: int, dev: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_mknod, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) + } else { // NOTE: arm64 does not have mknod + return int(intrinsics.syscall(SYS_mknodat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) + } +} + sys_truncate :: proc(path: cstring, length: i64) -> int { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_truncate, uintptr(rawptr(path)), uintptr(length))) diff --git a/tests/core/crypto_hash b/tests/core/crypto_hash deleted file mode 100644 index 18b85a1e8ed34fa9fa8659c7e2841b67c9b476c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 621648 zcmeFa3w)Ht_5Z(tECwarMZuyKiFL7wiY5vQRdgdkpVgr8RbW8EMSp7Qw|AOrFSH{)UB5#v zb!G}3dikXn9x?jR%P$^v`K4FRnmuav*dsSg>Gu#?moJ`h@|mGGw)}DY z>bu^Ua7y>#7ks7Sh>EYCaN!-&TRKRdc=Qp!-<;_FKb7t5N0N5m4)drT&`0cmK4Ay+ zVLPB-484GVAO9QxVSDgVbP*+An{vt2>gr3cm@48GSABhIXv!4Hm@>2af*I9QuDIaRD?`&} zOr0vhS6IPQrd)ExRaZKODWMa}6UR-Ma@ZjyqXT$kA3W@kF{sKo_UE7e(>(Bz#2_eJl?qG!*8VO5r2 z^HKife+shbzR#(wFpDmK^gqQ}bQAAf!PqRii)5xGo<+Aa*;eqf=t1NUg(|Y>yZVj( zH~p^#{%e8%THwDH_^$>2Yk~h-;J+65KVyOQk$pFNwQuKn_2JBvypT6HRo$<*)2n?f zZ@KA1@0eF0_l|sx@5qQaNcrh1%XIbf8Tq{O+OlRkO@5W~+Nx$!CjW%;+M;HfO@5j3 z+7f4)On!;-+Nx$6P5wdUwKdMvnEWr5*OoO?MPB-rypu>ibH0~+#jAa-yW)&QN2>9r z6GC1`TY*VBsx}`V>K(c}_5R){{^ipSiHxX2LMYVOvSPg#^2Y1CdXE;7)a8M#BJ_4m zYg|4pU{-&Z8vZ%&nk3onwY__+*VfbD%W3zX*;+lgPr@!v!pG~Y{hIMpUtw=OYmYO% z6{=tX<@bSOFJE&oJ&;$L@bpu?G^Upc+>;T&(=#z@^A(l)u?OMc|lAM4f6V$k;R z>QBl`f0KemIn`Ht^%JAsQ4^xGF7fJb90o^$SARO`Nd;-0`(QcQ8~3;BaIbTRPojQz3G4R8Ju|B%QQMZ6s9l!l^>&nx>zJ`N zzM(z0dhgQufpFemTE9Dti{NX7FBiUC%KKICUmAI2;50aX4%mGfJaj-P*Q( zF!qBH<<5dqdh5W_FYg+en*e8y=gajs7@z9IcE@Jj*4|zW|JgQOW*9$a)6kivXO(`X z^vu#TPLC9hpK|#wp-9pA^nih(j_|vDYuY9L;Ld-$CK@IlHyh zBt7WkYcEN?xA-=FT&izArRB*nFGHkOmnoyxq^`bNx8=$*3-~s*8YYgTJ9m(UO=UG( zjXkyiWe?i9A)|I~;oH^t95rqxOAVD3^qOvswB35c7OW$&w#b0=@fN$o_F-N_X+9!e zpdfNqDpC~Q`z?gEEP+WaP?RGA;|IqVMd=8y1y;;5s;vMj*g^drFm9=L0aIuK^>&~R z(3s|^$Aj}9ghJbokZ9`Q7a-$Gt-5&0=Lp90esQ&G zIkH|hek}z0`hw^k;X6paZ|!lL3gClU4-DlP73Kk*v&{uMGu{Gpj(Ias?n(%m&2k(W zJajP>ge)boiaiRliVcO4&z>muTg$b=FSGiql)868?doR~xEtxb0yiM%|wPB$wFMMPTd* zzrnXLO-J}upyD2yOeW^)`W+2rrfFsk{QycwxW~j|R+Yv1l=9i5JemIIsMV3&o@ z0&DUObu}>cIRiU^l@SB~B;LUWJ^?J)!@v$;(@+B+6T_YcwgGECZ{Sj3{0j#D9$2}* zfi1wMn1R0o7JSLT2Z3D&8u)8b4>s_AV9LT@07Hiu>d%4kLlYW|_1IZn@w!PvB0X;) zM(l7j;6uPB8@hf9oJ}35w*kLk;q|~m6AXr)G1Yj3B*OC+iESbcGNapY-L80p%4zL2 z5;L}=Y_*f^0G>`_tDOq6)vi@FQ{Ebv3(2F zalpM1*B%Z{unW{!_}uC~KHxhLIKnnN!8TiVtQM%}u~GYR)RYS0po!h#*KP`G?~wyT zF{%RJ9u4P419Jj~cVQ^BvUjnvdsuYZ!&gf#w(Dm*xC@Cs$kC`Y4UTJoo&(B5{%BI; zAt?i4djO!R4*UVI(XKMz45-z>$L%U}K|nnjIM%K*M+MYEVCYQaphE*{KT%IJ)T@Ad z&>ACCaghlGnKcRo@9}M&A-@~wwGJldyko?3#ybi~Q1UMn7h6lM0%}o$`ZTb~8tqA- z^Ny83=QHg<=SjmCbm&$cQ`AijxuWn`tHyW|eW z_+CJ*1J1Tib9F#HA6R1@?4*D?78u7FFFIu9(+SLTqD}eLtv{Oto7U(dxY_ijC zbU>AlR+wow{JL|EL&-l-qtWrO5A?Ykt{qONOnGY}Fs&QM-`jc`85aZH5XgU>^J(l&_#8a+CqQ($o5ULUE{7QHebGhb7`RJpttSR5b%?;emc)(r zPk~Op`r}%?9_VzLE@(A86X-S%#{nzpjYeBOhtNkztTMlI2xUf~j45wDDbV6&%F*r> zTTePUWu%u=MtV7Aq?c1hdWGznM0)8t4_cO9HBK4%9Hb{mtTHPc!u6z#%DHBC2wO^2 z7-2ndkn_N;6zW6NUvD6i@&XTh-4$oa2ddw3>w*4wK)nNMr}e;_fX>&x25ht*I60tB z1U6d_JS?D&08W+%4jwL_L*{o}A=iI=wuWo>qf@55wH(b&JIV2_l+!&o4`-2UvaUA+ z=v?nApc~lB1+D8{3Uqd#26Urw5zx7w`iL&SAh8C%*C9sxi|C?qnwG7+)=7a%nzPi? ze08I(`Re4WKdx2HSEq~SiPKQ?Rp(tKoB(`~-Vj$?fKdKGVs+76GbU)bc7Jp+<*g?N zO1w!q%B5|+Kan_HG*_K2>W|aqWAV@FqWI@*cn&aSJg+c((PXnP4lCB7l>E-dwRVtG zDuz-jM~7Ve%48Et0p6nKy?Fr5S>WUCh^VAtuamJZ@HqZ@%=8;4146(*o-0z$WVt@qjuC*lGP? z?|`}saJq?$`5GG}rS6NmJgsH$~3Wn%i`5k*z0xtF&&Q_@bvMk#-g^ zKG@jy3_%+gPX)ShI2q_h=OmzYgTeXrV5%z?TV*s4h1k_f8CR~h-LXXRyx>|-wQdQh zR{?9RR@$T5U2XovGtAy!u>|%%lGveH2{N5)xb`3#G3Bl21U>$ca(cYM*3;-YA5(mC zz4#r_^-c50_4syR&F;nyHvrv^PwPVqI?KltOHk%T606J$Agj!5DWh_ZEk8KjsJ?EL zTy609^`vN|Sc8iVHerP;wJy9s>Y&4wDgciBJB!b%3c(`4Cw5B3DAwk#XvVk7XUSKsC1cC>4#7d(nMla z`Z35^Un;3QGI->IgE9BuQ9n|``QO(4iE?g#$W>4{^+B5Ag+2_!BL>=)-jURTVUsUA z9W}=~?HEiAsHXv+vtw{W0d)W{ZpT39OeePs*u)s%G9xSCK)EwXY*!U8 z)YZhJqorCXbU}G?q{h-~J&2sKLUO!f4ZXZh^p5bMBn8)bg3`lnWQ%~Ip~e9Y0J<^Q zAL#Tb0JV6^SPtOJeb9AIbf9&YxA zgW0u%Bhn+=yRj6ud8>E(CU2&zT!gwcbY0GrUs*YB{jkdd|3j zs&QOnX7BLZPm$HL_s_PA--g9@@!G@bqGGn!dRbs~t;KjwN_2Z}pKLuxdbmiaIPL6v zx!_Lip9@D0GAfPykrl0YYgN)b)`xAh{72(wm07Z>62)+DI2GTn>FmR5u9Hqad#$Wx=K!e?XC4F#%y}d{?IuzwZ~BV zdb04T%-#Q(1$0N!=Ygut#5rgZK3J4r{kmja$G1L=@|Tfu4Oy?X3W5t+KZk&+?-iZs zLDFa)?`)ux{S{!By+3w3(2a5h(2e~hp!0|mf$|gd_-(m~Ky^?Mog}g5`6fso4#-kT zigWua)`Ijw>!YcdRc`d?2+x2)SHQX4@~W+z?yLL;$hCSLm0fw4U!!nn z!nS(in?~JJNUXY(Kt}!_bkU#B!CrDynYdcDteT?a_?ZxJh-%S0!e^7Xz;is%x!K`B zf4u}cm&_L|Fjn7;Hg4DZCU7fG&B7i&3l4;yOJY^}D#)~JuFRsuAbNDFt8gC%xt~}A0`wsH7@?8?!$^ysh{oXTmLW8~J@OsPDMB>6y z1F-olqyKdQ^%CIZ(;14Q@ii&U>2L5Yof8eScJY#9YRS@C4~cH&b3n`_q{gUUQjvmR zlZc)Bh#-BuhM7EUHO7^x%xhDjYTc1Y_sn2%_yT zlGsiafNZC(<~hnSrhMsqD9)wIDW{i{Y`uOYFWNDb9`2Ti{4_q&s4stWcHRJV+N}q= zG3f?sqzDsZimlKwBvzTjK~|Y6DWh`Q)-zPta<(Z%`39e>BYc^I6i+d*BYbL5dNj}- z{fdCi*1~%R)c(MY*22=u@%|0C!dm!=fcglqVzTMv-2qiGXpxz;!(|(^+l9pTCJfRi z(Qu7NZ(OP#(9;8I9GGH2bv|tdqv!8PYifVZv|!h=D~6^p zLSn1tJIk|vA$W`{-vw$K!@!yg>}PwU=kGeL5j9Gp;+s<@7~ia*5cV@ktmM-{`tS^V zgr(V)Plaka(h)ul*loof8&D4h_Lwl1Kh#S8E)*pHki<&J1L#I(3b5uN)9-SiyDmQtSi#uhCBFnB=+`7xmj^(m z*@i0VqH>zv%|3k`CDDf(?@*u*qxOn{9pOI*q?HE3_AtOLtUm)5Uu<+~45&8(d#%%7 z7EsRu=ACbN%K~Z%Fm$$|?i)~d6ZH%eR{mUShHe%V+P*8&_uR#MyZ1eJ@d8lKU9^XD zhx332e7C^op5*vz!1oyN4sKqwhyS*Z<+~6*cP4A4&~@v6;0K29VaIn|z;`c&?#Yk^ zz|r;+YEi)OU8ru@YJo>thG?MCT&S`%dd>h&unZeN$AgDaV~J|0ZWnt2u-r1d2!qr0 zBB)N+3ZQgF*yCcb&v2gxl^%+EEO3RrCU}3qPzu#WqeFnJEW@{hCW@iDCWZrD6W0X{ zBLWG7fLpAD3xXy-2i57YWpJMkUcm4XRHwsRK&Qi@Fu3*TZKzJdbHE&XMBOuBSQ{{` z0PbcPKFaSK{3im2M}R{u!)q`&OD=}$y7_aU>*gQDU@f^QknkO#EXjeQY43ru?R{!# zm>IK13SDPz1kR?VNa4r>j*|C|eB|?b{OdX@sn(6u3hixbT^7_j3wRT?cqPd3HE@EF zpYVJ($j;!ad39*aJhI->A5-L_$s-V$(k-HMy_clM#`(*DdIlTnC8F+bTD=(PqR9n7 z=d9-gUF10jsCdMl=uRNDe@bF?`3cDB@)dMZIZgjfY)gL@sPvc!tmh;yvi%t7Mwv*HnM#;pz8eG-#%Ga6;RIu7TU;mVn96-7`Krv7ElKR z3l!M~55EOSOW!21it3#1EIXOrnDV9fqK_M8*^=%(XzOV_JMAcIJcn7mHJ(j}7#nIl zon4 zj(Re17i(JS<*0=~&zg2VTUru5=@f<({ugja8!g?vImv4O%4UgzpM;*}-y@5oBaNv5N5z6}s0|uHsjs&dv zm0Em}Z++lf3v>%a#jh>oa>;N0F1APbHZofEJUyTOUc)u!`UeH=;rsZOh+!Yv-Heg{ zfRWF)KIO^rF9G3sjl_AuGr*cnM#*Dn++2Gt8b6|06-V-|78A9P59FP=FOp^N`RW+6 zfq9JZPVSx~O|ISM?zK6sU6lR8=Co#!yU*sHw7Cat?kRF8w3$xa?CkUX#P%dF4cHAwQ5D^2**jzzR@T#9_W;iK27Du zqmKkSeMSciB|xY9Awcy=`dkS{=u8r6+Y!DRWc6uw`g{!v`aEelpCQqQO22ZD>G3lI zIgtgVTMdNm8i0}55x!WosYc6F1L`rrL3TbL6i|l&tL%IZ2h#j{<}>b}e=WB{JHj{fExts<*DEpa4P?>ydP7CMG(Z!YXMWEv|H^>Ih#Oa9<3!%DL#&VYo-7E%!Sl@`sM_x`2Bs+$u-* z*(K`V&}Hm5$$ib{9<#YoX4(yHCx_|AKV_*$T56|qMI)cH$ty|*kKcnpgNlkb)^+v- znGV%1pT>jKu6&*=j}(q9GSWug^{%?Vh;L)xrPrV`AFjcV`3Xd14tdXBD`GJIvQf-y z`L=^`jZVyK$hL={<6GRv_t*}!hI;&_HZ%Zy1eisQm4>OROERqiLuSZ^^#keJ8tc%w31eO~xEWYaQWIzD=d2 zx6lxuT(99KF4vDAO@Tb+wL$WYQ4g#a_iy<&+{rNy0rAkO5;l0$0oFqgBC*O8IS=(} zpVAtp@<`#B6Abs5$;d{h^GK}spW|!6`U$)hJrH`e6{@))vvh>3eWAoLV4c_sNA
Y1k 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

# Build package in odin build filename.odin -file # Build single-file package, must contain entry point. Flags -file Tells `odin build` to treat the given file as a self-contained package. This means that `/a.odin` won't have access to `/b.odin`'s contents. ``` ``` W:\Odin>odin run examples\demo\demo.odin ERROR: `odin run` takes a package as its first argument. Did you mean `odin run examples\demo\demo.odin -file`? The `-file` flag tells it to treat a file as a self-contained package. ``` --- build_odin.sh | 2 +- src/build_settings.cpp | 23 ++++- src/main.cpp | 201 ++++++++++++++++++++++++----------------- 3 files changed, 141 insertions(+), 85 deletions(-) diff --git a/build_odin.sh b/build_odin.sh index dd2725f5d..aef3f2836 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -102,7 +102,7 @@ build_odin() { } run_demo() { - ./odin run examples/demo/demo.odin + ./odin run examples/demo/demo.odin -file } case $OS in diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b9875e43f..2f3eb03a5 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -598,7 +598,6 @@ bool allow_check_foreign_filepath(void) { return true; } - // TODO(bill): OS dependent versions for the BuildContext // join_path // is_dir @@ -606,6 +605,28 @@ bool allow_check_foreign_filepath(void) { // is_abs_path // has_subdir +enum TargetFileValidity : u8 { + TargetFileValidity_Invalid, + + TargetFileValidity_Writable_File, + TargetFileValidity_No_Write_Permission, + TargetFileValidity_Directory, + + TargetTargetFileValidity_COUNT, +}; + +TargetFileValidity set_output_filename(void) { + // Assembles the output filename from build_context information. + // Returns `true` if it doesn't exist or is a file. + // Returns `false` if a directory or write-protected file. + + + + + return TargetFileValidity_Writable_File; +} + + String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; diff --git a/src/main.cpp b/src/main.cpp index 52177e326..7dd82f173 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -585,14 +585,14 @@ void usage(String argv0) { print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(0, "Commands:"); - print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable."); + print_usage_line(1, "build compile directory of .odin files, as an executable."); print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); - print_usage_line(1, "check parse, and type check an .odin file, or directory of .odin files"); + print_usage_line(1, "check parse, and type check a directory of .odin files"); print_usage_line(1, "query parse, type check, and output a .json file containing information about the program"); print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program"); print_usage_line(1, "test build ands runs procedures with the attribute @(test) in the initial package"); - print_usage_line(1, "doc generate documentation .odin file, or directory of .odin files"); + print_usage_line(1, "doc generate documentation on a directory of .odin files"); print_usage_line(1, "version print version"); print_usage_line(1, "report print information useful to reporting a bug"); print_usage_line(0, ""); @@ -604,6 +604,7 @@ enum BuildFlagKind { BuildFlag_Invalid, BuildFlag_Help, + BuildFlag_SingleFile, BuildFlag_OutFile, BuildFlag_OptimizationLevel, @@ -762,79 +763,80 @@ ExactValue build_param_to_exact_value(String name, String param) { bool parse_build_flags(Array args) { auto build_flags = array_make(heap_allocator(), 0, BuildFlag_COUNT); - add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all); - add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build &~ Command_test); - add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer, Command__does_build); - add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("O"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_ExportTimings, str_lit("export-timings"), BuildFlagParam_String, Command__does_check); - add_flag(&build_flags, BuildFlag_ExportTimingsFile, str_lit("export-timings-file"), BuildFlagParam_String, Command__does_check); - add_flag(&build_flags, BuildFlag_ShowUnused, str_lit("show-unused"), BuildFlagParam_None, Command_check); - add_flag(&build_flags, BuildFlag_ShowUnusedWithLocation, str_lit("show-unused-with-location"), BuildFlagParam_None, Command_check); - add_flag(&build_flags, BuildFlag_ShowSystemCalls, str_lit("show-system-calls"), BuildFlagParam_None, Command_all); - add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer, Command_all); - add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None, Command__does_build|Command_strip_semicolon); - add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check); - add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true); - add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message - add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check); - add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); - add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_UseSeparateModules,str_lit("use-separate-modules"),BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_ThreadedChecker, str_lit("threaded-checker"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); - add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check); + add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build &~ Command_test); + add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer, Command__does_build); + add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("O"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ExportTimings, str_lit("export-timings"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_ExportTimingsFile, str_lit("export-timings-file"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_ShowUnused, str_lit("show-unused"), BuildFlagParam_None, Command_check); + add_flag(&build_flags, BuildFlag_ShowUnusedWithLocation, str_lit("show-unused-with-location"), BuildFlagParam_None, Command_check); + add_flag(&build_flags, BuildFlag_ShowSystemCalls, str_lit("show-system-calls"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer, Command_all); + add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None, Command__does_build | Command_strip_semicolon); + add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true); + add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message + add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); + add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_ThreadedChecker, str_lit("threaded-checker"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); + add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); - add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_InsertSemicolon, str_lit("insert-semicolon"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_InsertSemicolon, str_lit("insert-semicolon"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query); - add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query); - add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query); + add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query); + add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query); + add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query); - add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc); - add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc); - add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc); + add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc); + add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc); + add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc); - add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); - add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all); - add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all); - add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); #if defined(GB_SYSTEM_WINDOWS) - add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_Subsystem, str_lit("subsystem"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_Subsystem, str_lit("subsystem"), BuildFlagParam_String, Command__does_build); #endif @@ -1879,32 +1881,46 @@ void remove_temp_files(lbGenerator *gen) { void print_show_help(String const arg0, String const &command) { print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0)); - print_usage_line(0, "Usage"); + print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command)); print_usage_line(0, ""); if (command == "build") { - print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable."); - print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); - } else if (command == "run") { - print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); - print_usage_line(1, " append an empty flag and then the args, '-- ', to specify args for the output."); - } else if (command == "check") { - print_usage_line(1, "check parse and type check .odin file(s)"); - } else if (command == "test") { - print_usage_line(1, "test build ands runs procedures with the attribute @(test) in the initial package"); - } else if (command == "query") { - print_usage_line(1, "query [experimental] parse, type check, and output a .json file containing information about the program"); - } else if (command == "doc") { - print_usage_line(1, "doc generate documentation from a .odin file, or directory of .odin files"); + print_usage_line(1, "build Compile directory of .odin files as an executable."); + print_usage_line(2, "One must contain the program's entry point, all must be in the same package."); + print_usage_line(2, "Use `-file` to build a single file instead."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin doc core/path"); - print_usage_line(3, "odin doc core/path core/path/filepath"); + print_usage_line(3, "odin build . # Build package in current directory"); + print_usage_line(3, "odin build # Build package in "); + print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point."); + } else if (command == "run") { + print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable."); + print_usage_line(2, "Append an empty flag and then the args, '-- ', to specify args for the output."); + print_usage_line(2, "Examples:"); + print_usage_line(3, "odin run . # Build and run package in current directory"); + print_usage_line(3, "odin run # Build and run package in "); + print_usage_line(3, "odin run filename.odin -file # Build and run single-file package, must contain entry point."); + } else if (command == "check") { + print_usage_line(1, "check Parse and type check directory of .odin files"); + print_usage_line(2, "Examples:"); + print_usage_line(3, "odin check . # Type check package in current directory"); + print_usage_line(3, "odin check # Type check package in "); + print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point."); + } else if (command == "test") { + print_usage_line(1, "test Build ands runs procedures with the attribute @(test) in the initial package"); + } else if (command == "query") { + print_usage_line(1, "query [experimental] Parse, type check, and output a .json file containing information about the program"); + } else if (command == "doc") { + print_usage_line(1, "doc generate documentation from a directory of .odin files"); + print_usage_line(2, "Examples:"); + print_usage_line(3, "odin doc . # Generate documentation on package in current directory"); + print_usage_line(3, "odin doc # Generate documentation on package in "); + print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package."); } else if (command == "version") { print_usage_line(1, "version print version"); } else if (command == "strip-semicolon") { print_usage_line(1, "strip-semicolon"); - print_usage_line(2, "parse and type check .odin file(s) and then remove unneeded semicolons from the entire project"); + print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project"); } bool doc = command == "doc"; @@ -1919,6 +1935,13 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "Flags"); print_usage_line(0, ""); + if (check) { + print_usage_line(1, "-file"); + print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command)); + print_usage_line(2, "This means that `/a.odin` won't have access to `/b.odin`'s contents."); + print_usage_line(0, ""); + } + if (doc) { print_usage_line(1, "-short"); print_usage_line(2, "Show shortened documentation for the packages"); @@ -2487,8 +2510,6 @@ int strip_semicolons(Parser *parser) { return cast(int)failed; } - - int main(int arg_count, char const **arg_ptr) { if (arg_count < 2) { usage(make_string_c(arg_ptr[0])); @@ -2557,6 +2578,7 @@ int main(int arg_count, char const **arg_ptr) { args = array_slice(args, 0, last_non_run_arg); run_args_string = string_join_and_quote(heap_allocator(), run_args); + init_filename = args[2]; run_output = true; @@ -2649,6 +2671,19 @@ int main(int arg_count, char const **arg_ptr) { build_context.show_help = true; } + if (init_filename.len > 0 && !build_context.show_help) { + // The command must be build, run, test, check, or another that takes a directory or filename. + if (!path_is_directory(init_filename)) { + // Input package is a filename. We allow this only if `-file` was given, otherwise we exit with an error message. + if (!(args.count > 3 && args[3] == "-file")) { + gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command)); + gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename)); + gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n"); + return 1; + } + } + } + build_context.command = command; if (!parse_build_flags(args)) { From bb9165edd25aa4d8c5df514764a281a14ac79316 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 5 Apr 2022 20:45:00 +0200 Subject: [PATCH 0511/1052] Add -help to CI tests. --- src/main.cpp | 12 ++++++++++-- tests/core/Makefile | 18 +++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7dd82f173..fc8792ceb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2550,6 +2550,7 @@ int main(int arg_count, char const **arg_ptr) { String command = args[1]; String init_filename = {}; String run_args_string = {}; + isize last_non_run_arg = args.count; bool run_output = false; if (command == "run" || command == "test") { @@ -2565,7 +2566,6 @@ int main(int arg_count, char const **arg_ptr) { Array run_args = array_make(heap_allocator(), 0, arg_count); defer (array_free(&run_args)); - isize last_non_run_arg = args.count; for_array(i, args) { if (args[i] == "--") { last_non_run_arg = i; @@ -2675,7 +2675,15 @@ int main(int arg_count, char const **arg_ptr) { // The command must be build, run, test, check, or another that takes a directory or filename. if (!path_is_directory(init_filename)) { // Input package is a filename. We allow this only if `-file` was given, otherwise we exit with an error message. - if (!(args.count > 3 && args[3] == "-file")) { + bool single_file_package = false; + for_array(i, args) { + if (i >= 3 && i <= last_non_run_arg && args[i] == "-file") { + single_file_package = true; + break; + } + } + + if (!single_file_package) { gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command)); gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename)); gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n"); diff --git a/tests/core/Makefile b/tests/core/Makefile index 652ebb151..6a92b4efb 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -8,19 +8,19 @@ download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image/test_core_image.odin + $(ODIN) run image/test_core_image.odin -file compress_test: - $(ODIN) run compress/test_core_compress.odin + $(ODIN) run compress/test_core_compress.odin -file strings_test: - $(ODIN) run strings/test_core_strings.odin + $(ODIN) run strings/test_core_strings.odin -file hash_test: $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check crypto_test: - $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check + $(ODIN) run crypto -out=test_crypto_hash -o:speed -no-bounds-check noise_test: $(ODIN) run math/noise -out=test_noise @@ -31,16 +31,16 @@ encoding_test: $(ODIN) run encoding/varint -out=test_varint math_test: - $(ODIN) run math/test_core_math.odin -out=test_core_math -collection:tests=.. + $(ODIN) run math/test_core_math.odin -out=test_core_math -file -collection:tests=.. linalg_glsl_math_test: - $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -out=test_linalg_glsl_math -collection:tests=.. + $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=test_linalg_glsl_math -collection:tests=.. filepath_test: - $(ODIN) run path/filepath/test_core_filepath.odin -out=test_core_filepath -collection:tests=.. + $(ODIN) run path/filepath/test_core_filepath.odin -file -out=test_core_filepath -collection:tests=.. reflect_test: - $(ODIN) run reflect/test_core_reflect.odin -out=test_core_reflect -collection:tests=.. + $(ODIN) run reflect/test_core_reflect.odin -file -out=test_core_reflect -collection:tests=.. os_exit_test: - $(ODIN) run os/test_core_os_exit.odin -out=test_core_os_exit && exit 1 || exit 0 + $(ODIN) run os/test_core_os_exit.odin -file -out=test_core_os_exit && exit 1 || exit 0 From 767ed21bfed250bfeef523ae62cbd9a06bb4c025 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 5 Apr 2022 20:47:37 +0200 Subject: [PATCH 0512/1052] -file for tests\issues. --- tests/issues/run.bat | 4 ++-- tests/issues/run.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/issues/run.bat b/tests/issues/run.bat index b145dda48..a652d9694 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -6,10 +6,10 @@ set COMMON=-collection:tests=tests -out:tests\issues\build\test_issue @echo on -.\odin build tests\issues\test_issue_829.odin %COMMON% +.\odin build tests\issues\test_issue_829.odin %COMMON% -file tests\issues\build\test_issue -.\odin build tests\issues\test_issue_1592.odin %COMMON% +.\odin build tests\issues\test_issue_1592.odin %COMMON% -file tests\issues\build\test_issue @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index c4f978771..117a9a5f1 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -7,10 +7,10 @@ COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" set -x -./odin build tests/issues/test_issue_829.odin $COMMON +./odin build tests/issues/test_issue_829.odin $COMMON -file tests/issues/build/test_issue -./odin build tests/issues/test_issue_1592.odin $COMMON +./odin build tests/issues/test_issue_1592.odin $COMMON -file tests/issues/build/test_issue set +x From 426a6a95284688b992952201961244b7f4502ef4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 5 Apr 2022 21:10:24 +0100 Subject: [PATCH 0513/1052] Update nightly.yml to build the directory --- .github/workflows/nightly.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index dac888ce6..3c4185830 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -19,7 +19,7 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin run examples/demo/demo.odin + odin run examples/demo - name: Copy artifacts run: | rm bin/llvm/windows/LLVM-C.lib @@ -45,7 +45,7 @@ jobs: - name: build odin run: make nightly - name: Odin run - run: ./odin run examples/demo/demo.odin + run: ./odin run examples/demo - name: Copy artifacts run: | mkdir dist @@ -72,7 +72,7 @@ jobs: - name: build odin run: make nightly - name: Odin run - run: ./odin run examples/demo/demo.odin + run: ./odin run examples/demo - name: Copy artifacts run: | mkdir dist From aadb4db2113896011a9cbc661c2ccde893300cb1 Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 6 Apr 2022 10:53:46 -0400 Subject: [PATCH 0514/1052] avoid temp_allocator on stupidly long paths --- core/os/os2/file_linux.odin | 86 +++++++++++++++++++++++++++++++------ core/os/os2/path_linux.odin | 37 +++++++++++++--- core/os/os2/stat_linux.odin | 20 ++++++--- 3 files changed, 117 insertions(+), 26 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 89075e00c..998fe8617 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -29,8 +29,13 @@ _O_PATH :: 0o10000000 _AT_FDCWD :: -100 +_CSTRING_NAME_HEAP_THRESHOLD :: 512 + _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { - cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } flags_i: int switch flags & O_RDONLY|O_WRONLY|O_RDWR { @@ -46,7 +51,7 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Erro flags_i |= (_O_TRUNC * int(.Trunc in flags)) flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags)) - handle_i := unix.sys_open(cstr, flags_i, int(perm)) + handle_i := unix.sys_open(name_cstr, flags_i, int(perm)) if handle_i < 0 { return INVALID_HANDLE, _get_platform_error(handle_i) } @@ -174,7 +179,10 @@ _truncate :: proc(fd: Handle, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } handle_i := unix.sys_open(name_cstr, int(File_Flags.Read)) if handle_i < 0 { @@ -189,20 +197,41 @@ _remove :: proc(name: string) -> Error { } _rename :: proc(old_name, new_name: string) -> Error { - old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) - new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) + old_name_cstr, old_allocated := _name_to_cstring(old_name) + new_name_cstr, new_allocated := _name_to_cstring(new_name) + defer if old_allocated { + delete(old_name_cstr) + } + defer if new_allocated { + delete(new_name_cstr) + } + return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr)) } _link :: proc(old_name, new_name: string) -> Error { - old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) - new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) + old_name_cstr, old_allocated := _name_to_cstring(old_name) + new_name_cstr, new_allocated := _name_to_cstring(new_name) + defer if old_allocated { + delete(old_name_cstr) + } + defer if new_allocated { + delete(new_name_cstr) + } + return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr)) } _symlink :: proc(old_name, new_name: string) -> Error { - old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) - new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) + old_name_cstr, old_allocated := _name_to_cstring(old_name) + new_name_cstr, new_allocated := _name_to_cstring(new_name) + defer if old_allocated { + delete(old_name_cstr) + } + defer if new_allocated { + delete(new_name_cstr) + } + return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr)) } @@ -225,12 +254,18 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator := context.allocator) -> ( } _read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) { - name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } return _read_link_cstr(name_cstr, allocator) } _unlink :: proc(name: string) -> Error { - name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } return _ok_or_error(unix.sys_unlink(name_cstr)) } @@ -247,12 +282,18 @@ _chown :: proc(fd: Handle, uid, gid: int) -> Error { } _lchown :: proc(name: string, uid, gid: int) -> Error { - name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid)) } _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { - name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } times := [2]Unix_File_Time { { atime._nsec, 0 }, { mtime._nsec, 0 }, @@ -261,7 +302,10 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { } _exists :: proc(name: string) -> bool { - name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } return unix.sys_access(name_cstr, F_OK) == 0 } @@ -282,3 +326,17 @@ _is_dir :: proc(fd: Handle) -> bool { } return S_ISDIR(s.mode) } + +// Ideally we want to use the temp_allocator. PATH_MAX on Linux is commonly +// defined as 512, however, it is well known that paths can exceed that limit. +// So, in theory you could have a path larger than the entire temp_allocator's +// buffer. Therefor any large paths will use context.allocator. +_name_to_cstring :: proc(path: string) -> (cpath: cstring, allocated: bool) { + if len(path) > _CSTRING_NAME_HEAP_THRESHOLD { + cpath = strings.clone_to_cstring(path) + allocated = true + return + } + cpath = strings.clone_to_cstring(path, context.temp_allocator) + return +} diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 889f7e447..5dadb7608 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -24,11 +24,16 @@ _is_path_separator :: proc(c: byte) -> bool { } _mkdir :: proc(path: string, perm: File_Mode) -> Error { + // NOTE: These modes would require sys_mknod, however, that would require + // additional arguments to this function. if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { return .Invalid_Argument } - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + path_cstr, allocated := _name_to_cstring(path) + defer if allocated { + delete(path_cstr) + } return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777))) } @@ -69,7 +74,19 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { } // need something we can edit, and use to generate cstrings - path_bytes := make([]u8, len(path) + 1, context.temp_allocator) + allocated: bool + path_bytes: []u8 + if len(path) > _CSTRING_NAME_HEAP_THRESHOLD { + allocated = true + path_bytes = make([]u8, len(path) + 1) + } else { + path_bytes = make([]u8, len(path) + 1, context.temp_allocator) + } + defer if allocated { + delete(path_bytes) + } + + // NULL terminate the byte slice to make it a valid cstring copy(path_bytes, path) path_bytes[len(path)] = 0 @@ -165,12 +182,15 @@ _remove_all :: proc(path: string) -> Error { return nil } - cstr := strings.clone_to_cstring(path, context.temp_allocator) + path_cstr, allocated := _name_to_cstring(path) + defer if allocated { + delete(path_cstr) + } - handle_i := unix.sys_open(cstr, _OPENDIR_FLAGS) + handle_i := unix.sys_open(path_cstr, _OPENDIR_FLAGS) switch handle_i { case -ENOTDIR: - return _ok_or_error(unix.sys_unlink(cstr)) + return _ok_or_error(unix.sys_unlink(path_cstr)) case -4096..<0: return _get_platform_error(handle_i) } @@ -178,7 +198,7 @@ _remove_all :: proc(path: string) -> Error { fd := Handle(handle_i) defer close(fd) _remove_all_dir(fd) or_return - return _ok_or_error(unix.sys_rmdir(cstr)) + return _ok_or_error(unix.sys_rmdir(path_cstr)) } _getwd :: proc(allocator := context.allocator) -> (string, Error) { @@ -203,6 +223,9 @@ _getwd :: proc(allocator := context.allocator) -> (string, Error) { } _setwd :: proc(dir: string) -> Error { - dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) + dir_cstr, allocated := _name_to_cstring(dir) + defer if allocated { + delete(dir_cstr) + } return _ok_or_error(unix.sys_chdir(dir_cstr)) } diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index d22f32d65..9bfd900b6 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -108,8 +108,12 @@ _fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) // NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath _stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { - cstr := strings.clone_to_cstring(name, context.temp_allocator) - fd := unix.sys_open(cstr, _O_RDONLY) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } + + fd := unix.sys_open(name_cstr, _O_RDONLY) if fd < 0 { return {}, _get_platform_error(fd) } @@ -118,8 +122,11 @@ _stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error } _lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { - cstr := strings.clone_to_cstring(name, context.temp_allocator) - fd := unix.sys_open(cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } + fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW) if fd < 0 { return {}, _get_platform_error(fd) } @@ -132,7 +139,10 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool { } _stat_internal :: proc(name: string) -> (s: OS_Stat, res: int) { - name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + name_cstr, allocated := _name_to_cstring(name) + defer if allocated { + delete(name_cstr) + } res = unix.sys_stat(name_cstr, &s) return } From 698fcb7813dd391de76a5663ee64c48ce4f7d067 Mon Sep 17 00:00:00 2001 From: hikari Date: Wed, 6 Apr 2022 18:44:43 +0300 Subject: [PATCH 0515/1052] mem: replace size procedures with constants --- core/mem/mem.odin | 11 ++++++----- core/odin/printer/printer.odin | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 817c0ea5f..a5252d950 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -3,6 +3,12 @@ package mem import "core:runtime" import "core:intrinsics" +Byte :: 1 +Kilobyte :: 1024 * Byte +Megabyte :: 1024 * Kilobyte +Gigabyte :: 1024 * Megabyte +Terabyte :: 1024 * Gigabyte + set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr { return runtime.memset(data, i32(value), len) } @@ -192,11 +198,6 @@ any_to_bytes :: proc "contextless" (val: any) -> []byte { } -kilobytes :: proc "contextless" (x: int) -> int { return (x) * 1024 } -megabytes :: proc "contextless" (x: int) -> int { return kilobytes(x) * 1024 } -gigabytes :: proc "contextless" (x: int) -> int { return megabytes(x) * 1024 } -terabytes :: proc "contextless" (x: int) -> int { return gigabytes(x) * 1024 } - is_power_of_two :: proc "contextless" (x: uintptr) -> bool { if x <= 0 { return false diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index abda44fa2..807cc99bd 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -151,7 +151,7 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { fix_lines(p) - builder := strings.make_builder(0, mem.megabytes(5), p.allocator) + builder := strings.make_builder(0, 5 * mem.Megabyte, p.allocator) last_line := 0 From ad90f416a59be22dbf8fca89890a70407dc5826c Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 7 Apr 2022 12:24:53 +0300 Subject: [PATCH 0516/1052] runtime: fix typo --- core/runtime/core.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index a5a190a9c..4ab21d8cf 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -565,7 +565,7 @@ __init_context :: proc "contextless" (c: ^Context) { return } - // NOTE(bill): Do not initialize these procedures with a call as they are not defined with the "contexless" calling convention + // NOTE(bill): Do not initialize these procedures with a call as they are not defined with the "contextless" calling convention c.allocator.procedure = default_allocator_proc c.allocator.data = nil From 8a8b5c753fc39101583a5817d8552ab8a6197b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Thu, 7 Apr 2022 16:48:34 +0200 Subject: [PATCH 0517/1052] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 166112c43..9e46f80d0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@
-
+ From c4a7739d13d386743a53ebe3371e8061310ea2cb Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 7 Apr 2022 19:28:24 +0300 Subject: [PATCH 0518/1052] sys/windows: add a couple macros --- core/sys/windows/util.odin | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index d464007d3..f448f6bc5 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -15,6 +15,14 @@ HIWORD :: #force_inline proc "contextless" (x: DWORD) -> WORD { return WORD(x >> 16) } +GET_X_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int { + return cast(c_int)cast(c_short)LOWORD(cast(DWORD)lp) +} + +GET_Y_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int { + return cast(c_int)cast(c_short)HIWORD(cast(DWORD)lp) +} + utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 { if len(s) < 1 { return nil From f2f1330238d46bb6e80eac33da99604ac2f99a52 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 8 Apr 2022 10:29:23 +0100 Subject: [PATCH 0519/1052] Add https://github.com/odin-lang/examples --- examples/demo/demo.odin | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index b3ce3ade9..b03345849 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -33,6 +33,10 @@ import "core:math/big" core and vendor library collections. Nightly Builds - https://odin-lang.org/docs/nightly/ Get the latest nightly builds of Odin. + More Odin Examples - https://github.com/odin-lang/examples + This repository contains examples of how certain things can be accomplished + in idiomatic Odin, allowing you learn its semantics, as well as how to use + parts of the core and vendor package collections. */ the_basics :: proc() { @@ -2419,6 +2423,13 @@ matrix_type :: proc() { } main :: proc() { + /* + For More Odin Examples - https://github.com/odin-lang/examples + This repository contains examples of how certain things can be accomplished + in idiomatic Odin, allowing you learn its semantics, as well as how to use + parts of the core and vendor package collections. + */ + when true { the_basics() control_flow() From 9ae566adcc5e7e55039349eed2b4768739391ae8 Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 8 Apr 2022 13:45:19 -0400 Subject: [PATCH 0520/1052] commit before fetching upstream/master --- core/os/os2/file_linux.odin | 8 +- core/sys/unix/syscalls_linux.odin | 125 +++++++++++++++++++++--------- 2 files changed, 91 insertions(+), 42 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 998fe8617..449eff1e2 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -331,12 +331,12 @@ _is_dir :: proc(fd: Handle) -> bool { // defined as 512, however, it is well known that paths can exceed that limit. // So, in theory you could have a path larger than the entire temp_allocator's // buffer. Therefor any large paths will use context.allocator. -_name_to_cstring :: proc(path: string) -> (cpath: cstring, allocated: bool) { - if len(path) > _CSTRING_NAME_HEAP_THRESHOLD { - cpath = strings.clone_to_cstring(path) +_name_to_cstring :: proc(name: string) -> (cname: cstring, allocated: bool) { + if len(name) > _CSTRING_NAME_HEAP_THRESHOLD { + cname = strings.clone_to_cstring(name) allocated = true return } - cpath = strings.clone_to_cstring(path, context.temp_allocator) + cname = strings.clone_to_cstring(name, context.temp_allocator) return } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 6fc6dc594..e72bfcedf 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1518,11 +1518,43 @@ when ODIN_ARCH == .amd64 { #panic("Unsupported architecture") } +// syscall related constants AT_FDCWD :: ~uintptr(99) AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_FOLLOW :: uintptr(0x400) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) +PROT_NONE :: 0x0 +PROT_READ :: 0x1 +PROT_WRITE :: 0x2 +PROT_EXEC :: 0x4 +PROT_GROWSDOWN :: 0x01000000 +PROT_GROWSUP :: 0x02000000 + +MAP_FIXED :: 0x1 +MAP_PRIVATE :: 0x2 +MAP_SHARED :: 0x4 +MAP_ANONYMOUS :: 0x20 + +MADV_NORMAL :: 0 +MADV_RANDOM :: 1 +MADV_SEQUENTIAL :: 2 +MADV_WILLNEED :: 3 +MADV_DONTNEED :: 4 +MADV_FREE :: 8 +MADV_REMOVE :: 9 +MADV_DONTFORK :: 10 +MADV_DOFORK :: 11 +MADV_MERGEABLE :: 12 +MADV_UNMERGEABLE :: 13 +MADV_HUGEPAGE :: 14 +MADV_NOHUGEPAGE :: 15 +MADV_DONTDUMP :: 16 +MADV_DODUMP :: 17 +MADV_WIPEONFORK :: 18 +MADV_KEEPONFORK :: 19 +MADV_HWPOISON :: 100 + sys_gettid :: proc "contextless" () -> int { return cast(int)intrinsics.syscall(SYS_gettid) } @@ -1531,7 +1563,7 @@ sys_getrandom :: proc "contextless" (buf: ^byte, buflen: int, flags: uint) -> in return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags)) } -sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { +sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open @@ -1539,19 +1571,19 @@ sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { } } -sys_openat :: proc(dfd: int, path: cstring, flags: int, mode: int = 0o000) -> int { +sys_openat :: proc "contextless" (dfd: int, path: cstring, flags: int, mode: int = 0o000) -> int { return int(intrinsics.syscall(SYS_openat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } -sys_close :: proc(fd: int) -> int { +sys_close :: proc "contextless" (fd: int) -> int { return int(intrinsics.syscall(SYS_close, uintptr(fd))) } -sys_read :: proc(fd: int, buf: rawptr, size: uint) -> int { +sys_read :: proc "contextless" (fd: int, buf: rawptr, size: uint) -> int { return int(intrinsics.syscall(SYS_read, uintptr(fd), uintptr(buf), uintptr(size))) } -sys_pread :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { +sys_pread :: proc "contextless" (fd: int, buf: rawptr, size: uint, offset: i64) -> int { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_pread64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) } else { @@ -1561,11 +1593,11 @@ sys_pread :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { } } -sys_write :: proc(fd: int, buf: rawptr, size: uint) -> int { +sys_write :: proc "contextless" (fd: int, buf: rawptr, size: uint) -> int { return int(intrinsics.syscall(SYS_write, uintptr(fd), uintptr(buf), uintptr(size))) } -sys_pwrite :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { +sys_pwrite :: proc "contextless" (fd: int, buf: rawptr, size: uint, offset: i64) -> int { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_pwrite64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) } else { @@ -1575,7 +1607,7 @@ sys_pwrite :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { } } -sys_lseek :: proc(fd: int, offset: i64, whence: int) -> i64 { +sys_lseek :: proc "contextless" (fd: int, offset: i64, whence: int) -> i64 { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return i64(intrinsics.syscall(SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) } else { @@ -1587,7 +1619,7 @@ sys_lseek :: proc(fd: int, offset: i64, whence: int) -> i64 { } } -sys_stat :: proc(path: cstring, stat: rawptr) -> int { +sys_stat :: proc "contextless" (path: cstring, stat: rawptr) -> int { when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_stat, uintptr(rawptr(path)), uintptr(stat))) } else when ODIN_ARCH != .arm64 { @@ -1597,7 +1629,7 @@ sys_stat :: proc(path: cstring, stat: rawptr) -> int { } } -sys_fstat :: proc(fd: int, stat: rawptr) -> int { +sys_fstat :: proc "contextless" (fd: int, stat: rawptr) -> int { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_fstat, uintptr(fd), uintptr(stat))) } else { @@ -1605,7 +1637,7 @@ sys_fstat :: proc(fd: int, stat: rawptr) -> int { } } -sys_lstat :: proc(path: cstring, stat: rawptr) -> int { +sys_lstat :: proc "contextless" (path: cstring, stat: rawptr) -> int { when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) } else when ODIN_ARCH != .arm64 { @@ -1615,7 +1647,7 @@ sys_lstat :: proc(path: cstring, stat: rawptr) -> int { } } -sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { +sys_readlink :: proc "contextless" (path: cstring, buf: rawptr, bufsiz: uint) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } else { // NOTE: arm64 does not have readlink @@ -1623,7 +1655,7 @@ sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { } } -sys_symlink :: proc(old_name: cstring, new_name: cstring) -> int { +sys_symlink :: proc "contextless" (old_name: cstring, new_name: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_symlink, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have symlink @@ -1631,7 +1663,7 @@ sys_symlink :: proc(old_name: cstring, new_name: cstring) -> int { } } -sys_access :: proc(path: cstring, mask: int) -> int { +sys_access :: proc "contextless" (path: cstring, mask: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_access, uintptr(rawptr(path)), uintptr(mask))) } else { // NOTE: arm64 does not have access @@ -1639,19 +1671,19 @@ sys_access :: proc(path: cstring, mask: int) -> int { } } -sys_getcwd :: proc(buf: rawptr, size: uint) -> int { +sys_getcwd :: proc "contextless" (buf: rawptr, size: uint) -> int { return int(intrinsics.syscall(SYS_getcwd, uintptr(buf), uintptr(size))) } -sys_chdir :: proc(path: cstring) -> int { +sys_chdir :: proc "contextless" (path: cstring) -> int { return int(intrinsics.syscall(SYS_chdir, uintptr(rawptr(path)))) } -sys_fchdir :: proc(fd: int) -> int { +sys_fchdir :: proc "contextless" (fd: int) -> int { return int(intrinsics.syscall(SYS_fchdir, uintptr(fd))) } -sys_chmod :: proc(path: cstring, mode: int) -> int { +sys_chmod :: proc "contextless" (path: cstring, mode: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have chmod @@ -1659,11 +1691,11 @@ sys_chmod :: proc(path: cstring, mode: int) -> int { } } -sys_fchmod :: proc(fd: int, mode: int) -> int { +sys_fchmod :: proc "contextless" (fd: int, mode: int) -> int { return int(intrinsics.syscall(SYS_fchmod, uintptr(fd), uintptr(mode))) } -sys_chown :: proc(path: cstring, user: int, group: int) -> int { +sys_chown :: proc "contextless" (path: cstring, user: int, group: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have chown @@ -1671,11 +1703,11 @@ sys_chown :: proc(path: cstring, user: int, group: int) -> int { } } -sys_fchown :: proc(fd: int, user: int, group: int) -> int { +sys_fchown :: proc "contextless" (fd: int, user: int, group: int) -> int { return int(intrinsics.syscall(SYS_fchown, uintptr(fd), uintptr(user), uintptr(group))) } -sys_lchown :: proc(path: cstring, user: int, group: int) -> int { +sys_lchown :: proc "contextless" (path: cstring, user: int, group: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_lchown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have lchown @@ -1683,7 +1715,7 @@ sys_lchown :: proc(path: cstring, user: int, group: int) -> int { } } -sys_rename :: proc(old, new: cstring) -> int { +sys_rename :: proc "contextless" (old, new: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) } else { // NOTE: arm64 does not have rename @@ -1691,7 +1723,7 @@ sys_rename :: proc(old, new: cstring) -> int { } } -sys_link :: proc(old_name: cstring, new_name: cstring) -> int { +sys_link :: proc "contextless" (old_name: cstring, new_name: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_link, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have link @@ -1699,7 +1731,7 @@ sys_link :: proc(old_name: cstring, new_name: cstring) -> int { } } -sys_unlink :: proc(path: cstring) -> int { +sys_unlink :: proc "contextless" (path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_unlink, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have unlink @@ -1707,11 +1739,11 @@ sys_unlink :: proc(path: cstring) -> int { } } -sys_unlinkat :: proc(dfd: int, path: cstring, flag: int = 0) -> int { +sys_unlinkat :: proc "contextless" (dfd: int, path: cstring, flag: int = 0) -> int { return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), flag)) } -sys_rmdir :: proc(path: cstring) -> int { +sys_rmdir :: proc "contextless" (path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have rmdir @@ -1719,7 +1751,7 @@ sys_rmdir :: proc(path: cstring) -> int { } } -sys_mkdir :: proc(path: cstring, mode: int) -> int { +sys_mkdir :: proc "contextless" (path: cstring, mode: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir @@ -1727,11 +1759,11 @@ sys_mkdir :: proc(path: cstring, mode: int) -> int { } } -sys_mkdirat :: proc(dfd: int, path: cstring, mode: int) -> int { +sys_mkdirat :: proc "contextless" (dfd: int, path: cstring, mode: int) -> int { return int(intrinsics.syscall(SYS_mkdirat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode))) } -sys_mknod :: proc(path: cstring, mode: int, dev: int) -> int { +sys_mknod :: proc "contextless" (path: cstring, mode: int, dev: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mknod, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } else { // NOTE: arm64 does not have mknod @@ -1739,11 +1771,11 @@ sys_mknod :: proc(path: cstring, mode: int, dev: int) -> int { } } -sys_mknodat :: proc(dfd: int, path: cstring, mode: int, dev: int) -> int { +sys_mknodat :: proc "contextless" (dfd: int, path: cstring, mode: int, dev: int) -> int { return int(intrinsics.syscall(SYS_mknodat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } -sys_truncate :: proc(path: cstring, length: i64) -> int { +sys_truncate :: proc "contextless" (path: cstring, length: i64) -> int { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_truncate, uintptr(rawptr(path)), uintptr(length))) } else { @@ -1753,7 +1785,7 @@ sys_truncate :: proc(path: cstring, length: i64) -> int { } } -sys_ftruncate :: proc(fd: int, length: i64) -> int { +sys_ftruncate :: proc "contextless" (fd: int, length: i64) -> int { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_ftruncate, uintptr(fd), uintptr(length))) } else { @@ -1763,15 +1795,15 @@ sys_ftruncate :: proc(fd: int, length: i64) -> int { } } -sys_fsync :: proc(fd: int) -> int { +sys_fsync :: proc "contextless" (fd: int) -> int { return int(intrinsics.syscall(SYS_fsync, uintptr(fd))) } -sys_getdents64 :: proc(fd: int, dirent: rawptr, count: int) -> int { +sys_getdents64 :: proc "contextless" (fd: int, dirent: rawptr, count: int) -> int { return int(intrinsics.syscall(SYS_getdents64, uintptr(fd), uintptr(dirent), uintptr(count))) } -sys_fork :: proc() -> int { +sys_fork :: proc "contextless" () -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_fork)) } else { @@ -1779,13 +1811,30 @@ sys_fork :: proc() -> int { } } +sys_mmap :: proc "contextless" (addr: rawptr, length: uint, prot, flags, fd: int, offset: uintptr) -> int { + return int(intrinsics.syscall(unix.SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset)) +} + +sys_munmap :: proc "contextless" (addr: rawptr, length: uint) -> int { + return int(intrinsics.syscall(unix.SYS_munmap, uintptr(addr), uintptr(length))) +} + +sys_mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: int) -> int { + return int(intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot))) +} + +sys_madvise :: proc "contextless" (addr: rawptr, length: uint, advice: int) -> int { + return int(intrinsics.syscall(unix.SYS_madvise, uintptr(addr), uintptr(length), uintptr(advice))) +} + + // NOTE: Unsure about if this works directly on 32 bit archs. It may need 32 bit version of the time struct. // As of Linux 5.1, there is a utimensat_time64 function. Maybe use this in the future? -sys_utimensat :: proc(dfd: int, path: cstring, times: rawptr, flags: int) -> int { +sys_utimensat :: proc "contextless" (dfd: int, path: cstring, times: rawptr, flags: int) -> int { return int(intrinsics.syscall(SYS_utimensat, uintptr(dfd), uintptr(rawptr(path)), uintptr(times), uintptr(flags))) } -get_errno :: proc(res: int) -> i32 { +get_errno :: proc "contextless" (res: int) -> i32 { if res < 0 && res > -4096 { return i32(-res) } From 1a2c36e482315f87af92f29d36ad204789a129a5 Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 8 Apr 2022 13:52:36 -0400 Subject: [PATCH 0521/1052] whoops --- core/sys/unix/syscalls_linux.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index e72bfcedf..8e0f7d89d 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1812,19 +1812,19 @@ sys_fork :: proc "contextless" () -> int { } sys_mmap :: proc "contextless" (addr: rawptr, length: uint, prot, flags, fd: int, offset: uintptr) -> int { - return int(intrinsics.syscall(unix.SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset)) + return int(intrinsics.syscall(SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset)) } sys_munmap :: proc "contextless" (addr: rawptr, length: uint) -> int { - return int(intrinsics.syscall(unix.SYS_munmap, uintptr(addr), uintptr(length))) + return int(intrinsics.syscall(SYS_munmap, uintptr(addr), uintptr(length))) } sys_mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: int) -> int { - return int(intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot))) + return int(intrinsics.syscall(SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot))) } sys_madvise :: proc "contextless" (addr: rawptr, length: uint, advice: int) -> int { - return int(intrinsics.syscall(unix.SYS_madvise, uintptr(addr), uintptr(length), uintptr(advice))) + return int(intrinsics.syscall(SYS_madvise, uintptr(addr), uintptr(length), uintptr(advice))) } From 15b440c4f1878a27f6cc2f2bf1249022f237fe7d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 4 Apr 2022 15:39:42 +0200 Subject: [PATCH 0522/1052] [image] Add QOI load/save. Additionally: - Firm up PNG loader with some additional checks. - Add helper functions to `core:image` to expand grayscale to RGB(A), and so on. TODO: Possibly replace PNG's post-processing steps with calls to the new helper functions. --- core/compress/common.odin | 4 - core/image/common.odin | 830 +++++++++++++++++++++++++- core/image/png/helpers.odin | 13 +- core/image/png/png.odin | 75 ++- core/image/qoi/qoi.odin | 407 +++++++++++++ tests/core/image/test_core_image.odin | 2 +- 6 files changed, 1270 insertions(+), 61 deletions(-) create mode 100644 core/image/qoi/qoi.odin diff --git a/core/compress/common.odin b/core/compress/common.odin index 58aeac25b..f4e378269 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -128,7 +128,6 @@ Deflate_Error :: enum { BType_3, } - // General I/O context for ZLIB, LZW, etc. Context_Memory_Input :: struct #packed { input_data: []u8, @@ -151,7 +150,6 @@ when size_of(rawptr) == 8 { #assert(size_of(Context_Memory_Input) == 52) } - Context_Stream_Input :: struct #packed { input_data: []u8, input: io.Stream, @@ -185,8 +183,6 @@ Context_Stream_Input :: struct #packed { This simplifies end-of-stream handling where bits may be left in the bit buffer. */ -// TODO: Make these return compress.Error errors. - input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Error) { return i64(len(z.input_data)), nil } diff --git a/core/image/common.odin b/core/image/common.odin index adaa094d8..2e7bca17e 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -15,6 +15,32 @@ import "core:mem" import "core:compress" import "core:runtime" +/* + 67_108_864 pixels max by default. + + For QOI, the Worst case scenario means all pixels will be encoded as RGBA literals, costing 5 bytes each. + This caps memory usage at 320 MiB. + + The tunable is limited to 4_294_836_225 pixels maximum, or 4 GiB per 8-bit channel. + It is not advised to tune it this large. + + The 64 Megapixel default is considered to be a decent upper bound you won't run into in practice, + except in very specific circumstances. + +*/ +MAX_DIMENSIONS :: min(#config(MAX_DIMENSIONS, 8192 * 8192), 65535 * 65535) + +// Color +RGB_Pixel :: [3]u8 +RGBA_Pixel :: [4]u8 +RGB_Pixel_16 :: [3]u16 +RGBA_Pixel_16 :: [4]u16 +// Grayscale +G_Pixel :: [1]u8 +GA_Pixel :: [2]u8 +G_Pixel_16 :: [1]u16 +GA_Pixel_16 :: [2]u16 + Image :: struct { width: int, height: int, @@ -26,15 +52,17 @@ Image :: struct { For convenience, we return them as u16 so we don't need to switch on the type in our viewer, and can just test against nil. */ - background: Maybe([3]u16), - + background: Maybe(RGB_Pixel_16), metadata: Image_Metadata, } Image_Metadata :: union { ^PNG_Info, + ^QOI_Info, } + + /* IMPORTANT: `.do_not_expand_*` options currently skip handling of the `alpha_*` options, therefore Gray+Alpha will be returned as such even if you add `.alpha_drop_if_present`, @@ -46,13 +74,13 @@ Image_Metadata :: union { /* Image_Option: `.info` - This option behaves as `.return_ihdr` and `.do_not_decompress_image` and can be used + This option behaves as `.return_metadata` and `.do_not_decompress_image` and can be used to gather an image's dimensions and color information. `.return_header` - Fill out img.sidecar.header with the image's format-specific header struct. + Fill out img.metadata.header with the image's format-specific header struct. If we only care about the image specs, we can set `.return_header` + - `.do_not_decompress_image`, or `.info`, which works as if both of these were set. + `.do_not_decompress_image`, or `.info`. `.return_metadata` Returns all chunks not needed to decode the data. @@ -88,7 +116,7 @@ Image_Option: `.alpha_premultiply` If the image has an alpha channel, returns image data as follows: - RGB *= A, Gray = Gray *= A + RGB *= A, Gray = Gray *= A `.blend_background` If a bKGD chunk is present in a PNG, we normally just set `img.background` @@ -103,24 +131,29 @@ Image_Option: */ Option :: enum { + // LOAD OPTIONS info = 0, do_not_decompress_image, return_header, return_metadata, - alpha_add_if_missing, - alpha_drop_if_present, - alpha_premultiply, - blend_background, + alpha_add_if_missing, // Ignored for QOI. Always returns RGBA8. + alpha_drop_if_present, // Unimplemented for QOI. Returns error. + alpha_premultiply, // Unimplemented for QOI. Returns error. + blend_background, // Ignored for non-PNG formats // Unimplemented do_not_expand_grayscale, do_not_expand_indexed, do_not_expand_channels, + + // SAVE OPTIONS + qoi_all_channels_linear, // QOI, informative info. If not set, defaults to sRGB with linear alpha. } Options :: distinct bit_set[Option] Error :: union #shared_nil { General_Image_Error, PNG_Error, + QOI_Error, compress.Error, compress.General_Error, @@ -134,8 +167,13 @@ General_Image_Error :: enum { Invalid_Image_Dimensions, Image_Dimensions_Too_Large, Image_Does_Not_Adhere_to_Spec, + Invalid_Input_Image, + Invalid_Output, } +/* + PNG-specific definitions +*/ PNG_Error :: enum { None = 0, Invalid_PNG_Signature, @@ -147,7 +185,9 @@ PNG_Error :: enum { IDAT_Size_Too_Large, PLTE_Encountered_Unexpectedly, PLTE_Invalid_Length, + PLTE_Missing, TRNS_Encountered_Unexpectedly, + TNRS_Invalid_Length, BKGD_Invalid_Length, Unknown_Color_Type, Invalid_Color_Bit_Depth_Combo, @@ -158,9 +198,6 @@ PNG_Error :: enum { Invalid_Chunk_Length, } -/* - PNG-specific structs -*/ PNG_Info :: struct { header: PNG_IHDR, chunks: [dynamic]PNG_Chunk, @@ -223,7 +260,7 @@ PNG_Chunk_Type :: enum u32be { */ iDOT = 'i' << 24 | 'D' << 16 | 'O' << 8 | 'T', - CbGI = 'C' << 24 | 'b' << 16 | 'H' << 8 | 'I', + CgBI = 'C' << 24 | 'g' << 16 | 'B' << 8 | 'I', } PNG_IHDR :: struct #packed { @@ -251,16 +288,44 @@ PNG_Interlace_Method :: enum u8 { } /* - Functions to help with image buffer calculations + QOI-specific definitions */ +QOI_Error :: enum { + None = 0, + Invalid_QOI_Signature, + Invalid_Number_Of_Channels, // QOI allows 3 or 4 channel data. + Invalid_Bit_Depth, // QOI supports only 8-bit images, error only returned from writer. + Invalid_Color_Space, // QOI allows 0 = sRGB or 1 = linear. + Corrupt, // More data than pixels to decode into, for example. + Missing_Or_Corrupt_Trailer, // Image seemed to have decoded okay, but trailer is missing or corrupt. +} + +QOI_Magic :: u32be(0x716f6966) // "qoif" + +QOI_Color_Space :: enum u8 { + sRGB = 0, + Linear = 1, +} + +QOI_Header :: struct #packed { + magic: u32be, + width: u32be, + height: u32be, + channels: u8, + color_space: QOI_Color_Space, +} +#assert(size_of(QOI_Header) == 14) + +QOI_Info :: struct { + header: QOI_Header, +} + +// Function to help with image buffer calculations compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) { size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height return } -/* - For when you have an RGB(A) image, but want a particular channel. -*/ Channel :: enum u8 { R = 1, G = 2, @@ -268,7 +333,13 @@ Channel :: enum u8 { A = 4, } +// When you have an RGB(A) image, but want a particular channel. return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok: bool) { + // Were we actually given a valid image? + if img == nil { + return nil, false + } + ok = false t: bytes.Buffer @@ -298,7 +369,7 @@ return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok o = o[1:] } case 16: - buffer_size := compute_buffer_size(img.width, img.height, 2, 8) + buffer_size := compute_buffer_size(img.width, img.height, 1, 16) t = bytes.Buffer{} resize(&t.buf, buffer_size) @@ -326,3 +397,724 @@ return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok return res, true } + +// Does the image have 1 or 2 channels, a valid bit depth (8 or 16), +// Is the pointer valid, are the dimenions valid? +is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) { + // Were we actually given a valid image? + if img == nil { + return false + } + + // Are we a Gray or Gray + Alpha image? + if img.channels != 1 && img.channels != 2 { + return false + } + + // Do we have an acceptable bit depth? + if img.depth != 8 && img.depth != 16 { + return false + } + + // This returns 0 if any of the inputs is zero. + bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth) + + // If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail. + if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS { + return false + } + + return true +} + +// Does the image have 3 or 4 channels, a valid bit depth (8 or 16), +// Is the pointer valid, are the dimenions valid? +is_valid_color_image :: proc(img: ^Image) -> (ok: bool) { + // Were we actually given a valid image? + if img == nil { + return false + } + + // Are we an RGB or RGBA image? + if img.channels != 3 && img.channels != 4 { + return false + } + + // Do we have an acceptable bit depth? + if img.depth != 8 && img.depth != 16 { + return false + } + + // This returns 0 if any of the inputs is zero. + bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth) + + // If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail. + if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS { + return false + } + + return true +} + +// Does the image have 1..4 channels, a valid bit depth (8 or 16), +// Is the pointer valid, are the dimenions valid? +is_valid_image :: proc(img: ^Image) -> (ok: bool) { + // Were we actually given a valid image? + if img == nil { + return false + } + + return is_valid_color_image(img) || is_valid_grayscale_image(img) +} + +Alpha_Key :: union { + GA_Pixel, + RGBA_Pixel, + GA_Pixel_16, + RGBA_Pixel_16, +} + +/* + Add alpha channel if missing, in-place. + + Expects 1..4 channels (Gray, Gray + Alpha, RGB, RGBA). + Any other number of channels will be considered an error, returning `false` without modifying the image. + If the input image already has an alpha channel, it'll return `true` early (without considering optional keyed alpha). + + If an image doesn't already have an alpha channel: + If the optional `alpha_key` is provided, it will be resolved as follows: + - For RGB, if pix = key.rgb -> pix = {0, 0, 0, key.a} + - For Gray, if pix = key.r -> pix = {0, key.g} + Otherwise, an opaque alpha channel will be added. +*/ +alpha_add_if_missing :: proc(img: ^Image, alpha_key := Alpha_Key{}, allocator := context.allocator) -> (ok: bool) { + context.allocator = allocator + + if !is_valid_image(img) { + return false + } + + // We should now have a valid Image with 1..4 channels. Do we already have alpha? + if img.channels == 2 || img.channels == 4 { + // We're done. + return true + } + + channels := img.channels + 1 + bytes_wanted := compute_buffer_size(img.width, img.height, channels, img.depth) + + buf := bytes.Buffer{} + + // Can we allocate the return buffer? + if !resize(&buf.buf, bytes_wanted) { + delete(buf.buf) + return false + } + + switch img.depth { + case 8: + switch channels { + case 2: + // Turn Gray into Gray + Alpha + inp := mem.slice_data_cast([]G_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]GA_Pixel, buf.buf[:]) + + if key, key_ok := alpha_key.(GA_Pixel); key_ok { + // We have keyed alpha. + o: GA_Pixel + for p in inp { + if p == key.r { + o = GA_Pixel{0, key.g} + } else { + o = GA_Pixel{p.r, 255} + } + out[0] = o + out = out[1:] + } + } else { + // No keyed alpha, just make all pixels opaque. + o := GA_Pixel{0, 255} + for p in inp { + o.r = p.r + out[0] = o + out = out[1:] + } + } + + case 4: + // Turn RGB into RGBA + inp := mem.slice_data_cast([]RGB_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGBA_Pixel, buf.buf[:]) + + if key, key_ok := alpha_key.(RGBA_Pixel); key_ok { + // We have keyed alpha. + o: RGBA_Pixel + for p in inp { + if p == key.rgb { + o = RGBA_Pixel{0, 0, 0, key.a} + } else { + o = RGBA_Pixel{p.r, p.g, p.b, 255} + } + out[0] = o + out = out[1:] + } + } else { + // No keyed alpha, just make all pixels opaque. + o := RGBA_Pixel{0, 0, 0, 255} + for p in inp { + o.rgb = p + out[0] = o + out = out[1:] + } + } + case: + // We shouldn't get here. + unreachable() + } + case 16: + switch channels { + case 2: + // Turn Gray into Gray + Alpha + inp := mem.slice_data_cast([]G_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]GA_Pixel_16, buf.buf[:]) + + if key, key_ok := alpha_key.(GA_Pixel_16); key_ok { + // We have keyed alpha. + o: GA_Pixel_16 + for p in inp { + if p == key.r { + o = GA_Pixel_16{0, key.g} + } else { + o = GA_Pixel_16{p.r, 65535} + } + out[0] = o + out = out[1:] + } + } else { + // No keyed alpha, just make all pixels opaque. + o := GA_Pixel_16{0, 65535} + for p in inp { + o.r = p.r + out[0] = o + out = out[1:] + } + } + + case 4: + // Turn RGB into RGBA + inp := mem.slice_data_cast([]RGB_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGBA_Pixel_16, buf.buf[:]) + + if key, key_ok := alpha_key.(RGBA_Pixel_16); key_ok { + // We have keyed alpha. + o: RGBA_Pixel_16 + for p in inp { + if p == key.rgb { + o = RGBA_Pixel_16{0, 0, 0, key.a} + } else { + o = RGBA_Pixel_16{p.r, p.g, p.b, 65535} + } + out[0] = o + out = out[1:] + } + } else { + // No keyed alpha, just make all pixels opaque. + o := RGBA_Pixel_16{0, 0, 0, 65535} + for p in inp { + o.rgb = p + out[0] = o + out = out[1:] + } + } + case: + // We shouldn't get here. + unreachable() + } + } + + // If we got here, that means we've now got a buffer with the alpha channel added. + // Destroy the old pixel buffer and replace it with the new one, and update the channel count. + bytes.buffer_destroy(&img.pixels) + img.pixels = buf + img.channels = channels + return true +} +alpha_apply_keyed_alpha :: alpha_add_if_missing + +/* + Drop alpha channel if present, in-place. + + Expects 1..4 channels (Gray, Gray + Alpha, RGB, RGBA). + Any other number of channels will be considered an error, returning `false` without modifying the image. + + Of the `options`, the following are considered: + `.alpha_premultiply` + If the image has an alpha channel, returns image data as follows: + RGB *= A, Gray = Gray *= A + + `.blend_background` + If `img.background` is set, it'll be blended in like this: + RGB = (1 - A) * Background + A * RGB + + If an image has 1 (Gray) or 3 (RGB) channels, it'll return early without modifying the image, + with one exception: `alpha_key` and `img.background` are present, and `.blend_background` is set. + + In this case a keyed alpha pixel will be replaced with the background color. +*/ +alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Alpha_Key{}, allocator := context.allocator) -> (ok: bool) { + context.allocator = allocator + + if !is_valid_image(img) { + return false + } + + // Do we have a background to blend? + will_it_blend := false + switch v in img.background { + case RGB_Pixel_16: will_it_blend = true if .blend_background in options else false + } + + // Do we have keyed alpha? + keyed := false + switch v in alpha_key { + case GA_Pixel: keyed = true if img.channels == 1 && img.depth == 8 else false + case RGBA_Pixel: keyed = true if img.channels == 3 && img.depth == 8 else false + case GA_Pixel_16: keyed = true if img.channels == 1 && img.depth == 16 else false + case RGBA_Pixel_16: keyed = true if img.channels == 3 && img.depth == 16 else false + } + + // We should now have a valid Image with 1..4 channels. Do we have alpha? + if img.channels == 1 || img.channels == 3 { + if !(will_it_blend && keyed) { + // We're done + return true + } + } + + // # of destination channels + channels := 1 if img.channels < 3 else 3 + + bytes_wanted := compute_buffer_size(img.width, img.height, channels, img.depth) + buf := bytes.Buffer{} + + // Can we allocate the return buffer? + if !resize(&buf.buf, bytes_wanted) { + delete(buf.buf) + return false + } + + switch img.depth { + case 8: + switch img.channels { + case 1: // Gray to Gray, but we should have keyed alpha + background. + inp := mem.slice_data_cast([]G_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]G_Pixel, buf.buf[:]) + + key := alpha_key.(GA_Pixel).r + bg := G_Pixel{} + if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { + // Background is RGB 16-bit, take just the red channel's topmost byte. + bg = u8(temp_bg.r >> 8) + } + + for p in inp { + out[0] = bg if p == key else p + out = out[1:] + } + + case 2: // Gray + Alpha to Gray, no keyed alpha but we can have a background. + inp := mem.slice_data_cast([]GA_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]G_Pixel, buf.buf[:]) + + if will_it_blend { + // Blend with background "color", then drop alpha. + bg := f32(0.0) + if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { + // Background is RGB 16-bit, take just the red channel's topmost byte. + bg = f32(temp_bg.r >> 8) + } + + for p in inp { + a := f32(p.g) / 255.0 + c := ((1.0 - a) * bg + a * f32(p.r)) + out[0] = u8(c) + out = out[1:] + } + + } else if .alpha_premultiply in options { + // Premultiply component with alpha, then drop alpha. + for p in inp { + a := f32(p.g) / 255.0 + c := f32(p.r) * a + out[0] = u8(c) + out = out[1:] + } + } else { + // Just drop alpha on the floor. + for p in inp { + out[0] = p.r + out = out[1:] + } + } + + case 3: // RGB to RGB, but we should have keyed alpha + background. + inp := mem.slice_data_cast([]RGB_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGB_Pixel, buf.buf[:]) + + key := alpha_key.(RGBA_Pixel) + bg := RGB_Pixel{} + if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { + // Background is RGB 16-bit, squash down to 8 bits. + bg = {u8(temp_bg.r >> 8), u8(temp_bg.g >> 8), u8(temp_bg.b >> 8)} + } + + for p in inp { + out[0] = bg if p == key.rgb else p + out = out[1:] + } + + case 4: // RGBA to RGB, no keyed alpha but we can have a background or need to premultiply. + inp := mem.slice_data_cast([]RGBA_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGB_Pixel, buf.buf[:]) + + if will_it_blend { + // Blend with background "color", then drop alpha. + bg := [3]f32{} + if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { + // Background is RGB 16-bit, take just the red channel's topmost byte. + bg = {f32(temp_bg.r >> 8), f32(temp_bg.g >> 8), f32(temp_bg.b >> 8)} + } + + for p in inp { + a := f32(p.a) / 255.0 + rgb := [3]f32{f32(p.r), f32(p.g), f32(p.b)} + c := ((1.0 - a) * bg + a * rgb) + + out[0] = {u8(c.r), u8(c.g), u8(c.b)} + out = out[1:] + } + + } else if .alpha_premultiply in options { + // Premultiply component with alpha, then drop alpha. + for p in inp { + a := f32(p.a) / 255.0 + rgb := [3]f32{f32(p.r), f32(p.g), f32(p.b)} + c := rgb * a + + out[0] = {u8(c.r), u8(c.g), u8(c.b)} + out = out[1:] + } + } else { + // Just drop alpha on the floor. + for p in inp { + out[0] = p.rgb + out = out[1:] + } + } + } + + case 16: + switch img.channels { + case 1: // Gray to Gray, but we should have keyed alpha + background. + inp := mem.slice_data_cast([]G_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]G_Pixel_16, buf.buf[:]) + + key := alpha_key.(GA_Pixel_16).r + bg := G_Pixel_16{} + if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { + // Background is RGB 16-bit, take just the red channel. + bg = temp_bg.r + } + + for p in inp { + out[0] = bg if p == key else p + out = out[1:] + } + + case 2: // Gray + Alpha to Gray, no keyed alpha but we can have a background. + inp := mem.slice_data_cast([]GA_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]G_Pixel_16, buf.buf[:]) + + if will_it_blend { + // Blend with background "color", then drop alpha. + bg := f32(0.0) + if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { + // Background is RGB 16-bit, take just the red channel. + bg = f32(temp_bg.r) + } + + for p in inp { + a := f32(p.g) / 65535.0 + c := ((1.0 - a) * bg + a * f32(p.r)) + out[0] = u16(c) + out = out[1:] + } + + } else if .alpha_premultiply in options { + // Premultiply component with alpha, then drop alpha. + for p in inp { + a := f32(p.g) / 65535.0 + c := f32(p.r) * a + out[0] = u16(c) + out = out[1:] + } + } else { + // Just drop alpha on the floor. + for p in inp { + out[0] = p.r + out = out[1:] + } + } + + case 3: // RGB to RGB, but we should have keyed alpha + background. + inp := mem.slice_data_cast([]RGB_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGB_Pixel_16, buf.buf[:]) + + key := alpha_key.(RGBA_Pixel_16) + bg := img.background.(RGB_Pixel_16) + + for p in inp { + out[0] = bg if p == key.rgb else p + out = out[1:] + } + + case 4: // RGBA to RGB, no keyed alpha but we can have a background or need to premultiply. + inp := mem.slice_data_cast([]RGBA_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGB_Pixel_16, buf.buf[:]) + + if will_it_blend { + // Blend with background "color", then drop alpha. + bg := [3]f32{} + if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { + // Background is RGB 16-bit, convert to [3]f32 to blend. + bg = {f32(temp_bg.r), f32(temp_bg.g), f32(temp_bg.b)} + } + + for p in inp { + a := f32(p.a) / 65535.0 + rgb := [3]f32{f32(p.r), f32(p.g), f32(p.b)} + c := ((1.0 - a) * bg + a * rgb) + + out[0] = {u16(c.r), u16(c.g), u16(c.b)} + out = out[1:] + } + + } else if .alpha_premultiply in options { + // Premultiply component with alpha, then drop alpha. + for p in inp { + a := f32(p.a) / 65535.0 + rgb := [3]f32{f32(p.r), f32(p.g), f32(p.b)} + c := rgb * a + + out[0] = {u16(c.r), u16(c.g), u16(c.b)} + out = out[1:] + } + } else { + // Just drop alpha on the floor. + for p in inp { + out[0] = p.rgb + out = out[1:] + } + } + } + + case: + unreachable() + } + + // If we got here, that means we've now got a buffer with the alpha channel dropped. + // Destroy the old pixel buffer and replace it with the new one, and update the channel count. + bytes.buffer_destroy(&img.pixels) + img.pixels = buf + img.channels = channels + return true +} + +// Apply palette to 8-bit single-channel image and return an 8-bit RGB image, in-place. +// If the image given is not a valid 8-bit single channel image, the procedure will return `false` early. +apply_palette_rgb :: proc(img: ^Image, palette: [256]RGB_Pixel, allocator := context.allocator) -> (ok: bool) { + context.allocator = allocator + + if img == nil || img.channels != 1 || img.depth != 8 { + return false + } + + bytes_expected := compute_buffer_size(img.width, img.height, 1, 8) + if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS { + return false + } + + // Can we allocate the return buffer? + buf := bytes.Buffer{} + bytes_wanted := compute_buffer_size(img.width, img.height, 3, 8) + if !resize(&buf.buf, bytes_wanted) { + delete(buf.buf) + return false + } + + out := mem.slice_data_cast([]RGB_Pixel, buf.buf[:]) + + // Apply the palette + for p, i in img.pixels.buf { + out[i] = palette[p] + } + + // If we got here, that means we've now got a buffer with the alpha channel dropped. + // Destroy the old pixel buffer and replace it with the new one, and update the channel count. + bytes.buffer_destroy(&img.pixels) + img.pixels = buf + img.channels = 3 + return true +} + +// Apply palette to 8-bit single-channel image and return an 8-bit RGBA image, in-place. +// If the image given is not a valid 8-bit single channel image, the procedure will return `false` early. +apply_palette_rgba :: proc(img: ^Image, palette: [256]RGBA_Pixel, allocator := context.allocator) -> (ok: bool) { + context.allocator = allocator + + if img == nil || img.channels != 1 || img.depth != 8 { + return false + } + + bytes_expected := compute_buffer_size(img.width, img.height, 1, 8) + if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS { + return false + } + + // Can we allocate the return buffer? + buf := bytes.Buffer{} + bytes_wanted := compute_buffer_size(img.width, img.height, 4, 8) + if !resize(&buf.buf, bytes_wanted) { + delete(buf.buf) + return false + } + + out := mem.slice_data_cast([]RGBA_Pixel, buf.buf[:]) + + // Apply the palette + for p, i in img.pixels.buf { + out[i] = palette[p] + } + + // If we got here, that means we've now got a buffer with the alpha channel dropped. + // Destroy the old pixel buffer and replace it with the new one, and update the channel count. + bytes.buffer_destroy(&img.pixels) + img.pixels = buf + img.channels = 4 + return true +} +apply_palette :: proc{apply_palette_rgb, apply_palette_rgba} + + +// Replicates grayscale values into RGB(A) 8- or 16-bit images as appropriate. +// Returns early with `false` if already an RGB(A) image. +expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bool) { + context.allocator = allocator + + if !is_valid_grayscale_image(img) { + return false + } + + // We should have 1 or 2 channels of 8- or 16 bits now. We need to turn that into 3 or 4. + // Can we allocate the return buffer? + buf := bytes.Buffer{} + bytes_wanted := compute_buffer_size(img.width, img.height, img.channels + 2, img.depth) + if !resize(&buf.buf, bytes_wanted) { + delete(buf.buf) + return false + } + + switch img.depth { + case 8: + switch img.channels { + case 1: // Turn Gray into RGB + out := mem.slice_data_cast([]RGB_Pixel, buf.buf[:]) + + for p in img.pixels.buf { + out[0] = p // Broadcast gray value into RGB components. + out = out[1:] + } + + case 2: // Turn Gray + Alpha into RGBA + inp := mem.slice_data_cast([]GA_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGBA_Pixel, buf.buf[:]) + + for p in inp { + out[0].rgb = p.r // Gray component. + out[0].a = p.g // Alpha component. + } + + case: + unreachable() + } + + case 16: + switch img.channels { + case 1: // Turn Gray into RGB + inp := mem.slice_data_cast([]u16, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGB_Pixel_16, buf.buf[:]) + + for p in inp { + out[0] = p // Broadcast gray value into RGB components. + out = out[1:] + } + + case 2: // Turn Gray + Alpha into RGBA + inp := mem.slice_data_cast([]GA_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGBA_Pixel_16, buf.buf[:]) + + for p in inp { + out[0].rgb = p.r // Gray component. + out[0].a = p.g // Alpha component. + } + + case: + unreachable() + } + + case: + unreachable() + } + + + // If we got here, that means we've now got a buffer with the extra alpha channel. + // Destroy the old pixel buffer and replace it with the new one, and update the channel count. + bytes.buffer_destroy(&img.pixels) + img.pixels = buf + img.channels += 2 + return true +} + +/* + Helper functions to read and write data from/to a Context, etc. +*/ +@(optimization_mode="speed") +read_data :: proc(z: $C, $T: typeid) -> (res: T, err: compress.General_Error) { + if r, e := compress.read_data(z, T); e != .None { + return {}, .Stream_Too_Short + } else { + return r, nil + } +} + +@(optimization_mode="speed") +read_u8 :: proc(z: $C) -> (res: u8, err: compress.General_Error) { + if r, e := compress.read_u8(z); e != .None { + return {}, .Stream_Too_Short + } else { + return r, nil + } +} + +write_bytes :: proc(buf: ^bytes.Buffer, data: []u8) -> (err: compress.General_Error) { + if len(data) == 0 { + return nil + } else if len(data) == 1 { + if bytes.buffer_write_byte(buf, data[0]) != nil { + return compress.General_Error.Resize_Failed + } + } else if n, _ := bytes.buffer_write(buf, data); n != len(data) { + return compress.General_Error.Resize_Failed + } + return nil +} \ No newline at end of file diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index c64e6f471..0ebf0b20b 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -242,17 +242,16 @@ srgb :: proc(c: image.PNG_Chunk) -> (res: sRGB, ok: bool) { } plte :: proc(c: image.PNG_Chunk) -> (res: PLTE, ok: bool) { - if c.header.type != .PLTE { + if c.header.type != .PLTE || c.header.length % 3 != 0 || c.header.length > 768 { return {}, false } - i := 0; j := 0; ok = true - for j < int(c.header.length) { - res.entries[i] = {c.data[j], c.data[j+1], c.data[j+2]} - i += 1; j += 3 + plte := mem.slice_data_cast([]image.RGB_Pixel, c.data[:]) + for color, i in plte { + res.entries[i] = color } - res.used = u16(i) - return + res.used = u16(len(plte)) + return res, true } splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) { diff --git a/core/image/png/png.odin b/core/image/png/png.odin index bff0afde3..55d69e7c7 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -25,16 +25,13 @@ import "core:io" import "core:mem" import "core:intrinsics" -/* - 67_108_864 pixels max by default. - Maximum allowed dimensions are capped at 65535 * 65535. -*/ -MAX_DIMENSIONS :: min(#config(PNG_MAX_DIMENSIONS, 8192 * 8192), 65535 * 65535) +import "core:fmt" + + +// Limit chunk sizes. +// By default: IDAT = 8k x 8k x 16-bits + 8k filter bytes. +// The total number of pixels defaults to 64 Megapixel and can be tuned in image/common.odin. -/* - Limit chunk sizes. - By default: IDAT = 8k x 8k x 16-bits + 8k filter bytes. -*/ _MAX_IDAT_DEFAULT :: ( 8192 /* Width */ * 8192 /* Height */ * 2 /* 16-bit */) + 8192 /* Filter bytes */ _MAX_IDAT :: (65535 /* Width */ * 65535 /* Height */ * 2 /* 16-bit */) + 65535 /* Filter bytes */ @@ -64,7 +61,7 @@ Row_Filter :: enum u8 { Paeth = 4, } -PLTE_Entry :: [3]u8 +PLTE_Entry :: image.RGB_Pixel PLTE :: struct #packed { entries: [256]PLTE_Entry, @@ -259,7 +256,7 @@ read_header :: proc(ctx: ^$C) -> (image.PNG_IHDR, Error) { header := (^image.PNG_IHDR)(raw_data(c.data))^ // Validate IHDR using header - if width == 0 || height == 0 || u128(width) * u128(height) > MAX_DIMENSIONS { + if width == 0 || height == 0 || u128(width) * u128(height) > image.MAX_DIMENSIONS { return {}, .Invalid_Image_Dimensions } @@ -366,6 +363,10 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a options -= {.info} } + if .return_header in options && .return_metadata in options { + options -= {.return_header} + } + if .alpha_drop_if_present in options && .alpha_add_if_missing in options { return {}, compress.General_Error.Incompatible_Options } @@ -392,7 +393,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a idat_length := u64(0) - c: image.PNG_Chunk + c: image.PNG_Chunk ch: image.PNG_Chunk_Header e: io.Error @@ -473,6 +474,10 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } info.header = h + if .return_header in options && .return_metadata not_in options && .do_not_decompress_image not_in options { + return img, nil + } + case .PLTE: seen_plte = true // PLTE must appear before IDAT and can't appear for color types 0, 4. @@ -540,9 +545,6 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a seen_iend = true case .bKGD: - - // TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be - c = read_chunk(ctx) or_return seen_bkgd = true if .return_metadata in options { @@ -594,23 +596,39 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a */ final_image_channels += 1 - seen_trns = true + + if .Paletted in header.color_type { + if len(c.data) > 256 { + fmt.printf("[PLTE] tRNS length: %v\n", len(c.data)) + return img, .TNRS_Invalid_Length + } + } else if .Color in header.color_type { + if len(c.data) != 6 { + fmt.printf("[COLOR] tRNS length: %v\n", len(c.data)) + return img, .TNRS_Invalid_Length + } + } else if len(c.data) != 2 { + fmt.printf("[GRAY] tRNS length: %v\n", len(c.data)) + return img, .TNRS_Invalid_Length + } + if info.header.bit_depth < 8 && .Paletted not_in info.header.color_type { // Rescale tRNS data so key matches intensity - dsc := depth_scale_table + dsc := depth_scale_table scale := dsc[info.header.bit_depth] if scale != 1 { key := mem.slice_data_cast([]u16be, c.data)[0] * u16be(scale) c.data = []u8{0, u8(key & 255)} } } + trns = c - case .iDOT, .CbGI: + case .iDOT, .CgBI: /* iPhone PNG bastardization that doesn't adhere to spec with broken IDAT chunk. - We're not going to add support for it. If you have the misfortunte of coming + We're not going to add support for it. If you have the misfortune of coming across one of these files, use a utility to defry it. */ return img, .Image_Does_Not_Adhere_to_Spec @@ -635,6 +653,10 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a return img, .IDAT_Missing } + if .Paletted in header.color_type && !seen_plte { + return img, .PLTE_Missing + } + /* Calculate the expected output size, to help `inflate` make better decisions about the output buffer. We'll also use it to check the returned buffer size is what we expected it to be. @@ -683,15 +705,6 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a return {}, defilter_error } - /* - Now we'll handle the relocoring of paletted images, handling of tRNS chunks, - and we'll expand grayscale images to RGB(A). - - For the sake of convenience we return only RGB(A) images. In the future we - may supply an option to return Gray/Gray+Alpha as-is, in which case RGB(A) - will become the default. - */ - if .Paletted in header.color_type && .do_not_expand_indexed in options { return img, nil } @@ -699,7 +712,10 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a return img, nil } - + /* + Now we're going to optionally apply various post-processing stages, + to for example expand grayscale, apply a palette, premultiply alpha, etc. + */ raw_image_channels := img.channels out_image_channels := 3 @@ -1204,7 +1220,6 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a return img, nil } - filter_paeth :: #force_inline proc(left, up, up_left: u8) -> u8 { aa, bb, cc := i16(left), i16(up), i16(up_left) p := aa + bb - cc diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin new file mode 100644 index 000000000..c157e8099 --- /dev/null +++ b/core/image/qoi/qoi.odin @@ -0,0 +1,407 @@ +/* + Copyright 2022 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ + + +// package qoi implements a QOI image reader +// +// The QOI specification is at https://qoiformat.org. +package qoi + +import "core:mem" +import "core:image" +import "core:compress" +import "core:bytes" +import "core:os" + +Error :: image.Error +General :: compress.General_Error +Image :: image.Image +Options :: image.Options + +RGB_Pixel :: image.RGB_Pixel +RGBA_Pixel :: image.RGBA_Pixel + +save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + if img == nil { + return .Invalid_Input_Image + } + + if output == nil { + return .Invalid_Output + } + + pixels := img.width * img.height + if pixels == 0 || pixels > image.MAX_DIMENSIONS { + return .Invalid_Input_Image + } + + // QOI supports only 8-bit images with 3 or 4 channels. + if img.depth != 8 || img.channels < 3 || img.channels > 4 { + return .Invalid_Input_Image + } + + if img.channels * pixels != len(img.pixels.buf) { + return .Invalid_Input_Image + } + + written := 0 + + // Calculate and allocate maximum size. We'll reclaim space to actually written output at the end. + max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be) + + if !resize(&output.buf, max_size) { + return General.Resize_Failed + } + + header := image.QOI_Header{ + magic = image.QOI_Magic, + width = u32be(img.width), + height = u32be(img.height), + channels = u8(img.channels), + color_space = .Linear if .qoi_all_channels_linear in options else .sRGB, + } + header_bytes := transmute([size_of(image.QOI_Header)]u8)header + + copy(output.buf[written:], header_bytes[:]) + written += size_of(image.QOI_Header) + + /* + Encode loop starts here. + */ + seen: [64]RGBA_Pixel + pix := RGBA_Pixel{0, 0, 0, 255} + prev := pix + + seen[qoi_hash(pix)] = pix + + input := img.pixels.buf[:] + run := u8(0) + + for len(input) > 0 { + if img.channels == 4 { + pix = (^RGBA_Pixel)(raw_data(input))^ + } else { + pix.rgb = (^RGB_Pixel)(raw_data(input))^ + } + input = input[img.channels:] + + if pix == prev { + run += 1 + // As long as the pixel matches the last one, accumulate the run total. + // If we reach the max run length or the end of the image, write the run. + if run == 62 || len(input) == 0 { + // Encode and write run + output.buf[written] = u8(QOI_Opcode_Tag.RUN) | (run - 1) + written += 1 + run = 0 + } + } else { + if run > 0 { + // The pixel differs from the previous one, but we still need to write the pending run. + // Encode and write run + output.buf[written] = u8(QOI_Opcode_Tag.RUN) | (run - 1) + written += 1 + run = 0 + } + + index := qoi_hash(pix) + + if seen[index] == pix { + // Write indexed pixel + output.buf[written] = u8(QOI_Opcode_Tag.INDEX) | index + written += 1 + } else { + // Add pixel to index + seen[index] = pix + + // If the alpha matches the previous pixel's alpha, we don't need to write a full RGBA literal. + if pix.a == prev.a { + // Delta + d := pix.rgb - prev.rgb + + // DIFF, biased and modulo 256 + _d := d + 2 + + // LUMA, biased and modulo 256 + _l := RGB_Pixel{ d.r - d.g + 8, d.g + 32, d.b - d.g + 8 } + + if _d.r < 4 && _d.g < 4 && _d.b < 4 { + // Delta is between -2 and 1 inclusive + output.buf[written] = u8(QOI_Opcode_Tag.DIFF) | _d.r << 4 | _d.g << 2 | _d.b + written += 1 + } else if _l.r < 16 && _l.g < 64 && _l.b < 16 { + // Biased luma is between {-8..7, -32..31, -8..7} + output.buf[written ] = u8(QOI_Opcode_Tag.LUMA) | _l.g + output.buf[written + 1] = _l.r << 4 | _l.b + written += 2 + } else { + // Write RGB literal + output.buf[written] = u8(QOI_Opcode_Tag.RGB) + pix_bytes := transmute([4]u8)pix + copy(output.buf[written + 1:], pix_bytes[:3]) + written += 4 + } + } else { + // Write RGBA literal + output.buf[written] = u8(QOI_Opcode_Tag.RGBA) + pix_bytes := transmute([4]u8)pix + copy(output.buf[written + 1:], pix_bytes[:]) + written += 5 + } + } + } + prev = pix + } + + trailer := []u8{0, 0, 0, 0, 0, 0, 0, 1} + copy(output.buf[written:], trailer[:]) + written += len(trailer) + + resize(&output.buf, written) + return nil +} + +save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + out := &bytes.Buffer{} + defer bytes.buffer_destroy(out) + + save_to_memory(out, img, options) or_return + write_ok := os.write_entire_file(output, out.buf[:]) + + return nil if write_ok else General.Cannot_Open_File +} + +save :: proc{save_to_memory, save_to_file} + +load_from_slice :: proc(slice: []u8, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { + ctx := &compress.Context_Memory_Input{ + input_data = slice, + } + + img, err = load_from_context(ctx, options, allocator) + return img, err +} + +load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { + context.allocator = allocator + + data, ok := os.read_entire_file(filename) + defer delete(data) + + if ok { + return load_from_slice(data, options) + } else { + img = new(Image) + return img, compress.General_Error.File_Not_Found + } +} + +@(optimization_mode="speed") +load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { + context.allocator = allocator + options := options + + if .alpha_drop_if_present in options || .alpha_premultiply in options { + // TODO: Implement. + // As stated in image/common, unimplemented options are ignored. + } + + if .info in options { + options |= {.return_metadata, .do_not_decompress_image} + options -= {.info} + } + + if .return_header in options && .return_metadata in options { + options -= {.return_header} + } + + header := image.read_data(ctx, image.QOI_Header) or_return + if header.magic != image.QOI_Magic { + return img, .Invalid_QOI_Signature + } + + if img == nil { + img = new(Image) + } + + if .return_metadata in options { + info := new(image.QOI_Info) + info.header = header + img.metadata = info + } + + if header.channels != 3 && header.channels != 4 { + return img, .Invalid_Number_Of_Channels + } + + if header.color_space != .sRGB && header.color_space != .Linear { + return img, .Invalid_Color_Space + } + + if header.width == 0 || header.height == 0 { + return img, .Invalid_Image_Dimensions + } + + total_pixels := header.width * header.height + if total_pixels > image.MAX_DIMENSIONS { + return img, .Image_Dimensions_Too_Large + } + + img.width = int(header.width) + img.height = int(header.height) + img.channels = 4 + img.depth = 8 + + if .do_not_decompress_image in options { + return + } + + bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), 4, 8) + + if !resize(&img.pixels.buf, bytes_needed) { + return img, mem.Allocator_Error.Out_Of_Memory + } + pixels := mem.slice_data_cast([]RGBA_Pixel, img.pixels.buf[:]) + + /* + Decode loop starts here. + */ + seen: [64]RGBA_Pixel + pix := RGBA_Pixel{0, 0, 0, 255} + seen[qoi_hash(pix)] = pix + + decode: for len(pixels) > 0 { + data := image.read_u8(ctx) or_return + + tag := QOI_Opcode_Tag(data) + #partial switch tag { + case .RGB: + pix.rgb = image.read_data(ctx, RGB_Pixel) or_return + + #no_bounds_check { + seen[qoi_hash(pix)] = pix + } + + case .RGBA: + pix = image.read_data(ctx, RGBA_Pixel) or_return + + #no_bounds_check { + seen[qoi_hash(pix)] = pix + } + + case: + // 2-bit tag + tag = QOI_Opcode_Tag(data & QOI_Opcode_Mask) + #partial switch tag { + case .INDEX: + pix = seen[data & 63] + + case .DIFF: + diff_r := ((data >> 4) & 3) - 2 + diff_g := ((data >> 2) & 3) - 2 + diff_b := ((data >> 0) & 3) - 2 + + pix += {diff_r, diff_g, diff_b, 0} + + #no_bounds_check { + seen[qoi_hash(pix)] = pix + } + + case .LUMA: + data2 := image.read_u8(ctx) or_return + + diff_g := (data & 63) - 32 + diff_r := diff_g - 8 + ((data2 >> 4) & 15) + diff_b := diff_g - 8 + (data2 & 15) + + pix += {diff_r, diff_g, diff_b, 0} + + #no_bounds_check { + seen[qoi_hash(pix)] = pix + } + + case .RUN: + if length := int(data & 63) + 1; length > len(pixels) { + return img, .Corrupt + } else { + #no_bounds_check for i in 0.. (index: u8) { + i1 := u16(pixel.r) * 3 + i2 := u16(pixel.g) * 5 + i3 := u16(pixel.b) * 7 + i4 := u16(pixel.a) * 11 + + return u8((i1 + i2 + i3 + i4) & 63) +} \ No newline at end of file diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 52005d915..38291db6b 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -1500,7 +1500,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { passed &= dims_pass hash := hash.crc32(pixels) - error = fmt.tprintf("%v test %v hash is %08x, expected %08x.", file.file, count, hash, test.hash) + error = fmt.tprintf("%v test %v hash is %08x, expected %08x with %v.", file.file, count, hash, test.hash, test.options) expect(t, test.hash == hash, error) passed &= test.hash == hash From ab9457346d2eefb63a30993701377eb0ecb108ab Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 12 Apr 2022 18:26:10 +0200 Subject: [PATCH 0523/1052] [PNG] Remove debug printf. --- core/image/png/png.odin | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/image/png/png.odin b/core/image/png/png.odin index 55d69e7c7..ba888cb78 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -25,9 +25,6 @@ import "core:io" import "core:mem" import "core:intrinsics" -import "core:fmt" - - // Limit chunk sizes. // By default: IDAT = 8k x 8k x 16-bits + 8k filter bytes. // The total number of pixels defaults to 64 Megapixel and can be tuned in image/common.odin. @@ -600,16 +597,13 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a if .Paletted in header.color_type { if len(c.data) > 256 { - fmt.printf("[PLTE] tRNS length: %v\n", len(c.data)) return img, .TNRS_Invalid_Length } } else if .Color in header.color_type { if len(c.data) != 6 { - fmt.printf("[COLOR] tRNS length: %v\n", len(c.data)) return img, .TNRS_Invalid_Length } } else if len(c.data) != 2 { - fmt.printf("[GRAY] tRNS length: %v\n", len(c.data)) return img, .TNRS_Invalid_Length } From bf712e93557cd4f05433c00bb7a61dc48621b404 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 12 Apr 2022 19:23:48 +0200 Subject: [PATCH 0524/1052] [QOI] Add support for RGB images (previously loader always output RGBA). Also add QOI to CI test suite by roundtripping 8-bit RGB(A) through QOI and checking the hashes match. --- core/image/qoi/qoi.odin | 29 ++++++++++++----------- tests/core/image/test_core_image.odin | 34 +++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin index c157e8099..fdbaab686 100644 --- a/core/image/qoi/qoi.odin +++ b/core/image/qoi/qoi.odin @@ -210,11 +210,6 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a context.allocator = allocator options := options - if .alpha_drop_if_present in options || .alpha_premultiply in options { - // TODO: Implement. - // As stated in image/common, unimplemented options are ignored. - } - if .info in options { options |= {.return_metadata, .do_not_decompress_image} options -= {.info} @@ -258,19 +253,19 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a img.width = int(header.width) img.height = int(header.height) - img.channels = 4 + img.channels = 4 if .alpha_add_if_missing in options else int(header.channels) img.depth = 8 if .do_not_decompress_image in options { + img.channels = int(header.channels) return } - bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), 4, 8) + bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8) if !resize(&img.pixels.buf, bytes_needed) { return img, mem.Allocator_Error.Out_Of_Memory } - pixels := mem.slice_data_cast([]RGBA_Pixel, img.pixels.buf[:]) /* Decode loop starts here. @@ -278,6 +273,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a seen: [64]RGBA_Pixel pix := RGBA_Pixel{0, 0, 0, 255} seen[qoi_hash(pix)] = pix + pixels := img.pixels.buf[:] decode: for len(pixels) > 0 { data := image.read_u8(ctx) or_return @@ -330,13 +326,13 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } case .RUN: - if length := int(data & 63) + 1; length > len(pixels) { + if length := int(data & 63) + 1; (length * img.channels) > len(pixels) { return img, .Corrupt } else { - #no_bounds_check for i in 0.. (subtotal: int) { passed &= dims_pass - hash := hash.crc32(pixels) - error = fmt.tprintf("%v test %v hash is %08x, expected %08x with %v.", file.file, count, hash, test.hash, test.options) - expect(t, test.hash == hash, error) + png_hash := hash.crc32(pixels) + error = fmt.tprintf("%v test %v hash is %08x, expected %08x with %v.", file.file, count, png_hash, test.hash, test.options) + expect(t, test.hash == png_hash, error) + + passed &= test.hash == png_hash + + // Roundtrip through QOI to test the QOI encoder and decoder. + if passed && img.depth == 8 && (img.channels == 3 || img.channels == 4) { + qoi_buffer: bytes.Buffer + defer bytes.buffer_destroy(&qoi_buffer) + qoi_save_err := qoi.save(&qoi_buffer, img) + + error = fmt.tprintf("%v test %v QOI save failed with %v.", file.file, count, qoi_save_err) + expect(t, qoi_save_err == nil, error) + + if qoi_save_err == nil { + qoi_img, qoi_load_err := qoi.load(qoi_buffer.buf[:]) + defer qoi.destroy(qoi_img) + + error = fmt.tprintf("%v test %v QOI load failed with %v.", file.file, count, qoi_load_err) + expect(t, qoi_load_err == nil, error) + + qoi_hash := hash.crc32(qoi_img.pixels.buf[:]) + error = fmt.tprintf("%v test %v QOI load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, qoi_hash, png_hash, test.options) + expect(t, qoi_hash == png_hash, error) + } + } - passed &= test.hash == hash if .return_metadata in test.options { if v, ok := img.metadata.(^image.PNG_Info); ok { From 8310436350e7d2104c5b94c6f3909f9f517df502 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 13 Apr 2022 00:03:36 +0200 Subject: [PATCH 0525/1052] [varint] Clear up doc.odin. --- core/encoding/varint/doc.odin | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/core/encoding/varint/doc.odin b/core/encoding/varint/doc.odin index dd068b261..5e4708a59 100644 --- a/core/encoding/varint/doc.odin +++ b/core/encoding/varint/doc.odin @@ -4,24 +4,25 @@ Author of this Odin package: Jeroen van Rijn Example: - ```odin - import "core:encoding/varint" - import "core:fmt" + ```odin + import "core:encoding/varint" + import "core:fmt" - main :: proc() { - buf: [varint.LEB128_MAX_BYTES]u8 + main :: proc() { + buf: [varint.LEB128_MAX_BYTES]u8 - value := u128(42) + value := u128(42) - encode_size, encode_err := varint.encode_uleb128(buf[:], value) - assert(encode_size == 1 && encode_err == .None) + encode_size, encode_err := varint.encode_uleb128(buf[:], value) + assert(encode_size == 1 && encode_err == .None) - fmt.println(buf[:encode_size]) + fmt.printf("Encoded as %v\n", buf[:encode_size]) + decoded_val, decode_size, decode_err := varint.decode_uleb128(buf[:]) - decoded_val, decode_size, decode_err := varint.decode_uleb128(buf[:encode_size]) - assert(decoded_val == value && decode_size == encode_size && decode_err == .None) - } - ``` + assert(decoded_val == value && decode_size == encode_size && decode_err == .None) + fmt.printf("Decoded as %v, using %v byte%v\n", decoded_val, decode_size, "" if decode_size == 1 else "s") + } + ``` */ package varint \ No newline at end of file From a040be957ff3db94a1f35f73d4fc1b207ec1c526 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Wed, 13 Apr 2022 10:55:16 +0200 Subject: [PATCH 0526/1052] Fix tail recursion in `_quick_sort_general` The `if` statement should have been a `for` loop, in order to allow recursively sorting the subarrays with quicksort, and not resort to shell sort after one step. --- core/slice/sort_private.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/slice/sort_private.odin b/core/slice/sort_private.odin index 7abd2f1ce..d93d74bf9 100644 --- a/core/slice/sort_private.odin +++ b/core/slice/sort_private.odin @@ -150,7 +150,7 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND a, b, max_depth := a, b, max_depth - if b-a > 12 { // only use shell sort for lengths <= 12 + for b-a > 12 { // only use shell sort for lengths <= 12 if max_depth == 0 { heap_sort(data, a, b, call) return From 51db46551edb16eaa1396bbc3d8374dc1500154e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Apr 2022 15:03:47 +0100 Subject: [PATCH 0527/1052] Add MetalKit; Add NSApplication NSMenu NSMenuItem; Improve Metal classes --- vendor/darwin/Foundation/NSApplication.odin | 95 +++++++ vendor/darwin/Foundation/NSMenu.odin | 103 ++++++++ vendor/darwin/Foundation/NSNumber.odin | 6 +- vendor/darwin/Foundation/NSObject.odin | 5 +- vendor/darwin/Foundation/NSString.odin | 4 + vendor/darwin/Foundation/NSTypes.odin | 7 + vendor/darwin/Foundation/NSWindow.odin | 87 ++++++- vendor/darwin/Foundation/objc.odin | 73 ++++++ vendor/darwin/Metal/MetalClasses.odin | 14 +- vendor/darwin/MetalKit/MetalKit.odin | 259 ++++++++++++++++++++ 10 files changed, 637 insertions(+), 16 deletions(-) create mode 100644 vendor/darwin/Foundation/NSApplication.odin create mode 100644 vendor/darwin/Foundation/NSMenu.odin create mode 100644 vendor/darwin/Foundation/objc.odin create mode 100644 vendor/darwin/MetalKit/MetalKit.odin diff --git a/vendor/darwin/Foundation/NSApplication.odin b/vendor/darwin/Foundation/NSApplication.odin new file mode 100644 index 000000000..2fc4e6356 --- /dev/null +++ b/vendor/darwin/Foundation/NSApplication.odin @@ -0,0 +1,95 @@ +package objc_Foundation + +import "core:intrinsics" + +ActivationPolicy :: enum UInteger { + Regular = 0, + Accessory = 1, + Prohibited = 2, +} + +ApplicationDelegate :: struct { + willFinishLaunching: proc "c" (self: ^ApplicationDelegate, notification: ^Notification), + didFinishLaunching: proc "c" (self: ^ApplicationDelegate, notification: ^Notification), + shouldTerminateAfterLastWindowClosed: proc "c" (self: ^ApplicationDelegate, sender: ^Application), + + user_data: rawptr, +} + +@(objc_class="NSApplication") +Application :: struct {using _: Object} + +@(objc_type=Application, objc_name="sharedApplication", objc_is_class_method=true) +Application_sharedApplication :: proc() -> ^Application { + return msgSend(^Application, Application, "sharedApplication") +} + +@(objc_type=Application, objc_name="setDelegate") +Application_setDelegate :: proc(self: ^Application, delegate: ^ApplicationDelegate) { + willFinishLaunching :: proc "c" (self: ^Value, _: SEL, notification: ^Notification) { + del := (^ApplicationDelegate)(self->pointerValue()) + del->willFinishLaunching(notification) + } + didFinishLaunching :: proc "c" (self: ^Value, _: SEL, notification: ^Notification) { + del := (^ApplicationDelegate)(self->pointerValue()) + del->didFinishLaunching(notification) + } + shouldTerminateAfterLastWindowClosed :: proc "c" (self: ^Value, _: SEL, application: ^Application) { + del := (^ApplicationDelegate)(self->pointerValue()) + del->shouldTerminateAfterLastWindowClosed(application) + } + + wrapper := Value.valueWithPointer(delegate) + + class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("applicationWillFinishLaunching:"), auto_cast willFinishLaunching, "v@:@") + class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("applicationDidFinishLaunching:"), auto_cast didFinishLaunching, "v@:@") + class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("applicationShouldTerminateAfterLastWindowClosed:"), auto_cast shouldTerminateAfterLastWindowClosed, "B@:@") + + msgSend(nil, self, "setDelegate:", wrapper) +} + +@(objc_type=Application, objc_name="setActivationPolicy") +Application_setActivationPolicy :: proc(self: ^Application, activationPolicy: ActivationPolicy) -> BOOL { + return msgSend(BOOL, self, "setActivationPolicy:", activationPolicy) +} + +@(objc_type=Application, objc_name="activateIgnoringOtherApps") +Application_activateIgnoringOtherApps :: proc(self: ^Application, ignoreOtherApps: BOOL) { + msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps) +} + +@(objc_type=Application, objc_name="setMainMenu") +Application_setMainMenu :: proc(self: ^Application, menu: ^Menu) { + msgSend(nil, self, "setMainMenu:", menu) +} + +@(objc_type=Application, objc_name="windows") +Application_windows :: proc(self: ^Application) -> ^Array { + return msgSend(^Array, self, "windows") +} + +@(objc_type=Application, objc_name="run") +Application_run :: proc(self: ^Application) { + msgSend(nil, self, "run") +} + + +@(objc_type=Application, objc_name="terminate") +Application_terminate :: proc(self: ^Application, sender: ^Object) { + msgSend(nil, self, "terminate:", sender) +} + + + +@(objc_class="NSRunningApplication") +RunningApplication :: struct {using _: Object} + +@(objc_type=RunningApplication, objc_name="currentApplication", objc_is_class_method=true) +RunningApplication_currentApplication :: proc() -> ^RunningApplication { + return msgSend(^RunningApplication, RunningApplication, "currentApplication") +} + +@(objc_type=RunningApplication, objc_name="localizedName") +RunningApplication_localizedName :: proc(self: ^RunningApplication) -> ^String { + return msgSend(^String, self, "localizedName") +} \ No newline at end of file diff --git a/vendor/darwin/Foundation/NSMenu.odin b/vendor/darwin/Foundation/NSMenu.odin new file mode 100644 index 000000000..964e3061d --- /dev/null +++ b/vendor/darwin/Foundation/NSMenu.odin @@ -0,0 +1,103 @@ +package objc_Foundation + +import "core:builtin" +import "core:intrinsics" + +KeyEquivalentModifierFlag :: enum UInteger { + CapsLock = 16, // Set if Caps Lock key is pressed. + Shift = 17, // Set if Shift key is pressed. + Control = 18, // Set if Control key is pressed. + Option = 19, // Set if Option or Alternate key is pressed. + Command = 20, // Set if Command key is pressed. + NumericPad = 21, // Set if any key in the numeric keypad is pressed. + Help = 22, // Set if the Help key is pressed. + Function = 23, // Set if any function key is pressed. +} +KeyEquivalentModifierMask :: distinct bit_set[KeyEquivalentModifierFlag; UInteger] + +// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information. +KeyEventModifierFlagDeviceIndependentFlagsMask := transmute(KeyEquivalentModifierMask)_KeyEventModifierFlagDeviceIndependentFlagsMask +@(private) _KeyEventModifierFlagDeviceIndependentFlagsMask := UInteger(0xffff0000) + + +MenuItemCallback :: proc "c" (unused: rawptr, name: SEL, sender: ^Object) + + +@(objc_class="NSMenuItem") +MenuItem :: struct {using _: Object} + +@(objc_type=MenuItem, objc_name="alloc", objc_is_class_method=true) +MenuItem_alloc :: proc() -> ^MenuItem { + return msgSend(^MenuItem, MenuItem, "alloc") +} +@(objc_type=MenuItem, objc_name="registerActionCallback", objc_is_class_method=true) +MenuItem_registerActionCallback :: proc(name: cstring, callback: MenuItemCallback) -> SEL { + s := string(name) + n := len(s) + sel: SEL + if n > 0 && s[n-1] != ':' { + col_name := intrinsics.alloca(n+2, 1) + builtin.copy(col_name[:n], s) + col_name[n] = ':' + col_name[n+1] = 0 + sel = sel_registerName(cstring(col_name)) + } else { + sel = sel_registerName(name) + } + if callback != nil { + class_addMethod(intrinsics.objc_find_class("NSObject"), sel, auto_cast callback, "v@:@") + } + return sel +} + +@(objc_type=MenuItem, objc_name="init") +MenuItem_init :: proc(self: ^MenuItem) -> ^MenuItem { + return msgSend(^MenuItem, self, "init") +} + +@(objc_type=MenuItem, objc_name="setKeyEquivalentModifierMask") +MenuItem_setKeyEquivalentModifierMask :: proc(self: ^MenuItem, modifierMask: KeyEquivalentModifierMask) { + msgSend(nil, self, "setKeyEquivalentModifierMask:", modifierMask) +} + +@(objc_type=MenuItem, objc_name="keyEquivalentModifierMask") +MenuItem_keyEquivalentModifierMask :: proc(self: ^MenuItem) -> KeyEquivalentModifierMask { + return msgSend(KeyEquivalentModifierMask, self, "keyEquivalentModifierMask") +} + +@(objc_type=MenuItem, objc_name="setSubmenu") +MenuItem_setSubmenu :: proc(self: ^MenuItem, submenu: ^Menu) { + msgSend(nil, self, "setSubmenu:", submenu) +} + + + + +@(objc_class="NSMenu") +Menu :: struct {using _: Object} + +@(objc_type=Menu, objc_name="alloc", objc_is_class_method=true) +Menu_alloc :: proc() -> ^Menu { + return msgSend(^Menu, Menu, "alloc") +} + +@(objc_type=Menu, objc_name="init") +Menu_init :: proc(self: ^Menu) -> ^Menu { + return msgSend(^Menu, self, "init") +} + +@(objc_type=Menu, objc_name="initWithTitle") +Menu_initWithTitle :: proc(self: ^Menu, title: ^String) -> ^Menu { + return msgSend(^Menu, self, "initWithTitle:", title) +} + + +@(objc_type=Menu, objc_name="addItem") +Menu_addItem :: proc(self: ^Menu, item: ^MenuItem) { + msgSend(nil, self, "addItem:", item) +} + +@(objc_type=Menu, objc_name="addItemWithTitle") +Menu_addItemWithTitle :: proc(self: ^Menu, title: ^String, selector: SEL, keyEquivalent: ^String) -> ^MenuItem { + return msgSend(^MenuItem, self, "addItemWithTitle:action:keyEquivalent:", title, selector, keyEquivalent) +} \ No newline at end of file diff --git a/vendor/darwin/Foundation/NSNumber.odin b/vendor/darwin/Foundation/NSNumber.odin index 9201557a3..d459e673f 100644 --- a/vendor/darwin/Foundation/NSNumber.odin +++ b/vendor/darwin/Foundation/NSNumber.odin @@ -48,17 +48,17 @@ Value_getValue :: proc(self: ^Value, value: rawptr, size: UInteger) { @(objc_type=Value, objc_name="objCType") -Value_objCType :: proc(self: ^Value) -> cstring { +Value_objCType :: proc "c" (self: ^Value) -> cstring { return msgSend(cstring, self, "objCType") } @(objc_type=Value, objc_name="isEqualToValue") -Value_isEqualToValue :: proc(self, other: ^Value) -> BOOL { +Value_isEqualToValue :: proc "c" (self, other: ^Value) -> BOOL { return msgSend(BOOL, self, "isEqualToValue:", other) } @(objc_type=Value, objc_name="pointerValue") -Value_pointerValue :: proc(self: ^Value) -> rawptr { +Value_pointerValue :: proc "c" (self: ^Value) -> rawptr { return msgSend(rawptr, self, "pointerValue") } diff --git a/vendor/darwin/Foundation/NSObject.odin b/vendor/darwin/Foundation/NSObject.odin index 1ce17f2f5..6ec5939ee 100644 --- a/vendor/darwin/Foundation/NSObject.odin +++ b/vendor/darwin/Foundation/NSObject.odin @@ -53,7 +53,10 @@ autorelease :: proc(self: ^Object) { retainCount :: proc(self: ^Object) -> UInteger { return msgSend(UInteger, self, "retainCount") } - +@(objc_type=Object, objc_name="class") +class :: proc(self: ^Object) -> Class { + return msgSend(Class, self, "class") +} @(objc_type=Object, objc_name="hash") hash :: proc(self: ^Object) -> UInteger { diff --git a/vendor/darwin/Foundation/NSString.odin b/vendor/darwin/Foundation/NSString.odin index 45b5df37b..18e392415 100644 --- a/vendor/darwin/Foundation/NSString.odin +++ b/vendor/darwin/Foundation/NSString.odin @@ -49,6 +49,10 @@ StringCompareOption :: enum UInteger { unichar :: distinct u16 +@(link_prefix="NS", default_calling_convention="c") +foreign Foundation { + StringFromClass :: proc(cls: Class) -> ^String --- +} AT :: MakeConstantString MakeConstantString :: proc "c" (#const c: cstring) -> ^String { diff --git a/vendor/darwin/Foundation/NSTypes.odin b/vendor/darwin/Foundation/NSTypes.odin index 47f75630f..ef895d449 100644 --- a/vendor/darwin/Foundation/NSTypes.odin +++ b/vendor/darwin/Foundation/NSTypes.odin @@ -33,3 +33,10 @@ ComparisonResult :: enum Integer { } NotFound :: IntegerMax + +Float :: distinct (f32 when size_of(uint) == 4 else f64) + +Size :: struct { + width: Float, + height: Float, +} \ No newline at end of file diff --git a/vendor/darwin/Foundation/NSWindow.odin b/vendor/darwin/Foundation/NSWindow.odin index dec5a160c..3c7c17023 100644 --- a/vendor/darwin/Foundation/NSWindow.odin +++ b/vendor/darwin/Foundation/NSWindow.odin @@ -7,18 +7,75 @@ Rect :: struct { width, height: f64, } +WindowStyleFlag :: enum NS.UInteger { + Titled = 0, + Closable = 1, + Miniaturizable = 2, + Resizable = 3, + TexturedBackground = 8, + UnifiedTitleAndToolbar = 12, + FullScreen = 14, + FullSizeContentView = 15, + UtilityWindow = 4, + DocModalWindow = 6, + NonactivatingPanel = 7, + HUDWindow = 13, +} +WindowStyleMask :: distinct bit_set[WindowStyleFlag; NS.UInteger] +WindowStyleMaskBorderless :: WindowStyleMask{} +WindowStyleMaskTitled :: WindowStyleMask{.Titled} +WindowStyleMaskClosable :: WindowStyleMask{.Closable} +WindowStyleMaskMiniaturizable :: WindowStyleMask{.Miniaturizable} +WindowStyleMaskResizable :: WindowStyleMask{.Resizable} +WindowStyleMaskTexturedBackground :: WindowStyleMask{.TexturedBackground} +WindowStyleMaskUnifiedTitleAndToolbar :: WindowStyleMask{.UnifiedTitleAndToolbar} +WindowStyleMaskFullScreen :: WindowStyleMask{.FullScreen} +WindowStyleMaskFullSizeContentView :: WindowStyleMask{.FullSizeContentView} +WindowStyleMaskUtilityWindow :: WindowStyleMask{.UtilityWindow} +WindowStyleMaskDocModalWindow :: WindowStyleMask{.DocModalWindow} +WindowStyleMaskNonactivatingPanel :: WindowStyleMask{.NonactivatingPanel} +WindowStyleMaskHUDWindow :: WindowStyleMask{.HUDWindow} + +BackingStoreType :: enum NS.UInteger { + Retained = 0, + Nonretained = 1, + Buffered = 2, +} + @(objc_class="NSColor") Color :: struct {using _: Object} @(objc_class="CALayer") Layer :: struct { using _: NS.Object } +@(objc_type=Layer, objc_name="contentsScale") +Layer_contentsScale :: proc(self: ^Layer) -> Float { + return msgSend(Float, self, "contentsScale") +} +@(objc_type=Layer, objc_name="setContentsScale") +Layer_setContentsScale :: proc(self: ^Layer, scale: Float) { + msgSend(nil, self, "setContentsScale:", scale) +} +@(objc_type=Layer, objc_name="frame") +Layer_frame :: proc(self: ^Layer) -> Rect { + return msgSend(Rect, self, "frame") +} +@(objc_type=Layer, objc_name="addSublayer") +Layer_addSublayer :: proc(self: ^Layer, layer: ^Layer) { + msgSend(nil, self, "addSublayer:", layer) +} + @(objc_class="NSResponder") Responder :: struct {using _: Object} @(objc_class="NSView") View :: struct {using _: Responder} + +@(objc_type=View, objc_name="initWithFrame") +View_initWithFrame :: proc(self: ^View, frame: Rect) -> ^View { + return msgSend(^View, self, "initWithFrame:", frame) +} @(objc_type=View, objc_name="layer") View_layer :: proc(self: ^View) -> ^Layer { return msgSend(^Layer, self, "layer") @@ -27,10 +84,6 @@ View_layer :: proc(self: ^View) -> ^Layer { View_setLayer :: proc(self: ^View, layer: ^Layer) { msgSend(nil, self, "setLayer:", layer) } -@(objc_type=View, objc_name="setSubLayer") -View_setSubLayer :: proc(self: ^View, layer: ^Layer) { - msgSend(nil, self, "setSubLayer:", layer) -} @(objc_type=View, objc_name="wantsLayer") View_wantsLayer :: proc(self: ^View) -> BOOL { return msgSend(BOOL, self, "wantsLayer") @@ -40,14 +93,26 @@ View_setWantsLayer :: proc(self: ^View, wantsLayer: BOOL) { msgSend(nil, self, "setWantsLayer:", wantsLayer) } - @(objc_class="NSWindow") Window :: struct {using _: Responder} +@(objc_type=Window, objc_name="alloc", objc_is_class_method=true) +Window_alloc :: proc() -> ^Window { + return msgSend(^Window, Window, "alloc") +} + +@(objc_type=Window, objc_name="initWithContentRect") +Window_initWithContentRect :: proc(self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: bool) -> ^Window { + return msgSend(^Window, self, "initWithContentRect:styleMask:backing:defer:", contentRect, styleMask, backing, doDefer) +} @(objc_type=Window, objc_name="contentView") Window_contentView :: proc(self: ^Window) -> ^View { return msgSend(^View, self, "contentView") } +@(objc_type=Window, objc_name="setContentView") +Window_setContentView :: proc(self: ^Window, content_view: ^View) { + msgSend(nil, self, "setContentView:", content_view) +} @(objc_type=Window, objc_name="frame") Window_frame :: proc(self: ^Window) -> Rect { return msgSend(Rect, self, "frame") @@ -72,3 +137,15 @@ Window_backgroundColor :: proc(self: ^Window) -> ^NS.Color { Window_setBackgroundColor :: proc(self: ^Window, color: ^NS.Color) { msgSend(nil, self, "setBackgroundColor:", color) } +@(objc_type=Window, objc_name="makeKeyAndOrderFront") +Window_makeKeyAndOrderFront :: proc(self: ^Window, key: ^NS.Object) { + msgSend(nil, self, "makeKeyAndOrderFront:", key) +} +@(objc_type=Window, objc_name="setTitle") +Window_setTitle :: proc(self: ^Window, title: ^NS.String) { + msgSend(nil, self, "setTitle:", title) +} +@(objc_type=Window, objc_name="close") +Window_close :: proc(self: ^Window) { + msgSend(nil, self, "close") +} \ No newline at end of file diff --git a/vendor/darwin/Foundation/objc.odin b/vendor/darwin/Foundation/objc.odin new file mode 100644 index 000000000..7db82df73 --- /dev/null +++ b/vendor/darwin/Foundation/objc.odin @@ -0,0 +1,73 @@ +package objc_Foundation + +foreign import "system:Foundation.framework" + +import "core:intrinsics" +import "core:c" + +IMP :: proc "c" (object: id, sel: SEL, #c_vararg args: ..any) -> id + +foreign Foundation { + objc_lookUpClass :: proc "c" (name: cstring) -> Class --- + sel_registerName :: proc "c" (name: cstring) -> SEL --- + objc_allocateClassPair :: proc "c" (superclass: Class, name: cstring, extraBytes: uint) --- + + class_addMethod :: proc "c" (cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL --- +} + + +@(objc_class="NSZone") +Zone :: struct {using _: Object} + +@(link_prefix="NS") +foreign Foundation { + AllocateObject :: proc "c" (aClass: Class, extraBytes: UInteger, zone: ^Zone) -> id --- + DeallocateObject :: proc "c" (object: id) --- +} + +Method :: ^objc_method +objc_method :: struct { + method_name: SEL, + method_types: cstring, + method_imp: IMP, +} +objc_method_list :: struct {} + +objc_ivar :: struct {} +objc_ivar_list :: struct {} + +objc_cache :: struct { + mask: u32, + occupied: u32, + buckets: [1]Method, +} + +objc_protocol_list :: struct { + next: ^objc_protocol_list, + count: c.int, + list: [1]^Protocol, +} + +@(objc_class="Protocol") +Protocol :: struct{using _: intrinsics.objc_object} + +objc_object_internals :: struct { + isa: ^objc_class_internals, +} + + +objc_class_internals :: struct { + isa: Class, + super_class: Class, + name: cstring, + version: c.long, + info: c.long, + instance_size: c.long, + ivars: ^objc_ivar_list, + + methodLists: ^^objc_method_list, + + cache: rawptr, + protocols: rawptr, + +} \ No newline at end of file diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 56d40f5f2..29653f015 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -4474,16 +4474,16 @@ TextureDescriptor_storageMode :: #force_inline proc(self: ^TextureDescriptor) -> TextureDescriptor_swizzle :: #force_inline proc(self: ^TextureDescriptor) -> TextureSwizzleChannels { return msgSend(TextureSwizzleChannels, self, "swizzle") } -@(objc_type=TextureDescriptor, objc_name="texture2DDescriptor", objc_is_class_method=true) -TextureDescriptor_texture2DDescriptor :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, height: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { +@(objc_type=TextureDescriptor, objc_name="texture2DDescriptorWithPixelFormat", objc_is_class_method=true) +TextureDescriptor_texture2DDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, height: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "texture2DDescriptorWithPixelFormat:width:height:mipmapped:", pixelFormat, width, height, mipmapped) } -@(objc_type=TextureDescriptor, objc_name="textureBufferDescriptor", objc_is_class_method=true) -TextureDescriptor_textureBufferDescriptor :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { +@(objc_type=TextureDescriptor, objc_name="textureBufferDescriptorWithPixelFormat", objc_is_class_method=true) +TextureDescriptor_textureBufferDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, width: NS.UInteger, resourceOptions: ResourceOptions, usage: TextureUsage) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureBufferDescriptorWithPixelFormat:width:resourceOptions:usage:", pixelFormat, width, resourceOptions, usage) } -@(objc_type=TextureDescriptor, objc_name="textureCubeDescriptor", objc_is_class_method=true) -TextureDescriptor_textureCubeDescriptor :: #force_inline proc(pixelFormat: PixelFormat, size: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { +@(objc_type=TextureDescriptor, objc_name="textureCubeDescriptorWithPixelFormat", objc_is_class_method=true) +TextureDescriptor_textureCubeDescriptorWithPixelFormat :: #force_inline proc(pixelFormat: PixelFormat, size: NS.UInteger, mipmapped: BOOL) -> ^TextureDescriptor { return msgSend(^TextureDescriptor, TextureDescriptor, "textureCubeDescriptorWithPixelFormat:size:mipmapped:", pixelFormat, size, mipmapped) } @(objc_type=TextureDescriptor, objc_name="textureType") @@ -7683,7 +7683,7 @@ RenderCommandEncoder_drawPrimitivesWithInstanceCount :: #force_inline proc(self: msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:", primitiveType, vertexStart, vertexCount, instanceCount) } @(objc_type=RenderCommandEncoder, objc_name="drawPrimitivesWithInstances") -RenderCommandEncoder_drawPrimitivesWithInstance :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { +RenderCommandEncoder_drawPrimitivesWithInstances :: #force_inline proc(self: ^RenderCommandEncoder, primitiveType: PrimitiveType, vertexStart: NS.UInteger, vertexCount: NS.UInteger, instanceCount: NS.UInteger, baseInstance: NS.UInteger) { msgSend(nil, self, "drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:", primitiveType, vertexStart, vertexCount, instanceCount, baseInstance) } @(objc_type=RenderCommandEncoder, objc_name="executeCommandsInBuffer") diff --git a/vendor/darwin/MetalKit/MetalKit.odin b/vendor/darwin/MetalKit/MetalKit.odin new file mode 100644 index 000000000..90d147983 --- /dev/null +++ b/vendor/darwin/MetalKit/MetalKit.odin @@ -0,0 +1,259 @@ +package objc_MetalKit + +import NS "vendor:darwin/Foundation" +import MTL "vendor:darwin/Metal" +import CA "vendor:darwin/QuartzCore" +import "core:intrinsics" + +@(require) +foreign import "system:MetalKit.framework" + +@(private) +msgSend :: intrinsics.objc_send + +ColorSpaceRef :: struct {} + +ViewDelegate :: struct { + drawInMTKView: proc "c" (self: ^ViewDelegate, view: ^View), + drawableSizeWillChange: proc "c" (self: ^ViewDelegate, view: ^View, size: NS.Size), + + user_data: rawptr, +} + +@(objc_class="MTKView") +View :: struct {using _: NS.View} + +@(objc_type=View, objc_name="alloc", objc_is_class_method=true) +View_alloc :: proc() -> ^View { + return msgSend(^View, View, "alloc") +} +@(objc_type=View, objc_name="initWithFrame") +View_initWithFrame :: proc(self: ^View, frame: NS.Rect, device: ^MTL.Device) -> ^View { + return msgSend(^View, self, "initWithFrame:device:", frame, device) +} +@(objc_type=View, objc_name="initWithCoder") +View_initWithCoder :: proc(self: ^View, coder: ^NS.Coder) -> ^View { + return msgSend(^View, self, "initWithCoder:", coder) +} + +@(objc_type=View, objc_name="setDevice") +View_setDevice :: proc(self: ^View, device: ^MTL.Device) { + msgSend(nil, self, "setDevice:", device) +} +@(objc_type=View, objc_name="device") +View_device :: proc(self: ^View) -> ^MTL.Device { + return msgSend(^MTL.Device, self, "device") +} + +@(objc_type=View, objc_name="draw") +View_draw :: proc(self: ^View) { + msgSend(nil, self, "draw") +} + +@(objc_type=View, objc_name="setDelegate") +View_setDelegate :: proc(self: ^View, delegate: ^ViewDelegate) { + drawDispatch :: proc "c" (self: ^NS.Value, cmd: NS.SEL, view: ^View) { + del := (^ViewDelegate)(self->pointerValue()) + del->drawInMTKView(view) + } + drawableSizeWillChange :: proc "c" (self: ^NS.Value, cmd: NS.SEL, view: ^View, size: NS.Size) { + del := (^ViewDelegate)(self->pointerValue()) + del->drawableSizeWillChange(view, size) + } + + wrapper := NS.Value.valueWithPointer(delegate) + + NS.class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("drawInMTKView:"), auto_cast drawDispatch, "v@:@") + + cbparams :: "v@:@{CGSize=ff}" when size_of(NS.Float) == size_of(f32) else "v@:@{CGSize=dd}" + NS.class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("mtkView:drawableSizeWillChange:"), auto_cast drawableSizeWillChange, cbparams) + + msgSend(nil, self, "setDelegate:", wrapper) +} + +@(objc_type=View, objc_name="delegate") +View_delegate :: proc(self: ^View) -> ^ViewDelegate { + wrapper := msgSend(^NS.Value, self, "delegate") + if wrapper != nil { + return (^ViewDelegate)(wrapper->pointerValue()) + } + return nil +} + +@(objc_type=View, objc_name="currentDrawable") +View_currentDrawable :: proc(self: ^View) -> ^CA.MetalDrawable { + return msgSend(^CA.MetalDrawable, self, "currentDrawable") +} + +@(objc_type=View, objc_name="setFramebufferOnly") +View_setFramebufferOnly :: proc(self: ^View, framebufferOnly: bool) { + msgSend(nil, self, "setFramebufferOnly:", framebufferOnly) +} +@(objc_type=View, objc_name="framebufferOnly") +View_framebufferOnly :: proc(self: ^View) -> bool { + return msgSend(bool, self, "framebufferOnly") +} + +@(objc_type=View, objc_name="setDepthStencilAttachmentTextureUsage") +View_setDepthStencilAttachmentTextureUsage :: proc(self: ^View, textureUsage: MTL.TextureUsage) { + msgSend(nil, self, "setDepthStencilAttachmentTextureUsage:", textureUsage) +} +@(objc_type=View, objc_name="depthStencilAttachmentTextureUsage") +View_depthStencilAttachmentTextureUsage :: proc(self: ^View) -> MTL.TextureUsage { + return msgSend(MTL.TextureUsage, self, "depthStencilAttachmentTextureUsage") +} + +@(objc_type=View, objc_name="setMultisampleColorAttachmentTextureUsage") +View_setMultisampleColorAttachmentTextureUsage :: proc(self: ^View, textureUsage: MTL.TextureUsage) { + msgSend(nil, self, "setMultisampleColorAttachmentTextureUsage:", textureUsage) +} +@(objc_type=View, objc_name="multisampleColorAttachmentTextureUsage") +View_multisampleColorAttachmentTextureUsage :: proc(self: ^View) -> MTL.TextureUsage { + return msgSend(MTL.TextureUsage, self, "multisampleColorAttachmentTextureUsage") +} + +@(objc_type=View, objc_name="setPresentsWithTransaction") +View_setPresentsWithTransaction :: proc(self: ^View, presentsWithTransaction: bool) { + msgSend(nil, self, "setPresentsWithTransaction:", presentsWithTransaction) +} +@(objc_type=View, objc_name="presentsWithTransaction") +View_presentsWithTransaction :: proc(self: ^View) -> bool { + return msgSend(bool, self, "presentsWithTransaction") +} + +@(objc_type=View, objc_name="setColorPixelFormat") +View_setColorPixelFormat :: proc(self: ^View, colorPixelFormat: MTL.PixelFormat) { + msgSend(nil, self, "setColorPixelFormat:", colorPixelFormat) +} +@(objc_type=View, objc_name="colorPixelFormat") +View_colorPixelFormat :: proc(self: ^View) -> MTL.PixelFormat { + return msgSend(MTL.PixelFormat, self, "colorPixelFormat") +} + +@(objc_type=View, objc_name="setDepthStencilPixelFormat") +View_setDepthStencilPixelFormat :: proc(self: ^View, colorPixelFormat: MTL.PixelFormat) { + msgSend(nil, self, "setDepthStencilPixelFormat:", colorPixelFormat) +} +@(objc_type=View, objc_name="depthStencilPixelFormat") +View_depthStencilPixelFormat :: proc(self: ^View) -> MTL.PixelFormat { + return msgSend(MTL.PixelFormat, self, "depthStencilPixelFormat") +} + +@(objc_type=View, objc_name="setSampleCount") +View_setSampleCount :: proc(self: ^View, sampleCount: NS.UInteger) { + msgSend(nil, self, "setSampleCount:", sampleCount) +} +@(objc_type=View, objc_name="sampleCount") +View_sampleCount :: proc(self: ^View) -> NS.UInteger { + return msgSend(NS.UInteger, self, "sampleCount") +} + +@(objc_type=View, objc_name="setClearColor") +View_setClearColor :: proc(self: ^View, clearColor: MTL.ClearColor) { + msgSend(nil, self, "setClearColor:", clearColor) +} +@(objc_type=View, objc_name="clearColor") +View_clearColor :: proc(self: ^View) -> MTL.ClearColor { + return msgSend(MTL.ClearColor, self, "clearColor") +} + +@(objc_type=View, objc_name="setClearDepth") +View_setClearDepth :: proc(self: ^View, clearDepth: f64) { + msgSend(nil, self, "setClearDepth:", clearDepth) +} +@(objc_type=View, objc_name="clearDepth") +View_clearDepth :: proc(self: ^View) -> f64 { + return msgSend(f64, self, "clearDepth") +} + +@(objc_type=View, objc_name="setClearStencil") +View_setClearStencil :: proc(self: ^View, clearStencil: u32) { + msgSend(nil, self, "setClearStencil:", clearStencil) +} +@(objc_type=View, objc_name="clearStencil") +View_clearStencil :: proc(self: ^View) -> u32 { + return msgSend(u32, self, "clearStencil") +} + +@(objc_type=View, objc_name="depthStencilTexture") +View_depthStencilTexture :: proc(self: ^View) -> ^MTL.Texture { + return msgSend(^MTL.Texture, self, "depthStencilTexture") +} +@(objc_type=View, objc_name="multisampleColorTexture") +View_multisampleColorTexture :: proc(self: ^View) -> ^MTL.Texture { + return msgSend(^MTL.Texture, self, "multisampleColorTexture") +} + +@(objc_type=View, objc_name="releaseDrawables") +View_releaseDrawables :: proc(self: ^View) { + msgSend(nil, self, "releaseDrawables") +} + +@(objc_type=View, objc_name="currentRenderPassDescriptor") +View_currentRenderPassDescriptor :: proc(self: ^View) -> ^MTL.RenderPassDescriptor { + return msgSend(^MTL.RenderPassDescriptor, self, "currentRenderPassDescriptor") +} + +@(objc_type=View, objc_name="setPreferredFramesPerSecond") +View_setPreferredFramesPerSecond :: proc(self: ^View, preferredFramesPerSecond: NS.Integer) { + msgSend(nil, self, "setPreferredFramesPerSecond:", preferredFramesPerSecond) +} +@(objc_type=View, objc_name="preferredFramesPerSecond") +View_preferredFramesPerSecond :: proc(self: ^View) -> NS.Integer { + return msgSend(NS.Integer, self, "preferredFramesPerSecond") +} + +@(objc_type=View, objc_name="setEnableSetNeedsDisplay") +View_setEnableSetNeedsDisplay :: proc(self: ^View, enableSetNeedsDisplay: bool) { + msgSend(nil, self, "setEnableSetNeedsDisplay:", enableSetNeedsDisplay) +} +@(objc_type=View, objc_name="enableSetNeedsDisplay") +View_enableSetNeedsDisplay :: proc(self: ^View) -> bool { + return msgSend(bool, self, "enableSetNeedsDisplay") +} + +@(objc_type=View, objc_name="setAutoresizeDrawable") +View_setAutoresizeDrawable :: proc(self: ^View, autoresizeDrawable: bool) { + msgSend(nil, self, "setAutoresizeDrawable:", autoresizeDrawable) +} +@(objc_type=View, objc_name="autoresizeDrawable") +View_autoresizeDrawable :: proc(self: ^View) -> bool { + return msgSend(bool, self, "autoresizeDrawable") +} + +@(objc_type=View, objc_name="setDrawableSize") +View_setDrawableSize :: proc(self: ^View, drawableSize: NS.Size) { + msgSend(nil, self, "setDrawableSize:", drawableSize) +} +@(objc_type=View, objc_name="drawableSize") +View_drawableSize :: proc(self: ^View) -> NS.Size { + return msgSend(NS.Size, self, "drawableSize") +} + +@(objc_type=View, objc_name="preferredDrawableSize") +View_preferredDrawableSize :: proc(self: ^View) -> NS.Size { + return msgSend(NS.Size, self, "preferredDrawableSize") +} + +@(objc_type=View, objc_name="preferredDevice") +View_preferredDevice :: proc(self: ^View) -> ^MTL.Device { + return msgSend(^MTL.Device, self, "preferredDevice") +} + +@(objc_type=View, objc_name="setPaused") +View_setPaused :: proc(self: ^View, isPaused: bool) { + msgSend(nil, self, "setPaused:", isPaused) +} +@(objc_type=View, objc_name="isPaused") +View_isPaused :: proc(self: ^View) -> bool { + return msgSend(bool, self, "isPaused") +} + +@(objc_type=View, objc_name="setColorSpace") +View_setColorSpace :: proc(self: ^View, colorSpace: ColorSpaceRef) { + msgSend(nil, self, "setColorSpace:", colorSpace) +} +@(objc_type=View, objc_name="colorSpace") +View_colorSpace :: proc(self: ^View) -> ColorSpaceRef { + return msgSend(ColorSpaceRef, self, "colorSpace") +} From 8a9f7fc684b39c803cab184344a8a017308ed63a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Apr 2022 15:09:03 +0100 Subject: [PATCH 0528/1052] Fix #1713 --- src/check_expr.cpp | 5 ++++- src/exact_value.cpp | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index dcf17af39..336a711d4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8161,7 +8161,10 @@ ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type * case Type_Basic: { if (!is_type_any(t)) { if (cl->elems.count != 0) { - error(node, "Illegal compound literal"); + gbString s = type_to_string(t); + error(node, "Illegal compound literal, %s cannot be used as a compound literal with fields", s); + gb_string_free(s); + is_constant = false; } break; } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index f6df48951..cedef48c4 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -591,6 +591,7 @@ failure: i32 exact_value_order(ExactValue const &v) { switch (v.kind) { case ExactValue_Invalid: + case ExactValue_Compound: return 0; case ExactValue_Bool: case ExactValue_String: @@ -607,8 +608,6 @@ i32 exact_value_order(ExactValue const &v) { return 6; case ExactValue_Procedure: return 7; - // case ExactValue_Compound: - // return 8; default: GB_PANIC("How'd you get here? Invalid Value.kind %d", v.kind); From e53c85885559144f3273cfa13a10c6531787d173 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Apr 2022 15:47:49 +0100 Subject: [PATCH 0529/1052] Add NS.Block to allow for the creation of block-like lambdas in Odin --- vendor/darwin/Foundation/block_literal.odin | 67 +++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 vendor/darwin/Foundation/block_literal.odin diff --git a/vendor/darwin/Foundation/block_literal.odin b/vendor/darwin/Foundation/block_literal.odin new file mode 100644 index 000000000..19e9782e4 --- /dev/null +++ b/vendor/darwin/Foundation/block_literal.odin @@ -0,0 +1,67 @@ +package objc_Foundation + +import "core:intrinsics" + +Internal_Block_Literal_Base :: struct { + isa: ^intrinsics.objc_class, + flags: u32, + reserved: u32, + invoke: proc "c" (^Internal_Block_Literal), + descriptor: ^Block_Descriptor, +} + +Internal_Block_Literal :: struct { + using base: Internal_Block_Literal_Base, + // Imported Variables + user_proc: proc "c" (user_data: rawptr), + user_data: rawptr, +} + +Block_Descriptor :: struct { + reserved: uint, + size: uint, + copy_helper: proc "c" (dst, src: rawptr), + dispose_helper: proc "c" (src: rawptr), + signature: cstring, +} + +global_block_descriptor := Block_Descriptor{ + reserved = 0, + size = size_of(Internal_Block_Literal), +} + + +@(objc_class="NSConcreteGlobalBlock") +Block :: struct {using _: Object} + +@(objc_type=Block, objc_name="create", objc_is_class_method=true) +Block_create :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { + // Set to true on blocks that have captures (and thus are not true + // global blocks) but are known not to escape for various other + // reasons. For backward compatibility with old runtimes, whenever + // BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a + // non-escaping block returns the original block and releasing such a + // block is a no-op, which is exactly how global blocks are handled. + BLOCK_IS_NOESCAPE :: (1 << 23)|BLOCK_IS_GLOBAL + + BLOCK_HAS_COPY_DISPOSE :: 1 << 25 + BLOCK_HAS_CTOR :: 1 << 26 // helpers have C++ code + BLOCK_IS_GLOBAL :: 1 << 28 + BLOCK_HAS_STRET :: 1 << 29 // IFF BLOCK_HAS_SIGNATURE + BLOCK_HAS_SIGNATURE :: 1 << 30 + + extraBytes :: size_of(Internal_Block_Literal) - size_of(Internal_Block_Literal_Base) + + cls := intrinsics.objc_find_class("NSConcreteGlobalBlock") + bl := (^Internal_Block_Literal)(AllocateObject(cls, extraBytes, nil)) + bl.isa = cls + bl.flags = BLOCK_IS_GLOBAL + bl.invoke = proc "c" (bl: ^Internal_Block_Literal) { + bl.user_proc(bl.user_data) + } + bl.descriptor = &global_block_descriptor + bl.user_proc = user_proc + bl.user_data = user_data + + return auto_cast bl +} From 0d621511e582ccba60cb9c7c0d59fcfc88d4f9c4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Apr 2022 16:16:53 +0100 Subject: [PATCH 0530/1052] Correct signature types --- vendor/darwin/Metal/MetalClasses.odin | 28 +++++++++++++-------------- vendor/darwin/Metal/MetalTypes.odin | 16 +++++++-------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 29653f015..f91d5f112 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -6490,35 +6490,35 @@ Device_newCommandQueueWithMaxCommandBufferCount :: #force_inline proc(self: ^Dev return msgSend(^CommandQueue, self, "newCommandQueueWithMaxCommandBufferCount:", maxCommandBufferCount) } @(objc_type=Device, objc_name="newComputePipelineStateWithDescriptorWithCompletionHandler") -Device_newComputePipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { - msgSend(nil, self, "newComputePipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) +Device_newComputePipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "newComputePipelineStateWithDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithDescriptorWithReflection") -Device_newComputePipelineStateWithDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newComputePipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) +Device_newComputePipelineStateWithDescriptorWithReflection :: #force_inline proc(self: ^Device, descriptor: ^ComputePipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (res: ^ComputePipelineState, error: ^NS.Error) { + res = msgSend(^ComputePipelineState, self, "newComputePipelineStateWithDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } @(objc_type=Device, objc_name="newComputePipelineStateWithFunctionWithCompletionHandler") -Device_newComputePipelineStateWithFunctionWithCompletionHandler :: #force_inline proc(self: ^Device, computeFunction: ^Function, completionHandler: NewComputePipelineStateCompletionHandler) { - msgSend(nil, self, "newComputePipelineStateWithFunction:completionHandler:", computeFunction, completionHandler) +Device_newComputePipelineStateWithFunctionWithCompletionHandler :: #force_inline proc(self: ^Device, computeFunction: ^Function, completionHandler: NewComputePipelineStateCompletionHandler) -> ^ComputePipelineState { + return msgSend(^ComputePipelineState, self, "newComputePipelineStateWithFunction:completionHandler:", computeFunction, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunction") -Device_newComputePipelineStateWithFunction :: #force_inline proc(self: ^Device, computeFunction: ^Function) -> (res: ^Device, error: ^NS.Error) { - res = msgSend(^Device, self, "newComputePipelineStateWithFunction:error:", computeFunction, &error) +Device_newComputePipelineStateWithFunction :: #force_inline proc(self: ^Device, computeFunction: ^Function) -> (res: ^ComputePipelineState, error: ^NS.Error) { + res = msgSend(^ComputePipelineState, self, "newComputePipelineStateWithFunction:error:", computeFunction, &error) return } @(objc_type=Device, objc_name="newComputePipelineStateWithFunctionWithOptionsAndCompletionHandler") -Device_newComputePipelineStateWithFunctionWithOptionsAndCompletionHandler :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) { - msgSend(nil, self, "newComputePipelineStateWithFunction:options:completionHandler:", computeFunction, options, completionHandler) +Device_newComputePipelineStateWithFunctionWithOptionsAndCompletionHandler :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, completionHandler: NewComputePipelineStateWithReflectionCompletionHandler) -> (res: ^ComputePipelineState) { + return msgSend(^ComputePipelineState, self, "newComputePipelineStateWithFunction:options:completionHandler:", computeFunction, options, completionHandler) } @(objc_type=Device, objc_name="newComputePipelineStateWithFunctionWithReflection") -Device_newComputePipelineStateWithFunctionWithReflection :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, &error) +Device_newComputePipelineStateWithFunctionWithReflection :: #force_inline proc(self: ^Device, computeFunction: ^Function, options: PipelineOption, reflection: ^AutoreleasedComputePipelineReflection) -> (res: ^ComputePipelineState, error: ^NS.Error) { + res = msgSend(^ComputePipelineState, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, &error) return } @(objc_type=Device, objc_name="newCounterSampleBuffer") -Device_newCounterSampleBuffer :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor) -> (device: ^Device, error: ^NS.Error) { - device = msgSend(^Device, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, &error) +Device_newCounterSampleBuffer :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor) -> (counter: ^Counter, error: ^NS.Error) { + counter = msgSend(^Counter, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, &error) return } @(objc_type=Device, objc_name="newDefaultLibrary") diff --git a/vendor/darwin/Metal/MetalTypes.odin b/vendor/darwin/Metal/MetalTypes.odin index 673769c09..cc9d25ca0 100644 --- a/vendor/darwin/Metal/MetalTypes.odin +++ b/vendor/darwin/Metal/MetalTypes.odin @@ -184,16 +184,16 @@ Viewport :: struct { Timestamp :: distinct u64 -DeviceNotificationHandler :: distinct rawptr +DeviceNotificationHandler :: ^NS.Block AutoreleasedComputePipelineReflection :: ^ComputePipelineReflection AutoreleasedRenderPipelineReflection :: ^RenderPipelineReflection -NewLibraryCompletionHandler :: distinct rawptr -NewRenderPipelineStateCompletionHandler :: distinct rawptr -NewRenderPipelineStateWithReflectionCompletionHandler :: distinct rawptr -NewComputePipelineStateCompletionHandler :: distinct rawptr -NewComputePipelineStateWithReflectionCompletionHandler :: distinct rawptr -SharedEventNotificationBlock :: distinct rawptr +NewLibraryCompletionHandler :: ^NS.Block +NewRenderPipelineStateCompletionHandler :: ^NS.Block +NewRenderPipelineStateWithReflectionCompletionHandler :: ^NS.Block +NewComputePipelineStateCompletionHandler :: ^NS.Block +NewComputePipelineStateWithReflectionCompletionHandler :: ^NS.Block +SharedEventNotificationBlock :: ^NS.Block -DrawablePresentedHandler :: distinct rawptr +DrawablePresentedHandler :: ^NS.Block AutoreleasedArgument :: ^Argument \ No newline at end of file From ea0b02d9b95fd445f94ff96d94fae78332aa701c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Apr 2022 16:42:24 +0100 Subject: [PATCH 0531/1052] Add Buffer contentsAsSlice and contentsAsType --- vendor/darwin/Metal/MetalClasses.odin | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index f91d5f112..38a7267b9 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -5495,6 +5495,17 @@ Buffer_contents :: #force_inline proc(self: ^Buffer) -> []byte { Buffer_contentsPointer :: #force_inline proc(self: ^Buffer) -> rawptr { return msgSend(rawptr, self, "contents") } +@(objc_type=Buffer, objc_name="contentsAsSlice") +Buffer_contentsAsSlice :: #force_inline proc(self: ^Buffer, $T: typeid/[]$E) -> T { + contents := msgSend([^]byte, self, "contents") + length := Buffer_length(self) + return mem.slice_data_cast(T, contents[:length]) +} +@(objc_type=Buffer, objc_name="contentsAsType") +Buffer_contentsAsType :: #force_inline proc(self: ^Buffer, $T: typeid, offset: uintptr = 0) -> ^T { + ptr := msgSend(rawptr, self, "contents") + return (^T)(uintptr(ptr) + offset) +} @(objc_type=Buffer, objc_name="didModifyRange") Buffer_didModifyRange :: #force_inline proc(self: ^Buffer, range: NS.Range) { msgSend(nil, self, "didModifyRange:", range) From 9a2d9002e6de463fb6809d89d91b5b9959b748d1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Apr 2022 11:14:59 +0100 Subject: [PATCH 0532/1052] Minor fixes and add use of proc groups where better suited --- vendor/darwin/Metal/MetalClasses.odin | 44 +++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 38a7267b9..c039510c6 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -6442,12 +6442,12 @@ Device_maxTransferRate :: #force_inline proc(self: ^Device) -> u64 { return msgSend(u64, self, "maxTransferRate") } @(objc_type=Device, objc_name="minimumLinearTextureAlignmentForPixelFormat") -Device_minimumLinearTextureAlignmentForPixelFormat :: #force_inline proc(self: ^Device, format: PixelFormat) -> ^Device { - return msgSend(^Device, self, "minimumLinearTextureAlignmentForPixelFormat:", format) +Device_minimumLinearTextureAlignmentForPixelFormat :: #force_inline proc(self: ^Device, format: PixelFormat) -> NS.UInteger { + return msgSend(NS.UInteger, self, "minimumLinearTextureAlignmentForPixelFormat:", format) } @(objc_type=Device, objc_name="minimumTextureBufferAlignmentForPixelFormat") -Device_minimumTextureBufferAlignmentForPixelFormat :: #force_inline proc(self: ^Device, format: PixelFormat) -> ^Device { - return msgSend(^Device, self, "minimumTextureBufferAlignmentForPixelFormat:", format) +Device_minimumTextureBufferAlignmentForPixelFormat :: #force_inline proc(self: ^Device, format: PixelFormat) -> NS.UInteger { + return msgSend(NS.UInteger, self, "minimumTextureBufferAlignmentForPixelFormat:", format) } @(objc_type=Device, objc_name="name") Device_name :: #force_inline proc(self: ^Device) -> ^NS.String { @@ -6527,6 +6527,17 @@ Device_newComputePipelineStateWithFunctionWithReflection :: #force_inline proc(s res = msgSend(^ComputePipelineState, self, "newComputePipelineStateWithFunction:options:reflection:error:", computeFunction, options, reflection, &error) return } + +@(objc_type=Device, objc_name="newComputePipelineState") +Device_newComputePipelineState :: proc{ + Device_newComputePipelineStateWithDescriptorWithCompletionHandler, + Device_newComputePipelineStateWithDescriptorWithReflection, + Device_newComputePipelineStateWithFunctionWithCompletionHandler, + Device_newComputePipelineStateWithFunction, + Device_newComputePipelineStateWithFunctionWithOptionsAndCompletionHandler, + Device_newComputePipelineStateWithFunctionWithReflection, +} + @(objc_type=Device, objc_name="newCounterSampleBuffer") Device_newCounterSampleBuffer :: #force_inline proc(self: ^Device, descriptor: ^CounterSampleBufferDescriptor) -> (counter: ^Counter, error: ^NS.Error) { counter = msgSend(^Counter, self, "newCounterSampleBufferWithDescriptor:error:", descriptor, &error) @@ -6595,6 +6606,16 @@ Device_newLibraryWithURL :: #force_inline proc(self: ^Device, url: ^NS.URL) -> ( library = msgSend(^Library, self, "newLibraryWithURL:error:", url, &error) return } +@(objc_type=Device, objc_name="newLibrary") +Device_newLibrary :: proc{ + Device_newLibraryWithData, + Device_newLibraryWithFile, + Device_newLibraryWithSourceWithCompletionHandler, + Device_newLibraryWithSource, + Device_newLibraryWithURL, +} + + @(objc_type=Device, objc_name="newRasterizationRateMap") Device_newRasterizationRateMap :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMap { return msgSend(^RasterizationRateMap, self, "newRasterizationRateMapWithDescriptor:", descriptor) @@ -6603,8 +6624,8 @@ Device_newRasterizationRateMap :: #force_inline proc(self: ^Device, descriptor: Device_newRenderPipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) -> ^RenderPipelineState { return msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) } -@(objc_type=Device, objc_name="newRenderPipelineState") -Device_newRenderPipelineState :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { +@(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptor") +Device_newRenderPipelineStateWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor) -> (pipeline: ^RenderPipelineState, error: ^NS.Error) { pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:error:", descriptor, &error) return } @@ -6626,6 +6647,17 @@ Device_newRenderPipelineStateWithTileDescriptorWithReflection :: #force_inline p pipeline = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithTileDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } +@(objc_type=Device, objc_name="newRenderPipelineState") +Device_newRenderPipelineState :: proc{ + Device_newRenderPipelineStateWithDescriptorWithCompletionHandler, + Device_newRenderPipelineStateWithDescriptor, + Device_newRenderPipelineStateWithDescriptorWithOptionsAndCompletionHandler, + Device_newRenderPipelineStateWithDescriptorWithReflection, + Device_newRenderPipelineStateWithTileDescriptorWithCompletionHandler, + Device_newRenderPipelineStateWithTileDescriptorWithReflection, +} + + @(objc_type=Device, objc_name="newSamplerState") Device_newSamplerState :: #force_inline proc(self: ^Device, descriptor: ^SamplerDescriptor) -> ^SamplerState { return msgSend(^SamplerState, self, "newSamplerStateWithDescriptor:", descriptor) From cfeb16f917eafc987a00c4726322e3664c34ce02 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Apr 2022 11:20:42 +0100 Subject: [PATCH 0533/1052] Add more proc groups --- vendor/darwin/Metal/MetalClasses.odin | 65 +++++++++++++++++++++------ 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index c039510c6..c30fde95c 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -1152,6 +1152,12 @@ CaptureManager_newCaptureScopeWithCommandQueue :: #force_inline proc(self: ^Capt CaptureManager_newCaptureScopeWithDevice :: #force_inline proc(self: ^CaptureManager, device: ^Device) -> ^CaptureScope { return msgSend(^CaptureScope, self, "newCaptureScopeWithDevice:", device) } +@(objc_type=CaptureManager, objc_name="newCaptureScope") +CaptureManager_newCaptureScope :: proc{ + CaptureManager_newCaptureScopeWithCommandQueue, + CaptureManager_newCaptureScopeWithDevice, +} + @(objc_type=CaptureManager, objc_name="setDefaultCaptureScope") CaptureManager_setDefaultCaptureScope :: #force_inline proc(self: ^CaptureManager, defaultCaptureScope: ^CaptureScope) { msgSend(nil, self, "setDefaultCaptureScope:", defaultCaptureScope) @@ -6670,22 +6676,34 @@ Device_newSharedEvent :: #force_inline proc(self: ^Device) -> ^SharedEvent { Device_newSharedEventWithHandle :: #force_inline proc(self: ^Device, sharedEventHandle: ^SharedEventHandle) -> ^SharedEvent { return msgSend(^SharedEvent, self, "newSharedEventWithHandle:", sharedEventHandle) } -@(objc_type=Device, objc_name="newSharedTexture") -Device_newSharedTexture :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^SharedEvent { +@(objc_type=Device, objc_name="newSharedTextureWithDescriptor") +Device_newSharedTextureWithDescriptor :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor) -> ^SharedEvent { return msgSend(^SharedEvent, self, "newSharedTextureWithDescriptor:", descriptor) } @(objc_type=Device, objc_name="newSharedTextureWithHandle") Device_newSharedTextureWithHandle :: #force_inline proc(self: ^Device, sharedHandle: ^SharedTextureHandle) -> ^SharedEvent { return msgSend(^SharedEvent, self, "newSharedTextureWithHandle:", sharedHandle) } -@(objc_type=Device, objc_name="newTexture") -Device_newTexture :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^Texture { +@(objc_type=Device, objc_name="newSharedTexture") +Device_newSharedTexture :: proc{ + Device_newSharedTextureWithDescriptor, + Device_newSharedTextureWithHandle, +} + +@(objc_type=Device, objc_name="newTextureWithDescriptor") +Device_newTextureWithDescriptor :: #force_inline proc(self: ^Device, desc: ^TextureDescriptor) -> ^Texture { return msgSend(^Texture, self, "newTextureWithDescriptor:", desc) } @(objc_type=Device, objc_name="newTextureWithIOSurface") Device_newTextureWithIOSurface :: #force_inline proc(self: ^Device, descriptor: ^TextureDescriptor, iosurface: IOSurfaceRef, plane: NS.UInteger) -> ^Texture { return msgSend(^Texture, self, "newTextureWithDescriptor:iosurface:plane:", descriptor, iosurface, plane) } +@(objc_type=Device, objc_name="newTexture") +Device_newTexture :: proc{ + Device_newTextureWithDescriptor, + Device_newTextureWithIOSurface, +} + @(objc_type=Device, objc_name="peerCount") Device_peerCount :: #force_inline proc(self: ^Device) -> u32 { return msgSend(u32, self, "peerCount") @@ -7147,22 +7165,34 @@ Heap_label :: #force_inline proc(self: ^Heap) -> ^NS.String { Heap_maxAvailableSizeWithAlignment :: #force_inline proc(self: ^Heap, alignment: NS.UInteger) -> NS.UInteger { return msgSend(NS.UInteger, self, "maxAvailableSizeWithAlignment:", alignment) } -@(objc_type=Heap, objc_name="newBuffer") -Heap_newBuffer :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { +@(objc_type=Heap, objc_name="newBufferWithLength") +Heap_newBufferWithLength :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { return msgSend(^Buffer, self, "newBufferWithLength:options:", length, options) } @(objc_type=Heap, objc_name="newBufferWithOptions") Heap_newBufferWithOptions :: #force_inline proc(self: ^Heap, length: NS.UInteger, options: ResourceOptions, offset: NS.UInteger) -> ^Buffer { return msgSend(^Buffer, self, "newBufferWithLength:options:offset:", length, options, offset) } -@(objc_type=Heap, objc_name="newTexture") -Heap_newTexture :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Texture { +@(objc_type=Heap, objc_name="newBuffer") +Heap_newBuffer :: proc{ + Heap_newBufferWithLength, + Heap_newBufferWithOptions, +} + +@(objc_type=Heap, objc_name="newTextureWithDescriptor") +Heap_newTextureWithDescriptor :: #force_inline proc(self: ^Heap, desc: ^TextureDescriptor) -> ^Texture { return msgSend(^Texture, self, "newTextureWithDescriptor:", desc) } -@(objc_type=Heap, objc_name="newTextureWithOffset") -Heap_newTextureWithOffset :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Texture { +@(objc_type=Heap, objc_name="newTextureWithDescriptorAndOffset") +Heap_newTextureWithDescriptorAndOffset :: #force_inline proc(self: ^Heap, descriptor: ^TextureDescriptor, offset: NS.UInteger) -> ^Texture { return msgSend(^Texture, self, "newTextureWithDescriptor:offset:", descriptor, offset) } +@(objc_type=Heap, objc_name="newTexture") +Heap_newTexture :: proc{ + Heap_newTextureWithDescriptor, + Heap_newTextureWithDescriptorAndOffset, +} + @(objc_type=Heap, objc_name="resourceOptions") Heap_resourceOptions :: #force_inline proc(self: ^Heap) -> ResourceOptions { return msgSend(ResourceOptions, self, "resourceOptions") @@ -7431,7 +7461,7 @@ Library_label :: #force_inline proc(self: ^Library) -> ^NS.String { return msgSend(^NS.String, self, "label") } @(objc_type=Library, objc_name="newFunctionWithCompletionHandler") -Library_newFunctionWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: rawptr) -> ^Function { +Library_newFunctionWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^FunctionDescriptor, completionHandler: ^NS.Block) -> ^Function { return msgSend(^Function, self, "newFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithDescriptor") @@ -7444,7 +7474,7 @@ Library_newFunctionWithName :: #force_inline proc(self: ^Library, functionName: return msgSend(^Function, self, "newFunctionWithName:", functionName) } @(objc_type=Library, objc_name="newFunctionWithConstantValuesAndCompletionHandler") -Library_newFunctionWithConstantValuesAndCompletionHandler :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: rawptr) -> ^Function { +Library_newFunctionWithConstantValuesAndCompletionHandler :: #force_inline proc(self: ^Library, name: ^NS.String, constantValues: ^FunctionConstantValues, completionHandler: ^NS.Block) -> ^Function { return msgSend(^Function, self, "newFunctionWithName:constantValues:completionHandler:", name, constantValues, completionHandler) } @(objc_type=Library, objc_name="newFunctionWithConstantValues") @@ -7452,8 +7482,17 @@ Library_newFunctionWithConstantValues :: #force_inline proc(self: ^Library, name function = msgSend(^Function, self, "newFunctionWithName:constantValues:error:", name, constantValues, &error) return } +@(objc_type=Library, objc_name="newFunction") +Library_newFunction :: proc{ + Library_newFunctionWithCompletionHandler, + Library_newFunctionWithDescriptor, + Library_newFunctionWithName, + Library_newFunctionWithConstantValuesAndCompletionHandler, + Library_newFunctionWithConstantValues, +} + @(objc_type=Library, objc_name="newIntersectionFunctionWithCompletionHandler") -Library_newIntersectionFunctionWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: rawptr) -> ^Function { +Library_newIntersectionFunctionWithCompletionHandler :: #force_inline proc(self: ^Library, descriptor: ^IntersectionFunctionDescriptor, completionHandler: ^NS.Block) -> ^Function { return msgSend(^Function, self, "newIntersectionFunctionWithDescriptor:completionHandler:", descriptor, completionHandler) } @(objc_type=Library, objc_name="newIntersectionFunction") From 6b7c04e046d97bd08401123977a046398563bb87 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Apr 2022 11:33:28 +0100 Subject: [PATCH 0534/1052] Improve utilities --- .../{block_literal.odin => NSBlock.odin} | 20 +++++++++++++++---- vendor/darwin/Metal/MetalClasses.odin | 2 ++ vendor/darwin/Metal/MetalProcedures.odin | 5 +++++ 3 files changed, 23 insertions(+), 4 deletions(-) rename vendor/darwin/Foundation/{block_literal.odin => NSBlock.odin} (74%) diff --git a/vendor/darwin/Foundation/block_literal.odin b/vendor/darwin/Foundation/NSBlock.odin similarity index 74% rename from vendor/darwin/Foundation/block_literal.odin rename to vendor/darwin/Foundation/NSBlock.odin index 19e9782e4..67ab502e8 100644 --- a/vendor/darwin/Foundation/block_literal.odin +++ b/vendor/darwin/Foundation/NSBlock.odin @@ -34,8 +34,9 @@ global_block_descriptor := Block_Descriptor{ @(objc_class="NSConcreteGlobalBlock") Block :: struct {using _: Object} -@(objc_type=Block, objc_name="create", objc_is_class_method=true) -Block_create :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { + +@(private="file") +Block_createInternal :: proc "c" (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { // Set to true on blocks that have captures (and thus are not true // global blocks) but are known not to escape for various other // reasons. For backward compatibility with old runtimes, whenever @@ -55,13 +56,24 @@ Block_create :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: raw cls := intrinsics.objc_find_class("NSConcreteGlobalBlock") bl := (^Internal_Block_Literal)(AllocateObject(cls, extraBytes, nil)) bl.isa = cls - bl.flags = BLOCK_IS_GLOBAL + bl.flags = BLOCK_IS_GLOBAL if is_global else 0 bl.invoke = proc "c" (bl: ^Internal_Block_Literal) { bl.user_proc(bl.user_data) } bl.descriptor = &global_block_descriptor bl.user_proc = user_proc bl.user_data = user_data - + return auto_cast bl } + +@(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true) +Block_createGlobal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { + return Block_createInternal(true, user_data, user_proc) +} + + +@(objc_type=Block, objc_name="createLocal", objc_is_class_method=true) +Block_createLocal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { + return Block_createInternal(false, user_data, user_proc) +} diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index c30fde95c..075aae545 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -6588,6 +6588,7 @@ Device_newHeap :: #force_inline proc(self: ^Device, descriptor: ^HeapDescriptor) Device_newIndirectCommandBuffer :: #force_inline proc(self: ^Device, descriptor: ^IndirectCommandBufferDescriptor, maxCount: NS.UInteger, options: ResourceOptions) -> ^IndirectCommandBuffer { return msgSend(^IndirectCommandBuffer, self, "newIndirectCommandBufferWithDescriptor:maxCommandCount:options:", descriptor, maxCount, options) } + @(objc_type=Device, objc_name="newLibraryWithData") Device_newLibraryWithData :: #force_inline proc(self: ^Device, data: dispatch_data_t) -> (library: ^Library, error: ^NS.Error) { library = msgSend(^Library, self, "newLibraryWithData:error:", data, &error) @@ -6626,6 +6627,7 @@ Device_newLibrary :: proc{ Device_newRasterizationRateMap :: #force_inline proc(self: ^Device, descriptor: ^RasterizationRateMapDescriptor) -> ^RasterizationRateMap { return msgSend(^RasterizationRateMap, self, "newRasterizationRateMapWithDescriptor:", descriptor) } + @(objc_type=Device, objc_name="newRenderPipelineStateWithDescriptorWithCompletionHandler") Device_newRenderPipelineStateWithDescriptorWithCompletionHandler :: #force_inline proc(self: ^Device, descriptor: ^RenderPipelineDescriptor, completionHandler: NewRenderPipelineStateCompletionHandler) -> ^RenderPipelineState { return msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithDescriptor:completionHandler:", descriptor, completionHandler) diff --git a/vendor/darwin/Metal/MetalProcedures.odin b/vendor/darwin/Metal/MetalProcedures.odin index b76c7f541..ca8fb1aea 100644 --- a/vendor/darwin/Metal/MetalProcedures.odin +++ b/vendor/darwin/Metal/MetalProcedures.odin @@ -11,4 +11,9 @@ foreign Metal { CopyAllDevicesWithObserver :: proc(observer: ^id, handler: DeviceNotificationHandler) -> ^NS.Array --- CreateSystemDefaultDevice :: proc() -> ^Device --- RemoveDeviceObserver :: proc(observer: id) --- +} + + +new :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, NS.Object) { + return T.alloc()->init() } \ No newline at end of file From fc3f62e3eda6f6c605c0e1db73a1dc36cb5fc848 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Apr 2022 11:50:08 +0100 Subject: [PATCH 0535/1052] Minor rearrangement --- vendor/darwin/Foundation/NSBlock.odin | 34 ++++++++++++++------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/vendor/darwin/Foundation/NSBlock.odin b/vendor/darwin/Foundation/NSBlock.odin index 67ab502e8..7fa061484 100644 --- a/vendor/darwin/Foundation/NSBlock.odin +++ b/vendor/darwin/Foundation/NSBlock.odin @@ -2,6 +2,21 @@ package objc_Foundation import "core:intrinsics" +@(objc_class="NSConcreteGlobalBlock") +Block :: struct {using _: Object} + +@(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true) +Block_createGlobal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { + return Block_createInternal(true, user_data, user_proc) +} + +@(objc_type=Block, objc_name="createLocal", objc_is_class_method=true) +Block_createLocal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { + return Block_createInternal(false, user_data, user_proc) +} + + +@(private) Internal_Block_Literal_Base :: struct { isa: ^intrinsics.objc_class, flags: u32, @@ -10,6 +25,7 @@ Internal_Block_Literal_Base :: struct { descriptor: ^Block_Descriptor, } +@(private) Internal_Block_Literal :: struct { using base: Internal_Block_Literal_Base, // Imported Variables @@ -17,6 +33,7 @@ Internal_Block_Literal :: struct { user_data: rawptr, } +@(private) Block_Descriptor :: struct { reserved: uint, size: uint, @@ -25,16 +42,12 @@ Block_Descriptor :: struct { signature: cstring, } +@(private) global_block_descriptor := Block_Descriptor{ reserved = 0, size = size_of(Internal_Block_Literal), } - -@(objc_class="NSConcreteGlobalBlock") -Block :: struct {using _: Object} - - @(private="file") Block_createInternal :: proc "c" (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { // Set to true on blocks that have captures (and thus are not true @@ -66,14 +79,3 @@ Block_createInternal :: proc "c" (is_global: bool, user_data: rawptr, user_proc: return auto_cast bl } - -@(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true) -Block_createGlobal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { - return Block_createInternal(true, user_data, user_proc) -} - - -@(objc_type=Block, objc_name="createLocal", objc_is_class_method=true) -Block_createLocal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { - return Block_createInternal(false, user_data, user_proc) -} From 989641a6167498dfe6663fb330525d4d92becf8a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Apr 2022 12:14:12 +0100 Subject: [PATCH 0536/1052] Update Vulkan generation and package --- .../vulkan/_gen/create_vulkan_odin_wrapper.py | 37 +- vendor/vulkan/_gen/vk_icd.h | 2 +- vendor/vulkan/_gen/vk_platform.h | 4 +- vendor/vulkan/_gen/vulkan_core.h | 2569 ++++++++++++----- vendor/vulkan/_gen/vulkan_ios.h | 2 +- vendor/vulkan/_gen/vulkan_macos.h | 2 +- vendor/vulkan/_gen/vulkan_metal.h | 2 +- vendor/vulkan/_gen/vulkan_win32.h | 2 +- vendor/vulkan/core.odin | 98 +- vendor/vulkan/enums.odin | 1819 +++++++----- vendor/vulkan/procedures.odin | 341 ++- vendor/vulkan/structs.odin | 1529 ++++++---- 12 files changed, 4320 insertions(+), 2087 deletions(-) diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index f1949f973..ae1bc8d64 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -7,14 +7,14 @@ import os.path import math file_and_urls = [ - ("vk_platform.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vk_platform.h', True), - ("vulkan_core.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vulkan_core.h', False), - ("vk_layer.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vk_layer.h', True), - ("vk_icd.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vk_icd.h', True), - ("vulkan_win32.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vulkan_win32.h', False), - ("vulkan_metal.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vulkan_metal.h', False), - ("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vulkan_macos.h', False), - ("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vulkan_ios.h', False), + ("vk_platform.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_platform.h', True), + ("vulkan_core.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_core.h', False), + ("vk_layer.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_layer.h', True), + ("vk_icd.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_icd.h', True), + ("vulkan_win32.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_win32.h', False), + ("vulkan_metal.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_metal.h', False), + ("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h', False), + ("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h', False), ] for file, url, _ in file_and_urls: @@ -125,7 +125,7 @@ def to_snake_case(name): s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() -ext_suffixes = ["KHR", "EXT", "AMD", "NV", "NVX", "GOOGLE"] +ext_suffixes = ["KHR", "EXT", "AMD", "NV", "NVX", "GOOGLE", "KHX"] ext_suffixes_title = [ext.title() for ext in ext_suffixes] @@ -254,9 +254,19 @@ def parse_constants(f): f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value)) f.write("\n// Vendor Constants\n") - data = re.findall(r"#define VK_((?:"+'|'.join(ext_suffixes)+r")\w+)\s*(.*?)\n", src, re.S) + fixes = '|'.join(ext_suffixes) + inner = r"((?:(?:" + fixes + r")\w+)|(?:\w+" + fixes + r"))" + pattern = r"#define\s+VK_" + inner + r"\s*(.*?)\n" + data = re.findall(pattern, src, re.S) + + number_suffix_re = re.compile(r"(\d+)[UuLlFf]") + max_len = max(len(name) for name, value in data) for name, value in data: + value = remove_prefix(value, 'VK_') + v = number_suffix_re.findall(value) + if v: + value = v[0] f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value)) f.write("\n") @@ -652,15 +662,12 @@ MAX_MEMORY_TYPES :: 32 MAX_MEMORY_HEAPS :: 16 MAX_EXTENSION_NAME_SIZE :: 256 MAX_DESCRIPTION_SIZE :: 256 -MAX_DEVICE_GROUP_SIZE_KHX :: 32 MAX_DEVICE_GROUP_SIZE :: 32 LUID_SIZE_KHX :: 8 -LUID_SIZE_KHR :: 8 LUID_SIZE :: 8 -MAX_DRIVER_NAME_SIZE_KHR :: 256 -MAX_DRIVER_INFO_SIZE_KHR :: 256 -MAX_QUEUE_FAMILY_EXTERNAL :: ~u32(0)-1 +MAX_QUEUE_FAMILY_EXTERNAL :: ~u32(1) MAX_GLOBAL_PRIORITY_SIZE_EXT :: 16 +QUEUE_FAMILY_EXTERNAL :: MAX_QUEUE_FAMILY_EXTERNAL """[1::]) parse_constants(f) diff --git a/vendor/vulkan/_gen/vk_icd.h b/vendor/vulkan/_gen/vk_icd.h index ae006d06d..41989ee35 100644 --- a/vendor/vulkan/_gen/vk_icd.h +++ b/vendor/vulkan/_gen/vk_icd.h @@ -33,7 +33,7 @@ // Version 2 - Add Loader/ICD Interface version negotiation // via vk_icdNegotiateLoaderICDInterfaceVersion. // Version 3 - Add ICD creation/destruction of KHR_surface objects. -// Version 4 - Add unknown physical device extension qyering via +// Version 4 - Add unknown physical device extension querying via // vk_icdGetPhysicalDeviceProcAddr. // Version 5 - Tells ICDs that the loader is now paying attention to the // application version of Vulkan passed into the ApplicationInfo diff --git a/vendor/vulkan/_gen/vk_platform.h b/vendor/vulkan/_gen/vk_platform.h index 18b913abc..3ff8c5d14 100644 --- a/vendor/vulkan/_gen/vk_platform.h +++ b/vendor/vulkan/_gen/vk_platform.h @@ -2,7 +2,7 @@ // File: vk_platform.h // /* -** Copyright 2014-2021 The Khronos Group Inc. +** Copyright 2014-2022 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -42,7 +42,7 @@ extern "C" #define VKAPI_CALL __stdcall #define VKAPI_PTR VKAPI_CALL #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 - #error "Vulkan isn't supported for the 'armeabi' NDK ABI" + #error "Vulkan is not supported for the 'armeabi' NDK ABI" #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" // calling convention, i.e. float parameters are passed in registers. This diff --git a/vendor/vulkan/_gen/vulkan_core.h b/vendor/vulkan/_gen/vulkan_core.h index 18b302fa0..5c8b8461f 100644 --- a/vendor/vulkan/_gen/vulkan_core.h +++ b/vendor/vulkan/_gen/vulkan_core.h @@ -2,7 +2,7 @@ #define VULKAN_CORE_H_ 1 /* -** Copyright 2015-2021 The Khronos Group Inc. +** Copyright 2015-2022 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -72,10 +72,10 @@ extern "C" { #define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0 // Version of this file -#define VK_HEADER_VERSION 191 +#define VK_HEADER_VERSION 211 // Complete version of this file -#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 2, VK_HEADER_VERSION) +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) // DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. #define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) @@ -160,6 +160,7 @@ typedef enum VkResult { VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, VK_ERROR_FRAGMENTATION = -1000161000, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, + VK_PIPELINE_COMPILE_REQUIRED = 1000297000, VK_ERROR_SURFACE_LOST_KHR = -1000000000, VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, VK_SUBOPTIMAL_KHR = 1000001003, @@ -168,19 +169,20 @@ typedef enum VkResult { VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, VK_ERROR_INVALID_SHADER_NV = -1000012000, VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, - VK_ERROR_NOT_PERMITTED_EXT = -1000174001, + VK_ERROR_NOT_PERMITTED_KHR = -1000174001, VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, VK_THREAD_IDLE_KHR = 1000268000, VK_THREAD_DONE_KHR = 1000268001, VK_OPERATION_DEFERRED_KHR = 1000268002, VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, - VK_PIPELINE_COMPILE_REQUIRED_EXT = 1000297000, VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, + VK_ERROR_NOT_PERMITTED_EXT = VK_ERROR_NOT_PERMITTED_KHR, VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, - VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED_EXT, + VK_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; @@ -349,6 +351,58 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2 = 1000314004, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO = 1000314005, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO = 1000314006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 = 1000337000, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2 = 1000337001, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2 = 1000337004, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2 = 1000337005, + VK_STRUCTURE_TYPE_BUFFER_COPY_2 = 1000337006, + VK_STRUCTURE_TYPE_IMAGE_COPY_2 = 1000337007, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2 = 1000337008, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 = 1000337009, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2 = 1000337010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000, + VK_STRUCTURE_TYPE_RENDERING_INFO = 1000044000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO = 1000044001, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO = 1000044002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 = 1000360000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, @@ -418,8 +472,14 @@ typedef enum VkStructureType { #ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR = 1000023015, #endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_2_KHR = 1000023016, +#endif #ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR = 1000024000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR = 1000024001, #endif VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, @@ -436,54 +496,94 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT = 1000038000, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT = 1000038001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038001, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038002, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038003, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT = 1000038003, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT = 1000038004, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038004, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038005, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT = 1000038005, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT = 1000038006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT = 1000038006, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT = 1000038007, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT = 1000038007, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT = 1000038008, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT = 1000038008, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT = 1000038009, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_REFERENCE_LISTS_EXT = 1000038010, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_EXT = 1000039000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000039001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000039002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_VCL_FRAME_INFO_EXT = 1000039003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT = 1000039004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_EXT = 1000039005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_EMIT_PICTURE_PARAMETERS_EXT = 1000039006, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_EXT = 1000039007, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_REFERENCE_LISTS_EXT = 1000039008, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT = 1000039009, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT = 1000039010, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_EXT = 1000040000, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT = 1000040001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT = 1000040001, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT = 1000040002, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT = 1000040002, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT = 1000040003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT = 1000040003, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT = 1000040004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000040004, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000040005, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000040005, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000040006, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT = 1000040007, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT = 1000040006, #endif VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT = 1000044007, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD = 1000044008, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX = 1000044009, VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, @@ -493,7 +593,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = 1000066000, VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, @@ -565,10 +664,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID = 1000129006, VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, @@ -607,6 +703,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT = 1000158006, VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, #ifdef VK_ENABLE_BETA_EXTENSIONS @@ -634,7 +731,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, @@ -646,29 +742,28 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_EXT = 1000187000, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT = 1000187001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000187001, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000187002, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000187002, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000187003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT = 1000187003, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT = 1000187004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT = 1000187004, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT = 1000187005, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT = 1000187006, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT = 1000187005, #endif + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = 1000174000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = 1000388000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = 1000388001, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, - VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000192000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, @@ -689,14 +784,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = 1000215000, VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = 1000225000, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = 1000225001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = 1000225002, VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, @@ -712,7 +803,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = 1000245000, VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, @@ -743,7 +833,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, @@ -754,10 +843,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = 1000280000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = 1000280001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, @@ -771,30 +857,26 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, VK_STRUCTURE_TYPE_PRESENT_ID_KHR = 1000294000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = 1000295000, - VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = 1000295001, - VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = 1000295002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = 1000297000, #ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR = 1000299000, #endif #ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR = 1000299001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR = 1000299002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR = 1000299003, #endif VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, - VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = 1000314000, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = 1000314001, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = 1000314002, - VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = 1000314003, - VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = 1000314004, - VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = 1000314005, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = 1000314006, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = 1000314007, VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = 1000325000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, @@ -805,20 +887,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = 1000335000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, - VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = 1000337000, - VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = 1000337001, - VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = 1000337002, - VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = 1000337003, - VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = 1000337004, - VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = 1000337005, - VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = 1000337006, - VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = 1000337007, - VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = 1000337008, - VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = 1000337009, - VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = 1000337010, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = 1000342000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000, VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = 1000351000, VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = 1000351002, @@ -826,12 +898,24 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT = 1000353000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT = 1000355000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT = 1000355001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA = 1000366000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA = 1000366001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA = 1000366002, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA = 1000366003, + VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA = 1000366004, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA = 1000366005, + VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA = 1000366006, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA = 1000366007, + VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA = 1000366008, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA = 1000366009, VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, @@ -842,14 +926,31 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = 1000388000, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = 1000388001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, + VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001, + VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + VK_STRUCTURE_TYPE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INFO, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, @@ -869,6 +970,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, @@ -911,6 +1013,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO, VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, @@ -932,9 +1038,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, @@ -947,12 +1055,17 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT, VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES, VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, @@ -961,6 +1074,42 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; @@ -980,6 +1129,8 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL = 1000314000, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL = 1000314001, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, #ifdef VK_ENABLE_BETA_EXTENSIONS VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR = 1000024000, @@ -1002,8 +1153,6 @@ typedef enum VkImageLayout { #ifdef VK_ENABLE_BETA_EXTENSIONS VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR = 1000299002, #endif - VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = 1000314000, - VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = 1000314001, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, @@ -1011,6 +1160,8 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF } VkImageLayout; @@ -1043,6 +1194,7 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_COMMAND_POOL = 25, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT = 1000295000, VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, @@ -1063,9 +1215,10 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, - VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = 1000295000, + VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA = 1000366000, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } VkObjectType; @@ -1318,6 +1471,26 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, @@ -1326,26 +1499,20 @@ typedef enum VkFormat { VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = 1000066000, - VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = 1000066001, - VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = 1000066002, - VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = 1000066003, - VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = 1000066004, - VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = 1000066005, - VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = 1000066006, - VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = 1000066007, - VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = 1000066008, - VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = 1000066009, - VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = 1000066010, - VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = 1000066011, - VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = 1000066012, - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = 1000066013, - VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = 1000330000, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = 1000330001, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = 1000330002, - VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = 1000330003, - VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = 1000340000, - VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK, VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, @@ -1380,6 +1547,12 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, + VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16, + VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16, VK_FORMAT_MAX_ENUM = 0x7FFFFFFF } VkFormat; @@ -1422,6 +1595,7 @@ typedef enum VkQueryType { #ifdef VK_ENABLE_BETA_EXTENSIONS VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR = 1000299000, #endif + VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000, VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF } VkQueryType; @@ -1553,6 +1727,21 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_CULL_MODE = 1000267000, + VK_DYNAMIC_STATE_FRONT_FACE = 1000267001, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = 1000267002, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT = 1000267003, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT = 1000267004, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE = 1000267005, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE = 1000267006, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE = 1000267007, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP = 1000267008, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE = 1000267009, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE = 1000267010, + VK_DYNAMIC_STATE_STENCIL_OP = 1000267011, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE = 1000377001, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE = 1000377002, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE = 1000377004, VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, @@ -1562,25 +1751,25 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, - VK_DYNAMIC_STATE_CULL_MODE_EXT = 1000267000, - VK_DYNAMIC_STATE_FRONT_FACE_EXT = 1000267001, - VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = 1000267002, - VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = 1000267003, - VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = 1000267004, - VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = 1000267005, - VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = 1000267006, - VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = 1000267007, - VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = 1000267008, - VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = 1000267009, - VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = 1000267010, - VK_DYNAMIC_STATE_STENCIL_OP_EXT = 1000267011, VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, - VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = 1000377001, - VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = 1000377002, VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, - VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = 1000377004, VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, + VK_DYNAMIC_STATE_CULL_MODE_EXT = VK_DYNAMIC_STATE_CULL_MODE, + VK_DYNAMIC_STATE_FRONT_FACE_EXT = VK_DYNAMIC_STATE_FRONT_FACE, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_OP_EXT = VK_DYNAMIC_STATE_STENCIL_OP, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF } VkDynamicState; @@ -1699,10 +1888,11 @@ typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, - VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = 1000351000, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorType; @@ -1717,8 +1907,10 @@ typedef enum VkAttachmentLoadOp { typedef enum VkAttachmentStoreOp { VK_ATTACHMENT_STORE_OP_STORE = 0, VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_NONE_EXT = 1000301000, - VK_ATTACHMENT_STORE_OP_NONE_QCOM = VK_ATTACHMENT_STORE_OP_NONE_EXT, + VK_ATTACHMENT_STORE_OP_NONE = 1000301000, + VK_ATTACHMENT_STORE_OP_NONE_KHR = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_QCOM = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_EXT = VK_ATTACHMENT_STORE_OP_NONE, VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentStoreOp; @@ -1770,6 +1962,7 @@ typedef enum VkAccessFlagBits { VK_ACCESS_HOST_WRITE_BIT = 0x00004000, VK_ACCESS_MEMORY_READ_BIT = 0x00008000, VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_NONE = 0, VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, @@ -1781,10 +1974,10 @@ typedef enum VkAccessFlagBits { VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000, VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000, VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000, - VK_ACCESS_NONE_KHR = 0, VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, + VK_ACCESS_NONE_KHR = VK_ACCESS_NONE, VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; typedef VkFlags VkAccessFlags; @@ -1797,6 +1990,7 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, + VK_IMAGE_ASPECT_NONE = 0, VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, @@ -1804,6 +1998,7 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, + VK_IMAGE_ASPECT_NONE_KHR = VK_IMAGE_ASPECT_NONE, VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageAspectFlagBits; typedef VkFlags VkImageAspectFlags; @@ -1879,6 +2074,8 @@ typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, + VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 0x00020000, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = 0x00008000, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, @@ -1935,6 +2132,11 @@ typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageUsageFlagBits; typedef VkFlags VkImageUsageFlags; + +typedef enum VkInstanceCreateFlagBits { + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; typedef VkFlags VkInstanceCreateFlags; typedef enum VkMemoryHeapFlagBits { @@ -2000,6 +2202,7 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_NONE = 0, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000, @@ -2009,10 +2212,10 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000, VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 0x00020000, - VK_PIPELINE_STAGE_NONE_KHR = 0, VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + VK_PIPELINE_STAGE_NONE_KHR = VK_PIPELINE_STAGE_NONE, VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; typedef VkFlags VkPipelineStageFlags; @@ -2040,7 +2243,8 @@ typedef VkFlags VkFenceCreateFlags; typedef VkFlags VkSemaphoreCreateFlags; typedef enum VkEventCreateFlagBits { - VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = 0x00000001, + VK_EVENT_CREATE_DEVICE_ONLY_BIT = 0x00000001, + VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = VK_EVENT_CREATE_DEVICE_ONLY_BIT, VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkEventCreateFlagBits; typedef VkFlags VkEventCreateFlags; @@ -2132,7 +2336,8 @@ typedef VkFlags VkImageViewCreateFlags; typedef VkFlags VkShaderModuleCreateFlags; typedef enum VkPipelineCacheCreateFlagBits { - VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = 0x00000001, + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCacheCreateFlagBits; typedef VkFlags VkPipelineCacheCreateFlags; @@ -2152,6 +2357,10 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 0x00000010, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 0x00000100, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT = 0x00000200, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00200000, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00400000, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000, @@ -2164,19 +2373,25 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080, VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00040000, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 0x00000800, - VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = 0x00000100, - VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = 0x00000200, + VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 0x00800000, + VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT = 0x00000400, VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV = 0x00100000, VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT, VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCreateFlagBits; typedef VkFlags VkPipelineCreateFlags; typedef enum VkPipelineShaderStageCreateFlagBits { - VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 0x00000001, - VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 0x00000002, + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT = 0x00000001, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT = 0x00000002, + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT, VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineShaderStageCreateFlagBits; typedef VkFlags VkPipelineShaderStageCreateFlags; @@ -2222,9 +2437,25 @@ typedef VkFlags VkPipelineTessellationStateCreateFlags; typedef VkFlags VkPipelineViewportStateCreateFlags; typedef VkFlags VkPipelineRasterizationStateCreateFlags; typedef VkFlags VkPipelineMultisampleStateCreateFlags; + +typedef enum VkPipelineDepthStencilStateCreateFlagBits { + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 0x00000001, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 0x00000002, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineDepthStencilStateCreateFlagBits; typedef VkFlags VkPipelineDepthStencilStateCreateFlags; + +typedef enum VkPipelineColorBlendStateCreateFlagBits { + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = 0x00000001, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineColorBlendStateCreateFlagBits; typedef VkFlags VkPipelineColorBlendStateCreateFlags; typedef VkFlags VkPipelineDynamicStateCreateFlags; + +typedef enum VkPipelineLayoutCreateFlagBits { + VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 0x00000002, + VK_PIPELINE_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineLayoutCreateFlagBits; typedef VkFlags VkPipelineLayoutCreateFlags; typedef VkFlags VkShaderStageFlags; @@ -2288,6 +2519,9 @@ typedef enum VkSubpassDescriptionFlagBits { VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 0x00000004, VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 0x00000008, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = 0x00000010, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 0x00000020, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 0x00000040, VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubpassDescriptionFlagBits; typedef VkFlags VkSubpassDescriptionFlags; @@ -5285,6 +5519,11 @@ typedef enum VkDriverId { VK_DRIVER_ID_COREAVI_PROPRIETARY = 15, VK_DRIVER_ID_JUICE_PROPRIETARY = 16, VK_DRIVER_ID_VERISILICON_PROPRIETARY = 17, + VK_DRIVER_ID_MESA_TURNIP = 18, + VK_DRIVER_ID_MESA_V3DV = 19, + VK_DRIVER_ID_MESA_PANVK = 20, + VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21, + VK_DRIVER_ID_MESA_VENUS = 22, VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, @@ -6006,6 +6245,1037 @@ VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddress( #endif +#define VK_VERSION_1_3 1 +// Vulkan 1.3 version number +#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)// Patch version should always be set to 0 + +typedef uint64_t VkFlags64; +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot) + +typedef enum VkPipelineCreationFeedbackFlagBits { + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT = 0x00000001, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT = 0x00000002, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT = 0x00000004, + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT, + VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreationFeedbackFlagBits; +typedef VkFlags VkPipelineCreationFeedbackFlags; + +typedef enum VkToolPurposeFlagBits { + VK_TOOL_PURPOSE_VALIDATION_BIT = 0x00000001, + VK_TOOL_PURPOSE_PROFILING_BIT = 0x00000002, + VK_TOOL_PURPOSE_TRACING_BIT = 0x00000004, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT = 0x00000008, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT = 0x00000010, + VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 0x00000020, + VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 0x00000040, + VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = VK_TOOL_PURPOSE_VALIDATION_BIT, + VK_TOOL_PURPOSE_PROFILING_BIT_EXT = VK_TOOL_PURPOSE_PROFILING_BIT, + VK_TOOL_PURPOSE_TRACING_BIT_EXT = VK_TOOL_PURPOSE_TRACING_BIT, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT, + VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkToolPurposeFlagBits; +typedef VkFlags VkToolPurposeFlags; +typedef VkFlags VkPrivateDataSlotCreateFlags; +typedef VkFlags64 VkPipelineStageFlags2; + +// Flag bits for VkPipelineStageFlagBits2 +typedef VkFlags64 VkPipelineStageFlagBits2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE = 0ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE_KHR = 0ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT = 0x00000001ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 0x00000001ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT = 0x00000002ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 0x00000002ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT = 0x00000004ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 0x00000004ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT = 0x00000008ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 0x00000008ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 0x00000010ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 0x00000020ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT = 0x00000040ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 0x00000040ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT = 0x00000080ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 0x00000080ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT = 0x00000100ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 0x00000100ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT = 0x00000200ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 0x00000200ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 0x00000400ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT = 0x00000800ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 0x00000800ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT = 0x00002000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 0x00002000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT = 0x00004000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 0x00004000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT = 0x00008000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 0x00008000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT = 0x00010000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 0x00010000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT = 0x100000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 0x100000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT = 0x200000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 0x200000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT = 0x400000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 0x400000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT = 0x800000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 0x800000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT = 0x1000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 0x1000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT = 0x2000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 0x2000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 0x4000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 0x4000000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR = 0x04000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR = 0x08000000ULL; +#endif +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 0x00020000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 0x00400000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 0x00200000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 0x00200000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 0x00080000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 0x00100000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 0x8000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0x10000000000ULL; + +typedef VkFlags64 VkAccessFlags2; + +// Flag bits for VkAccessFlagBits2 +typedef VkFlags64 VkAccessFlagBits2; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 0x00000001ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 0x00000001ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 0x00000002ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 0x00000002ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 0x00000004ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 0x00000008ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 0x00000008ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 0x00000010ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 0x00000010ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 0x00000020ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 0x00000020ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 0x00000040ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 0x00000040ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 0x00000080ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 0x00000080ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 0x00000100ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 0x00000200ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 0x00000400ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 0x00000800ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 0x00000800ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 0x00001000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 0x00001000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 0x00002000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 0x00002000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 0x00004000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 0x00004000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 0x00008000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 0x00008000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 0x00010000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 0x00010000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 0x100000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 0x100000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 0x200000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 0x200000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 0x400000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR = 0x800000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR = 0x1000000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR = 0x2000000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR = 0x4000000000ULL; +#endif +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 0x8000000000ULL; + + +typedef enum VkSubmitFlagBits { + VK_SUBMIT_PROTECTED_BIT = 0x00000001, + VK_SUBMIT_PROTECTED_BIT_KHR = VK_SUBMIT_PROTECTED_BIT, + VK_SUBMIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubmitFlagBits; +typedef VkFlags VkSubmitFlags; + +typedef enum VkRenderingFlagBits { + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 0x00000001, + VK_RENDERING_SUSPENDING_BIT = 0x00000002, + VK_RENDERING_RESUMING_BIT = 0x00000004, + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, + VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT, + VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT, + VK_RENDERING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderingFlagBits; +typedef VkFlags VkRenderingFlags; +typedef VkFlags64 VkFormatFeatureFlags2; + +// Flag bits for VkFormatFeatureFlagBits2 +typedef VkFlags64 VkFormatFeatureFlagBits2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT = 0x00000001ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR = 0x00000001ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT = 0x00000002ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR = 0x00000002ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR = 0x00000004ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 0x00000008ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT = 0x00000010ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 0x00000010ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR = 0x00000020ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT = 0x00000040ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR = 0x00000040ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT = 0x00000080ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR = 0x00000080ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR = 0x00000100ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 0x00000200ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT = 0x00000400ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR = 0x00000400ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT = 0x00000800ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR = 0x00000800ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR = 0x00001000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT = 0x00002000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT = 0x00004000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR = 0x00004000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT = 0x00008000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR = 0x00008000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR = 0x00010000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT = 0x00400000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR = 0x00400000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT = 0x00800000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT = 0x80000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR = 0x80000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT = 0x100000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR = 0x100000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT = 0x200000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR = 0x200000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_DECODE_OUTPUT_BIT_KHR = 0x02000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_DECODE_DPB_BIT_KHR = 0x04000000ULL; +#endif +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000ULL; +#endif +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 0x4000000000ULL; + +typedef struct VkPhysicalDeviceVulkan13Features { + VkStructureType sType; + void* pNext; + VkBool32 robustImageAccess; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; + VkBool32 pipelineCreationCacheControl; + VkBool32 privateData; + VkBool32 shaderDemoteToHelperInvocation; + VkBool32 shaderTerminateInvocation; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; + VkBool32 synchronization2; + VkBool32 textureCompressionASTC_HDR; + VkBool32 shaderZeroInitializeWorkgroupMemory; + VkBool32 dynamicRendering; + VkBool32 shaderIntegerDotProduct; + VkBool32 maintenance4; +} VkPhysicalDeviceVulkan13Features; + +typedef struct VkPhysicalDeviceVulkan13Properties { + VkStructureType sType; + void* pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; + uint32_t maxInlineUniformTotalSize; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceVulkan13Properties; + +typedef struct VkPipelineCreationFeedback { + VkPipelineCreationFeedbackFlags flags; + uint64_t duration; +} VkPipelineCreationFeedback; + +typedef struct VkPipelineCreationFeedbackCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreationFeedback* pPipelineCreationFeedback; + uint32_t pipelineStageCreationFeedbackCount; + VkPipelineCreationFeedback* pPipelineStageCreationFeedbacks; +} VkPipelineCreationFeedbackCreateInfo; + +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderTerminateInvocation; +} VkPhysicalDeviceShaderTerminateInvocationFeatures; + +typedef struct VkPhysicalDeviceToolProperties { + VkStructureType sType; + void* pNext; + char name[VK_MAX_EXTENSION_NAME_SIZE]; + char version[VK_MAX_EXTENSION_NAME_SIZE]; + VkToolPurposeFlags purposes; + char description[VK_MAX_DESCRIPTION_SIZE]; + char layer[VK_MAX_EXTENSION_NAME_SIZE]; +} VkPhysicalDeviceToolProperties; + +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderDemoteToHelperInvocation; +} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures; + +typedef struct VkPhysicalDevicePrivateDataFeatures { + VkStructureType sType; + void* pNext; + VkBool32 privateData; +} VkPhysicalDevicePrivateDataFeatures; + +typedef struct VkDevicePrivateDataCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t privateDataSlotRequestCount; +} VkDevicePrivateDataCreateInfo; + +typedef struct VkPrivateDataSlotCreateInfo { + VkStructureType sType; + const void* pNext; + VkPrivateDataSlotCreateFlags flags; +} VkPrivateDataSlotCreateInfo; + +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures { + VkStructureType sType; + void* pNext; + VkBool32 pipelineCreationCacheControl; +} VkPhysicalDevicePipelineCreationCacheControlFeatures; + +typedef struct VkMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; +} VkMemoryBarrier2; + +typedef struct VkBufferMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier2; + +typedef struct VkImageMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier2; + +typedef struct VkDependencyInfo { + VkStructureType sType; + const void* pNext; + VkDependencyFlags dependencyFlags; + uint32_t memoryBarrierCount; + const VkMemoryBarrier2* pMemoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier2* pBufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier2* pImageMemoryBarriers; +} VkDependencyInfo; + +typedef struct VkSemaphoreSubmitInfo { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; + VkPipelineStageFlags2 stageMask; + uint32_t deviceIndex; +} VkSemaphoreSubmitInfo; + +typedef struct VkCommandBufferSubmitInfo { + VkStructureType sType; + const void* pNext; + VkCommandBuffer commandBuffer; + uint32_t deviceMask; +} VkCommandBufferSubmitInfo; + +typedef struct VkSubmitInfo2 { + VkStructureType sType; + const void* pNext; + VkSubmitFlags flags; + uint32_t waitSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pWaitSemaphoreInfos; + uint32_t commandBufferInfoCount; + const VkCommandBufferSubmitInfo* pCommandBufferInfos; + uint32_t signalSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pSignalSemaphoreInfos; +} VkSubmitInfo2; + +typedef struct VkPhysicalDeviceSynchronization2Features { + VkStructureType sType; + void* pNext; + VkBool32 synchronization2; +} VkPhysicalDeviceSynchronization2Features; + +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderZeroInitializeWorkgroupMemory; +} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures; + +typedef struct VkPhysicalDeviceImageRobustnessFeatures { + VkStructureType sType; + void* pNext; + VkBool32 robustImageAccess; +} VkPhysicalDeviceImageRobustnessFeatures; + +typedef struct VkBufferCopy2 { + VkStructureType sType; + const void* pNext; + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy2; + +typedef struct VkCopyBufferInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferCopy2* pRegions; +} VkCopyBufferInfo2; + +typedef struct VkImageCopy2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy2; + +typedef struct VkCopyImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2* pRegions; +} VkCopyImageInfo2; + +typedef struct VkBufferImageCopy2 { + VkStructureType sType; + const void* pNext; + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy2; + +typedef struct VkCopyBufferToImageInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkBufferImageCopy2* pRegions; +} VkCopyBufferToImageInfo2; + +typedef struct VkCopyImageToBufferInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferImageCopy2* pRegions; +} VkCopyImageToBufferInfo2; + +typedef struct VkImageBlit2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit2; + +typedef struct VkBlitImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageBlit2* pRegions; + VkFilter filter; +} VkBlitImageInfo2; + +typedef struct VkImageResolve2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve2; + +typedef struct VkResolveImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageResolve2* pRegions; +} VkResolveImageInfo2; + +typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures { + VkStructureType sType; + void* pNext; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; +} VkPhysicalDeviceSubgroupSizeControlFeatures; + +typedef struct VkPhysicalDeviceSubgroupSizeControlProperties { + VkStructureType sType; + void* pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; +} VkPhysicalDeviceSubgroupSizeControlProperties; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo { + VkStructureType sType; + void* pNext; + uint32_t requiredSubgroupSize; +} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo; + +typedef struct VkPhysicalDeviceInlineUniformBlockFeatures { + VkStructureType sType; + void* pNext; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; +} VkPhysicalDeviceInlineUniformBlockFeatures; + +typedef struct VkPhysicalDeviceInlineUniformBlockProperties { + VkStructureType sType; + void* pNext; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; +} VkPhysicalDeviceInlineUniformBlockProperties; + +typedef struct VkWriteDescriptorSetInlineUniformBlock { + VkStructureType sType; + const void* pNext; + uint32_t dataSize; + const void* pData; +} VkWriteDescriptorSetInlineUniformBlock; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t maxInlineUniformBlockBindings; +} VkDescriptorPoolInlineUniformBlockCreateInfo; + +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures { + VkStructureType sType; + void* pNext; + VkBool32 textureCompressionASTC_HDR; +} VkPhysicalDeviceTextureCompressionASTCHDRFeatures; + +typedef struct VkRenderingAttachmentInfo { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkResolveModeFlagBits resolveMode; + VkImageView resolveImageView; + VkImageLayout resolveImageLayout; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkClearValue clearValue; +} VkRenderingAttachmentInfo; + +typedef struct VkRenderingInfo { + VkStructureType sType; + const void* pNext; + VkRenderingFlags flags; + VkRect2D renderArea; + uint32_t layerCount; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkRenderingAttachmentInfo* pColorAttachments; + const VkRenderingAttachmentInfo* pDepthAttachment; + const VkRenderingAttachmentInfo* pStencilAttachment; +} VkRenderingInfo; + +typedef struct VkPipelineRenderingCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkPipelineRenderingCreateInfo; + +typedef struct VkPhysicalDeviceDynamicRenderingFeatures { + VkStructureType sType; + void* pNext; + VkBool32 dynamicRendering; +} VkPhysicalDeviceDynamicRenderingFeatures; + +typedef struct VkCommandBufferInheritanceRenderingInfo { + VkStructureType sType; + const void* pNext; + VkRenderingFlags flags; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; + VkSampleCountFlagBits rasterizationSamples; +} VkCommandBufferInheritanceRenderingInfo; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderIntegerDotProduct; +} VkPhysicalDeviceShaderIntegerDotProductFeatures; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties { + VkStructureType sType; + void* pNext; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; +} VkPhysicalDeviceShaderIntegerDotProductProperties; + +typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties { + VkStructureType sType; + void* pNext; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; +} VkPhysicalDeviceTexelBufferAlignmentProperties; + +typedef struct VkFormatProperties3 { + VkStructureType sType; + void* pNext; + VkFormatFeatureFlags2 linearTilingFeatures; + VkFormatFeatureFlags2 optimalTilingFeatures; + VkFormatFeatureFlags2 bufferFeatures; +} VkFormatProperties3; + +typedef struct VkPhysicalDeviceMaintenance4Features { + VkStructureType sType; + void* pNext; + VkBool32 maintenance4; +} VkPhysicalDeviceMaintenance4Features; + +typedef struct VkPhysicalDeviceMaintenance4Properties { + VkStructureType sType; + void* pNext; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceMaintenance4Properties; + +typedef struct VkDeviceBufferMemoryRequirements { + VkStructureType sType; + const void* pNext; + const VkBufferCreateInfo* pCreateInfo; +} VkDeviceBufferMemoryRequirements; + +typedef struct VkDeviceImageMemoryRequirements { + VkStructureType sType; + const void* pNext; + const VkImageCreateInfo* pCreateInfo; + VkImageAspectFlagBits planeAspect; +} VkDeviceImageMemoryRequirements; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolProperties* pToolProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlot)(VkDevice device, const VkPrivateDataSlotCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlot* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlot)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t* pData); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfo* pDependencyInfos); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2)(VkCommandBuffer commandBuffer, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2* pSubmits, VkFence fence); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2* pCopyBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2* pCopyImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2* pBlitImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2* pResolveImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRendering)(VkCommandBuffer commandBuffer, const VkRenderingInfo* pRenderingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRendering)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdSetCullMode)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFace)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopology)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCount)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCount)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes, const VkDeviceSize* pStrides); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnable)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOp)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnable)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOp)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); +typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice device, const VkDeviceBufferMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pToolCount, + VkPhysicalDeviceToolProperties* pToolProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlot( + VkDevice device, + const VkPrivateDataSlotCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlot* pPrivateDataSlot); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlot( + VkDevice device, + VkPrivateDataSlot privateDataSlot, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateData( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t data); + +VKAPI_ATTR void VKAPI_CALL vkGetPrivateData( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent2( + VkCommandBuffer commandBuffer, + VkEvent event, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent2( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags2 stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents2( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + const VkDependencyInfo* pDependencyInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier2( + VkCommandBuffer commandBuffer, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp2( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2 stage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo2* pSubmits, + VkFence fence); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer2( + VkCommandBuffer commandBuffer, + const VkCopyBufferInfo2* pCopyBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage2( + VkCommandBuffer commandBuffer, + const VkCopyImageInfo2* pCopyImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage2( + VkCommandBuffer commandBuffer, + const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer2( + VkCommandBuffer commandBuffer, + const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage2( + VkCommandBuffer commandBuffer, + const VkBlitImageInfo2* pBlitImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage2( + VkCommandBuffer commandBuffer, + const VkResolveImageInfo2* pResolveImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRendering( + VkCommandBuffer commandBuffer, + const VkRenderingInfo* pRenderingInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRendering( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCullMode( + VkCommandBuffer commandBuffer, + VkCullModeFlags cullMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetFrontFace( + VkCommandBuffer commandBuffer, + VkFrontFace frontFace); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveTopology( + VkCommandBuffer commandBuffer, + VkPrimitiveTopology primitiveTopology); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWithCount( + VkCommandBuffer commandBuffer, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissorWithCount( + VkCommandBuffer commandBuffer, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers2( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthWriteEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthWriteEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthCompareOp( + VkCommandBuffer commandBuffer, + VkCompareOp depthCompareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBoundsTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthBoundsTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 stencilTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilOp( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizerDiscardEnable( + VkCommandBuffer commandBuffer, + VkBool32 rasterizerDiscardEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBiasEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthBiasEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveRestartEnable( + VkCommandBuffer commandBuffer, + VkBool32 primitiveRestartEnable); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceBufferMemoryRequirements( + VkDevice device, + const VkDeviceBufferMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageMemoryRequirements( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirements( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +#endif + + #define VK_KHR_surface 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) #define VK_KHR_SURFACE_SPEC_VERSION 25 @@ -6432,6 +7702,68 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" +#define VK_KHR_dynamic_rendering 1 +#define VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME "VK_KHR_dynamic_rendering" +typedef VkRenderingFlags VkRenderingFlagsKHR; + +typedef VkRenderingFlagBits VkRenderingFlagBitsKHR; + +typedef VkRenderingInfo VkRenderingInfoKHR; + +typedef VkRenderingAttachmentInfo VkRenderingAttachmentInfoKHR; + +typedef VkPipelineRenderingCreateInfo VkPipelineRenderingCreateInfoKHR; + +typedef VkPhysicalDeviceDynamicRenderingFeatures VkPhysicalDeviceDynamicRenderingFeaturesKHR; + +typedef VkCommandBufferInheritanceRenderingInfo VkCommandBufferInheritanceRenderingInfoKHR; + +typedef struct VkRenderingFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkExtent2D shadingRateAttachmentTexelSize; +} VkRenderingFragmentShadingRateAttachmentInfoKHR; + +typedef struct VkRenderingFragmentDensityMapAttachmentInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; +} VkRenderingFragmentDensityMapAttachmentInfoEXT; + +typedef struct VkAttachmentSampleCountInfoAMD { + VkStructureType sType; + const void* pNext; + uint32_t colorAttachmentCount; + const VkSampleCountFlagBits* pColorAttachmentSamples; + VkSampleCountFlagBits depthStencilAttachmentSamples; +} VkAttachmentSampleCountInfoAMD; + +typedef VkAttachmentSampleCountInfoAMD VkAttachmentSampleCountInfoNV; + +typedef struct VkMultiviewPerViewAttributesInfoNVX { + VkStructureType sType; + const void* pNext; + VkBool32 perViewAttributes; + VkBool32 perViewAttributesPositionXOnly; +} VkMultiviewPerViewAttributesInfoNVX; + +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderingKHR)(VkCommandBuffer commandBuffer, const VkRenderingInfo* pRenderingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderingKHR)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderingKHR( + VkCommandBuffer commandBuffer, + const VkRenderingInfo* pRenderingInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderingKHR( + VkCommandBuffer commandBuffer); +#endif + + #define VK_KHR_multiview 1 #define VK_KHR_MULTIVIEW_SPEC_VERSION 1 #define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" @@ -6566,8 +7898,10 @@ VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( #define VK_KHR_maintenance1 1 -#define VK_KHR_MAINTENANCE1_SPEC_VERSION 2 -#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" +#define VK_KHR_MAINTENANCE_1_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1" +#define VK_KHR_MAINTENANCE1_SPEC_VERSION VK_KHR_MAINTENANCE_1_SPEC_VERSION +#define VK_KHR_MAINTENANCE1_EXTENSION_NAME VK_KHR_MAINTENANCE_1_EXTENSION_NAME typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); @@ -7147,8 +8481,10 @@ VKAPI_ATTR void VKAPI_CALL vkReleaseProfilingLockKHR( #define VK_KHR_maintenance2 1 -#define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" +#define VK_KHR_MAINTENANCE_2_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2" +#define VK_KHR_MAINTENANCE2_SPEC_VERSION VK_KHR_MAINTENANCE_2_SPEC_VERSION +#define VK_KHR_MAINTENANCE2_EXTENSION_NAME VK_KHR_MAINTENANCE_2_EXTENSION_NAME typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; @@ -7401,8 +8737,10 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR( #define VK_KHR_maintenance3 1 -#define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" +#define VK_KHR_MAINTENANCE_3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3" +#define VK_KHR_MAINTENANCE3_SPEC_VERSION VK_KHR_MAINTENANCE_3_SPEC_VERSION +#define VK_KHR_MAINTENANCE3_EXTENSION_NAME VK_KHR_MAINTENANCE_3_EXTENSION_NAME typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; @@ -7477,6 +8815,43 @@ typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { +#define VK_KHR_global_priority 1 +#define VK_MAX_GLOBAL_PRIORITY_SIZE_KHR 16U +#define VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION 1 +#define VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME "VK_KHR_global_priority" + +typedef enum VkQueueGlobalPriorityKHR { + VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR = 128, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR = 256, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR = 512, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR = 1024, + VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR, + VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_KHR = 0x7FFFFFFF +} VkQueueGlobalPriorityKHR; +typedef struct VkDeviceQueueGlobalPriorityCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkQueueGlobalPriorityKHR globalPriority; +} VkDeviceQueueGlobalPriorityCreateInfoKHR; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 globalPriorityQuery; +} VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR; + +typedef struct VkQueueFamilyGlobalPriorityPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t priorityCount; + VkQueueGlobalPriorityKHR priorities[VK_MAX_GLOBAL_PRIORITY_SIZE_KHR]; +} VkQueueFamilyGlobalPriorityPropertiesKHR; + + + #define VK_KHR_driver_properties 1 #define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 #define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" @@ -7569,16 +8944,12 @@ typedef VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryMo #define VK_KHR_shader_terminate_invocation 1 #define VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION 1 #define VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME "VK_KHR_shader_terminate_invocation" -typedef struct VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 shaderTerminateInvocation; -} VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; +typedef VkPhysicalDeviceShaderTerminateInvocationFeatures VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; #define VK_KHR_fragment_shading_rate 1 -#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 1 +#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 2 #define VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME "VK_KHR_fragment_shading_rate" typedef enum VkFragmentShadingRateCombinerOpKHR { @@ -7870,46 +9241,9 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableInternalRepresentationsKHR #define VK_KHR_shader_integer_dot_product 1 #define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION 1 #define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME "VK_KHR_shader_integer_dot_product" -typedef struct VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 shaderIntegerDotProduct; -} VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR; +typedef VkPhysicalDeviceShaderIntegerDotProductFeatures VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR; -typedef struct VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR { - VkStructureType sType; - void* pNext; - VkBool32 integerDotProduct8BitUnsignedAccelerated; - VkBool32 integerDotProduct8BitSignedAccelerated; - VkBool32 integerDotProduct8BitMixedSignednessAccelerated; - VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProduct16BitUnsignedAccelerated; - VkBool32 integerDotProduct16BitSignedAccelerated; - VkBool32 integerDotProduct16BitMixedSignednessAccelerated; - VkBool32 integerDotProduct32BitUnsignedAccelerated; - VkBool32 integerDotProduct32BitSignedAccelerated; - VkBool32 integerDotProduct32BitMixedSignednessAccelerated; - VkBool32 integerDotProduct64BitUnsignedAccelerated; - VkBool32 integerDotProduct64BitSignedAccelerated; - VkBool32 integerDotProduct64BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; -} VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR; +typedef VkPhysicalDeviceShaderIntegerDotProductProperties VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR; @@ -7949,261 +9283,94 @@ typedef struct VkPhysicalDevicePresentIdFeaturesKHR { #define VK_KHR_synchronization2 1 -typedef uint64_t VkFlags64; #define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 #define VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME "VK_KHR_synchronization2" -typedef VkFlags64 VkPipelineStageFlags2KHR; +typedef VkPipelineStageFlags2 VkPipelineStageFlags2KHR; -// Flag bits for VkPipelineStageFlagBits2KHR -typedef VkFlags64 VkPipelineStageFlagBits2KHR; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_NONE_KHR = 0ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 0x00000001ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 0x00000002ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 0x00000004ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 0x00000008ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 0x00000010ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 0x00000020ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 0x00000040ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 0x00000080ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 0x00000100ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 0x00000200ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 0x00000400ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 0x00000800ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 0x00001000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 0x00001000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 0x00002000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 0x00004000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 0x00008000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 0x00010000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 0x100000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 0x200000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 0x400000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 0x800000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 0x1000000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 0x2000000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 0x4000000000ULL; -#ifdef VK_ENABLE_BETA_EXTENSIONS -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR = 0x04000000ULL; -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR = 0x08000000ULL; -#endif -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 0x00020000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 0x00400000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 0x00200000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 0x00200000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 0x00080000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 0x00100000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 0x8000000000ULL; -static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0x10000000000ULL; +typedef VkPipelineStageFlagBits2 VkPipelineStageFlagBits2KHR; -typedef VkFlags64 VkAccessFlags2KHR; +typedef VkAccessFlags2 VkAccessFlags2KHR; -// Flag bits for VkAccessFlagBits2KHR -typedef VkFlags64 VkAccessFlagBits2KHR; -static const VkAccessFlagBits2KHR VK_ACCESS_2_NONE_KHR = 0ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 0x00000001ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_INDEX_READ_BIT_KHR = 0x00000002ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 0x00000004ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 0x00000008ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 0x00000010ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_READ_BIT_KHR = 0x00000020ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 0x00000040ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 0x00000080ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 0x00000100ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 0x00000200ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 0x00000400ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 0x00000800ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 0x00001000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_HOST_READ_BIT_KHR = 0x00002000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_HOST_WRITE_BIT_KHR = 0x00004000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_MEMORY_READ_BIT_KHR = 0x00008000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 0x00010000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 0x100000000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 0x200000000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ULL; -#ifdef VK_ENABLE_BETA_EXTENSIONS -static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR = 0x800000000ULL; -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS -static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR = 0x1000000000ULL; -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS -static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR = 0x2000000000ULL; -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS -static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR = 0x4000000000ULL; -#endif -static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000ULL; -static const VkAccessFlagBits2KHR VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 0x8000000000ULL; +typedef VkAccessFlagBits2 VkAccessFlagBits2KHR; +typedef VkSubmitFlagBits VkSubmitFlagBitsKHR; -typedef enum VkSubmitFlagBitsKHR { - VK_SUBMIT_PROTECTED_BIT_KHR = 0x00000001, - VK_SUBMIT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSubmitFlagBitsKHR; -typedef VkFlags VkSubmitFlagsKHR; -typedef struct VkMemoryBarrier2KHR { - VkStructureType sType; - const void* pNext; - VkPipelineStageFlags2KHR srcStageMask; - VkAccessFlags2KHR srcAccessMask; - VkPipelineStageFlags2KHR dstStageMask; - VkAccessFlags2KHR dstAccessMask; -} VkMemoryBarrier2KHR; +typedef VkSubmitFlags VkSubmitFlagsKHR; -typedef struct VkBufferMemoryBarrier2KHR { - VkStructureType sType; - const void* pNext; - VkPipelineStageFlags2KHR srcStageMask; - VkAccessFlags2KHR srcAccessMask; - VkPipelineStageFlags2KHR dstStageMask; - VkAccessFlags2KHR dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize size; -} VkBufferMemoryBarrier2KHR; +typedef VkMemoryBarrier2 VkMemoryBarrier2KHR; -typedef struct VkImageMemoryBarrier2KHR { - VkStructureType sType; - const void* pNext; - VkPipelineStageFlags2KHR srcStageMask; - VkAccessFlags2KHR srcAccessMask; - VkPipelineStageFlags2KHR dstStageMask; - VkAccessFlags2KHR dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier2KHR; +typedef VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR; -typedef struct VkDependencyInfoKHR { - VkStructureType sType; - const void* pNext; - VkDependencyFlags dependencyFlags; - uint32_t memoryBarrierCount; - const VkMemoryBarrier2KHR* pMemoryBarriers; - uint32_t bufferMemoryBarrierCount; - const VkBufferMemoryBarrier2KHR* pBufferMemoryBarriers; - uint32_t imageMemoryBarrierCount; - const VkImageMemoryBarrier2KHR* pImageMemoryBarriers; -} VkDependencyInfoKHR; +typedef VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR; -typedef struct VkSemaphoreSubmitInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - uint64_t value; - VkPipelineStageFlags2KHR stageMask; - uint32_t deviceIndex; -} VkSemaphoreSubmitInfoKHR; +typedef VkDependencyInfo VkDependencyInfoKHR; -typedef struct VkCommandBufferSubmitInfoKHR { - VkStructureType sType; - const void* pNext; - VkCommandBuffer commandBuffer; - uint32_t deviceMask; -} VkCommandBufferSubmitInfoKHR; +typedef VkSubmitInfo2 VkSubmitInfo2KHR; -typedef struct VkSubmitInfo2KHR { - VkStructureType sType; - const void* pNext; - VkSubmitFlagsKHR flags; - uint32_t waitSemaphoreInfoCount; - const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos; - uint32_t commandBufferInfoCount; - const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos; - uint32_t signalSemaphoreInfoCount; - const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos; -} VkSubmitInfo2KHR; +typedef VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR; -typedef struct VkPhysicalDeviceSynchronization2FeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 synchronization2; -} VkPhysicalDeviceSynchronization2FeaturesKHR; +typedef VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR; + +typedef VkPhysicalDeviceSynchronization2Features VkPhysicalDeviceSynchronization2FeaturesKHR; typedef struct VkQueueFamilyCheckpointProperties2NV { - VkStructureType sType; - void* pNext; - VkPipelineStageFlags2KHR checkpointExecutionStageMask; + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2 checkpointExecutionStageMask; } VkQueueFamilyCheckpointProperties2NV; typedef struct VkCheckpointData2NV { - VkStructureType sType; - void* pNext; - VkPipelineStageFlags2KHR stage; - void* pCheckpointMarker; + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2 stage; + void* pCheckpointMarker; } VkCheckpointData2NV; -typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfoKHR* pDependencyInfo); -typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2KHR stageMask); -typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfoKHR* pDependencyInfos); -typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer commandBuffer, const VkDependencyInfoKHR* pDependencyInfo); -typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage, VkQueryPool queryPool, uint32_t query); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2KHR)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2KHR* pSubmits, VkFence fence); -typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfo* pDependencyInfos); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer commandBuffer, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2KHR)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2* pSubmits, VkFence fence); +typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointData2NV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointData2NV* pCheckpointData); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent2KHR( VkCommandBuffer commandBuffer, VkEvent event, - const VkDependencyInfoKHR* pDependencyInfo); + const VkDependencyInfo* pDependencyInfo); VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent2KHR( VkCommandBuffer commandBuffer, VkEvent event, - VkPipelineStageFlags2KHR stageMask); + VkPipelineStageFlags2 stageMask); VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents2KHR( VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, - const VkDependencyInfoKHR* pDependencyInfos); + const VkDependencyInfo* pDependencyInfos); VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier2KHR( VkCommandBuffer commandBuffer, - const VkDependencyInfoKHR* pDependencyInfo); + const VkDependencyInfo* pDependencyInfo); VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp2KHR( VkCommandBuffer commandBuffer, - VkPipelineStageFlags2KHR stage, + VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2KHR( VkQueue queue, uint32_t submitCount, - const VkSubmitInfo2KHR* pSubmits, + const VkSubmitInfo2* pSubmits, VkFence fence); VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarker2AMD( VkCommandBuffer commandBuffer, - VkPipelineStageFlags2KHR stage, + VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); @@ -8229,11 +9396,7 @@ typedef struct VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR { #define VK_KHR_zero_initialize_workgroup_memory 1 #define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION 1 #define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME "VK_KHR_zero_initialize_workgroup_memory" -typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 shaderZeroInitializeWorkgroupMemory; -} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; +typedef VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; @@ -8254,148 +9417,109 @@ typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR { #define VK_KHR_copy_commands2 1 #define VK_KHR_COPY_COMMANDS_2_SPEC_VERSION 1 #define VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME "VK_KHR_copy_commands2" -typedef struct VkBufferCopy2KHR { - VkStructureType sType; - const void* pNext; - VkDeviceSize srcOffset; - VkDeviceSize dstOffset; - VkDeviceSize size; -} VkBufferCopy2KHR; +typedef VkCopyBufferInfo2 VkCopyBufferInfo2KHR; -typedef struct VkCopyBufferInfo2KHR { - VkStructureType sType; - const void* pNext; - VkBuffer srcBuffer; - VkBuffer dstBuffer; - uint32_t regionCount; - const VkBufferCopy2KHR* pRegions; -} VkCopyBufferInfo2KHR; +typedef VkCopyImageInfo2 VkCopyImageInfo2KHR; -typedef struct VkImageCopy2KHR { - VkStructureType sType; - const void* pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy2KHR; +typedef VkCopyBufferToImageInfo2 VkCopyBufferToImageInfo2KHR; -typedef struct VkCopyImageInfo2KHR { - VkStructureType sType; - const void* pNext; - VkImage srcImage; - VkImageLayout srcImageLayout; - VkImage dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageCopy2KHR* pRegions; -} VkCopyImageInfo2KHR; +typedef VkCopyImageToBufferInfo2 VkCopyImageToBufferInfo2KHR; -typedef struct VkBufferImageCopy2KHR { - VkStructureType sType; - const void* pNext; - VkDeviceSize bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy2KHR; +typedef VkBlitImageInfo2 VkBlitImageInfo2KHR; -typedef struct VkCopyBufferToImageInfo2KHR { - VkStructureType sType; - const void* pNext; - VkBuffer srcBuffer; - VkImage dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkBufferImageCopy2KHR* pRegions; -} VkCopyBufferToImageInfo2KHR; +typedef VkResolveImageInfo2 VkResolveImageInfo2KHR; -typedef struct VkCopyImageToBufferInfo2KHR { - VkStructureType sType; - const void* pNext; - VkImage srcImage; - VkImageLayout srcImageLayout; - VkBuffer dstBuffer; - uint32_t regionCount; - const VkBufferImageCopy2KHR* pRegions; -} VkCopyImageToBufferInfo2KHR; +typedef VkBufferCopy2 VkBufferCopy2KHR; -typedef struct VkImageBlit2KHR { - VkStructureType sType; - const void* pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets[2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets[2]; -} VkImageBlit2KHR; +typedef VkImageCopy2 VkImageCopy2KHR; -typedef struct VkBlitImageInfo2KHR { - VkStructureType sType; - const void* pNext; - VkImage srcImage; - VkImageLayout srcImageLayout; - VkImage dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageBlit2KHR* pRegions; - VkFilter filter; -} VkBlitImageInfo2KHR; +typedef VkImageBlit2 VkImageBlit2KHR; -typedef struct VkImageResolve2KHR { - VkStructureType sType; - const void* pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve2KHR; +typedef VkBufferImageCopy2 VkBufferImageCopy2KHR; -typedef struct VkResolveImageInfo2KHR { - VkStructureType sType; - const void* pNext; - VkImage srcImage; - VkImageLayout srcImageLayout; - VkImage dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageResolve2KHR* pRegions; -} VkResolveImageInfo2KHR; +typedef VkImageResolve2 VkImageResolve2KHR; -typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2KHR* pCopyBufferInfo); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2KHR* pCopyImageInfo); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2KHR* pCopyBufferToImageInfo); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2KHR* pCopyImageToBufferInfo); -typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2KHR* pBlitImageInfo); -typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2KHR* pResolveImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2* pCopyBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2* pCopyImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2* pBlitImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2* pResolveImageInfo); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer2KHR( VkCommandBuffer commandBuffer, - const VkCopyBufferInfo2KHR* pCopyBufferInfo); + const VkCopyBufferInfo2* pCopyBufferInfo); VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage2KHR( VkCommandBuffer commandBuffer, - const VkCopyImageInfo2KHR* pCopyImageInfo); + const VkCopyImageInfo2* pCopyImageInfo); VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage2KHR( VkCommandBuffer commandBuffer, - const VkCopyBufferToImageInfo2KHR* pCopyBufferToImageInfo); + const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer2KHR( VkCommandBuffer commandBuffer, - const VkCopyImageToBufferInfo2KHR* pCopyImageToBufferInfo); + const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage2KHR( VkCommandBuffer commandBuffer, - const VkBlitImageInfo2KHR* pBlitImageInfo); + const VkBlitImageInfo2* pBlitImageInfo); VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage2KHR( VkCommandBuffer commandBuffer, - const VkResolveImageInfo2KHR* pResolveImageInfo); + const VkResolveImageInfo2* pResolveImageInfo); +#endif + + +#define VK_KHR_format_feature_flags2 1 +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 1 +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME "VK_KHR_format_feature_flags2" +typedef VkFormatFeatureFlags2 VkFormatFeatureFlags2KHR; + +typedef VkFormatFeatureFlagBits2 VkFormatFeatureFlagBits2KHR; + +typedef VkFormatProperties3 VkFormatProperties3KHR; + + + +#define VK_KHR_portability_enumeration 1 +#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1 +#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration" + + +#define VK_KHR_maintenance4 1 +#define VK_KHR_MAINTENANCE_4_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4" +typedef VkPhysicalDeviceMaintenance4Features VkPhysicalDeviceMaintenance4FeaturesKHR; + +typedef VkPhysicalDeviceMaintenance4Properties VkPhysicalDeviceMaintenance4PropertiesKHR; + +typedef VkDeviceBufferMemoryRequirements VkDeviceBufferMemoryRequirementsKHR; + +typedef VkDeviceImageMemoryRequirements VkDeviceImageMemoryRequirementsKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice device, const VkDeviceBufferMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceBufferMemoryRequirementsKHR( + VkDevice device, + const VkDeviceBufferMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageMemoryRequirementsKHR( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirementsKHR( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); #endif @@ -8443,6 +9567,7 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT = 1000029001, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT = 1000366000, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, @@ -9028,11 +10153,7 @@ typedef struct VkValidationFlagsEXT { #define VK_EXT_texture_compression_astc_hdr 1 #define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_SPEC_VERSION 1 #define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" -typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 textureCompressionASTC_HDR; -} VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; +typedef VkPhysicalDeviceTextureCompressionASTCHDRFeatures VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; @@ -9302,8 +10423,10 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE( #define VK_NV_viewport_array2 1 -#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1 -#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2" +#define VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME "VK_NV_viewport_array2" +#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION +#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME #define VK_NVX_multiview_per_view_attributes 1 @@ -9658,35 +10781,13 @@ typedef VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFil #define VK_EXT_inline_uniform_block 1 #define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 #define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" -typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; -} VkPhysicalDeviceInlineUniformBlockFeaturesEXT; +typedef VkPhysicalDeviceInlineUniformBlockFeatures VkPhysicalDeviceInlineUniformBlockFeaturesEXT; -typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxInlineUniformBlockSize; - uint32_t maxPerStageDescriptorInlineUniformBlocks; - uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - uint32_t maxDescriptorSetInlineUniformBlocks; - uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; -} VkPhysicalDeviceInlineUniformBlockPropertiesEXT; +typedef VkPhysicalDeviceInlineUniformBlockProperties VkPhysicalDeviceInlineUniformBlockPropertiesEXT; -typedef struct VkWriteDescriptorSetInlineUniformBlockEXT { - VkStructureType sType; - const void* pNext; - uint32_t dataSize; - const void* pData; -} VkWriteDescriptorSetInlineUniformBlockEXT; +typedef VkWriteDescriptorSetInlineUniformBlock VkWriteDescriptorSetInlineUniformBlockEXT; -typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t maxInlineUniformBlockBindings; -} VkDescriptorPoolInlineUniformBlockCreateInfoEXT; +typedef VkDescriptorPoolInlineUniformBlockCreateInfo VkDescriptorPoolInlineUniformBlockCreateInfoEXT; @@ -9873,7 +10974,7 @@ typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { #define VK_EXT_image_drm_format_modifier 1 -#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 2 #define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" typedef struct VkDrmFormatModifierPropertiesEXT { uint64_t drmFormatModifier; @@ -9918,6 +11019,19 @@ typedef struct VkImageDrmFormatModifierPropertiesEXT { uint64_t drmFormatModifier; } VkImageDrmFormatModifierPropertiesEXT; +typedef struct VkDrmFormatModifierProperties2EXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags2 drmFormatModifierTilingFeatures; +} VkDrmFormatModifierProperties2EXT; + +typedef struct VkDrmFormatModifierPropertiesList2EXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierProperties2EXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesList2EXT; + typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties); #ifndef VK_NO_PROTOTYPES @@ -10519,19 +11633,9 @@ typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { #define VK_EXT_global_priority 1 #define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 #define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" +typedef VkQueueGlobalPriorityKHR VkQueueGlobalPriorityEXT; -typedef enum VkQueueGlobalPriorityEXT { - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024, - VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_EXT = 0x7FFFFFFF -} VkQueueGlobalPriorityEXT; -typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkQueueGlobalPriorityEXT globalPriority; -} VkDeviceQueueGlobalPriorityCreateInfoEXT; +typedef VkDeviceQueueGlobalPriorityCreateInfoKHR VkDeviceQueueGlobalPriorityCreateInfoEXT; @@ -10709,26 +11813,13 @@ typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { #define VK_EXT_pipeline_creation_feedback 1 #define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 #define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" +typedef VkPipelineCreationFeedbackFlagBits VkPipelineCreationFeedbackFlagBitsEXT; -typedef enum VkPipelineCreationFeedbackFlagBitsEXT { - VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = 0x00000001, - VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = 0x00000002, - VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = 0x00000004, - VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkPipelineCreationFeedbackFlagBitsEXT; -typedef VkFlags VkPipelineCreationFeedbackFlagsEXT; -typedef struct VkPipelineCreationFeedbackEXT { - VkPipelineCreationFeedbackFlagsEXT flags; - uint64_t duration; -} VkPipelineCreationFeedbackEXT; +typedef VkPipelineCreationFeedbackFlags VkPipelineCreationFeedbackFlagsEXT; -typedef struct VkPipelineCreationFeedbackCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineCreationFeedbackEXT* pPipelineCreationFeedback; - uint32_t pipelineStageCreationFeedbackCount; - VkPipelineCreationFeedbackEXT* pPipelineStageCreationFeedbacks; -} VkPipelineCreationFeedbackCreateInfoEXT; +typedef VkPipelineCreationFeedbackCreateInfo VkPipelineCreationFeedbackCreateInfoEXT; + +typedef VkPipelineCreationFeedback VkPipelineCreationFeedbackEXT; @@ -11079,7 +12170,7 @@ VKAPI_ATTR void VKAPI_CALL vkSetLocalDimmingAMD( #define VK_EXT_fragment_density_map 1 -#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 2 #define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { VkStructureType sType; @@ -11113,8 +12204,10 @@ typedef VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLay #define VK_GOOGLE_hlsl_functionality1 1 -#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1 -#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME #define VK_GOOGLE_decorate_string 1 @@ -11125,27 +12218,11 @@ typedef VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLay #define VK_EXT_subgroup_size_control 1 #define VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION 2 #define VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME "VK_EXT_subgroup_size_control" -typedef struct VkPhysicalDeviceSubgroupSizeControlFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 subgroupSizeControl; - VkBool32 computeFullSubgroups; -} VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; +typedef VkPhysicalDeviceSubgroupSizeControlFeatures VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; -typedef struct VkPhysicalDeviceSubgroupSizeControlPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t minSubgroupSize; - uint32_t maxSubgroupSize; - uint32_t maxComputeWorkgroupSubgroups; - VkShaderStageFlags requiredSubgroupSizeStages; -} VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; +typedef VkPhysicalDeviceSubgroupSizeControlProperties VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; -typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT { - VkStructureType sType; - void* pNext; - uint32_t requiredSubgroupSize; -} VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; +typedef VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; @@ -11262,35 +12339,19 @@ VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT( #define VK_EXT_tooling_info 1 #define VK_EXT_TOOLING_INFO_SPEC_VERSION 1 #define VK_EXT_TOOLING_INFO_EXTENSION_NAME "VK_EXT_tooling_info" +typedef VkToolPurposeFlagBits VkToolPurposeFlagBitsEXT; -typedef enum VkToolPurposeFlagBitsEXT { - VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = 0x00000001, - VK_TOOL_PURPOSE_PROFILING_BIT_EXT = 0x00000002, - VK_TOOL_PURPOSE_TRACING_BIT_EXT = 0x00000004, - VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = 0x00000008, - VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = 0x00000010, - VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 0x00000020, - VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 0x00000040, - VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkToolPurposeFlagBitsEXT; -typedef VkFlags VkToolPurposeFlagsEXT; -typedef struct VkPhysicalDeviceToolPropertiesEXT { - VkStructureType sType; - void* pNext; - char name[VK_MAX_EXTENSION_NAME_SIZE]; - char version[VK_MAX_EXTENSION_NAME_SIZE]; - VkToolPurposeFlagsEXT purposes; - char description[VK_MAX_DESCRIPTION_SIZE]; - char layer[VK_MAX_EXTENSION_NAME_SIZE]; -} VkPhysicalDeviceToolPropertiesEXT; +typedef VkToolPurposeFlags VkToolPurposeFlagsEXT; -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolPropertiesEXT* pToolProperties); +typedef VkPhysicalDeviceToolProperties VkPhysicalDeviceToolPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolProperties* pToolProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolPropertiesEXT( VkPhysicalDevice physicalDevice, uint32_t* pToolCount, - VkPhysicalDeviceToolPropertiesEXT* pToolProperties); + VkPhysicalDeviceToolProperties* pToolProperties); #endif @@ -11721,11 +12782,7 @@ typedef struct VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT { #define VK_EXT_shader_demote_to_helper_invocation 1 #define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 #define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" -typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 shaderDemoteToHelperInvocation; -} VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; +typedef VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; @@ -11947,14 +13004,7 @@ typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { VkBool32 texelBufferAlignment; } VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; -typedef struct VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT { - VkStructureType sType; - void* pNext; - VkDeviceSize storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; -} VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; +typedef VkPhysicalDeviceTexelBufferAlignmentProperties VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; @@ -12092,61 +13142,47 @@ typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { #define VK_EXT_private_data 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlotEXT) +typedef VkPrivateDataSlot VkPrivateDataSlotEXT; + #define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 #define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" +typedef VkPrivateDataSlotCreateFlags VkPrivateDataSlotCreateFlagsEXT; -typedef enum VkPrivateDataSlotCreateFlagBitsEXT { - VK_PRIVATE_DATA_SLOT_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkPrivateDataSlotCreateFlagBitsEXT; -typedef VkFlags VkPrivateDataSlotCreateFlagsEXT; -typedef struct VkPhysicalDevicePrivateDataFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 privateData; -} VkPhysicalDevicePrivateDataFeaturesEXT; +typedef VkPhysicalDevicePrivateDataFeatures VkPhysicalDevicePrivateDataFeaturesEXT; -typedef struct VkDevicePrivateDataCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t privateDataSlotRequestCount; -} VkDevicePrivateDataCreateInfoEXT; +typedef VkDevicePrivateDataCreateInfo VkDevicePrivateDataCreateInfoEXT; -typedef struct VkPrivateDataSlotCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPrivateDataSlotCreateFlagsEXT flags; -} VkPrivateDataSlotCreateInfoEXT; +typedef VkPrivateDataSlotCreateInfo VkPrivateDataSlotCreateInfoEXT; -typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlotEXT* pPrivateDataSlot); -typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlotEXT privateDataSlot, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t data); -typedef void (VKAPI_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t* pData); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlot* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t* pData); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlotEXT( VkDevice device, - const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkPrivateDataSlotCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, - VkPrivateDataSlotEXT* pPrivateDataSlot); + VkPrivateDataSlot* pPrivateDataSlot); VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlotEXT( VkDevice device, - VkPrivateDataSlotEXT privateDataSlot, + VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateDataEXT( VkDevice device, VkObjectType objectType, uint64_t objectHandle, - VkPrivateDataSlotEXT privateDataSlot, + VkPrivateDataSlot privateDataSlot, uint64_t data); VKAPI_ATTR void VKAPI_CALL vkGetPrivateDataEXT( VkDevice device, VkObjectType objectType, uint64_t objectHandle, - VkPrivateDataSlotEXT privateDataSlot, + VkPrivateDataSlot privateDataSlot, uint64_t* pData); #endif @@ -12154,11 +13190,7 @@ VKAPI_ATTR void VKAPI_CALL vkGetPrivateDataEXT( #define VK_EXT_pipeline_creation_cache_control 1 #define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 #define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" -typedef struct VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 pipelineCreationCacheControl; -} VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; +typedef VkPhysicalDevicePipelineCreationCacheControlFeatures VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; @@ -12192,6 +13224,39 @@ typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { #define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" +#define VK_EXT_graphics_pipeline_library 1 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION 1 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME "VK_EXT_graphics_pipeline_library" + +typedef enum VkGraphicsPipelineLibraryFlagBitsEXT { + VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT = 0x00000001, + VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT = 0x00000002, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT = 0x00000004, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT = 0x00000008, + VK_GRAPHICS_PIPELINE_LIBRARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkGraphicsPipelineLibraryFlagBitsEXT; +typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 graphicsPipelineLibrary; +} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT; + +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 graphicsPipelineLibraryFastLinking; + VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration; +} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT; + +typedef struct VkGraphicsPipelineLibraryCreateInfoEXT { + VkStructureType sType; + void* pNext; + VkGraphicsPipelineLibraryFlagsEXT flags; +} VkGraphicsPipelineLibraryCreateInfoEXT; + + + #define VK_NV_fragment_shading_rate_enums 1 #define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1 #define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums" @@ -12384,11 +13449,7 @@ typedef struct VkCopyCommandTransformInfoQCOM { #define VK_EXT_image_robustness 1 #define VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION 1 #define VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_image_robustness" -typedef struct VkPhysicalDeviceImageRobustnessFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 robustImageAccess; -} VkPhysicalDeviceImageRobustnessFeaturesEXT; +typedef VkPhysicalDeviceImageRobustnessFeatures VkPhysicalDeviceImageRobustnessFeaturesEXT; @@ -12404,6 +13465,30 @@ typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { +#define VK_ARM_rasterization_order_attachment_access 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_ARM_rasterization_order_attachment_access" +typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 rasterizationOrderColorAttachmentAccess; + VkBool32 rasterizationOrderDepthAttachmentAccess; + VkBool32 rasterizationOrderStencilAttachmentAccess; +} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM; + + + +#define VK_EXT_rgba10x6_formats 1 +#define VK_EXT_RGBA10X6_FORMATS_SPEC_VERSION 1 +#define VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME "VK_EXT_rgba10x6_formats" +typedef struct VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 formatRgba10x6WithoutYCbCrSampler; +} VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT; + + + #define VK_NV_acquire_winrt_display 1 #define VK_NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION 1 #define VK_NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME "VK_NV_acquire_winrt_display" @@ -12500,6 +13585,23 @@ typedef struct VkPhysicalDeviceDrmPropertiesEXT { +#define VK_EXT_depth_clip_control 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clip_control" +typedef struct VkPhysicalDeviceDepthClipControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClipControl; +} VkPhysicalDeviceDepthClipControlFeaturesEXT; + +typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 negativeOneToOne; +} VkPipelineViewportDepthClipControlCreateInfoEXT; + + + #define VK_EXT_primitive_topology_list_restart 1 #define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION 1 #define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME "VK_EXT_primitive_topology_list_restart" @@ -12660,22 +13762,43 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetColorWrite #endif -#define VK_EXT_global_priority_query 1 -#define VK_MAX_GLOBAL_PRIORITY_SIZE_EXT 16U -#define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1 -#define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query" -typedef struct VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT { +#define VK_EXT_primitives_generated_query 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME "VK_EXT_primitives_generated_query" +typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT { VkStructureType sType; void* pNext; - VkBool32 globalPriorityQuery; -} VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT; + VkBool32 primitivesGeneratedQuery; + VkBool32 primitivesGeneratedQueryWithRasterizerDiscard; + VkBool32 primitivesGeneratedQueryWithNonZeroStreams; +} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT; -typedef struct VkQueueFamilyGlobalPriorityPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t priorityCount; - VkQueueGlobalPriorityEXT priorities[VK_MAX_GLOBAL_PRIORITY_SIZE_EXT]; -} VkQueueFamilyGlobalPriorityPropertiesEXT; + + +#define VK_EXT_global_priority_query 1 +#define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1 +#define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query" +#define VK_MAX_GLOBAL_PRIORITY_SIZE_EXT VK_MAX_GLOBAL_PRIORITY_SIZE_KHR +typedef VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT; + +typedef VkQueueFamilyGlobalPriorityPropertiesKHR VkQueueFamilyGlobalPriorityPropertiesEXT; + + + +#define VK_EXT_image_view_min_lod 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME "VK_EXT_image_view_min_lod" +typedef struct VkPhysicalDeviceImageViewMinLodFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 minLod; +} VkPhysicalDeviceImageViewMinLodFeaturesEXT; + +typedef struct VkImageViewMinLodCreateInfoEXT { + VkStructureType sType; + const void* pNext; + float minLod; +} VkImageViewMinLodCreateInfoEXT; @@ -12728,11 +13851,42 @@ VKAPI_ATTR void VKAPI_CALL vkCmdDrawMultiIndexedEXT( #endif +#define VK_EXT_image_2d_view_of_3d 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_2d_view_of_3d" +typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 image2DViewOf3D; + VkBool32 sampler2DViewOf3D; +} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT; + + + #define VK_EXT_load_store_op_none 1 #define VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION 1 #define VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_EXT_load_store_op_none" +#define VK_EXT_border_color_swizzle 1 +#define VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION 1 +#define VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME "VK_EXT_border_color_swizzle" +typedef struct VkPhysicalDeviceBorderColorSwizzleFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 borderColorSwizzle; + VkBool32 borderColorSwizzleFromImage; +} VkPhysicalDeviceBorderColorSwizzleFeaturesEXT; + +typedef struct VkSamplerBorderColorComponentMappingCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkComponentMapping components; + VkBool32 srgb; +} VkSamplerBorderColorComponentMappingCreateInfoEXT; + + + #define VK_EXT_pageable_device_local_memory 1 #define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION 1 #define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME "VK_EXT_pageable_device_local_memory" @@ -12752,9 +13906,88 @@ VKAPI_ATTR void VKAPI_CALL vkSetDeviceMemoryPriorityEXT( #endif +#define VK_VALVE_descriptor_set_host_mapping 1 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION 1 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME "VK_VALVE_descriptor_set_host_mapping" +typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE { + VkStructureType sType; + void* pNext; + VkBool32 descriptorSetHostMapping; +} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE; + +typedef struct VkDescriptorSetBindingReferenceVALVE { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayout descriptorSetLayout; + uint32_t binding; +} VkDescriptorSetBindingReferenceVALVE; + +typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE { + VkStructureType sType; + void* pNext; + size_t descriptorOffset; + uint32_t descriptorSize; +} VkDescriptorSetLayoutHostMappingInfoVALVE; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice device, const VkDescriptorSetBindingReferenceVALVE* pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetHostMappingVALVE)(VkDevice device, VkDescriptorSet descriptorSet, void** ppData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutHostMappingInfoVALVE( + VkDevice device, + const VkDescriptorSetBindingReferenceVALVE* pBindingReference, + VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetHostMappingVALVE( + VkDevice device, + VkDescriptorSet descriptorSet, + void** ppData); +#endif + + +#define VK_QCOM_fragment_density_map_offset 1 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_QCOM_fragment_density_map_offset" +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMapOffset; +} VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM { + VkStructureType sType; + void* pNext; + VkExtent2D fragmentDensityOffsetGranularity; +} VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM; + +typedef struct VkSubpassFragmentDensityMapOffsetEndInfoQCOM { + VkStructureType sType; + const void* pNext; + uint32_t fragmentDensityOffsetCount; + const VkOffset2D* pFragmentDensityOffsets; +} VkSubpassFragmentDensityMapOffsetEndInfoQCOM; + + + +#define VK_NV_linear_color_attachment 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME "VK_NV_linear_color_attachment" +typedef struct VkPhysicalDeviceLinearColorAttachmentFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 linearColorAttachment; +} VkPhysicalDeviceLinearColorAttachmentFeaturesNV; + + + +#define VK_GOOGLE_surfaceless_query 1 +#define VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION 1 +#define VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME "VK_GOOGLE_surfaceless_query" + + #define VK_KHR_acceleration_structure 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) -#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 12 +#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13 #define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" typedef enum VkBuildAccelerationStructureModeKHR { diff --git a/vendor/vulkan/_gen/vulkan_ios.h b/vendor/vulkan/_gen/vulkan_ios.h index 6e7e6afea..579220543 100644 --- a/vendor/vulkan/_gen/vulkan_ios.h +++ b/vendor/vulkan/_gen/vulkan_ios.h @@ -2,7 +2,7 @@ #define VULKAN_IOS_H_ 1 /* -** Copyright 2015-2021 The Khronos Group Inc. +** Copyright 2015-2022 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/vendor/vulkan/_gen/vulkan_macos.h b/vendor/vulkan/_gen/vulkan_macos.h index c49b123d0..8e197c7cf 100644 --- a/vendor/vulkan/_gen/vulkan_macos.h +++ b/vendor/vulkan/_gen/vulkan_macos.h @@ -2,7 +2,7 @@ #define VULKAN_MACOS_H_ 1 /* -** Copyright 2015-2021 The Khronos Group Inc. +** Copyright 2015-2022 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/vendor/vulkan/_gen/vulkan_metal.h b/vendor/vulkan/_gen/vulkan_metal.h index 5cf4a703a..3631f1200 100644 --- a/vendor/vulkan/_gen/vulkan_metal.h +++ b/vendor/vulkan/_gen/vulkan_metal.h @@ -2,7 +2,7 @@ #define VULKAN_METAL_H_ 1 /* -** Copyright 2015-2021 The Khronos Group Inc. +** Copyright 2015-2022 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/vendor/vulkan/_gen/vulkan_win32.h b/vendor/vulkan/_gen/vulkan_win32.h index 1b680f0b1..affe0c02a 100644 --- a/vendor/vulkan/_gen/vulkan_win32.h +++ b/vendor/vulkan/_gen/vulkan_win32.h @@ -2,7 +2,7 @@ #define VULKAN_WIN32_H_ 1 /* -** Copyright 2015-2021 The Khronos Group Inc. +** Copyright 2015-2022 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/vendor/vulkan/core.odin b/vendor/vulkan/core.odin index 67ca47553..94c667910 100644 --- a/vendor/vulkan/core.odin +++ b/vendor/vulkan/core.odin @@ -39,18 +39,15 @@ MAX_MEMORY_TYPES :: 32 MAX_MEMORY_HEAPS :: 16 MAX_EXTENSION_NAME_SIZE :: 256 MAX_DESCRIPTION_SIZE :: 256 -MAX_DEVICE_GROUP_SIZE_KHX :: 32 MAX_DEVICE_GROUP_SIZE :: 32 LUID_SIZE_KHX :: 8 -LUID_SIZE_KHR :: 8 LUID_SIZE :: 8 -MAX_DRIVER_NAME_SIZE_KHR :: 256 -MAX_DRIVER_INFO_SIZE_KHR :: 256 -MAX_QUEUE_FAMILY_EXTERNAL :: ~u32(0)-1 +MAX_QUEUE_FAMILY_EXTERNAL :: ~u32(1) MAX_GLOBAL_PRIORITY_SIZE_EXT :: 16 +QUEUE_FAMILY_EXTERNAL :: MAX_QUEUE_FAMILY_EXTERNAL // General Constants -HEADER_VERSION :: 191 +HEADER_VERSION :: 211 MAX_DRIVER_NAME_SIZE :: 256 MAX_DRIVER_INFO_SIZE :: 256 @@ -70,6 +67,9 @@ KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME :: "VK_KHR_display_swapc KHR_sampler_mirror_clamp_to_edge :: 1 KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION :: 3 KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME :: "VK_KHR_sampler_mirror_clamp_to_edge" +KHR_dynamic_rendering :: 1 +KHR_DYNAMIC_RENDERING_SPEC_VERSION :: 1 +KHR_DYNAMIC_RENDERING_EXTENSION_NAME :: "VK_KHR_dynamic_rendering" KHR_multiview :: 1 KHR_MULTIVIEW_SPEC_VERSION :: 1 KHR_MULTIVIEW_EXTENSION_NAME :: "VK_KHR_multiview" @@ -83,17 +83,22 @@ KHR_shader_draw_parameters :: 1 KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION :: 1 KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME :: "VK_KHR_shader_draw_parameters" KHR_maintenance1 :: 1 -KHR_MAINTENANCE1_SPEC_VERSION :: 2 -KHR_MAINTENANCE1_EXTENSION_NAME :: "VK_KHR_maintenance1" +KHR_MAINTENANCE_1_SPEC_VERSION :: 2 +KHR_MAINTENANCE_1_EXTENSION_NAME :: "VK_KHR_maintenance1" +KHR_MAINTENANCE1_SPEC_VERSION :: KHR_MAINTENANCE_1_SPEC_VERSION +KHR_MAINTENANCE1_EXTENSION_NAME :: KHR_MAINTENANCE_1_EXTENSION_NAME KHR_device_group_creation :: 1 KHR_DEVICE_GROUP_CREATION_SPEC_VERSION :: 1 KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME :: "VK_KHR_device_group_creation" +MAX_DEVICE_GROUP_SIZE_KHR :: MAX_DEVICE_GROUP_SIZE KHR_external_memory_capabilities :: 1 KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION :: 1 KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME :: "VK_KHR_external_memory_capabilities" +LUID_SIZE_KHR :: LUID_SIZE KHR_external_memory :: 1 KHR_EXTERNAL_MEMORY_SPEC_VERSION :: 1 KHR_EXTERNAL_MEMORY_EXTENSION_NAME :: "VK_KHR_external_memory" +QUEUE_FAMILY_EXTERNAL_KHR :: QUEUE_FAMILY_EXTERNAL KHR_external_memory_fd :: 1 KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION :: 1 KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME :: "VK_KHR_external_memory_fd" @@ -143,8 +148,10 @@ KHR_performance_query :: 1 KHR_PERFORMANCE_QUERY_SPEC_VERSION :: 1 KHR_PERFORMANCE_QUERY_EXTENSION_NAME :: "VK_KHR_performance_query" KHR_maintenance2 :: 1 -KHR_MAINTENANCE2_SPEC_VERSION :: 1 -KHR_MAINTENANCE2_EXTENSION_NAME :: "VK_KHR_maintenance2" +KHR_MAINTENANCE_2_SPEC_VERSION :: 1 +KHR_MAINTENANCE_2_EXTENSION_NAME :: "VK_KHR_maintenance2" +KHR_MAINTENANCE2_SPEC_VERSION :: KHR_MAINTENANCE_2_SPEC_VERSION +KHR_MAINTENANCE2_EXTENSION_NAME :: KHR_MAINTENANCE_2_EXTENSION_NAME KHR_get_surface_capabilities2 :: 1 KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION :: 1 KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME :: "VK_KHR_get_surface_capabilities2" @@ -176,8 +183,10 @@ KHR_bind_memory2 :: 1 KHR_BIND_MEMORY_2_SPEC_VERSION :: 1 KHR_BIND_MEMORY_2_EXTENSION_NAME :: "VK_KHR_bind_memory2" KHR_maintenance3 :: 1 -KHR_MAINTENANCE3_SPEC_VERSION :: 1 -KHR_MAINTENANCE3_EXTENSION_NAME :: "VK_KHR_maintenance3" +KHR_MAINTENANCE_3_SPEC_VERSION :: 1 +KHR_MAINTENANCE_3_EXTENSION_NAME :: "VK_KHR_maintenance3" +KHR_MAINTENANCE3_SPEC_VERSION :: KHR_MAINTENANCE_3_SPEC_VERSION +KHR_MAINTENANCE3_EXTENSION_NAME :: KHR_MAINTENANCE_3_EXTENSION_NAME KHR_draw_indirect_count :: 1 KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION :: 1 KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME :: "VK_KHR_draw_indirect_count" @@ -193,9 +202,15 @@ KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME :: "VK_KHR_shader_atomic KHR_shader_clock :: 1 KHR_SHADER_CLOCK_SPEC_VERSION :: 1 KHR_SHADER_CLOCK_EXTENSION_NAME :: "VK_KHR_shader_clock" +KHR_global_priority :: 1 +MAX_GLOBAL_PRIORITY_SIZE_KHR :: 16 +KHR_GLOBAL_PRIORITY_SPEC_VERSION :: 1 +KHR_GLOBAL_PRIORITY_EXTENSION_NAME :: "VK_KHR_global_priority" KHR_driver_properties :: 1 KHR_DRIVER_PROPERTIES_SPEC_VERSION :: 1 KHR_DRIVER_PROPERTIES_EXTENSION_NAME :: "VK_KHR_driver_properties" +MAX_DRIVER_NAME_SIZE_KHR :: MAX_DRIVER_NAME_SIZE +MAX_DRIVER_INFO_SIZE_KHR :: MAX_DRIVER_INFO_SIZE KHR_shader_float_controls :: 1 KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION :: 4 KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME :: "VK_KHR_shader_float_controls" @@ -215,7 +230,7 @@ KHR_shader_terminate_invocation :: 1 KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION :: 1 KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME :: "VK_KHR_shader_terminate_invocation" KHR_fragment_shading_rate :: 1 -KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION :: 1 +KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION :: 2 KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME :: "VK_KHR_fragment_shading_rate" KHR_spirv_1_4 :: 1 KHR_SPIRV_1_4_SPEC_VERSION :: 1 @@ -268,6 +283,15 @@ KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME :: "VK_KHR_workgroup_mem KHR_copy_commands2 :: 1 KHR_COPY_COMMANDS_2_SPEC_VERSION :: 1 KHR_COPY_COMMANDS_2_EXTENSION_NAME :: "VK_KHR_copy_commands2" +KHR_format_feature_flags2 :: 1 +KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION :: 1 +KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME :: "VK_KHR_format_feature_flags2" +KHR_portability_enumeration :: 1 +KHR_PORTABILITY_ENUMERATION_SPEC_VERSION :: 1 +KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME :: "VK_KHR_portability_enumeration" +KHR_maintenance4 :: 1 +KHR_MAINTENANCE_4_SPEC_VERSION :: 2 +KHR_MAINTENANCE_4_EXTENSION_NAME :: "VK_KHR_maintenance4" EXT_debug_report :: 1 EXT_DEBUG_REPORT_SPEC_VERSION :: 10 EXT_DEBUG_REPORT_EXTENSION_NAME :: "VK_EXT_debug_report" @@ -374,8 +398,10 @@ NV_geometry_shader_passthrough :: 1 NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION :: 1 NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME :: "VK_NV_geometry_shader_passthrough" NV_viewport_array2 :: 1 -NV_VIEWPORT_ARRAY2_SPEC_VERSION :: 1 -NV_VIEWPORT_ARRAY2_EXTENSION_NAME :: "VK_NV_viewport_array2" +NV_VIEWPORT_ARRAY_2_SPEC_VERSION :: 1 +NV_VIEWPORT_ARRAY_2_EXTENSION_NAME :: "VK_NV_viewport_array2" +NV_VIEWPORT_ARRAY2_SPEC_VERSION :: NV_VIEWPORT_ARRAY_2_SPEC_VERSION +NV_VIEWPORT_ARRAY2_EXTENSION_NAME :: NV_VIEWPORT_ARRAY_2_EXTENSION_NAME NVX_multiview_per_view_attributes :: 1 NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION :: 1 NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME :: "VK_NVX_multiview_per_view_attributes" @@ -446,7 +472,7 @@ EXT_post_depth_coverage :: 1 EXT_POST_DEPTH_COVERAGE_SPEC_VERSION :: 1 EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME :: "VK_EXT_post_depth_coverage" EXT_image_drm_format_modifier :: 1 -EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION :: 1 +EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION :: 2 EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME :: "VK_EXT_image_drm_format_modifier" EXT_validation_cache :: 1 EXT_VALIDATION_CACHE_SPEC_VERSION :: 1 @@ -463,6 +489,7 @@ NV_SHADING_RATE_IMAGE_EXTENSION_NAME :: "VK_NV_shading_rate_i NV_ray_tracing :: 1 NV_RAY_TRACING_SPEC_VERSION :: 3 NV_RAY_TRACING_EXTENSION_NAME :: "VK_NV_ray_tracing" +SHADER_UNUSED_KHR :: 0 NV_representative_fragment_test :: 1 NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION :: 2 NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME :: "VK_NV_representative_fragment_test" @@ -524,14 +551,16 @@ AMD_display_native_hdr :: 1 AMD_DISPLAY_NATIVE_HDR_SPEC_VERSION :: 1 AMD_DISPLAY_NATIVE_HDR_EXTENSION_NAME :: "VK_AMD_display_native_hdr" EXT_fragment_density_map :: 1 -EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION :: 1 +EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION :: 2 EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME :: "VK_EXT_fragment_density_map" EXT_scalar_block_layout :: 1 EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION :: 1 EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME :: "VK_EXT_scalar_block_layout" GOOGLE_hlsl_functionality1 :: 1 -GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION :: 1 -GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME :: "VK_GOOGLE_hlsl_functionality1" +GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION :: 1 +GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME :: "VK_GOOGLE_hlsl_functionality1" +GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION :: GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION +GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME :: GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME GOOGLE_decorate_string :: 1 GOOGLE_DECORATE_STRING_SPEC_VERSION :: 1 GOOGLE_DECORATE_STRING_EXTENSION_NAME :: "VK_GOOGLE_decorate_string" @@ -640,6 +669,9 @@ EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME :: "VK_EXT_pipeline_crea NV_device_diagnostics_config :: 1 NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION :: 1 NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME :: "VK_NV_device_diagnostics_config" +EXT_graphics_pipeline_library :: 1 +EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION :: 1 +EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME :: "VK_EXT_graphics_pipeline_library" NV_fragment_shading_rate_enums :: 1 NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION :: 1 NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME :: "VK_NV_fragment_shading_rate_enums" @@ -658,6 +690,9 @@ EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME :: "VK_EXT_image_robustn EXT_4444_formats :: 1 EXT_4444_FORMATS_SPEC_VERSION :: 1 EXT_4444_FORMATS_EXTENSION_NAME :: "VK_EXT_4444_formats" +EXT_rgba10x6_formats :: 1 +EXT_RGBA10X6_FORMATS_SPEC_VERSION :: 1 +EXT_RGBA10X6_FORMATS_EXTENSION_NAME :: "VK_EXT_rgba10x6_formats" NV_acquire_winrt_display :: 1 NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION :: 1 NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME :: "VK_NV_acquire_winrt_display" @@ -667,6 +702,9 @@ EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME :: "VK_EXT_vertex_input_ EXT_physical_device_drm :: 1 EXT_PHYSICAL_DEVICE_DRM_SPEC_VERSION :: 1 EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME :: "VK_EXT_physical_device_drm" +EXT_depth_clip_control :: 1 +EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION :: 1 +EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME :: "VK_EXT_depth_clip_control" EXT_primitive_topology_list_restart :: 1 EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION :: 1 EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME :: "VK_EXT_primitive_topology_list_restart" @@ -679,20 +717,38 @@ EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME :: "VK_EXT_extended_dyna EXT_color_write_enable :: 1 EXT_COLOR_WRITE_ENABLE_SPEC_VERSION :: 1 EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME :: "VK_EXT_color_write_enable" +EXT_primitives_generated_query :: 1 +EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION :: 1 +EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME :: "VK_EXT_primitives_generated_query" EXT_global_priority_query :: 1 EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION :: 1 EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME :: "VK_EXT_global_priority_query" +EXT_image_view_min_lod :: 1 +EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION :: 1 +EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME :: "VK_EXT_image_view_min_lod" EXT_multi_draw :: 1 EXT_MULTI_DRAW_SPEC_VERSION :: 1 EXT_MULTI_DRAW_EXTENSION_NAME :: "VK_EXT_multi_draw" +EXT_image_2d_view_of_3d :: 1 +EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION :: 1 +EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME :: "VK_EXT_image_2d_view_of_3d" EXT_load_store_op_none :: 1 EXT_LOAD_STORE_OP_NONE_SPEC_VERSION :: 1 EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME :: "VK_EXT_load_store_op_none" +EXT_border_color_swizzle :: 1 +EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION :: 1 +EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME :: "VK_EXT_border_color_swizzle" EXT_pageable_device_local_memory :: 1 EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION :: 1 EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME :: "VK_EXT_pageable_device_local_memory" +NV_linear_color_attachment :: 1 +NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION :: 1 +NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME :: "VK_NV_linear_color_attachment" +GOOGLE_surfaceless_query :: 1 +GOOGLE_SURFACELESS_QUERY_SPEC_VERSION :: 1 +GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME :: "VK_GOOGLE_surfaceless_query" KHR_acceleration_structure :: 1 -KHR_ACCELERATION_STRUCTURE_SPEC_VERSION :: 12 +KHR_ACCELERATION_STRUCTURE_SPEC_VERSION :: 13 KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME :: "VK_KHR_acceleration_structure" KHR_ray_tracing_pipeline :: 1 KHR_RAY_TRACING_PIPELINE_SPEC_VERSION :: 1 @@ -756,6 +812,7 @@ Framebuffer :: distinct NonDispatchableHandle CommandPool :: distinct NonDispatchableHandle SamplerYcbcrConversion :: distinct NonDispatchableHandle DescriptorUpdateTemplate :: distinct NonDispatchableHandle +PrivateDataSlot :: distinct NonDispatchableHandle SurfaceKHR :: distinct NonDispatchableHandle SwapchainKHR :: distinct NonDispatchableHandle DisplayKHR :: distinct NonDispatchableHandle @@ -769,7 +826,6 @@ ValidationCacheEXT :: distinct NonDispatchableHandle AccelerationStructureNV :: distinct NonDispatchableHandle PerformanceConfigurationINTEL :: distinct NonDispatchableHandle IndirectCommandsLayoutNV :: distinct NonDispatchableHandle -PrivateDataSlotEXT :: distinct NonDispatchableHandle AccelerationStructureKHR :: distinct NonDispatchableHandle diff --git a/vendor/vulkan/enums.odin b/vendor/vulkan/enums.odin index be6691ab4..b2eec06ab 100644 --- a/vendor/vulkan/enums.odin +++ b/vendor/vulkan/enums.odin @@ -78,7 +78,7 @@ AccessFlag :: enum Flags { ACCELERATION_STRUCTURE_WRITE_NV = ACCELERATION_STRUCTURE_WRITE_KHR, } -AccessFlags_NONE_KHR :: AccessFlags{} +AccessFlags_NONE :: AccessFlags{} AcquireProfilingLockFlagsKHR :: distinct bit_set[AcquireProfilingLockFlagKHR; Flags] @@ -100,8 +100,7 @@ AttachmentLoadOp :: enum c.int { AttachmentStoreOp :: enum c.int { STORE = 0, DONT_CARE = 1, - NONE_EXT = 1000301000, - NONE_QCOM = NONE_EXT, + NONE = 1000301000, } BlendFactor :: enum c.int { @@ -460,6 +459,7 @@ DebugReportObjectTypeEXT :: enum c.int { CU_FUNCTION_NVX = 1000029001, ACCELERATION_STRUCTURE_KHR = 1000150000, ACCELERATION_STRUCTURE_NV = 1000165000, + BUFFER_COLLECTION_FUCHSIA = 1000366000, DEBUG_REPORT = DEBUG_REPORT_CALLBACK_EXT, VALIDATION_CACHE = VALIDATION_CACHE_EXT, DESCRIPTOR_UPDATE_TEMPLATE_KHR = DESCRIPTOR_UPDATE_TEMPLATE, @@ -530,10 +530,11 @@ DescriptorType :: enum c.int { UNIFORM_BUFFER_DYNAMIC = 8, STORAGE_BUFFER_DYNAMIC = 9, INPUT_ATTACHMENT = 10, - INLINE_UNIFORM_BLOCK_EXT = 1000138000, + INLINE_UNIFORM_BLOCK = 1000138000, ACCELERATION_STRUCTURE_KHR = 1000150000, ACCELERATION_STRUCTURE_NV = 1000165000, MUTABLE_VALVE = 1000351000, + INLINE_UNIFORM_BLOCK_EXT = INLINE_UNIFORM_BLOCK, } DescriptorUpdateTemplateType :: enum c.int { @@ -615,6 +616,11 @@ DriverId :: enum c.int { COREAVI_PROPRIETARY = 15, JUICE_PROPRIETARY = 16, VERISILICON_PROPRIETARY = 17, + MESA_TURNIP = 18, + MESA_V3DV = 19, + MESA_PANVK = 20, + SAMSUNG_PROPRIETARY = 21, + MESA_VENUS = 22, AMD_PROPRIETARY_KHR = AMD_PROPRIETARY, AMD_OPEN_SOURCE_KHR = AMD_OPEN_SOURCE, MESA_RADV_KHR = MESA_RADV, @@ -639,6 +645,21 @@ DynamicState :: enum c.int { STENCIL_COMPARE_MASK = 6, STENCIL_WRITE_MASK = 7, STENCIL_REFERENCE = 8, + CULL_MODE = 1000267000, + FRONT_FACE = 1000267001, + PRIMITIVE_TOPOLOGY = 1000267002, + VIEWPORT_WITH_COUNT = 1000267003, + SCISSOR_WITH_COUNT = 1000267004, + VERTEX_INPUT_BINDING_STRIDE = 1000267005, + DEPTH_TEST_ENABLE = 1000267006, + DEPTH_WRITE_ENABLE = 1000267007, + DEPTH_COMPARE_OP = 1000267008, + DEPTH_BOUNDS_TEST_ENABLE = 1000267009, + STENCIL_TEST_ENABLE = 1000267010, + STENCIL_OP = 1000267011, + RASTERIZER_DISCARD_ENABLE = 1000377001, + DEPTH_BIAS_ENABLE = 1000377002, + PRIMITIVE_RESTART_ENABLE = 1000377004, VIEWPORT_W_SCALING_NV = 1000087000, DISCARD_RECTANGLE_EXT = 1000099000, SAMPLE_LOCATIONS_EXT = 1000143000, @@ -648,30 +669,31 @@ DynamicState :: enum c.int { EXCLUSIVE_SCISSOR_NV = 1000205001, FRAGMENT_SHADING_RATE_KHR = 1000226000, LINE_STIPPLE_EXT = 1000259000, - CULL_MODE_EXT = 1000267000, - FRONT_FACE_EXT = 1000267001, - PRIMITIVE_TOPOLOGY_EXT = 1000267002, - VIEWPORT_WITH_COUNT_EXT = 1000267003, - SCISSOR_WITH_COUNT_EXT = 1000267004, - VERTEX_INPUT_BINDING_STRIDE_EXT = 1000267005, - DEPTH_TEST_ENABLE_EXT = 1000267006, - DEPTH_WRITE_ENABLE_EXT = 1000267007, - DEPTH_COMPARE_OP_EXT = 1000267008, - DEPTH_BOUNDS_TEST_ENABLE_EXT = 1000267009, - STENCIL_TEST_ENABLE_EXT = 1000267010, - STENCIL_OP_EXT = 1000267011, VERTEX_INPUT_EXT = 1000352000, PATCH_CONTROL_POINTS_EXT = 1000377000, - RASTERIZER_DISCARD_ENABLE_EXT = 1000377001, - DEPTH_BIAS_ENABLE_EXT = 1000377002, LOGIC_OP_EXT = 1000377003, - PRIMITIVE_RESTART_ENABLE_EXT = 1000377004, COLOR_WRITE_ENABLE_EXT = 1000381000, + CULL_MODE_EXT = CULL_MODE, + FRONT_FACE_EXT = FRONT_FACE, + PRIMITIVE_TOPOLOGY_EXT = PRIMITIVE_TOPOLOGY, + VIEWPORT_WITH_COUNT_EXT = VIEWPORT_WITH_COUNT, + SCISSOR_WITH_COUNT_EXT = SCISSOR_WITH_COUNT, + VERTEX_INPUT_BINDING_STRIDE_EXT = VERTEX_INPUT_BINDING_STRIDE, + DEPTH_TEST_ENABLE_EXT = DEPTH_TEST_ENABLE, + DEPTH_WRITE_ENABLE_EXT = DEPTH_WRITE_ENABLE, + DEPTH_COMPARE_OP_EXT = DEPTH_COMPARE_OP, + DEPTH_BOUNDS_TEST_ENABLE_EXT = DEPTH_BOUNDS_TEST_ENABLE, + STENCIL_TEST_ENABLE_EXT = STENCIL_TEST_ENABLE, + STENCIL_OP_EXT = STENCIL_OP, + RASTERIZER_DISCARD_ENABLE_EXT = RASTERIZER_DISCARD_ENABLE, + DEPTH_BIAS_ENABLE_EXT = DEPTH_BIAS_ENABLE, + PRIMITIVE_RESTART_ENABLE_EXT = PRIMITIVE_RESTART_ENABLE, } EventCreateFlags :: distinct bit_set[EventCreateFlag; Flags] EventCreateFlag :: enum Flags { - DEVICE_ONLY_KHR = 0, + DEVICE_ONLY = 0, + DEVICE_ONLY_KHR = DEVICE_ONLY, } ExternalFenceFeatureFlags :: distinct bit_set[ExternalFenceFeatureFlag; Flags] @@ -1005,6 +1027,26 @@ Format :: enum c.int { G16_B16_R16_3PLANE_422_UNORM = 1000156031, G16_B16R16_2PLANE_422_UNORM = 1000156032, G16_B16_R16_3PLANE_444_UNORM = 1000156033, + G8_B8R8_2PLANE_444_UNORM = 1000330000, + G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + G16_B16R16_2PLANE_444_UNORM = 1000330003, + A4R4G4B4_UNORM_PACK16 = 1000340000, + A4B4G4R4_UNORM_PACK16 = 1000340001, + ASTC_4x4_SFLOAT_BLOCK = 1000066000, + ASTC_5x4_SFLOAT_BLOCK = 1000066001, + ASTC_5x5_SFLOAT_BLOCK = 1000066002, + ASTC_6x5_SFLOAT_BLOCK = 1000066003, + ASTC_6x6_SFLOAT_BLOCK = 1000066004, + ASTC_8x5_SFLOAT_BLOCK = 1000066005, + ASTC_8x6_SFLOAT_BLOCK = 1000066006, + ASTC_8x8_SFLOAT_BLOCK = 1000066007, + ASTC_10x5_SFLOAT_BLOCK = 1000066008, + ASTC_10x6_SFLOAT_BLOCK = 1000066009, + ASTC_10x8_SFLOAT_BLOCK = 1000066010, + ASTC_10x10_SFLOAT_BLOCK = 1000066011, + ASTC_12x10_SFLOAT_BLOCK = 1000066012, + ASTC_12x12_SFLOAT_BLOCK = 1000066013, PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, @@ -1013,26 +1055,20 @@ Format :: enum c.int { PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - ASTC_4x4_SFLOAT_BLOCK_EXT = 1000066000, - ASTC_5x4_SFLOAT_BLOCK_EXT = 1000066001, - ASTC_5x5_SFLOAT_BLOCK_EXT = 1000066002, - ASTC_6x5_SFLOAT_BLOCK_EXT = 1000066003, - ASTC_6x6_SFLOAT_BLOCK_EXT = 1000066004, - ASTC_8x5_SFLOAT_BLOCK_EXT = 1000066005, - ASTC_8x6_SFLOAT_BLOCK_EXT = 1000066006, - ASTC_8x8_SFLOAT_BLOCK_EXT = 1000066007, - ASTC_10x5_SFLOAT_BLOCK_EXT = 1000066008, - ASTC_10x6_SFLOAT_BLOCK_EXT = 1000066009, - ASTC_10x8_SFLOAT_BLOCK_EXT = 1000066010, - ASTC_10x10_SFLOAT_BLOCK_EXT = 1000066011, - ASTC_12x10_SFLOAT_BLOCK_EXT = 1000066012, - ASTC_12x12_SFLOAT_BLOCK_EXT = 1000066013, - G8_B8R8_2PLANE_444_UNORM_EXT = 1000330000, - G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = 1000330001, - G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = 1000330002, - G16_B16R16_2PLANE_444_UNORM_EXT = 1000330003, - A4R4G4B4_UNORM_PACK16_EXT = 1000340000, - A4B4G4R4_UNORM_PACK16_EXT = 1000340001, + ASTC_4x4_SFLOAT_BLOCK_EXT = ASTC_4x4_SFLOAT_BLOCK, + ASTC_5x4_SFLOAT_BLOCK_EXT = ASTC_5x4_SFLOAT_BLOCK, + ASTC_5x5_SFLOAT_BLOCK_EXT = ASTC_5x5_SFLOAT_BLOCK, + ASTC_6x5_SFLOAT_BLOCK_EXT = ASTC_6x5_SFLOAT_BLOCK, + ASTC_6x6_SFLOAT_BLOCK_EXT = ASTC_6x6_SFLOAT_BLOCK, + ASTC_8x5_SFLOAT_BLOCK_EXT = ASTC_8x5_SFLOAT_BLOCK, + ASTC_8x6_SFLOAT_BLOCK_EXT = ASTC_8x6_SFLOAT_BLOCK, + ASTC_8x8_SFLOAT_BLOCK_EXT = ASTC_8x8_SFLOAT_BLOCK, + ASTC_10x5_SFLOAT_BLOCK_EXT = ASTC_10x5_SFLOAT_BLOCK, + ASTC_10x6_SFLOAT_BLOCK_EXT = ASTC_10x6_SFLOAT_BLOCK, + ASTC_10x8_SFLOAT_BLOCK_EXT = ASTC_10x8_SFLOAT_BLOCK, + ASTC_10x10_SFLOAT_BLOCK_EXT = ASTC_10x10_SFLOAT_BLOCK, + ASTC_12x10_SFLOAT_BLOCK_EXT = ASTC_12x10_SFLOAT_BLOCK, + ASTC_12x12_SFLOAT_BLOCK_EXT = ASTC_12x12_SFLOAT_BLOCK, G8B8G8R8_422_UNORM_KHR = G8B8G8R8_422_UNORM, B8G8R8G8_422_UNORM_KHR = B8G8R8G8_422_UNORM, G8_B8_R8_3PLANE_420_UNORM_KHR = G8_B8_R8_3PLANE_420_UNORM, @@ -1067,6 +1103,12 @@ Format :: enum c.int { G16_B16_R16_3PLANE_422_UNORM_KHR = G16_B16_R16_3PLANE_422_UNORM, G16_B16R16_2PLANE_422_UNORM_KHR = G16_B16R16_2PLANE_422_UNORM, G16_B16_R16_3PLANE_444_UNORM_KHR = G16_B16_R16_3PLANE_444_UNORM, + G8_B8R8_2PLANE_444_UNORM_EXT = G8_B8R8_2PLANE_444_UNORM, + G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, + G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, + G16_B16R16_2PLANE_444_UNORM_EXT = G16_B16R16_2PLANE_444_UNORM, + A4R4G4B4_UNORM_PACK16_EXT = A4R4G4B4_UNORM_PACK16, + A4B4G4R4_UNORM_PACK16_EXT = A4B4G4R4_UNORM_PACK16, } FormatFeatureFlags :: distinct bit_set[FormatFeatureFlag; Flags] @@ -1190,6 +1232,14 @@ GeometryTypeKHR :: enum c.int { AABBS_NV = AABBS, } +GraphicsPipelineLibraryFlagsEXT :: distinct bit_set[GraphicsPipelineLibraryFlagEXT; Flags] +GraphicsPipelineLibraryFlagEXT :: enum Flags { + VERTEX_INPUT_INTERFACE = 0, + PRE_RASTERIZATION_SHADERS = 1, + FRAGMENT_SHADER = 2, + FRAGMENT_OUTPUT_INTERFACE = 3, +} + ImageAspectFlags :: distinct bit_set[ImageAspectFlag; Flags] ImageAspectFlag :: enum Flags { COLOR = 0, @@ -1208,6 +1258,9 @@ ImageAspectFlag :: enum Flags { PLANE_2_KHR = PLANE_2, } +ImageAspectFlags_NONE :: ImageAspectFlags{} + + ImageCreateFlags :: distinct bit_set[ImageCreateFlag; Flags] ImageCreateFlag :: enum Flags { SPARSE_BINDING = 0, @@ -1225,6 +1278,8 @@ ImageCreateFlag :: enum Flags { CORNER_SAMPLED_NV = 13, SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_EXT = 12, SUBSAMPLED_EXT = 14, + D2_VIEW_COMPATIBLE_EXT = 17, + FRAGMENT_DENSITY_MAP_OFFSET_QCOM = 15, SPLIT_INSTANCE_BIND_REGIONS_KHR = SPLIT_INSTANCE_BIND_REGIONS, D2_ARRAY_COMPATIBLE_KHR = D2_ARRAY_COMPATIBLE, BLOCK_TEXEL_VIEW_COMPATIBLE_KHR = BLOCK_TEXEL_VIEW_COMPATIBLE, @@ -1249,6 +1304,8 @@ ImageLayout :: enum c.int { DEPTH_READ_ONLY_OPTIMAL = 1000241001, STENCIL_ATTACHMENT_OPTIMAL = 1000241002, STENCIL_READ_ONLY_OPTIMAL = 1000241003, + READ_ONLY_OPTIMAL = 1000314000, + ATTACHMENT_OPTIMAL = 1000314001, PRESENT_SRC_KHR = 1000001002, VIDEO_DECODE_DST_KHR = 1000024000, VIDEO_DECODE_SRC_KHR = 1000024001, @@ -1259,8 +1316,6 @@ ImageLayout :: enum c.int { VIDEO_ENCODE_DST_KHR = 1000299000, VIDEO_ENCODE_SRC_KHR = 1000299001, VIDEO_ENCODE_DPB_KHR = 1000299002, - READ_ONLY_OPTIMAL_KHR = 1000314000, - ATTACHMENT_OPTIMAL_KHR = 1000314001, DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, SHADING_RATE_OPTIMAL_NV = FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, @@ -1268,6 +1323,8 @@ ImageLayout :: enum c.int { DEPTH_READ_ONLY_OPTIMAL_KHR = DEPTH_READ_ONLY_OPTIMAL, STENCIL_ATTACHMENT_OPTIMAL_KHR = STENCIL_ATTACHMENT_OPTIMAL, STENCIL_READ_ONLY_OPTIMAL_KHR = STENCIL_READ_ONLY_OPTIMAL, + READ_ONLY_OPTIMAL_KHR = READ_ONLY_OPTIMAL, + ATTACHMENT_OPTIMAL_KHR = ATTACHMENT_OPTIMAL, } ImageTiling :: enum c.int { @@ -1351,6 +1408,11 @@ IndirectStateFlagNV :: enum Flags { FLAG_FRONTFACE = 0, } +InstanceCreateFlags :: distinct bit_set[InstanceCreateFlag; Flags] +InstanceCreateFlag :: enum Flags { + ENUMERATE_PORTABILITY_KHR = 0, +} + InternalAllocationType :: enum c.int { EXECUTABLE = 0, } @@ -1446,6 +1508,7 @@ ObjectType :: enum c.int { COMMAND_POOL = 25, SAMPLER_YCBCR_CONVERSION = 1000156000, DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + PRIVATE_DATA_SLOT = 1000295000, SURFACE_KHR = 1000000000, SWAPCHAIN_KHR = 1000001000, DISPLAY_KHR = 1000002000, @@ -1462,9 +1525,10 @@ ObjectType :: enum c.int { PERFORMANCE_CONFIGURATION_INTEL = 1000210000, DEFERRED_OPERATION_KHR = 1000268000, INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, - PRIVATE_DATA_SLOT_EXT = 1000295000, + BUFFER_COLLECTION_FUCHSIA = 1000366000, DESCRIPTOR_UPDATE_TEMPLATE_KHR = DESCRIPTOR_UPDATE_TEMPLATE, SAMPLER_YCBCR_CONVERSION_KHR = SAMPLER_YCBCR_CONVERSION, + PRIVATE_DATA_SLOT_EXT = PRIVATE_DATA_SLOT, } PeerMemoryFeatureFlags :: distinct bit_set[PeerMemoryFeatureFlag; Flags] @@ -1557,48 +1621,71 @@ PipelineBindPoint :: enum c.int { PipelineCacheCreateFlags :: distinct bit_set[PipelineCacheCreateFlag; Flags] PipelineCacheCreateFlag :: enum Flags { - EXTERNALLY_SYNCHRONIZED_EXT = 0, + EXTERNALLY_SYNCHRONIZED = 0, + EXTERNALLY_SYNCHRONIZED_EXT = EXTERNALLY_SYNCHRONIZED, } PipelineCacheHeaderVersion :: enum c.int { ONE = 1, } +PipelineColorBlendStateCreateFlags :: distinct bit_set[PipelineColorBlendStateCreateFlag; Flags] +PipelineColorBlendStateCreateFlag :: enum Flags { + RASTERIZATION_ORDER_ATTACHMENT_ACCESS_ARM = 0, +} + PipelineCompilerControlFlagsAMD :: distinct bit_set[PipelineCompilerControlFlagAMD; Flags] PipelineCompilerControlFlagAMD :: enum Flags { } PipelineCreateFlags :: distinct bit_set[PipelineCreateFlag; Flags] PipelineCreateFlag :: enum Flags { - DISABLE_OPTIMIZATION = 0, - ALLOW_DERIVATIVES = 1, - DERIVATIVE = 2, - VIEW_INDEX_FROM_DEVICE_INDEX = 3, - DISPATCH_BASE = 4, - RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_KHR = 14, - RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_KHR = 15, - RAY_TRACING_NO_NULL_MISS_SHADERS_KHR = 16, - RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_KHR = 17, - RAY_TRACING_SKIP_TRIANGLES_KHR = 12, - RAY_TRACING_SKIP_AABBS_KHR = 13, - RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_KHR = 19, - DEFER_COMPILE_NV = 5, - CAPTURE_STATISTICS_KHR = 6, - CAPTURE_INTERNAL_REPRESENTATIONS_KHR = 7, - INDIRECT_BINDABLE_NV = 18, - LIBRARY_KHR = 11, - FAIL_ON_PIPELINE_COMPILE_REQUIRED_EXT = 8, - EARLY_RETURN_ON_FAILURE_EXT = 9, - RAY_TRACING_ALLOW_MOTION_NV = 20, - VIEW_INDEX_FROM_DEVICE_INDEX_KHR = VIEW_INDEX_FROM_DEVICE_INDEX, - DISPATCH_BASE_KHR = DISPATCH_BASE, + DISABLE_OPTIMIZATION = 0, + ALLOW_DERIVATIVES = 1, + DERIVATIVE = 2, + VIEW_INDEX_FROM_DEVICE_INDEX = 3, + DISPATCH_BASE = 4, + FAIL_ON_PIPELINE_COMPILE_REQUIRED = 8, + EARLY_RETURN_ON_FAILURE = 9, + RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_KHR = 21, + RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_EXT = 22, + RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_KHR = 14, + RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_KHR = 15, + RAY_TRACING_NO_NULL_MISS_SHADERS_KHR = 16, + RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_KHR = 17, + RAY_TRACING_SKIP_TRIANGLES_KHR = 12, + RAY_TRACING_SKIP_AABBS_KHR = 13, + RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_KHR = 19, + DEFER_COMPILE_NV = 5, + CAPTURE_STATISTICS_KHR = 6, + CAPTURE_INTERNAL_REPRESENTATIONS_KHR = 7, + INDIRECT_BINDABLE_NV = 18, + LIBRARY_KHR = 11, + RETAIN_LINK_TIME_OPTIMIZATION_INFO_EXT = 23, + LINK_TIME_OPTIMIZATION_EXT = 10, + RAY_TRACING_ALLOW_MOTION_NV = 20, + PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_KHR = RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_KHR, + PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_EXT = RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_EXT, + VIEW_INDEX_FROM_DEVICE_INDEX_KHR = VIEW_INDEX_FROM_DEVICE_INDEX, + DISPATCH_BASE_KHR = DISPATCH_BASE, + FAIL_ON_PIPELINE_COMPILE_REQUIRED_EXT = FAIL_ON_PIPELINE_COMPILE_REQUIRED, + EARLY_RETURN_ON_FAILURE_EXT = EARLY_RETURN_ON_FAILURE, } -PipelineCreationFeedbackFlagsEXT :: distinct bit_set[PipelineCreationFeedbackFlagEXT; Flags] -PipelineCreationFeedbackFlagEXT :: enum Flags { - VALID = 0, - APPLICATION_PIPELINE_CACHE_HIT = 1, - BASE_PIPELINE_ACCELERATION = 2, +PipelineCreationFeedbackFlags :: distinct bit_set[PipelineCreationFeedbackFlag; Flags] +PipelineCreationFeedbackFlag :: enum Flags { + VALID = 0, + APPLICATION_PIPELINE_CACHE_HIT = 1, + BASE_PIPELINE_ACCELERATION = 2, + VALID_EXT = VALID, + APPLICATION_PIPELINE_CACHE_HIT_EXT = APPLICATION_PIPELINE_CACHE_HIT, + BASE_PIPELINE_ACCELERATION_EXT = BASE_PIPELINE_ACCELERATION, +} + +PipelineDepthStencilStateCreateFlags :: distinct bit_set[PipelineDepthStencilStateCreateFlag; Flags] +PipelineDepthStencilStateCreateFlag :: enum Flags { + RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_ARM = 0, + RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_ARM = 1, } PipelineExecutableStatisticFormatKHR :: enum c.int { @@ -1608,10 +1695,17 @@ PipelineExecutableStatisticFormatKHR :: enum c.int { FLOAT64 = 3, } +PipelineLayoutCreateFlags :: distinct bit_set[PipelineLayoutCreateFlag; Flags] +PipelineLayoutCreateFlag :: enum Flags { + INDEPENDENT_SETS_EXT = 1, +} + PipelineShaderStageCreateFlags :: distinct bit_set[PipelineShaderStageCreateFlag; Flags] PipelineShaderStageCreateFlag :: enum Flags { - ALLOW_VARYING_SUBGROUP_SIZE_EXT = 0, - REQUIRE_FULL_SUBGROUPS_EXT = 1, + ALLOW_VARYING_SUBGROUP_SIZE = 0, + REQUIRE_FULL_SUBGROUPS = 1, + ALLOW_VARYING_SUBGROUP_SIZE_EXT = ALLOW_VARYING_SUBGROUP_SIZE, + REQUIRE_FULL_SUBGROUPS_EXT = REQUIRE_FULL_SUBGROUPS, } PipelineStageFlags :: distinct bit_set[PipelineStageFlag; Flags] @@ -1647,7 +1741,7 @@ PipelineStageFlag :: enum Flags { ACCELERATION_STRUCTURE_BUILD_NV = ACCELERATION_STRUCTURE_BUILD_KHR, } -PipelineStageFlags_NONE_KHR :: PipelineStageFlags{} +PipelineStageFlags_NONE :: PipelineStageFlags{} PointClippingBehavior :: enum c.int { @@ -1687,10 +1781,6 @@ PrimitiveTopology :: enum c.int { PATCH_LIST = 10, } -PrivateDataSlotCreateFlagsEXT :: distinct bit_set[PrivateDataSlotCreateFlagEXT; Flags] -PrivateDataSlotCreateFlagEXT :: enum Flags { -} - ProvokingVertexModeEXT :: enum c.int { FIRST_VERTEX = 0, LAST_VERTEX = 1, @@ -1741,6 +1831,7 @@ QueryType :: enum c.int { ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, PERFORMANCE_QUERY_INTEL = 1000210000, VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR = 1000299000, + PRIMITIVES_GENERATED_EXT = 1000382000, } QueueFlags :: distinct bit_set[QueueFlag; Flags] @@ -1754,11 +1845,15 @@ QueueFlag :: enum Flags { VIDEO_ENCODE_KHR = 6, } -QueueGlobalPriorityEXT :: enum c.int { - LOW = 128, - MEDIUM = 256, - HIGH = 512, - REALTIME = 1024, +QueueGlobalPriorityKHR :: enum c.int { + LOW = 128, + MEDIUM = 256, + HIGH = 512, + REALTIME = 1024, + LOW_EXT = LOW, + MEDIUM_EXT = MEDIUM, + HIGH_EXT = HIGH, + REALTIME_EXT = REALTIME, } RasterizationOrderAMD :: enum c.int { @@ -1780,6 +1875,16 @@ RenderPassCreateFlag :: enum Flags { TRANSFORM_QCOM = 1, } +RenderingFlags :: distinct bit_set[RenderingFlag; Flags] +RenderingFlag :: enum Flags { + CONTENTS_SECONDARY_COMMAND_BUFFERS = 0, + SUSPENDING = 1, + RESUMING = 2, + CONTENTS_SECONDARY_COMMAND_BUFFERS_KHR = CONTENTS_SECONDARY_COMMAND_BUFFERS, + SUSPENDING_KHR = SUSPENDING, + RESUMING_KHR = RESUMING, +} + ResolveModeFlags :: distinct bit_set[ResolveModeFlag; Flags] ResolveModeFlag :: enum Flags { SAMPLE_ZERO = 0, @@ -1819,6 +1924,7 @@ Result :: enum c.int { ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, ERROR_FRAGMENTATION = -1000161000, ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, + PIPELINE_COMPILE_REQUIRED = 1000297000, ERROR_SURFACE_LOST_KHR = -1000000000, ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, SUBOPTIMAL_KHR = 1000001003, @@ -1827,19 +1933,20 @@ Result :: enum c.int { ERROR_VALIDATION_FAILED_EXT = -1000011001, ERROR_INVALID_SHADER_NV = -1000012000, ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, - ERROR_NOT_PERMITTED_EXT = -1000174001, + ERROR_NOT_PERMITTED_KHR = -1000174001, ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, THREAD_IDLE_KHR = 1000268000, THREAD_DONE_KHR = 1000268001, OPERATION_DEFERRED_KHR = 1000268002, OPERATION_NOT_DEFERRED_KHR = 1000268003, - PIPELINE_COMPILE_REQUIRED_EXT = 1000297000, ERROR_OUT_OF_POOL_MEMORY_KHR = ERROR_OUT_OF_POOL_MEMORY, ERROR_INVALID_EXTERNAL_HANDLE_KHR = ERROR_INVALID_EXTERNAL_HANDLE, ERROR_FRAGMENTATION_EXT = ERROR_FRAGMENTATION, + ERROR_NOT_PERMITTED_EXT = ERROR_NOT_PERMITTED_KHR, ERROR_INVALID_DEVICE_ADDRESS_EXT = ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, - ERROR_PIPELINE_COMPILE_REQUIRED_EXT = PIPELINE_COMPILE_REQUIRED_EXT, + PIPELINE_COMPILE_REQUIRED_EXT = PIPELINE_COMPILE_REQUIRED, + ERROR_PIPELINE_COMPILE_REQUIRED_EXT = PIPELINE_COMPILE_REQUIRED, } SampleCountFlags :: distinct bit_set[SampleCountFlag; Flags] @@ -2036,692 +2143,809 @@ StencilOp :: enum c.int { } StructureType :: enum c.int { - APPLICATION_INFO = 0, - INSTANCE_CREATE_INFO = 1, - DEVICE_QUEUE_CREATE_INFO = 2, - DEVICE_CREATE_INFO = 3, - SUBMIT_INFO = 4, - MEMORY_ALLOCATE_INFO = 5, - MAPPED_MEMORY_RANGE = 6, - BIND_SPARSE_INFO = 7, - FENCE_CREATE_INFO = 8, - SEMAPHORE_CREATE_INFO = 9, - EVENT_CREATE_INFO = 10, - QUERY_POOL_CREATE_INFO = 11, - BUFFER_CREATE_INFO = 12, - BUFFER_VIEW_CREATE_INFO = 13, - IMAGE_CREATE_INFO = 14, - IMAGE_VIEW_CREATE_INFO = 15, - SHADER_MODULE_CREATE_INFO = 16, - PIPELINE_CACHE_CREATE_INFO = 17, - PIPELINE_SHADER_STAGE_CREATE_INFO = 18, - PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, - PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, - PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, - PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, - PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, - PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, - PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, - PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, - PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, - GRAPHICS_PIPELINE_CREATE_INFO = 28, - COMPUTE_PIPELINE_CREATE_INFO = 29, - PIPELINE_LAYOUT_CREATE_INFO = 30, - SAMPLER_CREATE_INFO = 31, - DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, - DESCRIPTOR_POOL_CREATE_INFO = 33, - DESCRIPTOR_SET_ALLOCATE_INFO = 34, - WRITE_DESCRIPTOR_SET = 35, - COPY_DESCRIPTOR_SET = 36, - FRAMEBUFFER_CREATE_INFO = 37, - RENDER_PASS_CREATE_INFO = 38, - COMMAND_POOL_CREATE_INFO = 39, - COMMAND_BUFFER_ALLOCATE_INFO = 40, - COMMAND_BUFFER_INHERITANCE_INFO = 41, - COMMAND_BUFFER_BEGIN_INFO = 42, - RENDER_PASS_BEGIN_INFO = 43, - BUFFER_MEMORY_BARRIER = 44, - IMAGE_MEMORY_BARRIER = 45, - MEMORY_BARRIER = 46, - LOADER_INSTANCE_CREATE_INFO = 47, - LOADER_DEVICE_CREATE_INFO = 48, - PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, - BIND_BUFFER_MEMORY_INFO = 1000157000, - BIND_IMAGE_MEMORY_INFO = 1000157001, - PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, - MEMORY_DEDICATED_REQUIREMENTS = 1000127000, - MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, - MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, - DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, - DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, - DEVICE_GROUP_SUBMIT_INFO = 1000060005, - DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, - BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, - BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, - PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, - DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, - BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, - IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, - IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, - MEMORY_REQUIREMENTS_2 = 1000146003, - SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, - PHYSICAL_DEVICE_FEATURES_2 = 1000059000, - PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, - FORMAT_PROPERTIES_2 = 1000059002, - IMAGE_FORMAT_PROPERTIES_2 = 1000059003, - PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, - QUEUE_FAMILY_PROPERTIES_2 = 1000059005, - PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, - SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, - PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, - PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, - RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, - IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, - PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, - RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, - PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, - PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, - PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, - PROTECTED_SUBMIT_INFO = 1000145000, - PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, - PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, - DEVICE_QUEUE_INFO_2 = 1000145003, - SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, - SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, - BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, - IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, - PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, - SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, - DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, - PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, - EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, - PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, - EXTERNAL_BUFFER_PROPERTIES = 1000071003, - PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, - EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, - EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, - EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, - PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, - EXTERNAL_FENCE_PROPERTIES = 1000112001, - EXPORT_FENCE_CREATE_INFO = 1000113000, - EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, - PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, - EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, - PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, - DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, - PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, - PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, - PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50, - PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51, - PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52, - IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000, - ATTACHMENT_DESCRIPTION_2 = 1000109000, - ATTACHMENT_REFERENCE_2 = 1000109001, - SUBPASS_DESCRIPTION_2 = 1000109002, - SUBPASS_DEPENDENCY_2 = 1000109003, - RENDER_PASS_CREATE_INFO_2 = 1000109004, - SUBPASS_BEGIN_INFO = 1000109005, - SUBPASS_END_INFO = 1000109006, - PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000, - PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000, - PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000, - PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000, - PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000, - DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000, - PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001, - PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002, - DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003, - DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004, - PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000, - SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001, - PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000, - IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000, - PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000, - SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001, - PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000, - PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000, - FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001, - FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002, - RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003, - PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000, - PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000, - PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000, - ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001, - ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002, - PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000, - PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000, - PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001, - SEMAPHORE_TYPE_CREATE_INFO = 1000207002, - TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003, - SEMAPHORE_WAIT_INFO = 1000207004, - SEMAPHORE_SIGNAL_INFO = 1000207005, - PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000, - BUFFER_DEVICE_ADDRESS_INFO = 1000244001, - BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, - MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, - DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, - SWAPCHAIN_CREATE_INFO_KHR = 1000001000, - PRESENT_INFO_KHR = 1000001001, - DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, - IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, - BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, - ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, - DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, - DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, - DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, - DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, - DISPLAY_PRESENT_INFO_KHR = 1000003000, - XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, - XCB_SURFACE_CREATE_INFO_KHR = 1000005000, - WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, - WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, - DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, - PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, - DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, - DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, - DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, - VIDEO_PROFILE_KHR = 1000023000, - VIDEO_CAPABILITIES_KHR = 1000023001, - VIDEO_PICTURE_RESOURCE_KHR = 1000023002, - VIDEO_GET_MEMORY_PROPERTIES_KHR = 1000023003, - VIDEO_BIND_MEMORY_KHR = 1000023004, - VIDEO_SESSION_CREATE_INFO_KHR = 1000023005, - VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000023006, - VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR = 1000023007, - VIDEO_BEGIN_CODING_INFO_KHR = 1000023008, - VIDEO_END_CODING_INFO_KHR = 1000023009, - VIDEO_CODING_CONTROL_INFO_KHR = 1000023010, - VIDEO_REFERENCE_SLOT_KHR = 1000023011, - VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000023012, - VIDEO_PROFILES_KHR = 1000023013, - PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR = 1000023014, - VIDEO_FORMAT_PROPERTIES_KHR = 1000023015, - VIDEO_DECODE_INFO_KHR = 1000024000, - DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, - DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, - DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, - PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, - PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, - PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, - CU_MODULE_CREATE_INFO_NVX = 1000029000, - CU_FUNCTION_CREATE_INFO_NVX = 1000029001, - CU_LAUNCH_INFO_NVX = 1000029002, - IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, - IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, - VIDEO_ENCODE_H264_CAPABILITIES_EXT = 1000038000, - VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT = 1000038001, - VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038002, - VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038003, - VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT = 1000038004, - VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038005, - VIDEO_ENCODE_H264_NALU_SLICE_EXT = 1000038006, - VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT = 1000038007, - VIDEO_ENCODE_H264_PROFILE_EXT = 1000038008, - VIDEO_DECODE_H264_CAPABILITIES_EXT = 1000040000, - VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT = 1000040001, - VIDEO_DECODE_H264_PICTURE_INFO_EXT = 1000040002, - VIDEO_DECODE_H264_MVC_EXT = 1000040003, - VIDEO_DECODE_H264_PROFILE_EXT = 1000040004, - VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000040005, - VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000040006, - VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT = 1000040007, - TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, - STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, - PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, - EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, - EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, - IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, - EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, - WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, - VALIDATION_FLAGS_EXT = 1000061000, - VI_SURFACE_CREATE_INFO_NN = 1000062000, - PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = 1000066000, - IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, - PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, - IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, - EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, - MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, - MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, - IMPORT_MEMORY_FD_INFO_KHR = 1000074000, - MEMORY_FD_PROPERTIES_KHR = 1000074001, - MEMORY_GET_FD_INFO_KHR = 1000074002, - WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, - IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, - EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, - D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, - SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, - IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, - SEMAPHORE_GET_FD_INFO_KHR = 1000079001, - PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, - COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, - PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, - CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, - PRESENT_REGIONS_KHR = 1000084000, - PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, - SURFACE_CAPABILITIES_2_EXT = 1000090000, - DISPLAY_POWER_INFO_EXT = 1000091000, - DEVICE_EVENT_INFO_EXT = 1000091001, - DISPLAY_EVENT_INFO_EXT = 1000091002, - SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, - PRESENT_TIMES_INFO_GOOGLE = 1000092000, - PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, - PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, - PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, - PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, - PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, - PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, - PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, - PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, - HDR_METADATA_EXT = 1000105000, - SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, - IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, - EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, - FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, - IMPORT_FENCE_FD_INFO_KHR = 1000115000, - FENCE_GET_FD_INFO_KHR = 1000115001, - PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR = 1000116000, - PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR = 1000116001, - QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR = 1000116002, - PERFORMANCE_QUERY_SUBMIT_INFO_KHR = 1000116003, - ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, - PERFORMANCE_COUNTER_KHR = 1000116005, - PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, - PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, - SURFACE_CAPABILITIES_2_KHR = 1000119001, - SURFACE_FORMAT_2_KHR = 1000119002, - DISPLAY_PROPERTIES_2_KHR = 1000121000, - DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, - DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, - DISPLAY_PLANE_INFO_2_KHR = 1000121003, - DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, - IOS_SURFACE_CREATE_INFO_MVK = 1000122000, - MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, - DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, - DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, - DEBUG_UTILS_LABEL_EXT = 1000128002, - DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, - DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, - ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, - ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, - ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, - IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, - MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, - EXTERNAL_FORMAT_ANDROID = 1000129005, - PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, - PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, - WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, - DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, - SAMPLE_LOCATIONS_INFO_EXT = 1000143000, - RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, - PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, - PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, - MULTISAMPLE_PROPERTIES_EXT = 1000143004, - PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, - PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, - PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, - PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, - WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, - ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, - ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, - ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, - ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, - ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, - ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, - ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, - COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, - COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, - COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, - PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, - PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, - ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, - ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, - PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, - PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, - RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, - RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, - RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, - PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, - PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, - PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, - PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, - DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, - PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, - IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, - IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, - IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, - VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, - SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, - PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, - PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, - PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, - PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, - PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, - PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, - RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, - ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, - GEOMETRY_NV = 1000165003, - GEOMETRY_TRIANGLES_NV = 1000165004, - GEOMETRY_AABB_NV = 1000165005, - BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, - WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, - ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, - PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, - RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, - ACCELERATION_STRUCTURE_INFO_NV = 1000165012, - PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, - PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, - PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, - FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, - DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, - IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, - MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, - PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, - PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, - PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, - CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, - PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, - VIDEO_DECODE_H265_CAPABILITIES_EXT = 1000187000, - VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT = 1000187001, - VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000187002, - VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000187003, - VIDEO_DECODE_H265_PROFILE_EXT = 1000187004, - VIDEO_DECODE_H265_PICTURE_INFO_EXT = 1000187005, - VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT = 1000187006, - DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, - PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, - PRESENT_FRAME_TOKEN_GGP = 1000191000, - PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000192000, - PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, - PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, - PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, - PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = 1000203000, - PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, - PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, - PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, - CHECKPOINT_DATA_NV = 1000206000, - QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, - PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL = 1000209000, - QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL = 1000210000, - INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, - PERFORMANCE_MARKER_INFO_INTEL = 1000210002, - PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, - PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, - PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, - PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, - DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, - SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, - IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, - PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = 1000215000, - METAL_SURFACE_CREATE_INFO_EXT = 1000217000, - PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, - PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, - RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, - PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = 1000225000, - PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = 1000225001, - PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = 1000225002, - FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, - PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, - PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, - PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, - PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, - PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, - PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, - PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, - PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, - PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, - MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, - SURFACE_PROTECTED_CAPABILITIES_KHR = 1000239000, - PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, - PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, - BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, - PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = 1000245000, - VALIDATION_FEATURES_EXT = 1000247000, - PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, - PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, - COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, - PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, - PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV = 1000250000, - PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV = 1000250001, - FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, - PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, - PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, - PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT = 1000254000, - PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT = 1000254001, - PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT = 1000254002, - SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, - SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, - SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, - HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000, - PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, - PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, - PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, - PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, - PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, - PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, - PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, - PIPELINE_INFO_KHR = 1000269001, - PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, - PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, - PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, - PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, - PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, - PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000, - PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, - GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, - GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, - INDIRECT_COMMANDS_LAYOUT_TOKEN_NV = 1000277003, - INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV = 1000277004, - GENERATED_COMMANDS_INFO_NV = 1000277005, - GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, - PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, - PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, - COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, - PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = 1000280000, - PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = 1000280001, - PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, - PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001, - COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, - RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, - PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, - DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT = 1000284001, - DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT = 1000284002, - PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, - PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, - SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, - PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, - PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, - PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, - PRESENT_ID_KHR = 1000294000, - PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, - PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = 1000295000, - DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = 1000295001, - PRIVATE_DATA_SLOT_CREATE_INFO_EXT = 1000295002, - PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = 1000297000, - VIDEO_ENCODE_INFO_KHR = 1000299000, - VIDEO_ENCODE_RATE_CONTROL_INFO_KHR = 1000299001, - PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, - DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, - MEMORY_BARRIER_2_KHR = 1000314000, - BUFFER_MEMORY_BARRIER_2_KHR = 1000314001, - IMAGE_MEMORY_BARRIER_2_KHR = 1000314002, - DEPENDENCY_INFO_KHR = 1000314003, - SUBMIT_INFO_2_KHR = 1000314004, - SEMAPHORE_SUBMIT_INFO_KHR = 1000314005, - COMMAND_BUFFER_SUBMIT_INFO_KHR = 1000314006, - PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = 1000314007, - QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, - CHECKPOINT_DATA_2_NV = 1000314009, - PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, - PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = 1000325000, - PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, - PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, - PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, - ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000, - PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001, - ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002, - PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, - PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, - PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, - COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, - PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = 1000335000, - PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, - COPY_BUFFER_INFO_2_KHR = 1000337000, - COPY_IMAGE_INFO_2_KHR = 1000337001, - COPY_BUFFER_TO_IMAGE_INFO_2_KHR = 1000337002, - COPY_IMAGE_TO_BUFFER_INFO_2_KHR = 1000337003, - BLIT_IMAGE_INFO_2_KHR = 1000337004, - RESOLVE_IMAGE_INFO_2_KHR = 1000337005, - BUFFER_COPY_2_KHR = 1000337006, - IMAGE_COPY_2_KHR = 1000337007, - IMAGE_BLIT_2_KHR = 1000337008, - BUFFER_IMAGE_COPY_2_KHR = 1000337009, - IMAGE_RESOLVE_2_KHR = 1000337010, - PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, - DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, - PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = 1000351000, - MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = 1000351002, - PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, - VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, - VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, - PHYSICAL_DEVICE_DRM_PROPERTIES_EXT = 1000353000, - PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, - IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, - MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, - MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, - IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, - SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, - SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, - PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, - PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, - PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000, - MEMORY_GET_REMOTE_ADDRESS_INFO_NV = 1000371000, - PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001, - PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, - SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, - PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, - PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, - PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = 1000388000, - QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = 1000388001, - PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, - PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, - PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, - PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, - PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, - DEBUG_REPORT_CREATE_INFO_EXT = DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, - RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = RENDER_PASS_MULTIVIEW_CREATE_INFO, - PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = PHYSICAL_DEVICE_MULTIVIEW_FEATURES, - PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, - PHYSICAL_DEVICE_FEATURES_2_KHR = PHYSICAL_DEVICE_FEATURES_2, - PHYSICAL_DEVICE_PROPERTIES_2_KHR = PHYSICAL_DEVICE_PROPERTIES_2, - FORMAT_PROPERTIES_2_KHR = FORMAT_PROPERTIES_2, - IMAGE_FORMAT_PROPERTIES_2_KHR = IMAGE_FORMAT_PROPERTIES_2, - PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - QUEUE_FAMILY_PROPERTIES_2_KHR = QUEUE_FAMILY_PROPERTIES_2, - PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, - SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = SPARSE_IMAGE_FORMAT_PROPERTIES_2, - PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, - MEMORY_ALLOCATE_FLAGS_INFO_KHR = MEMORY_ALLOCATE_FLAGS_INFO, - DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, - DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, - DEVICE_GROUP_SUBMIT_INFO_KHR = DEVICE_GROUP_SUBMIT_INFO, - DEVICE_GROUP_BIND_SPARSE_INFO_KHR = DEVICE_GROUP_BIND_SPARSE_INFO, - BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, - BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, - PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = PHYSICAL_DEVICE_GROUP_PROPERTIES, - DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = DEVICE_GROUP_DEVICE_CREATE_INFO, - PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, - EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = EXTERNAL_IMAGE_FORMAT_PROPERTIES, - PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, - EXTERNAL_BUFFER_PROPERTIES_KHR = EXTERNAL_BUFFER_PROPERTIES, - PHYSICAL_DEVICE_ID_PROPERTIES_KHR = PHYSICAL_DEVICE_ID_PROPERTIES, - EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = EXTERNAL_MEMORY_BUFFER_CREATE_INFO, - EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = EXTERNAL_MEMORY_IMAGE_CREATE_INFO, - EXPORT_MEMORY_ALLOCATE_INFO_KHR = EXPORT_MEMORY_ALLOCATE_INFO, - PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, - EXTERNAL_SEMAPHORE_PROPERTIES_KHR = EXTERNAL_SEMAPHORE_PROPERTIES, - EXPORT_SEMAPHORE_CREATE_INFO_KHR = EXPORT_SEMAPHORE_CREATE_INFO, - PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, - PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, - PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, - DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, - SURFACE_CAPABILITIES2_EXT = SURFACE_CAPABILITIES_2_EXT, - PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, - FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, - FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, - RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = RENDER_PASS_ATTACHMENT_BEGIN_INFO, - ATTACHMENT_DESCRIPTION_2_KHR = ATTACHMENT_DESCRIPTION_2, - ATTACHMENT_REFERENCE_2_KHR = ATTACHMENT_REFERENCE_2, - SUBPASS_DESCRIPTION_2_KHR = SUBPASS_DESCRIPTION_2, - SUBPASS_DEPENDENCY_2_KHR = SUBPASS_DEPENDENCY_2, - RENDER_PASS_CREATE_INFO_2_KHR = RENDER_PASS_CREATE_INFO_2, - SUBPASS_BEGIN_INFO_KHR = SUBPASS_BEGIN_INFO, - SUBPASS_END_INFO_KHR = SUBPASS_END_INFO, - PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, - EXTERNAL_FENCE_PROPERTIES_KHR = EXTERNAL_FENCE_PROPERTIES, - EXPORT_FENCE_CREATE_INFO_KHR = EXPORT_FENCE_CREATE_INFO, - PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, - RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, - IMAGE_VIEW_USAGE_CREATE_INFO_KHR = IMAGE_VIEW_USAGE_CREATE_INFO, - PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, - PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, - PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, - MEMORY_DEDICATED_REQUIREMENTS_KHR = MEMORY_DEDICATED_REQUIREMENTS, - MEMORY_DEDICATED_ALLOCATE_INFO_KHR = MEMORY_DEDICATED_ALLOCATE_INFO, - PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, - SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = SAMPLER_REDUCTION_MODE_CREATE_INFO, - BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = BUFFER_MEMORY_REQUIREMENTS_INFO_2, - IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = IMAGE_MEMORY_REQUIREMENTS_INFO_2, - IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, - MEMORY_REQUIREMENTS_2_KHR = MEMORY_REQUIREMENTS_2, - SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, - IMAGE_FORMAT_LIST_CREATE_INFO_KHR = IMAGE_FORMAT_LIST_CREATE_INFO, - SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = SAMPLER_YCBCR_CONVERSION_CREATE_INFO, - SAMPLER_YCBCR_CONVERSION_INFO_KHR = SAMPLER_YCBCR_CONVERSION_INFO, - BIND_IMAGE_PLANE_MEMORY_INFO_KHR = BIND_IMAGE_PLANE_MEMORY_INFO, - IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, - PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, - SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, - BIND_BUFFER_MEMORY_INFO_KHR = BIND_BUFFER_MEMORY_INFO, - BIND_IMAGE_MEMORY_INFO_KHR = BIND_IMAGE_MEMORY_INFO, - DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, - PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, - PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, - DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, - DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, - PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, - DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = DESCRIPTOR_SET_LAYOUT_SUPPORT, - PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, - PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, - PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, - PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = PHYSICAL_DEVICE_DRIVER_PROPERTIES, - PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, - PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, - SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE, - PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, - PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, - SEMAPHORE_TYPE_CREATE_INFO_KHR = SEMAPHORE_TYPE_CREATE_INFO, - TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR = TIMELINE_SEMAPHORE_SUBMIT_INFO, - SEMAPHORE_WAIT_INFO_KHR = SEMAPHORE_WAIT_INFO, - SEMAPHORE_SIGNAL_INFO_KHR = SEMAPHORE_SIGNAL_INFO, - QUERY_POOL_CREATE_INFO_INTEL = QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, - PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, - PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, - PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, - ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = ATTACHMENT_REFERENCE_STENCIL_LAYOUT, - ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, - PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, - BUFFER_DEVICE_ADDRESS_INFO_EXT = BUFFER_DEVICE_ADDRESS_INFO, - IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = IMAGE_STENCIL_USAGE_CREATE_INFO, - PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, - PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, - BUFFER_DEVICE_ADDRESS_INFO_KHR = BUFFER_DEVICE_ADDRESS_INFO, - BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, - MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, - DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, - PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, + APPLICATION_INFO = 0, + INSTANCE_CREATE_INFO = 1, + DEVICE_QUEUE_CREATE_INFO = 2, + DEVICE_CREATE_INFO = 3, + SUBMIT_INFO = 4, + MEMORY_ALLOCATE_INFO = 5, + MAPPED_MEMORY_RANGE = 6, + BIND_SPARSE_INFO = 7, + FENCE_CREATE_INFO = 8, + SEMAPHORE_CREATE_INFO = 9, + EVENT_CREATE_INFO = 10, + QUERY_POOL_CREATE_INFO = 11, + BUFFER_CREATE_INFO = 12, + BUFFER_VIEW_CREATE_INFO = 13, + IMAGE_CREATE_INFO = 14, + IMAGE_VIEW_CREATE_INFO = 15, + SHADER_MODULE_CREATE_INFO = 16, + PIPELINE_CACHE_CREATE_INFO = 17, + PIPELINE_SHADER_STAGE_CREATE_INFO = 18, + PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, + PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, + PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, + PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, + PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, + PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, + PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, + PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, + PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, + GRAPHICS_PIPELINE_CREATE_INFO = 28, + COMPUTE_PIPELINE_CREATE_INFO = 29, + PIPELINE_LAYOUT_CREATE_INFO = 30, + SAMPLER_CREATE_INFO = 31, + DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, + DESCRIPTOR_POOL_CREATE_INFO = 33, + DESCRIPTOR_SET_ALLOCATE_INFO = 34, + WRITE_DESCRIPTOR_SET = 35, + COPY_DESCRIPTOR_SET = 36, + FRAMEBUFFER_CREATE_INFO = 37, + RENDER_PASS_CREATE_INFO = 38, + COMMAND_POOL_CREATE_INFO = 39, + COMMAND_BUFFER_ALLOCATE_INFO = 40, + COMMAND_BUFFER_INHERITANCE_INFO = 41, + COMMAND_BUFFER_BEGIN_INFO = 42, + RENDER_PASS_BEGIN_INFO = 43, + BUFFER_MEMORY_BARRIER = 44, + IMAGE_MEMORY_BARRIER = 45, + MEMORY_BARRIER = 46, + LOADER_INSTANCE_CREATE_INFO = 47, + LOADER_DEVICE_CREATE_INFO = 48, + PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, + BIND_BUFFER_MEMORY_INFO = 1000157000, + BIND_IMAGE_MEMORY_INFO = 1000157001, + PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, + MEMORY_DEDICATED_REQUIREMENTS = 1000127000, + MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, + MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, + DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, + DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, + DEVICE_GROUP_SUBMIT_INFO = 1000060005, + DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, + BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, + BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, + PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, + DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, + BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, + IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, + IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, + MEMORY_REQUIREMENTS_2 = 1000146003, + SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, + PHYSICAL_DEVICE_FEATURES_2 = 1000059000, + PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, + FORMAT_PROPERTIES_2 = 1000059002, + IMAGE_FORMAT_PROPERTIES_2 = 1000059003, + PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, + QUEUE_FAMILY_PROPERTIES_2 = 1000059005, + PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, + SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, + PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, + PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, + RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, + IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, + PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, + RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, + PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, + PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, + PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, + PROTECTED_SUBMIT_INFO = 1000145000, + PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, + PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, + DEVICE_QUEUE_INFO_2 = 1000145003, + SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, + SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, + BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, + IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, + PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, + SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, + DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, + PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, + EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, + PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, + EXTERNAL_BUFFER_PROPERTIES = 1000071003, + PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, + EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, + EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, + EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, + PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, + EXTERNAL_FENCE_PROPERTIES = 1000112001, + EXPORT_FENCE_CREATE_INFO = 1000113000, + EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, + PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, + EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, + PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, + DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, + PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, + PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, + PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50, + PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51, + PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52, + IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000, + ATTACHMENT_DESCRIPTION_2 = 1000109000, + ATTACHMENT_REFERENCE_2 = 1000109001, + SUBPASS_DESCRIPTION_2 = 1000109002, + SUBPASS_DEPENDENCY_2 = 1000109003, + RENDER_PASS_CREATE_INFO_2 = 1000109004, + SUBPASS_BEGIN_INFO = 1000109005, + SUBPASS_END_INFO = 1000109006, + PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000, + PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000, + PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000, + PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000, + PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000, + DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000, + PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001, + PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002, + DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003, + DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004, + PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000, + SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001, + PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000, + IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000, + PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000, + SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001, + PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000, + PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000, + FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001, + FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002, + RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003, + PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000, + PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000, + PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000, + ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001, + ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002, + PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000, + PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000, + PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001, + SEMAPHORE_TYPE_CREATE_INFO = 1000207002, + TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003, + SEMAPHORE_WAIT_INFO = 1000207004, + SEMAPHORE_SIGNAL_INFO = 1000207005, + PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000, + BUFFER_DEVICE_ADDRESS_INFO = 1000244001, + BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, + MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, + DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, + PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53, + PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54, + PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000, + PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000, + PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000, + PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000, + PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000, + DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001, + PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002, + PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000, + MEMORY_BARRIER_2 = 1000314000, + BUFFER_MEMORY_BARRIER_2 = 1000314001, + IMAGE_MEMORY_BARRIER_2 = 1000314002, + DEPENDENCY_INFO = 1000314003, + SUBMIT_INFO_2 = 1000314004, + SEMAPHORE_SUBMIT_INFO = 1000314005, + COMMAND_BUFFER_SUBMIT_INFO = 1000314006, + PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007, + PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000, + PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000, + COPY_BUFFER_INFO_2 = 1000337000, + COPY_IMAGE_INFO_2 = 1000337001, + COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002, + COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003, + BLIT_IMAGE_INFO_2 = 1000337004, + RESOLVE_IMAGE_INFO_2 = 1000337005, + BUFFER_COPY_2 = 1000337006, + IMAGE_COPY_2 = 1000337007, + IMAGE_BLIT_2 = 1000337008, + BUFFER_IMAGE_COPY_2 = 1000337009, + IMAGE_RESOLVE_2 = 1000337010, + PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000, + PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001, + PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002, + PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000, + PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001, + WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002, + DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003, + PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000, + RENDERING_INFO = 1000044000, + RENDERING_ATTACHMENT_INFO = 1000044001, + PIPELINE_RENDERING_CREATE_INFO = 1000044002, + PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003, + COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004, + PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000, + PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001, + PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001, + FORMAT_PROPERTIES_3 = 1000360000, + PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000, + PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001, + DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002, + DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003, + SWAPCHAIN_CREATE_INFO_KHR = 1000001000, + PRESENT_INFO_KHR = 1000001001, + DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, + IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, + BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, + ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, + DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, + DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, + DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, + DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, + DISPLAY_PRESENT_INFO_KHR = 1000003000, + XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, + WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, + PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, + DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, + DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, + DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, + VIDEO_PROFILE_KHR = 1000023000, + VIDEO_CAPABILITIES_KHR = 1000023001, + VIDEO_PICTURE_RESOURCE_KHR = 1000023002, + VIDEO_GET_MEMORY_PROPERTIES_KHR = 1000023003, + VIDEO_BIND_MEMORY_KHR = 1000023004, + VIDEO_SESSION_CREATE_INFO_KHR = 1000023005, + VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000023006, + VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR = 1000023007, + VIDEO_BEGIN_CODING_INFO_KHR = 1000023008, + VIDEO_END_CODING_INFO_KHR = 1000023009, + VIDEO_CODING_CONTROL_INFO_KHR = 1000023010, + VIDEO_REFERENCE_SLOT_KHR = 1000023011, + VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000023012, + VIDEO_PROFILES_KHR = 1000023013, + PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR = 1000023014, + VIDEO_FORMAT_PROPERTIES_KHR = 1000023015, + QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_2_KHR = 1000023016, + VIDEO_DECODE_INFO_KHR = 1000024000, + VIDEO_DECODE_CAPABILITIES_KHR = 1000024001, + DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, + DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, + DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, + PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, + PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, + CU_MODULE_CREATE_INFO_NVX = 1000029000, + CU_FUNCTION_CREATE_INFO_NVX = 1000029001, + CU_LAUNCH_INFO_NVX = 1000029002, + IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, + IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, + VIDEO_ENCODE_H264_CAPABILITIES_EXT = 1000038000, + VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038001, + VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038002, + VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT = 1000038003, + VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038004, + VIDEO_ENCODE_H264_NALU_SLICE_EXT = 1000038005, + VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT = 1000038006, + VIDEO_ENCODE_H264_PROFILE_EXT = 1000038007, + VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT = 1000038008, + VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT = 1000038009, + VIDEO_ENCODE_H264_REFERENCE_LISTS_EXT = 1000038010, + VIDEO_ENCODE_H265_CAPABILITIES_EXT = 1000039000, + VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000039001, + VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000039002, + VIDEO_ENCODE_H265_VCL_FRAME_INFO_EXT = 1000039003, + VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT = 1000039004, + VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_EXT = 1000039005, + VIDEO_ENCODE_H265_EMIT_PICTURE_PARAMETERS_EXT = 1000039006, + VIDEO_ENCODE_H265_PROFILE_EXT = 1000039007, + VIDEO_ENCODE_H265_REFERENCE_LISTS_EXT = 1000039008, + VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT = 1000039009, + VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT = 1000039010, + VIDEO_DECODE_H264_CAPABILITIES_EXT = 1000040000, + VIDEO_DECODE_H264_PICTURE_INFO_EXT = 1000040001, + VIDEO_DECODE_H264_MVC_EXT = 1000040002, + VIDEO_DECODE_H264_PROFILE_EXT = 1000040003, + VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000040004, + VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000040005, + VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT = 1000040006, + TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006, + RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT = 1000044007, + ATTACHMENT_SAMPLE_COUNT_INFO_AMD = 1000044008, + MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX = 1000044009, + STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, + PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, + EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, + EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, + IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, + EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, + WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, + VALIDATION_FLAGS_EXT = 1000061000, + VI_SURFACE_CREATE_INFO_NN = 1000062000, + IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, + PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, + IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, + EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, + MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, + MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, + IMPORT_MEMORY_FD_INFO_KHR = 1000074000, + MEMORY_FD_PROPERTIES_KHR = 1000074001, + MEMORY_GET_FD_INFO_KHR = 1000074002, + WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, + IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, + EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, + D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, + SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, + IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, + SEMAPHORE_GET_FD_INFO_KHR = 1000079001, + PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, + COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, + PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, + CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, + PRESENT_REGIONS_KHR = 1000084000, + PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, + SURFACE_CAPABILITIES_2_EXT = 1000090000, + DISPLAY_POWER_INFO_EXT = 1000091000, + DEVICE_EVENT_INFO_EXT = 1000091001, + DISPLAY_EVENT_INFO_EXT = 1000091002, + SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, + PRESENT_TIMES_INFO_GOOGLE = 1000092000, + PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, + PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, + PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, + PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, + PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, + PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, + PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, + PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, + HDR_METADATA_EXT = 1000105000, + SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, + IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, + EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, + FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, + IMPORT_FENCE_FD_INFO_KHR = 1000115000, + FENCE_GET_FD_INFO_KHR = 1000115001, + PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR = 1000116000, + PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR = 1000116001, + QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR = 1000116002, + PERFORMANCE_QUERY_SUBMIT_INFO_KHR = 1000116003, + ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, + PERFORMANCE_COUNTER_KHR = 1000116005, + PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, + PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, + SURFACE_CAPABILITIES_2_KHR = 1000119001, + SURFACE_FORMAT_2_KHR = 1000119002, + DISPLAY_PROPERTIES_2_KHR = 1000121000, + DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, + DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, + DISPLAY_PLANE_INFO_2_KHR = 1000121003, + DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, + IOS_SURFACE_CREATE_INFO_MVK = 1000122000, + MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, + DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, + DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, + DEBUG_UTILS_LABEL_EXT = 1000128002, + DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, + DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, + ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, + ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, + ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, + IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, + MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, + EXTERNAL_FORMAT_ANDROID = 1000129005, + ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID = 1000129006, + SAMPLE_LOCATIONS_INFO_EXT = 1000143000, + RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, + PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, + PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, + MULTISAMPLE_PROPERTIES_EXT = 1000143004, + PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, + PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, + PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, + PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, + WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, + ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, + ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, + ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, + ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, + ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, + ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, + ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, + COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, + COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, + COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, + PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, + PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, + ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, + ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, + PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, + PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, + RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, + RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, + RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, + PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, + PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, + PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, + DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, + PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, + IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, + IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, + IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT = 1000158006, + VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, + SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, + PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, + PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, + PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, + PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, + PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, + PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, + RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, + ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, + GEOMETRY_NV = 1000165003, + GEOMETRY_TRIANGLES_NV = 1000165004, + GEOMETRY_AABB_NV = 1000165005, + BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, + ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, + PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, + RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, + ACCELERATION_STRUCTURE_INFO_NV = 1000165012, + PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, + PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, + PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, + FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, + IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, + MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, + PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, + PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, + PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, + CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, + PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + VIDEO_DECODE_H265_CAPABILITIES_EXT = 1000187000, + VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000187001, + VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000187002, + VIDEO_DECODE_H265_PROFILE_EXT = 1000187003, + VIDEO_DECODE_H265_PICTURE_INFO_EXT = 1000187004, + VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT = 1000187005, + DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = 1000174000, + PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = 1000388000, + QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = 1000388001, + DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, + PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, + PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, + PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, + PRESENT_FRAME_TOKEN_GGP = 1000191000, + PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, + PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, + PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, + PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = 1000203000, + PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, + PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, + PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, + CHECKPOINT_DATA_NV = 1000206000, + QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, + PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL = 1000209000, + QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL = 1000210000, + INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, + PERFORMANCE_MARKER_INFO_INTEL = 1000210002, + PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, + PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, + PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, + PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, + DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, + SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, + IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + METAL_SURFACE_CREATE_INFO_EXT = 1000217000, + PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, + PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, + RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, + FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, + PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, + PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, + PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, + PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, + PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, + PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, + PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, + PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, + PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, + MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, + SURFACE_PROTECTED_CAPABILITIES_KHR = 1000239000, + PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, + PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, + BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, + VALIDATION_FEATURES_EXT = 1000247000, + PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, + PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, + COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, + PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, + PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV = 1000250000, + PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV = 1000250001, + FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, + PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, + PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, + PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT = 1000254000, + PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT = 1000254001, + PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT = 1000254002, + SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, + SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, + SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, + HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000, + PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, + PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, + PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, + PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, + PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, + PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, + PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, + PIPELINE_INFO_KHR = 1000269001, + PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, + PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, + PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, + PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, + PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, + PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, + GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, + GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, + INDIRECT_COMMANDS_LAYOUT_TOKEN_NV = 1000277003, + INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV = 1000277004, + GENERATED_COMMANDS_INFO_NV = 1000277005, + GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, + PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, + PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, + COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, + PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, + COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, + RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, + PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, + DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT = 1000284001, + DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT = 1000284002, + PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, + PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, + SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, + PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, + PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, + PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, + PRESENT_ID_KHR = 1000294000, + PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, + VIDEO_ENCODE_INFO_KHR = 1000299000, + VIDEO_ENCODE_RATE_CONTROL_INFO_KHR = 1000299001, + VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR = 1000299002, + VIDEO_ENCODE_CAPABILITIES_KHR = 1000299003, + PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, + DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, + QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, + CHECKPOINT_DATA_2_NV = 1000314009, + PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000, + PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001, + GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002, + PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, + PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, + PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, + PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, + ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000, + PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001, + ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002, + PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, + PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, + PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, + COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, + PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, + PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, + PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = 1000342000, + PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000, + DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, + PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = 1000351000, + MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = 1000351002, + PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, + VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, + VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, + PHYSICAL_DEVICE_DRM_PROPERTIES_EXT = 1000353000, + PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT = 1000355000, + PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT = 1000355001, + PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, + IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, + MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, + MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, + IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, + SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, + BUFFER_COLLECTION_CREATE_INFO_FUCHSIA = 1000366000, + IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA = 1000366001, + BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA = 1000366002, + BUFFER_COLLECTION_PROPERTIES_FUCHSIA = 1000366003, + BUFFER_CONSTRAINTS_INFO_FUCHSIA = 1000366004, + BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA = 1000366005, + IMAGE_CONSTRAINTS_INFO_FUCHSIA = 1000366006, + IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA = 1000366007, + SYSMEM_COLOR_SPACE_FUCHSIA = 1000366008, + BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA = 1000366009, + SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, + PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, + PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, + PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000, + MEMORY_GET_REMOTE_ADDRESS_INFO_NV = 1000371000, + PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001, + PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, + SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, + PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, + PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, + PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000, + PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000, + IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001, + PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, + PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, + PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000, + PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, + SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, + PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, + PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, + DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001, + DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, + PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000, + PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001, + SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002, + PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, + PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, + DEBUG_REPORT_CREATE_INFO_EXT = DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + RENDERING_INFO_KHR = RENDERING_INFO, + RENDERING_ATTACHMENT_INFO_KHR = RENDERING_ATTACHMENT_INFO, + PIPELINE_RENDERING_CREATE_INFO_KHR = PIPELINE_RENDERING_CREATE_INFO, + PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR = PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR = COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, + ATTACHMENT_SAMPLE_COUNT_INFO_NV = ATTACHMENT_SAMPLE_COUNT_INFO_AMD, + RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = RENDER_PASS_MULTIVIEW_CREATE_INFO, + PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = PHYSICAL_DEVICE_MULTIVIEW_FEATURES, + PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, + PHYSICAL_DEVICE_FEATURES_2_KHR = PHYSICAL_DEVICE_FEATURES_2, + PHYSICAL_DEVICE_PROPERTIES_2_KHR = PHYSICAL_DEVICE_PROPERTIES_2, + FORMAT_PROPERTIES_2_KHR = FORMAT_PROPERTIES_2, + IMAGE_FORMAT_PROPERTIES_2_KHR = IMAGE_FORMAT_PROPERTIES_2, + PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + QUEUE_FAMILY_PROPERTIES_2_KHR = QUEUE_FAMILY_PROPERTIES_2, + PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, + SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = SPARSE_IMAGE_FORMAT_PROPERTIES_2, + PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, + MEMORY_ALLOCATE_FLAGS_INFO_KHR = MEMORY_ALLOCATE_FLAGS_INFO, + DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, + DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, + DEVICE_GROUP_SUBMIT_INFO_KHR = DEVICE_GROUP_SUBMIT_INFO, + DEVICE_GROUP_BIND_SPARSE_INFO_KHR = DEVICE_GROUP_BIND_SPARSE_INFO, + BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, + BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, + PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, + PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = PHYSICAL_DEVICE_GROUP_PROPERTIES, + DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = DEVICE_GROUP_DEVICE_CREATE_INFO, + PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = EXTERNAL_IMAGE_FORMAT_PROPERTIES, + PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, + EXTERNAL_BUFFER_PROPERTIES_KHR = EXTERNAL_BUFFER_PROPERTIES, + PHYSICAL_DEVICE_ID_PROPERTIES_KHR = PHYSICAL_DEVICE_ID_PROPERTIES, + EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = EXTERNAL_MEMORY_BUFFER_CREATE_INFO, + EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = EXTERNAL_MEMORY_IMAGE_CREATE_INFO, + EXPORT_MEMORY_ALLOCATE_INFO_KHR = EXPORT_MEMORY_ALLOCATE_INFO, + PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, + EXTERNAL_SEMAPHORE_PROPERTIES_KHR = EXTERNAL_SEMAPHORE_PROPERTIES, + EXPORT_SEMAPHORE_CREATE_INFO_KHR = EXPORT_SEMAPHORE_CREATE_INFO, + PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, + DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, + SURFACE_CAPABILITIES2_EXT = SURFACE_CAPABILITIES_2_EXT, + PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, + FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, + FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, + RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = RENDER_PASS_ATTACHMENT_BEGIN_INFO, + ATTACHMENT_DESCRIPTION_2_KHR = ATTACHMENT_DESCRIPTION_2, + ATTACHMENT_REFERENCE_2_KHR = ATTACHMENT_REFERENCE_2, + SUBPASS_DESCRIPTION_2_KHR = SUBPASS_DESCRIPTION_2, + SUBPASS_DEPENDENCY_2_KHR = SUBPASS_DEPENDENCY_2, + RENDER_PASS_CREATE_INFO_2_KHR = RENDER_PASS_CREATE_INFO_2, + SUBPASS_BEGIN_INFO_KHR = SUBPASS_BEGIN_INFO, + SUBPASS_END_INFO_KHR = SUBPASS_END_INFO, + PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, + EXTERNAL_FENCE_PROPERTIES_KHR = EXTERNAL_FENCE_PROPERTIES, + EXPORT_FENCE_CREATE_INFO_KHR = EXPORT_FENCE_CREATE_INFO, + PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, + RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, + IMAGE_VIEW_USAGE_CREATE_INFO_KHR = IMAGE_VIEW_USAGE_CREATE_INFO, + PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, + PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, + MEMORY_DEDICATED_REQUIREMENTS_KHR = MEMORY_DEDICATED_REQUIREMENTS, + MEMORY_DEDICATED_ALLOCATE_INFO_KHR = MEMORY_DEDICATED_ALLOCATE_INFO, + PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, + SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = SAMPLER_REDUCTION_MODE_CREATE_INFO, + PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES, + PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES, + WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK, + DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO, + BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = BUFFER_MEMORY_REQUIREMENTS_INFO_2, + IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = IMAGE_MEMORY_REQUIREMENTS_INFO_2, + IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, + MEMORY_REQUIREMENTS_2_KHR = MEMORY_REQUIREMENTS_2, + SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, + IMAGE_FORMAT_LIST_CREATE_INFO_KHR = IMAGE_FORMAT_LIST_CREATE_INFO, + SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = SAMPLER_YCBCR_CONVERSION_CREATE_INFO, + SAMPLER_YCBCR_CONVERSION_INFO_KHR = SAMPLER_YCBCR_CONVERSION_INFO, + BIND_IMAGE_PLANE_MEMORY_INFO_KHR = BIND_IMAGE_PLANE_MEMORY_INFO, + IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, + PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, + SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, + BIND_BUFFER_MEMORY_INFO_KHR = BIND_BUFFER_MEMORY_INFO, + BIND_IMAGE_MEMORY_INFO_KHR = BIND_IMAGE_MEMORY_INFO, + DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, + PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, + DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, + DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, + PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, + DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = DESCRIPTOR_SET_LAYOUT_SUPPORT, + DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR, + PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, + PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, + PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, + PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = PIPELINE_CREATION_FEEDBACK_CREATE_INFO, + PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = PHYSICAL_DEVICE_DRIVER_PROPERTIES, + PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, + PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, + SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE, + PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, + PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, + SEMAPHORE_TYPE_CREATE_INFO_KHR = SEMAPHORE_TYPE_CREATE_INFO, + TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR = TIMELINE_SEMAPHORE_SUBMIT_INFO, + SEMAPHORE_WAIT_INFO_KHR = SEMAPHORE_WAIT_INFO, + SEMAPHORE_SIGNAL_INFO_KHR = SEMAPHORE_SIGNAL_INFO, + QUERY_POOL_CREATE_INFO_INTEL = QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, + PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, + PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES, + PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, + PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, + PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES, + PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, + ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = ATTACHMENT_REFERENCE_STENCIL_LAYOUT, + ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, + PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, + BUFFER_DEVICE_ADDRESS_INFO_EXT = BUFFER_DEVICE_ADDRESS_INFO, + PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = PHYSICAL_DEVICE_TOOL_PROPERTIES, + IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = IMAGE_STENCIL_USAGE_CREATE_INFO, + PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, + PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, + BUFFER_DEVICE_ADDRESS_INFO_KHR = BUFFER_DEVICE_ADDRESS_INFO, + BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, + MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, + DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, + PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, + PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, + PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, + PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, + PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES, + PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, + DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = DEVICE_PRIVATE_DATA_CREATE_INFO, + PRIVATE_DATA_SLOT_CREATE_INFO_EXT = PRIVATE_DATA_SLOT_CREATE_INFO, + PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES, + MEMORY_BARRIER_2_KHR = MEMORY_BARRIER_2, + BUFFER_MEMORY_BARRIER_2_KHR = BUFFER_MEMORY_BARRIER_2, + IMAGE_MEMORY_BARRIER_2_KHR = IMAGE_MEMORY_BARRIER_2, + DEPENDENCY_INFO_KHR = DEPENDENCY_INFO, + SUBMIT_INFO_2_KHR = SUBMIT_INFO_2, + SEMAPHORE_SUBMIT_INFO_KHR = SEMAPHORE_SUBMIT_INFO, + COMMAND_BUFFER_SUBMIT_INFO_KHR = COMMAND_BUFFER_SUBMIT_INFO, + PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, + PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, + PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES, + COPY_BUFFER_INFO_2_KHR = COPY_BUFFER_INFO_2, + COPY_IMAGE_INFO_2_KHR = COPY_IMAGE_INFO_2, + COPY_BUFFER_TO_IMAGE_INFO_2_KHR = COPY_BUFFER_TO_IMAGE_INFO_2, + COPY_IMAGE_TO_BUFFER_INFO_2_KHR = COPY_IMAGE_TO_BUFFER_INFO_2, + BLIT_IMAGE_INFO_2_KHR = BLIT_IMAGE_INFO_2, + RESOLVE_IMAGE_INFO_2_KHR = RESOLVE_IMAGE_INFO_2, + BUFFER_COPY_2_KHR = BUFFER_COPY_2, + IMAGE_COPY_2_KHR = IMAGE_COPY_2, + IMAGE_BLIT_2_KHR = IMAGE_BLIT_2, + BUFFER_IMAGE_COPY_2_KHR = BUFFER_IMAGE_COPY_2, + IMAGE_RESOLVE_2_KHR = IMAGE_RESOLVE_2, + FORMAT_PROPERTIES_3_KHR = FORMAT_PROPERTIES_3, + PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR, + QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR, + PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES, + PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR = PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES, + DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR = DEVICE_BUFFER_MEMORY_REQUIREMENTS, + DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR = DEVICE_IMAGE_MEMORY_REQUIREMENTS, } SubgroupFeatureFlags :: distinct bit_set[SubgroupFeatureFlag; Flags] @@ -2737,9 +2961,10 @@ SubgroupFeatureFlag :: enum Flags { PARTITIONED_NV = 8, } -SubmitFlagsKHR :: distinct bit_set[SubmitFlagKHR; Flags] -SubmitFlagKHR :: enum Flags { - PROTECTED = 0, +SubmitFlags :: distinct bit_set[SubmitFlag; Flags] +SubmitFlag :: enum Flags { + PROTECTED = 0, + PROTECTED_KHR = PROTECTED, } SubpassContents :: enum c.int { @@ -2749,10 +2974,13 @@ SubpassContents :: enum c.int { SubpassDescriptionFlags :: distinct bit_set[SubpassDescriptionFlag; Flags] SubpassDescriptionFlag :: enum Flags { - PER_VIEW_ATTRIBUTES_NVX = 0, - PER_VIEW_POSITION_X_ONLY_NVX = 1, - FRAGMENT_REGION_QCOM = 2, - SHADER_RESOLVE_QCOM = 3, + PER_VIEW_ATTRIBUTES_NVX = 0, + PER_VIEW_POSITION_X_ONLY_NVX = 1, + FRAGMENT_REGION_QCOM = 2, + SHADER_RESOLVE_QCOM = 3, + RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_ARM = 4, + RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_ARM = 5, + RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_ARM = 6, } SurfaceCounterFlagsEXT :: distinct bit_set[SurfaceCounterFlagEXT; Flags] @@ -2802,15 +3030,20 @@ TimeDomainEXT :: enum c.int { QUERY_PERFORMANCE_COUNTER = 3, } -ToolPurposeFlagsEXT :: distinct bit_set[ToolPurposeFlagEXT; Flags] -ToolPurposeFlagEXT :: enum Flags { - VALIDATION = 0, - PROFILING = 1, - TRACING = 2, - ADDITIONAL_FEATURES = 3, - MODIFYING_FEATURES = 4, - DEBUG_REPORTING = 5, - DEBUG_MARKERS = 6, +ToolPurposeFlags :: distinct bit_set[ToolPurposeFlag; Flags] +ToolPurposeFlag :: enum Flags { + VALIDATION = 0, + PROFILING = 1, + TRACING = 2, + ADDITIONAL_FEATURES = 3, + MODIFYING_FEATURES = 4, + DEBUG_REPORTING_EXT = 5, + DEBUG_MARKERS_EXT = 6, + VALIDATION_EXT = VALIDATION, + PROFILING_EXT = PROFILING, + TRACING_EXT = TRACING, + ADDITIONAL_FEATURES_EXT = ADDITIONAL_FEATURES, + MODIFYING_FEATURES_EXT = MODIFYING_FEATURES, } ValidationCacheHeaderVersionEXT :: enum c.int { @@ -2894,32 +3127,24 @@ HeadlessSurfaceCreateFlagsEXT :: distinct bit_set[Headles HeadlessSurfaceCreateFlagEXT :: enum u32 {} IOSSurfaceCreateFlagsMVK :: distinct bit_set[IOSSurfaceCreateFlagMVK; Flags] IOSSurfaceCreateFlagMVK :: enum u32 {} -InstanceCreateFlags :: distinct bit_set[InstanceCreateFlag; Flags] -InstanceCreateFlag :: enum u32 {} MacOSSurfaceCreateFlagsMVK :: distinct bit_set[MacOSSurfaceCreateFlagMVK; Flags] MacOSSurfaceCreateFlagMVK :: enum u32 {} MemoryMapFlags :: distinct bit_set[MemoryMapFlag; Flags] MemoryMapFlag :: enum u32 {} MetalSurfaceCreateFlagsEXT :: distinct bit_set[MetalSurfaceCreateFlagEXT; Flags] MetalSurfaceCreateFlagEXT :: enum u32 {} -PipelineColorBlendStateCreateFlags :: distinct bit_set[PipelineColorBlendStateCreateFlag; Flags] -PipelineColorBlendStateCreateFlag :: enum u32 {} PipelineCoverageModulationStateCreateFlagsNV :: distinct bit_set[PipelineCoverageModulationStateCreateFlagNV; Flags] PipelineCoverageModulationStateCreateFlagNV :: enum u32 {} PipelineCoverageReductionStateCreateFlagsNV :: distinct bit_set[PipelineCoverageReductionStateCreateFlagNV; Flags] PipelineCoverageReductionStateCreateFlagNV :: enum u32 {} PipelineCoverageToColorStateCreateFlagsNV :: distinct bit_set[PipelineCoverageToColorStateCreateFlagNV; Flags] PipelineCoverageToColorStateCreateFlagNV :: enum u32 {} -PipelineDepthStencilStateCreateFlags :: distinct bit_set[PipelineDepthStencilStateCreateFlag; Flags] -PipelineDepthStencilStateCreateFlag :: enum u32 {} PipelineDiscardRectangleStateCreateFlagsEXT :: distinct bit_set[PipelineDiscardRectangleStateCreateFlagEXT; Flags] PipelineDiscardRectangleStateCreateFlagEXT :: enum u32 {} PipelineDynamicStateCreateFlags :: distinct bit_set[PipelineDynamicStateCreateFlag; Flags] PipelineDynamicStateCreateFlag :: enum u32 {} PipelineInputAssemblyStateCreateFlags :: distinct bit_set[PipelineInputAssemblyStateCreateFlag; Flags] PipelineInputAssemblyStateCreateFlag :: enum u32 {} -PipelineLayoutCreateFlags :: distinct bit_set[PipelineLayoutCreateFlag; Flags] -PipelineLayoutCreateFlag :: enum u32 {} PipelineMultisampleStateCreateFlags :: distinct bit_set[PipelineMultisampleStateCreateFlag; Flags] PipelineMultisampleStateCreateFlag :: enum u32 {} PipelineRasterizationConservativeStateCreateFlagsEXT :: distinct bit_set[PipelineRasterizationConservativeStateCreateFlagEXT; Flags] @@ -2938,6 +3163,8 @@ PipelineViewportStateCreateFlags :: distinct bit_set[Pipelin PipelineViewportStateCreateFlag :: enum u32 {} PipelineViewportSwizzleStateCreateFlagsNV :: distinct bit_set[PipelineViewportSwizzleStateCreateFlagNV; Flags] PipelineViewportSwizzleStateCreateFlagNV :: enum u32 {} +PrivateDataSlotCreateFlags :: distinct bit_set[PrivateDataSlotCreateFlag; Flags] +PrivateDataSlotCreateFlag :: enum u32 {} QueryPoolCreateFlags :: distinct bit_set[QueryPoolCreateFlag; Flags] QueryPoolCreateFlag :: enum u32 {} SemaphoreCreateFlags :: distinct bit_set[SemaphoreCreateFlag; Flags] diff --git a/vendor/vulkan/procedures.odin b/vendor/vulkan/procedures.odin index 7557d3c36..227f02a87 100644 --- a/vendor/vulkan/procedures.odin +++ b/vendor/vulkan/procedures.odin @@ -100,7 +100,8 @@ ProcGetPhysicalDeviceSurfaceFormatsKHR :: #type pro ProcGetPhysicalDeviceSurfacePresentModes2EXT :: #type proc "system" (physicalDevice: PhysicalDevice, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pPresentModeCount: ^u32, pPresentModes: [^]PresentModeKHR) -> Result ProcGetPhysicalDeviceSurfacePresentModesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, surface: SurfaceKHR, pPresentModeCount: ^u32, pPresentModes: [^]PresentModeKHR) -> Result ProcGetPhysicalDeviceSurfaceSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, surface: SurfaceKHR, pSupported: ^b32) -> Result -ProcGetPhysicalDeviceToolPropertiesEXT :: #type proc "system" (physicalDevice: PhysicalDevice, pToolCount: ^u32, pToolProperties: [^]PhysicalDeviceToolPropertiesEXT) -> Result +ProcGetPhysicalDeviceToolProperties :: #type proc "system" (physicalDevice: PhysicalDevice, pToolCount: ^u32, pToolProperties: [^]PhysicalDeviceToolProperties) -> Result +ProcGetPhysicalDeviceToolPropertiesEXT :: #type proc "system" (physicalDevice: PhysicalDevice, pToolCount: ^u32, pToolProperties: [^]PhysicalDeviceToolProperties) -> Result ProcGetPhysicalDeviceWin32PresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32 ProcGetWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result ProcReleaseDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result @@ -131,6 +132,8 @@ ProcCmdBeginQueryIndexedEXT :: #type proc "system" (comm ProcCmdBeginRenderPass :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, contents: SubpassContents) ProcCmdBeginRenderPass2 :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, pSubpassBeginInfo: ^SubpassBeginInfo) ProcCmdBeginRenderPass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pRenderPassBegin: ^RenderPassBeginInfo, pSubpassBeginInfo: ^SubpassBeginInfo) +ProcCmdBeginRendering :: #type proc "system" (commandBuffer: CommandBuffer, pRenderingInfo: ^RenderingInfo) +ProcCmdBeginRenderingKHR :: #type proc "system" (commandBuffer: CommandBuffer, pRenderingInfo: ^RenderingInfo) ProcCmdBeginTransformFeedbackEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstCounterBuffer: u32, counterBufferCount: u32, pCounterBuffers: [^]Buffer, pCounterBufferOffsets: [^]DeviceSize) ProcCmdBindDescriptorSets :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, layout: PipelineLayout, firstSet: u32, descriptorSetCount: u32, pDescriptorSets: [^]DescriptorSet, dynamicOffsetCount: u32, pDynamicOffsets: [^]u32) ProcCmdBindIndexBuffer :: #type proc "system" (commandBuffer: CommandBuffer, buffer: Buffer, offset: DeviceSize, indexType: IndexType) @@ -140,9 +143,11 @@ ProcCmdBindPipelineShaderGroupNV :: #type proc "system" (comm ProcCmdBindShadingRateImageNV :: #type proc "system" (commandBuffer: CommandBuffer, imageView: ImageView, imageLayout: ImageLayout) ProcCmdBindTransformFeedbackBuffersEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize, pSizes: [^]DeviceSize) ProcCmdBindVertexBuffers :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize) +ProcCmdBindVertexBuffers2 :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize, pSizes: [^]DeviceSize, pStrides: [^]DeviceSize) ProcCmdBindVertexBuffers2EXT :: #type proc "system" (commandBuffer: CommandBuffer, firstBinding: u32, bindingCount: u32, pBuffers: [^]Buffer, pOffsets: [^]DeviceSize, pSizes: [^]DeviceSize, pStrides: [^]DeviceSize) ProcCmdBlitImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageBlit, filter: Filter) -ProcCmdBlitImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pBlitImageInfo: ^BlitImageInfo2KHR) +ProcCmdBlitImage2 :: #type proc "system" (commandBuffer: CommandBuffer, pBlitImageInfo: ^BlitImageInfo2) +ProcCmdBlitImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pBlitImageInfo: ^BlitImageInfo2) ProcCmdBuildAccelerationStructureNV :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^AccelerationStructureInfoNV, instanceData: Buffer, instanceOffset: DeviceSize, update: b32, dst: AccelerationStructureNV, src: AccelerationStructureNV, scratch: Buffer, scratchOffset: DeviceSize) ProcCmdBuildAccelerationStructuresIndirectKHR :: #type proc "system" (commandBuffer: CommandBuffer, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, pIndirectDeviceAddresses: [^]DeviceAddress, pIndirectStrides: [^]u32, ppMaxPrimitiveCounts: ^[^]u32) ProcCmdBuildAccelerationStructuresKHR :: #type proc "system" (commandBuffer: CommandBuffer, infoCount: u32, pInfos: [^]AccelerationStructureBuildGeometryInfoKHR, ppBuildRangeInfos: ^[^]AccelerationStructureBuildRangeInfoKHR) @@ -153,13 +158,17 @@ ProcCmdCopyAccelerationStructureKHR :: #type proc "system" (comm ProcCmdCopyAccelerationStructureNV :: #type proc "system" (commandBuffer: CommandBuffer, dst: AccelerationStructureNV, src: AccelerationStructureNV, mode: CopyAccelerationStructureModeKHR) ProcCmdCopyAccelerationStructureToMemoryKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyAccelerationStructureToMemoryInfoKHR) ProcCmdCopyBuffer :: #type proc "system" (commandBuffer: CommandBuffer, srcBuffer: Buffer, dstBuffer: Buffer, regionCount: u32, pRegions: [^]BufferCopy) -ProcCmdCopyBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferInfo: ^CopyBufferInfo2KHR) +ProcCmdCopyBuffer2 :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferInfo: ^CopyBufferInfo2) +ProcCmdCopyBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferInfo: ^CopyBufferInfo2) ProcCmdCopyBufferToImage :: #type proc "system" (commandBuffer: CommandBuffer, srcBuffer: Buffer, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]BufferImageCopy) -ProcCmdCopyBufferToImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferToImageInfo: ^CopyBufferToImageInfo2KHR) +ProcCmdCopyBufferToImage2 :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferToImageInfo: ^CopyBufferToImageInfo2) +ProcCmdCopyBufferToImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyBufferToImageInfo: ^CopyBufferToImageInfo2) ProcCmdCopyImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageCopy) -ProcCmdCopyImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageInfo: ^CopyImageInfo2KHR) +ProcCmdCopyImage2 :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageInfo: ^CopyImageInfo2) +ProcCmdCopyImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageInfo: ^CopyImageInfo2) ProcCmdCopyImageToBuffer :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstBuffer: Buffer, regionCount: u32, pRegions: [^]BufferImageCopy) -ProcCmdCopyImageToBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageToBufferInfo: ^CopyImageToBufferInfo2KHR) +ProcCmdCopyImageToBuffer2 :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageToBufferInfo: ^CopyImageToBufferInfo2) +ProcCmdCopyImageToBuffer2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pCopyImageToBufferInfo: ^CopyImageToBufferInfo2) ProcCmdCopyMemoryToAccelerationStructureKHR :: #type proc "system" (commandBuffer: CommandBuffer, pInfo: ^CopyMemoryToAccelerationStructureInfoKHR) ProcCmdCopyQueryPoolResults :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, firstQuery: u32, queryCount: u32, dstBuffer: Buffer, dstOffset: DeviceSize, stride: DeviceSize, flags: QueryResultFlags) ProcCmdCuLaunchKernelNVX :: #type proc "system" (commandBuffer: CommandBuffer, pLaunchInfo: ^CuLaunchInfoNVX) @@ -193,6 +202,8 @@ ProcCmdEndQueryIndexedEXT :: #type proc "system" (comm ProcCmdEndRenderPass :: #type proc "system" (commandBuffer: CommandBuffer) ProcCmdEndRenderPass2 :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassEndInfo: ^SubpassEndInfo) ProcCmdEndRenderPass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassEndInfo: ^SubpassEndInfo) +ProcCmdEndRendering :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdEndRenderingKHR :: #type proc "system" (commandBuffer: CommandBuffer) ProcCmdEndTransformFeedbackEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstCounterBuffer: u32, counterBufferCount: u32, pCounterBuffers: [^]Buffer, pCounterBufferOffsets: [^]DeviceSize) ProcCmdExecuteCommands :: #type proc "system" (commandBuffer: CommandBuffer, commandBufferCount: u32, pCommandBuffers: [^]CommandBuffer) ProcCmdExecuteGeneratedCommandsNV :: #type proc "system" (commandBuffer: CommandBuffer, isPreprocessed: b32, pGeneratedCommandsInfo: ^GeneratedCommandsInfoNV) @@ -202,35 +213,46 @@ ProcCmdNextSubpass :: #type proc "system" (comm ProcCmdNextSubpass2 :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassBeginInfo: ^SubpassBeginInfo, pSubpassEndInfo: ^SubpassEndInfo) ProcCmdNextSubpass2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pSubpassBeginInfo: ^SubpassBeginInfo, pSubpassEndInfo: ^SubpassEndInfo) ProcCmdPipelineBarrier :: #type proc "system" (commandBuffer: CommandBuffer, srcStageMask: PipelineStageFlags, dstStageMask: PipelineStageFlags, dependencyFlags: DependencyFlags, memoryBarrierCount: u32, pMemoryBarriers: [^]MemoryBarrier, bufferMemoryBarrierCount: u32, pBufferMemoryBarriers: [^]BufferMemoryBarrier, imageMemoryBarrierCount: u32, pImageMemoryBarriers: [^]ImageMemoryBarrier) -ProcCmdPipelineBarrier2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pDependencyInfo: ^DependencyInfoKHR) +ProcCmdPipelineBarrier2 :: #type proc "system" (commandBuffer: CommandBuffer, pDependencyInfo: ^DependencyInfo) +ProcCmdPipelineBarrier2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pDependencyInfo: ^DependencyInfo) ProcCmdPreprocessGeneratedCommandsNV :: #type proc "system" (commandBuffer: CommandBuffer, pGeneratedCommandsInfo: ^GeneratedCommandsInfoNV) ProcCmdPushConstants :: #type proc "system" (commandBuffer: CommandBuffer, layout: PipelineLayout, stageFlags: ShaderStageFlags, offset: u32, size: u32, pValues: rawptr) ProcCmdPushDescriptorSetKHR :: #type proc "system" (commandBuffer: CommandBuffer, pipelineBindPoint: PipelineBindPoint, layout: PipelineLayout, set: u32, descriptorWriteCount: u32, pDescriptorWrites: [^]WriteDescriptorSet) ProcCmdPushDescriptorSetWithTemplateKHR :: #type proc "system" (commandBuffer: CommandBuffer, descriptorUpdateTemplate: DescriptorUpdateTemplate, layout: PipelineLayout, set: u32, pData: rawptr) ProcCmdResetEvent :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags) -ProcCmdResetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags2KHR) +ProcCmdResetEvent2 :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags2) +ProcCmdResetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags2) ProcCmdResetQueryPool :: #type proc "system" (commandBuffer: CommandBuffer, queryPool: QueryPool, firstQuery: u32, queryCount: u32) ProcCmdResolveImage :: #type proc "system" (commandBuffer: CommandBuffer, srcImage: Image, srcImageLayout: ImageLayout, dstImage: Image, dstImageLayout: ImageLayout, regionCount: u32, pRegions: [^]ImageResolve) -ProcCmdResolveImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pResolveImageInfo: ^ResolveImageInfo2KHR) +ProcCmdResolveImage2 :: #type proc "system" (commandBuffer: CommandBuffer, pResolveImageInfo: ^ResolveImageInfo2) +ProcCmdResolveImage2KHR :: #type proc "system" (commandBuffer: CommandBuffer, pResolveImageInfo: ^ResolveImageInfo2) ProcCmdSetBlendConstants :: #type proc "system" (commandBuffer: CommandBuffer) ProcCmdSetCheckpointNV :: #type proc "system" (commandBuffer: CommandBuffer, pCheckpointMarker: rawptr) ProcCmdSetCoarseSampleOrderNV :: #type proc "system" (commandBuffer: CommandBuffer, sampleOrderType: CoarseSampleOrderTypeNV, customSampleOrderCount: u32, pCustomSampleOrders: [^]CoarseSampleOrderCustomNV) +ProcCmdSetCullMode :: #type proc "system" (commandBuffer: CommandBuffer, cullMode: CullModeFlags) ProcCmdSetCullModeEXT :: #type proc "system" (commandBuffer: CommandBuffer, cullMode: CullModeFlags) ProcCmdSetDepthBias :: #type proc "system" (commandBuffer: CommandBuffer, depthBiasConstantFactor: f32, depthBiasClamp: f32, depthBiasSlopeFactor: f32) +ProcCmdSetDepthBiasEnable :: #type proc "system" (commandBuffer: CommandBuffer, depthBiasEnable: b32) ProcCmdSetDepthBiasEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthBiasEnable: b32) ProcCmdSetDepthBounds :: #type proc "system" (commandBuffer: CommandBuffer, minDepthBounds: f32, maxDepthBounds: f32) +ProcCmdSetDepthBoundsTestEnable :: #type proc "system" (commandBuffer: CommandBuffer, depthBoundsTestEnable: b32) ProcCmdSetDepthBoundsTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthBoundsTestEnable: b32) +ProcCmdSetDepthCompareOp :: #type proc "system" (commandBuffer: CommandBuffer, depthCompareOp: CompareOp) ProcCmdSetDepthCompareOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthCompareOp: CompareOp) +ProcCmdSetDepthTestEnable :: #type proc "system" (commandBuffer: CommandBuffer, depthTestEnable: b32) ProcCmdSetDepthTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthTestEnable: b32) +ProcCmdSetDepthWriteEnable :: #type proc "system" (commandBuffer: CommandBuffer, depthWriteEnable: b32) ProcCmdSetDepthWriteEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, depthWriteEnable: b32) ProcCmdSetDeviceMask :: #type proc "system" (commandBuffer: CommandBuffer, deviceMask: u32) ProcCmdSetDeviceMaskKHR :: #type proc "system" (commandBuffer: CommandBuffer, deviceMask: u32) ProcCmdSetDiscardRectangleEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstDiscardRectangle: u32, discardRectangleCount: u32, pDiscardRectangles: [^]Rect2D) ProcCmdSetEvent :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, stageMask: PipelineStageFlags) -ProcCmdSetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, pDependencyInfo: ^DependencyInfoKHR) +ProcCmdSetEvent2 :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, pDependencyInfo: ^DependencyInfo) +ProcCmdSetEvent2KHR :: #type proc "system" (commandBuffer: CommandBuffer, event: Event, pDependencyInfo: ^DependencyInfo) ProcCmdSetExclusiveScissorNV :: #type proc "system" (commandBuffer: CommandBuffer, firstExclusiveScissor: u32, exclusiveScissorCount: u32, pExclusiveScissors: [^]Rect2D) ProcCmdSetFragmentShadingRateEnumNV :: #type proc "system" (commandBuffer: CommandBuffer, shadingRate: FragmentShadingRateNV) ProcCmdSetFragmentShadingRateKHR :: #type proc "system" (commandBuffer: CommandBuffer, pFragmentSize: ^Extent2D) +ProcCmdSetFrontFace :: #type proc "system" (commandBuffer: CommandBuffer, frontFace: FrontFace) ProcCmdSetFrontFaceEXT :: #type proc "system" (commandBuffer: CommandBuffer, frontFace: FrontFace) ProcCmdSetLineStippleEXT :: #type proc "system" (commandBuffer: CommandBuffer, lineStippleFactor: u32, lineStipplePattern: u16) ProcCmdSetLineWidth :: #type proc "system" (commandBuffer: CommandBuffer, lineWidth: f32) @@ -239,22 +261,29 @@ ProcCmdSetPatchControlPointsEXT :: #type proc "system" (comm ProcCmdSetPerformanceMarkerINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^PerformanceMarkerInfoINTEL) -> Result ProcCmdSetPerformanceOverrideINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pOverrideInfo: ^PerformanceOverrideInfoINTEL) -> Result ProcCmdSetPerformanceStreamMarkerINTEL :: #type proc "system" (commandBuffer: CommandBuffer, pMarkerInfo: ^PerformanceStreamMarkerInfoINTEL) -> Result +ProcCmdSetPrimitiveRestartEnable :: #type proc "system" (commandBuffer: CommandBuffer, primitiveRestartEnable: b32) ProcCmdSetPrimitiveRestartEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, primitiveRestartEnable: b32) +ProcCmdSetPrimitiveTopology :: #type proc "system" (commandBuffer: CommandBuffer, primitiveTopology: PrimitiveTopology) ProcCmdSetPrimitiveTopologyEXT :: #type proc "system" (commandBuffer: CommandBuffer, primitiveTopology: PrimitiveTopology) +ProcCmdSetRasterizerDiscardEnable :: #type proc "system" (commandBuffer: CommandBuffer, rasterizerDiscardEnable: b32) ProcCmdSetRasterizerDiscardEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, rasterizerDiscardEnable: b32) ProcCmdSetRayTracingPipelineStackSizeKHR :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStackSize: u32) ProcCmdSetSampleLocationsEXT :: #type proc "system" (commandBuffer: CommandBuffer, pSampleLocationsInfo: ^SampleLocationsInfoEXT) ProcCmdSetScissor :: #type proc "system" (commandBuffer: CommandBuffer, firstScissor: u32, scissorCount: u32, pScissors: [^]Rect2D) +ProcCmdSetScissorWithCount :: #type proc "system" (commandBuffer: CommandBuffer, scissorCount: u32, pScissors: [^]Rect2D) ProcCmdSetScissorWithCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, scissorCount: u32, pScissors: [^]Rect2D) ProcCmdSetStencilCompareMask :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, compareMask: u32) +ProcCmdSetStencilOp :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, failOp: StencilOp, passOp: StencilOp, depthFailOp: StencilOp, compareOp: CompareOp) ProcCmdSetStencilOpEXT :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, failOp: StencilOp, passOp: StencilOp, depthFailOp: StencilOp, compareOp: CompareOp) ProcCmdSetStencilReference :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, reference: u32) +ProcCmdSetStencilTestEnable :: #type proc "system" (commandBuffer: CommandBuffer, stencilTestEnable: b32) ProcCmdSetStencilTestEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, stencilTestEnable: b32) ProcCmdSetStencilWriteMask :: #type proc "system" (commandBuffer: CommandBuffer, faceMask: StencilFaceFlags, writeMask: u32) ProcCmdSetVertexInputEXT :: #type proc "system" (commandBuffer: CommandBuffer, vertexBindingDescriptionCount: u32, pVertexBindingDescriptions: [^]VertexInputBindingDescription2EXT, vertexAttributeDescriptionCount: u32, pVertexAttributeDescriptions: [^]VertexInputAttributeDescription2EXT) ProcCmdSetViewport :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pViewports: [^]Viewport) ProcCmdSetViewportShadingRatePaletteNV :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pShadingRatePalettes: [^]ShadingRatePaletteNV) ProcCmdSetViewportWScalingNV :: #type proc "system" (commandBuffer: CommandBuffer, firstViewport: u32, viewportCount: u32, pViewportWScalings: [^]ViewportWScalingNV) +ProcCmdSetViewportWithCount :: #type proc "system" (commandBuffer: CommandBuffer, viewportCount: u32, pViewports: [^]Viewport) ProcCmdSetViewportWithCountEXT :: #type proc "system" (commandBuffer: CommandBuffer, viewportCount: u32, pViewports: [^]Viewport) ProcCmdSubpassShadingHUAWEI :: #type proc "system" (commandBuffer: CommandBuffer) ProcCmdTraceRaysIndirectKHR :: #type proc "system" (commandBuffer: CommandBuffer, pRaygenShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pMissShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pHitShaderBindingTable: [^]StridedDeviceAddressRegionKHR, pCallableShaderBindingTable: [^]StridedDeviceAddressRegionKHR, indirectDeviceAddress: DeviceAddress) @@ -262,13 +291,15 @@ ProcCmdTraceRaysKHR :: #type proc "system" (comm ProcCmdTraceRaysNV :: #type proc "system" (commandBuffer: CommandBuffer, raygenShaderBindingTableBuffer: Buffer, raygenShaderBindingOffset: DeviceSize, missShaderBindingTableBuffer: Buffer, missShaderBindingOffset: DeviceSize, missShaderBindingStride: DeviceSize, hitShaderBindingTableBuffer: Buffer, hitShaderBindingOffset: DeviceSize, hitShaderBindingStride: DeviceSize, callableShaderBindingTableBuffer: Buffer, callableShaderBindingOffset: DeviceSize, callableShaderBindingStride: DeviceSize, width: u32, height: u32, depth: u32) ProcCmdUpdateBuffer :: #type proc "system" (commandBuffer: CommandBuffer, dstBuffer: Buffer, dstOffset: DeviceSize, dataSize: DeviceSize, pData: rawptr) ProcCmdWaitEvents :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, srcStageMask: PipelineStageFlags, dstStageMask: PipelineStageFlags, memoryBarrierCount: u32, pMemoryBarriers: [^]MemoryBarrier, bufferMemoryBarrierCount: u32, pBufferMemoryBarriers: [^]BufferMemoryBarrier, imageMemoryBarrierCount: u32, pImageMemoryBarriers: [^]ImageMemoryBarrier) -ProcCmdWaitEvents2KHR :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, pDependencyInfos: [^]DependencyInfoKHR) +ProcCmdWaitEvents2 :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, pDependencyInfos: [^]DependencyInfo) +ProcCmdWaitEvents2KHR :: #type proc "system" (commandBuffer: CommandBuffer, eventCount: u32, pEvents: [^]Event, pDependencyInfos: [^]DependencyInfo) ProcCmdWriteAccelerationStructuresPropertiesKHR :: #type proc "system" (commandBuffer: CommandBuffer, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureKHR, queryType: QueryType, queryPool: QueryPool, firstQuery: u32) ProcCmdWriteAccelerationStructuresPropertiesNV :: #type proc "system" (commandBuffer: CommandBuffer, accelerationStructureCount: u32, pAccelerationStructures: [^]AccelerationStructureNV, queryType: QueryType, queryPool: QueryPool, firstQuery: u32) -ProcCmdWriteBufferMarker2AMD :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2KHR, dstBuffer: Buffer, dstOffset: DeviceSize, marker: u32) +ProcCmdWriteBufferMarker2AMD :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2, dstBuffer: Buffer, dstOffset: DeviceSize, marker: u32) ProcCmdWriteBufferMarkerAMD :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStage: PipelineStageFlags, dstBuffer: Buffer, dstOffset: DeviceSize, marker: u32) ProcCmdWriteTimestamp :: #type proc "system" (commandBuffer: CommandBuffer, pipelineStage: PipelineStageFlags, queryPool: QueryPool, query: u32) -ProcCmdWriteTimestamp2KHR :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2KHR, queryPool: QueryPool, query: u32) +ProcCmdWriteTimestamp2 :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2, queryPool: QueryPool, query: u32) +ProcCmdWriteTimestamp2KHR :: #type proc "system" (commandBuffer: CommandBuffer, stage: PipelineStageFlags2, queryPool: QueryPool, query: u32) ProcCompileDeferredNV :: #type proc "system" (device: Device, pipeline: Pipeline, shader: u32) -> Result ProcCopyAccelerationStructureKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyAccelerationStructureInfoKHR) -> Result ProcCopyAccelerationStructureToMemoryKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pInfo: ^CopyAccelerationStructureToMemoryInfoKHR) -> Result @@ -295,7 +326,8 @@ ProcCreateImageView :: #type proc "system" (devi ProcCreateIndirectCommandsLayoutNV :: #type proc "system" (device: Device, pCreateInfo: ^IndirectCommandsLayoutCreateInfoNV, pAllocator: ^AllocationCallbacks, pIndirectCommandsLayout: ^IndirectCommandsLayoutNV) -> Result ProcCreatePipelineCache :: #type proc "system" (device: Device, pCreateInfo: ^PipelineCacheCreateInfo, pAllocator: ^AllocationCallbacks, pPipelineCache: ^PipelineCache) -> Result ProcCreatePipelineLayout :: #type proc "system" (device: Device, pCreateInfo: ^PipelineLayoutCreateInfo, pAllocator: ^AllocationCallbacks, pPipelineLayout: ^PipelineLayout) -> Result -ProcCreatePrivateDataSlotEXT :: #type proc "system" (device: Device, pCreateInfo: ^PrivateDataSlotCreateInfoEXT, pAllocator: ^AllocationCallbacks, pPrivateDataSlot: ^PrivateDataSlotEXT) -> Result +ProcCreatePrivateDataSlot :: #type proc "system" (device: Device, pCreateInfo: ^PrivateDataSlotCreateInfo, pAllocator: ^AllocationCallbacks, pPrivateDataSlot: ^PrivateDataSlot) -> Result +ProcCreatePrivateDataSlotEXT :: #type proc "system" (device: Device, pCreateInfo: ^PrivateDataSlotCreateInfo, pAllocator: ^AllocationCallbacks, pPrivateDataSlot: ^PrivateDataSlot) -> Result ProcCreateQueryPool :: #type proc "system" (device: Device, pCreateInfo: ^QueryPoolCreateInfo, pAllocator: ^AllocationCallbacks, pQueryPool: ^QueryPool) -> Result ProcCreateRayTracingPipelinesKHR :: #type proc "system" (device: Device, deferredOperation: DeferredOperationKHR, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]RayTracingPipelineCreateInfoKHR, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result ProcCreateRayTracingPipelinesNV :: #type proc "system" (device: Device, pipelineCache: PipelineCache, createInfoCount: u32, pCreateInfos: [^]RayTracingPipelineCreateInfoNV, pAllocator: ^AllocationCallbacks, pPipelines: [^]Pipeline) -> Result @@ -335,7 +367,8 @@ ProcDestroyIndirectCommandsLayoutNV :: #type proc "system" (devi ProcDestroyPipeline :: #type proc "system" (device: Device, pipeline: Pipeline, pAllocator: ^AllocationCallbacks) ProcDestroyPipelineCache :: #type proc "system" (device: Device, pipelineCache: PipelineCache, pAllocator: ^AllocationCallbacks) ProcDestroyPipelineLayout :: #type proc "system" (device: Device, pipelineLayout: PipelineLayout, pAllocator: ^AllocationCallbacks) -ProcDestroyPrivateDataSlotEXT :: #type proc "system" (device: Device, privateDataSlot: PrivateDataSlotEXT, pAllocator: ^AllocationCallbacks) +ProcDestroyPrivateDataSlot :: #type proc "system" (device: Device, privateDataSlot: PrivateDataSlot, pAllocator: ^AllocationCallbacks) +ProcDestroyPrivateDataSlotEXT :: #type proc "system" (device: Device, privateDataSlot: PrivateDataSlot, pAllocator: ^AllocationCallbacks) ProcDestroyQueryPool :: #type proc "system" (device: Device, queryPool: QueryPool, pAllocator: ^AllocationCallbacks) ProcDestroyRenderPass :: #type proc "system" (device: Device, renderPass: RenderPass, pAllocator: ^AllocationCallbacks) ProcDestroySampler :: #type proc "system" (device: Device, sampler: Sampler, pAllocator: ^AllocationCallbacks) @@ -367,14 +400,22 @@ ProcGetBufferOpaqueCaptureAddressKHR :: #type proc "system" (devi ProcGetCalibratedTimestampsEXT :: #type proc "system" (device: Device, timestampCount: u32, pTimestampInfos: [^]CalibratedTimestampInfoEXT, pTimestamps: [^]u64, pMaxDeviation: ^u64) -> Result ProcGetDeferredOperationMaxConcurrencyKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> u32 ProcGetDeferredOperationResultKHR :: #type proc "system" (device: Device, operation: DeferredOperationKHR) -> Result +ProcGetDescriptorSetHostMappingVALVE :: #type proc "system" (device: Device, descriptorSet: DescriptorSet, ppData: ^rawptr) +ProcGetDescriptorSetLayoutHostMappingInfoVALVE :: #type proc "system" (device: Device, pBindingReference: ^DescriptorSetBindingReferenceVALVE, pHostMapping: ^DescriptorSetLayoutHostMappingInfoVALVE) ProcGetDescriptorSetLayoutSupport :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pSupport: ^DescriptorSetLayoutSupport) ProcGetDescriptorSetLayoutSupportKHR :: #type proc "system" (device: Device, pCreateInfo: ^DescriptorSetLayoutCreateInfo, pSupport: ^DescriptorSetLayoutSupport) ProcGetDeviceAccelerationStructureCompatibilityKHR :: #type proc "system" (device: Device, pVersionInfo: ^AccelerationStructureVersionInfoKHR, pCompatibility: ^AccelerationStructureCompatibilityKHR) +ProcGetDeviceBufferMemoryRequirements :: #type proc "system" (device: Device, pInfo: ^DeviceBufferMemoryRequirements, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetDeviceBufferMemoryRequirementsKHR :: #type proc "system" (device: Device, pInfo: ^DeviceBufferMemoryRequirements, pMemoryRequirements: [^]MemoryRequirements2) ProcGetDeviceGroupPeerMemoryFeatures :: #type proc "system" (device: Device, heapIndex: u32, localDeviceIndex: u32, remoteDeviceIndex: u32, pPeerMemoryFeatures: [^]PeerMemoryFeatureFlags) ProcGetDeviceGroupPeerMemoryFeaturesKHR :: #type proc "system" (device: Device, heapIndex: u32, localDeviceIndex: u32, remoteDeviceIndex: u32, pPeerMemoryFeatures: [^]PeerMemoryFeatureFlags) ProcGetDeviceGroupPresentCapabilitiesKHR :: #type proc "system" (device: Device, pDeviceGroupPresentCapabilities: [^]DeviceGroupPresentCapabilitiesKHR) -> Result ProcGetDeviceGroupSurfacePresentModes2EXT :: #type proc "system" (device: Device, pSurfaceInfo: ^PhysicalDeviceSurfaceInfo2KHR, pModes: [^]DeviceGroupPresentModeFlagsKHR) -> Result ProcGetDeviceGroupSurfacePresentModesKHR :: #type proc "system" (device: Device, surface: SurfaceKHR, pModes: [^]DeviceGroupPresentModeFlagsKHR) -> Result +ProcGetDeviceImageMemoryRequirements :: #type proc "system" (device: Device, pInfo: ^DeviceImageMemoryRequirements, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetDeviceImageMemoryRequirementsKHR :: #type proc "system" (device: Device, pInfo: ^DeviceImageMemoryRequirements, pMemoryRequirements: [^]MemoryRequirements2) +ProcGetDeviceImageSparseMemoryRequirements :: #type proc "system" (device: Device, pInfo: ^DeviceImageMemoryRequirements, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements2) +ProcGetDeviceImageSparseMemoryRequirementsKHR :: #type proc "system" (device: Device, pInfo: ^DeviceImageMemoryRequirements, pSparseMemoryRequirementCount: ^u32, pSparseMemoryRequirements: [^]SparseImageMemoryRequirements2) ProcGetDeviceMemoryCommitment :: #type proc "system" (device: Device, memory: DeviceMemory, pCommittedMemoryInBytes: [^]DeviceSize) ProcGetDeviceMemoryOpaqueCaptureAddress :: #type proc "system" (device: Device, pInfo: ^DeviceMemoryOpaqueCaptureAddressInfo) -> u64 ProcGetDeviceMemoryOpaqueCaptureAddressKHR :: #type proc "system" (device: Device, pInfo: ^DeviceMemoryOpaqueCaptureAddressInfo) -> u64 @@ -410,7 +451,8 @@ ProcGetPipelineCacheData :: #type proc "system" (devi ProcGetPipelineExecutableInternalRepresentationsKHR :: #type proc "system" (device: Device, pExecutableInfo: ^PipelineExecutableInfoKHR, pInternalRepresentationCount: ^u32, pInternalRepresentations: [^]PipelineExecutableInternalRepresentationKHR) -> Result ProcGetPipelineExecutablePropertiesKHR :: #type proc "system" (device: Device, pPipelineInfo: ^PipelineInfoKHR, pExecutableCount: ^u32, pProperties: [^]PipelineExecutablePropertiesKHR) -> Result ProcGetPipelineExecutableStatisticsKHR :: #type proc "system" (device: Device, pExecutableInfo: ^PipelineExecutableInfoKHR, pStatisticCount: ^u32, pStatistics: [^]PipelineExecutableStatisticKHR) -> Result -ProcGetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlotEXT, pData: ^u64) +ProcGetPrivateData :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlot, pData: ^u64) +ProcGetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlot, pData: ^u64) ProcGetQueryPoolResults :: #type proc "system" (device: Device, queryPool: QueryPool, firstQuery: u32, queryCount: u32, dataSize: int, pData: rawptr, stride: DeviceSize, flags: QueryResultFlags) -> Result ProcGetQueueCheckpointData2NV :: #type proc "system" (queue: Queue, pCheckpointDataCount: ^u32, pCheckpointData: ^CheckpointData2NV) ProcGetQueueCheckpointDataNV :: #type proc "system" (queue: Queue, pCheckpointDataCount: ^u32, pCheckpointData: ^CheckpointDataNV) @@ -445,7 +487,8 @@ ProcQueueInsertDebugUtilsLabelEXT :: #type proc "system" (queu ProcQueuePresentKHR :: #type proc "system" (queue: Queue, pPresentInfo: ^PresentInfoKHR) -> Result ProcQueueSetPerformanceConfigurationINTEL :: #type proc "system" (queue: Queue, configuration: PerformanceConfigurationINTEL) -> Result ProcQueueSubmit :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo, fence: Fence) -> Result -ProcQueueSubmit2KHR :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo2KHR, fence: Fence) -> Result +ProcQueueSubmit2 :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo2, fence: Fence) -> Result +ProcQueueSubmit2KHR :: #type proc "system" (queue: Queue, submitCount: u32, pSubmits: [^]SubmitInfo2, fence: Fence) -> Result ProcQueueWaitIdle :: #type proc "system" (queue: Queue) -> Result ProcRegisterDeviceEventEXT :: #type proc "system" (device: Device, pDeviceEventInfo: ^DeviceEventInfoEXT, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result ProcRegisterDisplayEventEXT :: #type proc "system" (device: Device, display: DisplayKHR, pDisplayEventInfo: ^DisplayEventInfoEXT, pAllocator: ^AllocationCallbacks, pFence: ^Fence) -> Result @@ -465,7 +508,8 @@ ProcSetDeviceMemoryPriorityEXT :: #type proc "system" (devi ProcSetEvent :: #type proc "system" (device: Device, event: Event) -> Result ProcSetHdrMetadataEXT :: #type proc "system" (device: Device, swapchainCount: u32, pSwapchains: [^]SwapchainKHR, pMetadata: ^HdrMetadataEXT) ProcSetLocalDimmingAMD :: #type proc "system" (device: Device, swapChain: SwapchainKHR, localDimmingEnable: b32) -ProcSetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlotEXT, data: u64) -> Result +ProcSetPrivateData :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlot, data: u64) -> Result +ProcSetPrivateDataEXT :: #type proc "system" (device: Device, objectType: ObjectType, objectHandle: u64, privateDataSlot: PrivateDataSlot, data: u64) -> Result ProcSignalSemaphore :: #type proc "system" (device: Device, pSignalInfo: ^SemaphoreSignalInfo) -> Result ProcSignalSemaphoreKHR :: #type proc "system" (device: Device, pSignalInfo: ^SemaphoreSignalInfo) -> Result ProcTrimCommandPool :: #type proc "system" (device: Device, commandPool: CommandPool, flags: CommandPoolTrimFlags) @@ -568,6 +612,7 @@ GetPhysicalDeviceSurfaceFormatsKHR: ProcGetPhysical GetPhysicalDeviceSurfacePresentModes2EXT: ProcGetPhysicalDeviceSurfacePresentModes2EXT GetPhysicalDeviceSurfacePresentModesKHR: ProcGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfaceSupportKHR: ProcGetPhysicalDeviceSurfaceSupportKHR +GetPhysicalDeviceToolProperties: ProcGetPhysicalDeviceToolProperties GetPhysicalDeviceToolPropertiesEXT: ProcGetPhysicalDeviceToolPropertiesEXT GetPhysicalDeviceWin32PresentationSupportKHR: ProcGetPhysicalDeviceWin32PresentationSupportKHR GetWinrtDisplayNV: ProcGetWinrtDisplayNV @@ -599,6 +644,8 @@ CmdBeginQueryIndexedEXT: ProcCmdBeginQueryIndexedEXT CmdBeginRenderPass: ProcCmdBeginRenderPass CmdBeginRenderPass2: ProcCmdBeginRenderPass2 CmdBeginRenderPass2KHR: ProcCmdBeginRenderPass2KHR +CmdBeginRendering: ProcCmdBeginRendering +CmdBeginRenderingKHR: ProcCmdBeginRenderingKHR CmdBeginTransformFeedbackEXT: ProcCmdBeginTransformFeedbackEXT CmdBindDescriptorSets: ProcCmdBindDescriptorSets CmdBindIndexBuffer: ProcCmdBindIndexBuffer @@ -608,8 +655,10 @@ CmdBindPipelineShaderGroupNV: ProcCmdBindPipelineShaderGroupN CmdBindShadingRateImageNV: ProcCmdBindShadingRateImageNV CmdBindTransformFeedbackBuffersEXT: ProcCmdBindTransformFeedbackBuffersEXT CmdBindVertexBuffers: ProcCmdBindVertexBuffers +CmdBindVertexBuffers2: ProcCmdBindVertexBuffers2 CmdBindVertexBuffers2EXT: ProcCmdBindVertexBuffers2EXT CmdBlitImage: ProcCmdBlitImage +CmdBlitImage2: ProcCmdBlitImage2 CmdBlitImage2KHR: ProcCmdBlitImage2KHR CmdBuildAccelerationStructureNV: ProcCmdBuildAccelerationStructureNV CmdBuildAccelerationStructuresIndirectKHR: ProcCmdBuildAccelerationStructuresIndirectKHR @@ -621,12 +670,16 @@ CmdCopyAccelerationStructureKHR: ProcCmdCopyAccelerationStructur CmdCopyAccelerationStructureNV: ProcCmdCopyAccelerationStructureNV CmdCopyAccelerationStructureToMemoryKHR: ProcCmdCopyAccelerationStructureToMemoryKHR CmdCopyBuffer: ProcCmdCopyBuffer +CmdCopyBuffer2: ProcCmdCopyBuffer2 CmdCopyBuffer2KHR: ProcCmdCopyBuffer2KHR CmdCopyBufferToImage: ProcCmdCopyBufferToImage +CmdCopyBufferToImage2: ProcCmdCopyBufferToImage2 CmdCopyBufferToImage2KHR: ProcCmdCopyBufferToImage2KHR CmdCopyImage: ProcCmdCopyImage +CmdCopyImage2: ProcCmdCopyImage2 CmdCopyImage2KHR: ProcCmdCopyImage2KHR CmdCopyImageToBuffer: ProcCmdCopyImageToBuffer +CmdCopyImageToBuffer2: ProcCmdCopyImageToBuffer2 CmdCopyImageToBuffer2KHR: ProcCmdCopyImageToBuffer2KHR CmdCopyMemoryToAccelerationStructureKHR: ProcCmdCopyMemoryToAccelerationStructureKHR CmdCopyQueryPoolResults: ProcCmdCopyQueryPoolResults @@ -661,6 +714,8 @@ CmdEndQueryIndexedEXT: ProcCmdEndQueryIndexedEXT CmdEndRenderPass: ProcCmdEndRenderPass CmdEndRenderPass2: ProcCmdEndRenderPass2 CmdEndRenderPass2KHR: ProcCmdEndRenderPass2KHR +CmdEndRendering: ProcCmdEndRendering +CmdEndRenderingKHR: ProcCmdEndRenderingKHR CmdEndTransformFeedbackEXT: ProcCmdEndTransformFeedbackEXT CmdExecuteCommands: ProcCmdExecuteCommands CmdExecuteGeneratedCommandsNV: ProcCmdExecuteGeneratedCommandsNV @@ -670,35 +725,46 @@ CmdNextSubpass: ProcCmdNextSubpass CmdNextSubpass2: ProcCmdNextSubpass2 CmdNextSubpass2KHR: ProcCmdNextSubpass2KHR CmdPipelineBarrier: ProcCmdPipelineBarrier +CmdPipelineBarrier2: ProcCmdPipelineBarrier2 CmdPipelineBarrier2KHR: ProcCmdPipelineBarrier2KHR CmdPreprocessGeneratedCommandsNV: ProcCmdPreprocessGeneratedCommandsNV CmdPushConstants: ProcCmdPushConstants CmdPushDescriptorSetKHR: ProcCmdPushDescriptorSetKHR CmdPushDescriptorSetWithTemplateKHR: ProcCmdPushDescriptorSetWithTemplateKHR CmdResetEvent: ProcCmdResetEvent +CmdResetEvent2: ProcCmdResetEvent2 CmdResetEvent2KHR: ProcCmdResetEvent2KHR CmdResetQueryPool: ProcCmdResetQueryPool CmdResolveImage: ProcCmdResolveImage +CmdResolveImage2: ProcCmdResolveImage2 CmdResolveImage2KHR: ProcCmdResolveImage2KHR CmdSetBlendConstants: ProcCmdSetBlendConstants CmdSetCheckpointNV: ProcCmdSetCheckpointNV CmdSetCoarseSampleOrderNV: ProcCmdSetCoarseSampleOrderNV +CmdSetCullMode: ProcCmdSetCullMode CmdSetCullModeEXT: ProcCmdSetCullModeEXT CmdSetDepthBias: ProcCmdSetDepthBias +CmdSetDepthBiasEnable: ProcCmdSetDepthBiasEnable CmdSetDepthBiasEnableEXT: ProcCmdSetDepthBiasEnableEXT CmdSetDepthBounds: ProcCmdSetDepthBounds +CmdSetDepthBoundsTestEnable: ProcCmdSetDepthBoundsTestEnable CmdSetDepthBoundsTestEnableEXT: ProcCmdSetDepthBoundsTestEnableEXT +CmdSetDepthCompareOp: ProcCmdSetDepthCompareOp CmdSetDepthCompareOpEXT: ProcCmdSetDepthCompareOpEXT +CmdSetDepthTestEnable: ProcCmdSetDepthTestEnable CmdSetDepthTestEnableEXT: ProcCmdSetDepthTestEnableEXT +CmdSetDepthWriteEnable: ProcCmdSetDepthWriteEnable CmdSetDepthWriteEnableEXT: ProcCmdSetDepthWriteEnableEXT CmdSetDeviceMask: ProcCmdSetDeviceMask CmdSetDeviceMaskKHR: ProcCmdSetDeviceMaskKHR CmdSetDiscardRectangleEXT: ProcCmdSetDiscardRectangleEXT CmdSetEvent: ProcCmdSetEvent +CmdSetEvent2: ProcCmdSetEvent2 CmdSetEvent2KHR: ProcCmdSetEvent2KHR CmdSetExclusiveScissorNV: ProcCmdSetExclusiveScissorNV CmdSetFragmentShadingRateEnumNV: ProcCmdSetFragmentShadingRateEnumNV CmdSetFragmentShadingRateKHR: ProcCmdSetFragmentShadingRateKHR +CmdSetFrontFace: ProcCmdSetFrontFace CmdSetFrontFaceEXT: ProcCmdSetFrontFaceEXT CmdSetLineStippleEXT: ProcCmdSetLineStippleEXT CmdSetLineWidth: ProcCmdSetLineWidth @@ -707,22 +773,29 @@ CmdSetPatchControlPointsEXT: ProcCmdSetPatchControlPointsEXT CmdSetPerformanceMarkerINTEL: ProcCmdSetPerformanceMarkerINTEL CmdSetPerformanceOverrideINTEL: ProcCmdSetPerformanceOverrideINTEL CmdSetPerformanceStreamMarkerINTEL: ProcCmdSetPerformanceStreamMarkerINTEL +CmdSetPrimitiveRestartEnable: ProcCmdSetPrimitiveRestartEnable CmdSetPrimitiveRestartEnableEXT: ProcCmdSetPrimitiveRestartEnableEXT +CmdSetPrimitiveTopology: ProcCmdSetPrimitiveTopology CmdSetPrimitiveTopologyEXT: ProcCmdSetPrimitiveTopologyEXT +CmdSetRasterizerDiscardEnable: ProcCmdSetRasterizerDiscardEnable CmdSetRasterizerDiscardEnableEXT: ProcCmdSetRasterizerDiscardEnableEXT CmdSetRayTracingPipelineStackSizeKHR: ProcCmdSetRayTracingPipelineStackSizeKHR CmdSetSampleLocationsEXT: ProcCmdSetSampleLocationsEXT CmdSetScissor: ProcCmdSetScissor +CmdSetScissorWithCount: ProcCmdSetScissorWithCount CmdSetScissorWithCountEXT: ProcCmdSetScissorWithCountEXT CmdSetStencilCompareMask: ProcCmdSetStencilCompareMask +CmdSetStencilOp: ProcCmdSetStencilOp CmdSetStencilOpEXT: ProcCmdSetStencilOpEXT CmdSetStencilReference: ProcCmdSetStencilReference +CmdSetStencilTestEnable: ProcCmdSetStencilTestEnable CmdSetStencilTestEnableEXT: ProcCmdSetStencilTestEnableEXT CmdSetStencilWriteMask: ProcCmdSetStencilWriteMask CmdSetVertexInputEXT: ProcCmdSetVertexInputEXT CmdSetViewport: ProcCmdSetViewport CmdSetViewportShadingRatePaletteNV: ProcCmdSetViewportShadingRatePaletteNV CmdSetViewportWScalingNV: ProcCmdSetViewportWScalingNV +CmdSetViewportWithCount: ProcCmdSetViewportWithCount CmdSetViewportWithCountEXT: ProcCmdSetViewportWithCountEXT CmdSubpassShadingHUAWEI: ProcCmdSubpassShadingHUAWEI CmdTraceRaysIndirectKHR: ProcCmdTraceRaysIndirectKHR @@ -730,12 +803,14 @@ CmdTraceRaysKHR: ProcCmdTraceRaysKHR CmdTraceRaysNV: ProcCmdTraceRaysNV CmdUpdateBuffer: ProcCmdUpdateBuffer CmdWaitEvents: ProcCmdWaitEvents +CmdWaitEvents2: ProcCmdWaitEvents2 CmdWaitEvents2KHR: ProcCmdWaitEvents2KHR CmdWriteAccelerationStructuresPropertiesKHR: ProcCmdWriteAccelerationStructuresPropertiesKHR CmdWriteAccelerationStructuresPropertiesNV: ProcCmdWriteAccelerationStructuresPropertiesNV CmdWriteBufferMarker2AMD: ProcCmdWriteBufferMarker2AMD CmdWriteBufferMarkerAMD: ProcCmdWriteBufferMarkerAMD CmdWriteTimestamp: ProcCmdWriteTimestamp +CmdWriteTimestamp2: ProcCmdWriteTimestamp2 CmdWriteTimestamp2KHR: ProcCmdWriteTimestamp2KHR CompileDeferredNV: ProcCompileDeferredNV CopyAccelerationStructureKHR: ProcCopyAccelerationStructureKHR @@ -763,6 +838,7 @@ CreateImageView: ProcCreateImageView CreateIndirectCommandsLayoutNV: ProcCreateIndirectCommandsLayoutNV CreatePipelineCache: ProcCreatePipelineCache CreatePipelineLayout: ProcCreatePipelineLayout +CreatePrivateDataSlot: ProcCreatePrivateDataSlot CreatePrivateDataSlotEXT: ProcCreatePrivateDataSlotEXT CreateQueryPool: ProcCreateQueryPool CreateRayTracingPipelinesKHR: ProcCreateRayTracingPipelinesKHR @@ -803,6 +879,7 @@ DestroyIndirectCommandsLayoutNV: ProcDestroyIndirectCommandsLayo DestroyPipeline: ProcDestroyPipeline DestroyPipelineCache: ProcDestroyPipelineCache DestroyPipelineLayout: ProcDestroyPipelineLayout +DestroyPrivateDataSlot: ProcDestroyPrivateDataSlot DestroyPrivateDataSlotEXT: ProcDestroyPrivateDataSlotEXT DestroyQueryPool: ProcDestroyQueryPool DestroyRenderPass: ProcDestroyRenderPass @@ -835,14 +912,22 @@ GetBufferOpaqueCaptureAddressKHR: ProcGetBufferOpaqueCaptureAddre GetCalibratedTimestampsEXT: ProcGetCalibratedTimestampsEXT GetDeferredOperationMaxConcurrencyKHR: ProcGetDeferredOperationMaxConcurrencyKHR GetDeferredOperationResultKHR: ProcGetDeferredOperationResultKHR +GetDescriptorSetHostMappingVALVE: ProcGetDescriptorSetHostMappingVALVE +GetDescriptorSetLayoutHostMappingInfoVALVE: ProcGetDescriptorSetLayoutHostMappingInfoVALVE GetDescriptorSetLayoutSupport: ProcGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupportKHR: ProcGetDescriptorSetLayoutSupportKHR GetDeviceAccelerationStructureCompatibilityKHR: ProcGetDeviceAccelerationStructureCompatibilityKHR +GetDeviceBufferMemoryRequirements: ProcGetDeviceBufferMemoryRequirements +GetDeviceBufferMemoryRequirementsKHR: ProcGetDeviceBufferMemoryRequirementsKHR GetDeviceGroupPeerMemoryFeatures: ProcGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeaturesKHR: ProcGetDeviceGroupPeerMemoryFeaturesKHR GetDeviceGroupPresentCapabilitiesKHR: ProcGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupSurfacePresentModes2EXT: ProcGetDeviceGroupSurfacePresentModes2EXT GetDeviceGroupSurfacePresentModesKHR: ProcGetDeviceGroupSurfacePresentModesKHR +GetDeviceImageMemoryRequirements: ProcGetDeviceImageMemoryRequirements +GetDeviceImageMemoryRequirementsKHR: ProcGetDeviceImageMemoryRequirementsKHR +GetDeviceImageSparseMemoryRequirements: ProcGetDeviceImageSparseMemoryRequirements +GetDeviceImageSparseMemoryRequirementsKHR: ProcGetDeviceImageSparseMemoryRequirementsKHR GetDeviceMemoryCommitment: ProcGetDeviceMemoryCommitment GetDeviceMemoryOpaqueCaptureAddress: ProcGetDeviceMemoryOpaqueCaptureAddress GetDeviceMemoryOpaqueCaptureAddressKHR: ProcGetDeviceMemoryOpaqueCaptureAddressKHR @@ -878,6 +963,7 @@ GetPipelineCacheData: ProcGetPipelineCacheData GetPipelineExecutableInternalRepresentationsKHR: ProcGetPipelineExecutableInternalRepresentationsKHR GetPipelineExecutablePropertiesKHR: ProcGetPipelineExecutablePropertiesKHR GetPipelineExecutableStatisticsKHR: ProcGetPipelineExecutableStatisticsKHR +GetPrivateData: ProcGetPrivateData GetPrivateDataEXT: ProcGetPrivateDataEXT GetQueryPoolResults: ProcGetQueryPoolResults GetQueueCheckpointData2NV: ProcGetQueueCheckpointData2NV @@ -913,6 +999,7 @@ QueueInsertDebugUtilsLabelEXT: ProcQueueInsertDebugUtilsLabelE QueuePresentKHR: ProcQueuePresentKHR QueueSetPerformanceConfigurationINTEL: ProcQueueSetPerformanceConfigurationINTEL QueueSubmit: ProcQueueSubmit +QueueSubmit2: ProcQueueSubmit2 QueueSubmit2KHR: ProcQueueSubmit2KHR QueueWaitIdle: ProcQueueWaitIdle RegisterDeviceEventEXT: ProcRegisterDeviceEventEXT @@ -933,6 +1020,7 @@ SetDeviceMemoryPriorityEXT: ProcSetDeviceMemoryPriorityEXT SetEvent: ProcSetEvent SetHdrMetadataEXT: ProcSetHdrMetadataEXT SetLocalDimmingAMD: ProcSetLocalDimmingAMD +SetPrivateData: ProcSetPrivateData SetPrivateDataEXT: ProcSetPrivateDataEXT SignalSemaphore: ProcSignalSemaphore SignalSemaphoreKHR: ProcSignalSemaphoreKHR @@ -1036,6 +1124,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&GetPhysicalDeviceSurfacePresentModes2EXT, "vkGetPhysicalDeviceSurfacePresentModes2EXT") set_proc_address(&GetPhysicalDeviceSurfacePresentModesKHR, "vkGetPhysicalDeviceSurfacePresentModesKHR") set_proc_address(&GetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR") + set_proc_address(&GetPhysicalDeviceToolProperties, "vkGetPhysicalDeviceToolProperties") set_proc_address(&GetPhysicalDeviceToolPropertiesEXT, "vkGetPhysicalDeviceToolPropertiesEXT") set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR") set_proc_address(&GetWinrtDisplayNV, "vkGetWinrtDisplayNV") @@ -1067,6 +1156,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CmdBeginRenderPass, "vkCmdBeginRenderPass") set_proc_address(&CmdBeginRenderPass2, "vkCmdBeginRenderPass2") set_proc_address(&CmdBeginRenderPass2KHR, "vkCmdBeginRenderPass2KHR") + set_proc_address(&CmdBeginRendering, "vkCmdBeginRendering") + set_proc_address(&CmdBeginRenderingKHR, "vkCmdBeginRenderingKHR") set_proc_address(&CmdBeginTransformFeedbackEXT, "vkCmdBeginTransformFeedbackEXT") set_proc_address(&CmdBindDescriptorSets, "vkCmdBindDescriptorSets") set_proc_address(&CmdBindIndexBuffer, "vkCmdBindIndexBuffer") @@ -1076,8 +1167,10 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CmdBindShadingRateImageNV, "vkCmdBindShadingRateImageNV") set_proc_address(&CmdBindTransformFeedbackBuffersEXT, "vkCmdBindTransformFeedbackBuffersEXT") set_proc_address(&CmdBindVertexBuffers, "vkCmdBindVertexBuffers") + set_proc_address(&CmdBindVertexBuffers2, "vkCmdBindVertexBuffers2") set_proc_address(&CmdBindVertexBuffers2EXT, "vkCmdBindVertexBuffers2EXT") set_proc_address(&CmdBlitImage, "vkCmdBlitImage") + set_proc_address(&CmdBlitImage2, "vkCmdBlitImage2") set_proc_address(&CmdBlitImage2KHR, "vkCmdBlitImage2KHR") set_proc_address(&CmdBuildAccelerationStructureNV, "vkCmdBuildAccelerationStructureNV") set_proc_address(&CmdBuildAccelerationStructuresIndirectKHR, "vkCmdBuildAccelerationStructuresIndirectKHR") @@ -1089,12 +1182,16 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CmdCopyAccelerationStructureNV, "vkCmdCopyAccelerationStructureNV") set_proc_address(&CmdCopyAccelerationStructureToMemoryKHR, "vkCmdCopyAccelerationStructureToMemoryKHR") set_proc_address(&CmdCopyBuffer, "vkCmdCopyBuffer") + set_proc_address(&CmdCopyBuffer2, "vkCmdCopyBuffer2") set_proc_address(&CmdCopyBuffer2KHR, "vkCmdCopyBuffer2KHR") set_proc_address(&CmdCopyBufferToImage, "vkCmdCopyBufferToImage") + set_proc_address(&CmdCopyBufferToImage2, "vkCmdCopyBufferToImage2") set_proc_address(&CmdCopyBufferToImage2KHR, "vkCmdCopyBufferToImage2KHR") set_proc_address(&CmdCopyImage, "vkCmdCopyImage") + set_proc_address(&CmdCopyImage2, "vkCmdCopyImage2") set_proc_address(&CmdCopyImage2KHR, "vkCmdCopyImage2KHR") set_proc_address(&CmdCopyImageToBuffer, "vkCmdCopyImageToBuffer") + set_proc_address(&CmdCopyImageToBuffer2, "vkCmdCopyImageToBuffer2") set_proc_address(&CmdCopyImageToBuffer2KHR, "vkCmdCopyImageToBuffer2KHR") set_proc_address(&CmdCopyMemoryToAccelerationStructureKHR, "vkCmdCopyMemoryToAccelerationStructureKHR") set_proc_address(&CmdCopyQueryPoolResults, "vkCmdCopyQueryPoolResults") @@ -1129,6 +1226,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CmdEndRenderPass, "vkCmdEndRenderPass") set_proc_address(&CmdEndRenderPass2, "vkCmdEndRenderPass2") set_proc_address(&CmdEndRenderPass2KHR, "vkCmdEndRenderPass2KHR") + set_proc_address(&CmdEndRendering, "vkCmdEndRendering") + set_proc_address(&CmdEndRenderingKHR, "vkCmdEndRenderingKHR") set_proc_address(&CmdEndTransformFeedbackEXT, "vkCmdEndTransformFeedbackEXT") set_proc_address(&CmdExecuteCommands, "vkCmdExecuteCommands") set_proc_address(&CmdExecuteGeneratedCommandsNV, "vkCmdExecuteGeneratedCommandsNV") @@ -1138,35 +1237,46 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CmdNextSubpass2, "vkCmdNextSubpass2") set_proc_address(&CmdNextSubpass2KHR, "vkCmdNextSubpass2KHR") set_proc_address(&CmdPipelineBarrier, "vkCmdPipelineBarrier") + set_proc_address(&CmdPipelineBarrier2, "vkCmdPipelineBarrier2") set_proc_address(&CmdPipelineBarrier2KHR, "vkCmdPipelineBarrier2KHR") set_proc_address(&CmdPreprocessGeneratedCommandsNV, "vkCmdPreprocessGeneratedCommandsNV") set_proc_address(&CmdPushConstants, "vkCmdPushConstants") set_proc_address(&CmdPushDescriptorSetKHR, "vkCmdPushDescriptorSetKHR") set_proc_address(&CmdPushDescriptorSetWithTemplateKHR, "vkCmdPushDescriptorSetWithTemplateKHR") set_proc_address(&CmdResetEvent, "vkCmdResetEvent") + set_proc_address(&CmdResetEvent2, "vkCmdResetEvent2") set_proc_address(&CmdResetEvent2KHR, "vkCmdResetEvent2KHR") set_proc_address(&CmdResetQueryPool, "vkCmdResetQueryPool") set_proc_address(&CmdResolveImage, "vkCmdResolveImage") + set_proc_address(&CmdResolveImage2, "vkCmdResolveImage2") set_proc_address(&CmdResolveImage2KHR, "vkCmdResolveImage2KHR") set_proc_address(&CmdSetBlendConstants, "vkCmdSetBlendConstants") set_proc_address(&CmdSetCheckpointNV, "vkCmdSetCheckpointNV") set_proc_address(&CmdSetCoarseSampleOrderNV, "vkCmdSetCoarseSampleOrderNV") + set_proc_address(&CmdSetCullMode, "vkCmdSetCullMode") set_proc_address(&CmdSetCullModeEXT, "vkCmdSetCullModeEXT") set_proc_address(&CmdSetDepthBias, "vkCmdSetDepthBias") + set_proc_address(&CmdSetDepthBiasEnable, "vkCmdSetDepthBiasEnable") set_proc_address(&CmdSetDepthBiasEnableEXT, "vkCmdSetDepthBiasEnableEXT") set_proc_address(&CmdSetDepthBounds, "vkCmdSetDepthBounds") + set_proc_address(&CmdSetDepthBoundsTestEnable, "vkCmdSetDepthBoundsTestEnable") set_proc_address(&CmdSetDepthBoundsTestEnableEXT, "vkCmdSetDepthBoundsTestEnableEXT") + set_proc_address(&CmdSetDepthCompareOp, "vkCmdSetDepthCompareOp") set_proc_address(&CmdSetDepthCompareOpEXT, "vkCmdSetDepthCompareOpEXT") + set_proc_address(&CmdSetDepthTestEnable, "vkCmdSetDepthTestEnable") set_proc_address(&CmdSetDepthTestEnableEXT, "vkCmdSetDepthTestEnableEXT") + set_proc_address(&CmdSetDepthWriteEnable, "vkCmdSetDepthWriteEnable") set_proc_address(&CmdSetDepthWriteEnableEXT, "vkCmdSetDepthWriteEnableEXT") set_proc_address(&CmdSetDeviceMask, "vkCmdSetDeviceMask") set_proc_address(&CmdSetDeviceMaskKHR, "vkCmdSetDeviceMaskKHR") set_proc_address(&CmdSetDiscardRectangleEXT, "vkCmdSetDiscardRectangleEXT") set_proc_address(&CmdSetEvent, "vkCmdSetEvent") + set_proc_address(&CmdSetEvent2, "vkCmdSetEvent2") set_proc_address(&CmdSetEvent2KHR, "vkCmdSetEvent2KHR") set_proc_address(&CmdSetExclusiveScissorNV, "vkCmdSetExclusiveScissorNV") set_proc_address(&CmdSetFragmentShadingRateEnumNV, "vkCmdSetFragmentShadingRateEnumNV") set_proc_address(&CmdSetFragmentShadingRateKHR, "vkCmdSetFragmentShadingRateKHR") + set_proc_address(&CmdSetFrontFace, "vkCmdSetFrontFace") set_proc_address(&CmdSetFrontFaceEXT, "vkCmdSetFrontFaceEXT") set_proc_address(&CmdSetLineStippleEXT, "vkCmdSetLineStippleEXT") set_proc_address(&CmdSetLineWidth, "vkCmdSetLineWidth") @@ -1175,22 +1285,29 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CmdSetPerformanceMarkerINTEL, "vkCmdSetPerformanceMarkerINTEL") set_proc_address(&CmdSetPerformanceOverrideINTEL, "vkCmdSetPerformanceOverrideINTEL") set_proc_address(&CmdSetPerformanceStreamMarkerINTEL, "vkCmdSetPerformanceStreamMarkerINTEL") + set_proc_address(&CmdSetPrimitiveRestartEnable, "vkCmdSetPrimitiveRestartEnable") set_proc_address(&CmdSetPrimitiveRestartEnableEXT, "vkCmdSetPrimitiveRestartEnableEXT") + set_proc_address(&CmdSetPrimitiveTopology, "vkCmdSetPrimitiveTopology") set_proc_address(&CmdSetPrimitiveTopologyEXT, "vkCmdSetPrimitiveTopologyEXT") + set_proc_address(&CmdSetRasterizerDiscardEnable, "vkCmdSetRasterizerDiscardEnable") set_proc_address(&CmdSetRasterizerDiscardEnableEXT, "vkCmdSetRasterizerDiscardEnableEXT") set_proc_address(&CmdSetRayTracingPipelineStackSizeKHR, "vkCmdSetRayTracingPipelineStackSizeKHR") set_proc_address(&CmdSetSampleLocationsEXT, "vkCmdSetSampleLocationsEXT") set_proc_address(&CmdSetScissor, "vkCmdSetScissor") + set_proc_address(&CmdSetScissorWithCount, "vkCmdSetScissorWithCount") set_proc_address(&CmdSetScissorWithCountEXT, "vkCmdSetScissorWithCountEXT") set_proc_address(&CmdSetStencilCompareMask, "vkCmdSetStencilCompareMask") + set_proc_address(&CmdSetStencilOp, "vkCmdSetStencilOp") set_proc_address(&CmdSetStencilOpEXT, "vkCmdSetStencilOpEXT") set_proc_address(&CmdSetStencilReference, "vkCmdSetStencilReference") + set_proc_address(&CmdSetStencilTestEnable, "vkCmdSetStencilTestEnable") set_proc_address(&CmdSetStencilTestEnableEXT, "vkCmdSetStencilTestEnableEXT") set_proc_address(&CmdSetStencilWriteMask, "vkCmdSetStencilWriteMask") set_proc_address(&CmdSetVertexInputEXT, "vkCmdSetVertexInputEXT") set_proc_address(&CmdSetViewport, "vkCmdSetViewport") set_proc_address(&CmdSetViewportShadingRatePaletteNV, "vkCmdSetViewportShadingRatePaletteNV") set_proc_address(&CmdSetViewportWScalingNV, "vkCmdSetViewportWScalingNV") + set_proc_address(&CmdSetViewportWithCount, "vkCmdSetViewportWithCount") set_proc_address(&CmdSetViewportWithCountEXT, "vkCmdSetViewportWithCountEXT") set_proc_address(&CmdSubpassShadingHUAWEI, "vkCmdSubpassShadingHUAWEI") set_proc_address(&CmdTraceRaysIndirectKHR, "vkCmdTraceRaysIndirectKHR") @@ -1198,12 +1315,14 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CmdTraceRaysNV, "vkCmdTraceRaysNV") set_proc_address(&CmdUpdateBuffer, "vkCmdUpdateBuffer") set_proc_address(&CmdWaitEvents, "vkCmdWaitEvents") + set_proc_address(&CmdWaitEvents2, "vkCmdWaitEvents2") set_proc_address(&CmdWaitEvents2KHR, "vkCmdWaitEvents2KHR") set_proc_address(&CmdWriteAccelerationStructuresPropertiesKHR, "vkCmdWriteAccelerationStructuresPropertiesKHR") set_proc_address(&CmdWriteAccelerationStructuresPropertiesNV, "vkCmdWriteAccelerationStructuresPropertiesNV") set_proc_address(&CmdWriteBufferMarker2AMD, "vkCmdWriteBufferMarker2AMD") set_proc_address(&CmdWriteBufferMarkerAMD, "vkCmdWriteBufferMarkerAMD") set_proc_address(&CmdWriteTimestamp, "vkCmdWriteTimestamp") + set_proc_address(&CmdWriteTimestamp2, "vkCmdWriteTimestamp2") set_proc_address(&CmdWriteTimestamp2KHR, "vkCmdWriteTimestamp2KHR") set_proc_address(&CompileDeferredNV, "vkCompileDeferredNV") set_proc_address(&CopyAccelerationStructureKHR, "vkCopyAccelerationStructureKHR") @@ -1231,6 +1350,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CreateIndirectCommandsLayoutNV, "vkCreateIndirectCommandsLayoutNV") set_proc_address(&CreatePipelineCache, "vkCreatePipelineCache") set_proc_address(&CreatePipelineLayout, "vkCreatePipelineLayout") + set_proc_address(&CreatePrivateDataSlot, "vkCreatePrivateDataSlot") set_proc_address(&CreatePrivateDataSlotEXT, "vkCreatePrivateDataSlotEXT") set_proc_address(&CreateQueryPool, "vkCreateQueryPool") set_proc_address(&CreateRayTracingPipelinesKHR, "vkCreateRayTracingPipelinesKHR") @@ -1271,6 +1391,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&DestroyPipeline, "vkDestroyPipeline") set_proc_address(&DestroyPipelineCache, "vkDestroyPipelineCache") set_proc_address(&DestroyPipelineLayout, "vkDestroyPipelineLayout") + set_proc_address(&DestroyPrivateDataSlot, "vkDestroyPrivateDataSlot") set_proc_address(&DestroyPrivateDataSlotEXT, "vkDestroyPrivateDataSlotEXT") set_proc_address(&DestroyQueryPool, "vkDestroyQueryPool") set_proc_address(&DestroyRenderPass, "vkDestroyRenderPass") @@ -1303,14 +1424,22 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&GetCalibratedTimestampsEXT, "vkGetCalibratedTimestampsEXT") set_proc_address(&GetDeferredOperationMaxConcurrencyKHR, "vkGetDeferredOperationMaxConcurrencyKHR") set_proc_address(&GetDeferredOperationResultKHR, "vkGetDeferredOperationResultKHR") + set_proc_address(&GetDescriptorSetHostMappingVALVE, "vkGetDescriptorSetHostMappingVALVE") + set_proc_address(&GetDescriptorSetLayoutHostMappingInfoVALVE, "vkGetDescriptorSetLayoutHostMappingInfoVALVE") set_proc_address(&GetDescriptorSetLayoutSupport, "vkGetDescriptorSetLayoutSupport") set_proc_address(&GetDescriptorSetLayoutSupportKHR, "vkGetDescriptorSetLayoutSupportKHR") set_proc_address(&GetDeviceAccelerationStructureCompatibilityKHR, "vkGetDeviceAccelerationStructureCompatibilityKHR") + set_proc_address(&GetDeviceBufferMemoryRequirements, "vkGetDeviceBufferMemoryRequirements") + set_proc_address(&GetDeviceBufferMemoryRequirementsKHR, "vkGetDeviceBufferMemoryRequirementsKHR") set_proc_address(&GetDeviceGroupPeerMemoryFeatures, "vkGetDeviceGroupPeerMemoryFeatures") set_proc_address(&GetDeviceGroupPeerMemoryFeaturesKHR, "vkGetDeviceGroupPeerMemoryFeaturesKHR") set_proc_address(&GetDeviceGroupPresentCapabilitiesKHR, "vkGetDeviceGroupPresentCapabilitiesKHR") set_proc_address(&GetDeviceGroupSurfacePresentModes2EXT, "vkGetDeviceGroupSurfacePresentModes2EXT") set_proc_address(&GetDeviceGroupSurfacePresentModesKHR, "vkGetDeviceGroupSurfacePresentModesKHR") + set_proc_address(&GetDeviceImageMemoryRequirements, "vkGetDeviceImageMemoryRequirements") + set_proc_address(&GetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR") + set_proc_address(&GetDeviceImageSparseMemoryRequirements, "vkGetDeviceImageSparseMemoryRequirements") + set_proc_address(&GetDeviceImageSparseMemoryRequirementsKHR, "vkGetDeviceImageSparseMemoryRequirementsKHR") set_proc_address(&GetDeviceMemoryCommitment, "vkGetDeviceMemoryCommitment") set_proc_address(&GetDeviceMemoryOpaqueCaptureAddress, "vkGetDeviceMemoryOpaqueCaptureAddress") set_proc_address(&GetDeviceMemoryOpaqueCaptureAddressKHR, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") @@ -1346,6 +1475,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&GetPipelineExecutableInternalRepresentationsKHR, "vkGetPipelineExecutableInternalRepresentationsKHR") set_proc_address(&GetPipelineExecutablePropertiesKHR, "vkGetPipelineExecutablePropertiesKHR") set_proc_address(&GetPipelineExecutableStatisticsKHR, "vkGetPipelineExecutableStatisticsKHR") + set_proc_address(&GetPrivateData, "vkGetPrivateData") set_proc_address(&GetPrivateDataEXT, "vkGetPrivateDataEXT") set_proc_address(&GetQueryPoolResults, "vkGetQueryPoolResults") set_proc_address(&GetQueueCheckpointData2NV, "vkGetQueueCheckpointData2NV") @@ -1381,6 +1511,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&QueuePresentKHR, "vkQueuePresentKHR") set_proc_address(&QueueSetPerformanceConfigurationINTEL, "vkQueueSetPerformanceConfigurationINTEL") set_proc_address(&QueueSubmit, "vkQueueSubmit") + set_proc_address(&QueueSubmit2, "vkQueueSubmit2") set_proc_address(&QueueSubmit2KHR, "vkQueueSubmit2KHR") set_proc_address(&QueueWaitIdle, "vkQueueWaitIdle") set_proc_address(&RegisterDeviceEventEXT, "vkRegisterDeviceEventEXT") @@ -1401,6 +1532,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&SetEvent, "vkSetEvent") set_proc_address(&SetHdrMetadataEXT, "vkSetHdrMetadataEXT") set_proc_address(&SetLocalDimmingAMD, "vkSetLocalDimmingAMD") + set_proc_address(&SetPrivateData, "vkSetPrivateData") set_proc_address(&SetPrivateDataEXT, "vkSetPrivateDataEXT") set_proc_address(&SignalSemaphore, "vkSignalSemaphore") set_proc_address(&SignalSemaphoreKHR, "vkSignalSemaphoreKHR") @@ -1445,6 +1577,8 @@ Device_VTable :: struct { CmdBeginRenderPass: ProcCmdBeginRenderPass, CmdBeginRenderPass2: ProcCmdBeginRenderPass2, CmdBeginRenderPass2KHR: ProcCmdBeginRenderPass2KHR, + CmdBeginRendering: ProcCmdBeginRendering, + CmdBeginRenderingKHR: ProcCmdBeginRenderingKHR, CmdBeginTransformFeedbackEXT: ProcCmdBeginTransformFeedbackEXT, CmdBindDescriptorSets: ProcCmdBindDescriptorSets, CmdBindIndexBuffer: ProcCmdBindIndexBuffer, @@ -1454,8 +1588,10 @@ Device_VTable :: struct { CmdBindShadingRateImageNV: ProcCmdBindShadingRateImageNV, CmdBindTransformFeedbackBuffersEXT: ProcCmdBindTransformFeedbackBuffersEXT, CmdBindVertexBuffers: ProcCmdBindVertexBuffers, + CmdBindVertexBuffers2: ProcCmdBindVertexBuffers2, CmdBindVertexBuffers2EXT: ProcCmdBindVertexBuffers2EXT, CmdBlitImage: ProcCmdBlitImage, + CmdBlitImage2: ProcCmdBlitImage2, CmdBlitImage2KHR: ProcCmdBlitImage2KHR, CmdBuildAccelerationStructureNV: ProcCmdBuildAccelerationStructureNV, CmdBuildAccelerationStructuresIndirectKHR: ProcCmdBuildAccelerationStructuresIndirectKHR, @@ -1467,12 +1603,16 @@ Device_VTable :: struct { CmdCopyAccelerationStructureNV: ProcCmdCopyAccelerationStructureNV, CmdCopyAccelerationStructureToMemoryKHR: ProcCmdCopyAccelerationStructureToMemoryKHR, CmdCopyBuffer: ProcCmdCopyBuffer, + CmdCopyBuffer2: ProcCmdCopyBuffer2, CmdCopyBuffer2KHR: ProcCmdCopyBuffer2KHR, CmdCopyBufferToImage: ProcCmdCopyBufferToImage, + CmdCopyBufferToImage2: ProcCmdCopyBufferToImage2, CmdCopyBufferToImage2KHR: ProcCmdCopyBufferToImage2KHR, CmdCopyImage: ProcCmdCopyImage, + CmdCopyImage2: ProcCmdCopyImage2, CmdCopyImage2KHR: ProcCmdCopyImage2KHR, CmdCopyImageToBuffer: ProcCmdCopyImageToBuffer, + CmdCopyImageToBuffer2: ProcCmdCopyImageToBuffer2, CmdCopyImageToBuffer2KHR: ProcCmdCopyImageToBuffer2KHR, CmdCopyMemoryToAccelerationStructureKHR: ProcCmdCopyMemoryToAccelerationStructureKHR, CmdCopyQueryPoolResults: ProcCmdCopyQueryPoolResults, @@ -1507,6 +1647,8 @@ Device_VTable :: struct { CmdEndRenderPass: ProcCmdEndRenderPass, CmdEndRenderPass2: ProcCmdEndRenderPass2, CmdEndRenderPass2KHR: ProcCmdEndRenderPass2KHR, + CmdEndRendering: ProcCmdEndRendering, + CmdEndRenderingKHR: ProcCmdEndRenderingKHR, CmdEndTransformFeedbackEXT: ProcCmdEndTransformFeedbackEXT, CmdExecuteCommands: ProcCmdExecuteCommands, CmdExecuteGeneratedCommandsNV: ProcCmdExecuteGeneratedCommandsNV, @@ -1516,35 +1658,46 @@ Device_VTable :: struct { CmdNextSubpass2: ProcCmdNextSubpass2, CmdNextSubpass2KHR: ProcCmdNextSubpass2KHR, CmdPipelineBarrier: ProcCmdPipelineBarrier, + CmdPipelineBarrier2: ProcCmdPipelineBarrier2, CmdPipelineBarrier2KHR: ProcCmdPipelineBarrier2KHR, CmdPreprocessGeneratedCommandsNV: ProcCmdPreprocessGeneratedCommandsNV, CmdPushConstants: ProcCmdPushConstants, CmdPushDescriptorSetKHR: ProcCmdPushDescriptorSetKHR, CmdPushDescriptorSetWithTemplateKHR: ProcCmdPushDescriptorSetWithTemplateKHR, CmdResetEvent: ProcCmdResetEvent, + CmdResetEvent2: ProcCmdResetEvent2, CmdResetEvent2KHR: ProcCmdResetEvent2KHR, CmdResetQueryPool: ProcCmdResetQueryPool, CmdResolveImage: ProcCmdResolveImage, + CmdResolveImage2: ProcCmdResolveImage2, CmdResolveImage2KHR: ProcCmdResolveImage2KHR, CmdSetBlendConstants: ProcCmdSetBlendConstants, CmdSetCheckpointNV: ProcCmdSetCheckpointNV, CmdSetCoarseSampleOrderNV: ProcCmdSetCoarseSampleOrderNV, + CmdSetCullMode: ProcCmdSetCullMode, CmdSetCullModeEXT: ProcCmdSetCullModeEXT, CmdSetDepthBias: ProcCmdSetDepthBias, + CmdSetDepthBiasEnable: ProcCmdSetDepthBiasEnable, CmdSetDepthBiasEnableEXT: ProcCmdSetDepthBiasEnableEXT, CmdSetDepthBounds: ProcCmdSetDepthBounds, + CmdSetDepthBoundsTestEnable: ProcCmdSetDepthBoundsTestEnable, CmdSetDepthBoundsTestEnableEXT: ProcCmdSetDepthBoundsTestEnableEXT, + CmdSetDepthCompareOp: ProcCmdSetDepthCompareOp, CmdSetDepthCompareOpEXT: ProcCmdSetDepthCompareOpEXT, + CmdSetDepthTestEnable: ProcCmdSetDepthTestEnable, CmdSetDepthTestEnableEXT: ProcCmdSetDepthTestEnableEXT, + CmdSetDepthWriteEnable: ProcCmdSetDepthWriteEnable, CmdSetDepthWriteEnableEXT: ProcCmdSetDepthWriteEnableEXT, CmdSetDeviceMask: ProcCmdSetDeviceMask, CmdSetDeviceMaskKHR: ProcCmdSetDeviceMaskKHR, CmdSetDiscardRectangleEXT: ProcCmdSetDiscardRectangleEXT, CmdSetEvent: ProcCmdSetEvent, + CmdSetEvent2: ProcCmdSetEvent2, CmdSetEvent2KHR: ProcCmdSetEvent2KHR, CmdSetExclusiveScissorNV: ProcCmdSetExclusiveScissorNV, CmdSetFragmentShadingRateEnumNV: ProcCmdSetFragmentShadingRateEnumNV, CmdSetFragmentShadingRateKHR: ProcCmdSetFragmentShadingRateKHR, + CmdSetFrontFace: ProcCmdSetFrontFace, CmdSetFrontFaceEXT: ProcCmdSetFrontFaceEXT, CmdSetLineStippleEXT: ProcCmdSetLineStippleEXT, CmdSetLineWidth: ProcCmdSetLineWidth, @@ -1553,22 +1706,29 @@ Device_VTable :: struct { CmdSetPerformanceMarkerINTEL: ProcCmdSetPerformanceMarkerINTEL, CmdSetPerformanceOverrideINTEL: ProcCmdSetPerformanceOverrideINTEL, CmdSetPerformanceStreamMarkerINTEL: ProcCmdSetPerformanceStreamMarkerINTEL, + CmdSetPrimitiveRestartEnable: ProcCmdSetPrimitiveRestartEnable, CmdSetPrimitiveRestartEnableEXT: ProcCmdSetPrimitiveRestartEnableEXT, + CmdSetPrimitiveTopology: ProcCmdSetPrimitiveTopology, CmdSetPrimitiveTopologyEXT: ProcCmdSetPrimitiveTopologyEXT, + CmdSetRasterizerDiscardEnable: ProcCmdSetRasterizerDiscardEnable, CmdSetRasterizerDiscardEnableEXT: ProcCmdSetRasterizerDiscardEnableEXT, CmdSetRayTracingPipelineStackSizeKHR: ProcCmdSetRayTracingPipelineStackSizeKHR, CmdSetSampleLocationsEXT: ProcCmdSetSampleLocationsEXT, CmdSetScissor: ProcCmdSetScissor, + CmdSetScissorWithCount: ProcCmdSetScissorWithCount, CmdSetScissorWithCountEXT: ProcCmdSetScissorWithCountEXT, CmdSetStencilCompareMask: ProcCmdSetStencilCompareMask, + CmdSetStencilOp: ProcCmdSetStencilOp, CmdSetStencilOpEXT: ProcCmdSetStencilOpEXT, CmdSetStencilReference: ProcCmdSetStencilReference, + CmdSetStencilTestEnable: ProcCmdSetStencilTestEnable, CmdSetStencilTestEnableEXT: ProcCmdSetStencilTestEnableEXT, CmdSetStencilWriteMask: ProcCmdSetStencilWriteMask, CmdSetVertexInputEXT: ProcCmdSetVertexInputEXT, CmdSetViewport: ProcCmdSetViewport, CmdSetViewportShadingRatePaletteNV: ProcCmdSetViewportShadingRatePaletteNV, CmdSetViewportWScalingNV: ProcCmdSetViewportWScalingNV, + CmdSetViewportWithCount: ProcCmdSetViewportWithCount, CmdSetViewportWithCountEXT: ProcCmdSetViewportWithCountEXT, CmdSubpassShadingHUAWEI: ProcCmdSubpassShadingHUAWEI, CmdTraceRaysIndirectKHR: ProcCmdTraceRaysIndirectKHR, @@ -1576,12 +1736,14 @@ Device_VTable :: struct { CmdTraceRaysNV: ProcCmdTraceRaysNV, CmdUpdateBuffer: ProcCmdUpdateBuffer, CmdWaitEvents: ProcCmdWaitEvents, + CmdWaitEvents2: ProcCmdWaitEvents2, CmdWaitEvents2KHR: ProcCmdWaitEvents2KHR, CmdWriteAccelerationStructuresPropertiesKHR: ProcCmdWriteAccelerationStructuresPropertiesKHR, CmdWriteAccelerationStructuresPropertiesNV: ProcCmdWriteAccelerationStructuresPropertiesNV, CmdWriteBufferMarker2AMD: ProcCmdWriteBufferMarker2AMD, CmdWriteBufferMarkerAMD: ProcCmdWriteBufferMarkerAMD, CmdWriteTimestamp: ProcCmdWriteTimestamp, + CmdWriteTimestamp2: ProcCmdWriteTimestamp2, CmdWriteTimestamp2KHR: ProcCmdWriteTimestamp2KHR, CompileDeferredNV: ProcCompileDeferredNV, CopyAccelerationStructureKHR: ProcCopyAccelerationStructureKHR, @@ -1609,6 +1771,7 @@ Device_VTable :: struct { CreateIndirectCommandsLayoutNV: ProcCreateIndirectCommandsLayoutNV, CreatePipelineCache: ProcCreatePipelineCache, CreatePipelineLayout: ProcCreatePipelineLayout, + CreatePrivateDataSlot: ProcCreatePrivateDataSlot, CreatePrivateDataSlotEXT: ProcCreatePrivateDataSlotEXT, CreateQueryPool: ProcCreateQueryPool, CreateRayTracingPipelinesKHR: ProcCreateRayTracingPipelinesKHR, @@ -1649,6 +1812,7 @@ Device_VTable :: struct { DestroyPipeline: ProcDestroyPipeline, DestroyPipelineCache: ProcDestroyPipelineCache, DestroyPipelineLayout: ProcDestroyPipelineLayout, + DestroyPrivateDataSlot: ProcDestroyPrivateDataSlot, DestroyPrivateDataSlotEXT: ProcDestroyPrivateDataSlotEXT, DestroyQueryPool: ProcDestroyQueryPool, DestroyRenderPass: ProcDestroyRenderPass, @@ -1681,14 +1845,22 @@ Device_VTable :: struct { GetCalibratedTimestampsEXT: ProcGetCalibratedTimestampsEXT, GetDeferredOperationMaxConcurrencyKHR: ProcGetDeferredOperationMaxConcurrencyKHR, GetDeferredOperationResultKHR: ProcGetDeferredOperationResultKHR, + GetDescriptorSetHostMappingVALVE: ProcGetDescriptorSetHostMappingVALVE, + GetDescriptorSetLayoutHostMappingInfoVALVE: ProcGetDescriptorSetLayoutHostMappingInfoVALVE, GetDescriptorSetLayoutSupport: ProcGetDescriptorSetLayoutSupport, GetDescriptorSetLayoutSupportKHR: ProcGetDescriptorSetLayoutSupportKHR, GetDeviceAccelerationStructureCompatibilityKHR: ProcGetDeviceAccelerationStructureCompatibilityKHR, + GetDeviceBufferMemoryRequirements: ProcGetDeviceBufferMemoryRequirements, + GetDeviceBufferMemoryRequirementsKHR: ProcGetDeviceBufferMemoryRequirementsKHR, GetDeviceGroupPeerMemoryFeatures: ProcGetDeviceGroupPeerMemoryFeatures, GetDeviceGroupPeerMemoryFeaturesKHR: ProcGetDeviceGroupPeerMemoryFeaturesKHR, GetDeviceGroupPresentCapabilitiesKHR: ProcGetDeviceGroupPresentCapabilitiesKHR, GetDeviceGroupSurfacePresentModes2EXT: ProcGetDeviceGroupSurfacePresentModes2EXT, GetDeviceGroupSurfacePresentModesKHR: ProcGetDeviceGroupSurfacePresentModesKHR, + GetDeviceImageMemoryRequirements: ProcGetDeviceImageMemoryRequirements, + GetDeviceImageMemoryRequirementsKHR: ProcGetDeviceImageMemoryRequirementsKHR, + GetDeviceImageSparseMemoryRequirements: ProcGetDeviceImageSparseMemoryRequirements, + GetDeviceImageSparseMemoryRequirementsKHR: ProcGetDeviceImageSparseMemoryRequirementsKHR, GetDeviceMemoryCommitment: ProcGetDeviceMemoryCommitment, GetDeviceMemoryOpaqueCaptureAddress: ProcGetDeviceMemoryOpaqueCaptureAddress, GetDeviceMemoryOpaqueCaptureAddressKHR: ProcGetDeviceMemoryOpaqueCaptureAddressKHR, @@ -1724,6 +1896,7 @@ Device_VTable :: struct { GetPipelineExecutableInternalRepresentationsKHR: ProcGetPipelineExecutableInternalRepresentationsKHR, GetPipelineExecutablePropertiesKHR: ProcGetPipelineExecutablePropertiesKHR, GetPipelineExecutableStatisticsKHR: ProcGetPipelineExecutableStatisticsKHR, + GetPrivateData: ProcGetPrivateData, GetPrivateDataEXT: ProcGetPrivateDataEXT, GetQueryPoolResults: ProcGetQueryPoolResults, GetQueueCheckpointData2NV: ProcGetQueueCheckpointData2NV, @@ -1759,6 +1932,7 @@ Device_VTable :: struct { QueuePresentKHR: ProcQueuePresentKHR, QueueSetPerformanceConfigurationINTEL: ProcQueueSetPerformanceConfigurationINTEL, QueueSubmit: ProcQueueSubmit, + QueueSubmit2: ProcQueueSubmit2, QueueSubmit2KHR: ProcQueueSubmit2KHR, QueueWaitIdle: ProcQueueWaitIdle, RegisterDeviceEventEXT: ProcRegisterDeviceEventEXT, @@ -1779,6 +1953,7 @@ Device_VTable :: struct { SetEvent: ProcSetEvent, SetHdrMetadataEXT: ProcSetHdrMetadataEXT, SetLocalDimmingAMD: ProcSetLocalDimmingAMD, + SetPrivateData: ProcSetPrivateData, SetPrivateDataEXT: ProcSetPrivateDataEXT, SignalSemaphore: ProcSignalSemaphore, SignalSemaphoreKHR: ProcSignalSemaphoreKHR, @@ -1821,6 +1996,8 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CmdBeginRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass") vtable.CmdBeginRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2") vtable.CmdBeginRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2KHR") + vtable.CmdBeginRendering = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRendering") + vtable.CmdBeginRenderingKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderingKHR") vtable.CmdBeginTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginTransformFeedbackEXT") vtable.CmdBindDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkCmdBindDescriptorSets") vtable.CmdBindIndexBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdBindIndexBuffer") @@ -1830,8 +2007,10 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CmdBindShadingRateImageNV = auto_cast GetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV") vtable.CmdBindTransformFeedbackBuffersEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindTransformFeedbackBuffersEXT") vtable.CmdBindVertexBuffers = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers") + vtable.CmdBindVertexBuffers2 = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers2") vtable.CmdBindVertexBuffers2EXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers2EXT") vtable.CmdBlitImage = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage") + vtable.CmdBlitImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage2") vtable.CmdBlitImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage2KHR") vtable.CmdBuildAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV") vtable.CmdBuildAccelerationStructuresIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresIndirectKHR") @@ -1843,12 +2022,16 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CmdCopyAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureNV") vtable.CmdCopyAccelerationStructureToMemoryKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureToMemoryKHR") vtable.CmdCopyBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer") + vtable.CmdCopyBuffer2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer2") vtable.CmdCopyBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer2KHR") vtable.CmdCopyBufferToImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage") + vtable.CmdCopyBufferToImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage2") vtable.CmdCopyBufferToImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage2KHR") vtable.CmdCopyImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage") + vtable.CmdCopyImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage2") vtable.CmdCopyImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage2KHR") vtable.CmdCopyImageToBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer") + vtable.CmdCopyImageToBuffer2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer2") vtable.CmdCopyImageToBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer2KHR") vtable.CmdCopyMemoryToAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyMemoryToAccelerationStructureKHR") vtable.CmdCopyQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkCmdCopyQueryPoolResults") @@ -1883,6 +2066,8 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CmdEndRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass") vtable.CmdEndRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2") vtable.CmdEndRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2KHR") + vtable.CmdEndRendering = auto_cast GetDeviceProcAddr(device, "vkCmdEndRendering") + vtable.CmdEndRenderingKHR = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderingKHR") vtable.CmdEndTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndTransformFeedbackEXT") vtable.CmdExecuteCommands = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteCommands") vtable.CmdExecuteGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteGeneratedCommandsNV") @@ -1892,35 +2077,46 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CmdNextSubpass2 = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2") vtable.CmdNextSubpass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2KHR") vtable.CmdPipelineBarrier = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier") + vtable.CmdPipelineBarrier2 = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier2") vtable.CmdPipelineBarrier2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier2KHR") vtable.CmdPreprocessGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdPreprocessGeneratedCommandsNV") vtable.CmdPushConstants = auto_cast GetDeviceProcAddr(device, "vkCmdPushConstants") vtable.CmdPushDescriptorSetKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetKHR") vtable.CmdPushDescriptorSetWithTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetWithTemplateKHR") vtable.CmdResetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent") + vtable.CmdResetEvent2 = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent2") vtable.CmdResetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent2KHR") vtable.CmdResetQueryPool = auto_cast GetDeviceProcAddr(device, "vkCmdResetQueryPool") vtable.CmdResolveImage = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage") + vtable.CmdResolveImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage2") vtable.CmdResolveImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage2KHR") vtable.CmdSetBlendConstants = auto_cast GetDeviceProcAddr(device, "vkCmdSetBlendConstants") vtable.CmdSetCheckpointNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCheckpointNV") vtable.CmdSetCoarseSampleOrderNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCoarseSampleOrderNV") + vtable.CmdSetCullMode = auto_cast GetDeviceProcAddr(device, "vkCmdSetCullMode") vtable.CmdSetCullModeEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetCullModeEXT") vtable.CmdSetDepthBias = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBias") + vtable.CmdSetDepthBiasEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBiasEnable") vtable.CmdSetDepthBiasEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBiasEnableEXT") vtable.CmdSetDepthBounds = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBounds") + vtable.CmdSetDepthBoundsTestEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnable") vtable.CmdSetDepthBoundsTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnableEXT") + vtable.CmdSetDepthCompareOp = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthCompareOp") vtable.CmdSetDepthCompareOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthCompareOpEXT") + vtable.CmdSetDepthTestEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthTestEnable") vtable.CmdSetDepthTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthTestEnableEXT") + vtable.CmdSetDepthWriteEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthWriteEnable") vtable.CmdSetDepthWriteEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthWriteEnableEXT") vtable.CmdSetDeviceMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMask") vtable.CmdSetDeviceMaskKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMaskKHR") vtable.CmdSetDiscardRectangleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDiscardRectangleEXT") vtable.CmdSetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent") + vtable.CmdSetEvent2 = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent2") vtable.CmdSetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent2KHR") vtable.CmdSetExclusiveScissorNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetExclusiveScissorNV") vtable.CmdSetFragmentShadingRateEnumNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateEnumNV") vtable.CmdSetFragmentShadingRateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateKHR") + vtable.CmdSetFrontFace = auto_cast GetDeviceProcAddr(device, "vkCmdSetFrontFace") vtable.CmdSetFrontFaceEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetFrontFaceEXT") vtable.CmdSetLineStippleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineStippleEXT") vtable.CmdSetLineWidth = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineWidth") @@ -1929,22 +2125,29 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CmdSetPerformanceMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceMarkerINTEL") vtable.CmdSetPerformanceOverrideINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceOverrideINTEL") vtable.CmdSetPerformanceStreamMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceStreamMarkerINTEL") + vtable.CmdSetPrimitiveRestartEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveRestartEnable") vtable.CmdSetPrimitiveRestartEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveRestartEnableEXT") + vtable.CmdSetPrimitiveTopology = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveTopology") vtable.CmdSetPrimitiveTopologyEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveTopologyEXT") + vtable.CmdSetRasterizerDiscardEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetRasterizerDiscardEnable") vtable.CmdSetRasterizerDiscardEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetRasterizerDiscardEnableEXT") vtable.CmdSetRayTracingPipelineStackSizeKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetRayTracingPipelineStackSizeKHR") vtable.CmdSetSampleLocationsEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetSampleLocationsEXT") vtable.CmdSetScissor = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissor") + vtable.CmdSetScissorWithCount = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissorWithCount") vtable.CmdSetScissorWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissorWithCountEXT") vtable.CmdSetStencilCompareMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilCompareMask") + vtable.CmdSetStencilOp = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilOp") vtable.CmdSetStencilOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilOpEXT") vtable.CmdSetStencilReference = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilReference") + vtable.CmdSetStencilTestEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilTestEnable") vtable.CmdSetStencilTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT") vtable.CmdSetStencilWriteMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilWriteMask") vtable.CmdSetVertexInputEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetVertexInputEXT") vtable.CmdSetViewport = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewport") vtable.CmdSetViewportShadingRatePaletteNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportShadingRatePaletteNV") vtable.CmdSetViewportWScalingNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWScalingNV") + vtable.CmdSetViewportWithCount = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWithCount") vtable.CmdSetViewportWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT") vtable.CmdSubpassShadingHUAWEI = auto_cast GetDeviceProcAddr(device, "vkCmdSubpassShadingHUAWEI") vtable.CmdTraceRaysIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysIndirectKHR") @@ -1952,12 +2155,14 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CmdTraceRaysNV = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysNV") vtable.CmdUpdateBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdUpdateBuffer") vtable.CmdWaitEvents = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents") + vtable.CmdWaitEvents2 = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents2") vtable.CmdWaitEvents2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents2KHR") vtable.CmdWriteAccelerationStructuresPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesKHR") vtable.CmdWriteAccelerationStructuresPropertiesNV = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesNV") vtable.CmdWriteBufferMarker2AMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarker2AMD") vtable.CmdWriteBufferMarkerAMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarkerAMD") vtable.CmdWriteTimestamp = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp") + vtable.CmdWriteTimestamp2 = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp2") vtable.CmdWriteTimestamp2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp2KHR") vtable.CompileDeferredNV = auto_cast GetDeviceProcAddr(device, "vkCompileDeferredNV") vtable.CopyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCopyAccelerationStructureKHR") @@ -1985,6 +2190,7 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.CreateIndirectCommandsLayoutNV = auto_cast GetDeviceProcAddr(device, "vkCreateIndirectCommandsLayoutNV") vtable.CreatePipelineCache = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineCache") vtable.CreatePipelineLayout = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineLayout") + vtable.CreatePrivateDataSlot = auto_cast GetDeviceProcAddr(device, "vkCreatePrivateDataSlot") vtable.CreatePrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkCreatePrivateDataSlotEXT") vtable.CreateQueryPool = auto_cast GetDeviceProcAddr(device, "vkCreateQueryPool") vtable.CreateRayTracingPipelinesKHR = auto_cast GetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR") @@ -2025,6 +2231,7 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.DestroyPipeline = auto_cast GetDeviceProcAddr(device, "vkDestroyPipeline") vtable.DestroyPipelineCache = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineCache") vtable.DestroyPipelineLayout = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineLayout") + vtable.DestroyPrivateDataSlot = auto_cast GetDeviceProcAddr(device, "vkDestroyPrivateDataSlot") vtable.DestroyPrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkDestroyPrivateDataSlotEXT") vtable.DestroyQueryPool = auto_cast GetDeviceProcAddr(device, "vkDestroyQueryPool") vtable.DestroyRenderPass = auto_cast GetDeviceProcAddr(device, "vkDestroyRenderPass") @@ -2057,14 +2264,22 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.GetCalibratedTimestampsEXT = auto_cast GetDeviceProcAddr(device, "vkGetCalibratedTimestampsEXT") vtable.GetDeferredOperationMaxConcurrencyKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationMaxConcurrencyKHR") vtable.GetDeferredOperationResultKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationResultKHR") + vtable.GetDescriptorSetHostMappingVALVE = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetHostMappingVALVE") + vtable.GetDescriptorSetLayoutHostMappingInfoVALVE = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutHostMappingInfoVALVE") vtable.GetDescriptorSetLayoutSupport = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupport") vtable.GetDescriptorSetLayoutSupportKHR = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupportKHR") vtable.GetDeviceAccelerationStructureCompatibilityKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceAccelerationStructureCompatibilityKHR") + vtable.GetDeviceBufferMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetDeviceBufferMemoryRequirements") + vtable.GetDeviceBufferMemoryRequirementsKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceBufferMemoryRequirementsKHR") vtable.GetDeviceGroupPeerMemoryFeatures = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeatures") vtable.GetDeviceGroupPeerMemoryFeaturesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeaturesKHR") vtable.GetDeviceGroupPresentCapabilitiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPresentCapabilitiesKHR") vtable.GetDeviceGroupSurfacePresentModes2EXT = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModes2EXT") vtable.GetDeviceGroupSurfacePresentModesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModesKHR") + vtable.GetDeviceImageMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageMemoryRequirements") + vtable.GetDeviceImageMemoryRequirementsKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageMemoryRequirementsKHR") + vtable.GetDeviceImageSparseMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageSparseMemoryRequirements") + vtable.GetDeviceImageSparseMemoryRequirementsKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageSparseMemoryRequirementsKHR") vtable.GetDeviceMemoryCommitment = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryCommitment") vtable.GetDeviceMemoryOpaqueCaptureAddress = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddress") vtable.GetDeviceMemoryOpaqueCaptureAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") @@ -2100,6 +2315,7 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.GetPipelineExecutableInternalRepresentationsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableInternalRepresentationsKHR") vtable.GetPipelineExecutablePropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutablePropertiesKHR") vtable.GetPipelineExecutableStatisticsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableStatisticsKHR") + vtable.GetPrivateData = auto_cast GetDeviceProcAddr(device, "vkGetPrivateData") vtable.GetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkGetPrivateDataEXT") vtable.GetQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkGetQueryPoolResults") vtable.GetQueueCheckpointData2NV = auto_cast GetDeviceProcAddr(device, "vkGetQueueCheckpointData2NV") @@ -2135,6 +2351,7 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.QueuePresentKHR = auto_cast GetDeviceProcAddr(device, "vkQueuePresentKHR") vtable.QueueSetPerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkQueueSetPerformanceConfigurationINTEL") vtable.QueueSubmit = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit") + vtable.QueueSubmit2 = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit2") vtable.QueueSubmit2KHR = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit2KHR") vtable.QueueWaitIdle = auto_cast GetDeviceProcAddr(device, "vkQueueWaitIdle") vtable.RegisterDeviceEventEXT = auto_cast GetDeviceProcAddr(device, "vkRegisterDeviceEventEXT") @@ -2155,6 +2372,7 @@ load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable vtable.SetEvent = auto_cast GetDeviceProcAddr(device, "vkSetEvent") vtable.SetHdrMetadataEXT = auto_cast GetDeviceProcAddr(device, "vkSetHdrMetadataEXT") vtable.SetLocalDimmingAMD = auto_cast GetDeviceProcAddr(device, "vkSetLocalDimmingAMD") + vtable.SetPrivateData = auto_cast GetDeviceProcAddr(device, "vkSetPrivateData") vtable.SetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkSetPrivateDataEXT") vtable.SignalSemaphore = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphore") vtable.SignalSemaphoreKHR = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphoreKHR") @@ -2197,6 +2415,8 @@ load_proc_addresses_device :: proc(device: Device) { CmdBeginRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass") CmdBeginRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2") CmdBeginRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderPass2KHR") + CmdBeginRendering = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRendering") + CmdBeginRenderingKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBeginRenderingKHR") CmdBeginTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBeginTransformFeedbackEXT") CmdBindDescriptorSets = auto_cast GetDeviceProcAddr(device, "vkCmdBindDescriptorSets") CmdBindIndexBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdBindIndexBuffer") @@ -2206,8 +2426,10 @@ load_proc_addresses_device :: proc(device: Device) { CmdBindShadingRateImageNV = auto_cast GetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV") CmdBindTransformFeedbackBuffersEXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindTransformFeedbackBuffersEXT") CmdBindVertexBuffers = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers") + CmdBindVertexBuffers2 = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers2") CmdBindVertexBuffers2EXT = auto_cast GetDeviceProcAddr(device, "vkCmdBindVertexBuffers2EXT") CmdBlitImage = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage") + CmdBlitImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage2") CmdBlitImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdBlitImage2KHR") CmdBuildAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV") CmdBuildAccelerationStructuresIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresIndirectKHR") @@ -2219,12 +2441,16 @@ load_proc_addresses_device :: proc(device: Device) { CmdCopyAccelerationStructureNV = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureNV") CmdCopyAccelerationStructureToMemoryKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyAccelerationStructureToMemoryKHR") CmdCopyBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer") + CmdCopyBuffer2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer2") CmdCopyBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBuffer2KHR") CmdCopyBufferToImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage") + CmdCopyBufferToImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage2") CmdCopyBufferToImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyBufferToImage2KHR") CmdCopyImage = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage") + CmdCopyImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage2") CmdCopyImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImage2KHR") CmdCopyImageToBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer") + CmdCopyImageToBuffer2 = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer2") CmdCopyImageToBuffer2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyImageToBuffer2KHR") CmdCopyMemoryToAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCmdCopyMemoryToAccelerationStructureKHR") CmdCopyQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkCmdCopyQueryPoolResults") @@ -2259,6 +2485,8 @@ load_proc_addresses_device :: proc(device: Device) { CmdEndRenderPass = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass") CmdEndRenderPass2 = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2") CmdEndRenderPass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderPass2KHR") + CmdEndRendering = auto_cast GetDeviceProcAddr(device, "vkCmdEndRendering") + CmdEndRenderingKHR = auto_cast GetDeviceProcAddr(device, "vkCmdEndRenderingKHR") CmdEndTransformFeedbackEXT = auto_cast GetDeviceProcAddr(device, "vkCmdEndTransformFeedbackEXT") CmdExecuteCommands = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteCommands") CmdExecuteGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdExecuteGeneratedCommandsNV") @@ -2268,35 +2496,46 @@ load_proc_addresses_device :: proc(device: Device) { CmdNextSubpass2 = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2") CmdNextSubpass2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdNextSubpass2KHR") CmdPipelineBarrier = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier") + CmdPipelineBarrier2 = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier2") CmdPipelineBarrier2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdPipelineBarrier2KHR") CmdPreprocessGeneratedCommandsNV = auto_cast GetDeviceProcAddr(device, "vkCmdPreprocessGeneratedCommandsNV") CmdPushConstants = auto_cast GetDeviceProcAddr(device, "vkCmdPushConstants") CmdPushDescriptorSetKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetKHR") CmdPushDescriptorSetWithTemplateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdPushDescriptorSetWithTemplateKHR") CmdResetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent") + CmdResetEvent2 = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent2") CmdResetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResetEvent2KHR") CmdResetQueryPool = auto_cast GetDeviceProcAddr(device, "vkCmdResetQueryPool") CmdResolveImage = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage") + CmdResolveImage2 = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage2") CmdResolveImage2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdResolveImage2KHR") CmdSetBlendConstants = auto_cast GetDeviceProcAddr(device, "vkCmdSetBlendConstants") CmdSetCheckpointNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCheckpointNV") CmdSetCoarseSampleOrderNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetCoarseSampleOrderNV") + CmdSetCullMode = auto_cast GetDeviceProcAddr(device, "vkCmdSetCullMode") CmdSetCullModeEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetCullModeEXT") CmdSetDepthBias = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBias") + CmdSetDepthBiasEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBiasEnable") CmdSetDepthBiasEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBiasEnableEXT") CmdSetDepthBounds = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBounds") + CmdSetDepthBoundsTestEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnable") CmdSetDepthBoundsTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnableEXT") + CmdSetDepthCompareOp = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthCompareOp") CmdSetDepthCompareOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthCompareOpEXT") + CmdSetDepthTestEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthTestEnable") CmdSetDepthTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthTestEnableEXT") + CmdSetDepthWriteEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthWriteEnable") CmdSetDepthWriteEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDepthWriteEnableEXT") CmdSetDeviceMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMask") CmdSetDeviceMaskKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetDeviceMaskKHR") CmdSetDiscardRectangleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetDiscardRectangleEXT") CmdSetEvent = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent") + CmdSetEvent2 = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent2") CmdSetEvent2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetEvent2KHR") CmdSetExclusiveScissorNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetExclusiveScissorNV") CmdSetFragmentShadingRateEnumNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateEnumNV") CmdSetFragmentShadingRateKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetFragmentShadingRateKHR") + CmdSetFrontFace = auto_cast GetDeviceProcAddr(device, "vkCmdSetFrontFace") CmdSetFrontFaceEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetFrontFaceEXT") CmdSetLineStippleEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineStippleEXT") CmdSetLineWidth = auto_cast GetDeviceProcAddr(device, "vkCmdSetLineWidth") @@ -2305,22 +2544,29 @@ load_proc_addresses_device :: proc(device: Device) { CmdSetPerformanceMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceMarkerINTEL") CmdSetPerformanceOverrideINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceOverrideINTEL") CmdSetPerformanceStreamMarkerINTEL = auto_cast GetDeviceProcAddr(device, "vkCmdSetPerformanceStreamMarkerINTEL") + CmdSetPrimitiveRestartEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveRestartEnable") CmdSetPrimitiveRestartEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveRestartEnableEXT") + CmdSetPrimitiveTopology = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveTopology") CmdSetPrimitiveTopologyEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetPrimitiveTopologyEXT") + CmdSetRasterizerDiscardEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetRasterizerDiscardEnable") CmdSetRasterizerDiscardEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetRasterizerDiscardEnableEXT") CmdSetRayTracingPipelineStackSizeKHR = auto_cast GetDeviceProcAddr(device, "vkCmdSetRayTracingPipelineStackSizeKHR") CmdSetSampleLocationsEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetSampleLocationsEXT") CmdSetScissor = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissor") + CmdSetScissorWithCount = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissorWithCount") CmdSetScissorWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetScissorWithCountEXT") CmdSetStencilCompareMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilCompareMask") + CmdSetStencilOp = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilOp") CmdSetStencilOpEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilOpEXT") CmdSetStencilReference = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilReference") + CmdSetStencilTestEnable = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilTestEnable") CmdSetStencilTestEnableEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT") CmdSetStencilWriteMask = auto_cast GetDeviceProcAddr(device, "vkCmdSetStencilWriteMask") CmdSetVertexInputEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetVertexInputEXT") CmdSetViewport = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewport") CmdSetViewportShadingRatePaletteNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportShadingRatePaletteNV") CmdSetViewportWScalingNV = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWScalingNV") + CmdSetViewportWithCount = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWithCount") CmdSetViewportWithCountEXT = auto_cast GetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT") CmdSubpassShadingHUAWEI = auto_cast GetDeviceProcAddr(device, "vkCmdSubpassShadingHUAWEI") CmdTraceRaysIndirectKHR = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysIndirectKHR") @@ -2328,12 +2574,14 @@ load_proc_addresses_device :: proc(device: Device) { CmdTraceRaysNV = auto_cast GetDeviceProcAddr(device, "vkCmdTraceRaysNV") CmdUpdateBuffer = auto_cast GetDeviceProcAddr(device, "vkCmdUpdateBuffer") CmdWaitEvents = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents") + CmdWaitEvents2 = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents2") CmdWaitEvents2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWaitEvents2KHR") CmdWriteAccelerationStructuresPropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesKHR") CmdWriteAccelerationStructuresPropertiesNV = auto_cast GetDeviceProcAddr(device, "vkCmdWriteAccelerationStructuresPropertiesNV") CmdWriteBufferMarker2AMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarker2AMD") CmdWriteBufferMarkerAMD = auto_cast GetDeviceProcAddr(device, "vkCmdWriteBufferMarkerAMD") CmdWriteTimestamp = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp") + CmdWriteTimestamp2 = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp2") CmdWriteTimestamp2KHR = auto_cast GetDeviceProcAddr(device, "vkCmdWriteTimestamp2KHR") CompileDeferredNV = auto_cast GetDeviceProcAddr(device, "vkCompileDeferredNV") CopyAccelerationStructureKHR = auto_cast GetDeviceProcAddr(device, "vkCopyAccelerationStructureKHR") @@ -2361,6 +2609,7 @@ load_proc_addresses_device :: proc(device: Device) { CreateIndirectCommandsLayoutNV = auto_cast GetDeviceProcAddr(device, "vkCreateIndirectCommandsLayoutNV") CreatePipelineCache = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineCache") CreatePipelineLayout = auto_cast GetDeviceProcAddr(device, "vkCreatePipelineLayout") + CreatePrivateDataSlot = auto_cast GetDeviceProcAddr(device, "vkCreatePrivateDataSlot") CreatePrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkCreatePrivateDataSlotEXT") CreateQueryPool = auto_cast GetDeviceProcAddr(device, "vkCreateQueryPool") CreateRayTracingPipelinesKHR = auto_cast GetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR") @@ -2401,6 +2650,7 @@ load_proc_addresses_device :: proc(device: Device) { DestroyPipeline = auto_cast GetDeviceProcAddr(device, "vkDestroyPipeline") DestroyPipelineCache = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineCache") DestroyPipelineLayout = auto_cast GetDeviceProcAddr(device, "vkDestroyPipelineLayout") + DestroyPrivateDataSlot = auto_cast GetDeviceProcAddr(device, "vkDestroyPrivateDataSlot") DestroyPrivateDataSlotEXT = auto_cast GetDeviceProcAddr(device, "vkDestroyPrivateDataSlotEXT") DestroyQueryPool = auto_cast GetDeviceProcAddr(device, "vkDestroyQueryPool") DestroyRenderPass = auto_cast GetDeviceProcAddr(device, "vkDestroyRenderPass") @@ -2433,14 +2683,22 @@ load_proc_addresses_device :: proc(device: Device) { GetCalibratedTimestampsEXT = auto_cast GetDeviceProcAddr(device, "vkGetCalibratedTimestampsEXT") GetDeferredOperationMaxConcurrencyKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationMaxConcurrencyKHR") GetDeferredOperationResultKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeferredOperationResultKHR") + GetDescriptorSetHostMappingVALVE = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetHostMappingVALVE") + GetDescriptorSetLayoutHostMappingInfoVALVE = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutHostMappingInfoVALVE") GetDescriptorSetLayoutSupport = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupport") GetDescriptorSetLayoutSupportKHR = auto_cast GetDeviceProcAddr(device, "vkGetDescriptorSetLayoutSupportKHR") GetDeviceAccelerationStructureCompatibilityKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceAccelerationStructureCompatibilityKHR") + GetDeviceBufferMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetDeviceBufferMemoryRequirements") + GetDeviceBufferMemoryRequirementsKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceBufferMemoryRequirementsKHR") GetDeviceGroupPeerMemoryFeatures = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeatures") GetDeviceGroupPeerMemoryFeaturesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPeerMemoryFeaturesKHR") GetDeviceGroupPresentCapabilitiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupPresentCapabilitiesKHR") GetDeviceGroupSurfacePresentModes2EXT = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModes2EXT") GetDeviceGroupSurfacePresentModesKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceGroupSurfacePresentModesKHR") + GetDeviceImageMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageMemoryRequirements") + GetDeviceImageMemoryRequirementsKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageMemoryRequirementsKHR") + GetDeviceImageSparseMemoryRequirements = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageSparseMemoryRequirements") + GetDeviceImageSparseMemoryRequirementsKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceImageSparseMemoryRequirementsKHR") GetDeviceMemoryCommitment = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryCommitment") GetDeviceMemoryOpaqueCaptureAddress = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddress") GetDeviceMemoryOpaqueCaptureAddressKHR = auto_cast GetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") @@ -2476,6 +2734,7 @@ load_proc_addresses_device :: proc(device: Device) { GetPipelineExecutableInternalRepresentationsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableInternalRepresentationsKHR") GetPipelineExecutablePropertiesKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutablePropertiesKHR") GetPipelineExecutableStatisticsKHR = auto_cast GetDeviceProcAddr(device, "vkGetPipelineExecutableStatisticsKHR") + GetPrivateData = auto_cast GetDeviceProcAddr(device, "vkGetPrivateData") GetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkGetPrivateDataEXT") GetQueryPoolResults = auto_cast GetDeviceProcAddr(device, "vkGetQueryPoolResults") GetQueueCheckpointData2NV = auto_cast GetDeviceProcAddr(device, "vkGetQueueCheckpointData2NV") @@ -2511,6 +2770,7 @@ load_proc_addresses_device :: proc(device: Device) { QueuePresentKHR = auto_cast GetDeviceProcAddr(device, "vkQueuePresentKHR") QueueSetPerformanceConfigurationINTEL = auto_cast GetDeviceProcAddr(device, "vkQueueSetPerformanceConfigurationINTEL") QueueSubmit = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit") + QueueSubmit2 = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit2") QueueSubmit2KHR = auto_cast GetDeviceProcAddr(device, "vkQueueSubmit2KHR") QueueWaitIdle = auto_cast GetDeviceProcAddr(device, "vkQueueWaitIdle") RegisterDeviceEventEXT = auto_cast GetDeviceProcAddr(device, "vkRegisterDeviceEventEXT") @@ -2531,6 +2791,7 @@ load_proc_addresses_device :: proc(device: Device) { SetEvent = auto_cast GetDeviceProcAddr(device, "vkSetEvent") SetHdrMetadataEXT = auto_cast GetDeviceProcAddr(device, "vkSetHdrMetadataEXT") SetLocalDimmingAMD = auto_cast GetDeviceProcAddr(device, "vkSetLocalDimmingAMD") + SetPrivateData = auto_cast GetDeviceProcAddr(device, "vkSetPrivateData") SetPrivateDataEXT = auto_cast GetDeviceProcAddr(device, "vkSetPrivateDataEXT") SignalSemaphore = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphore") SignalSemaphoreKHR = auto_cast GetDeviceProcAddr(device, "vkSignalSemaphoreKHR") @@ -2626,6 +2887,7 @@ load_proc_addresses_instance :: proc(instance: Instance) { GetPhysicalDeviceSurfacePresentModes2EXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModes2EXT") GetPhysicalDeviceSurfacePresentModesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR") GetPhysicalDeviceSurfaceSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR") + GetPhysicalDeviceToolProperties = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceToolProperties") GetPhysicalDeviceToolPropertiesEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceToolPropertiesEXT") GetPhysicalDeviceWin32PresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR") GetWinrtDisplayNV = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV") @@ -2657,6 +2919,8 @@ load_proc_addresses_instance :: proc(instance: Instance) { CmdBeginRenderPass = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRenderPass") CmdBeginRenderPass2 = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRenderPass2") CmdBeginRenderPass2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRenderPass2KHR") + CmdBeginRendering = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRendering") + CmdBeginRenderingKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginRenderingKHR") CmdBeginTransformFeedbackEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBeginTransformFeedbackEXT") CmdBindDescriptorSets = auto_cast GetInstanceProcAddr(instance, "vkCmdBindDescriptorSets") CmdBindIndexBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdBindIndexBuffer") @@ -2666,8 +2930,10 @@ load_proc_addresses_instance :: proc(instance: Instance) { CmdBindShadingRateImageNV = auto_cast GetInstanceProcAddr(instance, "vkCmdBindShadingRateImageNV") CmdBindTransformFeedbackBuffersEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBindTransformFeedbackBuffersEXT") CmdBindVertexBuffers = auto_cast GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers") + CmdBindVertexBuffers2 = auto_cast GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers2") CmdBindVertexBuffers2EXT = auto_cast GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers2EXT") CmdBlitImage = auto_cast GetInstanceProcAddr(instance, "vkCmdBlitImage") + CmdBlitImage2 = auto_cast GetInstanceProcAddr(instance, "vkCmdBlitImage2") CmdBlitImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBlitImage2KHR") CmdBuildAccelerationStructureNV = auto_cast GetInstanceProcAddr(instance, "vkCmdBuildAccelerationStructureNV") CmdBuildAccelerationStructuresIndirectKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdBuildAccelerationStructuresIndirectKHR") @@ -2679,12 +2945,16 @@ load_proc_addresses_instance :: proc(instance: Instance) { CmdCopyAccelerationStructureNV = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyAccelerationStructureNV") CmdCopyAccelerationStructureToMemoryKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyAccelerationStructureToMemoryKHR") CmdCopyBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBuffer") + CmdCopyBuffer2 = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBuffer2") CmdCopyBuffer2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBuffer2KHR") CmdCopyBufferToImage = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage") + CmdCopyBufferToImage2 = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage2") CmdCopyBufferToImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage2KHR") CmdCopyImage = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImage") + CmdCopyImage2 = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImage2") CmdCopyImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImage2KHR") CmdCopyImageToBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer") + CmdCopyImageToBuffer2 = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer2") CmdCopyImageToBuffer2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer2KHR") CmdCopyMemoryToAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyMemoryToAccelerationStructureKHR") CmdCopyQueryPoolResults = auto_cast GetInstanceProcAddr(instance, "vkCmdCopyQueryPoolResults") @@ -2719,6 +2989,8 @@ load_proc_addresses_instance :: proc(instance: Instance) { CmdEndRenderPass = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRenderPass") CmdEndRenderPass2 = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRenderPass2") CmdEndRenderPass2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRenderPass2KHR") + CmdEndRendering = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRendering") + CmdEndRenderingKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdEndRenderingKHR") CmdEndTransformFeedbackEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdEndTransformFeedbackEXT") CmdExecuteCommands = auto_cast GetInstanceProcAddr(instance, "vkCmdExecuteCommands") CmdExecuteGeneratedCommandsNV = auto_cast GetInstanceProcAddr(instance, "vkCmdExecuteGeneratedCommandsNV") @@ -2728,35 +3000,46 @@ load_proc_addresses_instance :: proc(instance: Instance) { CmdNextSubpass2 = auto_cast GetInstanceProcAddr(instance, "vkCmdNextSubpass2") CmdNextSubpass2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdNextSubpass2KHR") CmdPipelineBarrier = auto_cast GetInstanceProcAddr(instance, "vkCmdPipelineBarrier") + CmdPipelineBarrier2 = auto_cast GetInstanceProcAddr(instance, "vkCmdPipelineBarrier2") CmdPipelineBarrier2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdPipelineBarrier2KHR") CmdPreprocessGeneratedCommandsNV = auto_cast GetInstanceProcAddr(instance, "vkCmdPreprocessGeneratedCommandsNV") CmdPushConstants = auto_cast GetInstanceProcAddr(instance, "vkCmdPushConstants") CmdPushDescriptorSetKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdPushDescriptorSetKHR") CmdPushDescriptorSetWithTemplateKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdPushDescriptorSetWithTemplateKHR") CmdResetEvent = auto_cast GetInstanceProcAddr(instance, "vkCmdResetEvent") + CmdResetEvent2 = auto_cast GetInstanceProcAddr(instance, "vkCmdResetEvent2") CmdResetEvent2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdResetEvent2KHR") CmdResetQueryPool = auto_cast GetInstanceProcAddr(instance, "vkCmdResetQueryPool") CmdResolveImage = auto_cast GetInstanceProcAddr(instance, "vkCmdResolveImage") + CmdResolveImage2 = auto_cast GetInstanceProcAddr(instance, "vkCmdResolveImage2") CmdResolveImage2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdResolveImage2KHR") CmdSetBlendConstants = auto_cast GetInstanceProcAddr(instance, "vkCmdSetBlendConstants") CmdSetCheckpointNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetCheckpointNV") CmdSetCoarseSampleOrderNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetCoarseSampleOrderNV") + CmdSetCullMode = auto_cast GetInstanceProcAddr(instance, "vkCmdSetCullMode") CmdSetCullModeEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetCullModeEXT") CmdSetDepthBias = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBias") + CmdSetDepthBiasEnable = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBiasEnable") CmdSetDepthBiasEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBiasEnableEXT") CmdSetDepthBounds = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBounds") + CmdSetDepthBoundsTestEnable = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBoundsTestEnable") CmdSetDepthBoundsTestEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthBoundsTestEnableEXT") + CmdSetDepthCompareOp = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthCompareOp") CmdSetDepthCompareOpEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthCompareOpEXT") + CmdSetDepthTestEnable = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthTestEnable") CmdSetDepthTestEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthTestEnableEXT") + CmdSetDepthWriteEnable = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthWriteEnable") CmdSetDepthWriteEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDepthWriteEnableEXT") CmdSetDeviceMask = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDeviceMask") CmdSetDeviceMaskKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDeviceMaskKHR") CmdSetDiscardRectangleEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetDiscardRectangleEXT") CmdSetEvent = auto_cast GetInstanceProcAddr(instance, "vkCmdSetEvent") + CmdSetEvent2 = auto_cast GetInstanceProcAddr(instance, "vkCmdSetEvent2") CmdSetEvent2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetEvent2KHR") CmdSetExclusiveScissorNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetExclusiveScissorNV") CmdSetFragmentShadingRateEnumNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetFragmentShadingRateEnumNV") CmdSetFragmentShadingRateKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetFragmentShadingRateKHR") + CmdSetFrontFace = auto_cast GetInstanceProcAddr(instance, "vkCmdSetFrontFace") CmdSetFrontFaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetFrontFaceEXT") CmdSetLineStippleEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetLineStippleEXT") CmdSetLineWidth = auto_cast GetInstanceProcAddr(instance, "vkCmdSetLineWidth") @@ -2765,22 +3048,29 @@ load_proc_addresses_instance :: proc(instance: Instance) { CmdSetPerformanceMarkerINTEL = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPerformanceMarkerINTEL") CmdSetPerformanceOverrideINTEL = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPerformanceOverrideINTEL") CmdSetPerformanceStreamMarkerINTEL = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPerformanceStreamMarkerINTEL") + CmdSetPrimitiveRestartEnable = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPrimitiveRestartEnable") CmdSetPrimitiveRestartEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPrimitiveRestartEnableEXT") + CmdSetPrimitiveTopology = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPrimitiveTopology") CmdSetPrimitiveTopologyEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetPrimitiveTopologyEXT") + CmdSetRasterizerDiscardEnable = auto_cast GetInstanceProcAddr(instance, "vkCmdSetRasterizerDiscardEnable") CmdSetRasterizerDiscardEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetRasterizerDiscardEnableEXT") CmdSetRayTracingPipelineStackSizeKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdSetRayTracingPipelineStackSizeKHR") CmdSetSampleLocationsEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetSampleLocationsEXT") CmdSetScissor = auto_cast GetInstanceProcAddr(instance, "vkCmdSetScissor") + CmdSetScissorWithCount = auto_cast GetInstanceProcAddr(instance, "vkCmdSetScissorWithCount") CmdSetScissorWithCountEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetScissorWithCountEXT") CmdSetStencilCompareMask = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilCompareMask") + CmdSetStencilOp = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilOp") CmdSetStencilOpEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilOpEXT") CmdSetStencilReference = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilReference") + CmdSetStencilTestEnable = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilTestEnable") CmdSetStencilTestEnableEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilTestEnableEXT") CmdSetStencilWriteMask = auto_cast GetInstanceProcAddr(instance, "vkCmdSetStencilWriteMask") CmdSetVertexInputEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetVertexInputEXT") CmdSetViewport = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewport") CmdSetViewportShadingRatePaletteNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewportShadingRatePaletteNV") CmdSetViewportWScalingNV = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewportWScalingNV") + CmdSetViewportWithCount = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewportWithCount") CmdSetViewportWithCountEXT = auto_cast GetInstanceProcAddr(instance, "vkCmdSetViewportWithCountEXT") CmdSubpassShadingHUAWEI = auto_cast GetInstanceProcAddr(instance, "vkCmdSubpassShadingHUAWEI") CmdTraceRaysIndirectKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdTraceRaysIndirectKHR") @@ -2788,12 +3078,14 @@ load_proc_addresses_instance :: proc(instance: Instance) { CmdTraceRaysNV = auto_cast GetInstanceProcAddr(instance, "vkCmdTraceRaysNV") CmdUpdateBuffer = auto_cast GetInstanceProcAddr(instance, "vkCmdUpdateBuffer") CmdWaitEvents = auto_cast GetInstanceProcAddr(instance, "vkCmdWaitEvents") + CmdWaitEvents2 = auto_cast GetInstanceProcAddr(instance, "vkCmdWaitEvents2") CmdWaitEvents2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdWaitEvents2KHR") CmdWriteAccelerationStructuresPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteAccelerationStructuresPropertiesKHR") CmdWriteAccelerationStructuresPropertiesNV = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteAccelerationStructuresPropertiesNV") CmdWriteBufferMarker2AMD = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteBufferMarker2AMD") CmdWriteBufferMarkerAMD = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteBufferMarkerAMD") CmdWriteTimestamp = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteTimestamp") + CmdWriteTimestamp2 = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteTimestamp2") CmdWriteTimestamp2KHR = auto_cast GetInstanceProcAddr(instance, "vkCmdWriteTimestamp2KHR") CompileDeferredNV = auto_cast GetInstanceProcAddr(instance, "vkCompileDeferredNV") CopyAccelerationStructureKHR = auto_cast GetInstanceProcAddr(instance, "vkCopyAccelerationStructureKHR") @@ -2821,6 +3113,7 @@ load_proc_addresses_instance :: proc(instance: Instance) { CreateIndirectCommandsLayoutNV = auto_cast GetInstanceProcAddr(instance, "vkCreateIndirectCommandsLayoutNV") CreatePipelineCache = auto_cast GetInstanceProcAddr(instance, "vkCreatePipelineCache") CreatePipelineLayout = auto_cast GetInstanceProcAddr(instance, "vkCreatePipelineLayout") + CreatePrivateDataSlot = auto_cast GetInstanceProcAddr(instance, "vkCreatePrivateDataSlot") CreatePrivateDataSlotEXT = auto_cast GetInstanceProcAddr(instance, "vkCreatePrivateDataSlotEXT") CreateQueryPool = auto_cast GetInstanceProcAddr(instance, "vkCreateQueryPool") CreateRayTracingPipelinesKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateRayTracingPipelinesKHR") @@ -2861,6 +3154,7 @@ load_proc_addresses_instance :: proc(instance: Instance) { DestroyPipeline = auto_cast GetInstanceProcAddr(instance, "vkDestroyPipeline") DestroyPipelineCache = auto_cast GetInstanceProcAddr(instance, "vkDestroyPipelineCache") DestroyPipelineLayout = auto_cast GetInstanceProcAddr(instance, "vkDestroyPipelineLayout") + DestroyPrivateDataSlot = auto_cast GetInstanceProcAddr(instance, "vkDestroyPrivateDataSlot") DestroyPrivateDataSlotEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyPrivateDataSlotEXT") DestroyQueryPool = auto_cast GetInstanceProcAddr(instance, "vkDestroyQueryPool") DestroyRenderPass = auto_cast GetInstanceProcAddr(instance, "vkDestroyRenderPass") @@ -2893,14 +3187,22 @@ load_proc_addresses_instance :: proc(instance: Instance) { GetCalibratedTimestampsEXT = auto_cast GetInstanceProcAddr(instance, "vkGetCalibratedTimestampsEXT") GetDeferredOperationMaxConcurrencyKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeferredOperationMaxConcurrencyKHR") GetDeferredOperationResultKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeferredOperationResultKHR") + GetDescriptorSetHostMappingVALVE = auto_cast GetInstanceProcAddr(instance, "vkGetDescriptorSetHostMappingVALVE") + GetDescriptorSetLayoutHostMappingInfoVALVE = auto_cast GetInstanceProcAddr(instance, "vkGetDescriptorSetLayoutHostMappingInfoVALVE") GetDescriptorSetLayoutSupport = auto_cast GetInstanceProcAddr(instance, "vkGetDescriptorSetLayoutSupport") GetDescriptorSetLayoutSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDescriptorSetLayoutSupportKHR") GetDeviceAccelerationStructureCompatibilityKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceAccelerationStructureCompatibilityKHR") + GetDeviceBufferMemoryRequirements = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceBufferMemoryRequirements") + GetDeviceBufferMemoryRequirementsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceBufferMemoryRequirementsKHR") GetDeviceGroupPeerMemoryFeatures = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupPeerMemoryFeatures") GetDeviceGroupPeerMemoryFeaturesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupPeerMemoryFeaturesKHR") GetDeviceGroupPresentCapabilitiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupPresentCapabilitiesKHR") GetDeviceGroupSurfacePresentModes2EXT = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupSurfacePresentModes2EXT") GetDeviceGroupSurfacePresentModesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceGroupSurfacePresentModesKHR") + GetDeviceImageMemoryRequirements = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceImageMemoryRequirements") + GetDeviceImageMemoryRequirementsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceImageMemoryRequirementsKHR") + GetDeviceImageSparseMemoryRequirements = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceImageSparseMemoryRequirements") + GetDeviceImageSparseMemoryRequirementsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceImageSparseMemoryRequirementsKHR") GetDeviceMemoryCommitment = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceMemoryCommitment") GetDeviceMemoryOpaqueCaptureAddress = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceMemoryOpaqueCaptureAddress") GetDeviceMemoryOpaqueCaptureAddressKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDeviceMemoryOpaqueCaptureAddressKHR") @@ -2936,6 +3238,7 @@ load_proc_addresses_instance :: proc(instance: Instance) { GetPipelineExecutableInternalRepresentationsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPipelineExecutableInternalRepresentationsKHR") GetPipelineExecutablePropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPipelineExecutablePropertiesKHR") GetPipelineExecutableStatisticsKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPipelineExecutableStatisticsKHR") + GetPrivateData = auto_cast GetInstanceProcAddr(instance, "vkGetPrivateData") GetPrivateDataEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPrivateDataEXT") GetQueryPoolResults = auto_cast GetInstanceProcAddr(instance, "vkGetQueryPoolResults") GetQueueCheckpointData2NV = auto_cast GetInstanceProcAddr(instance, "vkGetQueueCheckpointData2NV") @@ -2971,6 +3274,7 @@ load_proc_addresses_instance :: proc(instance: Instance) { QueuePresentKHR = auto_cast GetInstanceProcAddr(instance, "vkQueuePresentKHR") QueueSetPerformanceConfigurationINTEL = auto_cast GetInstanceProcAddr(instance, "vkQueueSetPerformanceConfigurationINTEL") QueueSubmit = auto_cast GetInstanceProcAddr(instance, "vkQueueSubmit") + QueueSubmit2 = auto_cast GetInstanceProcAddr(instance, "vkQueueSubmit2") QueueSubmit2KHR = auto_cast GetInstanceProcAddr(instance, "vkQueueSubmit2KHR") QueueWaitIdle = auto_cast GetInstanceProcAddr(instance, "vkQueueWaitIdle") RegisterDeviceEventEXT = auto_cast GetInstanceProcAddr(instance, "vkRegisterDeviceEventEXT") @@ -2991,6 +3295,7 @@ load_proc_addresses_instance :: proc(instance: Instance) { SetEvent = auto_cast GetInstanceProcAddr(instance, "vkSetEvent") SetHdrMetadataEXT = auto_cast GetInstanceProcAddr(instance, "vkSetHdrMetadataEXT") SetLocalDimmingAMD = auto_cast GetInstanceProcAddr(instance, "vkSetLocalDimmingAMD") + SetPrivateData = auto_cast GetInstanceProcAddr(instance, "vkSetPrivateData") SetPrivateDataEXT = auto_cast GetInstanceProcAddr(instance, "vkSetPrivateDataEXT") SignalSemaphore = auto_cast GetInstanceProcAddr(instance, "vkSignalSemaphore") SignalSemaphoreKHR = auto_cast GetInstanceProcAddr(instance, "vkSignalSemaphoreKHR") diff --git a/vendor/vulkan/structs.odin b/vendor/vulkan/structs.odin index 3c655a4fa..3bc3e1935 100644 --- a/vendor/vulkan/structs.odin +++ b/vendor/vulkan/structs.odin @@ -2170,6 +2170,537 @@ DeviceMemoryOpaqueCaptureAddressInfo :: struct { memory: DeviceMemory, } +PhysicalDeviceVulkan13Features :: struct { + sType: StructureType, + pNext: rawptr, + robustImageAccess: b32, + inlineUniformBlock: b32, + descriptorBindingInlineUniformBlockUpdateAfterBind: b32, + pipelineCreationCacheControl: b32, + privateData: b32, + shaderDemoteToHelperInvocation: b32, + shaderTerminateInvocation: b32, + subgroupSizeControl: b32, + computeFullSubgroups: b32, + synchronization2: b32, + textureCompressionASTC_HDR: b32, + shaderZeroInitializeWorkgroupMemory: b32, + dynamicRendering: b32, + shaderIntegerDotProduct: b32, + maintenance4: b32, +} + +PhysicalDeviceVulkan13Properties :: struct { + sType: StructureType, + pNext: rawptr, + minSubgroupSize: u32, + maxSubgroupSize: u32, + maxComputeWorkgroupSubgroups: u32, + requiredSubgroupSizeStages: ShaderStageFlags, + maxInlineUniformBlockSize: u32, + maxPerStageDescriptorInlineUniformBlocks: u32, + maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks: u32, + maxDescriptorSetInlineUniformBlocks: u32, + maxDescriptorSetUpdateAfterBindInlineUniformBlocks: u32, + maxInlineUniformTotalSize: u32, + integerDotProduct8BitUnsignedAccelerated: b32, + integerDotProduct8BitSignedAccelerated: b32, + integerDotProduct8BitMixedSignednessAccelerated: b32, + integerDotProduct4x8BitPackedUnsignedAccelerated: b32, + integerDotProduct4x8BitPackedSignedAccelerated: b32, + integerDotProduct4x8BitPackedMixedSignednessAccelerated: b32, + integerDotProduct16BitUnsignedAccelerated: b32, + integerDotProduct16BitSignedAccelerated: b32, + integerDotProduct16BitMixedSignednessAccelerated: b32, + integerDotProduct32BitUnsignedAccelerated: b32, + integerDotProduct32BitSignedAccelerated: b32, + integerDotProduct32BitMixedSignednessAccelerated: b32, + integerDotProduct64BitUnsignedAccelerated: b32, + integerDotProduct64BitSignedAccelerated: b32, + integerDotProduct64BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating8BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating8BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated: b32, + integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating16BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating16BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating32BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating32BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating64BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating64BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated: b32, + storageTexelBufferOffsetAlignmentBytes: DeviceSize, + storageTexelBufferOffsetSingleTexelAlignment: b32, + uniformTexelBufferOffsetAlignmentBytes: DeviceSize, + uniformTexelBufferOffsetSingleTexelAlignment: b32, + maxBufferSize: DeviceSize, +} + +PipelineCreationFeedback :: struct { + flags: PipelineCreationFeedbackFlags, + duration: u64, +} + +PipelineCreationFeedbackCreateInfo :: struct { + sType: StructureType, + pNext: rawptr, + pPipelineCreationFeedback: ^PipelineCreationFeedback, + pipelineStageCreationFeedbackCount: u32, + pPipelineStageCreationFeedbacks: [^]PipelineCreationFeedback, +} + +PhysicalDeviceShaderTerminateInvocationFeatures :: struct { + sType: StructureType, + pNext: rawptr, + shaderTerminateInvocation: b32, +} + +PhysicalDeviceToolProperties :: struct { + sType: StructureType, + pNext: rawptr, + name: [MAX_EXTENSION_NAME_SIZE]byte, + version: [MAX_EXTENSION_NAME_SIZE]byte, + purposes: ToolPurposeFlags, + description: [MAX_DESCRIPTION_SIZE]byte, + layer: [MAX_EXTENSION_NAME_SIZE]byte, +} + +PhysicalDeviceShaderDemoteToHelperInvocationFeatures :: struct { + sType: StructureType, + pNext: rawptr, + shaderDemoteToHelperInvocation: b32, +} + +PhysicalDevicePrivateDataFeatures :: struct { + sType: StructureType, + pNext: rawptr, + privateData: b32, +} + +DevicePrivateDataCreateInfo :: struct { + sType: StructureType, + pNext: rawptr, + privateDataSlotRequestCount: u32, +} + +PrivateDataSlotCreateInfo :: struct { + sType: StructureType, + pNext: rawptr, + flags: PrivateDataSlotCreateFlags, +} + +PhysicalDevicePipelineCreationCacheControlFeatures :: struct { + sType: StructureType, + pNext: rawptr, + pipelineCreationCacheControl: b32, +} + +MemoryBarrier2 :: struct { + sType: StructureType, + pNext: rawptr, + srcStageMask: PipelineStageFlags2, + srcAccessMask: AccessFlags2, + dstStageMask: PipelineStageFlags2, + dstAccessMask: AccessFlags2, +} + +BufferMemoryBarrier2 :: struct { + sType: StructureType, + pNext: rawptr, + srcStageMask: PipelineStageFlags2, + srcAccessMask: AccessFlags2, + dstStageMask: PipelineStageFlags2, + dstAccessMask: AccessFlags2, + srcQueueFamilyIndex: u32, + dstQueueFamilyIndex: u32, + buffer: Buffer, + offset: DeviceSize, + size: DeviceSize, +} + +ImageMemoryBarrier2 :: struct { + sType: StructureType, + pNext: rawptr, + srcStageMask: PipelineStageFlags2, + srcAccessMask: AccessFlags2, + dstStageMask: PipelineStageFlags2, + dstAccessMask: AccessFlags2, + oldLayout: ImageLayout, + newLayout: ImageLayout, + srcQueueFamilyIndex: u32, + dstQueueFamilyIndex: u32, + image: Image, + subresourceRange: ImageSubresourceRange, +} + +DependencyInfo :: struct { + sType: StructureType, + pNext: rawptr, + dependencyFlags: DependencyFlags, + memoryBarrierCount: u32, + pMemoryBarriers: [^]MemoryBarrier2, + bufferMemoryBarrierCount: u32, + pBufferMemoryBarriers: [^]BufferMemoryBarrier2, + imageMemoryBarrierCount: u32, + pImageMemoryBarriers: [^]ImageMemoryBarrier2, +} + +SemaphoreSubmitInfo :: struct { + sType: StructureType, + pNext: rawptr, + semaphore: Semaphore, + value: u64, + stageMask: PipelineStageFlags2, + deviceIndex: u32, +} + +CommandBufferSubmitInfo :: struct { + sType: StructureType, + pNext: rawptr, + commandBuffer: CommandBuffer, + deviceMask: u32, +} + +SubmitInfo2 :: struct { + sType: StructureType, + pNext: rawptr, + flags: SubmitFlags, + waitSemaphoreInfoCount: u32, + pWaitSemaphoreInfos: [^]SemaphoreSubmitInfo, + commandBufferInfoCount: u32, + pCommandBufferInfos: [^]CommandBufferSubmitInfo, + signalSemaphoreInfoCount: u32, + pSignalSemaphoreInfos: [^]SemaphoreSubmitInfo, +} + +PhysicalDeviceSynchronization2Features :: struct { + sType: StructureType, + pNext: rawptr, + synchronization2: b32, +} + +PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures :: struct { + sType: StructureType, + pNext: rawptr, + shaderZeroInitializeWorkgroupMemory: b32, +} + +PhysicalDeviceImageRobustnessFeatures :: struct { + sType: StructureType, + pNext: rawptr, + robustImageAccess: b32, +} + +BufferCopy2 :: struct { + sType: StructureType, + pNext: rawptr, + srcOffset: DeviceSize, + dstOffset: DeviceSize, + size: DeviceSize, +} + +CopyBufferInfo2 :: struct { + sType: StructureType, + pNext: rawptr, + srcBuffer: Buffer, + dstBuffer: Buffer, + regionCount: u32, + pRegions: [^]BufferCopy2, +} + +ImageCopy2 :: struct { + sType: StructureType, + pNext: rawptr, + srcSubresource: ImageSubresourceLayers, + srcOffset: Offset3D, + dstSubresource: ImageSubresourceLayers, + dstOffset: Offset3D, + extent: Extent3D, +} + +CopyImageInfo2 :: struct { + sType: StructureType, + pNext: rawptr, + srcImage: Image, + srcImageLayout: ImageLayout, + dstImage: Image, + dstImageLayout: ImageLayout, + regionCount: u32, + pRegions: [^]ImageCopy2, +} + +BufferImageCopy2 :: struct { + sType: StructureType, + pNext: rawptr, + bufferOffset: DeviceSize, + bufferRowLength: u32, + bufferImageHeight: u32, + imageSubresource: ImageSubresourceLayers, + imageOffset: Offset3D, + imageExtent: Extent3D, +} + +CopyBufferToImageInfo2 :: struct { + sType: StructureType, + pNext: rawptr, + srcBuffer: Buffer, + dstImage: Image, + dstImageLayout: ImageLayout, + regionCount: u32, + pRegions: [^]BufferImageCopy2, +} + +CopyImageToBufferInfo2 :: struct { + sType: StructureType, + pNext: rawptr, + srcImage: Image, + srcImageLayout: ImageLayout, + dstBuffer: Buffer, + regionCount: u32, + pRegions: [^]BufferImageCopy2, +} + +ImageBlit2 :: struct { + sType: StructureType, + pNext: rawptr, + srcSubresource: ImageSubresourceLayers, + srcOffsets: [2]Offset3D, + dstSubresource: ImageSubresourceLayers, + dstOffsets: [2]Offset3D, +} + +BlitImageInfo2 :: struct { + sType: StructureType, + pNext: rawptr, + srcImage: Image, + srcImageLayout: ImageLayout, + dstImage: Image, + dstImageLayout: ImageLayout, + regionCount: u32, + pRegions: [^]ImageBlit2, + filter: Filter, +} + +ImageResolve2 :: struct { + sType: StructureType, + pNext: rawptr, + srcSubresource: ImageSubresourceLayers, + srcOffset: Offset3D, + dstSubresource: ImageSubresourceLayers, + dstOffset: Offset3D, + extent: Extent3D, +} + +ResolveImageInfo2 :: struct { + sType: StructureType, + pNext: rawptr, + srcImage: Image, + srcImageLayout: ImageLayout, + dstImage: Image, + dstImageLayout: ImageLayout, + regionCount: u32, + pRegions: [^]ImageResolve2, +} + +PhysicalDeviceSubgroupSizeControlFeatures :: struct { + sType: StructureType, + pNext: rawptr, + subgroupSizeControl: b32, + computeFullSubgroups: b32, +} + +PhysicalDeviceSubgroupSizeControlProperties :: struct { + sType: StructureType, + pNext: rawptr, + minSubgroupSize: u32, + maxSubgroupSize: u32, + maxComputeWorkgroupSubgroups: u32, + requiredSubgroupSizeStages: ShaderStageFlags, +} + +PipelineShaderStageRequiredSubgroupSizeCreateInfo :: struct { + sType: StructureType, + pNext: rawptr, + requiredSubgroupSize: u32, +} + +PhysicalDeviceInlineUniformBlockFeatures :: struct { + sType: StructureType, + pNext: rawptr, + inlineUniformBlock: b32, + descriptorBindingInlineUniformBlockUpdateAfterBind: b32, +} + +PhysicalDeviceInlineUniformBlockProperties :: struct { + sType: StructureType, + pNext: rawptr, + maxInlineUniformBlockSize: u32, + maxPerStageDescriptorInlineUniformBlocks: u32, + maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks: u32, + maxDescriptorSetInlineUniformBlocks: u32, + maxDescriptorSetUpdateAfterBindInlineUniformBlocks: u32, +} + +WriteDescriptorSetInlineUniformBlock :: struct { + sType: StructureType, + pNext: rawptr, + dataSize: u32, + pData: rawptr, +} + +DescriptorPoolInlineUniformBlockCreateInfo :: struct { + sType: StructureType, + pNext: rawptr, + maxInlineUniformBlockBindings: u32, +} + +PhysicalDeviceTextureCompressionASTCHDRFeatures :: struct { + sType: StructureType, + pNext: rawptr, + textureCompressionASTC_HDR: b32, +} + +RenderingAttachmentInfo :: struct { + sType: StructureType, + pNext: rawptr, + imageView: ImageView, + imageLayout: ImageLayout, + resolveMode: ResolveModeFlags, + resolveImageView: ImageView, + resolveImageLayout: ImageLayout, + loadOp: AttachmentLoadOp, + storeOp: AttachmentStoreOp, + clearValue: ClearValue, +} + +RenderingInfo :: struct { + sType: StructureType, + pNext: rawptr, + flags: RenderingFlags, + renderArea: Rect2D, + layerCount: u32, + viewMask: u32, + colorAttachmentCount: u32, + pColorAttachments: [^]RenderingAttachmentInfo, + pDepthAttachment: ^RenderingAttachmentInfo, + pStencilAttachment: ^RenderingAttachmentInfo, +} + +PipelineRenderingCreateInfo :: struct { + sType: StructureType, + pNext: rawptr, + viewMask: u32, + colorAttachmentCount: u32, + pColorAttachmentFormats: [^]Format, + depthAttachmentFormat: Format, + stencilAttachmentFormat: Format, +} + +PhysicalDeviceDynamicRenderingFeatures :: struct { + sType: StructureType, + pNext: rawptr, + dynamicRendering: b32, +} + +CommandBufferInheritanceRenderingInfo :: struct { + sType: StructureType, + pNext: rawptr, + flags: RenderingFlags, + viewMask: u32, + colorAttachmentCount: u32, + pColorAttachmentFormats: [^]Format, + depthAttachmentFormat: Format, + stencilAttachmentFormat: Format, + rasterizationSamples: SampleCountFlags, +} + +PhysicalDeviceShaderIntegerDotProductFeatures :: struct { + sType: StructureType, + pNext: rawptr, + shaderIntegerDotProduct: b32, +} + +PhysicalDeviceShaderIntegerDotProductProperties :: struct { + sType: StructureType, + pNext: rawptr, + integerDotProduct8BitUnsignedAccelerated: b32, + integerDotProduct8BitSignedAccelerated: b32, + integerDotProduct8BitMixedSignednessAccelerated: b32, + integerDotProduct4x8BitPackedUnsignedAccelerated: b32, + integerDotProduct4x8BitPackedSignedAccelerated: b32, + integerDotProduct4x8BitPackedMixedSignednessAccelerated: b32, + integerDotProduct16BitUnsignedAccelerated: b32, + integerDotProduct16BitSignedAccelerated: b32, + integerDotProduct16BitMixedSignednessAccelerated: b32, + integerDotProduct32BitUnsignedAccelerated: b32, + integerDotProduct32BitSignedAccelerated: b32, + integerDotProduct32BitMixedSignednessAccelerated: b32, + integerDotProduct64BitUnsignedAccelerated: b32, + integerDotProduct64BitSignedAccelerated: b32, + integerDotProduct64BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating8BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating8BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated: b32, + integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating16BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating16BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating32BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating32BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated: b32, + integerDotProductAccumulatingSaturating64BitUnsignedAccelerated: b32, + integerDotProductAccumulatingSaturating64BitSignedAccelerated: b32, + integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated: b32, +} + +PhysicalDeviceTexelBufferAlignmentProperties :: struct { + sType: StructureType, + pNext: rawptr, + storageTexelBufferOffsetAlignmentBytes: DeviceSize, + storageTexelBufferOffsetSingleTexelAlignment: b32, + uniformTexelBufferOffsetAlignmentBytes: DeviceSize, + uniformTexelBufferOffsetSingleTexelAlignment: b32, +} + +FormatProperties3 :: struct { + sType: StructureType, + pNext: rawptr, + linearTilingFeatures: FormatFeatureFlags2, + optimalTilingFeatures: FormatFeatureFlags2, + bufferFeatures: FormatFeatureFlags2, +} + +PhysicalDeviceMaintenance4Features :: struct { + sType: StructureType, + pNext: rawptr, + maintenance4: b32, +} + +PhysicalDeviceMaintenance4Properties :: struct { + sType: StructureType, + pNext: rawptr, + maxBufferSize: DeviceSize, +} + +DeviceBufferMemoryRequirements :: struct { + sType: StructureType, + pNext: rawptr, + pCreateInfo: ^BufferCreateInfo, +} + +DeviceImageMemoryRequirements :: struct { + sType: StructureType, + pNext: rawptr, + pCreateInfo: ^ImageCreateInfo, + planeAspect: ImageAspectFlags, +} + SurfaceCapabilitiesKHR :: struct { minImageCount: u32, maxImageCount: u32, @@ -2329,6 +2860,36 @@ DisplayPresentInfoKHR :: struct { persistent: b32, } +RenderingFragmentShadingRateAttachmentInfoKHR :: struct { + sType: StructureType, + pNext: rawptr, + imageView: ImageView, + imageLayout: ImageLayout, + shadingRateAttachmentTexelSize: Extent2D, +} + +RenderingFragmentDensityMapAttachmentInfoEXT :: struct { + sType: StructureType, + pNext: rawptr, + imageView: ImageView, + imageLayout: ImageLayout, +} + +AttachmentSampleCountInfoAMD :: struct { + sType: StructureType, + pNext: rawptr, + colorAttachmentCount: u32, + pColorAttachmentSamples: [^]SampleCountFlags, + depthStencilAttachmentSamples: SampleCountFlags, +} + +MultiviewPerViewAttributesInfoNVX :: struct { + sType: StructureType, + pNext: rawptr, + perViewAttributes: b32, + perViewAttributesPositionXOnly: b32, +} + ImportMemoryFdInfoKHR :: struct { sType: StructureType, pNext: rawptr, @@ -2528,10 +3089,23 @@ PhysicalDeviceShaderClockFeaturesKHR :: struct { shaderDeviceClock: b32, } -PhysicalDeviceShaderTerminateInvocationFeaturesKHR :: struct { - sType: StructureType, - pNext: rawptr, - shaderTerminateInvocation: b32, +DeviceQueueGlobalPriorityCreateInfoKHR :: struct { + sType: StructureType, + pNext: rawptr, + globalPriority: QueueGlobalPriorityKHR, +} + +PhysicalDeviceGlobalPriorityQueryFeaturesKHR :: struct { + sType: StructureType, + pNext: rawptr, + globalPriorityQuery: b32, +} + +QueueFamilyGlobalPriorityPropertiesKHR :: struct { + sType: StructureType, + pNext: rawptr, + priorityCount: u32, + priorities: [MAX_GLOBAL_PRIORITY_SIZE_KHR]QueueGlobalPriorityKHR, } FragmentShadingRateAttachmentInfoKHR :: struct { @@ -2651,47 +3225,6 @@ PipelineExecutableInternalRepresentationKHR :: struct { pData: rawptr, } -PhysicalDeviceShaderIntegerDotProductFeaturesKHR :: struct { - sType: StructureType, - pNext: rawptr, - shaderIntegerDotProduct: b32, -} - -PhysicalDeviceShaderIntegerDotProductPropertiesKHR :: struct { - sType: StructureType, - pNext: rawptr, - integerDotProduct8BitUnsignedAccelerated: b32, - integerDotProduct8BitSignedAccelerated: b32, - integerDotProduct8BitMixedSignednessAccelerated: b32, - integerDotProduct4x8BitPackedUnsignedAccelerated: b32, - integerDotProduct4x8BitPackedSignedAccelerated: b32, - integerDotProduct4x8BitPackedMixedSignednessAccelerated: b32, - integerDotProduct16BitUnsignedAccelerated: b32, - integerDotProduct16BitSignedAccelerated: b32, - integerDotProduct16BitMixedSignednessAccelerated: b32, - integerDotProduct32BitUnsignedAccelerated: b32, - integerDotProduct32BitSignedAccelerated: b32, - integerDotProduct32BitMixedSignednessAccelerated: b32, - integerDotProduct64BitUnsignedAccelerated: b32, - integerDotProduct64BitSignedAccelerated: b32, - integerDotProduct64BitMixedSignednessAccelerated: b32, - integerDotProductAccumulatingSaturating8BitUnsignedAccelerated: b32, - integerDotProductAccumulatingSaturating8BitSignedAccelerated: b32, - integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated: b32, - integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated: b32, - integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated: b32, - integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated: b32, - integerDotProductAccumulatingSaturating16BitUnsignedAccelerated: b32, - integerDotProductAccumulatingSaturating16BitSignedAccelerated: b32, - integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated: b32, - integerDotProductAccumulatingSaturating32BitUnsignedAccelerated: b32, - integerDotProductAccumulatingSaturating32BitSignedAccelerated: b32, - integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated: b32, - integerDotProductAccumulatingSaturating64BitUnsignedAccelerated: b32, - integerDotProductAccumulatingSaturating64BitSignedAccelerated: b32, - integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated: b32, -} - PipelineLibraryCreateInfoKHR :: struct { sType: StructureType, pNext: rawptr, @@ -2712,100 +3245,16 @@ PhysicalDevicePresentIdFeaturesKHR :: struct { presentId: b32, } -MemoryBarrier2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcStageMask: PipelineStageFlags2KHR, - srcAccessMask: AccessFlags2KHR, - dstStageMask: PipelineStageFlags2KHR, - dstAccessMask: AccessFlags2KHR, -} - -BufferMemoryBarrier2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcStageMask: PipelineStageFlags2KHR, - srcAccessMask: AccessFlags2KHR, - dstStageMask: PipelineStageFlags2KHR, - dstAccessMask: AccessFlags2KHR, - srcQueueFamilyIndex: u32, - dstQueueFamilyIndex: u32, - buffer: Buffer, - offset: DeviceSize, - size: DeviceSize, -} - -ImageMemoryBarrier2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcStageMask: PipelineStageFlags2KHR, - srcAccessMask: AccessFlags2KHR, - dstStageMask: PipelineStageFlags2KHR, - dstAccessMask: AccessFlags2KHR, - oldLayout: ImageLayout, - newLayout: ImageLayout, - srcQueueFamilyIndex: u32, - dstQueueFamilyIndex: u32, - image: Image, - subresourceRange: ImageSubresourceRange, -} - -DependencyInfoKHR :: struct { - sType: StructureType, - pNext: rawptr, - dependencyFlags: DependencyFlags, - memoryBarrierCount: u32, - pMemoryBarriers: [^]MemoryBarrier2KHR, - bufferMemoryBarrierCount: u32, - pBufferMemoryBarriers: [^]BufferMemoryBarrier2KHR, - imageMemoryBarrierCount: u32, - pImageMemoryBarriers: [^]ImageMemoryBarrier2KHR, -} - -SemaphoreSubmitInfoKHR :: struct { - sType: StructureType, - pNext: rawptr, - semaphore: Semaphore, - value: u64, - stageMask: PipelineStageFlags2KHR, - deviceIndex: u32, -} - -CommandBufferSubmitInfoKHR :: struct { - sType: StructureType, - pNext: rawptr, - commandBuffer: CommandBuffer, - deviceMask: u32, -} - -SubmitInfo2KHR :: struct { - sType: StructureType, - pNext: rawptr, - flags: SubmitFlagsKHR, - waitSemaphoreInfoCount: u32, - pWaitSemaphoreInfos: [^]SemaphoreSubmitInfoKHR, - commandBufferInfoCount: u32, - pCommandBufferInfos: [^]CommandBufferSubmitInfoKHR, - signalSemaphoreInfoCount: u32, - pSignalSemaphoreInfos: [^]SemaphoreSubmitInfoKHR, -} - -PhysicalDeviceSynchronization2FeaturesKHR :: struct { - sType: StructureType, - pNext: rawptr, - synchronization2: b32, -} - QueueFamilyCheckpointProperties2NV :: struct { sType: StructureType, pNext: rawptr, - checkpointExecutionStageMask: PipelineStageFlags2KHR, + checkpointExecutionStageMask: PipelineStageFlags2, } CheckpointData2NV :: struct { sType: StructureType, pNext: rawptr, - stage: PipelineStageFlags2KHR, + stage: PipelineStageFlags2, pCheckpointMarker: rawptr, } @@ -2815,12 +3264,6 @@ PhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR :: struct { shaderSubgroupUniformControlFlow: b32, } -PhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR :: struct { - sType: StructureType, - pNext: rawptr, - shaderZeroInitializeWorkgroupMemory: b32, -} - PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR :: struct { sType: StructureType, pNext: rawptr, @@ -2830,117 +3273,6 @@ PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR :: struct { workgroupMemoryExplicitLayout16BitAccess: b32, } -BufferCopy2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcOffset: DeviceSize, - dstOffset: DeviceSize, - size: DeviceSize, -} - -CopyBufferInfo2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcBuffer: Buffer, - dstBuffer: Buffer, - regionCount: u32, - pRegions: [^]BufferCopy2KHR, -} - -ImageCopy2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcSubresource: ImageSubresourceLayers, - srcOffset: Offset3D, - dstSubresource: ImageSubresourceLayers, - dstOffset: Offset3D, - extent: Extent3D, -} - -CopyImageInfo2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcImage: Image, - srcImageLayout: ImageLayout, - dstImage: Image, - dstImageLayout: ImageLayout, - regionCount: u32, - pRegions: [^]ImageCopy2KHR, -} - -BufferImageCopy2KHR :: struct { - sType: StructureType, - pNext: rawptr, - bufferOffset: DeviceSize, - bufferRowLength: u32, - bufferImageHeight: u32, - imageSubresource: ImageSubresourceLayers, - imageOffset: Offset3D, - imageExtent: Extent3D, -} - -CopyBufferToImageInfo2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcBuffer: Buffer, - dstImage: Image, - dstImageLayout: ImageLayout, - regionCount: u32, - pRegions: [^]BufferImageCopy2KHR, -} - -CopyImageToBufferInfo2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcImage: Image, - srcImageLayout: ImageLayout, - dstBuffer: Buffer, - regionCount: u32, - pRegions: [^]BufferImageCopy2KHR, -} - -ImageBlit2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcSubresource: ImageSubresourceLayers, - srcOffsets: [2]Offset3D, - dstSubresource: ImageSubresourceLayers, - dstOffsets: [2]Offset3D, -} - -BlitImageInfo2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcImage: Image, - srcImageLayout: ImageLayout, - dstImage: Image, - dstImageLayout: ImageLayout, - regionCount: u32, - pRegions: [^]ImageBlit2KHR, - filter: Filter, -} - -ImageResolve2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcSubresource: ImageSubresourceLayers, - srcOffset: Offset3D, - dstSubresource: ImageSubresourceLayers, - dstOffset: Offset3D, - extent: Extent3D, -} - -ResolveImageInfo2KHR :: struct { - sType: StructureType, - pNext: rawptr, - srcImage: Image, - srcImageLayout: ImageLayout, - dstImage: Image, - dstImageLayout: ImageLayout, - regionCount: u32, - pRegions: [^]ImageResolve2KHR, -} - DebugReportCallbackCreateInfoEXT :: struct { sType: StructureType, pNext: rawptr, @@ -3130,12 +3462,6 @@ ValidationFlagsEXT :: struct { pDisabledValidationChecks: [^]ValidationCheckEXT, } -PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - textureCompressionASTC_HDR: b32, -} - ImageViewASTCDecodeModeEXT :: struct { sType: StructureType, pNext: rawptr, @@ -3385,36 +3711,6 @@ DebugUtilsObjectTagInfoEXT :: struct { pTag: rawptr, } -PhysicalDeviceInlineUniformBlockFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - inlineUniformBlock: b32, - descriptorBindingInlineUniformBlockUpdateAfterBind: b32, -} - -PhysicalDeviceInlineUniformBlockPropertiesEXT :: struct { - sType: StructureType, - pNext: rawptr, - maxInlineUniformBlockSize: u32, - maxPerStageDescriptorInlineUniformBlocks: u32, - maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks: u32, - maxDescriptorSetInlineUniformBlocks: u32, - maxDescriptorSetUpdateAfterBindInlineUniformBlocks: u32, -} - -WriteDescriptorSetInlineUniformBlockEXT :: struct { - sType: StructureType, - pNext: rawptr, - dataSize: u32, - pData: rawptr, -} - -DescriptorPoolInlineUniformBlockCreateInfoEXT :: struct { - sType: StructureType, - pNext: rawptr, - maxInlineUniformBlockBindings: u32, -} - SampleLocationEXT :: struct { x: f32, y: f32, @@ -3570,6 +3866,19 @@ ImageDrmFormatModifierPropertiesEXT :: struct { drmFormatModifier: u64, } +DrmFormatModifierProperties2EXT :: struct { + drmFormatModifier: u64, + drmFormatModifierPlaneCount: u32, + drmFormatModifierTilingFeatures: FormatFeatureFlags2, +} + +DrmFormatModifierPropertiesList2EXT :: struct { + sType: StructureType, + pNext: rawptr, + drmFormatModifierCount: u32, + pDrmFormatModifierProperties: [^]DrmFormatModifierProperties2EXT, +} + ValidationCacheCreateInfoEXT :: struct { sType: StructureType, pNext: rawptr, @@ -3792,12 +4101,6 @@ FilterCubicImageViewImageFormatPropertiesEXT :: struct { filterCubicMinmax: b32, } -DeviceQueueGlobalPriorityCreateInfoEXT :: struct { - sType: StructureType, - pNext: rawptr, - globalPriority: QueueGlobalPriorityEXT, -} - ImportMemoryHostPointerInfoEXT :: struct { sType: StructureType, pNext: rawptr, @@ -3879,19 +4182,6 @@ PhysicalDeviceVertexAttributeDivisorFeaturesEXT :: struct { vertexAttributeInstanceRateZeroDivisor: b32, } -PipelineCreationFeedbackEXT :: struct { - flags: PipelineCreationFeedbackFlagsEXT, - duration: u64, -} - -PipelineCreationFeedbackCreateInfoEXT :: struct { - sType: StructureType, - pNext: rawptr, - pPipelineCreationFeedback: ^PipelineCreationFeedbackEXT, - pipelineStageCreationFeedbackCount: u32, - pPipelineStageCreationFeedbacks: [^]PipelineCreationFeedbackEXT, -} - PhysicalDeviceComputeShaderDerivativesFeaturesNV :: struct { sType: StructureType, pNext: rawptr, @@ -4067,28 +4357,6 @@ RenderPassFragmentDensityMapCreateInfoEXT :: struct { fragmentDensityMapAttachment: AttachmentReference, } -PhysicalDeviceSubgroupSizeControlFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - subgroupSizeControl: b32, - computeFullSubgroups: b32, -} - -PhysicalDeviceSubgroupSizeControlPropertiesEXT :: struct { - sType: StructureType, - pNext: rawptr, - minSubgroupSize: u32, - maxSubgroupSize: u32, - maxComputeWorkgroupSubgroups: u32, - requiredSubgroupSizeStages: ShaderStageFlags, -} - -PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT :: struct { - sType: StructureType, - pNext: rawptr, - requiredSubgroupSize: u32, -} - PhysicalDeviceShaderCoreProperties2AMD :: struct { sType: StructureType, pNext: rawptr, @@ -4148,16 +4416,6 @@ BufferDeviceAddressCreateInfoEXT :: struct { deviceAddress: DeviceAddress, } -PhysicalDeviceToolPropertiesEXT :: struct { - sType: StructureType, - pNext: rawptr, - name: [MAX_EXTENSION_NAME_SIZE]byte, - version: [MAX_EXTENSION_NAME_SIZE]byte, - purposes: ToolPurposeFlagsEXT, - description: [MAX_DESCRIPTION_SIZE]byte, - layer: [MAX_EXTENSION_NAME_SIZE]byte, -} - ValidationFeaturesEXT :: struct { sType: StructureType, pNext: rawptr, @@ -4327,12 +4585,6 @@ PhysicalDeviceShaderAtomicFloat2FeaturesEXT :: struct { sparseImageFloat32AtomicMinMax: b32, } -PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - shaderDemoteToHelperInvocation: b32, -} - PhysicalDeviceDeviceGeneratedCommandsPropertiesNV :: struct { sType: StructureType, pNext: rawptr, @@ -4472,15 +4724,6 @@ PhysicalDeviceTexelBufferAlignmentFeaturesEXT :: struct { texelBufferAlignment: b32, } -PhysicalDeviceTexelBufferAlignmentPropertiesEXT :: struct { - sType: StructureType, - pNext: rawptr, - storageTexelBufferOffsetAlignmentBytes: DeviceSize, - storageTexelBufferOffsetSingleTexelAlignment: b32, - uniformTexelBufferOffsetAlignmentBytes: DeviceSize, - uniformTexelBufferOffsetSingleTexelAlignment: b32, -} - RenderPassTransformBeginInfoQCOM :: struct { sType: StructureType, pNext: rawptr, @@ -4555,30 +4798,6 @@ PhysicalDeviceCustomBorderColorFeaturesEXT :: struct { customBorderColorWithoutFormat: b32, } -PhysicalDevicePrivateDataFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - privateData: b32, -} - -DevicePrivateDataCreateInfoEXT :: struct { - sType: StructureType, - pNext: rawptr, - privateDataSlotRequestCount: u32, -} - -PrivateDataSlotCreateInfoEXT :: struct { - sType: StructureType, - pNext: rawptr, - flags: PrivateDataSlotCreateFlagsEXT, -} - -PhysicalDevicePipelineCreationCacheControlFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - pipelineCreationCacheControl: b32, -} - PhysicalDeviceDiagnosticsConfigFeaturesNV :: struct { sType: StructureType, pNext: rawptr, @@ -4591,6 +4810,25 @@ DeviceDiagnosticsConfigCreateInfoNV :: struct { flags: DeviceDiagnosticsConfigFlagsNV, } +PhysicalDeviceGraphicsPipelineLibraryFeaturesEXT :: struct { + sType: StructureType, + pNext: rawptr, + graphicsPipelineLibrary: b32, +} + +PhysicalDeviceGraphicsPipelineLibraryPropertiesEXT :: struct { + sType: StructureType, + pNext: rawptr, + graphicsPipelineLibraryFastLinking: b32, + graphicsPipelineLibraryIndependentInterpolationDecoration: b32, +} + +GraphicsPipelineLibraryCreateInfoEXT :: struct { + sType: StructureType, + pNext: rawptr, + flags: GraphicsPipelineLibraryFlagsEXT, +} + PhysicalDeviceFragmentShadingRateEnumsFeaturesNV :: struct { sType: StructureType, pNext: rawptr, @@ -4708,12 +4946,6 @@ CopyCommandTransformInfoQCOM :: struct { transform: SurfaceTransformFlagsKHR, } -PhysicalDeviceImageRobustnessFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - robustImageAccess: b32, -} - PhysicalDevice4444FormatsFeaturesEXT :: struct { sType: StructureType, pNext: rawptr, @@ -4721,6 +4953,20 @@ PhysicalDevice4444FormatsFeaturesEXT :: struct { formatA4B4G4R4: b32, } +PhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM :: struct { + sType: StructureType, + pNext: rawptr, + rasterizationOrderColorAttachmentAccess: b32, + rasterizationOrderDepthAttachmentAccess: b32, + rasterizationOrderStencilAttachmentAccess: b32, +} + +PhysicalDeviceRGBA10X6FormatsFeaturesEXT :: struct { + sType: StructureType, + pNext: rawptr, + formatRgba10x6WithoutYCbCrSampler: b32, +} + PhysicalDeviceMutableDescriptorTypeFeaturesVALVE :: struct { sType: StructureType, pNext: rawptr, @@ -4774,6 +5020,18 @@ PhysicalDeviceDrmPropertiesEXT :: struct { renderMinor: i64, } +PhysicalDeviceDepthClipControlFeaturesEXT :: struct { + sType: StructureType, + pNext: rawptr, + depthClipControl: b32, +} + +PipelineViewportDepthClipControlCreateInfoEXT :: struct { + sType: StructureType, + pNext: rawptr, + negativeOneToOne: b32, +} + PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT :: struct { sType: StructureType, pNext: rawptr, @@ -4840,17 +5098,24 @@ PipelineColorWriteCreateInfoEXT :: struct { pColorWriteEnables: [^]b32, } -PhysicalDeviceGlobalPriorityQueryFeaturesEXT :: struct { - sType: StructureType, - pNext: rawptr, - globalPriorityQuery: b32, +PhysicalDevicePrimitivesGeneratedQueryFeaturesEXT :: struct { + sType: StructureType, + pNext: rawptr, + primitivesGeneratedQuery: b32, + primitivesGeneratedQueryWithRasterizerDiscard: b32, + primitivesGeneratedQueryWithNonZeroStreams: b32, } -QueueFamilyGlobalPriorityPropertiesEXT :: struct { - sType: StructureType, - pNext: rawptr, - priorityCount: u32, - priorities: [MAX_GLOBAL_PRIORITY_SIZE_EXT]QueueGlobalPriorityEXT, +PhysicalDeviceImageViewMinLodFeaturesEXT :: struct { + sType: StructureType, + pNext: rawptr, + minLod: b32, +} + +ImageViewMinLodCreateInfoEXT :: struct { + sType: StructureType, + pNext: rawptr, + minLod: f32, } PhysicalDeviceMultiDrawFeaturesEXT :: struct { @@ -4876,12 +5141,78 @@ MultiDrawIndexedInfoEXT :: struct { vertexOffset: i32, } +PhysicalDeviceImage2DViewOf3DFeaturesEXT :: struct { + sType: StructureType, + pNext: rawptr, + image2DViewOf3D: b32, + sampler2DViewOf3D: b32, +} + +PhysicalDeviceBorderColorSwizzleFeaturesEXT :: struct { + sType: StructureType, + pNext: rawptr, + borderColorSwizzle: b32, + borderColorSwizzleFromImage: b32, +} + +SamplerBorderColorComponentMappingCreateInfoEXT :: struct { + sType: StructureType, + pNext: rawptr, + components: ComponentMapping, + srgb: b32, +} + PhysicalDevicePageableDeviceLocalMemoryFeaturesEXT :: struct { sType: StructureType, pNext: rawptr, pageableDeviceLocalMemory: b32, } +PhysicalDeviceDescriptorSetHostMappingFeaturesVALVE :: struct { + sType: StructureType, + pNext: rawptr, + descriptorSetHostMapping: b32, +} + +DescriptorSetBindingReferenceVALVE :: struct { + sType: StructureType, + pNext: rawptr, + descriptorSetLayout: DescriptorSetLayout, + binding: u32, +} + +DescriptorSetLayoutHostMappingInfoVALVE :: struct { + sType: StructureType, + pNext: rawptr, + descriptorOffset: int, + descriptorSize: u32, +} + +PhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM :: struct { + sType: StructureType, + pNext: rawptr, + fragmentDensityMapOffset: b32, +} + +PhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM :: struct { + sType: StructureType, + pNext: rawptr, + fragmentDensityOffsetGranularity: Extent2D, +} + +SubpassFragmentDensityMapOffsetEndInfoQCOM :: struct { + sType: StructureType, + pNext: rawptr, + fragmentDensityOffsetCount: u32, + pFragmentDensityOffsets: [^]Offset2D, +} + +PhysicalDeviceLinearColorAttachmentFeaturesNV :: struct { + sType: StructureType, + pNext: rawptr, + linearColorAttachment: b32, +} + DeviceOrHostAddressKHR :: struct #raw_union { deviceAddress: DeviceAddress, hostAddress: rawptr, @@ -5283,178 +5614,252 @@ IOSSurfaceCreateInfoMVK :: struct { } // Aliases -PhysicalDeviceVariablePointerFeatures :: PhysicalDeviceVariablePointersFeatures -PhysicalDeviceShaderDrawParameterFeatures :: PhysicalDeviceShaderDrawParametersFeatures -RenderPassMultiviewCreateInfoKHR :: RenderPassMultiviewCreateInfo -PhysicalDeviceMultiviewFeaturesKHR :: PhysicalDeviceMultiviewFeatures -PhysicalDeviceMultiviewPropertiesKHR :: PhysicalDeviceMultiviewProperties -PhysicalDeviceFeatures2KHR :: PhysicalDeviceFeatures2 -PhysicalDeviceProperties2KHR :: PhysicalDeviceProperties2 -FormatProperties2KHR :: FormatProperties2 -ImageFormatProperties2KHR :: ImageFormatProperties2 -PhysicalDeviceImageFormatInfo2KHR :: PhysicalDeviceImageFormatInfo2 -QueueFamilyProperties2KHR :: QueueFamilyProperties2 -PhysicalDeviceMemoryProperties2KHR :: PhysicalDeviceMemoryProperties2 -SparseImageFormatProperties2KHR :: SparseImageFormatProperties2 -PhysicalDeviceSparseImageFormatInfo2KHR :: PhysicalDeviceSparseImageFormatInfo2 -PeerMemoryFeatureFlagsKHR :: PeerMemoryFeatureFlags -PeerMemoryFeatureFlagKHR :: PeerMemoryFeatureFlag -MemoryAllocateFlagsKHR :: MemoryAllocateFlags -MemoryAllocateFlagKHR :: MemoryAllocateFlag -MemoryAllocateFlagsInfoKHR :: MemoryAllocateFlagsInfo -DeviceGroupRenderPassBeginInfoKHR :: DeviceGroupRenderPassBeginInfo -DeviceGroupCommandBufferBeginInfoKHR :: DeviceGroupCommandBufferBeginInfo -DeviceGroupSubmitInfoKHR :: DeviceGroupSubmitInfo -DeviceGroupBindSparseInfoKHR :: DeviceGroupBindSparseInfo -BindBufferMemoryDeviceGroupInfoKHR :: BindBufferMemoryDeviceGroupInfo -BindImageMemoryDeviceGroupInfoKHR :: BindImageMemoryDeviceGroupInfo -CommandPoolTrimFlagsKHR :: CommandPoolTrimFlags -PhysicalDeviceGroupPropertiesKHR :: PhysicalDeviceGroupProperties -DeviceGroupDeviceCreateInfoKHR :: DeviceGroupDeviceCreateInfo -ExternalMemoryHandleTypeFlagsKHR :: ExternalMemoryHandleTypeFlags -ExternalMemoryHandleTypeFlagKHR :: ExternalMemoryHandleTypeFlag -ExternalMemoryFeatureFlagsKHR :: ExternalMemoryFeatureFlags -ExternalMemoryFeatureFlagKHR :: ExternalMemoryFeatureFlag -ExternalMemoryPropertiesKHR :: ExternalMemoryProperties -PhysicalDeviceExternalImageFormatInfoKHR :: PhysicalDeviceExternalImageFormatInfo -ExternalImageFormatPropertiesKHR :: ExternalImageFormatProperties -PhysicalDeviceExternalBufferInfoKHR :: PhysicalDeviceExternalBufferInfo -ExternalBufferPropertiesKHR :: ExternalBufferProperties -PhysicalDeviceIDPropertiesKHR :: PhysicalDeviceIDProperties -ExternalMemoryImageCreateInfoKHR :: ExternalMemoryImageCreateInfo -ExternalMemoryBufferCreateInfoKHR :: ExternalMemoryBufferCreateInfo -ExportMemoryAllocateInfoKHR :: ExportMemoryAllocateInfo -ExternalSemaphoreHandleTypeFlagsKHR :: ExternalSemaphoreHandleTypeFlags -ExternalSemaphoreHandleTypeFlagKHR :: ExternalSemaphoreHandleTypeFlag -ExternalSemaphoreFeatureFlagsKHR :: ExternalSemaphoreFeatureFlags -ExternalSemaphoreFeatureFlagKHR :: ExternalSemaphoreFeatureFlag -PhysicalDeviceExternalSemaphoreInfoKHR :: PhysicalDeviceExternalSemaphoreInfo -ExternalSemaphorePropertiesKHR :: ExternalSemaphoreProperties -SemaphoreImportFlagsKHR :: SemaphoreImportFlags -SemaphoreImportFlagKHR :: SemaphoreImportFlag -ExportSemaphoreCreateInfoKHR :: ExportSemaphoreCreateInfo -PhysicalDeviceShaderFloat16Int8FeaturesKHR :: PhysicalDeviceShaderFloat16Int8Features -PhysicalDeviceFloat16Int8FeaturesKHR :: PhysicalDeviceShaderFloat16Int8Features -PhysicalDevice16BitStorageFeaturesKHR :: PhysicalDevice16BitStorageFeatures -DescriptorUpdateTemplateKHR :: DescriptorUpdateTemplate -DescriptorUpdateTemplateTypeKHR :: DescriptorUpdateTemplateType -DescriptorUpdateTemplateCreateFlagsKHR :: DescriptorUpdateTemplateCreateFlags -DescriptorUpdateTemplateEntryKHR :: DescriptorUpdateTemplateEntry -DescriptorUpdateTemplateCreateInfoKHR :: DescriptorUpdateTemplateCreateInfo -PhysicalDeviceImagelessFramebufferFeaturesKHR :: PhysicalDeviceImagelessFramebufferFeatures -FramebufferAttachmentsCreateInfoKHR :: FramebufferAttachmentsCreateInfo -FramebufferAttachmentImageInfoKHR :: FramebufferAttachmentImageInfo -RenderPassAttachmentBeginInfoKHR :: RenderPassAttachmentBeginInfo -RenderPassCreateInfo2KHR :: RenderPassCreateInfo2 -AttachmentDescription2KHR :: AttachmentDescription2 -AttachmentReference2KHR :: AttachmentReference2 -SubpassDescription2KHR :: SubpassDescription2 -SubpassDependency2KHR :: SubpassDependency2 -SubpassBeginInfoKHR :: SubpassBeginInfo -SubpassEndInfoKHR :: SubpassEndInfo -ExternalFenceHandleTypeFlagsKHR :: ExternalFenceHandleTypeFlags -ExternalFenceHandleTypeFlagKHR :: ExternalFenceHandleTypeFlag -ExternalFenceFeatureFlagsKHR :: ExternalFenceFeatureFlags -ExternalFenceFeatureFlagKHR :: ExternalFenceFeatureFlag -PhysicalDeviceExternalFenceInfoKHR :: PhysicalDeviceExternalFenceInfo -ExternalFencePropertiesKHR :: ExternalFenceProperties -FenceImportFlagsKHR :: FenceImportFlags -FenceImportFlagKHR :: FenceImportFlag -ExportFenceCreateInfoKHR :: ExportFenceCreateInfo -PointClippingBehaviorKHR :: PointClippingBehavior -TessellationDomainOriginKHR :: TessellationDomainOrigin -PhysicalDevicePointClippingPropertiesKHR :: PhysicalDevicePointClippingProperties -RenderPassInputAttachmentAspectCreateInfoKHR :: RenderPassInputAttachmentAspectCreateInfo -InputAttachmentAspectReferenceKHR :: InputAttachmentAspectReference -ImageViewUsageCreateInfoKHR :: ImageViewUsageCreateInfo -PipelineTessellationDomainOriginStateCreateInfoKHR :: PipelineTessellationDomainOriginStateCreateInfo -PhysicalDeviceVariablePointerFeaturesKHR :: PhysicalDeviceVariablePointersFeatures -PhysicalDeviceVariablePointersFeaturesKHR :: PhysicalDeviceVariablePointersFeatures -MemoryDedicatedRequirementsKHR :: MemoryDedicatedRequirements -MemoryDedicatedAllocateInfoKHR :: MemoryDedicatedAllocateInfo -BufferMemoryRequirementsInfo2KHR :: BufferMemoryRequirementsInfo2 -ImageMemoryRequirementsInfo2KHR :: ImageMemoryRequirementsInfo2 -ImageSparseMemoryRequirementsInfo2KHR :: ImageSparseMemoryRequirementsInfo2 -MemoryRequirements2KHR :: MemoryRequirements2 -SparseImageMemoryRequirements2KHR :: SparseImageMemoryRequirements2 -ImageFormatListCreateInfoKHR :: ImageFormatListCreateInfo -SamplerYcbcrConversionKHR :: SamplerYcbcrConversion -SamplerYcbcrModelConversionKHR :: SamplerYcbcrModelConversion -SamplerYcbcrRangeKHR :: SamplerYcbcrRange -ChromaLocationKHR :: ChromaLocation -SamplerYcbcrConversionCreateInfoKHR :: SamplerYcbcrConversionCreateInfo -SamplerYcbcrConversionInfoKHR :: SamplerYcbcrConversionInfo -BindImagePlaneMemoryInfoKHR :: BindImagePlaneMemoryInfo -ImagePlaneMemoryRequirementsInfoKHR :: ImagePlaneMemoryRequirementsInfo -PhysicalDeviceSamplerYcbcrConversionFeaturesKHR :: PhysicalDeviceSamplerYcbcrConversionFeatures -SamplerYcbcrConversionImageFormatPropertiesKHR :: SamplerYcbcrConversionImageFormatProperties -BindBufferMemoryInfoKHR :: BindBufferMemoryInfo -BindImageMemoryInfoKHR :: BindImageMemoryInfo -PhysicalDeviceMaintenance3PropertiesKHR :: PhysicalDeviceMaintenance3Properties -DescriptorSetLayoutSupportKHR :: DescriptorSetLayoutSupport -PhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR :: PhysicalDeviceShaderSubgroupExtendedTypesFeatures -PhysicalDevice8BitStorageFeaturesKHR :: PhysicalDevice8BitStorageFeatures -PhysicalDeviceShaderAtomicInt64FeaturesKHR :: PhysicalDeviceShaderAtomicInt64Features -DriverIdKHR :: DriverId -ConformanceVersionKHR :: ConformanceVersion -PhysicalDeviceDriverPropertiesKHR :: PhysicalDeviceDriverProperties -ShaderFloatControlsIndependenceKHR :: ShaderFloatControlsIndependence -PhysicalDeviceFloatControlsPropertiesKHR :: PhysicalDeviceFloatControlsProperties -ResolveModeFlagKHR :: ResolveModeFlag -ResolveModeFlagsKHR :: ResolveModeFlags -SubpassDescriptionDepthStencilResolveKHR :: SubpassDescriptionDepthStencilResolve -PhysicalDeviceDepthStencilResolvePropertiesKHR :: PhysicalDeviceDepthStencilResolveProperties -SemaphoreTypeKHR :: SemaphoreType -SemaphoreWaitFlagKHR :: SemaphoreWaitFlag -SemaphoreWaitFlagsKHR :: SemaphoreWaitFlags -PhysicalDeviceTimelineSemaphoreFeaturesKHR :: PhysicalDeviceTimelineSemaphoreFeatures -PhysicalDeviceTimelineSemaphorePropertiesKHR :: PhysicalDeviceTimelineSemaphoreProperties -SemaphoreTypeCreateInfoKHR :: SemaphoreTypeCreateInfo -TimelineSemaphoreSubmitInfoKHR :: TimelineSemaphoreSubmitInfo -SemaphoreWaitInfoKHR :: SemaphoreWaitInfo -SemaphoreSignalInfoKHR :: SemaphoreSignalInfo -PhysicalDeviceVulkanMemoryModelFeaturesKHR :: PhysicalDeviceVulkanMemoryModelFeatures -PhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR :: PhysicalDeviceSeparateDepthStencilLayoutsFeatures -AttachmentReferenceStencilLayoutKHR :: AttachmentReferenceStencilLayout -AttachmentDescriptionStencilLayoutKHR :: AttachmentDescriptionStencilLayout -PhysicalDeviceUniformBufferStandardLayoutFeaturesKHR :: PhysicalDeviceUniformBufferStandardLayoutFeatures -PhysicalDeviceBufferDeviceAddressFeaturesKHR :: PhysicalDeviceBufferDeviceAddressFeatures -BufferDeviceAddressInfoKHR :: BufferDeviceAddressInfo -BufferOpaqueCaptureAddressCreateInfoKHR :: BufferOpaqueCaptureAddressCreateInfo -MemoryOpaqueCaptureAddressAllocateInfoKHR :: MemoryOpaqueCaptureAddressAllocateInfo -DeviceMemoryOpaqueCaptureAddressInfoKHR :: DeviceMemoryOpaqueCaptureAddressInfo -PipelineStageFlags2KHR :: Flags64 -PipelineStageFlag2KHR :: Flags64 -AccessFlags2KHR :: Flags64 -AccessFlag2KHR :: Flags64 -SamplerReductionModeEXT :: SamplerReductionMode -SamplerReductionModeCreateInfoEXT :: SamplerReductionModeCreateInfo -PhysicalDeviceSamplerFilterMinmaxPropertiesEXT :: PhysicalDeviceSamplerFilterMinmaxProperties -DescriptorBindingFlagEXT :: DescriptorBindingFlag -DescriptorBindingFlagsEXT :: DescriptorBindingFlags -DescriptorSetLayoutBindingFlagsCreateInfoEXT :: DescriptorSetLayoutBindingFlagsCreateInfo -PhysicalDeviceDescriptorIndexingFeaturesEXT :: PhysicalDeviceDescriptorIndexingFeatures -PhysicalDeviceDescriptorIndexingPropertiesEXT :: PhysicalDeviceDescriptorIndexingProperties -DescriptorSetVariableDescriptorCountAllocateInfoEXT :: DescriptorSetVariableDescriptorCountAllocateInfo -DescriptorSetVariableDescriptorCountLayoutSupportEXT :: DescriptorSetVariableDescriptorCountLayoutSupport -RayTracingShaderGroupTypeNV :: RayTracingShaderGroupTypeKHR -GeometryTypeNV :: GeometryTypeKHR -AccelerationStructureTypeNV :: AccelerationStructureTypeKHR -CopyAccelerationStructureModeNV :: CopyAccelerationStructureModeKHR -GeometryFlagsNV :: GeometryFlagsKHR -GeometryFlagNV :: GeometryFlagKHR -GeometryInstanceFlagsNV :: GeometryInstanceFlagsKHR -GeometryInstanceFlagNV :: GeometryInstanceFlagKHR -BuildAccelerationStructureFlagsNV :: BuildAccelerationStructureFlagsKHR -BuildAccelerationStructureFlagNV :: BuildAccelerationStructureFlagKHR -TransformMatrixNV :: TransformMatrixKHR -AabbPositionsNV :: AabbPositionsKHR -AccelerationStructureInstanceNV :: AccelerationStructureInstanceKHR -QueryPoolCreateInfoINTEL :: QueryPoolPerformanceQueryCreateInfoINTEL -PhysicalDeviceScalarBlockLayoutFeaturesEXT :: PhysicalDeviceScalarBlockLayoutFeatures -PhysicalDeviceBufferAddressFeaturesEXT :: PhysicalDeviceBufferDeviceAddressFeaturesEXT -BufferDeviceAddressInfoEXT :: BufferDeviceAddressInfo -ImageStencilUsageCreateInfoEXT :: ImageStencilUsageCreateInfo -PhysicalDeviceHostQueryResetFeaturesEXT :: PhysicalDeviceHostQueryResetFeatures +PhysicalDeviceVariablePointerFeatures :: PhysicalDeviceVariablePointersFeatures +PhysicalDeviceShaderDrawParameterFeatures :: PhysicalDeviceShaderDrawParametersFeatures +PipelineStageFlags2 :: Flags64 +PipelineStageFlag2 :: Flags64 +AccessFlags2 :: Flags64 +AccessFlag2 :: Flags64 +FormatFeatureFlags2 :: Flags64 +FormatFeatureFlag2 :: Flags64 +RenderingFlagsKHR :: RenderingFlags +RenderingFlagKHR :: RenderingFlag +RenderingInfoKHR :: RenderingInfo +RenderingAttachmentInfoKHR :: RenderingAttachmentInfo +PipelineRenderingCreateInfoKHR :: PipelineRenderingCreateInfo +PhysicalDeviceDynamicRenderingFeaturesKHR :: PhysicalDeviceDynamicRenderingFeatures +CommandBufferInheritanceRenderingInfoKHR :: CommandBufferInheritanceRenderingInfo +AttachmentSampleCountInfoNV :: AttachmentSampleCountInfoAMD +RenderPassMultiviewCreateInfoKHR :: RenderPassMultiviewCreateInfo +PhysicalDeviceMultiviewFeaturesKHR :: PhysicalDeviceMultiviewFeatures +PhysicalDeviceMultiviewPropertiesKHR :: PhysicalDeviceMultiviewProperties +PhysicalDeviceFeatures2KHR :: PhysicalDeviceFeatures2 +PhysicalDeviceProperties2KHR :: PhysicalDeviceProperties2 +FormatProperties2KHR :: FormatProperties2 +ImageFormatProperties2KHR :: ImageFormatProperties2 +PhysicalDeviceImageFormatInfo2KHR :: PhysicalDeviceImageFormatInfo2 +QueueFamilyProperties2KHR :: QueueFamilyProperties2 +PhysicalDeviceMemoryProperties2KHR :: PhysicalDeviceMemoryProperties2 +SparseImageFormatProperties2KHR :: SparseImageFormatProperties2 +PhysicalDeviceSparseImageFormatInfo2KHR :: PhysicalDeviceSparseImageFormatInfo2 +PeerMemoryFeatureFlagsKHR :: PeerMemoryFeatureFlags +PeerMemoryFeatureFlagKHR :: PeerMemoryFeatureFlag +MemoryAllocateFlagsKHR :: MemoryAllocateFlags +MemoryAllocateFlagKHR :: MemoryAllocateFlag +MemoryAllocateFlagsInfoKHR :: MemoryAllocateFlagsInfo +DeviceGroupRenderPassBeginInfoKHR :: DeviceGroupRenderPassBeginInfo +DeviceGroupCommandBufferBeginInfoKHR :: DeviceGroupCommandBufferBeginInfo +DeviceGroupSubmitInfoKHR :: DeviceGroupSubmitInfo +DeviceGroupBindSparseInfoKHR :: DeviceGroupBindSparseInfo +BindBufferMemoryDeviceGroupInfoKHR :: BindBufferMemoryDeviceGroupInfo +BindImageMemoryDeviceGroupInfoKHR :: BindImageMemoryDeviceGroupInfo +CommandPoolTrimFlagsKHR :: CommandPoolTrimFlags +PhysicalDeviceGroupPropertiesKHR :: PhysicalDeviceGroupProperties +DeviceGroupDeviceCreateInfoKHR :: DeviceGroupDeviceCreateInfo +ExternalMemoryHandleTypeFlagsKHR :: ExternalMemoryHandleTypeFlags +ExternalMemoryHandleTypeFlagKHR :: ExternalMemoryHandleTypeFlag +ExternalMemoryFeatureFlagsKHR :: ExternalMemoryFeatureFlags +ExternalMemoryFeatureFlagKHR :: ExternalMemoryFeatureFlag +ExternalMemoryPropertiesKHR :: ExternalMemoryProperties +PhysicalDeviceExternalImageFormatInfoKHR :: PhysicalDeviceExternalImageFormatInfo +ExternalImageFormatPropertiesKHR :: ExternalImageFormatProperties +PhysicalDeviceExternalBufferInfoKHR :: PhysicalDeviceExternalBufferInfo +ExternalBufferPropertiesKHR :: ExternalBufferProperties +PhysicalDeviceIDPropertiesKHR :: PhysicalDeviceIDProperties +ExternalMemoryImageCreateInfoKHR :: ExternalMemoryImageCreateInfo +ExternalMemoryBufferCreateInfoKHR :: ExternalMemoryBufferCreateInfo +ExportMemoryAllocateInfoKHR :: ExportMemoryAllocateInfo +ExternalSemaphoreHandleTypeFlagsKHR :: ExternalSemaphoreHandleTypeFlags +ExternalSemaphoreHandleTypeFlagKHR :: ExternalSemaphoreHandleTypeFlag +ExternalSemaphoreFeatureFlagsKHR :: ExternalSemaphoreFeatureFlags +ExternalSemaphoreFeatureFlagKHR :: ExternalSemaphoreFeatureFlag +PhysicalDeviceExternalSemaphoreInfoKHR :: PhysicalDeviceExternalSemaphoreInfo +ExternalSemaphorePropertiesKHR :: ExternalSemaphoreProperties +SemaphoreImportFlagsKHR :: SemaphoreImportFlags +SemaphoreImportFlagKHR :: SemaphoreImportFlag +ExportSemaphoreCreateInfoKHR :: ExportSemaphoreCreateInfo +PhysicalDeviceShaderFloat16Int8FeaturesKHR :: PhysicalDeviceShaderFloat16Int8Features +PhysicalDeviceFloat16Int8FeaturesKHR :: PhysicalDeviceShaderFloat16Int8Features +PhysicalDevice16BitStorageFeaturesKHR :: PhysicalDevice16BitStorageFeatures +DescriptorUpdateTemplateKHR :: DescriptorUpdateTemplate +DescriptorUpdateTemplateTypeKHR :: DescriptorUpdateTemplateType +DescriptorUpdateTemplateCreateFlagsKHR :: DescriptorUpdateTemplateCreateFlags +DescriptorUpdateTemplateEntryKHR :: DescriptorUpdateTemplateEntry +DescriptorUpdateTemplateCreateInfoKHR :: DescriptorUpdateTemplateCreateInfo +PhysicalDeviceImagelessFramebufferFeaturesKHR :: PhysicalDeviceImagelessFramebufferFeatures +FramebufferAttachmentsCreateInfoKHR :: FramebufferAttachmentsCreateInfo +FramebufferAttachmentImageInfoKHR :: FramebufferAttachmentImageInfo +RenderPassAttachmentBeginInfoKHR :: RenderPassAttachmentBeginInfo +RenderPassCreateInfo2KHR :: RenderPassCreateInfo2 +AttachmentDescription2KHR :: AttachmentDescription2 +AttachmentReference2KHR :: AttachmentReference2 +SubpassDescription2KHR :: SubpassDescription2 +SubpassDependency2KHR :: SubpassDependency2 +SubpassBeginInfoKHR :: SubpassBeginInfo +SubpassEndInfoKHR :: SubpassEndInfo +ExternalFenceHandleTypeFlagsKHR :: ExternalFenceHandleTypeFlags +ExternalFenceHandleTypeFlagKHR :: ExternalFenceHandleTypeFlag +ExternalFenceFeatureFlagsKHR :: ExternalFenceFeatureFlags +ExternalFenceFeatureFlagKHR :: ExternalFenceFeatureFlag +PhysicalDeviceExternalFenceInfoKHR :: PhysicalDeviceExternalFenceInfo +ExternalFencePropertiesKHR :: ExternalFenceProperties +FenceImportFlagsKHR :: FenceImportFlags +FenceImportFlagKHR :: FenceImportFlag +ExportFenceCreateInfoKHR :: ExportFenceCreateInfo +PointClippingBehaviorKHR :: PointClippingBehavior +TessellationDomainOriginKHR :: TessellationDomainOrigin +PhysicalDevicePointClippingPropertiesKHR :: PhysicalDevicePointClippingProperties +RenderPassInputAttachmentAspectCreateInfoKHR :: RenderPassInputAttachmentAspectCreateInfo +InputAttachmentAspectReferenceKHR :: InputAttachmentAspectReference +ImageViewUsageCreateInfoKHR :: ImageViewUsageCreateInfo +PipelineTessellationDomainOriginStateCreateInfoKHR :: PipelineTessellationDomainOriginStateCreateInfo +PhysicalDeviceVariablePointerFeaturesKHR :: PhysicalDeviceVariablePointersFeatures +PhysicalDeviceVariablePointersFeaturesKHR :: PhysicalDeviceVariablePointersFeatures +MemoryDedicatedRequirementsKHR :: MemoryDedicatedRequirements +MemoryDedicatedAllocateInfoKHR :: MemoryDedicatedAllocateInfo +BufferMemoryRequirementsInfo2KHR :: BufferMemoryRequirementsInfo2 +ImageMemoryRequirementsInfo2KHR :: ImageMemoryRequirementsInfo2 +ImageSparseMemoryRequirementsInfo2KHR :: ImageSparseMemoryRequirementsInfo2 +MemoryRequirements2KHR :: MemoryRequirements2 +SparseImageMemoryRequirements2KHR :: SparseImageMemoryRequirements2 +ImageFormatListCreateInfoKHR :: ImageFormatListCreateInfo +SamplerYcbcrConversionKHR :: SamplerYcbcrConversion +SamplerYcbcrModelConversionKHR :: SamplerYcbcrModelConversion +SamplerYcbcrRangeKHR :: SamplerYcbcrRange +ChromaLocationKHR :: ChromaLocation +SamplerYcbcrConversionCreateInfoKHR :: SamplerYcbcrConversionCreateInfo +SamplerYcbcrConversionInfoKHR :: SamplerYcbcrConversionInfo +BindImagePlaneMemoryInfoKHR :: BindImagePlaneMemoryInfo +ImagePlaneMemoryRequirementsInfoKHR :: ImagePlaneMemoryRequirementsInfo +PhysicalDeviceSamplerYcbcrConversionFeaturesKHR :: PhysicalDeviceSamplerYcbcrConversionFeatures +SamplerYcbcrConversionImageFormatPropertiesKHR :: SamplerYcbcrConversionImageFormatProperties +BindBufferMemoryInfoKHR :: BindBufferMemoryInfo +BindImageMemoryInfoKHR :: BindImageMemoryInfo +PhysicalDeviceMaintenance3PropertiesKHR :: PhysicalDeviceMaintenance3Properties +DescriptorSetLayoutSupportKHR :: DescriptorSetLayoutSupport +PhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR :: PhysicalDeviceShaderSubgroupExtendedTypesFeatures +PhysicalDevice8BitStorageFeaturesKHR :: PhysicalDevice8BitStorageFeatures +PhysicalDeviceShaderAtomicInt64FeaturesKHR :: PhysicalDeviceShaderAtomicInt64Features +DriverIdKHR :: DriverId +ConformanceVersionKHR :: ConformanceVersion +PhysicalDeviceDriverPropertiesKHR :: PhysicalDeviceDriverProperties +ShaderFloatControlsIndependenceKHR :: ShaderFloatControlsIndependence +PhysicalDeviceFloatControlsPropertiesKHR :: PhysicalDeviceFloatControlsProperties +ResolveModeFlagKHR :: ResolveModeFlag +ResolveModeFlagsKHR :: ResolveModeFlags +SubpassDescriptionDepthStencilResolveKHR :: SubpassDescriptionDepthStencilResolve +PhysicalDeviceDepthStencilResolvePropertiesKHR :: PhysicalDeviceDepthStencilResolveProperties +SemaphoreTypeKHR :: SemaphoreType +SemaphoreWaitFlagKHR :: SemaphoreWaitFlag +SemaphoreWaitFlagsKHR :: SemaphoreWaitFlags +PhysicalDeviceTimelineSemaphoreFeaturesKHR :: PhysicalDeviceTimelineSemaphoreFeatures +PhysicalDeviceTimelineSemaphorePropertiesKHR :: PhysicalDeviceTimelineSemaphoreProperties +SemaphoreTypeCreateInfoKHR :: SemaphoreTypeCreateInfo +TimelineSemaphoreSubmitInfoKHR :: TimelineSemaphoreSubmitInfo +SemaphoreWaitInfoKHR :: SemaphoreWaitInfo +SemaphoreSignalInfoKHR :: SemaphoreSignalInfo +PhysicalDeviceVulkanMemoryModelFeaturesKHR :: PhysicalDeviceVulkanMemoryModelFeatures +PhysicalDeviceShaderTerminateInvocationFeaturesKHR :: PhysicalDeviceShaderTerminateInvocationFeatures +PhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR :: PhysicalDeviceSeparateDepthStencilLayoutsFeatures +AttachmentReferenceStencilLayoutKHR :: AttachmentReferenceStencilLayout +AttachmentDescriptionStencilLayoutKHR :: AttachmentDescriptionStencilLayout +PhysicalDeviceUniformBufferStandardLayoutFeaturesKHR :: PhysicalDeviceUniformBufferStandardLayoutFeatures +PhysicalDeviceBufferDeviceAddressFeaturesKHR :: PhysicalDeviceBufferDeviceAddressFeatures +BufferDeviceAddressInfoKHR :: BufferDeviceAddressInfo +BufferOpaqueCaptureAddressCreateInfoKHR :: BufferOpaqueCaptureAddressCreateInfo +MemoryOpaqueCaptureAddressAllocateInfoKHR :: MemoryOpaqueCaptureAddressAllocateInfo +DeviceMemoryOpaqueCaptureAddressInfoKHR :: DeviceMemoryOpaqueCaptureAddressInfo +PhysicalDeviceShaderIntegerDotProductFeaturesKHR :: PhysicalDeviceShaderIntegerDotProductFeatures +PhysicalDeviceShaderIntegerDotProductPropertiesKHR :: PhysicalDeviceShaderIntegerDotProductProperties +PipelineStageFlags2KHR :: PipelineStageFlags2 +PipelineStageFlag2KHR :: PipelineStageFlag2 +AccessFlags2KHR :: AccessFlags2 +AccessFlag2KHR :: AccessFlag2 +SubmitFlagKHR :: SubmitFlag +SubmitFlagsKHR :: SubmitFlags +MemoryBarrier2KHR :: MemoryBarrier2 +BufferMemoryBarrier2KHR :: BufferMemoryBarrier2 +ImageMemoryBarrier2KHR :: ImageMemoryBarrier2 +DependencyInfoKHR :: DependencyInfo +SubmitInfo2KHR :: SubmitInfo2 +SemaphoreSubmitInfoKHR :: SemaphoreSubmitInfo +CommandBufferSubmitInfoKHR :: CommandBufferSubmitInfo +PhysicalDeviceSynchronization2FeaturesKHR :: PhysicalDeviceSynchronization2Features +PhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR :: PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures +CopyBufferInfo2KHR :: CopyBufferInfo2 +CopyImageInfo2KHR :: CopyImageInfo2 +CopyBufferToImageInfo2KHR :: CopyBufferToImageInfo2 +CopyImageToBufferInfo2KHR :: CopyImageToBufferInfo2 +BlitImageInfo2KHR :: BlitImageInfo2 +ResolveImageInfo2KHR :: ResolveImageInfo2 +BufferCopy2KHR :: BufferCopy2 +ImageCopy2KHR :: ImageCopy2 +ImageBlit2KHR :: ImageBlit2 +BufferImageCopy2KHR :: BufferImageCopy2 +ImageResolve2KHR :: ImageResolve2 +FormatFeatureFlags2KHR :: FormatFeatureFlags2 +FormatFeatureFlag2KHR :: FormatFeatureFlag2 +FormatProperties3KHR :: FormatProperties3 +PhysicalDeviceMaintenance4FeaturesKHR :: PhysicalDeviceMaintenance4Features +PhysicalDeviceMaintenance4PropertiesKHR :: PhysicalDeviceMaintenance4Properties +DeviceBufferMemoryRequirementsKHR :: DeviceBufferMemoryRequirements +DeviceImageMemoryRequirementsKHR :: DeviceImageMemoryRequirements +PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT :: PhysicalDeviceTextureCompressionASTCHDRFeatures +SamplerReductionModeEXT :: SamplerReductionMode +SamplerReductionModeCreateInfoEXT :: SamplerReductionModeCreateInfo +PhysicalDeviceSamplerFilterMinmaxPropertiesEXT :: PhysicalDeviceSamplerFilterMinmaxProperties +PhysicalDeviceInlineUniformBlockFeaturesEXT :: PhysicalDeviceInlineUniformBlockFeatures +PhysicalDeviceInlineUniformBlockPropertiesEXT :: PhysicalDeviceInlineUniformBlockProperties +WriteDescriptorSetInlineUniformBlockEXT :: WriteDescriptorSetInlineUniformBlock +DescriptorPoolInlineUniformBlockCreateInfoEXT :: DescriptorPoolInlineUniformBlockCreateInfo +DescriptorBindingFlagEXT :: DescriptorBindingFlag +DescriptorBindingFlagsEXT :: DescriptorBindingFlags +DescriptorSetLayoutBindingFlagsCreateInfoEXT :: DescriptorSetLayoutBindingFlagsCreateInfo +PhysicalDeviceDescriptorIndexingFeaturesEXT :: PhysicalDeviceDescriptorIndexingFeatures +PhysicalDeviceDescriptorIndexingPropertiesEXT :: PhysicalDeviceDescriptorIndexingProperties +DescriptorSetVariableDescriptorCountAllocateInfoEXT :: DescriptorSetVariableDescriptorCountAllocateInfo +DescriptorSetVariableDescriptorCountLayoutSupportEXT :: DescriptorSetVariableDescriptorCountLayoutSupport +RayTracingShaderGroupTypeNV :: RayTracingShaderGroupTypeKHR +GeometryTypeNV :: GeometryTypeKHR +AccelerationStructureTypeNV :: AccelerationStructureTypeKHR +CopyAccelerationStructureModeNV :: CopyAccelerationStructureModeKHR +GeometryFlagsNV :: GeometryFlagsKHR +GeometryFlagNV :: GeometryFlagKHR +GeometryInstanceFlagsNV :: GeometryInstanceFlagsKHR +GeometryInstanceFlagNV :: GeometryInstanceFlagKHR +BuildAccelerationStructureFlagsNV :: BuildAccelerationStructureFlagsKHR +BuildAccelerationStructureFlagNV :: BuildAccelerationStructureFlagKHR +TransformMatrixNV :: TransformMatrixKHR +AabbPositionsNV :: AabbPositionsKHR +AccelerationStructureInstanceNV :: AccelerationStructureInstanceKHR +QueueGlobalPriorityEXT :: QueueGlobalPriorityKHR +DeviceQueueGlobalPriorityCreateInfoEXT :: DeviceQueueGlobalPriorityCreateInfoKHR +PipelineCreationFeedbackFlagEXT :: PipelineCreationFeedbackFlag +PipelineCreationFeedbackFlagsEXT :: PipelineCreationFeedbackFlags +PipelineCreationFeedbackCreateInfoEXT :: PipelineCreationFeedbackCreateInfo +PipelineCreationFeedbackEXT :: PipelineCreationFeedback +QueryPoolCreateInfoINTEL :: QueryPoolPerformanceQueryCreateInfoINTEL +PhysicalDeviceScalarBlockLayoutFeaturesEXT :: PhysicalDeviceScalarBlockLayoutFeatures +PhysicalDeviceSubgroupSizeControlFeaturesEXT :: PhysicalDeviceSubgroupSizeControlFeatures +PhysicalDeviceSubgroupSizeControlPropertiesEXT :: PhysicalDeviceSubgroupSizeControlProperties +PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT :: PipelineShaderStageRequiredSubgroupSizeCreateInfo +PhysicalDeviceBufferAddressFeaturesEXT :: PhysicalDeviceBufferDeviceAddressFeaturesEXT +BufferDeviceAddressInfoEXT :: BufferDeviceAddressInfo +ToolPurposeFlagEXT :: ToolPurposeFlag +ToolPurposeFlagsEXT :: ToolPurposeFlags +PhysicalDeviceToolPropertiesEXT :: PhysicalDeviceToolProperties +ImageStencilUsageCreateInfoEXT :: ImageStencilUsageCreateInfo +PhysicalDeviceHostQueryResetFeaturesEXT :: PhysicalDeviceHostQueryResetFeatures +PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT :: PhysicalDeviceShaderDemoteToHelperInvocationFeatures +PhysicalDeviceTexelBufferAlignmentPropertiesEXT :: PhysicalDeviceTexelBufferAlignmentProperties +PrivateDataSlotEXT :: PrivateDataSlot +PrivateDataSlotCreateFlagsEXT :: PrivateDataSlotCreateFlags +PhysicalDevicePrivateDataFeaturesEXT :: PhysicalDevicePrivateDataFeatures +DevicePrivateDataCreateInfoEXT :: DevicePrivateDataCreateInfo +PrivateDataSlotCreateInfoEXT :: PrivateDataSlotCreateInfo +PhysicalDevicePipelineCreationCacheControlFeaturesEXT :: PhysicalDevicePipelineCreationCacheControlFeatures +PhysicalDeviceImageRobustnessFeaturesEXT :: PhysicalDeviceImageRobustnessFeatures +PhysicalDeviceGlobalPriorityQueryFeaturesEXT :: PhysicalDeviceGlobalPriorityQueryFeaturesKHR +QueueFamilyGlobalPriorityPropertiesEXT :: QueueFamilyGlobalPriorityPropertiesKHR From cfae39c29d4c795c3236670bf7453f16d4b5b4cf Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 15 Apr 2022 19:16:31 +0300 Subject: [PATCH 0537/1052] sys/windows: add procedures and types --- core/sys/windows/kernel32.odin | 14 +++++++++ core/sys/windows/types.odin | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index f81c51311..735e065e2 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -92,6 +92,20 @@ foreign kernel32 { CreateSemaphoreW :: proc(attributes: LPSECURITY_ATTRIBUTES, initial_count, maximum_count: LONG, name: LPCSTR) -> HANDLE --- ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: LONG, previous_count: ^LONG) -> BOOL --- + CreateWaitableTimerW :: proc( + lpTimerAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + lpTimerName: LPCWSTR, + ) -> HANDLE --- + SetWaitableTimerEx :: proc( + hTimer: HANDLE, + lpDueTime: ^LARGE_INTEGER, + lPeriod: LONG, + pfnCompletionRoutine: PTIMERAPCROUTINE, + lpArgToCompletionRoutine: LPVOID, + WakeContext: PREASON_CONTEXT, + TolerableDelay: ULONG, + ) -> BOOL --- WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD --- Sleep :: proc(dwMilliseconds: DWORD) --- GetProcessId :: proc(handle: HANDLE) -> DWORD --- diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index de19cd6cc..f05dd3310 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -123,6 +123,8 @@ PCONDITION_VARIABLE :: ^CONDITION_VARIABLE PLARGE_INTEGER :: ^LARGE_INTEGER PSRWLOCK :: ^SRWLOCK +MMRESULT :: UINT + SOCKET :: distinct uintptr // TODO socklen_t :: c_int ADDRESS_FAMILY :: USHORT @@ -195,6 +197,56 @@ GET_FILEEX_INFO_LEVELS :: distinct i32 GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0 GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1 +// String resource number bases (internal use) + +MMSYSERR_BASE :: 0 +WAVERR_BASE :: 32 +MIDIERR_BASE :: 64 +TIMERR_BASE :: 96 +JOYERR_BASE :: 160 +MCIERR_BASE :: 256 +MIXERR_BASE :: 1024 + +MCI_STRING_OFFSET :: 512 +MCI_VD_OFFSET :: 1024 +MCI_CD_OFFSET :: 1088 +MCI_WAVE_OFFSET :: 1152 +MCI_SEQ_OFFSET :: 1216 + +// timer error return values +TIMERR_NOERROR :: 0 // no error +TIMERR_NOCANDO :: TIMERR_BASE + 1 // request not completed +TIMERR_STRUCT :: TIMERR_BASE + 33 // time struct size + +DIAGNOSTIC_REASON_VERSION :: 0 + +DIAGNOSTIC_REASON_SIMPLE_STRING :: 0x00000001 +DIAGNOSTIC_REASON_DETAILED_STRING :: 0x00000002 +DIAGNOSTIC_REASON_NOT_SPECIFIED :: 0x80000000 + +// Defines for power request APIs + +POWER_REQUEST_CONTEXT_VERSION :: DIAGNOSTIC_REASON_VERSION + +POWER_REQUEST_CONTEXT_SIMPLE_STRING :: DIAGNOSTIC_REASON_SIMPLE_STRING +POWER_REQUEST_CONTEXT_DETAILED_STRING :: DIAGNOSTIC_REASON_DETAILED_STRING + +REASON_CONTEXT :: struct { + Version: ULONG, + Flags: DWORD, + Reason: struct #raw_union { + Detailed: struct { + LocalizedReasonModule: HMODULE, + LocalizedReasonId: ULONG, + ReasonStringCount: ULONG, + ReasonStrings: ^LPWSTR, + }, + SimpleReasonString: LPWSTR, + }, +} +PREASON_CONTEXT :: ^REASON_CONTEXT + +PTIMERAPCROUTINE :: #type proc "stdcall" (lpArgToCompletionRoutine: LPVOID, dwTimerLowValue, dwTimerHighValue: DWORD) TIMERPROC :: #type proc "stdcall" (HWND, UINT, UINT_PTR, DWORD) From d3fbf36df7cddf2cf69f7d761ccf4dfea863a40c Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 15 Apr 2022 19:18:22 +0300 Subject: [PATCH 0538/1052] sys/windows: add winmm bindings file --- core/sys/windows/winmm.odin | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 core/sys/windows/winmm.odin diff --git a/core/sys/windows/winmm.odin b/core/sys/windows/winmm.odin new file mode 100644 index 000000000..6d3fc409e --- /dev/null +++ b/core/sys/windows/winmm.odin @@ -0,0 +1,9 @@ +// +build windows +package sys_windows + +foreign import winmm "system:Winmm.lib" + +@(default_calling_convention="stdcall") +foreign winmm { + timeBeginPeriod :: proc(uPeriod: UINT) -> MMRESULT --- +} From 1b4d5b73abf8d582e3493f0d52c91d0f0d3ec102 Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 15 Apr 2022 22:04:34 +0300 Subject: [PATCH 0539/1052] sys/windows: add some constants --- core/sys/windows/types.odin | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index f05dd3310..6bded29e1 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -786,6 +786,10 @@ HOVER_DEFAULT :: 0xFFFFFFFF USER_TIMER_MAXIMUM :: 0x7FFFFFFF USER_TIMER_MINIMUM :: 0x0000000A +// WM_ACTIVATE state values +WA_INACTIVE :: 0 +WA_ACTIVE :: 1 +WA_CLICKACTIVE :: 2 // SetWindowsHook() codes WH_MIN :: -1 From b05fbaacdaf8ffe37ad04f9d4439b06d8b538869 Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 16 Apr 2022 00:32:17 +0300 Subject: [PATCH 0540/1052] time: add accurate sleep procedure --- core/time/time.odin | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/time/time.odin b/core/time/time.odin index fddb09d85..7056f83f8 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -213,6 +213,37 @@ time_add :: proc(t: Time, d: Duration) -> Time { return Time{t._nsec + i64(d)} } +// Accurate sleep borrowed from: https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/ +accurate_sleep :: proc(d: Duration) { + to_sleep, estimate, mean, m2, count: Duration + + to_sleep = d + estimate = 5 * Millisecond + mean = 5 * Millisecond + count = 1 + + for to_sleep > estimate { + start := tick_now() + sleep(1 * Millisecond) + + observed := tick_since(start) + to_sleep -= observed + + count += 1 + + delta := observed - mean + mean += delta / count + m2 += delta * (observed - mean) + stddev := intrinsics.sqrt(f64(m2) / f64(count - 1)) + estimate = mean + Duration(stddev) + } + + start := tick_now() + for to_sleep > tick_since(start) { + intrinsics.cpu_relax() // prevent the spinlock from taking the thread hostage, still accurate enough + // NOTE: it is possible that sometimes cpu can relax a bit too much, in that case it should spinlock freely for a while (TODO) + } +} ABSOLUTE_ZERO_YEAR :: i64(-292277022399) // Day is chosen so that 2001-01-01 is Monday in the calculations ABSOLUTE_TO_INTERNAL :: i64(-9223371966579724800) // i64((ABSOLUTE_ZERO_YEAR - 1) * 365.2425 * SECONDS_PER_DAY); From 44316401c915cd96a9c97a0747d7487bac905ac7 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 16 Apr 2022 02:07:57 +0200 Subject: [PATCH 0541/1052] Add uleb128 byte-at-a-time decoder. --- core/encoding/varint/leb128.odin | 54 +++++++++++------- .../encoding/varint/test_core_varint.odin | 2 +- tests/core/encoding/varint/varint | Bin 0 -> 308984 bytes 3 files changed, 34 insertions(+), 22 deletions(-) create mode 100755 tests/core/encoding/varint/varint diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin index 476b9c2c9..4cad1da76 100644 --- a/core/encoding/varint/leb128.odin +++ b/core/encoding/varint/leb128.odin @@ -10,8 +10,6 @@ // the LEB128 format as used by DWARF debug info, Android .dex and other file formats. package varint -import "core:fmt" - // In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file. // Instead we'll set limits on the values we'll encode/decode // 18 * 7 bits = 126, which means that a possible 19th byte may at most be `0b0000_0011`. @@ -25,32 +23,47 @@ Error :: enum { // Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used. // Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. -decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int, err: Error) { - more := true +decode_uleb128_buffer :: proc(buf: []u8) -> (val: u128, size: int, err: Error) { + if len(buf) == 0 { + return 0, 0, .Buffer_Too_Small + } - for v, i in buf { - size = i + 1 - - // 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011. - if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0b0000_0011 { - return 0, 0, .Value_Too_Large - } - - val |= u128(v & 0x7f) << uint(i * 7) - - if v < 128 { - more = false - break + for v in buf { + val, size, err = decode_uleb128_byte(v, size, val) + if err != .Buffer_Too_Small { + return } } - // If the buffer runs out before the number ends, return an error. - if more { - return 0, 0, .Buffer_Too_Small + if err == .Buffer_Too_Small { + val, size = 0, 0 } return } +// Decodes an unsigned LEB128 integer into value a byte at a time. +// Returns `.None` when decoded properly, `.Value_Too_Large` when they value +// exceeds the limits of a u128, and `.Buffer_Too_Small` when it's not yet fully decoded. +decode_uleb128_byte :: proc(input: u8, offset: int, accumulator: u128) -> (val: u128, size: int, err: Error) { + size = offset + 1 + + // 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011. + if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && input > 0b0000_0011 { + return 0, 0, .Value_Too_Large + } + + val = accumulator | u128(input & 0x7f) << uint(offset * 7) + + if input < 128 { + // We're done + return + } + + // If the buffer runs out before the number ends, return an error. + return val, size, .Buffer_Too_Small +} +decode_uleb128 :: proc {decode_uleb128_buffer, decode_uleb128_byte} + // Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used. // Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { @@ -89,7 +102,6 @@ encode_uleb128 :: proc(buf: []u8, val: u128) -> (size: int, err: Error) { size += 1 if size > len(buf) { - fmt.println(val, buf[:size - 1]) return 0, .Buffer_Too_Small } diff --git a/tests/core/encoding/varint/test_core_varint.odin b/tests/core/encoding/varint/test_core_varint.odin index 093b043d7..2c3669afa 100644 --- a/tests/core/encoding/varint/test_core_varint.odin +++ b/tests/core/encoding/varint/test_core_varint.odin @@ -51,7 +51,7 @@ test_leb128 :: proc(t: ^testing.T) { msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) expect(t, size == vector.size && val == vector.value, msg) - msg = fmt.tprintf("Expected decoder to return error %v, got %v", vector.error, err) + msg = fmt.tprintf("Expected decoder to return error %v, got %v for vector %v", vector.error, err, vector) expect(t, err == vector.error, msg) if err == .None { // Try to roundtrip diff --git a/tests/core/encoding/varint/varint b/tests/core/encoding/varint/varint new file mode 100755 index 0000000000000000000000000000000000000000..1e982544582db7a8f719d5229759a019afa45103 GIT binary patch literal 308984 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 Date: Sat, 16 Apr 2022 13:46:36 +0300 Subject: [PATCH 0542/1052] runtime: update comment description --- core/runtime/core.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 4ab21d8cf..4269450de 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -401,6 +401,7 @@ Raw_Cstring :: struct { Linux, Essence, FreeBSD, + OpenBSD, WASI, JS, Freestanding, From 0a0440a6e869e8d8791608f14fb55f37f323a23e Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 16 Apr 2022 14:08:37 +0300 Subject: [PATCH 0543/1052] time: yield accurate_sleep instead of relaxing the cpu --- core/time/time.odin | 10 ++++++++-- core/time/time_unix.odin | 6 ++++++ core/time/time_windows.odin | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/core/time/time.odin b/core/time/time.odin index 7056f83f8..f2e974647 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -213,6 +213,10 @@ time_add :: proc(t: Time, d: Duration) -> Time { return Time{t._nsec + i64(d)} } +yield :: proc "contextless" () { + _yield() +} + // Accurate sleep borrowed from: https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/ accurate_sleep :: proc(d: Duration) { to_sleep, estimate, mean, m2, count: Duration @@ -240,8 +244,10 @@ accurate_sleep :: proc(d: Duration) { start := tick_now() for to_sleep > tick_since(start) { - intrinsics.cpu_relax() // prevent the spinlock from taking the thread hostage, still accurate enough - // NOTE: it is possible that sometimes cpu can relax a bit too much, in that case it should spinlock freely for a while (TODO) + // prevent the spinlock from taking the thread hostage, still accurate enough + yield() + // NOTE: it might be possible that it yields for too long, in that case it should spinlock freely for a while + // TODO: needs actual testing done to check if that's the case } } diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin index 37fc1fd3e..db15a824a 100644 --- a/core/time/time_unix.odin +++ b/core/time/time_unix.odin @@ -1,6 +1,8 @@ //+build linux, darwin, freebsd, openbsd package time +import "core:sys/unix" + IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC. when ODIN_OS == .Darwin { @@ -17,6 +19,10 @@ foreign libc { @(link_name="nanosleep") _unix_nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> i32 --- } +_yield :: proc "contextless" () { + unix.sched_yield() +} + TimeSpec :: struct { tv_sec : i64, /* seconds */ tv_nsec : i64, /* nanoseconds */ diff --git a/core/time/time_windows.odin b/core/time/time_windows.odin index 0fb9eaa0f..397741126 100644 --- a/core/time/time_windows.odin +++ b/core/time/time_windows.odin @@ -35,3 +35,7 @@ _tick_now :: proc "contextless" () -> Tick { _nsec := mul_div_u64(i64(now), 1e9, i64(qpc_frequency)) return Tick{_nsec = _nsec} } + +_yield :: proc "contextless" () { + win32.SwitchToThread() +} From 4f4793817cfb1782c1b2e6cf55ffdbfb01bcffaf Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 16 Apr 2022 14:35:49 +0300 Subject: [PATCH 0544/1052] time: fix unix build --- core/time/time_unix.odin | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin index db15a824a..0cfa196a2 100644 --- a/core/time/time_unix.odin +++ b/core/time/time_unix.odin @@ -1,8 +1,6 @@ //+build linux, darwin, freebsd, openbsd package time -import "core:sys/unix" - IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC. when ODIN_OS == .Darwin { @@ -19,8 +17,18 @@ foreign libc { @(link_name="nanosleep") _unix_nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> i32 --- } +foreign import "system:pthread" + +import "core:c" + +@(private="file") +@(default_calling_convention="c") +foreign pthread { + sched_yield :: proc() -> c.int --- +} + _yield :: proc "contextless" () { - unix.sched_yield() + sched_yield() } TimeSpec :: struct { From 8bf73950fa3bfaea940f8c14e69824b06908aa5e Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 16 Apr 2022 14:36:48 +0300 Subject: [PATCH 0545/1052] time: remove unnecessary yield --- core/time/time.odin | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/time/time.odin b/core/time/time.odin index f2e974647..ac233fbd2 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -213,10 +213,6 @@ time_add :: proc(t: Time, d: Duration) -> Time { return Time{t._nsec + i64(d)} } -yield :: proc "contextless" () { - _yield() -} - // Accurate sleep borrowed from: https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/ accurate_sleep :: proc(d: Duration) { to_sleep, estimate, mean, m2, count: Duration @@ -245,7 +241,7 @@ accurate_sleep :: proc(d: Duration) { start := tick_now() for to_sleep > tick_since(start) { // prevent the spinlock from taking the thread hostage, still accurate enough - yield() + _yield() // NOTE: it might be possible that it yields for too long, in that case it should spinlock freely for a while // TODO: needs actual testing done to check if that's the case } From 91037766d2b583ac34d23eee5a46f10df9d3cba0 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 16 Apr 2022 16:48:08 +0200 Subject: [PATCH 0546/1052] Update time.odin Add caveats. --- core/time/time.odin | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/time/time.odin b/core/time/time.odin index ac233fbd2..1f778a8de 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -214,12 +214,17 @@ time_add :: proc(t: Time, d: Duration) -> Time { } // Accurate sleep borrowed from: https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/ +// +// Accuracy seems to be pretty good out of the box on Linux, to within around 4µs worst case. +// On Windows it depends but is comparable with regular sleep in the worst case. +// To get the same kind of accuracy as on Linux, have your program call `win32.time_begin_period(1)` to +// tell Windows to use a more accurate timer for your process. accurate_sleep :: proc(d: Duration) { to_sleep, estimate, mean, m2, count: Duration to_sleep = d estimate = 5 * Millisecond - mean = 5 * Millisecond + mean = 5 * Millisecond count = 1 for to_sleep > estimate { From 6d0ba8d1898adabceafc6a181395f5d158176a04 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 16 Apr 2022 18:14:01 +0200 Subject: [PATCH 0547/1052] [LEB128] Add byte-at-a-time ILEB decoder. --- core/encoding/varint/leb128.odin | 44 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin index 4cad1da76..f8fcc7de5 100644 --- a/core/encoding/varint/leb128.odin +++ b/core/encoding/varint/leb128.odin @@ -66,33 +66,47 @@ decode_uleb128 :: proc {decode_uleb128_buffer, decode_uleb128_byte} // Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used. // Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. -decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { - shift: uint - +decode_ileb128_buffer :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { if len(buf) == 0 { return 0, 0, .Buffer_Too_Small } for v in buf { - size += 1 - - // 18 * 7 bits = 126, which including sign means we can have a 19th byte. - if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0x7f { - return 0, 0, .Value_Too_Large + val, size, err = decode_ileb128_byte(v, size, val) + if err != .Buffer_Too_Small { + return } - - val |= i128(v & 0x7f) << shift - shift += 7 - - if v < 128 { break } } - if buf[size - 1] & 0x40 == 0x40 { - val |= max(i128) << shift + if err == .Buffer_Too_Small { + val, size = 0, 0 } return } +// Decode a a signed LEB128 integer into value and number of bytes used, one byte at a time. +// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. +decode_ileb128_byte :: proc(input: u8, offset: int, accumulator: i128) -> (val: i128, size: int, err: Error) { + size = offset + 1 + shift := uint(offset * 7) + + // 18 * 7 bits = 126, which including sign means we can have a 19th byte. + if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && input > 0x7f { + return 0, 0, .Value_Too_Large + } + + val = accumulator | i128(input & 0x7f) << shift + + if input < 128 { + if input & 0x40 == 0x40 { + val |= max(i128) << (shift + 7) + } + return val, size, .None + } + return val, size, .Buffer_Too_Small +} +decode_ileb128 :: proc{decode_ileb128_buffer, decode_ileb128_byte} + // Encode `val` into `buf` as an unsigned LEB128 encoded series of bytes. // `buf` must be appropriately sized. encode_uleb128 :: proc(buf: []u8, val: u128) -> (size: int, err: Error) { From 939973acd7a8ea17cc9dfda2a55e79dd0109a49c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 17 Apr 2022 12:35:34 +0200 Subject: [PATCH 0548/1052] [QOI] Add to examples/all. --- examples/all/all_main.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 6a039e4dd..4f5bfbdc1 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -61,6 +61,7 @@ import hash "core:hash" import image "core:image" import png "core:image/png" +import qoi "core:image/qoi" import io "core:io" import log "core:log" @@ -159,6 +160,7 @@ _ :: fmt _ :: hash _ :: image _ :: png +_ :: qoi _ :: io _ :: log _ :: math From b78f3a806930fe026c027aedf511696bc6691b96 Mon Sep 17 00:00:00 2001 From: hikari Date: Sun, 17 Apr 2022 19:17:38 +0300 Subject: [PATCH 0549/1052] sys/windows: add timeEndPeriod --- core/sys/windows/winmm.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/sys/windows/winmm.odin b/core/sys/windows/winmm.odin index 6d3fc409e..9edd56acc 100644 --- a/core/sys/windows/winmm.odin +++ b/core/sys/windows/winmm.odin @@ -6,4 +6,5 @@ foreign import winmm "system:Winmm.lib" @(default_calling_convention="stdcall") foreign winmm { timeBeginPeriod :: proc(uPeriod: UINT) -> MMRESULT --- + timeEndPeriod :: proc(uPeriod: UINT) -> MMRESULT --- } From 4247ba67ed83a16c321363cdf8260f71826325ca Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Mon, 18 Apr 2022 15:24:54 +0800 Subject: [PATCH 0550/1052] Fix bugs in core:container/lru --- core/container/lru/lru_cache.odin | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/core/container/lru/lru_cache.odin b/core/container/lru/lru_cache.odin index f8e6f7b46..81f0142b0 100644 --- a/core/container/lru/lru_cache.odin +++ b/core/container/lru/lru_cache.odin @@ -60,6 +60,8 @@ clear :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) { set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Allocator_Error { if e, ok := c.entries[key]; ok { e.value = value + _pop_node(c, e) + _push_front_node(c, e) return nil } @@ -67,10 +69,14 @@ set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Alloc e.key = key e.value = value - _push_front_node(c, e) - if c.count > c.capacity { + assert(c.count <= c.capacity) + if c.count == c.capacity { _remove_node(c, c.tail) } + else { + c.count += 1 + } + _push_front_node(c, e) c.entries[key] = e return nil @@ -122,6 +128,7 @@ remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool { return false } _remove_node(c, e) + c.count -= 1 return true } @@ -143,8 +150,6 @@ _remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) { node.prev = nil node.next = nil - c.count -= 1 - delete_key(&c.entries, node.key) _call_on_remove(c, node) @@ -171,8 +176,6 @@ _push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) { c.tail = e } e.prev = nil - - c.count += 1 } @(private) @@ -180,6 +183,12 @@ _pop_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) { if e == nil { return } + if c.head == e { + c.head = e.next + } + if c.tail == e { + c.tail = e.prev + } if e.prev != nil { e.prev.next = e.next } From 7428e5226426d1d19601d5b557c3df51db233857 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Thu, 14 Apr 2022 16:53:48 +0000 Subject: [PATCH 0551/1052] Duplicate some basic slice procedures from core:mem into core:slice --- core/slice/slice.odin | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 520e3e1e0..b8fb29ab3 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -10,6 +10,53 @@ _ :: builtin _ :: bits _ :: mem +/* + Turn a pointer and a length into a slice. +*/ +from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T { + return ([^]T)(ptr)[:count] +} + +/* + Turn a pointer and a length into a byte slice. +*/ +bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte { + return ([^]byte)(ptr)[:byte_count] +} + +/* + Turn a slice into a byte slice. + + See `slice.reinterpret` to go the other way. +*/ +to_bytes :: proc "contextless" (s: []$T) -> []byte { + return ([^]byte)(raw_data(s))[:len(s) * size_of(T)] +} + +/* + Turn a slice of one type, into a slice of another type. + + Only converts the type and length of the slice itself. + The length is rounded down to the nearest whole number of items. + + ``` + large_items := []i64{1, 2, 3, 4} + small_items := slice.reinterpret([]i32, large_items) + assert(len(small_items) == 8) + ``` + ``` + small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0} + large_items := slice.reinterpret([]i64, small_items) + assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes. + ``` +*/ +reinterpret :: proc "contextless" ($T: typeid/[]$U, s: []$V) -> []U { + bytes := to_bytes(s) + n := len(bytes) / size_of(U) + return ([^]U)(raw_data(bytes))[:n] +} + swap :: proc(array: $T/[]$E, a, b: int) { when size_of(E) > 8 { From df4a0c62add28af74ac8c926b3a6e0612296ccd1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 18 Apr 2022 19:10:53 +0200 Subject: [PATCH 0552/1052] Delete accidentally added test artefact. --- tests/core/encoding/varint/varint | Bin 308984 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 tests/core/encoding/varint/varint diff --git a/tests/core/encoding/varint/varint b/tests/core/encoding/varint/varint deleted file mode 100755 index 1e982544582db7a8f719d5229759a019afa45103..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 308984 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 Date: Mon, 18 Apr 2022 01:00:19 +0100 Subject: [PATCH 0553/1052] Added initial Netpbm image format support --- core/image/common.odin | 46 +++ core/image/netpbm/doc.odin | 32 ++ core/image/netpbm/helpers.odin | 26 ++ core/image/netpbm/netpbm.odin | 681 +++++++++++++++++++++++++++++++++ 4 files changed, 785 insertions(+) create mode 100644 core/image/netpbm/doc.odin create mode 100644 core/image/netpbm/helpers.odin create mode 100644 core/image/netpbm/netpbm.odin diff --git a/core/image/common.odin b/core/image/common.odin index 2e7bca17e..bf93e9313 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -57,6 +57,7 @@ Image :: struct { } Image_Metadata :: union { + ^Netpbm_Info, ^PNG_Info, ^QOI_Info, } @@ -152,6 +153,7 @@ Options :: distinct bit_set[Option] Error :: union #shared_nil { General_Image_Error, + Netpbm_Error, PNG_Error, QOI_Error, @@ -171,6 +173,50 @@ General_Image_Error :: enum { Invalid_Output, } +/* + Netpbm-specific definitions +*/ +Netpbm_Format :: enum { + P1, P2, P3, P4, P5, P6, P7, Pf, PF, +} + +Netpbm_Header :: struct { + format: Netpbm_Format, + width: int, + height: int, + channels: int, + depth: int, + maxval: int, + tupltype: string, + scale: f32, + little_endian: bool, +} + +Netpbm_Info :: struct { + header: Netpbm_Header, +} + +Netpbm_Error :: enum { + None = 0, + + // reading + File_Not_Readable, + Invalid_Signature, + Invalid_Header_Token_Character, + Incomplete_Header, + Invalid_Header_Value, + Duplicate_Header_Field, + Buffer_Too_Small, + Invalid_Buffer_ASCII_Token, + Invalid_Buffer_Value, + + // writing + File_Not_Writable, + Invalid_Format, + Invalid_Number_Of_Channels, + Invalid_Image_Depth, +} + /* PNG-specific definitions */ diff --git a/core/image/netpbm/doc.odin b/core/image/netpbm/doc.odin new file mode 100644 index 000000000..baeb99968 --- /dev/null +++ b/core/image/netpbm/doc.odin @@ -0,0 +1,32 @@ +/* +Formats: + PBM (P1, P4): Portable Bit Map, stores black and white images (1 channel) + PGM (P2, P5): Portable Gray Map, stores greyscale images (1 channel, 1 or 2 bytes per value) + PPM (P3, P6): Portable Pixel Map, stores colour images (3 channel, 1 or 2 bytes per value) + PAM (P7 ): Portable Arbitrary Map, stores arbitrary channel images (1 or 2 bytes per value) + PFM (Pf, PF): Portable Float Map, stores floating-point images (Pf: 1 channel, PF: 3 channel) + +Reading + All formats fill out header fields `format`, `width`, `height`, `channels`, `depth` + Specific formats use more fields + PGM, PPM, and PAM set `maxval` + PAM also sets `tupltype`, and is able to set `channels` to an arbitrary value + PFM sets `scale` and `little_endian` + Currently doesn't support reading multiple images from one binary-format file + +Writing + All formats require the header field `format` to be specified + Additional header fields are required for specific formats + PGM, PPM, and PAM require `maxval` + PAM also uses `tupltype`, though it may be left as default (empty or nil string) + PFM requires `scale` and `little_endian`, though the latter may be left untouched (default is false) + +Some syntax differences from the specifications: + `channels` stores what the PAM specification calls `depth` + `depth` instead stores how many bytes will fit `maxval` (should only be 1, 2, or 4) + `scale` and `little_endian` are separated, so the `header` will always store a positive `scale` + `little_endian` will only be true for a negative `scale` PFM, every other format will be false + `little_endian` only describes the netpbm data being read/written, the image buffer will be native +*/ + +package netpbm diff --git a/core/image/netpbm/helpers.odin b/core/image/netpbm/helpers.odin new file mode 100644 index 000000000..5a3000a87 --- /dev/null +++ b/core/image/netpbm/helpers.odin @@ -0,0 +1,26 @@ +package netpbm + +import "core:bytes" +import "core:image" + +destroy :: proc(img: ^image.Image) -> bool { + if img == nil do return false + + //! TEMP CAST + info, ok := img.metadata.(^image.Netpbm_Info) + if !ok do return false + + bytes.buffer_destroy(&img.pixels) + header_destroy(&info.header) + free(info) + img.metadata = nil + + return true +} + +header_destroy :: proc(using header: ^Header) { + if format == .P7 && tupltype != "" { + delete(tupltype) + tupltype = "" + } +} diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin new file mode 100644 index 000000000..fa8ffc1db --- /dev/null +++ b/core/image/netpbm/netpbm.odin @@ -0,0 +1,681 @@ +package netpbm + +import "core:bytes" +import "core:fmt" +import "core:image" +import "core:mem" +import "core:os" +import "core:strconv" +import "core:strings" +import "core:unicode" + + + +Image :: image.Image +Format :: image.Netpbm_Format +Header :: image.Netpbm_Header +Info :: image.Netpbm_Info +Error :: image.Error +Format_Error :: image.Netpbm_Error + + + +Formats :: bit_set[Format] +PBM :: Formats{.P1, .P4} +PGM :: Formats{.P2, .P5} +PPM :: Formats{.P3, .P6} +PNM :: PBM + PGM + PPM +PAM :: Formats{.P7} +PFM :: Formats{.Pf, .PF} +ASCII :: Formats{.P1, .P2, .P3} +BINARY :: Formats{.P4, .P5, .P6} + PAM + PFM + + + +read :: proc { + read_from_file, + read_from_buffer, +} + +read_from_file :: proc(filename: string, allocator := context.allocator) -> (img: Image, err: Error) { + context.allocator = allocator + + data, ok := os.read_entire_file(filename); defer delete(data) + if !ok { + err = .File_Not_Readable + return + } + + return read_from_buffer(data) +} + +read_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { + context.allocator = allocator + + header: Header; defer header_destroy(&header) + header_size: int + header, header_size = parse_header(data) or_return + + img_data := data[header_size:] + img = decode_image(header, img_data) or_return + + info := new(Info) + info.header = header + if header.format == .P7 && header.tupltype != "" { + info.header.tupltype = strings.clone(header.tupltype) + } + img.metadata = info + + err = Format_Error.None + return +} + + + +write :: proc { + write_to_file, + write_to_buffer, +} + +write_to_file :: proc(filename: string, img: Image, allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + data: []byte; defer delete(data) + data = write_to_buffer(img) or_return + + if ok := os.write_entire_file(filename, data); !ok { + return .File_Not_Writable + } + + return Format_Error.None +} + +write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: []byte, err: Error) { + context.allocator = allocator + + info, ok := img.metadata.(^image.Netpbm_Info) + if !ok { + err = image.General_Image_Error.Invalid_Input_Image + return + } + // using info so we can just talk about the header + using info + + //? validation + if header.format in (PBM + PGM + Formats{.Pf}) && img.channels != 1 \ + || header.format in (PPM + Formats{.PF}) && img.channels != 3 { + err = Format_Error.Invalid_Number_Of_Channels + return + } + + if header.format in (PNM + PAM) { + if header.maxval <= int(max(u8)) && img.depth != 1 \ + || header.maxval > int(max(u8)) && header.maxval <= int(max(u16)) && img.depth != 2 { + err = Format_Error.Invalid_Image_Depth + return + } + } else if header.format in PFM && img.depth != 4 { + err = Format_Error.Invalid_Image_Depth + return + } + + // we will write to a string builder + data: strings.Builder + strings.init_builder(&data) + + // all PNM headers start with the format + fmt.sbprintf(&data, "%s\n", header.format) + if header.format in PNM { + fmt.sbprintf(&data, "%i %i\n", img.width, img.height) + if header.format not_in PBM { + fmt.sbprintf(&data, "%i\n", header.maxval) + } + } else if header.format in PAM { + fmt.sbprintf(&data, "WIDTH %i\nHEIGHT %i\nMAXVAL %i\nDEPTH %i\nTUPLTYPE %s\nENDHDR\n", + img.width, img.height, header.maxval, img.channels, header.tupltype) + } else if header.format in PFM { + scale := -header.scale if header.little_endian else header.scale + fmt.sbprintf(&data, "%i %i\n%f\n", img.width, img.height, scale) + } + + switch header.format { + // Compressed binary + case .P4: + header_buf := data.buf[:] + pixels := img.pixels.buf[:] + + p4_buffer_size := (img.width / 8 + 1) * img.height + reserve(&data.buf, len(header_buf) + p4_buffer_size) + + // we build up a byte value until it is completely filled + // or we reach the end the row + for y in 0 ..< img.height { + b: byte + + for x in 0 ..< img.width { + i := y * img.width + x + bit := byte(7 - (x % 8)) + v : byte = 0 if pixels[i] == 0 else 1 + b |= (v << bit) + + if bit == 0 { + append(&data.buf, b) + b = 0 + } + } + + if b != 0 { + append(&data.buf, b) + b = 0 + } + } + + // Simple binary + case .P5, .P6, .P7, .Pf, .PF: + header_buf := data.buf[:] + pixels := img.pixels.buf[:] + + resize(&data.buf, len(header_buf) + len(pixels)) + mem.copy(raw_data(data.buf[len(header_buf):]), raw_data(pixels), len(pixels)) + + // convert from native endianness + if img.depth == 2 { + pixels := mem.slice_data_cast([]u16be, data.buf[len(header_buf):]) + for p in &pixels { + p = u16be(transmute(u16) p) + } + } else if header.format in PFM { + if header.little_endian { + pixels := mem.slice_data_cast([]f32le, data.buf[len(header_buf):]) + for p in &pixels { + p = f32le(transmute(f32) p) + } + } else { + pixels := mem.slice_data_cast([]f32be, data.buf[len(header_buf):]) + for p in &pixels { + p = f32be(transmute(f32) p) + } + } + } + + // If-it-looks-like-a-bitmap ASCII + case .P1: + pixels := img.pixels.buf[:] + for y in 0 ..< img.height { + for x in 0 ..< img.width { + i := y * img.width + x + append(&data.buf, '0' if pixels[i] == 0 else '1') + } + append(&data.buf, '\n') + } + + // Token ASCII + case .P2, .P3: + switch img.depth { + case 1: + pixels := img.pixels.buf[:] + for y in 0 ..< img.height { + for x in 0 ..< img.width { + i := y * img.width + x + for c in 0 ..< img.channels { + i := i * img.channels + c + fmt.sbprintf(&data, "%i ", pixels[i]) + } + fmt.sbprint(&data, "\n") + } + fmt.sbprint(&data, "\n") + } + + case 2: + pixels := mem.slice_data_cast([]u16, img.pixels.buf[:]) + for y in 0 ..< img.height { + for x in 0 ..< img.width { + i := y * img.width + x + for c in 0 ..< img.channels { + i := i * img.channels + c + fmt.sbprintf(&data, "%i ", pixels[i]) + } + fmt.sbprint(&data, "\n") + } + fmt.sbprint(&data, "\n") + } + + case: + return data.buf[:], Format_Error.Invalid_Image_Depth + } + + case: + return data.buf[:], Format_Error.Invalid_Format + } + + return data.buf[:], Format_Error.None +} + + + +parse_header :: proc(data: []byte, allocator := context.allocator) -> (header: Header, length: int, err: Error) { + context.allocator = allocator + + // we need the signature and a space + if len(data) < 3 { + err = Format_Error.Incomplete_Header + return + } + + if data[0] == 'P' { + switch data[1] { + case '1' ..= '6': + return _parse_header_pnm(data) + case '7': + return _parse_header_pam(data, allocator) + case 'F', 'f': + return _parse_header_pfm(data) + } + } + + err = Format_Error.Invalid_Signature + return +} + +@(private) +_parse_header_pnm :: proc(data: []byte) -> (header: Header, length: int, err: Error) { + SIG_LENGTH :: 2 + + { + header_formats := []Format{.P1, .P2, .P3, .P4, .P5, .P6} + header.format = header_formats[data[1] - '0' - 1] + } + + // have a list of fielda for easy iteration + header_fields: []^int + if header.format in PBM { + header_fields = {&header.width, &header.height} + header.maxval = 1 // we know maxval for a bitmap + } else { + header_fields = {&header.width, &header.height, &header.maxval} + } + + // we're keeping track of the header byte length + length = SIG_LENGTH + + // loop state + in_comment := false + already_in_space := true + current_field := 0 + current_value := header_fields[0] + + parse_loop: for d, i in data[SIG_LENGTH:] { + length += 1 + + // handle comments + if in_comment { + switch d { + // comments only go up to next carriage return or line feed + case '\r', '\n': + in_comment = false + } + continue + } else if d == '#' { + in_comment = true + continue + } + + // handle whitespace + in_space := unicode.is_white_space(rune(d)) + if in_space { + if already_in_space { + continue + } + already_in_space = true + + // switch to next value + current_field += 1 + if current_field == len(header_fields) { + // header byte length is 1-index so we'll increment again + length += 1 + break parse_loop + } + current_value = header_fields[current_field] + } else { + already_in_space = false + + if !unicode.is_digit(rune(d)) { + err = Format_Error.Invalid_Header_Token_Character + return + } + + val := int(d - '0') + current_value^ = current_value^ * 10 + val + } + } + + // set extra info + header.channels = 3 if header.format in PPM else 1 + header.depth = 2 if header.maxval > int(max(u8)) else 1 + + // limit checking + if current_field < len(header_fields) { + err = Format_Error.Incomplete_Header + return + } + + if header.width < 1 \ + || header.height < 1 \ + || header.maxval < 1 || header.maxval > int(max(u16)) { + err = Format_Error.Invalid_Header_Value + return + } + + err = Format_Error.None + return +} + +@(private) +_parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (header: Header, length: int, err: Error) { + context.allocator = allocator + + // the spec needs the newline apparently + if string(data[0:3]) != "P7\n" { + err = Format_Error.Invalid_Signature + return + } + header.format = .P7 + + SIGNATURE_LENGTH :: 3 + HEADER_END :: "ENDHDR\n" + + // we can already work out the size of the header + header_end_index := strings.index(string(data), HEADER_END) + if header_end_index == -1 { + err = Format_Error.Incomplete_Header + return + } + length = header_end_index + len(HEADER_END) + + // string buffer for the tupltype + tupltype: strings.Builder + strings.init_builder(&tupltype, context.temp_allocator); defer strings.destroy_builder(&tupltype) + fmt.sbprint(&tupltype, "") + + // PAM uses actual lines, so we can iterate easily + line_iterator := string(data[SIGNATURE_LENGTH : header_end_index]) + parse_loop: for line in strings.split_lines_iterator(&line_iterator) { + line := line + + if len(line) == 0 || line[0] == '#' { + continue + } + + field, ok := strings.fields_iterator(&line) + value := strings.trim_space(line) + + // the field will change, but the logic stays the same + current_field: ^int + + switch field { + case "WIDTH": current_field = &header.width + case "HEIGHT": current_field = &header.height + case "DEPTH": current_field = &header.channels + case "MAXVAL": current_field = &header.maxval + + case "TUPLTYPE": + if len(value) == 0 { + err = Format_Error.Invalid_Header_Value + return + } + + if len(tupltype.buf) == 0 { + fmt.sbprint(&tupltype, value) + } else { + fmt.sbprint(&tupltype, "", value) + } + + continue + + case: + continue + } + + if current_field^ != 0 { + err = Format_Error.Duplicate_Header_Field + return + } + current_field^, ok = strconv.parse_int(value) + if !ok { + err = Format_Error.Invalid_Header_Value + return + } + } + + // extra info + header.depth = 2 if header.maxval > int(max(u8)) else 1 + + // limit checking + if header.width < 1 \ + || header.height < 1 \ + || header.depth < 1 \ + || header.maxval < 1 \ + || header.maxval > int(max(u16)) { + err = Format_Error.Invalid_Header_Value + return + } + + header.tupltype = strings.clone(strings.to_string(tupltype)) + err = Format_Error.None + return +} + +@(private) +_parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Error) { + // we can just cycle through tokens for PFM + field_iterator := string(data) + field, ok := strings.fields_iterator(&field_iterator) + + switch field { + case "Pf": + header.format = .Pf + header.channels = 1 + case "PF": + header.format = .PF + header.channels = 3 + case: + err = Format_Error.Invalid_Signature + return + } + + // floating point + header.depth = 4 + + // width + field, ok = strings.fields_iterator(&field_iterator) + if !ok { + err = Format_Error.Incomplete_Header + return + } + header.width, ok = strconv.parse_int(field) + if !ok { + err = Format_Error.Invalid_Header_Value + return + } + + // height + field, ok = strings.fields_iterator(&field_iterator) + if !ok { + err = Format_Error.Incomplete_Header + return + } + header.height, ok = strconv.parse_int(field) + if !ok { + err = Format_Error.Invalid_Header_Value + return + } + + // scale (sign is endianness) + field, ok = strings.fields_iterator(&field_iterator) + if !ok { + err = Format_Error.Incomplete_Header + return + } + header.scale, ok = strconv.parse_f32(field) + if !ok { + err = Format_Error.Invalid_Header_Value + return + } + + if header.scale < 0.0 { + header.little_endian = true + header.scale = -header.scale + } + + // pointer math to get header size + length = int((uintptr(raw_data(field_iterator)) + 1) - uintptr(raw_data(data))) + + // limit checking + if header.width < 1 \ + || header.height < 1 \ + || header.scale == 0.0 { + err = Format_Error.Invalid_Header_Value + return + } + + err = Format_Error.None + return +} + + + +decode_image :: proc(header: Header, data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { + context.allocator = allocator + + img = Image { + width = header.width, + height = header.height, + channels = header.channels, + depth = header.depth, + } + + buffer_size := img.width * img.height * img.channels * img.depth + + // we can check data size for binary formats + if header.format in BINARY { + if header.format == .P4 { + p4_size := (img.width / 8 + 1) * img.height + if len(data) < p4_size { + err = Format_Error.Buffer_Too_Small + return + } + } else { + if len(data) < buffer_size { + err = Format_Error.Buffer_Too_Small + return + } + } + } + + // for ASCII and P4, we use length for the termination condition, so start at 0 + // BINARY will be a simple memcopy so the buffer length should also be initialised + if header.format in ASCII || header.format == .P4 { + bytes.buffer_init_allocator(&img.pixels, 0, buffer_size) + } else { + bytes.buffer_init_allocator(&img.pixels, buffer_size, buffer_size) + } + + switch header.format { + // Compressed binary + case .P4: + for d in data { + for b in 1 ..= 8 { + bit := byte(8 - b) + pix := (d >> bit) & 1 + bytes.buffer_write_byte(&img.pixels, pix) + if len(img.pixels.buf) % img.width == 0 { + break + } + } + + if len(img.pixels.buf) == cap(img.pixels.buf) { + break + } + } + + // Simple binary + case .P5, .P6, .P7, .Pf, .PF: + mem.copy(raw_data(img.pixels.buf), raw_data(data), buffer_size) + + // convert to native endianness + if header.format in PFM { + pixels := mem.slice_data_cast([]f32, img.pixels.buf[:]) + if header.little_endian { + for p in &pixels { + p = f32(transmute(f32le) p) + } + } else { + for p in &pixels { + p = f32(transmute(f32be) p) + } + } + } else { + if img.depth == 2 { + pixels := mem.slice_data_cast([]u16, img.pixels.buf[:]) + for p in &pixels { + p = u16(transmute(u16be) p) + } + } + } + + // If-it-looks-like-a-bitmap ASCII + case .P1: + for c in data { + switch c { + case '0', '1': + bytes.buffer_write_byte(&img.pixels, c - '0') + } + + if len(img.pixels.buf) == cap(img.pixels.buf) { + break + } + } + + if len(img.pixels.buf) < cap(img.pixels.buf) { + err = Format_Error.Buffer_Too_Small + return + } + + // Token ASCII + case .P2, .P3: + field_iterator := string(data) + for field in strings.fields_iterator(&field_iterator) { + value, ok := strconv.parse_int(field) + if !ok { + err = Format_Error.Invalid_Buffer_ASCII_Token + return + } + + //? do we want to enforce the maxval, the limit, or neither + if value > int(max(u16)) /*header.maxval*/ { + err = Format_Error.Invalid_Buffer_Value + return + } + + switch img.depth { + case 1: + bytes.buffer_write_byte(&img.pixels, u8(value)) + case 2: + vb := transmute([2]u8) u16(value) + bytes.buffer_write(&img.pixels, vb[:]) + } + + if len(img.pixels.buf) == cap(img.pixels.buf) { + break + } + } + + if len(img.pixels.buf) < cap(img.pixels.buf) { + err = Format_Error.Buffer_Too_Small + return + } + } + + err = Format_Error.None + return +} From b6abd691f487d4583df65e7127d05b3feaf9f181 Mon Sep 17 00:00:00 2001 From: WalterPlinge <22519813+WalterPlinge@users.noreply.github.com> Date: Mon, 18 Apr 2022 20:42:50 +0100 Subject: [PATCH 0554/1052] Image: Fix implicit enum error --- core/image/common.odin | 3 +-- core/image/netpbm/netpbm.odin | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/image/common.odin b/core/image/common.odin index bf93e9313..0ebeb5b72 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -167,6 +167,7 @@ Error :: union #shared_nil { General_Image_Error :: enum { None = 0, Invalid_Image_Dimensions, + Invalid_Number_Of_Channels, Image_Dimensions_Too_Large, Image_Does_Not_Adhere_to_Spec, Invalid_Input_Image, @@ -213,7 +214,6 @@ Netpbm_Error :: enum { // writing File_Not_Writable, Invalid_Format, - Invalid_Number_Of_Channels, Invalid_Image_Depth, } @@ -339,7 +339,6 @@ PNG_Interlace_Method :: enum u8 { QOI_Error :: enum { None = 0, Invalid_QOI_Signature, - Invalid_Number_Of_Channels, // QOI allows 3 or 4 channel data. Invalid_Bit_Depth, // QOI supports only 8-bit images, error only returned from writer. Invalid_Color_Space, // QOI allows 0 = sRGB or 1 = linear. Corrupt, // More data than pixels to decode into, for example. diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index fa8ffc1db..5c082e384 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -104,7 +104,7 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: //? validation if header.format in (PBM + PGM + Formats{.Pf}) && img.channels != 1 \ || header.format in (PPM + Formats{.PF}) && img.channels != 3 { - err = Format_Error.Invalid_Number_Of_Channels + err = .Invalid_Number_Of_Channels return } From fdd24f787fd6df5c1f3339d6317c76a1bafe60f5 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 18 Apr 2022 23:28:34 +0200 Subject: [PATCH 0555/1052] [image/tga] Writer for RGB(A) 8-bit images. --- core/image/common.odin | 14 ++++++ core/image/tga/tga.odin | 103 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 core/image/tga/tga.odin diff --git a/core/image/common.odin b/core/image/common.odin index 2e7bca17e..8c77ec48a 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -320,6 +320,20 @@ QOI_Info :: struct { header: QOI_Header, } +TGA_Header :: struct #packed { + id_length: u8, + color_map_type: u8, + data_type_code: u8, + color_map_origin: u16le, + color_map_length: u16le, + color_map_depth: u8, + origin: [2]u16le, + dimensions: [2]u16le, + bits_per_pixel: u8, + image_descriptor: u8, +} +#assert(size_of(TGA_Header) == 18) + // Function to help with image buffer calculations compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) { size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height diff --git a/core/image/tga/tga.odin b/core/image/tga/tga.odin new file mode 100644 index 000000000..3c860cb62 --- /dev/null +++ b/core/image/tga/tga.odin @@ -0,0 +1,103 @@ +/* + Copyright 2022 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ + + +// package tga implements a TGA image writer for 8-bit RGB and RGBA images. +package tga + +import "core:mem" +import "core:image" +import "core:compress" +import "core:bytes" +import "core:os" + +Error :: image.Error +General :: compress.General_Error +Image :: image.Image +Options :: image.Options + +RGB_Pixel :: image.RGB_Pixel +RGBA_Pixel :: image.RGBA_Pixel + +save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + if img == nil { + return .Invalid_Input_Image + } + + if output == nil { + return .Invalid_Output + } + + pixels := img.width * img.height + if pixels == 0 || pixels > image.MAX_DIMENSIONS || img.width > 65535 || img.height > 65535 { + return .Invalid_Input_Image + } + + // Our TGA writer supports only 8-bit images with 3 or 4 channels. + if img.depth != 8 || img.channels < 3 || img.channels > 4 { + return .Invalid_Input_Image + } + + if img.channels * pixels != len(img.pixels.buf) { + return .Invalid_Input_Image + } + + written := 0 + + // Calculate and allocate necessary space. + necessary := pixels * img.channels + size_of(image.TGA_Header) + + if !resize(&output.buf, necessary) { + return General.Resize_Failed + } + + header := image.TGA_Header{ + data_type_code = 0x02, // Color, uncompressed. + dimensions = {u16le(img.width), u16le(img.height)}, + bits_per_pixel = u8(img.depth * img.channels), + image_descriptor = 1 << 5, // Origin is top left. + } + header_bytes := transmute([size_of(image.TGA_Header)]u8)header + + copy(output.buf[written:], header_bytes[:]) + written += size_of(image.TGA_Header) + + /* + Encode loop starts here. + */ + if img.channels == 3 { + pix := mem.slice_data_cast([]RGB_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGB_Pixel, output.buf[written:]) + for p, i in pix { + out[i] = p.bgr + } + } else if img.channels == 4 { + pix := mem.slice_data_cast([]RGBA_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGBA_Pixel, output.buf[written:]) + for p, i in pix { + out[i] = p.bgra + } + } + return nil +} + +save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + out := &bytes.Buffer{} + defer bytes.buffer_destroy(out) + + save_to_memory(out, img, options) or_return + write_ok := os.write_entire_file(output, out.buf[:]) + + return nil if write_ok else General.Cannot_Open_File +} + +save :: proc{save_to_memory, save_to_file} \ No newline at end of file From aa4eb35671c519c520bd25ff90837c1d70558c6b Mon Sep 17 00:00:00 2001 From: hikari Date: Tue, 19 Apr 2022 05:58:22 +0300 Subject: [PATCH 0556/1052] sys/windows: add some procedures --- core/sys/windows/kernel32.odin | 7 +++++++ core/sys/windows/user32.odin | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 735e065e2..cb90f71da 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -62,6 +62,13 @@ foreign kernel32 { GetCurrentProcessId :: proc() -> DWORD --- GetCurrentThread :: proc() -> HANDLE --- GetCurrentThreadId :: proc() -> DWORD --- + GetProcessTimes :: proc( + hProcess: HANDLE, + lpCreationTime: LPFILETIME, + lpExitTime: LPFILETIME, + lpKernelTime: LPFILETIME, + lpUserTime: LPFILETIME, + ) -> BOOL --- GetStdHandle :: proc(which: DWORD) -> HANDLE --- ExitProcess :: proc(uExitCode: c_uint) -> ! --- DeviceIoControl :: proc( diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 2316d3363..dd45df42a 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -60,6 +60,12 @@ foreign user32 { DestroyWindow :: proc(hWnd: HWND) -> BOOL --- ShowWindow :: proc(hWnd: HWND, nCmdShow: c_int) -> BOOL --- + BringWindowToTop :: proc(hWnd: HWND) -> BOOL --- + GetTopWindow :: proc(hWnd: HWND) -> HWND --- + SetForegroundWindow :: proc(hWnd: HWND) -> BOOL --- + GetForegroundWindow :: proc() -> HWND --- + SetActiveWindow :: proc(hWnd: HWND) -> HWND --- + GetActiveWindow :: proc() -> HWND --- GetMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- From ded8342f3fdb176d6c264057f3bdcb890bfcfad7 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Tue, 19 Apr 2022 20:46:33 +0800 Subject: [PATCH 0557/1052] Reduce allocations --- core/container/lru/lru_cache.odin | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/container/lru/lru_cache.odin b/core/container/lru/lru_cache.odin index 81f0142b0..b59f29f0c 100644 --- a/core/container/lru/lru_cache.odin +++ b/core/container/lru/lru_cache.odin @@ -65,20 +65,22 @@ set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Alloc return nil } - e := new(Node(Key, Value), c.node_allocator) or_return - e.key = key - e.value = value - + e : ^Node(Key, Value) = nil assert(c.count <= c.capacity) if c.count == c.capacity { - _remove_node(c, c.tail) + e = c.tail + _remove_node(c, e) } else { c.count += 1 + e = new(Node(Key, Value), c.node_allocator) or_return } - _push_front_node(c, e) + e.key = key + e.value = value + _push_front_node(c, e) c.entries[key] = e + return nil } @@ -128,6 +130,7 @@ remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool { return false } _remove_node(c, e) + free(node, c.node_allocator) c.count -= 1 return true } @@ -153,9 +156,6 @@ _remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) { delete_key(&c.entries, node.key) _call_on_remove(c, node) - - free(node, c.node_allocator) - } @(private) From 7654afc2db9e88b1803862310698ca047bf10a01 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 19 Apr 2022 15:01:54 +0200 Subject: [PATCH 0558/1052] Revert "Update `mem.nil_allocator` to match the same in `runtime`" The change broke JSON unmarshaling. This reverts commit 4484a3433d6c58f1d1c594a4c36317f323cb5102. --- core/mem/allocators.odin | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 4954122ed..b8bd9a065 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -6,24 +6,7 @@ import "core:runtime" nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) { - switch mode { - case .Alloc: - return nil, .Out_Of_Memory - case .Free: - return nil, .None - case .Free_All: - return nil, .Mode_Not_Implemented - case .Resize: - if size == 0 { - return nil, .None - } - return nil, .Out_Of_Memory - case .Query_Features: - return nil, .Mode_Not_Implemented - case .Query_Info: - return nil, .Mode_Not_Implemented - } - return nil, .None + return nil, nil } nil_allocator :: proc() -> Allocator { From 323e7a2d02819ef0b7137abbdfee8a0d48f5cecb Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 19 Apr 2022 15:03:09 +0200 Subject: [PATCH 0559/1052] Add JSON unmarshal test. --- tests/core/encoding/json/test_core_json.odin | 253 +++++++++++++++++++ 1 file changed, 253 insertions(+) diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin index 285cc04a1..c83710352 100644 --- a/tests/core/encoding/json/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -31,6 +31,7 @@ main :: proc() { parse_json(&t) marshal_json(&t) + unmarshal_json(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) if TEST_fail > 0 { @@ -90,3 +91,255 @@ marshal_json :: proc(t: ^testing.T) { expect(t, err == nil, "expected json error to be none") } + +PRODUCTS := ` +{ + "cash": "0", + "products": [ + { + "name": "Cog Cola", + "cost": "3", + "owned": "1", + + "profit": "4", + "seconds": 3, + "multiplier": 1, + "auto_click": false + }, + { + "name": "gingerBeer", + "cost": "9", + "owned": "0", + + "profit": "16", + "seconds": 5, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Coffee", + "cost": "27", + "owned": "0", + + "profit": "64", + "seconds": 7, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Haggis", + "cost": "81", + "owned": "0", + + "profit": "256", + "seconds": 11, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Lasagna", + "cost": "243", + "owned": "0", + + "profit": "1024", + "seconds": 13, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Asparagus", + "cost": "729", + "owned": "0", + + "profit": "4096", + "seconds": 17, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Yorkshire Pudding", + "cost": "2187", + "owned": "0", + + "profit": "16384", + "seconds": 19, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Salmon Wrap", + "cost": "6561", + "owned": "0", + + "profit": "65536", + "seconds": 23, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Poke Bowl", + "cost": "19683", + "owned": "0", + + "profit": "262144", + "seconds": 29, + "multiplier": 1, + "auto_click": false + }, + { + "name": "Chili Con Carne", + "cost": "59049", + "owned": "0", + + "profit": "1048576", + "seconds": 59, + "multiplier": 1, + "auto_click": false + }, + ], +} +` + +original_data := Game_Marshal{ + cash = "0", + products = { + { + name = "Cog Cola", + cost = "3", + owned = "1", + profit = "4", + seconds = 3, + multiplier = 1, + auto_click = false, + }, + { + name = "gingerBeer", + cost = "9", + owned = "0", + profit = "16", + seconds = 5, + multiplier = 1, + auto_click = false, + }, + { + name = "Coffee", + cost = "27", + owned = "0", + profit = "64", + seconds = 7, + multiplier = 1, + auto_click = false, + }, + { + name = "Haggis", + cost = "81", + owned = "0", + profit = "256", + seconds = 11, + multiplier = 1, + auto_click = false, + }, + { + name = "Lasagna", + cost = "243", + owned = "0", + profit = "1024", + seconds = 13, + multiplier = 1, + auto_click = false, + }, + { + name = "Asparagus", + cost = "729", + owned = "0", + profit = "4096", + seconds = 17, + multiplier = 1, + auto_click = false, + }, + { + name = "Yorkshire Pudding", + cost = "2187", + owned = "0", + profit = "16384", + seconds = 19, + multiplier = 1, + auto_click = false, + }, + { + name = "Salmon Wrap", + cost = "6561", + owned = "0", + profit = "65536", + seconds = 23, + multiplier = 1, + auto_click = false, + }, + { + name = "Poke Bowl", + cost = "19683", + owned = "0", + profit = "262144", + seconds = 29, + multiplier = 1, + auto_click = false, + }, + { + name = "Chili Con Carne", + cost = "59049", + owned = "0", + profit = "1048576", + seconds = 59, + multiplier = 1, + auto_click = false, + }, + }, +} + +Product_Marshal :: struct { + name: cstring, + owned: string, + + cost: string, + + profit: string, + seconds: int, + multiplier: int, + + auto_click: bool, +} + +Game_Marshal :: struct { + cash: string, + products: []Product_Marshal, +} + +cleanup :: proc(g: Game_Marshal) { + for p in g.products { + delete(p.name) + delete(p.owned) + delete(p.cost) + delete(p.profit) + } + delete(g.products) + delete(g.cash) +} + +@test +unmarshal_json :: proc(t: ^testing.T) { + g: Game_Marshal + err := json.unmarshal(transmute([]u8)PRODUCTS, &g, json.DEFAULT_SPECIFICATION) + defer cleanup(g) + + expect(t, err == nil, "Expected json error to be nil") + + msg := fmt.tprintf("Expected %v products to have been unmarshaled, got %v", len(original_data.products), len(g.products)) + expect(t, len(g.products) == len(original_data.products), msg) + + msg = fmt.tprintf("Expected cash to have been unmarshaled as %v, got %v", original_data.cash, g.cash) + expect(t, original_data.cash == g.cash, "Cash unmarshaled improperly") + + for p, i in g.products { + expect(t, p == original_data.products[i], "Producted unmarshaled improperly") + } +} \ No newline at end of file From 581255bf23af90b77bb2b6e2671b40e2b565754e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 19 Apr 2022 20:04:38 +0200 Subject: [PATCH 0560/1052] Fix unmarshal for escaped strings. --- core/encoding/json/parser.odin | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index c682ec9bd..0b9a1cf33 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -281,6 +281,11 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) { // IMPORTANT NOTE(bill): unquote_string assumes a mostly valid string unquote_string :: proc(token: Token, spec: Specification, allocator := context.allocator) -> (value: string, err: Error) { + if allocator.data == nil { + // We were called from `unmarshal_count_array`, return early. + return "", nil + } + get_u2_rune :: proc(s: string) -> rune { if len(s) < 4 || s[0] != '\\' || s[1] != 'x' { return -1 From 29b2c0476698d0f4b240e87945cfa278da82b57a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 19 Apr 2022 20:11:02 +0200 Subject: [PATCH 0561/1052] Revert "Fix unmarshal for escaped strings." This reverts commit 581255bf23af90b77bb2b6e2671b40e2b565754e. --- core/encoding/json/parser.odin | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index 0b9a1cf33..c682ec9bd 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -281,11 +281,6 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) { // IMPORTANT NOTE(bill): unquote_string assumes a mostly valid string unquote_string :: proc(token: Token, spec: Specification, allocator := context.allocator) -> (value: string, err: Error) { - if allocator.data == nil { - // We were called from `unmarshal_count_array`, return early. - return "", nil - } - get_u2_rune :: proc(s: string) -> rune { if len(s) < 4 || s[0] != '\\' || s[1] != 'x' { return -1 From a30b9b17b3a91bc856a037c1e1025e389a8524b3 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 19 Apr 2022 20:32:22 +0200 Subject: [PATCH 0562/1052] [json/unmarshal] Fix quoted strings. --- core/encoding/json/parser.odin | 6 ++++++ tests/core/encoding/json/test_core_json.odin | 20 +++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index c682ec9bd..7bf88c565 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -354,6 +354,12 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a b := bytes_make(len(s) + 2*utf8.UTF_MAX, 1, allocator) or_return w := copy(b, s[0:i]) + + if len(b) == 0 && allocator.data == nil { + // `unmarshal_count_array` calls us with a nil allocator + return string(b[:w]), nil + } + loop: for i < len(s) { c := s[i] switch { diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin index c83710352..0e6a6412f 100644 --- a/tests/core/encoding/json/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -71,7 +71,8 @@ parse_json :: proc(t: ^testing.T) { _, err := json.parse(transmute([]u8)json_data) - expect(t, err == .None, "expected json error to be none") + msg := fmt.tprintf("Expected `json.parse` to return nil, got %v", err) + expect(t, err == nil, msg) } @test @@ -88,8 +89,8 @@ marshal_json :: proc(t: ^testing.T) { } _, err := json.marshal(my_struct) - - expect(t, err == nil, "expected json error to be none") + msg := fmt.tprintf("Expected `json.marshal` to return nil, got %v", err) + expect(t, err == nil, msg) } PRODUCTS := ` @@ -97,7 +98,7 @@ PRODUCTS := ` "cash": "0", "products": [ { - "name": "Cog Cola", + "name": "Cog\nCola", "cost": "3", "owned": "1", @@ -204,7 +205,7 @@ original_data := Game_Marshal{ cash = "0", products = { { - name = "Cog Cola", + name = "Cog\nCola", cost = "3", owned = "1", profit = "4", @@ -331,13 +332,14 @@ unmarshal_json :: proc(t: ^testing.T) { err := json.unmarshal(transmute([]u8)PRODUCTS, &g, json.DEFAULT_SPECIFICATION) defer cleanup(g) - expect(t, err == nil, "Expected json error to be nil") + msg := fmt.tprintf("Expected `json.unmarshal` to return nil, got %v", err) + expect(t, err == nil, msg) - msg := fmt.tprintf("Expected %v products to have been unmarshaled, got %v", len(original_data.products), len(g.products)) + msg = fmt.tprintf("Expected %v products to have been unmarshaled, got %v", len(original_data.products), len(g.products)) expect(t, len(g.products) == len(original_data.products), msg) - msg = fmt.tprintf("Expected cash to have been unmarshaled as %v, got %v", original_data.cash, g.cash) - expect(t, original_data.cash == g.cash, "Cash unmarshaled improperly") + msg = fmt.tprintf("Expected cash to have been unmarshaled as %v, got %v", original_data.cash, g.cash) + expect(t, original_data.cash == g.cash, msg) for p, i in g.products { expect(t, p == original_data.products[i], "Producted unmarshaled improperly") From eee97f7f62bbd65dd03ea3ec8668fef3fcfc685c Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 21 Apr 2022 20:49:32 +0300 Subject: [PATCH 0563/1052] strings: add levenshtein_distance procedure --- core/strings/strings.odin | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 8e774b367..87bbb42cf 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1809,3 +1809,62 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { s^ = s[len(s):] return } + +// `levenshtein_distance` returns the Levenshtein edit distance between 2 strings. +// This is a single-row-version of the Wagner–Fischer algorithm, based on C code by Martin Ettl. +// Note: allocator isn't used if the length of string b in runes is smaller than 70. +levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> int { + LEVENSHTEIN_DEFAULT_COSTS: []int : { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + } + + m, n := utf8.rune_count_in_string(a), utf8.rune_count_in_string(b) + + if m == 0 do return n + if n == 0 do return m + + costs: []int + + if n + 1 > len(LEVENSHTEIN_DEFAULT_COSTS) { + costs = make([]int, n + 1, allocator) + } else { + costs = LEVENSHTEIN_DEFAULT_COSTS + } + + defer if n + 1 > len(LEVENSHTEIN_DEFAULT_COSTS) { + delete(costs, allocator) + } + + for k in 0..=n { + costs[k] = k + } + + i: int + for c1 in a { + costs[0] = i + 1 + corner := i + j: int + for c2 in b { + upper := costs[j + 1] + if c1 == c2 { + costs[j + 1] = corner + } else { + t := upper if upper < corner else corner + costs[j + 1] = (costs[j] if costs[j] < t else t) + 1 + } + + corner = upper + j += 1 + } + + i += 1 + } + + return costs[n] +} From 591732f347c094e706471994996fcffa44687e89 Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 21 Apr 2022 20:58:50 +0300 Subject: [PATCH 0564/1052] strings: levenshtein_distance: remove costs calculation for default array --- core/strings/strings.odin | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 87bbb42cf..3b33a5dc8 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1833,6 +1833,9 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> in if n + 1 > len(LEVENSHTEIN_DEFAULT_COSTS) { costs = make([]int, n + 1, allocator) + for k in 0..=n { + costs[k] = k + } } else { costs = LEVENSHTEIN_DEFAULT_COSTS } @@ -1841,10 +1844,6 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> in delete(costs, allocator) } - for k in 0..=n { - costs[k] = k - } - i: int for c1 in a { costs[0] = i + 1 From d8f0da164b92f52eda045d77e5f6abb5c5146f2a Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 21 Apr 2022 21:15:11 +0300 Subject: [PATCH 0565/1052] strings: levenshtein_distance: improve potential caching --- core/strings/strings.odin | 43 ++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 3b33a5dc8..f876aab3d 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -15,7 +15,7 @@ clone :: proc(s: string, allocator := context.allocator, loc := #caller_location } // returns a clone of the string `s` allocated using the `allocator` as a cstring -// a nul byte is appended to the clone, to make the cstring safe +// a nul byte is appended to the clone, to make the cstring safe clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> cstring { c := make([]byte, len(s)+1, allocator, loc) copy(c, s) @@ -37,7 +37,7 @@ string_from_nul_terminated_ptr :: proc(ptr: ^byte, len: int) -> string { return s } -// returns the raw ^byte start of the string `str` +// returns the raw ^byte start of the string `str` ptr_from_string :: proc(str: string) -> ^byte { d := transmute(mem.Raw_String)str return d.data @@ -969,7 +969,7 @@ count :: proc(s, substr: string) -> int { repeats the string `s` multiple `count` times and returns the allocated string panics when `count` is below 0 - strings.repeat("abc", 2) -> "abcabc" + strings.repeat("abc", 2) -> "abcabc" */ repeat :: proc(s: string, count: int, allocator := context.allocator) -> string { if count < 0 { @@ -1378,7 +1378,7 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator // skip when no results if substrings_found < 1 { - return + return } buf = make([]string, substrings_found + 1, allocator) @@ -1812,16 +1812,35 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { // `levenshtein_distance` returns the Levenshtein edit distance between 2 strings. // This is a single-row-version of the Wagner–Fischer algorithm, based on C code by Martin Ettl. -// Note: allocator isn't used if the length of string b in runes is smaller than 70. +// Note: allocator isn't used if the length of string b in runes is smaller than 256. levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> int { LEVENSHTEIN_DEFAULT_COSTS: []int : { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, } m, n := utf8.rune_count_in_string(a), utf8.rune_count_in_string(b) From 71b1cce517e421fd7eeff4d5ac15e5165dd318c0 Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 21 Apr 2022 21:19:11 +0300 Subject: [PATCH 0566/1052] strings: levenshtein_distance: 64 is actually faster than 256 --- core/strings/strings.odin | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index f876aab3d..6e01f5c8a 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1812,7 +1812,7 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { // `levenshtein_distance` returns the Levenshtein edit distance between 2 strings. // This is a single-row-version of the Wagner–Fischer algorithm, based on C code by Martin Ettl. -// Note: allocator isn't used if the length of string b in runes is smaller than 256. +// Note: allocator isn't used if the length of string b in runes is smaller than 64. levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> int { LEVENSHTEIN_DEFAULT_COSTS: []int : { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, @@ -1821,26 +1821,7 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> in 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, + 60, 61, 62, 63, } m, n := utf8.rune_count_in_string(a), utf8.rune_count_in_string(b) From f0267536929c5909a8098baf95cb5eb1a4fa6522 Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 21 Apr 2022 21:19:43 +0300 Subject: [PATCH 0567/1052] strings: levenshtein_distance: remove `do` --- core/strings/strings.odin | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 6e01f5c8a..a3d9fa93e 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1826,8 +1826,12 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> in m, n := utf8.rune_count_in_string(a), utf8.rune_count_in_string(b) - if m == 0 do return n - if n == 0 do return m + if m == 0 { + return n + } + if n == 0 { + return m + } costs: []int From e799476f90537ca173205a64da1fbf87b894b42e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 22 Apr 2022 16:55:47 +0200 Subject: [PATCH 0568/1052] [compress/shoco] Add short string compressor. --- core/compress/shoco/model.odin | 148 +++++++++ core/compress/shoco/shoco.odin | 318 ++++++++++++++++++++ examples/all/all_main.odin | 2 + tests/core/assets/Shoco/LICENSE | 26 ++ tests/core/assets/Shoco/LICENSE.shoco | Bin 0 -> 1269 bytes tests/core/assets/Shoco/README.md | 95 ++++++ tests/core/assets/Shoco/README.md.shoco | Bin 0 -> 2227 bytes tests/core/compress/test_core_compress.odin | 57 +++- 8 files changed, 645 insertions(+), 1 deletion(-) create mode 100644 core/compress/shoco/model.odin create mode 100644 core/compress/shoco/shoco.odin create mode 100644 tests/core/assets/Shoco/LICENSE create mode 100644 tests/core/assets/Shoco/LICENSE.shoco create mode 100644 tests/core/assets/Shoco/README.md create mode 100644 tests/core/assets/Shoco/README.md.shoco diff --git a/core/compress/shoco/model.odin b/core/compress/shoco/model.odin new file mode 100644 index 000000000..49e3dd97e --- /dev/null +++ b/core/compress/shoco/model.odin @@ -0,0 +1,148 @@ +/* + This file was generated, so don't edit this by hand. + Transliterated from https://github.com/Ed-von-Schleck/shoco/blob/master/shoco_model.h, + which is an English word model. +*/ + +// package shoco is an implementation of the shoco short string compressor +package shoco + +DEFAULT_MODEL :: Shoco_Model { + min_char = 39, + max_char = 122, + characters_by_id = { + 'e', 'a', 'i', 'o', 't', 'h', 'n', 'r', 's', 'l', 'u', 'c', 'w', 'm', 'd', 'b', 'p', 'f', 'g', 'v', 'y', 'k', '-', 'H', 'M', 'T', '\'', 'B', 'x', 'I', 'W', 'L', + }, + ids_by_character = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, 23, 29, -1, -1, 31, 24, -1, -1, -1, -1, -1, -1, 25, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 15, 11, 14, 0, 17, 18, 5, 2, -1, 21, 9, 13, 6, 3, 16, -1, 7, 8, 4, 10, 19, 12, 28, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }, + successors_by_bigram = { + {7, 4, 12, -1, 6, -1, 1, 0, 3, 5, -1, 9, -1, 8, 2, -1, 15, 14, -1, 10, 11, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1}, + {-1, -1, 6, -1, 1, -1, 0, 3, 2, 4, 15, 11, -1, 9, 5, 10, 13, -1, 12, 8, 7, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 11, -1, 4, 2, -1, 0, 8, 1, 5, -1, 6, -1, 3, 7, 15, -1, 12, 10, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, 14, 7, 5, -1, 1, 2, 8, 9, 0, 15, 6, 4, 11, -1, 12, 3, -1, 10, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 1, 5, 0, -1, 6, 10, 9, 7, 12, 11, -1, -1, -1, -1, 13, -1, -1, 8, -1, 15, -1, -1, -1, 14, -1, -1, -1, -1, -1}, + {0, 1, 2, 3, 4, -1, -1, 5, 9, 10, 6, -1, -1, 8, 15, 11, -1, 14, -1, -1, 7, -1, 13, -1, -1, -1, 12, -1, -1, -1, -1, -1}, + {2, 8, 7, 4, 3, -1, 9, -1, 6, 11, -1, 5, -1, -1, 0, -1, -1, 14, 1, 15, 10, 12, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1}, + {0, 3, 1, 2, 6, -1, 9, 8, 4, 12, 13, 10, -1, 11, 7, -1, -1, 15, 14, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 6, 3, 4, 1, 2, -1, -1, 5, 10, 7, 9, 11, 12, -1, -1, 8, 14, -1, -1, 15, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 6, 2, 5, 9, -1, -1, -1, 10, 1, 8, -1, 12, 14, 4, -1, 15, 7, -1, 13, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 10, 9, 15, 1, -1, 4, 0, 3, 2, -1, 6, -1, 12, 11, 13, 7, 14, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 6, 0, 4, 2, -1, 7, 13, 8, 9, 11, -1, -1, 15, -1, -1, -1, -1, -1, 10, 5, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 1, 4, -1, 2, 5, 6, 7, 8, -1, 14, -1, -1, 9, 15, -1, 12, -1, -1, -1, 10, 11, -1, -1, -1, 13, -1, -1, -1, -1, -1}, + {0, 1, 3, 2, 15, -1, 12, -1, 7, 14, 4, -1, -1, 9, -1, 8, 5, 10, -1, -1, 6, -1, 13, -1, -1, -1, 11, -1, -1, -1, -1, -1}, + {0, 3, 1, 2, -1, -1, 12, 6, 4, 9, 7, -1, -1, 14, 8, -1, -1, 15, 11, 13, 5, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 7, 2, 10, 13, -1, 6, 8, 1, 3, -1, -1, 14, 15, 11, -1, -1, -1, 12, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 2, 6, 3, 7, 10, -1, 1, 9, 4, 8, -1, -1, 15, -1, 12, 5, -1, -1, -1, 11, -1, 13, -1, -1, -1, 14, -1, -1, -1, -1, -1}, + {1, 3, 4, 0, 7, -1, 12, 2, 11, 8, 6, 13, -1, -1, -1, -1, -1, 5, -1, -1, 10, 15, 9, -1, -1, -1, 14, -1, -1, -1, -1, -1}, + {1, 3, 5, 2, 13, 0, 9, 4, 7, 6, 8, -1, -1, 15, -1, 11, -1, -1, 10, -1, 14, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 2, 1, 3, -1, -1, -1, 6, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 4, 0, 3, -1, 13, 12, 2, 7, -1, -1, 15, 10, 5, 8, 14, -1, -1, -1, -1, -1, 9, -1, -1, -1, 6, -1, -1, -1, -1, -1}, + {0, 9, 2, 14, 15, 4, 1, 13, 3, 5, -1, -1, 10, -1, -1, -1, -1, 6, 12, -1, 7, -1, 8, -1, -1, -1, 11, -1, -1, -1, -1, -1}, + {-1, 2, 14, -1, 1, 5, 8, 7, 4, 12, -1, 6, 9, 11, 13, 3, 10, 15, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 3, 2, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 1, 5, -1, -1, -1, 0, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 8, 4, 1, -1, 0, -1, 6, -1, -1, 5, -1, 7, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1}, + {12, 5, -1, -1, 1, -1, -1, 7, 0, 3, -1, 2, -1, 4, 6, -1, -1, -1, -1, 8, -1, -1, 15, -1, 13, 9, -1, -1, -1, -1, -1, 11}, + {1, 3, 2, 4, -1, -1, -1, 5, -1, 7, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1}, + {5, 3, 4, 12, 1, 6, -1, -1, -1, -1, 8, 2, -1, -1, -1, -1, 0, 9, -1, -1, 11, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, -1, -1, 0, -1, 1, 12, 3, -1, -1, -1, -1, 5, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, 6, -1, 10}, + {2, 3, 1, 4, -1, 0, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1}, + {5, 1, 3, 0, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 9, -1, -1, 6, -1, 7}, + }, + successors_reversed = { + {'s', 't', 'c', 'l', 'm', 'a', 'd', 'r', 'v', 'T', 'A', 'L', 'e', 'M', 'Y', '-'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'-', 't', 'a', 'b', 's', 'h', 'c', 'r', 'n', 'w', 'p', 'm', 'l', 'd', 'i', 'f'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'u', 'e', 'i', 'a', 'o', 'r', 'y', 'l', 'I', 'E', 'R', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'e', 'a', 'o', 'i', 'u', 'A', 'y', 'E', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'t', 'n', 'f', 's', '\'', 'm', 'I', 'N', 'A', 'E', 'L', 'Z', 'r', 'V', 'R', 'C'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'o', 'a', 'y', 'i', 'u', 'e', 'I', 'L', 'D', '\'', 'E', 'Y', '\x00', '\x00', '\x00', '\x00'}, + {'r', 'i', 'y', 'a', 'e', 'o', 'u', 'Y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'h', 'o', 'e', 'E', 'i', 'u', 'r', 'w', 'a', 'H', 'y', 'R', 'Z', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'h', 'i', 'e', 'a', 'o', 'r', 'I', 'y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'n', 't', 's', 'r', 'l', 'd', 'i', 'y', 'v', 'm', 'b', 'c', 'g', 'p', 'k', 'u'}, + {'e', 'l', 'o', 'u', 'y', 'a', 'r', 'i', 's', 'j', 't', 'b', 'v', 'h', 'm', 'd'}, + {'o', 'e', 'h', 'a', 't', 'k', 'i', 'r', 'l', 'u', 'y', 'c', 'q', 's', '-', 'd'}, + {'e', 'i', 'o', 'a', 's', 'y', 'r', 'u', 'd', 'l', '-', 'g', 'n', 'v', 'm', 'f'}, + {'r', 'n', 'd', 's', 'a', 'l', 't', 'e', 'm', 'c', 'v', 'y', 'i', 'x', 'f', 'p'}, + {'o', 'e', 'r', 'a', 'i', 'f', 'u', 't', 'l', '-', 'y', 's', 'n', 'c', '\'', 'k'}, + {'h', 'e', 'o', 'a', 'r', 'i', 'l', 's', 'u', 'n', 'g', 'b', '-', 't', 'y', 'm'}, + {'e', 'a', 'i', 'o', 't', 'r', 'u', 'y', 'm', 's', 'l', 'b', '\'', '-', 'f', 'd'}, + {'n', 's', 't', 'm', 'o', 'l', 'c', 'd', 'r', 'e', 'g', 'a', 'f', 'v', 'z', 'b'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'e', 'n', 'i', 's', 'h', 'l', 'f', 'y', '-', 'a', 'w', '\'', 'g', 'r', 'o', 't'}, + {'e', 'l', 'i', 'y', 'd', 'o', 'a', 'f', 'u', 't', 's', 'k', 'w', 'v', 'm', 'p'}, + {'e', 'a', 'o', 'i', 'u', 'p', 'y', 's', 'b', 'm', 'f', '\'', 'n', '-', 'l', 't'}, + {'d', 'g', 'e', 't', 'o', 'c', 's', 'i', 'a', 'n', 'y', 'l', 'k', '\'', 'f', 'v'}, + {'u', 'n', 'r', 'f', 'm', 't', 'w', 'o', 's', 'l', 'v', 'd', 'p', 'k', 'i', 'c'}, + {'e', 'r', 'a', 'o', 'l', 'p', 'i', 't', 'u', 's', 'h', 'y', 'b', '-', '\'', 'm'}, + {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'e', 'i', 'o', 'a', 's', 'y', 't', 'd', 'r', 'n', 'c', 'm', 'l', 'u', 'g', 'f'}, + {'e', 't', 'h', 'i', 'o', 's', 'a', 'u', 'p', 'c', 'l', 'w', 'm', 'k', 'f', 'y'}, + {'h', 'o', 'e', 'i', 'a', 't', 'r', 'u', 'y', 'l', 's', 'w', 'c', 'f', '\'', '-'}, + {'r', 't', 'l', 's', 'n', 'g', 'c', 'p', 'e', 'i', 'a', 'd', 'm', 'b', 'f', 'o'}, + {'e', 'i', 'a', 'o', 'y', 'u', 'r', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, + {'a', 'i', 'h', 'e', 'o', 'n', 'r', 's', 'l', 'd', 'k', '-', 'f', '\'', 'c', 'b'}, + {'p', 't', 'c', 'a', 'i', 'e', 'h', 'q', 'u', 'f', '-', 'y', 'o', '\x00', '\x00', '\x00'}, + {'o', 'e', 's', 't', 'i', 'd', '\'', 'l', 'b', '-', 'm', 'a', 'r', 'n', 'p', 'w'}, + }, + + character_count = 32, + successor_count = 16, + + max_successor_n = 7, + packs = { + { 0x80000000, 1, 2, { 26, 24, 24, 24, 24, 24, 24, 24 }, { 15, 3, 0, 0, 0, 0, 0, 0 }, 0xc0, 0x80 }, + { 0xc0000000, 2, 4, { 25, 22, 19, 16, 16, 16, 16, 16 }, { 15, 7, 7, 7, 0, 0, 0, 0 }, 0xe0, 0xc0 }, + { 0xe0000000, 4, 8, { 23, 19, 15, 11, 8, 5, 2, 0 }, { 31, 15, 15, 15, 7, 7, 7, 3 }, 0xf0, 0xe0 }, + }, +} \ No newline at end of file diff --git a/core/compress/shoco/shoco.odin b/core/compress/shoco/shoco.odin new file mode 100644 index 000000000..9c5008f5d --- /dev/null +++ b/core/compress/shoco/shoco.odin @@ -0,0 +1,318 @@ +/* + Copyright 2022 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + List of contributors: + Jeroen van Rijn: Initial implementation. + + An implementation of [shoco](https://github.com/Ed-von-Schleck/shoco) by Christian Schramm. +*/ + +// package shoco is an implementation of the shoco short string compressor +package shoco + +import "core:intrinsics" +import "core:compress" + +Shoco_Pack :: struct { + word: u32, + bytes_packed: i8, + bytes_unpacked: i8, + offsets: [8]u16, + masks: [8]i16, + header_mask: u8, + header: u8, +} + +Shoco_Model :: struct { + min_char: u8, + max_char: u8, + characters_by_id: []u8, + ids_by_character: [256]i16, + successors_by_bigram: [][]i8, + successors_reversed: [][]u8, + + character_count: u8, + successor_count: u8, + max_successor_n: i8, + packs: []Shoco_Pack, +} + +compress_bound :: proc(uncompressed_size: int) -> (worst_case_compressed_size: int) { + // Worst case compression happens when input is non-ASCII (128-255) + // Encoded as 0x00 + the byte in question. + return uncompressed_size * 2 +} + +decompress_bound :: proc(compressed_size: int, model := DEFAULT_MODEL) -> (maximum_decompressed_size: int) { + // Best case compression is 2:1 + most: f64 + for pack in model.packs { + val := f64(compressed_size) / f64(pack.bytes_packed) * f64(pack.bytes_unpacked) + most = max(most, val) + } + return int(most) +} + +find_best_encoding :: proc(indices: []i16, n_consecutive: i8, model := DEFAULT_MODEL) -> (res: int) { + for p := len(model.packs); p > 0; p -= 1 { + pack := model.packs[p - 1] + if n_consecutive >= pack.bytes_unpacked { + have_index := true + for i := 0; i < int(pack.bytes_unpacked); i += 1 { + if indices[i] > pack.masks[i] { + have_index = false + break + } + } + if have_index { + return p - 1 + } + } + } + return -1 +} + +validate_model :: proc(model: Shoco_Model) -> (int, compress.Error) { + if len(model.successors_reversed) != int(model.max_char - model.min_char) { + return 0, .Unknown_Compression_Method + } + + if len(model.characters_by_id) != int(model.character_count) { + return 0, .Unknown_Compression_Method + } + + if len(model.successors_by_bigram) != int(model.character_count) || len(model.successors_by_bigram[0]) != int(model.character_count) { + return 0, .Unknown_Compression_Method + } + + if len(model.successors_reversed[0]) != int(model.successor_count) { + return 0, .Unknown_Compression_Method + } + + // Model seems legit. + return 0, nil +} + +// Decompresses into provided buffer. +decompress_slice_to_output_buffer :: proc(input: []u8, output: []u8, model := DEFAULT_MODEL) -> (size: int, err: compress.Error) { + inp, inp_end := 0, len(input) + out, out_end := 0, len(output) + + validate_model(model) or_return + + for inp < inp_end { + val := transmute(i8)input[inp] + mark := int(-1) + + for val < 0 { + val <<= 1 + mark += 1 + } + + if mark > len(model.packs) { + return out, .Unknown_Compression_Method + } + + if mark < 0 { + if out >= out_end { + return out, .Output_Too_Short + } + + // Ignore the sentinel value for non-ASCII chars + if input[inp] == 0x00 { + inp += 1 + if inp >= inp_end { + return out, .Stream_Too_Short + } + } + output[out] = input[inp] + inp, out = inp + 1, out + 1 + + } else { + pack := model.packs[mark] + + if out + int(pack.bytes_unpacked) > out_end { + return out, .Output_Too_Short + } else if inp + int(pack.bytes_packed) > inp_end { + return out, .Stream_Too_Short + } + + code := intrinsics.unaligned_load((^u32)(&input[inp])) + when ODIN_ENDIAN == .Little { + code = intrinsics.byte_swap(code) + } + + // Unpack the leading char + offset := pack.offsets[0] + mask := pack.masks[0] + + last_chr := model.characters_by_id[(code >> offset) & u32(mask)] + output[out] = last_chr + + // Unpack the successor chars + for i := 1; i < int(pack.bytes_unpacked); i += 1 { + offset = pack.offsets[i] + mask = pack.masks[i] + + last_chr = model.successors_reversed[last_chr - model.min_char][(code >> offset) & u32(mask)] + output[out + i] = last_chr + } + + out += int(pack.bytes_unpacked) + inp += int(pack.bytes_packed) + } + } + + return out, nil +} + +decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (res: string, err: compress.Error) { + context.allocator = allocator + + if len(input) == 0 { + return "", .Stream_Too_Short + } + + max_output_size := decompress_bound(len(input), model) + + buf: [dynamic]u8 + if !resize(&buf, max_output_size) { + return "", .Out_Of_Memory + } + + length, result := decompress_slice_to_output_buffer(input, buf[:]) + resize(&buf, length) + return string(buf[:]), result +} +decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string} + +compress_string_to_buffer :: proc(input: string, output: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (size: int, err: compress.Error) { + inp, inp_end := 0, len(input) + out, out_end := 0, len(output) + output := output + + validate_model(model) or_return + + indices := make([]i16, model.max_successor_n + 1) + defer delete(indices) + + last_resort := false + + encode: for inp < inp_end { + if last_resort { + last_resort = false + + if input[inp] & 0x80 == 0x80 { + // Non-ASCII case + if out + 2 > out_end { + return out, .Output_Too_Short + } + + // Put in a sentinel byte + output[out] = 0x00 + out += 1 + } else { + // An ASCII byte + if out + 1 > out_end { + return out, .Output_Too_Short + } + } + output[out] = input[inp] + out, inp = out + 1, inp + 1 + } else { + // Find the longest string of known successors + indices[0] = model.ids_by_character[input[inp]] + last_chr_index := indices[0] + + if last_chr_index < 0 { + last_resort = true + continue encode + } + + rest := inp_end - inp + n_consecutive: i8 = 1 + for ; n_consecutive <= model.max_successor_n; n_consecutive += 1 { + if inp_end > 0 && int(n_consecutive) == rest { + break + } + + current_index := model.ids_by_character[input[inp + int(n_consecutive)]] + if current_index < 0 { // '\0' is always -1 + break + } + + successor_index := model.successors_by_bigram[last_chr_index][current_index] + if successor_index < 0 { + break + } + + indices[n_consecutive] = i16(successor_index) + last_chr_index = current_index + } + + if n_consecutive < 2 { + last_resort = true + continue encode + } + + pack_n := find_best_encoding(indices, n_consecutive) + if pack_n >= 0 { + if out + int(model.packs[pack_n].bytes_packed) > out_end { + return out, .Output_Too_Short + } + + pack := model.packs[pack_n] + code := pack.word + + for i := 0; i < int(pack.bytes_unpacked); i += 1 { + code |= u32(indices[i]) << pack.offsets[i] + } + + // In the little-endian world, we need to swap what's in the register to match the memory representation. + when ODIN_ENDIAN == .Little { + code = intrinsics.byte_swap(code) + } + out_ptr := raw_data(output[out:]) + + switch pack.bytes_packed { + case 4: + intrinsics.unaligned_store(transmute(^u32)out_ptr, code) + case 2: + intrinsics.unaligned_store(transmute(^u16)out_ptr, u16(code)) + case 1: + intrinsics.unaligned_store(transmute(^u8)out_ptr, u8(code)) + case: + return out, .Unknown_Compression_Method + } + + out += int(pack.bytes_packed) + inp += int(pack.bytes_unpacked) + } else { + last_resort = true + continue encode + } + } + } + return out, nil +} + +compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := context.allocator) -> (output: []u8, err: compress.Error) { + context.allocator = allocator + + if len(input) == 0 { + return {}, .Stream_Too_Short + } + + max_output_size := compress_bound(len(input)) + + buf: [dynamic]u8 + if !resize(&buf, max_output_size) { + return {}, .Out_Of_Memory + } + + length, result := compress_string_to_buffer(input, buf[:]) + resize(&buf, length) + return buf[:length], result +} +compress :: proc{compress_string_to_buffer, compress_string} \ No newline at end of file diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 4f5bfbdc1..27f199062 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -10,6 +10,7 @@ import c "core:c" import libc "core:c/libc" import compress "core:compress" +import shoco "core:compress/shoco" import gzip "core:compress/gzip" import zlib "core:compress/zlib" @@ -115,6 +116,7 @@ _ :: bytes _ :: c _ :: libc _ :: compress +_ :: shoco _ :: gzip _ :: zlib _ :: bit_array diff --git a/tests/core/assets/Shoco/LICENSE b/tests/core/assets/Shoco/LICENSE new file mode 100644 index 000000000..9ca94bcdf --- /dev/null +++ b/tests/core/assets/Shoco/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2016-2021 Ginger Bill. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/core/assets/Shoco/LICENSE.shoco b/tests/core/assets/Shoco/LICENSE.shoco new file mode 100644 index 0000000000000000000000000000000000000000..5d5e4d6236019bf208cc2ebb7a81ed06469b78a8 GIT binary patch literal 1269 zcmah{O=}cE6pS}Bg5XV079PalxF%5)^kUCU?{3TN^w{0A>*B?HY+}H~xDx`oi3E&d zqUIt(5=6*Jy{V{(hy;uW1AY+vKKOxN1%H6ACmW3@dTAc7Usu(uYX8{a$aL?KA#CYt zL3?Z4u5InD?QJN`HP_+w&E~*nVeeBctgjEB%sGyFaC+$Dxl6|}+KsCoBQqUx_>RQ>;av8k~9e?XTDtcz)f#vB>};yZd=z)$zV@`(U(t`ve~CtK;?l>5il6 z(#GTnO}!P?I8w7Chp0ApqHdc59XCii70X*)eBOkCiN=*R;Y@0A7uQU`e_T&-a|HMB z;vp{JfmgpwMh`ArnFQ_dJ;mEq!za-*)87#ObmPnQSq?}CYh8UkeO)x%iC1SP2W%X> z$4QDQ3Jopurot2l)v=Og5%2(B6{g7H%ebmUp=eN)VZfCJivsFKMhP!5k{X+srk9%> zd%>bA_`z6ltsxaeDGmjJ5xQcL5nQ_vksl_3hzc$U0Fg8ZMM)SMGt#xB&Y#a9^C)rU z7YT)VA{3^Y3CRl+S*|>hF~m$6;U^(eh!Yh{%|UB9fzW=)M2QDEVkbuMGLH;&k%i%3 zx3t=S+tK4Bl6fI_GA7zG5Q_W8uJfz%$vM&&y3jHAg)R6&P988-bsLzPA4q73E}ejt zSb=M7`Hv-(iJvH5vYN>Uop{;^lNgSIlz}zc(Oi{<&-Gq}(psNKqPdHJ8I} + Odin logo +
+ The Data-Oriented Language for Sane Software Development. +
+
+
+ + + + + +
+ + + + + + +

+ +# The Odin Programming Language + + +Odin is a general-purpose programming language with distinct typing, built for high performance, modern systems, and built-in data-oriented data types. The Odin Programming Language, the C alternative for the joy of programming. + +Website: [https://odin-lang.org/](https://odin-lang.org/) + +```odin +package main + +import "core:fmt" + +main :: proc() { + program := "+ + * 😃 - /" + accumulator := 0 + + for token in program { + switch token { + case '+': accumulator += 1 + case '-': accumulator -= 1 + case '*': accumulator *= 2 + case '/': accumulator /= 2 + case '😃': accumulator *= accumulator + case: // Ignore everything else + } + } + + fmt.printf("The program \"%s\" calculates the value %d\n", + program, accumulator) +} + +``` + +## Documentation + +#### [Getting Started](https://odin-lang.org/docs/install) + +Instructions for downloading and installing the Odin compiler and libraries. + +#### [Nightly Builds](https://odin-lang.org/docs/nightly/) + +Get the latest nightly builds of Odin. + +### Learning Odin + +#### [Overview of Odin](https://odin-lang.org/docs/overview) + +An overview of the Odin programming language. + +#### [Frequently Asked Questions (FAQ)](https://odin-lang.org/docs/faq) + +Answers to common questions about Odin. + +#### [Packages](https://pkg.odin-lang.org/) + +Documentation for all the official packages part of the [core](https://pkg.odin-lang.org/core/) and [vendor](https://pkg.odin-lang.org/vendor/) library collections. + +#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki) + +A wiki maintained by the Odin community. + +#### [Odin Discord](https://discord.gg/sVBPHEv) + +Get live support and talk with other odiners on the Odin Discord. + +### Articles + +#### [The Odin Blog](https://odin-lang.org/news/) + +The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests. + +## Warnings + +* The Odin compiler is still in development. diff --git a/tests/core/assets/Shoco/README.md.shoco b/tests/core/assets/Shoco/README.md.shoco new file mode 100644 index 0000000000000000000000000000000000000000..013f4f46928fb3d5c6ea62d76ddda91f29c6e420 GIT binary patch literal 2227 zcmb_eZ%i9y7)PfcxS7ZoGd~#fEaBQ-k6W+3qjxPf zYC>CJWrU6`YCtCgWoR-o!-q{UF$3*1i-IUxNkiNghgqT@O#E!(``#apDK*B}K(6m| z&+~hJ&-47=C#_L{n-M~8I{SPdeTV}5sTmeP4SU`6N2(V|vLG|+OpsN^Y2YNyO*b!u zfLLjmicP!eIp3(Osn1P%LqoV9o(QS`lz)fu^`-;E}x(e4@V52eP04=7Z z1P5FfC5E%64(RvkK1>QWzGCi--aLh$Bsj_Dq2Yj0 z9_sOJIUf!Uh*4el*m6pa!C8w8OHu8-XZ2ebbXYRQ^TVoU(*inK@^@P)MRj#`VINB2 zya95XatcLdehF(pXNz3^phif&IRI-G8mHZLUm5Nq8rH}y9)ct_qo7~DtCj^v@*7pv8`pc zwag6_rZ2Ls$hKO+A1j5D|17L!;BMuHbap<8<&>LNFM`BH>*7lgAMAxPHTj<%Qu5KxpDm zFE5d^h2I?Qi;8@&;gm0fY&hWzwIMJMIKm`;|4rIre&j+=B#x=qs(}QwMi#%s<(C|( zZ7t20#n1KV8PxR*oP*imwGi|eVcd^#y9V6#7G3N~8%PNVEWQQiO~EMEoJhmDON8m? zzj{SZ0^^<}K{>4%6?9~a^5JBQP$`*6M|80+oX?58!)|zLF_^uZYU)w9I$-Xjb}=B@ z(SO-@cob+ZAdtle(Tr5pBtYZ+5i9m literal 0 HcmV?d00001 diff --git a/tests/core/compress/test_core_compress.odin b/tests/core/compress/test_core_compress.odin index 51952a568..ee7233e52 100644 --- a/tests/core/compress/test_core_compress.odin +++ b/tests/core/compress/test_core_compress.odin @@ -7,13 +7,14 @@ package test_core_compress List of contributors: Jeroen van Rijn: Initial implementation. - A test suite for ZLIB, GZIP. + A test suite for ZLIB, GZIP and Shoco. */ import "core:testing" import "core:compress/zlib" import "core:compress/gzip" +import "core:compress/shoco" import "core:bytes" import "core:fmt" @@ -48,6 +49,7 @@ main :: proc() { t := testing.T{w=w} zlib_test(&t) gzip_test(&t) + shoco_test(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) if TEST_fail > 0 { @@ -134,3 +136,56 @@ gzip_test :: proc(t: ^testing.T) { expect(t, false, error) } } + +@test +shoco_test :: proc(t: ^testing.T) { + + Shoco_Tests :: []struct{ + compressed: []u8, + raw: []u8, + short_pack: int, + short_sentinel: int, + }{ + { #load("../assets/Shoco/README.md.shoco"), #load("../assets/Shoco/README.md"), 10, 1006 }, + { #load("../assets/Shoco/LICENSE.shoco"), #load("../assets/Shoco/LICENSE"), 25, 68 }, + } + + for v in Shoco_Tests { + expected_raw := len(v.raw) + expected_compressed := len(v.compressed) + + biggest_unpacked := shoco.decompress_bound(expected_compressed) + biggest_packed := shoco.compress_bound(expected_raw) + + buffer := make([]u8, max(biggest_packed, biggest_unpacked)) + defer delete(buffer) + + size, err := shoco.decompress(v.compressed, buffer[:]) + msg := fmt.tprintf("Expected `decompress` to return `nil`, got %v", err) + expect(t, err == nil, msg) + + msg = fmt.tprintf("Decompressed %v bytes into %v. Expected to decompress into %v bytes.", len(v.compressed), size, expected_raw) + expect(t, size == expected_raw, msg) + expect(t, string(buffer[:size]) == string(v.raw), "Decompressed contents don't match.") + + size, err = shoco.compress(string(v.raw), buffer[:]) + expect(t, err == nil, "Expected `compress` to return `nil`.") + + msg = fmt.tprintf("Compressed %v bytes into %v. Expected to compress into %v bytes.", expected_raw, size, expected_compressed) + expect(t, size == expected_compressed, msg) + + size, err = shoco.decompress(v.compressed, buffer[:expected_raw - 10]) + msg = fmt.tprintf("Decompressing into too small a buffer returned %v, expected `.Output_Too_Short`", err) + expect(t, err == .Output_Too_Short, msg) + + size, err = shoco.compress(string(v.raw), buffer[:expected_compressed - 10]) + msg = fmt.tprintf("Compressing into too small a buffer returned %v, expected `.Output_Too_Short`", err) + expect(t, err == .Output_Too_Short, msg) + + size, err = shoco.decompress(v.compressed[:v.short_pack], buffer[:]) + expect(t, err == .Stream_Too_Short, "Expected `decompress` to return `Stream_Too_Short` because there was no more data after selecting a pack.") + + size, err = shoco.decompress(v.compressed[:v.short_sentinel], buffer[:]) + expect(t, err == .Stream_Too_Short, "Expected `decompress` to return `Stream_Too_Short` because there was no more data after non-ASCII sentinel.") + } +} \ No newline at end of file From ac9a358c65820894968cc11b55b08de0646d98d4 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 22 Apr 2022 17:52:38 +0200 Subject: [PATCH 0569/1052] [shoco] Replace 2D slices in model with 1D slices. --- core/compress/shoco/model.odin | 230 ++++++++++++++++----------------- core/compress/shoco/shoco.odin | 22 ++-- 2 files changed, 127 insertions(+), 125 deletions(-) diff --git a/core/compress/shoco/model.odin b/core/compress/shoco/model.odin index 49e3dd97e..bbc38903d 100644 --- a/core/compress/shoco/model.odin +++ b/core/compress/shoco/model.odin @@ -17,123 +17,123 @@ DEFAULT_MODEL :: Shoco_Model { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, 23, 29, -1, -1, 31, 24, -1, -1, -1, -1, -1, -1, 25, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 15, 11, 14, 0, 17, 18, 5, 2, -1, 21, 9, 13, 6, 3, 16, -1, 7, 8, 4, 10, 19, 12, 28, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, successors_by_bigram = { - {7, 4, 12, -1, 6, -1, 1, 0, 3, 5, -1, 9, -1, 8, 2, -1, 15, 14, -1, 10, 11, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1}, - {-1, -1, 6, -1, 1, -1, 0, 3, 2, 4, 15, 11, -1, 9, 5, 10, 13, -1, 12, 8, 7, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 11, -1, 4, 2, -1, 0, 8, 1, 5, -1, 6, -1, 3, 7, 15, -1, 12, 10, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {-1, -1, 14, 7, 5, -1, 1, 2, 8, 9, 0, 15, 6, 4, 11, -1, 12, 3, -1, 10, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 4, 3, 1, 5, 0, -1, 6, 10, 9, 7, 12, 11, -1, -1, -1, -1, 13, -1, -1, 8, -1, 15, -1, -1, -1, 14, -1, -1, -1, -1, -1}, - {0, 1, 2, 3, 4, -1, -1, 5, 9, 10, 6, -1, -1, 8, 15, 11, -1, 14, -1, -1, 7, -1, 13, -1, -1, -1, 12, -1, -1, -1, -1, -1}, - {2, 8, 7, 4, 3, -1, 9, -1, 6, 11, -1, 5, -1, -1, 0, -1, -1, 14, 1, 15, 10, 12, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1}, - {0, 3, 1, 2, 6, -1, 9, 8, 4, 12, 13, 10, -1, 11, 7, -1, -1, 15, 14, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 6, 3, 4, 1, 2, -1, -1, 5, 10, 7, 9, 11, 12, -1, -1, 8, 14, -1, -1, 15, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 6, 2, 5, 9, -1, -1, -1, 10, 1, 8, -1, 12, 14, 4, -1, 15, 7, -1, 13, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 10, 9, 15, 1, -1, 4, 0, 3, 2, -1, 6, -1, 12, 11, 13, 7, 14, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 3, 6, 0, 4, 2, -1, 7, 13, 8, 9, 11, -1, -1, 15, -1, -1, -1, -1, -1, 10, 5, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 1, 4, -1, 2, 5, 6, 7, 8, -1, 14, -1, -1, 9, 15, -1, 12, -1, -1, -1, 10, 11, -1, -1, -1, 13, -1, -1, -1, -1, -1}, - {0, 1, 3, 2, 15, -1, 12, -1, 7, 14, 4, -1, -1, 9, -1, 8, 5, 10, -1, -1, 6, -1, 13, -1, -1, -1, 11, -1, -1, -1, -1, -1}, - {0, 3, 1, 2, -1, -1, 12, 6, 4, 9, 7, -1, -1, 14, 8, -1, -1, 15, 11, 13, 5, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 5, 7, 2, 10, 13, -1, 6, 8, 1, 3, -1, -1, 14, 15, 11, -1, -1, -1, 12, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 2, 6, 3, 7, 10, -1, 1, 9, 4, 8, -1, -1, 15, -1, 12, 5, -1, -1, -1, 11, -1, 13, -1, -1, -1, 14, -1, -1, -1, -1, -1}, - {1, 3, 4, 0, 7, -1, 12, 2, 11, 8, 6, 13, -1, -1, -1, -1, -1, 5, -1, -1, 10, 15, 9, -1, -1, -1, 14, -1, -1, -1, -1, -1}, - {1, 3, 5, 2, 13, 0, 9, 4, 7, 6, 8, -1, -1, 15, -1, 11, -1, -1, 10, -1, 14, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 2, 1, 3, -1, -1, -1, 6, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 11, 4, 0, 3, -1, 13, 12, 2, 7, -1, -1, 15, 10, 5, 8, 14, -1, -1, -1, -1, -1, 9, -1, -1, -1, 6, -1, -1, -1, -1, -1}, - {0, 9, 2, 14, 15, 4, 1, 13, 3, 5, -1, -1, 10, -1, -1, -1, -1, 6, 12, -1, 7, -1, 8, -1, -1, -1, 11, -1, -1, -1, -1, -1}, - {-1, 2, 14, -1, 1, 5, 8, 7, 4, 12, -1, 6, 9, 11, 13, 3, 10, 15, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 3, 2, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 3, 1, 5, -1, -1, -1, 0, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 8, 4, 1, -1, 0, -1, 6, -1, -1, 5, -1, 7, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1}, - {12, 5, -1, -1, 1, -1, -1, 7, 0, 3, -1, 2, -1, 4, 6, -1, -1, -1, -1, 8, -1, -1, 15, -1, 13, 9, -1, -1, -1, -1, -1, 11}, - {1, 3, 2, 4, -1, -1, -1, 5, -1, 7, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1}, - {5, 3, 4, 12, 1, 6, -1, -1, -1, -1, 8, 2, -1, -1, -1, -1, 0, 9, -1, -1, 11, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {-1, -1, -1, -1, 0, -1, 1, 12, 3, -1, -1, -1, -1, 5, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, 6, -1, 10}, - {2, 3, 1, 4, -1, 0, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1}, - {5, 1, 3, 0, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 9, -1, -1, 6, -1, 7}, + 7, 4, 12, -1, 6, -1, 1, 0, 3, 5, -1, 9, -1, 8, 2, -1, 15, 14, -1, 10, 11, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1, + 1, -1, 6, -1, 1, -1, 0, 3, 2, 4, 15, 11, -1, 9, 5, 10, 13, -1, 12, 8, 7, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 9, 11, -1, 4, 2, -1, 0, 8, 1, 5, -1, 6, -1, 3, 7, 15, -1, 12, 10, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 14, 7, 5, -1, 1, 2, 8, 9, 0, 15, 6, 4, 11, -1, 12, 3, -1, 10, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, 4, 3, 1, 5, 0, -1, 6, 10, 9, 7, 12, 11, -1, -1, -1, -1, 13, -1, -1, 8, -1, 15, -1, -1, -1, 14, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, -1, -1, 5, 9, 10, 6, -1, -1, 8, 15, 11, -1, 14, -1, -1, 7, -1, 13, -1, -1, -1, 12, -1, -1, -1, -1, -1, + 2, 8, 7, 4, 3, -1, 9, -1, 6, 11, -1, 5, -1, -1, 0, -1, -1, 14, 1, 15, 10, 12, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1, + 0, 3, 1, 2, 6, -1, 9, 8, 4, 12, 13, 10, -1, 11, 7, -1, -1, 15, 14, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 6, 3, 4, 1, 2, -1, -1, 5, 10, 7, 9, 11, 12, -1, -1, 8, 14, -1, -1, 15, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 6, 2, 5, 9, -1, -1, -1, 10, 1, 8, -1, 12, 14, 4, -1, 15, 7, -1, 13, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 8, 10, 9, 15, 1, -1, 4, 0, 3, 2, -1, 6, -1, 12, 11, 13, 7, 14, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 3, 6, 0, 4, 2, -1, 7, 13, 8, 9, 11, -1, -1, 15, -1, -1, -1, -1, -1, 10, 5, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 0, 1, 4, -1, 2, 5, 6, 7, 8, -1, 14, -1, -1, 9, 15, -1, 12, -1, -1, -1, 10, 11, -1, -1, -1, 13, -1, -1, -1, -1, -1, + 0, 1, 3, 2, 15, -1, 12, -1, 7, 14, 4, -1, -1, 9, -1, 8, 5, 10, -1, -1, 6, -1, 13, -1, -1, -1, 11, -1, -1, -1, -1, -1, + 0, 3, 1, 2, -1, -1, 12, 6, 4, 9, 7, -1, -1, 14, 8, -1, -1, 15, 11, 13, 5, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 5, 7, 2, 10, 13, -1, 6, 8, 1, 3, -1, -1, 14, 15, 11, -1, -1, -1, 12, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 2, 6, 3, 7, 10, -1, 1, 9, 4, 8, -1, -1, 15, -1, 12, 5, -1, -1, -1, 11, -1, 13, -1, -1, -1, 14, -1, -1, -1, -1, -1, + 1, 3, 4, 0, 7, -1, 12, 2, 11, 8, 6, 13, -1, -1, -1, -1, -1, 5, -1, -1, 10, 15, 9, -1, -1, -1, 14, -1, -1, -1, -1, -1, + 1, 3, 5, 2, 13, 0, 9, 4, 7, 6, 8, -1, -1, 15, -1, 11, -1, -1, 10, -1, 14, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 2, 1, 3, -1, -1, -1, 6, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 11, 4, 0, 3, -1, 13, 12, 2, 7, -1, -1, 15, 10, 5, 8, 14, -1, -1, -1, -1, -1, 9, -1, -1, -1, 6, -1, -1, -1, -1, -1, + 0, 9, 2, 14, 15, 4, 1, 13, 3, 5, -1, -1, 10, -1, -1, -1, -1, 6, 12, -1, 7, -1, 8, -1, -1, -1, 11, -1, -1, -1, -1, -1, + -1, 2, 14, -1, 1, 5, 8, 7, 4, 12, -1, 6, 9, 11, 13, 3, 10, 15, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 3, 2, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 3, 1, 5, -1, -1, -1, 0, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, 8, 4, 1, -1, 0, -1, 6, -1, -1, 5, -1, 7, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1, + 12, 5, -1, -1, 1, -1, -1, 7, 0, 3, -1, 2, -1, 4, 6, -1, -1, -1, -1, 8, -1, -1, 15, -1, 13, 9, -1, -1, -1, -1, -1, 11, + 1, 3, 2, 4, -1, -1, -1, 5, -1, 7, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, + 5, 3, 4, 12, 1, 6, -1, -1, -1, -1, 8, 2, -1, -1, -1, -1, 0, 9, -1, -1, 11, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 0, -1, 1, 12, 3, -1, -1, -1, -1, 5, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, 6, -1, 10, + 2, 3, 1, 4, -1, 0, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, + 5, 1, 3, 0, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 9, -1, -1, 6, -1, 7, }, successors_reversed = { - {'s', 't', 'c', 'l', 'm', 'a', 'd', 'r', 'v', 'T', 'A', 'L', 'e', 'M', 'Y', '-'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'-', 't', 'a', 'b', 's', 'h', 'c', 'r', 'n', 'w', 'p', 'm', 'l', 'd', 'i', 'f'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'u', 'e', 'i', 'a', 'o', 'r', 'y', 'l', 'I', 'E', 'R', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'e', 'a', 'o', 'i', 'u', 'A', 'y', 'E', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'t', 'n', 'f', 's', '\'', 'm', 'I', 'N', 'A', 'E', 'L', 'Z', 'r', 'V', 'R', 'C'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'o', 'a', 'y', 'i', 'u', 'e', 'I', 'L', 'D', '\'', 'E', 'Y', '\x00', '\x00', '\x00', '\x00'}, - {'r', 'i', 'y', 'a', 'e', 'o', 'u', 'Y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'h', 'o', 'e', 'E', 'i', 'u', 'r', 'w', 'a', 'H', 'y', 'R', 'Z', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'h', 'i', 'e', 'a', 'o', 'r', 'I', 'y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'n', 't', 's', 'r', 'l', 'd', 'i', 'y', 'v', 'm', 'b', 'c', 'g', 'p', 'k', 'u'}, - {'e', 'l', 'o', 'u', 'y', 'a', 'r', 'i', 's', 'j', 't', 'b', 'v', 'h', 'm', 'd'}, - {'o', 'e', 'h', 'a', 't', 'k', 'i', 'r', 'l', 'u', 'y', 'c', 'q', 's', '-', 'd'}, - {'e', 'i', 'o', 'a', 's', 'y', 'r', 'u', 'd', 'l', '-', 'g', 'n', 'v', 'm', 'f'}, - {'r', 'n', 'd', 's', 'a', 'l', 't', 'e', 'm', 'c', 'v', 'y', 'i', 'x', 'f', 'p'}, - {'o', 'e', 'r', 'a', 'i', 'f', 'u', 't', 'l', '-', 'y', 's', 'n', 'c', '\'', 'k'}, - {'h', 'e', 'o', 'a', 'r', 'i', 'l', 's', 'u', 'n', 'g', 'b', '-', 't', 'y', 'm'}, - {'e', 'a', 'i', 'o', 't', 'r', 'u', 'y', 'm', 's', 'l', 'b', '\'', '-', 'f', 'd'}, - {'n', 's', 't', 'm', 'o', 'l', 'c', 'd', 'r', 'e', 'g', 'a', 'f', 'v', 'z', 'b'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'e', 'n', 'i', 's', 'h', 'l', 'f', 'y', '-', 'a', 'w', '\'', 'g', 'r', 'o', 't'}, - {'e', 'l', 'i', 'y', 'd', 'o', 'a', 'f', 'u', 't', 's', 'k', 'w', 'v', 'm', 'p'}, - {'e', 'a', 'o', 'i', 'u', 'p', 'y', 's', 'b', 'm', 'f', '\'', 'n', '-', 'l', 't'}, - {'d', 'g', 'e', 't', 'o', 'c', 's', 'i', 'a', 'n', 'y', 'l', 'k', '\'', 'f', 'v'}, - {'u', 'n', 'r', 'f', 'm', 't', 'w', 'o', 's', 'l', 'v', 'd', 'p', 'k', 'i', 'c'}, - {'e', 'r', 'a', 'o', 'l', 'p', 'i', 't', 'u', 's', 'h', 'y', 'b', '-', '\'', 'm'}, - {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'e', 'i', 'o', 'a', 's', 'y', 't', 'd', 'r', 'n', 'c', 'm', 'l', 'u', 'g', 'f'}, - {'e', 't', 'h', 'i', 'o', 's', 'a', 'u', 'p', 'c', 'l', 'w', 'm', 'k', 'f', 'y'}, - {'h', 'o', 'e', 'i', 'a', 't', 'r', 'u', 'y', 'l', 's', 'w', 'c', 'f', '\'', '-'}, - {'r', 't', 'l', 's', 'n', 'g', 'c', 'p', 'e', 'i', 'a', 'd', 'm', 'b', 'f', 'o'}, - {'e', 'i', 'a', 'o', 'y', 'u', 'r', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}, - {'a', 'i', 'h', 'e', 'o', 'n', 'r', 's', 'l', 'd', 'k', '-', 'f', '\'', 'c', 'b'}, - {'p', 't', 'c', 'a', 'i', 'e', 'h', 'q', 'u', 'f', '-', 'y', 'o', '\x00', '\x00', '\x00'}, - {'o', 'e', 's', 't', 'i', 'd', '\'', 'l', 'b', '-', 'm', 'a', 'r', 'n', 'p', 'w'}, + 's', 't', 'c', 'l', 'm', 'a', 'd', 'r', 'v', 'T', 'A', 'L', 'e', 'M', 'Y', '-', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '-', 't', 'a', 'b', 's', 'h', 'c', 'r', 'n', 'w', 'p', 'm', 'l', 'd', 'i', 'f', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'u', 'e', 'i', 'a', 'o', 'r', 'y', 'l', 'I', 'E', 'R', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'e', 'a', 'o', 'i', 'u', 'A', 'y', 'E', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 't', 'n', 'f', 's', '\'', 'm', 'I', 'N', 'A', 'E', 'L', 'Z', 'r', 'V', 'R', 'C', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'o', 'a', 'y', 'i', 'u', 'e', 'I', 'L', 'D', '\'', 'E', 'Y', '\x00', '\x00', '\x00', '\x00', + 'r', 'i', 'y', 'a', 'e', 'o', 'u', 'Y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'h', 'o', 'e', 'E', 'i', 'u', 'r', 'w', 'a', 'H', 'y', 'R', 'Z', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'h', 'i', 'e', 'a', 'o', 'r', 'I', 'y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'n', 't', 's', 'r', 'l', 'd', 'i', 'y', 'v', 'm', 'b', 'c', 'g', 'p', 'k', 'u', + 'e', 'l', 'o', 'u', 'y', 'a', 'r', 'i', 's', 'j', 't', 'b', 'v', 'h', 'm', 'd', + 'o', 'e', 'h', 'a', 't', 'k', 'i', 'r', 'l', 'u', 'y', 'c', 'q', 's', '-', 'd', + 'e', 'i', 'o', 'a', 's', 'y', 'r', 'u', 'd', 'l', '-', 'g', 'n', 'v', 'm', 'f', + 'r', 'n', 'd', 's', 'a', 'l', 't', 'e', 'm', 'c', 'v', 'y', 'i', 'x', 'f', 'p', + 'o', 'e', 'r', 'a', 'i', 'f', 'u', 't', 'l', '-', 'y', 's', 'n', 'c', '\'', 'k', + 'h', 'e', 'o', 'a', 'r', 'i', 'l', 's', 'u', 'n', 'g', 'b', '-', 't', 'y', 'm', + 'e', 'a', 'i', 'o', 't', 'r', 'u', 'y', 'm', 's', 'l', 'b', '\'', '-', 'f', 'd', + 'n', 's', 't', 'm', 'o', 'l', 'c', 'd', 'r', 'e', 'g', 'a', 'f', 'v', 'z', 'b', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'e', 'n', 'i', 's', 'h', 'l', 'f', 'y', '-', 'a', 'w', '\'', 'g', 'r', 'o', 't', + 'e', 'l', 'i', 'y', 'd', 'o', 'a', 'f', 'u', 't', 's', 'k', 'w', 'v', 'm', 'p', + 'e', 'a', 'o', 'i', 'u', 'p', 'y', 's', 'b', 'm', 'f', '\'', 'n', '-', 'l', 't', + 'd', 'g', 'e', 't', 'o', 'c', 's', 'i', 'a', 'n', 'y', 'l', 'k', '\'', 'f', 'v', + 'u', 'n', 'r', 'f', 'm', 't', 'w', 'o', 's', 'l', 'v', 'd', 'p', 'k', 'i', 'c', + 'e', 'r', 'a', 'o', 'l', 'p', 'i', 't', 'u', 's', 'h', 'y', 'b', '-', '\'', 'm', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'e', 'i', 'o', 'a', 's', 'y', 't', 'd', 'r', 'n', 'c', 'm', 'l', 'u', 'g', 'f', + 'e', 't', 'h', 'i', 'o', 's', 'a', 'u', 'p', 'c', 'l', 'w', 'm', 'k', 'f', 'y', + 'h', 'o', 'e', 'i', 'a', 't', 'r', 'u', 'y', 'l', 's', 'w', 'c', 'f', '\'', '-', + 'r', 't', 'l', 's', 'n', 'g', 'c', 'p', 'e', 'i', 'a', 'd', 'm', 'b', 'f', 'o', + 'e', 'i', 'a', 'o', 'y', 'u', 'r', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + 'a', 'i', 'h', 'e', 'o', 'n', 'r', 's', 'l', 'd', 'k', '-', 'f', '\'', 'c', 'b', + 'p', 't', 'c', 'a', 'i', 'e', 'h', 'q', 'u', 'f', '-', 'y', 'o', '\x00', '\x00', '\x00', + 'o', 'e', 's', 't', 'i', 'd', '\'', 'l', 'b', '-', 'm', 'a', 'r', 'n', 'p', 'w', }, character_count = 32, diff --git a/core/compress/shoco/shoco.odin b/core/compress/shoco/shoco.odin index 9c5008f5d..3f5b696ea 100644 --- a/core/compress/shoco/shoco.odin +++ b/core/compress/shoco/shoco.odin @@ -14,6 +14,8 @@ package shoco import "core:intrinsics" import "core:compress" +import "core:fmt" + Shoco_Pack :: struct { word: u32, bytes_packed: i8, @@ -29,8 +31,8 @@ Shoco_Model :: struct { max_char: u8, characters_by_id: []u8, ids_by_character: [256]i16, - successors_by_bigram: [][]i8, - successors_reversed: [][]u8, + successors_by_bigram: []i8, + successors_reversed: []u8, character_count: u8, successor_count: u8, @@ -74,19 +76,15 @@ find_best_encoding :: proc(indices: []i16, n_consecutive: i8, model := DEFAULT_M } validate_model :: proc(model: Shoco_Model) -> (int, compress.Error) { - if len(model.successors_reversed) != int(model.max_char - model.min_char) { - return 0, .Unknown_Compression_Method - } - if len(model.characters_by_id) != int(model.character_count) { return 0, .Unknown_Compression_Method } - if len(model.successors_by_bigram) != int(model.character_count) || len(model.successors_by_bigram[0]) != int(model.character_count) { + if len(model.successors_by_bigram) != int(model.character_count) * int(model.character_count) { return 0, .Unknown_Compression_Method } - if len(model.successors_reversed[0]) != int(model.successor_count) { + if len(model.successors_reversed) != int(model.successor_count) * int(model.max_char - model.min_char) { return 0, .Unknown_Compression_Method } @@ -155,7 +153,11 @@ decompress_slice_to_output_buffer :: proc(input: []u8, output: []u8, model := DE offset = pack.offsets[i] mask = pack.masks[i] - last_chr = model.successors_reversed[last_chr - model.min_char][(code >> offset) & u32(mask)] + index_major := u32(last_chr - model.min_char) * u32(model.successor_count) + index_minor := (code >> offset) & u32(mask) + + last_chr = model.successors_reversed[index_major + index_minor] + output[out + i] = last_chr } @@ -242,7 +244,7 @@ compress_string_to_buffer :: proc(input: string, output: []u8, model := DEFAULT_ break } - successor_index := model.successors_by_bigram[last_chr_index][current_index] + successor_index := model.successors_by_bigram[last_chr_index * i16(model.character_count) + current_index] if successor_index < 0 { break } From b022167df12b3d62ddacd51e64f7ab3b4e170852 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 22 Apr 2022 17:56:34 +0200 Subject: [PATCH 0570/1052] Remove unused fmt. --- core/compress/shoco/shoco.odin | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/compress/shoco/shoco.odin b/core/compress/shoco/shoco.odin index 3f5b696ea..f94ce70b7 100644 --- a/core/compress/shoco/shoco.odin +++ b/core/compress/shoco/shoco.odin @@ -14,8 +14,6 @@ package shoco import "core:intrinsics" import "core:compress" -import "core:fmt" - Shoco_Pack :: struct { word: u32, bytes_packed: i8, From b44b6e7e5099cab83f4a6d0feb5af9f245dea738 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Sat, 23 Apr 2022 03:33:35 +0000 Subject: [PATCH 0571/1052] [path/filepath] Add file stem and long-extension procedures Adds stem(), short_stem(), and long_ext(); also adds doc-comments to base() and ext(). The 'stem' is usually 'the name' of the file; the basename without the file extension. To this end, this adds stem(), which is such that: stem(path) + ext(path) = base(path) However, 'file extension' has two different meanings to what constitutes it! > What is the extension of: 'name.tar.gz' ? Colloquially, you would likely think of it as 'a tarball' - which you might think is '.tar.gz'. But, if you're writing code to process a file of this type, you would first treat it as a Gzip file, and then treat the result as a TAR file - i.e: '.gz' ... _followed by_ '.tar'. ext() returns '.gz' here, since that is the most-immediate format that you would need to use to decode it; it would be a Gzip stream. Sometimes though, you do actually want to consider these longer file extensions. Perhaps you're extracting a tarball, and what to know what to call the intermediate tar file; perhaps you want to check to see if this file is a tarball, or just a Gzip file; or maybe you just want 'the name' of the file, and not this "strange 'name-and-part-of-the-extension' thing". So, this also adds short_stem() and long_ext(), such that: short_stem(path) + long_ext(path) = base(path) Thus, we can use either, but the most immediately-useful one is the easiest to reach for: stem('name.tar.gz') -> 'name.tar' ext('name.tar.gz') -> '.gz' short_stem('name.tar.gz') -> 'name' long_ext('name.tar.gz') -> '.tar.gz' These procedures are identical to their counterparts when the path only has a simple extension: stem('name.txt') -> 'name' ext('name.txt') -> '.txt' short_stem('name.txt') -> 'name' long_ext('name.txt') -> '.txt' --- core/path/filepath/path.odin | 133 ++++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 9 deletions(-) diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin index 42714d736..32e4a8a37 100644 --- a/core/path/filepath/path.odin +++ b/core/path/filepath/path.odin @@ -4,6 +4,8 @@ package filepath import "core:strings" +SEPARATOR_CHARS :: `/\` + // is_separator checks whether the byte is a valid separator character is_separator :: proc(c: byte) -> bool { switch c { @@ -69,6 +71,16 @@ volume_name_len :: proc(path: string) -> int { return 0 } +/* + Gets the file name and extension from a path. + + i.e: + 'path/to/name.tar.gz' -> 'name.tar.gz' + 'path/to/name.txt' -> 'name.txt' + 'path/to/name' -> 'name' + + Returns "." if the path is an empty string. +*/ base :: proc(path: string) -> string { if path == "" { return "." @@ -94,6 +106,118 @@ base :: proc(path: string) -> string { return path } +/* + Gets the name of a file from a path. + + The stem of a file is such that stem(path) + ext(path) = base(path). + + Only the last dot is considered when splitting the file extension. + See `short_stem`. + + i.e: + 'name.tar.gz' -> 'name.tar' + 'name.txt' -> 'name' + + Returns an empty string if there is no stem. e.g: '.gitignore'. + Returns an empty string if there's a trailing path separator. +*/ +stem :: proc(path: string) -> string { + if len(path) > 0 && is_separator(path[len(path) - 1]) { + // NOTE(tetra): Trailing separator + return "" + } + + // NOTE(tetra): Get the basename + path := path + if i := strings.last_index_any(path, SEPARATOR_CHARS); i != -1 { + path = path[i+1:] + } + + if i := strings.last_index_byte(path, '.'); i != -1 { + return path[:i] + } + + return path +} + +/* + Gets the name of a file from a path. + + The short stem is such that short_stem(path) + long_ext(path) = base(path). + + The first dot is used to split off the file extension, unlike `stem` which uses the last dot. + + i.e: + 'name.tar.gz' -> 'name' + 'name.txt' -> 'name' + + Returns an empty string if there is no stem. e.g: '.gitignore'. + Returns an empty string if there's a trailing path separator. +*/ +short_stem :: proc(path: string) -> string { + s := stem(path) + if i := strings.index_byte(s, '.'); i != -1 { + return s[:i] + } + return s +} + +/* + Gets the file extension from a path, including the dot. + + The file extension is such that stem(path) + ext(path) = base(path). + + Only the last dot is considered when splitting the file extension. + See `long_ext`. + + i.e: + 'name.tar.gz' -> '.gz' + 'name.txt' -> '.txt' + + Returns an empty string if there is no dot. + Returns an empty string if there is a trailing path separator. +*/ +ext :: proc(path: string) -> string { + for i := len(path)-1; i >= 0 && !is_separator(path[i]); i -= 1 { + if path[i] == '.' { + return path[i:] + } + } + return "" +} + +/* + Gets the file extension from a path, including the dot. + + The long file extension is such that short_stem(path) + long_ext(path) = base(path). + + The first dot is used to split off the file extension, unlike `ext` which uses the last dot. + + i.e: + 'name.tar.gz' -> '.tar.gz' + 'name.txt' -> '.txt' + + Returns an empty string if there is no dot. + Returns an empty string if there is a trailing path separator. +*/ +long_ext :: proc(path: string) -> string { + if len(path) > 0 && is_separator(path[len(path) - 1]) { + // NOTE(tetra): Trailing separator + return "" + } + + // NOTE(tetra): Get the basename + path := path + if i := strings.last_index_any(path, SEPARATOR_CHARS); i != -1 { + path = path[i+1:] + } + + if i := strings.index_byte(path, '.'); i != -1 { + return path[i:] + } + + return "" +} clean :: proc(path: string, allocator := context.allocator) -> string { context.allocator = allocator @@ -189,15 +313,6 @@ to_slash :: proc(path: string, allocator := context.allocator) -> (new_path: str return strings.replace_all(path, SEPARATOR_STRING, "/", allocator) } -ext :: proc(path: string) -> string { - for i := len(path)-1; i >= 0 && !is_separator(path[i]); i -= 1 { - if path[i] == '.' { - return path[i:] - } - } - return "" -} - Relative_Error :: enum { None, From 3cab2592c3e5a06882ffd711871a08c893b043f1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 6 Apr 2022 18:26:23 +0200 Subject: [PATCH 0572/1052] Compiler: Add early error for output path being a directory. - Introduce new `Path` type and an array of build paths on the build context. - Resolve input and output paths/files early (before parsing). - Error early if inputs are missing or outputs are directories. - Plumb new file path generation into linker stage instead of its adhoc method. TODO: - Remove more adhoc file path generation in parser and linker stage. - Make intermediate object file generation use new path system. - Round out and robustify Path helper functions. --- .gitignore | 1 + Makefile | 4 +- build_odin.sh | 4 +- src/build_settings.cpp | 220 +++++++++++++++++++--- src/common.cpp | 257 +------------------------- src/gb/gb.h | 50 +++-- src/llvm_backend.cpp | 14 +- src/llvm_backend_general.cpp | 1 - src/main.cpp | 152 ++++++++-------- src/parser.cpp | 2 +- src/path.cpp | 333 ++++++++++++++++++++++++++++++++++ src/string.cpp | 10 +- tests/core/build.bat | 28 +-- tests/core/math/big/build.bat | 2 +- tests/issues/run.sh | 4 +- 15 files changed, 676 insertions(+), 406 deletions(-) create mode 100644 src/path.cpp diff --git a/.gitignore b/.gitignore index e8b3d3050..d03a86fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -269,6 +269,7 @@ bin/ # - Linux/MacOS odin odin.dSYM +*.bin # shared collection shared/ diff --git a/Makefile b/Makefile index 82150c6a2..1a1c93180 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -all: debug demo +all: debug demo: - ./odin run examples/demo/demo.odin + ./odin run examples/demo report: ./odin report diff --git a/build_odin.sh b/build_odin.sh index aef3f2836..4810cafd2 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -102,7 +102,7 @@ build_odin() { } run_demo() { - ./odin run examples/demo/demo.odin -file + ./odin run examples/demo } case $OS in @@ -147,4 +147,4 @@ if [[ $# -eq 1 ]]; then exit 0 else panic "Too many arguments!" -fi +fi \ No newline at end of file diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 2f3eb03a5..0b582eac8 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -3,7 +3,6 @@ #include #endif - // #if defined(GB_SYSTEM_WINDOWS) // #define DEFAULT_TO_THREADED_CHECKER // #endif @@ -198,6 +197,22 @@ enum RelocMode : u8 { RelocMode_DynamicNoPIC, }; +enum BuildPath : u8 { + BuildPath_Main_Package, // Input Path to the package directory (or file) we're building. + BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`. + BuildPath_RES, // Output Path for .res file, generated from previous. + BuildPath_Win_SDK_Root, // windows_sdk_root + BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path + BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path + BuildPath_VS_EXE, // vs_exe_path + BuildPath_VS_LIB, // vs_library_path + + BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`. + BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`. + + BuildPathCOUNT, +}; + // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -226,9 +241,13 @@ struct BuildContext { bool show_help; + Array build_paths; // Contains `Path` objects to output filename, pdb, resource and intermediate files. + // BuildPath enum contains the indices of paths we know *before* the work starts. + String out_filepath; String resource_filepath; String pdb_filepath; + bool has_resource; String link_flags; String extra_linker_flags; @@ -300,8 +319,6 @@ struct BuildContext { }; - - gb_global BuildContext build_context = {0}; bool global_warnings_as_errors(void) { @@ -605,28 +622,6 @@ bool allow_check_foreign_filepath(void) { // is_abs_path // has_subdir -enum TargetFileValidity : u8 { - TargetFileValidity_Invalid, - - TargetFileValidity_Writable_File, - TargetFileValidity_No_Write_Permission, - TargetFileValidity_Directory, - - TargetTargetFileValidity_COUNT, -}; - -TargetFileValidity set_output_filename(void) { - // Assembles the output filename from build_context information. - // Returns `true` if it doesn't exist or is a file. - // Returns `false` if a directory or write-protected file. - - - - - return TargetFileValidity_Writable_File; -} - - String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; @@ -973,7 +968,6 @@ char *token_pos_to_string(TokenPos const &pos) { return s; } - void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; @@ -1152,8 +1146,178 @@ void init_build_context(TargetMetrics *cross_target) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); - - #undef LINK_FLAG_X64 #undef LINK_FLAG_386 } + +#if defined(GB_SYSTEM_WINDOWS) +// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. +// NOTE(Jeroen): No longer needed in `main.cpp -> linker_stage`. We now resolve those paths in `init_build_paths`. +#include "microsoft_craziness.h" +#endif + +// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. +// We've previously called `parse_build_flags`, so `out_filepath` should be set. +bool init_build_paths(String init_filename) { + gbAllocator ha = heap_allocator(); + BuildContext *bc = &build_context; + + // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index. + array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT); + + // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path. + bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename); + + bool produces_output_file = false; + if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { + produces_output_file = true; + } else if (bc->command_kind & Command__does_build) { + produces_output_file = true; + } + + if (!produces_output_file) { + // Command doesn't produce output files. We're done. + return true; + } + + #if defined(GB_SYSTEM_WINDOWS) + if (bc->resource_filepath.len > 0) { + bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); + bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); + bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc")); + bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res")); + } + + if (bc->pdb_filepath.len > 0) { + bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath); + } + + if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + return false; + } + + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + + if (find_result.windows_sdk_root.len > 0) { + bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); + } + + if (find_result.windows_sdk_um_library_path.len > 0) { + bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path); + } + + if (find_result.windows_sdk_ucrt_library_path.len > 0) { + bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path); + } + + if (find_result.vs_exe_path.len > 0) { + bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path); + } + + if (find_result.vs_library_path.len > 0) { + bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path); + } + + gb_free(ha, find_result.windows_sdk_root.text); + gb_free(ha, find_result.windows_sdk_um_library_path.text); + gb_free(ha, find_result.windows_sdk_ucrt_library_path.text); + gb_free(ha, find_result.vs_exe_path.text); + gb_free(ha, find_result.vs_library_path.text); + + } + #endif + + // All the build targets and OSes. + String output_extension; + + if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { + output_extension = STR_LIT("odin-doc"); + } else if (is_arch_wasm()) { + output_extension = STR_LIT("wasm"); + } else if (build_context.build_mode == BuildMode_Executable) { + // By default use a .bin executable extension. + output_extension = STR_LIT("bin"); + + if (build_context.metrics.os == TargetOs_windows) { + output_extension = STR_LIT("exe"); + } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { + output_extension = make_string(nullptr, 0); + } + } else if (build_context.build_mode == BuildMode_DynamicLibrary) { + // By default use a .so shared library extension. + output_extension = STR_LIT("so"); + + if (build_context.metrics.os == TargetOs_windows) { + output_extension = STR_LIT("dll"); + } else if (build_context.metrics.os == TargetOs_darwin) { + output_extension = STR_LIT("dylib"); + } + } else if (build_context.build_mode == BuildMode_Object) { + // By default use a .o object extension. + output_extension = STR_LIT("o"); + + if (build_context.metrics.os == TargetOs_windows) { + output_extension = STR_LIT("obj"); + } + } else if (build_context.build_mode == BuildMode_Assembly) { + // By default use a .S asm extension. + output_extension = STR_LIT("S"); + } else if (build_context.build_mode == BuildMode_LLVM_IR) { + output_extension = STR_LIT("ll"); + } else { + GB_PANIC("Unhandled build mode/target combination.\n"); + } + + if (bc->out_filepath.len > 0) { + bc->build_paths[BuildPath_Output] = path_from_string(ha, bc->out_filepath); + } else { + String output_name = remove_directory_from_path(init_filename); + output_name = remove_extension_from_path(output_name); + output_name = copy_string(ha, string_trim_whitespace(output_name)); + + /* + NOTE(Jeroen): This fallback substitution can't be made at this stage. + if (gen->output_name.len == 0) { + gen->output_name = c->info.init_scope->pkg->name; + } + */ + Path output_path = path_from_string(ha, output_name); + + #ifndef GB_SYSTEM_WINDOWS + char cwd[4096]; + getcwd(&cwd[0], 4096); + + const u8 * cwd_str = (const u8 *)&cwd[0]; + output_path.basename = copy_string(ha, make_string(cwd_str, strlen(cwd))); + #endif + + // Replace extension. + if (output_path.ext.len > 0) { + gb_free(ha, output_path.ext.text); + } + output_path.ext = copy_string(ha, output_extension); + + bc->build_paths[BuildPath_Output] = output_path; + } + + // Do we have an extension? We might not if the output filename was supplied. + if (bc->build_paths[BuildPath_Output].ext.len == 0) { + bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension); + } + + // Check if output path is a directory. + if (path_is_directory(bc->build_paths[BuildPath_Output])) { + String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); + defer (gb_free(ha, output_file.text)); + gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file)); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/common.cpp b/src/common.cpp index aaacda04b..94248fb62 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -675,262 +675,7 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) { #endif - -#if defined(GB_SYSTEM_WINDOWS) - bool path_is_directory(String path) { - gbAllocator a = heap_allocator(); - String16 wstr = string_to_string16(a, path); - defer (gb_free(a, wstr.text)); - - i32 attribs = GetFileAttributesW(wstr.text); - if (attribs < 0) return false; - - return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; - } - -#else - bool path_is_directory(String path) { - gbAllocator a = heap_allocator(); - char *copy = cast(char *)copy_string(a, path).text; - defer (gb_free(a, copy)); - - struct stat s; - if (stat(copy, &s) == 0) { - return (s.st_mode & S_IFDIR) != 0; - } - return false; - } -#endif - - -String path_to_full_path(gbAllocator a, String path) { - gbAllocator ha = heap_allocator(); - char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); - defer (gb_free(ha, path_c)); - - char *fullpath = gb_path_get_full_name(a, path_c); - String res = string_trim_whitespace(make_string_c(fullpath)); -#if defined(GB_SYSTEM_WINDOWS) - for (isize i = 0; i < res.len; i++) { - if (res.text[i] == '\\') { - res.text[i] = '/'; - } - } -#endif - return res; -} - - - -struct FileInfo { - String name; - String fullpath; - i64 size; - bool is_dir; -}; - -enum ReadDirectoryError { - ReadDirectory_None, - - ReadDirectory_InvalidPath, - ReadDirectory_NotExists, - ReadDirectory_Permission, - ReadDirectory_NotDir, - ReadDirectory_Empty, - ReadDirectory_Unknown, - - ReadDirectory_COUNT, -}; - -i64 get_file_size(String path) { - char *c_str = alloc_cstring(heap_allocator(), path); - defer (gb_free(heap_allocator(), c_str)); - - gbFile f = {}; - gbFileError err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - if (err != gbFileError_None) { - return -1; - } - return gb_file_size(&f); -} - - -#if defined(GB_SYSTEM_WINDOWS) -ReadDirectoryError read_directory(String path, Array *fi) { - GB_ASSERT(fi != nullptr); - - gbAllocator a = heap_allocator(); - - while (path.len > 0) { - Rune end = path[path.len-1]; - if (end == '/') { - path.len -= 1; - } else if (end == '\\') { - path.len -= 1; - } else { - break; - } - } - - if (path.len == 0) { - return ReadDirectory_InvalidPath; - } - { - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - case gbFileError_Invalid: return ReadDirectory_InvalidPath; - case gbFileError_NotExists: return ReadDirectory_NotExists; - // case gbFileError_Permission: return ReadDirectory_Permission; - } - } - - if (!path_is_directory(path)) { - return ReadDirectory_NotDir; - } - - - char *new_path = gb_alloc_array(a, char, path.len+3); - defer (gb_free(a, new_path)); - - gb_memmove(new_path, path.text, path.len); - gb_memmove(new_path+path.len, "/*", 2); - new_path[path.len+2] = 0; - - String np = make_string(cast(u8 *)new_path, path.len+2); - String16 wstr = string_to_string16(a, np); - defer (gb_free(a, wstr.text)); - - WIN32_FIND_DATAW file_data = {}; - HANDLE find_file = FindFirstFileW(wstr.text, &file_data); - if (find_file == INVALID_HANDLE_VALUE) { - return ReadDirectory_Unknown; - } - defer (FindClose(find_file)); - - array_init(fi, a, 0, 100); - - do { - wchar_t *filename_w = file_data.cFileName; - i64 size = cast(i64)file_data.nFileSizeLow; - size |= (cast(i64)file_data.nFileSizeHigh) << 32; - String name = string16_to_string(a, make_string16_c(filename_w)); - if (name == "." || name == "..") { - gb_free(a, name.text); - continue; - } - - String filepath = {}; - filepath.len = path.len+1+name.len; - filepath.text = gb_alloc_array(a, u8, filepath.len+1); - defer (gb_free(a, filepath.text)); - gb_memmove(filepath.text, path.text, path.len); - gb_memmove(filepath.text+path.len, "/", 1); - gb_memmove(filepath.text+path.len+1, name.text, name.len); - - FileInfo info = {}; - info.name = name; - info.fullpath = path_to_full_path(a, filepath); - info.size = size; - info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - array_add(fi, info); - } while (FindNextFileW(find_file, &file_data)); - - if (fi->count == 0) { - return ReadDirectory_Empty; - } - - return ReadDirectory_None; -} -#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) - -#include - -ReadDirectoryError read_directory(String path, Array *fi) { - GB_ASSERT(fi != nullptr); - - gbAllocator a = heap_allocator(); - - char *c_path = alloc_cstring(a, path); - defer (gb_free(a, c_path)); - - DIR *dir = opendir(c_path); - if (!dir) { - switch (errno) { - case ENOENT: - return ReadDirectory_NotExists; - case EACCES: - return ReadDirectory_Permission; - case ENOTDIR: - return ReadDirectory_NotDir; - default: - // ENOMEM: out of memory - // EMFILE: per-process limit on open fds reached - // ENFILE: system-wide limit on total open files reached - return ReadDirectory_Unknown; - } - GB_PANIC("unreachable"); - } - - array_init(fi, a, 0, 100); - - for (;;) { - struct dirent *entry = readdir(dir); - if (entry == nullptr) { - break; - } - - String name = make_string_c(entry->d_name); - if (name == "." || name == "..") { - continue; - } - - String filepath = {}; - filepath.len = path.len+1+name.len; - filepath.text = gb_alloc_array(a, u8, filepath.len+1); - defer (gb_free(a, filepath.text)); - gb_memmove(filepath.text, path.text, path.len); - gb_memmove(filepath.text+path.len, "/", 1); - gb_memmove(filepath.text+path.len+1, name.text, name.len); - filepath.text[filepath.len] = 0; - - - struct stat dir_stat = {}; - - if (stat((char *)filepath.text, &dir_stat)) { - continue; - } - - if (S_ISDIR(dir_stat.st_mode)) { - continue; - } - - i64 size = dir_stat.st_size; - - FileInfo info = {}; - info.name = name; - info.fullpath = path_to_full_path(a, filepath); - info.size = size; - array_add(fi, info); - } - - if (fi->count == 0) { - return ReadDirectory_Empty; - } - - return ReadDirectory_None; -} -#else -#error Implement read_directory -#endif - - +#include "path.cpp" struct LoadedFile { void *handle; diff --git a/src/gb/gb.h b/src/gb/gb.h index b72a893f7..3b2d6434c 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -6273,20 +6273,44 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) { #else char *p, *result, *fullpath = NULL; isize len; - p = realpath(path, NULL); - fullpath = p; - if (p == NULL) { - // NOTE(bill): File does not exist - fullpath = cast(char *)path; + fullpath = realpath(path, NULL); + + if (fullpath == NULL) { + // NOTE(Jeroen): Path doesn't exist. + if (gb_strlen(path) > 0 && path[0] == '/') { + // But it is an absolute path, so return as-is. + + fullpath = (char *)path; + len = gb_strlen(fullpath) + 1; + result = gb_alloc_array(a, char, len + 1); + + gb_memmove(result, fullpath, len); + result[len] = 0; + + } else { + // Appears to be a relative path, so construct an absolute one relative to . + char cwd[4096]; + getcwd(&cwd[0], 4096); + + isize path_len = gb_strlen(path); + isize cwd_len = gb_strlen(cwd); + len = cwd_len + 1 + path_len + 1; + result = gb_alloc_array(a, char, len); + + gb_memmove(result, (void *)cwd, cwd_len); + result[cwd_len] = '/'; + + gb_memmove(result + cwd_len + 1, (void *)path, gb_strlen(path)); + result[len] = 0; + + } + } else { + len = gb_strlen(fullpath) + 1; + result = gb_alloc_array(a, char, len + 1); + gb_memmove(result, fullpath, len); + result[len] = 0; + free(fullpath); } - - len = gb_strlen(fullpath); - - result = gb_alloc_array(a, char, len + 1); - gb_memmove(result, fullpath, len); - result[len] = 0; - free(p); - return result; #endif } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index f5cb84785..7781997f7 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -967,7 +967,12 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) } String lb_filepath_ll_for_module(lbModule *m) { - String path = m->gen->output_base; + String path = concatenate3_strings(permanent_allocator(), + build_context.build_paths[BuildPath_Output].basename, + STR_LIT("/"), + build_context.build_paths[BuildPath_Output].name + ); + if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } else if (USE_SEPARATE_MODULES) { @@ -978,7 +983,12 @@ String lb_filepath_ll_for_module(lbModule *m) { return path; } String lb_filepath_obj_for_module(lbModule *m) { - String path = m->gen->output_base; + String path = concatenate3_strings(permanent_allocator(), + build_context.build_paths[BuildPath_Output].basename, + STR_LIT("/"), + build_context.build_paths[BuildPath_Output].name + ); + if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 330059622..1a431a4ac 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -87,7 +87,6 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { return false; } - String init_fullpath = c->parser->init_fullpath; if (build_context.out_filepath.len == 0) { diff --git a/src/main.cpp b/src/main.cpp index fc8792ceb..7b0364149 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,7 +46,6 @@ gb_global Timings global_timings = {0}; #include "checker.cpp" #include "docs.cpp" - #include "llvm_backend.cpp" #if defined(GB_SYSTEM_OSX) @@ -57,16 +56,8 @@ gb_global Timings global_timings = {0}; #endif #include "query_data.cpp" - - -#if defined(GB_SYSTEM_WINDOWS) -// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. -#include "microsoft_craziness.h" -#endif - #include "bug_report.cpp" - // NOTE(bill): 'name' is used in debugging and profiling modes i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { isize const cmd_cap = 64<<20; // 64 MiB should be more than enough @@ -130,34 +121,35 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { } - - i32 linker_stage(lbGenerator *gen) { i32 result = 0; Timings *timings = &global_timings; - String output_base = gen->output_base; + String output_filename = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); + debugf("Linking %.*s\n", LIT(output_filename)); + + // TOOD(Jeroen): Make a `build_paths[BuildPath_Object] to avoid `%.*s.o`. if (is_arch_wasm()) { timings_start_section(timings, str_lit("wasm-ld")); #if defined(GB_SYSTEM_WINDOWS) result = system_exec_command_line_app("wasm-ld", - "\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", + "\"%.*s\\bin\\wasm-ld\" \"%.*s.o\" -o \"%.*s\" %.*s %.*s", LIT(build_context.ODIN_ROOT), - LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else result = system_exec_command_line_app("wasm-ld", - "wasm-ld \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", - LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + "wasm-ld \"%.*s.o\" -o \"%.*s\" %.*s %.*s", + LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #endif return result; } if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { -#ifdef GB_SYSTEM_UNIX +#if defined(GB_SYSTEM_UNIX) result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", - LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", LIT(target_os_names[build_context.metrics.os]), @@ -181,28 +173,11 @@ i32 linker_stage(lbGenerator *gen) { gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); - char const *output_ext = "exe"; gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); defer (gb_string_free(link_settings)); - - // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. - Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); - - if (find_result.windows_sdk_version == 0) { - gb_printf_err("Windows SDK not found.\n"); - exit(1); - } - - if (build_context.ignore_microsoft_magic) { - find_result = {}; - } - // Add library search paths. - if (find_result.vs_library_path.len > 0) { - GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); - GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - + if (build_context.build_paths[BuildPath_VS_LIB].basename.len > 0) { String path = {}; auto add_path = [&](String path) { if (path[path.len-1] == '\\') { @@ -210,9 +185,9 @@ i32 linker_stage(lbGenerator *gen) { } link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); }; - add_path(find_result.windows_sdk_um_library_path); - add_path(find_result.windows_sdk_ucrt_library_path); - add_path(find_result.vs_library_path); + add_path(build_context.build_paths[BuildPath_Win_SDK_UM_Lib].basename); + add_path(build_context.build_paths[BuildPath_Win_SDK_UCRT_Lib].basename); + add_path(build_context.build_paths[BuildPath_VS_LIB].basename); } @@ -252,14 +227,14 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.build_mode == BuildMode_DynamicLibrary) { - output_ext = "dll"; link_settings = gb_string_append_fmt(link_settings, " /DLL"); } else { link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); } if (build_context.pdb_filepath != "") { - link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); + String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]); + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(pdb_path)); } if (build_context.no_crt) { @@ -300,13 +275,21 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } + String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]); + defer (gb_free(heap_allocator(), vs_exe_path.text)); + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; if (!build_context.use_lld) { // msvc if (build_context.has_resource) { + String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]); + String res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]); + defer (gb_free(heap_allocator(), rc_path.text)); + defer (gb_free(heap_allocator(), res_path.text)); + result = system_exec_command_line_app("msvc-link", - "\"rc.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", - LIT(output_base), - LIT(build_context.resource_filepath) + "\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"", + LIT(res_path), + LIT(rc_path) ); if (result) { @@ -314,13 +297,13 @@ i32 linker_stage(lbGenerator *gen) { } result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s \"%.*s.res\" -OUT:\"%.*s.%s\" %s " + "\"%.*slink.exe\" %s \"%.*s\" -OUT:\"%.*s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(find_result.vs_exe_path), object_files, LIT(output_base), LIT(output_base), output_ext, + LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename), link_settings, subsystem_str, LIT(build_context.link_flags), @@ -329,13 +312,13 @@ i32 linker_stage(lbGenerator *gen) { ); } else { result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s -OUT:\"%.*s.%s\" %s " + "\"%.*slink.exe\" %s -OUT:\"%.*s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(find_result.vs_exe_path), object_files, LIT(output_base), output_ext, + LIT(vs_exe_path), object_files, LIT(output_filename), link_settings, subsystem_str, LIT(build_context.link_flags), @@ -350,13 +333,13 @@ i32 linker_stage(lbGenerator *gen) { } else { // lld result = system_exec_command_line_app("msvc-lld-link", - "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s " + "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(build_context.ODIN_ROOT), object_files, LIT(output_base),output_ext, + LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename), link_settings, subsystem_str, LIT(build_context.link_flags), @@ -415,7 +398,7 @@ i32 linker_stage(lbGenerator *gen) { } else if (string_ends_with(lib, str_lit(".so"))) { // dynamic lib, relative path to executable // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtimeto the executable + // at runtime to the executable lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths @@ -431,9 +414,6 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } - // Unlike the Win32 linker code, the output_ext includes the dot, because - // typically executable files on *NIX systems don't have extensions. - String output_ext = {}; gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); if (build_context.no_crt) { @@ -461,26 +441,12 @@ i32 linker_stage(lbGenerator *gen) { // correctly this way since all the other dependencies provided implicitly // by the compiler frontend are still needed and most of the command // line arguments prepared previously are incompatible with ld. - // - // Shared libraries are .dylib on MacOS and .so on Linux. - if (build_context.metrics.os == TargetOs_darwin) { - output_ext = STR_LIT(".dylib"); - } else { - output_ext = STR_LIT(".so"); - } link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } else if (build_context.metrics.os != TargetOs_openbsd) { // OpenBSD defaults to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } - if (build_context.out_filepath.len > 0) { - //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that - isize pos = string_extension_position(build_context.out_filepath); - if (pos > 0) { - output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); - } - } gbString platform_lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(platform_lib_str)); @@ -507,7 +473,7 @@ i32 linker_stage(lbGenerator *gen) { defer (gb_string_free(link_command_line)); link_command_line = gb_string_appendc(link_command_line, object_files); - link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s%.*s\" ", LIT(output_base), LIT(output_ext)); + link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags)); @@ -524,9 +490,7 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe // to the symbols in the object file - result = system_exec_command_line_app("dsymutil", - "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) - ); + result = system_exec_command_line_app("dsymutil", "dsymutil %.*s", LIT(output_filename)); if (result) { return result; @@ -1526,6 +1490,10 @@ bool parse_build_flags(Array args) { gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path)); bad_flags = true; break; + } else if (!gb_file_exists((const char *)path.text)) { + gb_printf_err("Invalid -resource path %.*s, file does not exist.\n", LIT(path)); + bad_flags = true; + break; } build_context.resource_filepath = substring(path, 0, string_extension_position(path)); build_context.has_resource = true; @@ -1540,6 +1508,11 @@ bool parse_build_flags(Array args) { String path = value.value_string; path = string_trim_whitespace(path); if (is_build_flag_path_valid(path)) { + if (path_is_directory(path)) { + gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path)); + bad_flags = true; + break; + } // #if defined(GB_SYSTEM_WINDOWS) // String ext = path_extension(path); // if (ext != ".pdb") { @@ -2666,6 +2639,8 @@ int main(int arg_count, char const **arg_ptr) { return 1; } + init_filename = copy_string(permanent_allocator(), init_filename); + if (init_filename == "-help" || init_filename == "--help") { build_context.show_help = true; @@ -2688,6 +2663,12 @@ int main(int arg_count, char const **arg_ptr) { gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename)); gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n"); return 1; + } else { + String const ext = str_lit(".odin"); + if (!string_ends_with(init_filename, ext)) { + gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); + return 1; + } } } } @@ -2709,13 +2690,24 @@ int main(int arg_count, char const **arg_ptr) { get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared"))); } - init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr); // if (build_context.word_size == 4 && build_context.metrics.os != TargetOs_js) { // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0])); // return 1; // } + // Set and check build paths... + if (!init_build_paths(init_filename)) { + return 1; + } + + if (build_context.show_debug_messages) { + for_array(i, build_context.build_paths) { + String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); + debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); + } + } + init_global_thread_pool(); defer (thread_pool_destroy(&global_thread_pool)); @@ -2732,6 +2724,8 @@ int main(int arg_count, char const **arg_ptr) { } defer (destroy_parser(parser)); + // TODO(jeroen): Remove the `init_filename` param. + // Let's put that on `build_context.build_paths[0]` instead. if (parse_packages(parser, init_filename) != ParseFile_None) { return 1; } @@ -2810,16 +2804,14 @@ int main(int arg_count, char const **arg_ptr) { } if (run_output) { + String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); + defer (gb_free(heap_allocator(), exe_name.text)); + #if defined(GB_SYSTEM_WINDOWS) - return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(gen->output_base), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "%.*s %.*s", LIT(exe_name), LIT(run_args_string)); #else - //NOTE(thebirk): This whole thing is a little leaky - String output_ext = {}; - String complete_path = concatenate_strings(permanent_allocator(), gen->output_base, output_ext); - complete_path = path_to_full_path(permanent_allocator(), complete_path); - return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); #endif } - return 0; } diff --git a/src/parser.cpp b/src/parser.cpp index 767119aa8..df7f908a6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5751,7 +5751,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } } } - + { // Add these packages serially and then process them parallel mutex_lock(&p->wait_mutex); diff --git a/src/path.cpp b/src/path.cpp new file mode 100644 index 000000000..8d8e532b8 --- /dev/null +++ b/src/path.cpp @@ -0,0 +1,333 @@ +/* + Path handling utilities. +*/ + +#if defined(GB_SYSTEM_WINDOWS) + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + String16 wstr = string_to_string16(a, path); + defer (gb_free(a, wstr.text)); + + i32 attribs = GetFileAttributesW(wstr.text); + if (attribs < 0) return false; + + return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + +#else + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + char *copy = cast(char *)copy_string(a, path).text; + defer (gb_free(a, copy)); + + struct stat s; + if (stat(copy, &s) == 0) { + return (s.st_mode & S_IFDIR) != 0; + } + return false; + } +#endif + + +String path_to_full_path(gbAllocator a, String path) { + gbAllocator ha = heap_allocator(); + char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); + defer (gb_free(ha, path_c)); + + char *fullpath = gb_path_get_full_name(a, path_c); + String res = string_trim_whitespace(make_string_c(fullpath)); +#if defined(GB_SYSTEM_WINDOWS) + for (isize i = 0; i < res.len; i++) { + if (res.text[i] == '\\') { + res.text[i] = '/'; + } + } +#endif + return copy_string(a, res); +} + +struct Path { + String basename; + String name; + String ext; +}; + +// NOTE(Jeroen): Naively turns a Path into a string. +String path_to_string(gbAllocator a, Path path) { + if (path.basename.len + path.name.len + path.ext.len == 0) { + return make_string(nullptr, 0); + } + + isize len = path.basename.len + 1 + path.name.len + 1; + if (path.ext.len > 0) { + len += path.ext.len + 1; + } + + u8 *str = gb_alloc_array(a, u8, len); + + isize i = 0; + gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len; + gb_memmove(str+i, "/", 1); i += 1; + gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len; + if (path.ext.len > 0) { + gb_memmove(str+i, ".", 1); i += 1; + gb_memmove(str+i, path.ext.text, path.ext.len); i += path.ext.len; + } + str[i] = 0; + + String res = make_string(str, i); + res = string_trim_whitespace(res); + return res; +} + +// NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`. +String path_to_full_path(gbAllocator a, Path path) { + String temp = path_to_string(heap_allocator(), path); + defer (gb_free(heap_allocator(), temp.text)); + + return path_to_full_path(a, temp); +} + +// NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path, +// and then breaks it into its components to make a Path. +Path path_from_string(gbAllocator a, String const &path) { + Path res = {}; + + if (path.len == 0) return res; + + String fullpath = path_to_full_path(a, path); + defer (gb_free(heap_allocator(), fullpath.text)); + + res.basename = directory_from_path(fullpath); + res.basename = copy_string(a, res.basename); + + if (string_ends_with(fullpath, '/')) { + // It's a directory. We don't need to tinker with the name and extension. + return res; + } + + isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len; + res.name = substring(fullpath, name_start, fullpath.len); + res.name = remove_extension_from_path(res.name); + res.name = copy_string(a, res.name); + + res.ext = path_extension(fullpath, false); // false says not to include the dot. + res.ext = copy_string(a, res.ext); + return res; +} + +bool path_is_directory(Path path) { + String path_string = path_to_full_path(heap_allocator(), path); + defer (gb_free(heap_allocator(), path_string.text)); + + return path_is_directory(path_string); +} + +struct FileInfo { + String name; + String fullpath; + i64 size; + bool is_dir; +}; + +enum ReadDirectoryError { + ReadDirectory_None, + + ReadDirectory_InvalidPath, + ReadDirectory_NotExists, + ReadDirectory_Permission, + ReadDirectory_NotDir, + ReadDirectory_Empty, + ReadDirectory_Unknown, + + ReadDirectory_COUNT, +}; + +i64 get_file_size(String path) { + char *c_str = alloc_cstring(heap_allocator(), path); + defer (gb_free(heap_allocator(), c_str)); + + gbFile f = {}; + gbFileError err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + if (err != gbFileError_None) { + return -1; + } + return gb_file_size(&f); +} + + +#if defined(GB_SYSTEM_WINDOWS) +ReadDirectoryError read_directory(String path, Array *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + while (path.len > 0) { + Rune end = path[path.len-1]; + if (end == '/') { + path.len -= 1; + } else if (end == '\\') { + path.len -= 1; + } else { + break; + } + } + + if (path.len == 0) { + return ReadDirectory_InvalidPath; + } + { + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + case gbFileError_Invalid: return ReadDirectory_InvalidPath; + case gbFileError_NotExists: return ReadDirectory_NotExists; + // case gbFileError_Permission: return ReadDirectory_Permission; + } + } + + if (!path_is_directory(path)) { + return ReadDirectory_NotDir; + } + + + char *new_path = gb_alloc_array(a, char, path.len+3); + defer (gb_free(a, new_path)); + + gb_memmove(new_path, path.text, path.len); + gb_memmove(new_path+path.len, "/*", 2); + new_path[path.len+2] = 0; + + String np = make_string(cast(u8 *)new_path, path.len+2); + String16 wstr = string_to_string16(a, np); + defer (gb_free(a, wstr.text)); + + WIN32_FIND_DATAW file_data = {}; + HANDLE find_file = FindFirstFileW(wstr.text, &file_data); + if (find_file == INVALID_HANDLE_VALUE) { + return ReadDirectory_Unknown; + } + defer (FindClose(find_file)); + + array_init(fi, a, 0, 100); + + do { + wchar_t *filename_w = file_data.cFileName; + i64 size = cast(i64)file_data.nFileSizeLow; + size |= (cast(i64)file_data.nFileSizeHigh) << 32; + String name = string16_to_string(a, make_string16_c(filename_w)); + if (name == "." || name == "..") { + gb_free(a, name.text); + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + array_add(fi, info); + } while (FindNextFileW(find_file, &file_data)); + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) + +#include + +ReadDirectoryError read_directory(String path, Array *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + char *c_path = alloc_cstring(a, path); + defer (gb_free(a, c_path)); + + DIR *dir = opendir(c_path); + if (!dir) { + switch (errno) { + case ENOENT: + return ReadDirectory_NotExists; + case EACCES: + return ReadDirectory_Permission; + case ENOTDIR: + return ReadDirectory_NotDir; + default: + // ENOMEM: out of memory + // EMFILE: per-process limit on open fds reached + // ENFILE: system-wide limit on total open files reached + return ReadDirectory_Unknown; + } + GB_PANIC("unreachable"); + } + + array_init(fi, a, 0, 100); + + for (;;) { + struct dirent *entry = readdir(dir); + if (entry == nullptr) { + break; + } + + String name = make_string_c(entry->d_name); + if (name == "." || name == "..") { + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + filepath.text[filepath.len] = 0; + + + struct stat dir_stat = {}; + + if (stat((char *)filepath.text, &dir_stat)) { + continue; + } + + if (S_ISDIR(dir_stat.st_mode)) { + continue; + } + + i64 size = dir_stat.st_size; + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + array_add(fi, info); + } + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#else +#error Implement read_directory +#endif + diff --git a/src/string.cpp b/src/string.cpp index d3dbc6904..3515df48e 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -245,15 +245,14 @@ gb_inline isize string_extension_position(String const &str) { return dot_pos; } -String path_extension(String const &str) { +String path_extension(String const &str, bool include_dot = true) { isize pos = string_extension_position(str); if (pos < 0) { return make_string(nullptr, 0); } - return substring(str, pos, str.len); + return substring(str, include_dot ? pos : pos + 1, str.len); } - String string_trim_whitespace(String str) { while (str.len > 0 && rune_is_whitespace(str[str.len-1])) { str.len--; @@ -328,7 +327,10 @@ String directory_from_path(String const &s) { break; } } - return substring(s, 0, i); + if (i >= 0) { + return substring(s, 0, i); + } + return substring(s, 0, 0); } String concatenate_strings(gbAllocator a, String const &x, String const &y) { diff --git a/tests/core/build.bat b/tests/core/build.bat index 2f9ba672e..1973c22aa 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -5,61 +5,61 @@ python3 download_assets.py echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% run image %COMMON% +%PATH_TO_ODIN% run image %COMMON% -out:test_image echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% run compress %COMMON% +%PATH_TO_ODIN% run compress %COMMON% -out:test_compress echo --- echo Running core:strings tests echo --- -%PATH_TO_ODIN% run strings %COMMON% +%PATH_TO_ODIN% run strings %COMMON% -out:test_strings echo --- echo Running core:hash tests echo --- -%PATH_TO_ODIN% run hash %COMMON% -o:size +%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_hash echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size +%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_odin echo --- echo Running core:crypto hash tests echo --- -%PATH_TO_ODIN% run crypto %COMMON% +%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding/hxa %COMMON% -%PATH_TO_ODIN% run encoding/json %COMMON% -%PATH_TO_ODIN% run encoding/varint %COMMON% +%PATH_TO_ODIN% run encoding/hxa %COMMON% -out:test_hxa +%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json +%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% +%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise echo --- echo Running core:math tests echo --- -%PATH_TO_ODIN% run math %COMMON% +%PATH_TO_ODIN% run math %COMMON% -out:test_math echo --- echo Running core:math/linalg/glsl tests echo --- -%PATH_TO_ODIN% run math/linalg/glsl %COMMON% +%PATH_TO_ODIN% run math/linalg/glsl %COMMON% -out:test_glsl echo --- echo Running core:path/filepath tests echo --- -%PATH_TO_ODIN% run path/filepath %COMMON% +%PATH_TO_ODIN% run path/filepath %COMMON% -out:test_filepath echo --- echo Running core:reflect tests echo --- -%PATH_TO_ODIN% run reflect %COMMON% +%PATH_TO_ODIN% run reflect %COMMON% -out:test_reflect diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index 16bdbc8ca..ad199d775 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -4,7 +4,7 @@ set PATH_TO_ODIN==..\..\..\..\odin set TEST_ARGS=-fast-tests set TEST_ARGS=-no-random set TEST_ARGS= -set OUT_NAME=math_big_test_library +set OUT_NAME=math_big_test_library.dll set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style echo --- echo Running core:math/big tests diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 117a9a5f1..91ec99e05 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -8,10 +8,10 @@ COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" set -x ./odin build tests/issues/test_issue_829.odin $COMMON -file -tests/issues/build/test_issue +tests/issues/build/test_issue.bin ./odin build tests/issues/test_issue_1592.odin $COMMON -file -tests/issues/build/test_issue +tests/issues/build/test_issue.bin set +x From 76d48b38d394b953ea4bbe1420ecd11e6e7dd028 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 8 Apr 2022 19:02:14 +0200 Subject: [PATCH 0573/1052] Compiler: Allow -out: to not have an extension on *nix for executables (only). --- src/build_settings.cpp | 4 +++- tests/issues/run.sh | 4 ++-- tests/vendor/Makefile | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 0b582eac8..55d129124 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1308,7 +1308,9 @@ bool init_build_paths(String init_filename) { // Do we have an extension? We might not if the output filename was supplied. if (bc->build_paths[BuildPath_Output].ext.len == 0) { - bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension); + if (build_context.metrics.os == TargetOs_windows || build_context.build_mode != BuildMode_Executable) { + bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension); + } } // Check if output path is a directory. diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 91ec99e05..117a9a5f1 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -8,10 +8,10 @@ COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" set -x ./odin build tests/issues/test_issue_829.odin $COMMON -file -tests/issues/build/test_issue.bin +tests/issues/build/test_issue ./odin build tests/issues/test_issue_1592.odin $COMMON -file -tests/issues/build/test_issue.bin +tests/issues/build/test_issue set +x diff --git a/tests/vendor/Makefile b/tests/vendor/Makefile index 341067c6e..c508f6c50 100644 --- a/tests/vendor/Makefile +++ b/tests/vendor/Makefile @@ -10,4 +10,4 @@ endif all: botan_test botan_test: - $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS) + $(ODIN) run botan -out=test_botan_hash -o:speed -no-bounds-check $(ODINFLAGS) From f4723aea4cb610a8ccc7d3614f8787d638d284d6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 8 Apr 2022 19:14:59 +0200 Subject: [PATCH 0574/1052] Remove redundant bit for non-Windows. --- src/build_settings.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 55d129124..212ded5c8 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1281,22 +1281,8 @@ bool init_build_paths(String init_filename) { output_name = remove_extension_from_path(output_name); output_name = copy_string(ha, string_trim_whitespace(output_name)); - /* - NOTE(Jeroen): This fallback substitution can't be made at this stage. - if (gen->output_name.len == 0) { - gen->output_name = c->info.init_scope->pkg->name; - } - */ Path output_path = path_from_string(ha, output_name); - #ifndef GB_SYSTEM_WINDOWS - char cwd[4096]; - getcwd(&cwd[0], 4096); - - const u8 * cwd_str = (const u8 *)&cwd[0]; - output_path.basename = copy_string(ha, make_string(cwd_str, strlen(cwd))); - #endif - // Replace extension. if (output_path.ext.len > 0) { gb_free(ha, output_path.ext.text); From 3d2856db31456e9a117209eccf8e1167b4401205 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 24 Apr 2022 14:19:25 +0200 Subject: [PATCH 0575/1052] Update tests to use new filename generation code. --- .github/workflows/ci.yml | 11 ++++++++--- core/crypto/util/util.odin | 1 + tests/core/Makefile | 29 +++++++++++++++-------------- tests/core/build.bat | 32 +++++++++++++++++--------------- tests/issues/run.bat | 21 ++++++++------------- tests/issues/run.sh | 19 +++++++++---------- tests/vendor/Makefile | 3 ++- tests/vendor/build.bat | 3 ++- 8 files changed, 62 insertions(+), 57 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3cc4283b0..989f56712 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,9 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: tests/issues/run.sh + run: | + cd tests/issues + run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -91,7 +93,9 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: tests/issues/run.sh + run: | + cd tests/issues + run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 @@ -163,7 +167,8 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - call tests\issues\run.bat + cd tests\issues + call build.bat timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd diff --git a/core/crypto/util/util.odin b/core/crypto/util/util.odin index 6273a232e..83b07e546 100644 --- a/core/crypto/util/util.odin +++ b/core/crypto/util/util.odin @@ -11,6 +11,7 @@ package util */ import "core:mem" +_ :: mem // @note(bp): this can replace the other two cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D { diff --git a/tests/core/Makefile b/tests/core/Makefile index 6a92b4efb..9bb622633 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,5 +1,6 @@ ODIN=../../odin PYTHON=$(shell which python3) +OUT_FILE=test_binary.bin all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test @@ -8,39 +9,39 @@ download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image/test_core_image.odin -file + $(ODIN) run image/test_core_image.odin -out=$(OUT_FILE) -file compress_test: - $(ODIN) run compress/test_core_compress.odin -file + $(ODIN) run compress/test_core_compress.odin -out=$(OUT_FILE) -file strings_test: - $(ODIN) run strings/test_core_strings.odin -file + $(ODIN) run strings/test_core_strings.odin -out=$(OUT_FILE) -file hash_test: - $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check + $(ODIN) run hash -out=$(OUT_FILE) -o:speed -no-bounds-check crypto_test: - $(ODIN) run crypto -out=test_crypto_hash -o:speed -no-bounds-check + $(ODIN) run crypto -out=$(OUT_FILE) -o:speed -no-bounds-check noise_test: - $(ODIN) run math/noise -out=test_noise + $(ODIN) run math/noise -out=$(OUT_FILE) encoding_test: - $(ODIN) run encoding/hxa -out=test_hxa -collection:tests=.. - $(ODIN) run encoding/json -out=test_json - $(ODIN) run encoding/varint -out=test_varint + $(ODIN) run encoding/hxa -out=$(OUT_FILE) -collection:tests=.. + $(ODIN) run encoding/json -out=$(OUT_FILE) + $(ODIN) run encoding/varint -out=$(OUT_FILE) math_test: - $(ODIN) run math/test_core_math.odin -out=test_core_math -file -collection:tests=.. + $(ODIN) run math/test_core_math.odin -out=$(OUT_FILE) -file -collection:tests=.. linalg_glsl_math_test: - $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=test_linalg_glsl_math -collection:tests=.. + $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=$(OUT_FILE) -collection:tests=.. filepath_test: - $(ODIN) run path/filepath/test_core_filepath.odin -file -out=test_core_filepath -collection:tests=.. + $(ODIN) run path/filepath/test_core_filepath.odin -file -out=$(OUT_FILE) -collection:tests=.. reflect_test: - $(ODIN) run reflect/test_core_reflect.odin -file -out=test_core_reflect -collection:tests=.. + $(ODIN) run reflect/test_core_reflect.odin -file -out=$(OUT_FILE) -collection:tests=.. os_exit_test: - $(ODIN) run os/test_core_os_exit.odin -file -out=test_core_os_exit && exit 1 || exit 0 + $(ODIN) run os/test_core_os_exit.odin -file -out=$(OUT_FILE) && exit 1 || exit 0 diff --git a/tests/core/build.bat b/tests/core/build.bat index 1973c22aa..331a473aa 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,65 +1,67 @@ @echo off -set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. +set OUT_FILE=test_binary.exe +set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. -out:%OUT_FILE% set PATH_TO_ODIN==..\..\odin + python3 download_assets.py echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% run image %COMMON% -out:test_image +%PATH_TO_ODIN% run image %COMMON% echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% run compress %COMMON% -out:test_compress +%PATH_TO_ODIN% run compress %COMMON% echo --- echo Running core:strings tests echo --- -%PATH_TO_ODIN% run strings %COMMON% -out:test_strings +%PATH_TO_ODIN% run strings %COMMON% echo --- echo Running core:hash tests echo --- -%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_hash +%PATH_TO_ODIN% run hash %COMMON% -o:size echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_odin +%PATH_TO_ODIN% run odin %COMMON% -o:size echo --- echo Running core:crypto hash tests echo --- -%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto +%PATH_TO_ODIN% run crypto %COMMON% echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding/hxa %COMMON% -out:test_hxa -%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json -%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint +%PATH_TO_ODIN% run encoding/hxa %COMMON% +%PATH_TO_ODIN% run encoding/json %COMMON% +%PATH_TO_ODIN% run encoding/varint %COMMON% echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise +%PATH_TO_ODIN% run math/noise %COMMON% echo --- echo Running core:math tests echo --- -%PATH_TO_ODIN% run math %COMMON% -out:test_math +%PATH_TO_ODIN% run math %COMMON% echo --- echo Running core:math/linalg/glsl tests echo --- -%PATH_TO_ODIN% run math/linalg/glsl %COMMON% -out:test_glsl +%PATH_TO_ODIN% run math/linalg/glsl %COMMON% echo --- echo Running core:path/filepath tests echo --- -%PATH_TO_ODIN% run path/filepath %COMMON% -out:test_filepath +%PATH_TO_ODIN% run path/filepath %COMMON% echo --- echo Running core:reflect tests echo --- -%PATH_TO_ODIN% run reflect %COMMON% -out:test_reflect +%PATH_TO_ODIN% run reflect %COMMON% diff --git a/tests/issues/run.bat b/tests/issues/run.bat index a652d9694..a936bd896 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -1,17 +1,12 @@ @echo off +set PATH_TO_ODIN==..\..\odin +set COMMON=-collection:tests=.. -out:build\test_issue +if not exist "build" mkdir build -if not exist "tests\issues\build\" mkdir tests\issues\build +%PATH_TO_ODIN% build test_issue_829.odin %COMMON% -file +build\test_issue -set COMMON=-collection:tests=tests -out:tests\issues\build\test_issue +%PATH_TO_ODIN% build test_issue_1592.odin %COMMON% -file +build\test_issue -@echo on - -.\odin build tests\issues\test_issue_829.odin %COMMON% -file -tests\issues\build\test_issue - -.\odin build tests\issues\test_issue_1592.odin %COMMON% -file -tests\issues\build\test_issue - -@echo off - -rmdir /S /Q tests\issues\build +rmdir /S /Q build diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 117a9a5f1..ec6d7130d 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -1,18 +1,17 @@ #!/bin/bash +ODIN=../../odin +COMMON="-collection:tests=.. -out:build/test_issue.bin" + set -eu - -mkdir -p tests/issues/build - -COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" - +mkdir -p build set -x -./odin build tests/issues/test_issue_829.odin $COMMON -file -tests/issues/build/test_issue +$ODIN build test_issue_829.odin $COMMON -file +build/test_issue.bin -./odin build tests/issues/test_issue_1592.odin $COMMON -file -tests/issues/build/test_issue +$ODIN build test_issue_1592.odin $COMMON -file +build/test_issue.bin set +x -rm -rf tests/issues/build +rm -rf build diff --git a/tests/vendor/Makefile b/tests/vendor/Makefile index c508f6c50..380e64e09 100644 --- a/tests/vendor/Makefile +++ b/tests/vendor/Makefile @@ -1,5 +1,6 @@ ODIN=../../odin ODINFLAGS= +OUT_FILE=test_binary.bin OS=$(shell uname) @@ -10,4 +11,4 @@ endif all: botan_test botan_test: - $(ODIN) run botan -out=test_botan_hash -o:speed -no-bounds-check $(ODINFLAGS) + $(ODIN) run botan -out=$(OUT_FILE) -o:speed -no-bounds-check $(ODINFLAGS) diff --git a/tests/vendor/build.bat b/tests/vendor/build.bat index e70d9f1d5..4bd9a6496 100644 --- a/tests/vendor/build.bat +++ b/tests/vendor/build.bat @@ -1,5 +1,6 @@ @echo off -set COMMON=-show-timings -no-bounds-check -vet -strict-style +set OUT_FILE=test_binary.exe +set COMMON=-show-timings -no-bounds-check -vet -strict-style -out:%OUT_FILE% set PATH_TO_ODIN==..\..\odin echo --- From 9f8d90f466454f4d14e755d44e4ba47ccbf0c92e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 24 Apr 2022 14:28:00 +0200 Subject: [PATCH 0576/1052] Update CI paths for issue tests. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 989f56712..d72775636 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: - name: Odin issues tests run: | cd tests/issues - run.sh + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -95,7 +95,7 @@ jobs: - name: Odin issues tests run: | cd tests/issues - run.sh + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 @@ -168,7 +168,7 @@ jobs: run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat cd tests\issues - call build.bat + call run.bat timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd From 63331ef731209ec8db65d7f26bdbebdf9459107d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 24 Apr 2022 19:53:36 +0200 Subject: [PATCH 0577/1052] Revert "Merge pull request #1702 from Kelimion/filename_generation" This reverts commit a40a53b10447c9223c24cccf565a95f1773d3922, reversing changes made to 5422a3b17eae821df4adf869960995e922eb0e76. --- .github/workflows/ci.yml | 11 +- .gitignore | 1 - Makefile | 4 +- build_odin.sh | 4 +- core/crypto/util/util.odin | 1 - src/build_settings.cpp | 208 +++------------------ src/common.cpp | 257 +++++++++++++++++++++++++- src/gb/gb.h | 50 ++--- src/llvm_backend.cpp | 14 +- src/llvm_backend_general.cpp | 1 + src/main.cpp | 152 ++++++++-------- src/parser.cpp | 2 +- src/path.cpp | 333 ---------------------------------- src/string.cpp | 10 +- tests/core/Makefile | 29 ++- tests/core/build.bat | 10 +- tests/core/math/big/build.bat | 2 +- tests/issues/run.bat | 21 ++- tests/issues/run.sh | 19 +- tests/vendor/Makefile | 3 +- tests/vendor/build.bat | 3 +- 21 files changed, 436 insertions(+), 699 deletions(-) delete mode 100644 src/path.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d72775636..3cc4283b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,9 +39,7 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: | - cd tests/issues - ./run.sh + run: tests/issues/run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -93,9 +91,7 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: | - cd tests/issues - ./run.sh + run: tests/issues/run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 @@ -167,8 +163,7 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - cd tests\issues - call run.bat + call tests\issues\run.bat timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd diff --git a/.gitignore b/.gitignore index d03a86fd7..e8b3d3050 100644 --- a/.gitignore +++ b/.gitignore @@ -269,7 +269,6 @@ bin/ # - Linux/MacOS odin odin.dSYM -*.bin # shared collection shared/ diff --git a/Makefile b/Makefile index 1a1c93180..82150c6a2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -all: debug +all: debug demo demo: - ./odin run examples/demo + ./odin run examples/demo/demo.odin report: ./odin report diff --git a/build_odin.sh b/build_odin.sh index 4810cafd2..aef3f2836 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -102,7 +102,7 @@ build_odin() { } run_demo() { - ./odin run examples/demo + ./odin run examples/demo/demo.odin -file } case $OS in @@ -147,4 +147,4 @@ if [[ $# -eq 1 ]]; then exit 0 else panic "Too many arguments!" -fi \ No newline at end of file +fi diff --git a/core/crypto/util/util.odin b/core/crypto/util/util.odin index 83b07e546..6273a232e 100644 --- a/core/crypto/util/util.odin +++ b/core/crypto/util/util.odin @@ -11,7 +11,6 @@ package util */ import "core:mem" -_ :: mem // @note(bp): this can replace the other two cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D { diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 212ded5c8..2f3eb03a5 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -3,6 +3,7 @@ #include #endif + // #if defined(GB_SYSTEM_WINDOWS) // #define DEFAULT_TO_THREADED_CHECKER // #endif @@ -197,22 +198,6 @@ enum RelocMode : u8 { RelocMode_DynamicNoPIC, }; -enum BuildPath : u8 { - BuildPath_Main_Package, // Input Path to the package directory (or file) we're building. - BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`. - BuildPath_RES, // Output Path for .res file, generated from previous. - BuildPath_Win_SDK_Root, // windows_sdk_root - BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path - BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path - BuildPath_VS_EXE, // vs_exe_path - BuildPath_VS_LIB, // vs_library_path - - BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`. - BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`. - - BuildPathCOUNT, -}; - // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -241,13 +226,9 @@ struct BuildContext { bool show_help; - Array build_paths; // Contains `Path` objects to output filename, pdb, resource and intermediate files. - // BuildPath enum contains the indices of paths we know *before* the work starts. - String out_filepath; String resource_filepath; String pdb_filepath; - bool has_resource; String link_flags; String extra_linker_flags; @@ -319,6 +300,8 @@ struct BuildContext { }; + + gb_global BuildContext build_context = {0}; bool global_warnings_as_errors(void) { @@ -622,6 +605,28 @@ bool allow_check_foreign_filepath(void) { // is_abs_path // has_subdir +enum TargetFileValidity : u8 { + TargetFileValidity_Invalid, + + TargetFileValidity_Writable_File, + TargetFileValidity_No_Write_Permission, + TargetFileValidity_Directory, + + TargetTargetFileValidity_COUNT, +}; + +TargetFileValidity set_output_filename(void) { + // Assembles the output filename from build_context information. + // Returns `true` if it doesn't exist or is a file. + // Returns `false` if a directory or write-protected file. + + + + + return TargetFileValidity_Writable_File; +} + + String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; @@ -968,6 +973,7 @@ char *token_pos_to_string(TokenPos const &pos) { return s; } + void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; @@ -1146,166 +1152,8 @@ void init_build_context(TargetMetrics *cross_target) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); + + #undef LINK_FLAG_X64 #undef LINK_FLAG_386 } - -#if defined(GB_SYSTEM_WINDOWS) -// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. -// NOTE(Jeroen): No longer needed in `main.cpp -> linker_stage`. We now resolve those paths in `init_build_paths`. -#include "microsoft_craziness.h" -#endif - -// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. -// We've previously called `parse_build_flags`, so `out_filepath` should be set. -bool init_build_paths(String init_filename) { - gbAllocator ha = heap_allocator(); - BuildContext *bc = &build_context; - - // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index. - array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT); - - // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path. - bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename); - - bool produces_output_file = false; - if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { - produces_output_file = true; - } else if (bc->command_kind & Command__does_build) { - produces_output_file = true; - } - - if (!produces_output_file) { - // Command doesn't produce output files. We're done. - return true; - } - - #if defined(GB_SYSTEM_WINDOWS) - if (bc->resource_filepath.len > 0) { - bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); - bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); - bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc")); - bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res")); - } - - if (bc->pdb_filepath.len > 0) { - bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath); - } - - if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { - // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. - Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); - - if (find_result.windows_sdk_version == 0) { - gb_printf_err("Windows SDK not found.\n"); - return false; - } - - GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); - GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - - if (find_result.windows_sdk_root.len > 0) { - bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); - } - - if (find_result.windows_sdk_um_library_path.len > 0) { - bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path); - } - - if (find_result.windows_sdk_ucrt_library_path.len > 0) { - bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path); - } - - if (find_result.vs_exe_path.len > 0) { - bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path); - } - - if (find_result.vs_library_path.len > 0) { - bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path); - } - - gb_free(ha, find_result.windows_sdk_root.text); - gb_free(ha, find_result.windows_sdk_um_library_path.text); - gb_free(ha, find_result.windows_sdk_ucrt_library_path.text); - gb_free(ha, find_result.vs_exe_path.text); - gb_free(ha, find_result.vs_library_path.text); - - } - #endif - - // All the build targets and OSes. - String output_extension; - - if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { - output_extension = STR_LIT("odin-doc"); - } else if (is_arch_wasm()) { - output_extension = STR_LIT("wasm"); - } else if (build_context.build_mode == BuildMode_Executable) { - // By default use a .bin executable extension. - output_extension = STR_LIT("bin"); - - if (build_context.metrics.os == TargetOs_windows) { - output_extension = STR_LIT("exe"); - } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { - output_extension = make_string(nullptr, 0); - } - } else if (build_context.build_mode == BuildMode_DynamicLibrary) { - // By default use a .so shared library extension. - output_extension = STR_LIT("so"); - - if (build_context.metrics.os == TargetOs_windows) { - output_extension = STR_LIT("dll"); - } else if (build_context.metrics.os == TargetOs_darwin) { - output_extension = STR_LIT("dylib"); - } - } else if (build_context.build_mode == BuildMode_Object) { - // By default use a .o object extension. - output_extension = STR_LIT("o"); - - if (build_context.metrics.os == TargetOs_windows) { - output_extension = STR_LIT("obj"); - } - } else if (build_context.build_mode == BuildMode_Assembly) { - // By default use a .S asm extension. - output_extension = STR_LIT("S"); - } else if (build_context.build_mode == BuildMode_LLVM_IR) { - output_extension = STR_LIT("ll"); - } else { - GB_PANIC("Unhandled build mode/target combination.\n"); - } - - if (bc->out_filepath.len > 0) { - bc->build_paths[BuildPath_Output] = path_from_string(ha, bc->out_filepath); - } else { - String output_name = remove_directory_from_path(init_filename); - output_name = remove_extension_from_path(output_name); - output_name = copy_string(ha, string_trim_whitespace(output_name)); - - Path output_path = path_from_string(ha, output_name); - - // Replace extension. - if (output_path.ext.len > 0) { - gb_free(ha, output_path.ext.text); - } - output_path.ext = copy_string(ha, output_extension); - - bc->build_paths[BuildPath_Output] = output_path; - } - - // Do we have an extension? We might not if the output filename was supplied. - if (bc->build_paths[BuildPath_Output].ext.len == 0) { - if (build_context.metrics.os == TargetOs_windows || build_context.build_mode != BuildMode_Executable) { - bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension); - } - } - - // Check if output path is a directory. - if (path_is_directory(bc->build_paths[BuildPath_Output])) { - String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); - defer (gb_free(ha, output_file.text)); - gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file)); - return false; - } - - return true; -} \ No newline at end of file diff --git a/src/common.cpp b/src/common.cpp index 94248fb62..aaacda04b 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -675,7 +675,262 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) { #endif -#include "path.cpp" + +#if defined(GB_SYSTEM_WINDOWS) + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + String16 wstr = string_to_string16(a, path); + defer (gb_free(a, wstr.text)); + + i32 attribs = GetFileAttributesW(wstr.text); + if (attribs < 0) return false; + + return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + +#else + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + char *copy = cast(char *)copy_string(a, path).text; + defer (gb_free(a, copy)); + + struct stat s; + if (stat(copy, &s) == 0) { + return (s.st_mode & S_IFDIR) != 0; + } + return false; + } +#endif + + +String path_to_full_path(gbAllocator a, String path) { + gbAllocator ha = heap_allocator(); + char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); + defer (gb_free(ha, path_c)); + + char *fullpath = gb_path_get_full_name(a, path_c); + String res = string_trim_whitespace(make_string_c(fullpath)); +#if defined(GB_SYSTEM_WINDOWS) + for (isize i = 0; i < res.len; i++) { + if (res.text[i] == '\\') { + res.text[i] = '/'; + } + } +#endif + return res; +} + + + +struct FileInfo { + String name; + String fullpath; + i64 size; + bool is_dir; +}; + +enum ReadDirectoryError { + ReadDirectory_None, + + ReadDirectory_InvalidPath, + ReadDirectory_NotExists, + ReadDirectory_Permission, + ReadDirectory_NotDir, + ReadDirectory_Empty, + ReadDirectory_Unknown, + + ReadDirectory_COUNT, +}; + +i64 get_file_size(String path) { + char *c_str = alloc_cstring(heap_allocator(), path); + defer (gb_free(heap_allocator(), c_str)); + + gbFile f = {}; + gbFileError err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + if (err != gbFileError_None) { + return -1; + } + return gb_file_size(&f); +} + + +#if defined(GB_SYSTEM_WINDOWS) +ReadDirectoryError read_directory(String path, Array *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + while (path.len > 0) { + Rune end = path[path.len-1]; + if (end == '/') { + path.len -= 1; + } else if (end == '\\') { + path.len -= 1; + } else { + break; + } + } + + if (path.len == 0) { + return ReadDirectory_InvalidPath; + } + { + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + case gbFileError_Invalid: return ReadDirectory_InvalidPath; + case gbFileError_NotExists: return ReadDirectory_NotExists; + // case gbFileError_Permission: return ReadDirectory_Permission; + } + } + + if (!path_is_directory(path)) { + return ReadDirectory_NotDir; + } + + + char *new_path = gb_alloc_array(a, char, path.len+3); + defer (gb_free(a, new_path)); + + gb_memmove(new_path, path.text, path.len); + gb_memmove(new_path+path.len, "/*", 2); + new_path[path.len+2] = 0; + + String np = make_string(cast(u8 *)new_path, path.len+2); + String16 wstr = string_to_string16(a, np); + defer (gb_free(a, wstr.text)); + + WIN32_FIND_DATAW file_data = {}; + HANDLE find_file = FindFirstFileW(wstr.text, &file_data); + if (find_file == INVALID_HANDLE_VALUE) { + return ReadDirectory_Unknown; + } + defer (FindClose(find_file)); + + array_init(fi, a, 0, 100); + + do { + wchar_t *filename_w = file_data.cFileName; + i64 size = cast(i64)file_data.nFileSizeLow; + size |= (cast(i64)file_data.nFileSizeHigh) << 32; + String name = string16_to_string(a, make_string16_c(filename_w)); + if (name == "." || name == "..") { + gb_free(a, name.text); + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + array_add(fi, info); + } while (FindNextFileW(find_file, &file_data)); + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) + +#include + +ReadDirectoryError read_directory(String path, Array *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + char *c_path = alloc_cstring(a, path); + defer (gb_free(a, c_path)); + + DIR *dir = opendir(c_path); + if (!dir) { + switch (errno) { + case ENOENT: + return ReadDirectory_NotExists; + case EACCES: + return ReadDirectory_Permission; + case ENOTDIR: + return ReadDirectory_NotDir; + default: + // ENOMEM: out of memory + // EMFILE: per-process limit on open fds reached + // ENFILE: system-wide limit on total open files reached + return ReadDirectory_Unknown; + } + GB_PANIC("unreachable"); + } + + array_init(fi, a, 0, 100); + + for (;;) { + struct dirent *entry = readdir(dir); + if (entry == nullptr) { + break; + } + + String name = make_string_c(entry->d_name); + if (name == "." || name == "..") { + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + filepath.text[filepath.len] = 0; + + + struct stat dir_stat = {}; + + if (stat((char *)filepath.text, &dir_stat)) { + continue; + } + + if (S_ISDIR(dir_stat.st_mode)) { + continue; + } + + i64 size = dir_stat.st_size; + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + array_add(fi, info); + } + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#else +#error Implement read_directory +#endif + + struct LoadedFile { void *handle; diff --git a/src/gb/gb.h b/src/gb/gb.h index 3b2d6434c..b72a893f7 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -6273,44 +6273,20 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) { #else char *p, *result, *fullpath = NULL; isize len; - fullpath = realpath(path, NULL); - - if (fullpath == NULL) { - // NOTE(Jeroen): Path doesn't exist. - if (gb_strlen(path) > 0 && path[0] == '/') { - // But it is an absolute path, so return as-is. - - fullpath = (char *)path; - len = gb_strlen(fullpath) + 1; - result = gb_alloc_array(a, char, len + 1); - - gb_memmove(result, fullpath, len); - result[len] = 0; - - } else { - // Appears to be a relative path, so construct an absolute one relative to . - char cwd[4096]; - getcwd(&cwd[0], 4096); - - isize path_len = gb_strlen(path); - isize cwd_len = gb_strlen(cwd); - len = cwd_len + 1 + path_len + 1; - result = gb_alloc_array(a, char, len); - - gb_memmove(result, (void *)cwd, cwd_len); - result[cwd_len] = '/'; - - gb_memmove(result + cwd_len + 1, (void *)path, gb_strlen(path)); - result[len] = 0; - - } - } else { - len = gb_strlen(fullpath) + 1; - result = gb_alloc_array(a, char, len + 1); - gb_memmove(result, fullpath, len); - result[len] = 0; - free(fullpath); + p = realpath(path, NULL); + fullpath = p; + if (p == NULL) { + // NOTE(bill): File does not exist + fullpath = cast(char *)path; } + + len = gb_strlen(fullpath); + + result = gb_alloc_array(a, char, len + 1); + gb_memmove(result, fullpath, len); + result[len] = 0; + free(p); + return result; #endif } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7781997f7..f5cb84785 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -967,12 +967,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) } String lb_filepath_ll_for_module(lbModule *m) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); - + String path = m->gen->output_base; if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } else if (USE_SEPARATE_MODULES) { @@ -983,12 +978,7 @@ String lb_filepath_ll_for_module(lbModule *m) { return path; } String lb_filepath_obj_for_module(lbModule *m) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); - + String path = m->gen->output_base; if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 1a431a4ac..330059622 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -87,6 +87,7 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { return false; } + String init_fullpath = c->parser->init_fullpath; if (build_context.out_filepath.len == 0) { diff --git a/src/main.cpp b/src/main.cpp index 7b0364149..fc8792ceb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,6 +46,7 @@ gb_global Timings global_timings = {0}; #include "checker.cpp" #include "docs.cpp" + #include "llvm_backend.cpp" #if defined(GB_SYSTEM_OSX) @@ -56,8 +57,16 @@ gb_global Timings global_timings = {0}; #endif #include "query_data.cpp" + + +#if defined(GB_SYSTEM_WINDOWS) +// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. +#include "microsoft_craziness.h" +#endif + #include "bug_report.cpp" + // NOTE(bill): 'name' is used in debugging and profiling modes i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { isize const cmd_cap = 64<<20; // 64 MiB should be more than enough @@ -121,35 +130,34 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { } + + i32 linker_stage(lbGenerator *gen) { i32 result = 0; Timings *timings = &global_timings; - String output_filename = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); - debugf("Linking %.*s\n", LIT(output_filename)); - - // TOOD(Jeroen): Make a `build_paths[BuildPath_Object] to avoid `%.*s.o`. + String output_base = gen->output_base; if (is_arch_wasm()) { timings_start_section(timings, str_lit("wasm-ld")); #if defined(GB_SYSTEM_WINDOWS) result = system_exec_command_line_app("wasm-ld", - "\"%.*s\\bin\\wasm-ld\" \"%.*s.o\" -o \"%.*s\" %.*s %.*s", + "\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", LIT(build_context.ODIN_ROOT), - LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else result = system_exec_command_line_app("wasm-ld", - "wasm-ld \"%.*s.o\" -o \"%.*s\" %.*s %.*s", - LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + "wasm-ld \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #endif return result; } if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { -#if defined(GB_SYSTEM_UNIX) +#ifdef GB_SYSTEM_UNIX result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", - LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", LIT(target_os_names[build_context.metrics.os]), @@ -173,11 +181,28 @@ i32 linker_stage(lbGenerator *gen) { gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); + char const *output_ext = "exe"; gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); defer (gb_string_free(link_settings)); + + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + exit(1); + } + + if (build_context.ignore_microsoft_magic) { + find_result = {}; + } + // Add library search paths. - if (build_context.build_paths[BuildPath_VS_LIB].basename.len > 0) { + if (find_result.vs_library_path.len > 0) { + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + String path = {}; auto add_path = [&](String path) { if (path[path.len-1] == '\\') { @@ -185,9 +210,9 @@ i32 linker_stage(lbGenerator *gen) { } link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); }; - add_path(build_context.build_paths[BuildPath_Win_SDK_UM_Lib].basename); - add_path(build_context.build_paths[BuildPath_Win_SDK_UCRT_Lib].basename); - add_path(build_context.build_paths[BuildPath_VS_LIB].basename); + add_path(find_result.windows_sdk_um_library_path); + add_path(find_result.windows_sdk_ucrt_library_path); + add_path(find_result.vs_library_path); } @@ -227,14 +252,14 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.build_mode == BuildMode_DynamicLibrary) { + output_ext = "dll"; link_settings = gb_string_append_fmt(link_settings, " /DLL"); } else { link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); } if (build_context.pdb_filepath != "") { - String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]); - link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(pdb_path)); + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); } if (build_context.no_crt) { @@ -275,21 +300,13 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } - String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]); - defer (gb_free(heap_allocator(), vs_exe_path.text)); - char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; if (!build_context.use_lld) { // msvc if (build_context.has_resource) { - String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]); - String res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]); - defer (gb_free(heap_allocator(), rc_path.text)); - defer (gb_free(heap_allocator(), res_path.text)); - result = system_exec_command_line_app("msvc-link", - "\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"", - LIT(res_path), - LIT(rc_path) + "\"rc.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", + LIT(output_base), + LIT(build_context.resource_filepath) ); if (result) { @@ -297,13 +314,13 @@ i32 linker_stage(lbGenerator *gen) { } result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s \"%.*s\" -OUT:\"%.*s\" %s " + "\"%.*slink.exe\" %s \"%.*s.res\" -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename), + LIT(find_result.vs_exe_path), object_files, LIT(output_base), LIT(output_base), output_ext, link_settings, subsystem_str, LIT(build_context.link_flags), @@ -312,13 +329,13 @@ i32 linker_stage(lbGenerator *gen) { ); } else { result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s -OUT:\"%.*s\" %s " + "\"%.*slink.exe\" %s -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(vs_exe_path), object_files, LIT(output_filename), + LIT(find_result.vs_exe_path), object_files, LIT(output_base), output_ext, link_settings, subsystem_str, LIT(build_context.link_flags), @@ -333,13 +350,13 @@ i32 linker_stage(lbGenerator *gen) { } else { // lld result = system_exec_command_line_app("msvc-lld-link", - "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s " + "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename), + LIT(build_context.ODIN_ROOT), object_files, LIT(output_base),output_ext, link_settings, subsystem_str, LIT(build_context.link_flags), @@ -398,7 +415,7 @@ i32 linker_stage(lbGenerator *gen) { } else if (string_ends_with(lib, str_lit(".so"))) { // dynamic lib, relative path to executable // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtime to the executable + // at runtimeto the executable lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths @@ -414,6 +431,9 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } + // Unlike the Win32 linker code, the output_ext includes the dot, because + // typically executable files on *NIX systems don't have extensions. + String output_ext = {}; gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); if (build_context.no_crt) { @@ -441,12 +461,26 @@ i32 linker_stage(lbGenerator *gen) { // correctly this way since all the other dependencies provided implicitly // by the compiler frontend are still needed and most of the command // line arguments prepared previously are incompatible with ld. + // + // Shared libraries are .dylib on MacOS and .so on Linux. + if (build_context.metrics.os == TargetOs_darwin) { + output_ext = STR_LIT(".dylib"); + } else { + output_ext = STR_LIT(".so"); + } link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } else if (build_context.metrics.os != TargetOs_openbsd) { // OpenBSD defaults to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } + if (build_context.out_filepath.len > 0) { + //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that + isize pos = string_extension_position(build_context.out_filepath); + if (pos > 0) { + output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); + } + } gbString platform_lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(platform_lib_str)); @@ -473,7 +507,7 @@ i32 linker_stage(lbGenerator *gen) { defer (gb_string_free(link_command_line)); link_command_line = gb_string_appendc(link_command_line, object_files); - link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); + link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s%.*s\" ", LIT(output_base), LIT(output_ext)); link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags)); @@ -490,7 +524,9 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe // to the symbols in the object file - result = system_exec_command_line_app("dsymutil", "dsymutil %.*s", LIT(output_filename)); + result = system_exec_command_line_app("dsymutil", + "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) + ); if (result) { return result; @@ -1490,10 +1526,6 @@ bool parse_build_flags(Array args) { gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path)); bad_flags = true; break; - } else if (!gb_file_exists((const char *)path.text)) { - gb_printf_err("Invalid -resource path %.*s, file does not exist.\n", LIT(path)); - bad_flags = true; - break; } build_context.resource_filepath = substring(path, 0, string_extension_position(path)); build_context.has_resource = true; @@ -1508,11 +1540,6 @@ bool parse_build_flags(Array args) { String path = value.value_string; path = string_trim_whitespace(path); if (is_build_flag_path_valid(path)) { - if (path_is_directory(path)) { - gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path)); - bad_flags = true; - break; - } // #if defined(GB_SYSTEM_WINDOWS) // String ext = path_extension(path); // if (ext != ".pdb") { @@ -2639,8 +2666,6 @@ int main(int arg_count, char const **arg_ptr) { return 1; } - init_filename = copy_string(permanent_allocator(), init_filename); - if (init_filename == "-help" || init_filename == "--help") { build_context.show_help = true; @@ -2663,12 +2688,6 @@ int main(int arg_count, char const **arg_ptr) { gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename)); gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n"); return 1; - } else { - String const ext = str_lit(".odin"); - if (!string_ends_with(init_filename, ext)) { - gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); - return 1; - } } } } @@ -2690,24 +2709,13 @@ int main(int arg_count, char const **arg_ptr) { get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared"))); } + init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr); // if (build_context.word_size == 4 && build_context.metrics.os != TargetOs_js) { // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0])); // return 1; // } - // Set and check build paths... - if (!init_build_paths(init_filename)) { - return 1; - } - - if (build_context.show_debug_messages) { - for_array(i, build_context.build_paths) { - String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); - debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); - } - } - init_global_thread_pool(); defer (thread_pool_destroy(&global_thread_pool)); @@ -2724,8 +2732,6 @@ int main(int arg_count, char const **arg_ptr) { } defer (destroy_parser(parser)); - // TODO(jeroen): Remove the `init_filename` param. - // Let's put that on `build_context.build_paths[0]` instead. if (parse_packages(parser, init_filename) != ParseFile_None) { return 1; } @@ -2804,14 +2810,16 @@ int main(int arg_count, char const **arg_ptr) { } if (run_output) { - String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); - defer (gb_free(heap_allocator(), exe_name.text)); - #if defined(GB_SYSTEM_WINDOWS) - return system_exec_command_line_app("odin run", "%.*s %.*s", LIT(exe_name), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(gen->output_base), LIT(run_args_string)); #else - return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); + //NOTE(thebirk): This whole thing is a little leaky + String output_ext = {}; + String complete_path = concatenate_strings(permanent_allocator(), gen->output_base, output_ext); + complete_path = path_to_full_path(permanent_allocator(), complete_path); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); #endif } + return 0; } diff --git a/src/parser.cpp b/src/parser.cpp index df7f908a6..767119aa8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5751,7 +5751,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } } } - + { // Add these packages serially and then process them parallel mutex_lock(&p->wait_mutex); diff --git a/src/path.cpp b/src/path.cpp deleted file mode 100644 index 8d8e532b8..000000000 --- a/src/path.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* - Path handling utilities. -*/ - -#if defined(GB_SYSTEM_WINDOWS) - bool path_is_directory(String path) { - gbAllocator a = heap_allocator(); - String16 wstr = string_to_string16(a, path); - defer (gb_free(a, wstr.text)); - - i32 attribs = GetFileAttributesW(wstr.text); - if (attribs < 0) return false; - - return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; - } - -#else - bool path_is_directory(String path) { - gbAllocator a = heap_allocator(); - char *copy = cast(char *)copy_string(a, path).text; - defer (gb_free(a, copy)); - - struct stat s; - if (stat(copy, &s) == 0) { - return (s.st_mode & S_IFDIR) != 0; - } - return false; - } -#endif - - -String path_to_full_path(gbAllocator a, String path) { - gbAllocator ha = heap_allocator(); - char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); - defer (gb_free(ha, path_c)); - - char *fullpath = gb_path_get_full_name(a, path_c); - String res = string_trim_whitespace(make_string_c(fullpath)); -#if defined(GB_SYSTEM_WINDOWS) - for (isize i = 0; i < res.len; i++) { - if (res.text[i] == '\\') { - res.text[i] = '/'; - } - } -#endif - return copy_string(a, res); -} - -struct Path { - String basename; - String name; - String ext; -}; - -// NOTE(Jeroen): Naively turns a Path into a string. -String path_to_string(gbAllocator a, Path path) { - if (path.basename.len + path.name.len + path.ext.len == 0) { - return make_string(nullptr, 0); - } - - isize len = path.basename.len + 1 + path.name.len + 1; - if (path.ext.len > 0) { - len += path.ext.len + 1; - } - - u8 *str = gb_alloc_array(a, u8, len); - - isize i = 0; - gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len; - gb_memmove(str+i, "/", 1); i += 1; - gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len; - if (path.ext.len > 0) { - gb_memmove(str+i, ".", 1); i += 1; - gb_memmove(str+i, path.ext.text, path.ext.len); i += path.ext.len; - } - str[i] = 0; - - String res = make_string(str, i); - res = string_trim_whitespace(res); - return res; -} - -// NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`. -String path_to_full_path(gbAllocator a, Path path) { - String temp = path_to_string(heap_allocator(), path); - defer (gb_free(heap_allocator(), temp.text)); - - return path_to_full_path(a, temp); -} - -// NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path, -// and then breaks it into its components to make a Path. -Path path_from_string(gbAllocator a, String const &path) { - Path res = {}; - - if (path.len == 0) return res; - - String fullpath = path_to_full_path(a, path); - defer (gb_free(heap_allocator(), fullpath.text)); - - res.basename = directory_from_path(fullpath); - res.basename = copy_string(a, res.basename); - - if (string_ends_with(fullpath, '/')) { - // It's a directory. We don't need to tinker with the name and extension. - return res; - } - - isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len; - res.name = substring(fullpath, name_start, fullpath.len); - res.name = remove_extension_from_path(res.name); - res.name = copy_string(a, res.name); - - res.ext = path_extension(fullpath, false); // false says not to include the dot. - res.ext = copy_string(a, res.ext); - return res; -} - -bool path_is_directory(Path path) { - String path_string = path_to_full_path(heap_allocator(), path); - defer (gb_free(heap_allocator(), path_string.text)); - - return path_is_directory(path_string); -} - -struct FileInfo { - String name; - String fullpath; - i64 size; - bool is_dir; -}; - -enum ReadDirectoryError { - ReadDirectory_None, - - ReadDirectory_InvalidPath, - ReadDirectory_NotExists, - ReadDirectory_Permission, - ReadDirectory_NotDir, - ReadDirectory_Empty, - ReadDirectory_Unknown, - - ReadDirectory_COUNT, -}; - -i64 get_file_size(String path) { - char *c_str = alloc_cstring(heap_allocator(), path); - defer (gb_free(heap_allocator(), c_str)); - - gbFile f = {}; - gbFileError err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - if (err != gbFileError_None) { - return -1; - } - return gb_file_size(&f); -} - - -#if defined(GB_SYSTEM_WINDOWS) -ReadDirectoryError read_directory(String path, Array *fi) { - GB_ASSERT(fi != nullptr); - - gbAllocator a = heap_allocator(); - - while (path.len > 0) { - Rune end = path[path.len-1]; - if (end == '/') { - path.len -= 1; - } else if (end == '\\') { - path.len -= 1; - } else { - break; - } - } - - if (path.len == 0) { - return ReadDirectory_InvalidPath; - } - { - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - case gbFileError_Invalid: return ReadDirectory_InvalidPath; - case gbFileError_NotExists: return ReadDirectory_NotExists; - // case gbFileError_Permission: return ReadDirectory_Permission; - } - } - - if (!path_is_directory(path)) { - return ReadDirectory_NotDir; - } - - - char *new_path = gb_alloc_array(a, char, path.len+3); - defer (gb_free(a, new_path)); - - gb_memmove(new_path, path.text, path.len); - gb_memmove(new_path+path.len, "/*", 2); - new_path[path.len+2] = 0; - - String np = make_string(cast(u8 *)new_path, path.len+2); - String16 wstr = string_to_string16(a, np); - defer (gb_free(a, wstr.text)); - - WIN32_FIND_DATAW file_data = {}; - HANDLE find_file = FindFirstFileW(wstr.text, &file_data); - if (find_file == INVALID_HANDLE_VALUE) { - return ReadDirectory_Unknown; - } - defer (FindClose(find_file)); - - array_init(fi, a, 0, 100); - - do { - wchar_t *filename_w = file_data.cFileName; - i64 size = cast(i64)file_data.nFileSizeLow; - size |= (cast(i64)file_data.nFileSizeHigh) << 32; - String name = string16_to_string(a, make_string16_c(filename_w)); - if (name == "." || name == "..") { - gb_free(a, name.text); - continue; - } - - String filepath = {}; - filepath.len = path.len+1+name.len; - filepath.text = gb_alloc_array(a, u8, filepath.len+1); - defer (gb_free(a, filepath.text)); - gb_memmove(filepath.text, path.text, path.len); - gb_memmove(filepath.text+path.len, "/", 1); - gb_memmove(filepath.text+path.len+1, name.text, name.len); - - FileInfo info = {}; - info.name = name; - info.fullpath = path_to_full_path(a, filepath); - info.size = size; - info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - array_add(fi, info); - } while (FindNextFileW(find_file, &file_data)); - - if (fi->count == 0) { - return ReadDirectory_Empty; - } - - return ReadDirectory_None; -} -#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) - -#include - -ReadDirectoryError read_directory(String path, Array *fi) { - GB_ASSERT(fi != nullptr); - - gbAllocator a = heap_allocator(); - - char *c_path = alloc_cstring(a, path); - defer (gb_free(a, c_path)); - - DIR *dir = opendir(c_path); - if (!dir) { - switch (errno) { - case ENOENT: - return ReadDirectory_NotExists; - case EACCES: - return ReadDirectory_Permission; - case ENOTDIR: - return ReadDirectory_NotDir; - default: - // ENOMEM: out of memory - // EMFILE: per-process limit on open fds reached - // ENFILE: system-wide limit on total open files reached - return ReadDirectory_Unknown; - } - GB_PANIC("unreachable"); - } - - array_init(fi, a, 0, 100); - - for (;;) { - struct dirent *entry = readdir(dir); - if (entry == nullptr) { - break; - } - - String name = make_string_c(entry->d_name); - if (name == "." || name == "..") { - continue; - } - - String filepath = {}; - filepath.len = path.len+1+name.len; - filepath.text = gb_alloc_array(a, u8, filepath.len+1); - defer (gb_free(a, filepath.text)); - gb_memmove(filepath.text, path.text, path.len); - gb_memmove(filepath.text+path.len, "/", 1); - gb_memmove(filepath.text+path.len+1, name.text, name.len); - filepath.text[filepath.len] = 0; - - - struct stat dir_stat = {}; - - if (stat((char *)filepath.text, &dir_stat)) { - continue; - } - - if (S_ISDIR(dir_stat.st_mode)) { - continue; - } - - i64 size = dir_stat.st_size; - - FileInfo info = {}; - info.name = name; - info.fullpath = path_to_full_path(a, filepath); - info.size = size; - array_add(fi, info); - } - - if (fi->count == 0) { - return ReadDirectory_Empty; - } - - return ReadDirectory_None; -} -#else -#error Implement read_directory -#endif - diff --git a/src/string.cpp b/src/string.cpp index 3515df48e..d3dbc6904 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -245,14 +245,15 @@ gb_inline isize string_extension_position(String const &str) { return dot_pos; } -String path_extension(String const &str, bool include_dot = true) { +String path_extension(String const &str) { isize pos = string_extension_position(str); if (pos < 0) { return make_string(nullptr, 0); } - return substring(str, include_dot ? pos : pos + 1, str.len); + return substring(str, pos, str.len); } + String string_trim_whitespace(String str) { while (str.len > 0 && rune_is_whitespace(str[str.len-1])) { str.len--; @@ -327,10 +328,7 @@ String directory_from_path(String const &s) { break; } } - if (i >= 0) { - return substring(s, 0, i); - } - return substring(s, 0, 0); + return substring(s, 0, i); } String concatenate_strings(gbAllocator a, String const &x, String const &y) { diff --git a/tests/core/Makefile b/tests/core/Makefile index 9bb622633..6a92b4efb 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,6 +1,5 @@ ODIN=../../odin PYTHON=$(shell which python3) -OUT_FILE=test_binary.bin all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test @@ -9,39 +8,39 @@ download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image/test_core_image.odin -out=$(OUT_FILE) -file + $(ODIN) run image/test_core_image.odin -file compress_test: - $(ODIN) run compress/test_core_compress.odin -out=$(OUT_FILE) -file + $(ODIN) run compress/test_core_compress.odin -file strings_test: - $(ODIN) run strings/test_core_strings.odin -out=$(OUT_FILE) -file + $(ODIN) run strings/test_core_strings.odin -file hash_test: - $(ODIN) run hash -out=$(OUT_FILE) -o:speed -no-bounds-check + $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check crypto_test: - $(ODIN) run crypto -out=$(OUT_FILE) -o:speed -no-bounds-check + $(ODIN) run crypto -out=test_crypto_hash -o:speed -no-bounds-check noise_test: - $(ODIN) run math/noise -out=$(OUT_FILE) + $(ODIN) run math/noise -out=test_noise encoding_test: - $(ODIN) run encoding/hxa -out=$(OUT_FILE) -collection:tests=.. - $(ODIN) run encoding/json -out=$(OUT_FILE) - $(ODIN) run encoding/varint -out=$(OUT_FILE) + $(ODIN) run encoding/hxa -out=test_hxa -collection:tests=.. + $(ODIN) run encoding/json -out=test_json + $(ODIN) run encoding/varint -out=test_varint math_test: - $(ODIN) run math/test_core_math.odin -out=$(OUT_FILE) -file -collection:tests=.. + $(ODIN) run math/test_core_math.odin -out=test_core_math -file -collection:tests=.. linalg_glsl_math_test: - $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=$(OUT_FILE) -collection:tests=.. + $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=test_linalg_glsl_math -collection:tests=.. filepath_test: - $(ODIN) run path/filepath/test_core_filepath.odin -file -out=$(OUT_FILE) -collection:tests=.. + $(ODIN) run path/filepath/test_core_filepath.odin -file -out=test_core_filepath -collection:tests=.. reflect_test: - $(ODIN) run reflect/test_core_reflect.odin -file -out=$(OUT_FILE) -collection:tests=.. + $(ODIN) run reflect/test_core_reflect.odin -file -out=test_core_reflect -collection:tests=.. os_exit_test: - $(ODIN) run os/test_core_os_exit.odin -file -out=$(OUT_FILE) && exit 1 || exit 0 + $(ODIN) run os/test_core_os_exit.odin -file -out=test_core_os_exit && exit 1 || exit 0 diff --git a/tests/core/build.bat b/tests/core/build.bat index 331a473aa..2f9ba672e 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,8 +1,6 @@ @echo off -set OUT_FILE=test_binary.exe -set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. -out:%OUT_FILE% +set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. set PATH_TO_ODIN==..\..\odin - python3 download_assets.py echo --- echo Running core:image tests @@ -37,14 +35,14 @@ echo --- echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding/hxa %COMMON% -%PATH_TO_ODIN% run encoding/json %COMMON% +%PATH_TO_ODIN% run encoding/hxa %COMMON% +%PATH_TO_ODIN% run encoding/json %COMMON% %PATH_TO_ODIN% run encoding/varint %COMMON% echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% +%PATH_TO_ODIN% run math/noise %COMMON% echo --- echo Running core:math tests diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index ad199d775..16bdbc8ca 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -4,7 +4,7 @@ set PATH_TO_ODIN==..\..\..\..\odin set TEST_ARGS=-fast-tests set TEST_ARGS=-no-random set TEST_ARGS= -set OUT_NAME=math_big_test_library.dll +set OUT_NAME=math_big_test_library set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style echo --- echo Running core:math/big tests diff --git a/tests/issues/run.bat b/tests/issues/run.bat index a936bd896..a652d9694 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -1,12 +1,17 @@ @echo off -set PATH_TO_ODIN==..\..\odin -set COMMON=-collection:tests=.. -out:build\test_issue -if not exist "build" mkdir build -%PATH_TO_ODIN% build test_issue_829.odin %COMMON% -file -build\test_issue +if not exist "tests\issues\build\" mkdir tests\issues\build -%PATH_TO_ODIN% build test_issue_1592.odin %COMMON% -file -build\test_issue +set COMMON=-collection:tests=tests -out:tests\issues\build\test_issue -rmdir /S /Q build +@echo on + +.\odin build tests\issues\test_issue_829.odin %COMMON% -file +tests\issues\build\test_issue + +.\odin build tests\issues\test_issue_1592.odin %COMMON% -file +tests\issues\build\test_issue + +@echo off + +rmdir /S /Q tests\issues\build diff --git a/tests/issues/run.sh b/tests/issues/run.sh index ec6d7130d..117a9a5f1 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -1,17 +1,18 @@ #!/bin/bash -ODIN=../../odin -COMMON="-collection:tests=.. -out:build/test_issue.bin" - set -eu -mkdir -p build + +mkdir -p tests/issues/build + +COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" + set -x -$ODIN build test_issue_829.odin $COMMON -file -build/test_issue.bin +./odin build tests/issues/test_issue_829.odin $COMMON -file +tests/issues/build/test_issue -$ODIN build test_issue_1592.odin $COMMON -file -build/test_issue.bin +./odin build tests/issues/test_issue_1592.odin $COMMON -file +tests/issues/build/test_issue set +x -rm -rf build +rm -rf tests/issues/build diff --git a/tests/vendor/Makefile b/tests/vendor/Makefile index 380e64e09..341067c6e 100644 --- a/tests/vendor/Makefile +++ b/tests/vendor/Makefile @@ -1,6 +1,5 @@ ODIN=../../odin ODINFLAGS= -OUT_FILE=test_binary.bin OS=$(shell uname) @@ -11,4 +10,4 @@ endif all: botan_test botan_test: - $(ODIN) run botan -out=$(OUT_FILE) -o:speed -no-bounds-check $(ODINFLAGS) + $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS) diff --git a/tests/vendor/build.bat b/tests/vendor/build.bat index 4bd9a6496..e70d9f1d5 100644 --- a/tests/vendor/build.bat +++ b/tests/vendor/build.bat @@ -1,6 +1,5 @@ @echo off -set OUT_FILE=test_binary.exe -set COMMON=-show-timings -no-bounds-check -vet -strict-style -out:%OUT_FILE% +set COMMON=-show-timings -no-bounds-check -vet -strict-style set PATH_TO_ODIN==..\..\odin echo --- From e01662c13959469c9c0bc4974a3b7c03d577d7a4 Mon Sep 17 00:00:00 2001 From: Florian Behr Date: Mon, 25 Apr 2022 13:23:05 +0200 Subject: [PATCH 0578/1052] Make allocator in pool_add_task() explicit --- core/thread/thread_pool.odin | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 3f782cf73..fe289d8aa 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -113,9 +113,8 @@ pool_join :: proc(pool: ^Pool) { // the thread pool. You can even add tasks from inside other tasks. // // Each task also needs an allocator which it either owns, or which is thread -// safe. By default, allocations in the task are disabled by use of the -// nil_allocator. -pool_add_task :: proc(pool: ^Pool, procedure: Task_Proc, data: rawptr, user_index: int = 0, allocator := context.allocator) { +// safe. +pool_add_task :: proc(pool: ^Pool, procedure: Task_Proc, data: rawptr, user_index: int = 0, allocator: mem.Allocator) { sync.guard(&pool.mutex) append(&pool.tasks, Task{ From 1fb76ad7687bc9efe538b79ac05dc0fafad06950 Mon Sep 17 00:00:00 2001 From: Florian Behr Date: Mon, 25 Apr 2022 13:41:19 +0200 Subject: [PATCH 0579/1052] change usage in demo.odin --- examples/demo/demo.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index b03345849..a36acdf18 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1166,7 +1166,8 @@ threading_example :: proc() { for i in 0..<30 { - thread.pool_add_task(pool=&pool, procedure=task_proc, data=nil, user_index=i) + // be mindful of the allocator used for tasks. The allocator needs to be thread safe, or be owned by the task for exclusive use + thread.pool_add_task(pool=&pool, procedure=task_proc, data=nil, user_index=i, allocator=context.allocator) } thread.pool_start(&pool) From ca6a1db7576dd72f5a5b4b73fec8cbad34e5bced Mon Sep 17 00:00:00 2001 From: Florian Behr Date: Mon, 25 Apr 2022 13:41:39 +0200 Subject: [PATCH 0580/1052] fix doc comment for pool_init --- core/thread/thread_pool.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index fe289d8aa..4fc02309e 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -44,7 +44,7 @@ Pool :: struct { } // Once initialized, the pool's memory address is not allowed to change until -// it is destroyed. If thread_count < 1, thread count 1 will be used. +// it is destroyed. // // The thread pool requires an allocator which it either owns, or which is thread safe. pool_init :: proc(pool: ^Pool, thread_count: int, allocator: mem.Allocator) { From ee67a0b9a1d83acad3e8ade9314bdad3bb0d2197 Mon Sep 17 00:00:00 2001 From: Florian Behr Date: Mon, 25 Apr 2022 14:08:09 +0200 Subject: [PATCH 0581/1052] reorder procedure parameters to make sure the optional argument in pool_add_task() is last, and the argument order is consistent with pool_init() --- core/thread/thread_pool.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 4fc02309e..af80da9aa 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -47,7 +47,7 @@ Pool :: struct { // it is destroyed. // // The thread pool requires an allocator which it either owns, or which is thread safe. -pool_init :: proc(pool: ^Pool, thread_count: int, allocator: mem.Allocator) { +pool_init :: proc(pool: ^Pool, allocator: mem.Allocator, thread_count: int) { context.allocator = allocator pool.allocator = allocator pool.tasks = make([dynamic]Task) @@ -114,7 +114,7 @@ pool_join :: proc(pool: ^Pool) { // // Each task also needs an allocator which it either owns, or which is thread // safe. -pool_add_task :: proc(pool: ^Pool, procedure: Task_Proc, data: rawptr, user_index: int = 0, allocator: mem.Allocator) { +pool_add_task :: proc(pool: ^Pool, allocator: mem.Allocator, procedure: Task_Proc, data: rawptr, user_index: int = 0) { sync.guard(&pool.mutex) append(&pool.tasks, Task{ From a412d34574649cceacea6a171ccd4af6119c7a0f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 11:35:34 +0100 Subject: [PATCH 0582/1052] Fix #1740 --- core/mem/virtual/virtual.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 2035171a7..21ab5ef21 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -120,7 +120,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) do_commit_if_necessary :: proc(block: ^Memory_Block, size: uint) -> (err: Allocator_Error) { if block.committed - block.used < size { pmblock := (^Platform_Memory_Block)(block) - base_offset := uint(uintptr(block) - uintptr(pmblock)) + base_offset := uint(uintptr(pmblock.block.base) - uintptr(pmblock)) platform_total_commit := base_offset + block.used + size assert(pmblock.committed <= pmblock.reserved) From 530401e5ee84bd3346b6a3213814a904696019df Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 11:38:32 +0100 Subject: [PATCH 0583/1052] Fix #1729 --- src/check_type.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 51f472961..c0ae64baa 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1338,14 +1338,14 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type * } } } - } else if (allow_caller_location && o.mode == Addressing_Context) { + } else if (allow_caller_location && (o.mode == Addressing_Context || are_types_identical(o.type, t_source_code_location))) { param_value.kind = ParameterValue_Value; param_value.ast_value = expr; } else if (o.value.kind != ExactValue_Invalid) { param_value.kind = ParameterValue_Constant; param_value.value = o.value; } else { - error(expr, "Default parameter must be a constant, %d", o.mode); + error(expr, "Default parameter must be a constant"); } } } else { From 3bd71229596427d43551ff6612d71505bb79c796 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 11:42:01 +0100 Subject: [PATCH 0584/1052] Fix #1720 --- vendor/vulkan/_gen/create_vulkan_odin_wrapper.py | 3 +++ vendor/vulkan/core.odin | 3 +++ 2 files changed, 6 insertions(+) diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index ae1bc8d64..9a32f5796 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -626,6 +626,9 @@ with open("../core.odin", 'w', encoding='utf-8') as f: f.write(BASE) f.write(""" API_VERSION_1_0 :: (1<<22) | (0<<12) | (0) +API_VERSION_1_1 :: (1<<22) | (1<<12) | (0) +API_VERSION_1_2 :: (1<<22) | (2<<12) | (0) +API_VERSION_1_3 :: (1<<22) | (3<<12) | (0) MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 { return (major<<22) | (minor<<12) | (patch) diff --git a/vendor/vulkan/core.odin b/vendor/vulkan/core.odin index 94c667910..b90bfad17 100644 --- a/vendor/vulkan/core.odin +++ b/vendor/vulkan/core.odin @@ -3,6 +3,9 @@ // package vulkan API_VERSION_1_0 :: (1<<22) | (0<<12) | (0) +API_VERSION_1_1 :: (1<<22) | (1<<12) | (0) +API_VERSION_1_2 :: (1<<22) | (2<<12) | (0) +API_VERSION_1_3 :: (1<<22) | (3<<12) | (0) MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 { return (major<<22) | (minor<<12) | (patch) From c81fd2e5dd82fba0d5a1eb6771b1816cdb4ba574 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 11:45:46 +0100 Subject: [PATCH 0585/1052] Fix #1644 --- core/math/linalg/specific.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/math/linalg/specific.odin b/core/math/linalg/specific.odin index cb007bd91..a4aaeb012 100644 --- a/core/math/linalg/specific.odin +++ b/core/math/linalg/specific.odin @@ -479,21 +479,21 @@ angle_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 { return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2 } - return math.cos(q.x) * 2 + return math.acos(q.w) * 2 } angle_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 { if abs(q.w) > math.SQRT_THREE*0.5 { return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2 } - return math.cos(q.x) * 2 + return math.acos(q.w) * 2 } angle_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 { if abs(q.w) > math.SQRT_THREE*0.5 { return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2 } - return math.cos(q.x) * 2 + return math.acos(q.w) * 2 } angle_from_quaternion :: proc{ angle_from_quaternion_f16, From a5342a01267f55dec5a5b9f775cec8c8379139b1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 26 Apr 2022 13:14:09 +0200 Subject: [PATCH 0586/1052] Address edge cases. --- .github/workflows/ci.yml | 11 ++---- .gitignore | 1 - Makefile | 4 +-- build_odin.sh | 4 +-- core/crypto/util/util.odin | 1 - src/build_settings.cpp | 42 ++++++++++++++++++---- src/path.cpp | 67 +++++++++++++++++++++++++++++++++-- src/string.cpp | 35 ------------------ tests/core/Makefile | 29 ++++++++------- tests/core/build.bat | 10 +++--- tests/core/math/big/build.bat | 2 +- tests/issues/run.bat | 21 ++++++----- tests/issues/run.sh | 19 +++++----- tests/vendor/Makefile | 3 +- tests/vendor/build.bat | 3 +- 15 files changed, 150 insertions(+), 102 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d72775636..3cc4283b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,9 +39,7 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: | - cd tests/issues - ./run.sh + run: tests/issues/run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -93,9 +91,7 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: | - cd tests/issues - ./run.sh + run: tests/issues/run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 @@ -167,8 +163,7 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - cd tests\issues - call run.bat + call tests\issues\run.bat timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd diff --git a/.gitignore b/.gitignore index d03a86fd7..e8b3d3050 100644 --- a/.gitignore +++ b/.gitignore @@ -269,7 +269,6 @@ bin/ # - Linux/MacOS odin odin.dSYM -*.bin # shared collection shared/ diff --git a/Makefile b/Makefile index 1a1c93180..82150c6a2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -all: debug +all: debug demo demo: - ./odin run examples/demo + ./odin run examples/demo/demo.odin report: ./odin report diff --git a/build_odin.sh b/build_odin.sh index 4810cafd2..aef3f2836 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -102,7 +102,7 @@ build_odin() { } run_demo() { - ./odin run examples/demo + ./odin run examples/demo/demo.odin -file } case $OS in @@ -147,4 +147,4 @@ if [[ $# -eq 1 ]]; then exit 0 else panic "Too many arguments!" -fi \ No newline at end of file +fi diff --git a/core/crypto/util/util.odin b/core/crypto/util/util.odin index 83b07e546..6273a232e 100644 --- a/core/crypto/util/util.odin +++ b/core/crypto/util/util.odin @@ -11,7 +11,6 @@ package util */ import "core:mem" -_ :: mem // @note(bp): this can replace the other two cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D { diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 212ded5c8..89d370144 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1276,16 +1276,44 @@ bool init_build_paths(String init_filename) { if (bc->out_filepath.len > 0) { bc->build_paths[BuildPath_Output] = path_from_string(ha, bc->out_filepath); + if (build_context.metrics.os == TargetOs_windows) { + String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); + defer (gb_free(ha, output_file.text)); + if (path_is_directory(bc->build_paths[BuildPath_Output])) { + gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file)); + return false; + } else if (bc->build_paths[BuildPath_Output].ext.len == 0) { + gb_printf_err("Output path %.*s must have an appropriate extension.\n", LIT(output_file)); + return false; + } + } } else { - String output_name = remove_directory_from_path(init_filename); - output_name = remove_extension_from_path(output_name); - output_name = copy_string(ha, string_trim_whitespace(output_name)); + Path output_path; - Path output_path = path_from_string(ha, output_name); + if (str_eq(init_filename, str_lit("."))) { + // We must name the output file after the current directory. + debugf("Output name will be created from current base name %.*s.\n", LIT(bc->build_paths[BuildPath_Main_Package].basename)); + String last_element = last_path_element(bc->build_paths[BuildPath_Main_Package].basename); - // Replace extension. - if (output_path.ext.len > 0) { - gb_free(ha, output_path.ext.text); + if (last_element.len == 0) { + gb_printf_err("The output name is created from the last path element. `%.*s` has none. Use `-out:output_name.ext` to set it.\n", LIT(bc->build_paths[BuildPath_Main_Package].basename)); + return false; + } + output_path.basename = copy_string(ha, bc->build_paths[BuildPath_Main_Package].basename); + output_path.name = copy_string(ha, last_element); + + } else { + // Init filename was not 'current path'. + // Contruct the output name from the path elements as usual. + String output_name = remove_directory_from_path(init_filename); + output_name = remove_extension_from_path(output_name); + output_name = copy_string(ha, string_trim_whitespace(output_name)); + output_path = path_from_string(ha, output_name); + + // Replace extension. + if (output_path.ext.len > 0) { + gb_free(ha, output_path.ext.text); + } } output_path.ext = copy_string(ha, output_extension); diff --git a/src/path.cpp b/src/path.cpp index 8d8e532b8..6f83c39ea 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -1,6 +1,46 @@ /* Path handling utilities. */ +String remove_extension_from_path(String const &s) { + for (isize i = s.len-1; i >= 0; i--) { + if (s[i] == '.') { + return substring(s, 0, i); + } + } + return s; +} + +String remove_directory_from_path(String const &s) { + isize len = 0; + for (isize i = s.len-1; i >= 0; i--) { + if (s[i] == '/' || + s[i] == '\\') { + break; + } + len += 1; + } + return substring(s, s.len-len, s.len); +} + +bool path_is_directory(String path); + +String directory_from_path(String const &s) { + if (path_is_directory(s)) { + return s; + } + + isize i = s.len-1; + for (; i >= 0; i--) { + if (s[i] == '/' || + s[i] == '\\') { + break; + } + } + if (i >= 0) { + return substring(s, 0, i); + } + return substring(s, 0, 0); +} #if defined(GB_SYSTEM_WINDOWS) bool path_is_directory(String path) { @@ -98,11 +138,15 @@ Path path_from_string(gbAllocator a, String const &path) { String fullpath = path_to_full_path(a, path); defer (gb_free(heap_allocator(), fullpath.text)); - res.basename = directory_from_path(fullpath); - res.basename = copy_string(a, res.basename); + res.basename = directory_from_path(fullpath); + res.basename = copy_string(a, res.basename); - if (string_ends_with(fullpath, '/')) { + if (path_is_directory(fullpath)) { // It's a directory. We don't need to tinker with the name and extension. + // It could have a superfluous trailing `/`. Remove it if so. + if (res.basename.len > 0 && res.basename.text[res.basename.len - 1] == '/') { + res.basename.len--; + } return res; } @@ -116,6 +160,23 @@ Path path_from_string(gbAllocator a, String const &path) { return res; } +// NOTE(Jeroen): Takes a path String and returns the last path element. +String last_path_element(String const &path) { + isize count = 0; + u8 * start = (u8 *)(&path.text[path.len - 1]); + for (isize length = path.len; length > 0 && path.text[length - 1] != '/'; length--) { + count++; + start--; + } + if (count > 0) { + start++; // Advance past the `/` and return the substring. + String res = make_string(start, count); + return res; + } + // Must be a root path like `/` or `C:/`, return empty String. + return STR_LIT(""); +} + bool path_is_directory(Path path) { String path_string = path_to_full_path(heap_allocator(), path); defer (gb_free(heap_allocator(), path_string.text)); diff --git a/src/string.cpp b/src/string.cpp index 3515df48e..616761265 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -298,41 +298,6 @@ String filename_from_path(String s) { return make_string(nullptr, 0); } -String remove_extension_from_path(String const &s) { - for (isize i = s.len-1; i >= 0; i--) { - if (s[i] == '.') { - return substring(s, 0, i); - } - } - return s; -} - -String remove_directory_from_path(String const &s) { - isize len = 0; - for (isize i = s.len-1; i >= 0; i--) { - if (s[i] == '/' || - s[i] == '\\') { - break; - } - len += 1; - } - return substring(s, s.len-len, s.len); -} - -String directory_from_path(String const &s) { - isize i = s.len-1; - for (; i >= 0; i--) { - if (s[i] == '/' || - s[i] == '\\') { - break; - } - } - if (i >= 0) { - return substring(s, 0, i); - } - return substring(s, 0, 0); -} - String concatenate_strings(gbAllocator a, String const &x, String const &y) { isize len = x.len+y.len; u8 *data = gb_alloc_array(a, u8, len+1); diff --git a/tests/core/Makefile b/tests/core/Makefile index 9bb622633..6a92b4efb 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,6 +1,5 @@ ODIN=../../odin PYTHON=$(shell which python3) -OUT_FILE=test_binary.bin all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test @@ -9,39 +8,39 @@ download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image/test_core_image.odin -out=$(OUT_FILE) -file + $(ODIN) run image/test_core_image.odin -file compress_test: - $(ODIN) run compress/test_core_compress.odin -out=$(OUT_FILE) -file + $(ODIN) run compress/test_core_compress.odin -file strings_test: - $(ODIN) run strings/test_core_strings.odin -out=$(OUT_FILE) -file + $(ODIN) run strings/test_core_strings.odin -file hash_test: - $(ODIN) run hash -out=$(OUT_FILE) -o:speed -no-bounds-check + $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check crypto_test: - $(ODIN) run crypto -out=$(OUT_FILE) -o:speed -no-bounds-check + $(ODIN) run crypto -out=test_crypto_hash -o:speed -no-bounds-check noise_test: - $(ODIN) run math/noise -out=$(OUT_FILE) + $(ODIN) run math/noise -out=test_noise encoding_test: - $(ODIN) run encoding/hxa -out=$(OUT_FILE) -collection:tests=.. - $(ODIN) run encoding/json -out=$(OUT_FILE) - $(ODIN) run encoding/varint -out=$(OUT_FILE) + $(ODIN) run encoding/hxa -out=test_hxa -collection:tests=.. + $(ODIN) run encoding/json -out=test_json + $(ODIN) run encoding/varint -out=test_varint math_test: - $(ODIN) run math/test_core_math.odin -out=$(OUT_FILE) -file -collection:tests=.. + $(ODIN) run math/test_core_math.odin -out=test_core_math -file -collection:tests=.. linalg_glsl_math_test: - $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=$(OUT_FILE) -collection:tests=.. + $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=test_linalg_glsl_math -collection:tests=.. filepath_test: - $(ODIN) run path/filepath/test_core_filepath.odin -file -out=$(OUT_FILE) -collection:tests=.. + $(ODIN) run path/filepath/test_core_filepath.odin -file -out=test_core_filepath -collection:tests=.. reflect_test: - $(ODIN) run reflect/test_core_reflect.odin -file -out=$(OUT_FILE) -collection:tests=.. + $(ODIN) run reflect/test_core_reflect.odin -file -out=test_core_reflect -collection:tests=.. os_exit_test: - $(ODIN) run os/test_core_os_exit.odin -file -out=$(OUT_FILE) && exit 1 || exit 0 + $(ODIN) run os/test_core_os_exit.odin -file -out=test_core_os_exit && exit 1 || exit 0 diff --git a/tests/core/build.bat b/tests/core/build.bat index 331a473aa..2f9ba672e 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,8 +1,6 @@ @echo off -set OUT_FILE=test_binary.exe -set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. -out:%OUT_FILE% +set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. set PATH_TO_ODIN==..\..\odin - python3 download_assets.py echo --- echo Running core:image tests @@ -37,14 +35,14 @@ echo --- echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding/hxa %COMMON% -%PATH_TO_ODIN% run encoding/json %COMMON% +%PATH_TO_ODIN% run encoding/hxa %COMMON% +%PATH_TO_ODIN% run encoding/json %COMMON% %PATH_TO_ODIN% run encoding/varint %COMMON% echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% +%PATH_TO_ODIN% run math/noise %COMMON% echo --- echo Running core:math tests diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index ad199d775..16bdbc8ca 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -4,7 +4,7 @@ set PATH_TO_ODIN==..\..\..\..\odin set TEST_ARGS=-fast-tests set TEST_ARGS=-no-random set TEST_ARGS= -set OUT_NAME=math_big_test_library.dll +set OUT_NAME=math_big_test_library set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style echo --- echo Running core:math/big tests diff --git a/tests/issues/run.bat b/tests/issues/run.bat index a936bd896..a652d9694 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -1,12 +1,17 @@ @echo off -set PATH_TO_ODIN==..\..\odin -set COMMON=-collection:tests=.. -out:build\test_issue -if not exist "build" mkdir build -%PATH_TO_ODIN% build test_issue_829.odin %COMMON% -file -build\test_issue +if not exist "tests\issues\build\" mkdir tests\issues\build -%PATH_TO_ODIN% build test_issue_1592.odin %COMMON% -file -build\test_issue +set COMMON=-collection:tests=tests -out:tests\issues\build\test_issue -rmdir /S /Q build +@echo on + +.\odin build tests\issues\test_issue_829.odin %COMMON% -file +tests\issues\build\test_issue + +.\odin build tests\issues\test_issue_1592.odin %COMMON% -file +tests\issues\build\test_issue + +@echo off + +rmdir /S /Q tests\issues\build diff --git a/tests/issues/run.sh b/tests/issues/run.sh index ec6d7130d..117a9a5f1 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -1,17 +1,18 @@ #!/bin/bash -ODIN=../../odin -COMMON="-collection:tests=.. -out:build/test_issue.bin" - set -eu -mkdir -p build + +mkdir -p tests/issues/build + +COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" + set -x -$ODIN build test_issue_829.odin $COMMON -file -build/test_issue.bin +./odin build tests/issues/test_issue_829.odin $COMMON -file +tests/issues/build/test_issue -$ODIN build test_issue_1592.odin $COMMON -file -build/test_issue.bin +./odin build tests/issues/test_issue_1592.odin $COMMON -file +tests/issues/build/test_issue set +x -rm -rf build +rm -rf tests/issues/build diff --git a/tests/vendor/Makefile b/tests/vendor/Makefile index 380e64e09..341067c6e 100644 --- a/tests/vendor/Makefile +++ b/tests/vendor/Makefile @@ -1,6 +1,5 @@ ODIN=../../odin ODINFLAGS= -OUT_FILE=test_binary.bin OS=$(shell uname) @@ -11,4 +10,4 @@ endif all: botan_test botan_test: - $(ODIN) run botan -out=$(OUT_FILE) -o:speed -no-bounds-check $(ODINFLAGS) + $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS) diff --git a/tests/vendor/build.bat b/tests/vendor/build.bat index 4bd9a6496..e70d9f1d5 100644 --- a/tests/vendor/build.bat +++ b/tests/vendor/build.bat @@ -1,6 +1,5 @@ @echo off -set OUT_FILE=test_binary.exe -set COMMON=-show-timings -no-bounds-check -vet -strict-style -out:%OUT_FILE% +set COMMON=-show-timings -no-bounds-check -vet -strict-style set PATH_TO_ODIN==..\..\odin echo --- From ec8221cb5def171deb5bea0cf4d6a935e74e33d2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 13:04:50 +0100 Subject: [PATCH 0587/1052] Simplify Atomic_Cond implementation --- core/sync/atomic.odin | 4 +- core/sync/primitives_atomic.odin | 109 +++++-------------------------- 2 files changed, 19 insertions(+), 94 deletions(-) diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index f537764c4..0900a6544 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -6,8 +6,8 @@ cpu_relax :: intrinsics.cpu_relax /* Atomic_Memory_Order :: enum { - Relaxed = 0, - Consume = 1, + Relaxed = 0, // Unordered + Consume = 1, // Monotonic Acquire = 2, Release = 3, Acq_Rel = 4, diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index 11fff4e60..bd32eb192 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -281,118 +281,43 @@ atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool { - -@(private="file") -Queue_Item :: struct { - next: ^Queue_Item, - futex: Futex, -} - -@(private="file") -queue_item_wait :: proc(item: ^Queue_Item) { - for atomic_load_explicit(&item.futex, .Acquire) == 0 { - futex_wait(&item.futex, 0) - cpu_relax() - } -} -@(private="file") -queue_item_wait_with_timeout :: proc(item: ^Queue_Item, duration: time.Duration) -> bool { - start := time.tick_now() - for atomic_load_explicit(&item.futex, .Acquire) == 0 { - remaining := duration - time.tick_since(start) - if remaining < 0 { - return false - } - if !futex_wait_with_timeout(&item.futex, 0, remaining) { - return false - } - cpu_relax() - } - return true -} -@(private="file") -queue_item_signal :: proc(item: ^Queue_Item) { - atomic_store_explicit(&item.futex, 1, .Release) - futex_signal(&item.futex) -} - - // Atomic_Cond implements a condition variable, a rendezvous point for threads // waiting for signalling the occurence of an event // // An Atomic_Cond must not be copied after first use Atomic_Cond :: struct { - queue_mutex: Atomic_Mutex, - queue_head: ^Queue_Item, - pending: bool, + state: Futex, + prev: u32, } atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) { - waiter := &Queue_Item{} + state := u32(atomic_load(&c.state)) + atomic_store(&c.prev, state) + unlock(m) + futex_wait(&c.state, state) + lock(m) - atomic_mutex_lock(&c.queue_mutex) - waiter.next = c.queue_head - c.queue_head = waiter - - atomic_store(&c.pending, true) - atomic_mutex_unlock(&c.queue_mutex) - - atomic_mutex_unlock(m) - queue_item_wait(waiter) - atomic_mutex_lock(m) } atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) { - waiter := &Queue_Item{} - - atomic_mutex_lock(&c.queue_mutex) - waiter.next = c.queue_head - c.queue_head = waiter - - atomic_store(&c.pending, true) - atomic_mutex_unlock(&c.queue_mutex) - - atomic_mutex_unlock(m) - ok = queue_item_wait_with_timeout(waiter, duration) - atomic_mutex_lock(m) + state := u32(atomic_load(&c.state)) + unlock(m) + ok = futex_wait_with_timeout(&c.state, state, duration) + lock(m) return } atomic_cond_signal :: proc(c: ^Atomic_Cond) { - if !atomic_load(&c.pending) { - return - } - - atomic_mutex_lock(&c.queue_mutex) - waiter := c.queue_head - if c.queue_head != nil { - c.queue_head = c.queue_head.next - } - atomic_store(&c.pending, c.queue_head != nil) - atomic_mutex_unlock(&c.queue_mutex) - - if waiter != nil { - queue_item_signal(waiter) - } + state := 1 + atomic_load(&c.prev) + atomic_store(&c.state, Futex(state)) + futex_signal(&c.state) } atomic_cond_broadcast :: proc(c: ^Atomic_Cond) { - if !atomic_load(&c.pending) { - return - } - - atomic_store(&c.pending, false) - - atomic_mutex_lock(&c.queue_mutex) - waiters := c.queue_head - c.queue_head = nil - atomic_mutex_unlock(&c.queue_mutex) - - for waiters != nil { - queue_item_signal(waiters) - waiters = waiters.next - } + state := 1 + atomic_load(&c.prev) + atomic_store(&c.state, Futex(state)) + futex_broadcast(&c.state) } // When waited upon, blocks until the internal count is greater than zero, then subtracts one. From 07d1a42768cd7082622fafc2bd01216e27bed54e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 13:11:34 +0100 Subject: [PATCH 0588/1052] Simplify `Atomic_Sema` implementation --- core/sync/primitives_atomic.odin | 65 +++++++++++++++----------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index bd32eb192..812e5ae97 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -325,30 +325,28 @@ atomic_cond_broadcast :: proc(c: ^Atomic_Cond) { // // An Atomic_Sema must not be copied after first use Atomic_Sema :: struct { - mutex: Atomic_Mutex, - cond: Atomic_Cond, - count: int, + count: Futex, } atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) { - atomic_mutex_lock(&s.mutex) - defer atomic_mutex_unlock(&s.mutex) - - s.count += count - atomic_cond_signal(&s.cond) + atomic_add_explicit(&s.count, Futex(count), .Release) + if count == 1 { + futex_signal(&s.count) + } else { + futex_broadcast(&s.count) + } } atomic_sema_wait :: proc(s: ^Atomic_Sema) { - atomic_mutex_lock(&s.mutex) - defer atomic_mutex_unlock(&s.mutex) - - for s.count == 0 { - atomic_cond_wait(&s.cond, &s.mutex) - } - - s.count -= 1 - if s.count > 0 { - atomic_cond_signal(&s.cond) + for { + original_count := atomic_load_explicit(&s.count, .Relaxed) + for original_count == 0 { + futex_wait(&s.count, u32(original_count)) + original_count = s.count + } + if original_count == atomic_compare_exchange_strong_explicit(&s.count, original_count, original_count-1, .Acquire, .Acquire) { + return + } } } @@ -356,25 +354,22 @@ atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) if duration <= 0 { return false } - atomic_mutex_lock(&s.mutex) - defer atomic_mutex_unlock(&s.mutex) - - start := time.tick_now() + for { - for s.count == 0 { - remaining := duration - time.tick_since(start) - if remaining < 0 { - return false + original_count := atomic_load_explicit(&s.count, .Relaxed) + for start := time.tick_now(); original_count == 0; /**/ { + remaining := duration - time.tick_since(start) + if remaining < 0 { + return false + } + + if !futex_wait_with_timeout(&s.count, u32(original_count), remaining) { + return false + } + original_count = s.count } - - if !atomic_cond_wait_with_timeout(&s.cond, &s.mutex, remaining) { - return false + if original_count == atomic_compare_exchange_strong_explicit(&s.count, original_count, original_count-1, .Acquire, .Acquire) { + return true } } - - s.count -= 1 - if s.count > 0 { - atomic_cond_signal(&s.cond) - } - return true } From 5e11ad2e1e6d0e335f47197c63a5ffdd8f405dd7 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 26 Apr 2022 14:23:23 +0200 Subject: [PATCH 0589/1052] Update test paths. --- .github/workflows/ci.yml | 11 ++++++++--- core/crypto/util/util.odin | 1 + tests/core/Makefile | 28 ++++++++++++++-------------- tests/core/build.bat | 28 ++++++++++++++-------------- tests/issues/run.bat | 14 +++++++------- tests/issues/run.sh | 16 ++++++++-------- tests/vendor/Makefile | 2 +- tests/vendor/build.bat | 4 ++-- 8 files changed, 55 insertions(+), 49 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3cc4283b0..d72775636 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,9 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: tests/issues/run.sh + run: | + cd tests/issues + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -91,7 +93,9 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: tests/issues/run.sh + run: | + cd tests/issues + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 @@ -163,7 +167,8 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - call tests\issues\run.bat + cd tests\issues + call run.bat timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd diff --git a/core/crypto/util/util.odin b/core/crypto/util/util.odin index 6273a232e..83b07e546 100644 --- a/core/crypto/util/util.odin +++ b/core/crypto/util/util.odin @@ -11,6 +11,7 @@ package util */ import "core:mem" +_ :: mem // @note(bp): this can replace the other two cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D { diff --git a/tests/core/Makefile b/tests/core/Makefile index 6a92b4efb..2c24fef75 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -8,39 +8,39 @@ download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image/test_core_image.odin -file + $(ODIN) run image/test_core_image.odin -file -out:test_core_image compress_test: - $(ODIN) run compress/test_core_compress.odin -file + $(ODIN) run compress/test_core_compress.odin -file -out:test_core_compress strings_test: - $(ODIN) run strings/test_core_strings.odin -file + $(ODIN) run strings/test_core_strings.odin -file -out:test_core_strings hash_test: - $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check + $(ODIN) run hash -o:speed -no-bounds-check -out:test_hash crypto_test: - $(ODIN) run crypto -out=test_crypto_hash -o:speed -no-bounds-check + $(ODIN) run crypto -o:speed -no-bounds-check -out:test_crypto_hash noise_test: - $(ODIN) run math/noise -out=test_noise + $(ODIN) run math/noise -out:test_noise encoding_test: - $(ODIN) run encoding/hxa -out=test_hxa -collection:tests=.. - $(ODIN) run encoding/json -out=test_json - $(ODIN) run encoding/varint -out=test_varint + $(ODIN) run encoding/hxa -collection:tests=.. -out:test_hxa + $(ODIN) run encoding/json -out:test_json + $(ODIN) run encoding/varint -out:test_varint math_test: - $(ODIN) run math/test_core_math.odin -out=test_core_math -file -collection:tests=.. + $(ODIN) run math/test_core_math.odin -file -collection:tests=.. -out:test_core_math linalg_glsl_math_test: - $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -out=test_linalg_glsl_math -collection:tests=.. + $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -file -collection:tests=.. -out:test_linalg_glsl_math filepath_test: - $(ODIN) run path/filepath/test_core_filepath.odin -file -out=test_core_filepath -collection:tests=.. + $(ODIN) run path/filepath/test_core_filepath.odin -file -collection:tests=.. -out:test_core_filepath reflect_test: - $(ODIN) run reflect/test_core_reflect.odin -file -out=test_core_reflect -collection:tests=.. + $(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect os_exit_test: - $(ODIN) run os/test_core_os_exit.odin -file -out=test_core_os_exit && exit 1 || exit 0 + $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index 2f9ba672e..b03fef4bb 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -5,61 +5,61 @@ python3 download_assets.py echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% run image %COMMON% +%PATH_TO_ODIN% run image %COMMON% -out:test_core_image.exe echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% run compress %COMMON% +%PATH_TO_ODIN% run compress %COMMON% -out:test_core_compress.exe echo --- echo Running core:strings tests echo --- -%PATH_TO_ODIN% run strings %COMMON% +%PATH_TO_ODIN% run strings %COMMON% -out:test_core_strings.exe echo --- echo Running core:hash tests echo --- -%PATH_TO_ODIN% run hash %COMMON% -o:size +%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_core_hash.exe echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size +%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_core_odin.exe echo --- echo Running core:crypto hash tests echo --- -%PATH_TO_ODIN% run crypto %COMMON% +%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto_hash.exe echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding/hxa %COMMON% -%PATH_TO_ODIN% run encoding/json %COMMON% -%PATH_TO_ODIN% run encoding/varint %COMMON% +%PATH_TO_ODIN% run encoding/hxa %COMMON% -out:test_hxa.exe +%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe +%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% +%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise.exe echo --- echo Running core:math tests echo --- -%PATH_TO_ODIN% run math %COMMON% +%PATH_TO_ODIN% run math %COMMON% -out:test_core_math.exe echo --- echo Running core:math/linalg/glsl tests echo --- -%PATH_TO_ODIN% run math/linalg/glsl %COMMON% +%PATH_TO_ODIN% run math/linalg/glsl %COMMON% -out:test_linalg_glsl.exe echo --- echo Running core:path/filepath tests echo --- -%PATH_TO_ODIN% run path/filepath %COMMON% +%PATH_TO_ODIN% run path/filepath %COMMON% -out:test_core_filepath.exe echo --- echo Running core:reflect tests echo --- -%PATH_TO_ODIN% run reflect %COMMON% +%PATH_TO_ODIN% run reflect %COMMON% -out:test_core_reflect.exe \ No newline at end of file diff --git a/tests/issues/run.bat b/tests/issues/run.bat index a652d9694..a7078ae0f 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -1,17 +1,17 @@ @echo off -if not exist "tests\issues\build\" mkdir tests\issues\build +if not exist "build\" mkdir build -set COMMON=-collection:tests=tests -out:tests\issues\build\test_issue +set COMMON=-collection:tests=.. -out:build\test_issue.exe @echo on -.\odin build tests\issues\test_issue_829.odin %COMMON% -file -tests\issues\build\test_issue +..\..\odin build test_issue_829.odin %COMMON% -file +build\test_issue -.\odin build tests\issues\test_issue_1592.odin %COMMON% -file -tests\issues\build\test_issue +..\..\odin build test_issue_1592.odin %COMMON% -file +build\test_issue @echo off -rmdir /S /Q tests\issues\build +rmdir /S /Q build diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 117a9a5f1..ec0804bac 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -1,18 +1,18 @@ #!/bin/bash set -eu -mkdir -p tests/issues/build - -COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" +mkdir -p build +ODIN=../../odin +COMMON="-collection:tests=.. -out:build/test_issue" set -x -./odin build tests/issues/test_issue_829.odin $COMMON -file -tests/issues/build/test_issue +$ODIN build test_issue_829.odin $COMMON -file +./build/test_issue -./odin build tests/issues/test_issue_1592.odin $COMMON -file -tests/issues/build/test_issue +$ODIN build test_issue_1592.odin $COMMON -file +./build/test_issue set +x -rm -rf tests/issues/build +rm -rf build diff --git a/tests/vendor/Makefile b/tests/vendor/Makefile index 341067c6e..6c68d7908 100644 --- a/tests/vendor/Makefile +++ b/tests/vendor/Makefile @@ -10,4 +10,4 @@ endif all: botan_test botan_test: - $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS) + $(ODIN) run botan -o:speed -no-bounds-check $(ODINFLAGS) -out=vendor_botan diff --git a/tests/vendor/build.bat b/tests/vendor/build.bat index e70d9f1d5..d92a5eaea 100644 --- a/tests/vendor/build.bat +++ b/tests/vendor/build.bat @@ -5,9 +5,9 @@ set PATH_TO_ODIN==..\..\odin echo --- echo Running vendor:botan tests echo --- -%PATH_TO_ODIN% run botan %COMMON% +%PATH_TO_ODIN% run botan %COMMON% -out:vendor_botan.exe echo --- echo Running vendor:glfw tests echo --- -%PATH_TO_ODIN% run glfw %COMMON% \ No newline at end of file +%PATH_TO_ODIN% run glfw %COMMON% -out:vendor_glfw.exe \ No newline at end of file From 9cf7a31068bb8f9bf63c6e7e8f350125334ea406 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 13:44:32 +0100 Subject: [PATCH 0590/1052] Implement `_Sema` with `Atomic_Sema` --- core/sync/sema_internal.odin | 42 ++++-------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/core/sync/sema_internal.odin b/core/sync/sema_internal.odin index e4a3c0bfc..8188abe28 100644 --- a/core/sync/sema_internal.odin +++ b/core/sync/sema_internal.odin @@ -6,53 +6,19 @@ import "core:time" when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { _Sema :: struct { - count: Futex, + sema: Atomic_Sema, } _sema_post :: proc(s: ^Sema, count := 1) { - atomic_add_explicit(&s.impl.count, Futex(count), .Release) - if count == 1 { - futex_signal(&s.impl.count) - } else { - futex_broadcast(&s.impl.count) - } + atomic_sema_post(&s.impl.sema, count) } _sema_wait :: proc(s: ^Sema) { - for { - original_count := atomic_load_explicit(&s.impl.count, .Relaxed) - for original_count == 0 { - futex_wait(&s.impl.count, u32(original_count)) - original_count = s.impl.count - } - if original_count == atomic_compare_exchange_strong_explicit(&s.impl.count, original_count, original_count-1, .Acquire, .Acquire) { - return - } - } + atomic_sema_wait(&s.impl.sema) } _sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { - if duration <= 0 { - return false - } - for { - - original_count := atomic_load_explicit(&s.impl.count, .Relaxed) - for start := time.tick_now(); original_count == 0; /**/ { - remaining := duration - time.tick_since(start) - if remaining < 0 { - return false - } - - if !futex_wait_with_timeout(&s.impl.count, u32(original_count), remaining) { - return false - } - original_count = s.impl.count - } - if original_count == atomic_compare_exchange_strong_explicit(&s.impl.count, original_count, original_count-1, .Acquire, .Acquire) { - return true - } - } + return atomic_sema_wait_with_timeout(&s.impl.sema, duration) } } else { _Sema :: struct { From ba5e33bc3518c327057102f56ac2c1cce55dc76f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 26 Apr 2022 14:51:16 +0200 Subject: [PATCH 0591/1052] Update CI workflow. --- .github/workflows/ci.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3cc4283b0..a5a6eddb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,9 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: tests/issues/run.sh + run: | + cd tests/issues + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -91,7 +93,8 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: tests/issues/run.sh + cd tests/issues + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 @@ -163,7 +166,8 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - call tests\issues\run.bat + cd tests\issues + call run.bat timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd From 1c03e6805775c58044d417eea2504312b4e916ab Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 26 Apr 2022 14:56:28 +0200 Subject: [PATCH 0592/1052] Update CI. --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5a6eddb1..d72775636 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,8 +40,8 @@ jobs: timeout-minutes: 10 - name: Odin issues tests run: | - cd tests/issues - ./run.sh + cd tests/issues + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -93,8 +93,9 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - cd tests/issues - ./run.sh + run: | + cd tests/issues + ./run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 From 40f0f5ad8dd56691ae42e9dd4b9a2f5e5395f3ee Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 26 Apr 2022 15:01:09 +0200 Subject: [PATCH 0593/1052] Update CI for math library. --- tests/core/math/big/build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index 16bdbc8ca..ad199d775 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -4,7 +4,7 @@ set PATH_TO_ODIN==..\..\..\..\odin set TEST_ARGS=-fast-tests set TEST_ARGS=-no-random set TEST_ARGS= -set OUT_NAME=math_big_test_library +set OUT_NAME=math_big_test_library.dll set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style echo --- echo Running core:math/big tests From d262eda91c527880a95f70a3d6fa20346c1d20d6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 26 Apr 2022 15:10:31 +0200 Subject: [PATCH 0594/1052] Update Makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 82150c6a2..91010a620 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -all: debug demo +all: debug demo: - ./odin run examples/demo/demo.odin + ./odin run examples/demo/demo.odin -file report: ./odin report From a6cef2e50ea4867f02bac5442debfa1de0743681 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Apr 2022 21:47:45 +0100 Subject: [PATCH 0595/1052] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 9ca94bcdf..9a87ab8da 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2021 Ginger Bill. All rights reserved. +Copyright (c) 2016-2022 Ginger Bill. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 5bc81642748af7c9f1eb6847a97639620e2d41c6 Mon Sep 17 00:00:00 2001 From: CiD- Date: Tue, 26 Apr 2022 17:11:30 -0400 Subject: [PATCH 0596/1052] add mremap + flags --- core/sys/unix/syscalls_linux.odin | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 8e0f7d89d..630b4ef24 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1524,18 +1524,26 @@ AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_FOLLOW :: uintptr(0x400) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) -PROT_NONE :: 0x0 -PROT_READ :: 0x1 -PROT_WRITE :: 0x2 -PROT_EXEC :: 0x4 +// mmap flags +PROT_NONE :: 0x0 +PROT_READ :: 0x1 +PROT_WRITE :: 0x2 +PROT_EXEC :: 0x4 PROT_GROWSDOWN :: 0x01000000 -PROT_GROWSUP :: 0x02000000 +PROT_GROWSUP :: 0x02000000 -MAP_FIXED :: 0x1 -MAP_PRIVATE :: 0x2 -MAP_SHARED :: 0x4 -MAP_ANONYMOUS :: 0x20 +MAP_FIXED :: 0x10 +MAP_SHARED :: 0x1 +MAP_PRIVATE :: 0x2 +MAP_SHARED_VALIDATE :: 0x3 +MAP_ANONYMOUS :: 0x20 +// mremap flags +MREMAP_MAYMOVE :: 1 +MREMAP_FIXED :: 2 +MREMAP_DONTUNMAP :: 4 + +// madvise flags MADV_NORMAL :: 0 MADV_RANDOM :: 1 MADV_SEQUENTIAL :: 2 @@ -1815,6 +1823,10 @@ sys_mmap :: proc "contextless" (addr: rawptr, length: uint, prot, flags, fd: int return int(intrinsics.syscall(SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset)) } +sys_mremap :: proc "contextless" (addr: rawptr, old_length, new_length: uint, flags: int, new_addr: rawptr = nil) -> int { + return int(intrinsics.syscall(SYS_mremap, uintptr(addr), uintptr(old_length), uintptr(new_length), uintptr(flags), uintptr(new_addr))) +} + sys_munmap :: proc "contextless" (addr: rawptr, length: uint) -> int { return int(intrinsics.syscall(SYS_munmap, uintptr(addr), uintptr(length))) } From 96924969895d78d93e8f39158a0409a6a2c214ab Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 12:27:53 +0100 Subject: [PATCH 0597/1052] Add `intrinsics.type_field_type` --- core/intrinsics/intrinsics.odin | 1 + src/check_builtin.cpp | 31 +++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 2 ++ 3 files changed, 34 insertions(+) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index a25e9783d..c132d4095 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -153,6 +153,7 @@ type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- +type_field_type :: proc($T: typeid, $name: string) -> typeid --- type_proc_parameter_count :: proc($T: typeid) -> int where type_is_proc(T) --- type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e055539c5..6c7972d45 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3926,6 +3926,37 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } break; + case BuiltinProc_type_field_type: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + Operand x = {}; + check_expr(c, &x, ce->args[1]); + + if (!is_type_string(x.type) || x.mode != Addressing_Constant || x.value.kind != ExactValue_String) { + error(ce->args[1], "Expected a const string for field argument"); + return false; + } + + String field_name = x.value.value_string; + + Selection sel = lookup_field(type, field_name, false); + if (sel.index.count == 0) { + gbString t = type_to_string(type); + error(ce->args[1], "'%.*s' is not a field of type %s", LIT(field_name), t); + gb_string_free(t); + return false; + } + operand->mode = Addressing_Type; + operand->type = sel.entity->type; + break; + } + break; case BuiltinProc_type_is_specialization_of: { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index fe14ae372..0f72f01f7 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -179,6 +179,7 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc__type_simple_boolean_end, BuiltinProc_type_has_field, + BuiltinProc_type_field_type, BuiltinProc_type_is_specialization_of, @@ -395,6 +396,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("type_has_field"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_field_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From 9349dfba8fec53f52f77a0c8928e115ec93ff447 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 12:39:45 +0100 Subject: [PATCH 0598/1052] Add new builtin `container_of` --- core/runtime/core_builtin.odin | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 67b1bd37b..13e464a76 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -5,6 +5,16 @@ import "core:intrinsics" @builtin Maybe :: union($T: typeid) #maybe {T} + +@builtin +container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: typeid, $field_name: string) -> ^T + where intrinsics.type_has_field(T, field_name), + intrinsics.type_field_type(T, field_name) == Field_Type { + offset :: offset_of_by_string(T, field_name) + return (^T)(uintptr(ptr) - offset) if ptr != nil else nil +} + + @thread_local global_default_temp_allocator_data: Default_Temp_Allocator @builtin From 3a9b0a22e728d1158efccb7f90e2c8aa05c486ef Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 14:27:33 +0100 Subject: [PATCH 0599/1052] Add `core:container/intrusive/list` --- .../intrusive/list/intrusive_list.odin | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 core/container/intrusive/list/intrusive_list.odin diff --git a/core/container/intrusive/list/intrusive_list.odin b/core/container/intrusive/list/intrusive_list.odin new file mode 100644 index 000000000..88e21edc5 --- /dev/null +++ b/core/container/intrusive/list/intrusive_list.odin @@ -0,0 +1,173 @@ +package container_intrusive_list + +import "core:intrinsics" + +// An intrusive doubly-linked list +// +// As this is an intrusive container, a `Node` must be embedded in your own +// structure which is conventionally called a "link". The use of `push_front` +// and `push_back` take the address of this node. Retrieving the data +// associated with the node requires finding the relative offset of the node +// of the parent structure. The parent type and field name are given to +// `iterator_*` procedures, or to the built-in `container_of` procedure. +// +// This data structure is two-pointers in size: +// 8 bytes on 32-bit platforms and 16 bytes on 64-bit platforms +List :: struct { + head: ^Node, + tail: ^Node, +} + + +Node :: struct { + next, prev: ^Node, +} + +push_front :: proc(list: ^List, node: ^Node) { + if list.head != nil { + list.head.prev = node + node.prev, node.next = nil, list.head + list.head = node + } else { + list.head, list.tail = node, node + node.prev, node.next = nil, nil + } +} + +push_back :: proc(list: ^List, node: ^Node) { + if list.tail != nil { + list.tail.next = node + node.prev, node.next = list.tail, nil + list.tail = node + } else { + list.head, list.tail = node, node + node.prev, node.next = nil, nil + } +} + +remove :: proc(list: ^List, node: ^Node) { + if node != nil { + if node.next != nil { + node.next.prev = node.prev + } + if node.prev != nil { + node.prev.next = node.next + } + if list.head == node { + list.head = node.next + } + if list.tail == node { + list.tail = node.prev + } + } +} + +remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) { + for node := list.head; node != nil; { + next := node.next + if to_erase(node) { + if node.next != nil { + node.next.prev = node.prev + } + if node.prev != nil { + node.prev.next = node.next + } + if list.head == node { + list.head = node.next + } + if list.tail == node { + list.tail = node.prev + } + } + node = next + } +} + + +is_empty :: proc(list: ^List) -> bool { + return list.head == nil +} + +pop_front :: proc(list: ^List) -> ^Node { + link := list.head + if link == nil { + return nil + } + if link.next != nil { + link.next.prev = link.prev + } + if link.prev != nil { + link.prev.next = link.next + } + if link == list.head { + list.head = link.next + } + if link == list.tail { + list.tail = link.prev + } + return link + +} +pop_back :: proc(list: ^List) -> ^Node { + link := list.tail + if link == nil { + return nil + } + if link.next != nil { + link.next.prev = link.prev + } + if link.prev != nil { + link.prev.next = link.next + } + if link == list.head { + list.head = link.next + } + if link == list.tail { + list.tail = link.prev + } + return link +} + + +Iterator :: struct($T: typeid) { + curr: ^Node, + offset: uintptr, +} + +iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T) + where intrinsics.type_has_field(T, field_name), + intrinsics.type_field_type(T, field_name) == Node { + return {list.head, offset_of_by_string(T, field_name)} +} + +iterator_tail :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T) + where intrinsics.type_has_field(T, field_name), + intrinsics.type_field_type(T, field_name) == Node { + return {list.tail, offset_of_by_string(T, field_name)} +} + +iterator_from_node :: proc(node: ^Node, $T: typeid, $field_name: string) -> Iterator(T) + where intrinsics.type_has_field(T, field_name), + intrinsics.type_field_type(T, field_name) == Node { + return {node, offset_of_by_string(T, field_name)} +} + +iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) { + node := it.curr + if node == nil { + return nil, false + } + it.curr = node.next + + return (^T)(uintptr(node) - it.offset), true +} + +iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) { + node := it.curr + if node == nil { + return nil, false + } + it.curr = node.prev + + return (^T)(uintptr(node) - it.offset), true +} \ No newline at end of file From fbbb0d7610d2ace168df2aec65d76f51f35ec6a8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 14:51:04 +0100 Subject: [PATCH 0600/1052] Update intrinsics.odin for documentation --- core/intrinsics/intrinsics.odin | 54 +++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index c132d4095..beb6f3f31 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -41,6 +41,10 @@ mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) --- mem_zero :: proc(ptr: rawptr, len: int) --- mem_zero_volatile :: proc(ptr: rawptr, len: int) --- +// prefer [^]T operations if possible +ptr_offset :: proc(ptr: ^$T, offset: int) -> ^T --- +ptr_sub :: proc(a, b: ^$T) -> int --- + unaligned_load :: proc(src: ^$T) -> T --- unaligned_store :: proc(dst: ^$T, val: T) -> T --- @@ -82,6 +86,7 @@ atomic_store_explicit :: proc(dst: ^$T, val: T, order: Atomic_Memory_Order) --- atomic_load :: proc(dst: ^$T) -> T --- atomic_load_explicit :: proc(dst: ^$T, order: Atomic_Memory_Order) -> T --- +// fetch then operator atomic_add :: proc(dst; ^$T, val: T) -> T --- atomic_add_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- atomic_sub :: proc(dst; ^$T, val: T) -> T --- @@ -119,19 +124,20 @@ type_is_string :: proc($T: typeid) -> bool --- type_is_typeid :: proc($T: typeid) -> bool --- type_is_any :: proc($T: typeid) -> bool --- -type_is_endian_platform :: proc($T: typeid) -> bool --- -type_is_endian_little :: proc($T: typeid) -> bool --- -type_is_endian_big :: proc($T: typeid) -> bool --- -type_is_unsigned :: proc($T: typeid) -> bool --- -type_is_numeric :: proc($T: typeid) -> bool --- -type_is_ordered :: proc($T: typeid) -> bool --- -type_is_ordered_numeric :: proc($T: typeid) -> bool --- -type_is_indexable :: proc($T: typeid) -> bool --- -type_is_sliceable :: proc($T: typeid) -> bool --- -type_is_comparable :: proc($T: typeid) -> bool --- -type_is_simple_compare :: proc($T: typeid) -> bool --- // easily compared using memcmp (== and !=) -type_is_dereferenceable :: proc($T: typeid) -> bool --- -type_is_valid_map_key :: proc($T: typeid) -> bool --- +type_is_endian_platform :: proc($T: typeid) -> bool --- +type_is_endian_little :: proc($T: typeid) -> bool --- +type_is_endian_big :: proc($T: typeid) -> bool --- +type_is_unsigned :: proc($T: typeid) -> bool --- +type_is_numeric :: proc($T: typeid) -> bool --- +type_is_ordered :: proc($T: typeid) -> bool --- +type_is_ordered_numeric :: proc($T: typeid) -> bool --- +type_is_indexable :: proc($T: typeid) -> bool --- +type_is_sliceable :: proc($T: typeid) -> bool --- +type_is_comparable :: proc($T: typeid) -> bool --- +type_is_simple_compare :: proc($T: typeid) -> bool --- // easily compared using memcmp (== and !=) +type_is_dereferenceable :: proc($T: typeid) -> bool --- +type_is_valid_map_key :: proc($T: typeid) -> bool --- +type_is_valid_matrix_elements :: proc($T: typeid) -> bool --- type_is_named :: proc($T: typeid) -> bool --- type_is_pointer :: proc($T: typeid) -> bool --- @@ -146,6 +152,7 @@ type_is_enum :: proc($T: typeid) -> bool --- type_is_proc :: proc($T: typeid) -> bool --- type_is_bit_set :: proc($T: typeid) -> bool --- type_is_simd_vector :: proc($T: typeid) -> bool --- +type_is_matrix :: proc($T: typeid) -> bool --- type_has_nil :: proc($T: typeid) -> bool --- @@ -161,20 +168,41 @@ type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) --- type_proc_parameter_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) --- type_proc_return_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) --- +type_struct_field_count :: proc($T: typeid) -> int where type_is_struct(T) --- + type_polymorphic_record_parameter_count :: proc($T: typeid) -> typeid --- type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V --- +type_is_specialized_polymorphic_record :: proc($T: typeid) -> bool --- +type_is_unspecialized_polymorphic_record :: proc($T: typeid) -> bool --- + +type_is_subtype_of :: proc($T, $U: typeid) -> bool --- type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) --- type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) --- +constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- // WASM targets only wasm_memory_grow :: proc(index, delta: uintptr) -> int --- wasm_memory_size :: proc(index: uintptr) -> int --- + +// Darwin targets only +objc_object :: struct{} +objc_selector :: struct{} +objc_class :: struct{} +objc_id :: ^objc_object +objc_SEL :: ^objc_selector +objc_Class :: ^objc_class + +objc_find_selector :: proc($name: string) -> objc_SEL --- +objc_register_selector :: proc($name: string) -> objc_SEL --- +objc_find_class :: proc($name: string) -> objc_Class --- +objc_register_class :: proc($name: string) -> objc_Class --- + // Internal compiler use only __entry_point :: proc() --- \ No newline at end of file From 904f0407f8e19a419dfe313181c2b47216121e11 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 14:53:26 +0100 Subject: [PATCH 0601/1052] Add `intrinsics.type_is_multi_pointer` --- src/check_builtin.cpp | 2 ++ src/checker_builtin_procs.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 6c7972d45..9a5d1c554 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -29,6 +29,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - is_type_named, is_type_pointer, + is_type_multi_pointer, is_type_array, is_type_enumerated_array, is_type_slice, @@ -3866,6 +3867,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_type_is_valid_matrix_elements: case BuiltinProc_type_is_named: case BuiltinProc_type_is_pointer: + case BuiltinProc_type_is_multi_pointer: case BuiltinProc_type_is_array: case BuiltinProc_type_is_enumerated_array: case BuiltinProc_type_is_slice: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 0f72f01f7..d301cae0c 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -158,6 +158,7 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_named, BuiltinProc_type_is_pointer, + BuiltinProc_type_is_multi_pointer, BuiltinProc_type_is_array, BuiltinProc_type_is_enumerated_array, BuiltinProc_type_is_slice, @@ -376,6 +377,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_named"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_multi_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_enumerated_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_slice"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From da0f722aad98afc94de09903a74802f43e6f5961 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 27 Apr 2022 15:56:45 +0200 Subject: [PATCH 0602/1052] Move Odin CI test assets over to its own repository. --- tests/core/download_assets.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/tests/core/download_assets.py b/tests/core/download_assets.py index d86f7f1e7..50137f563 100644 --- a/tests/core/download_assets.py +++ b/tests/core/download_assets.py @@ -5,8 +5,9 @@ import sys import os import zipfile +TEST_SUITES = ['PNG', 'XML'] DOWNLOAD_BASE_PATH = "assets/{}" -ASSETS_BASE_URL = "https://raw.githubusercontent.com/Kelimion/compress-odin/master/tests/assets/{}/{}" +ASSETS_BASE_URL = "https://raw.githubusercontent.com/odin-lang/test-assets/master/{}/{}" PNG_IMAGES = [ "basi0g01.png", "basi0g02.png", "basi0g04.png", "basi0g08.png", "basi0g16.png", "basi2c08.png", "basi2c16.png", "basi3p01.png", "basi3p02.png", "basi3p04.png", "basi3p08.png", "basi4a08.png", @@ -73,25 +74,27 @@ def try_download_and_unpack_zip(suite): print("Could not extract ZIP file") return 2 - def main(): - print("Downloading PNG assets") + for suite in TEST_SUITES: + print("Downloading {} assets".format(suite)) - # Make PNG assets path - try: - path = DOWNLOAD_BASE_PATH.format("PNG") - os.makedirs(path) - except FileExistsError: - pass + # Make assets path + try: + path = DOWNLOAD_BASE_PATH.format(suite) + os.makedirs(path) + except FileExistsError: + pass + + # Try downloading and unpacking the assets + r = try_download_and_unpack_zip(suite) + if r is not None: + return r + + # We could fall back on downloading the PNG files individually, but it's slow + print("Done downloading {} assets.".format(suite)) - # Try downloading and unpacking the PNG assets - r = try_download_and_unpack_zip("PNG") - if r is not None: - return r - # We could fall back on downloading the PNG files individually, but it's slow - print("Done downloading PNG assets") return 0 if __name__ == '__main__': From bd73b2845b2e7cadf38c441babeeb9765896b2be Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 15:03:48 +0100 Subject: [PATCH 0603/1052] Unify default `Sema` and `Atomic_Sema` behaviour --- core/sync/primitives_atomic.odin | 65 +++++++++++++++----------------- core/sync/sema_internal.odin | 42 ++------------------- 2 files changed, 34 insertions(+), 73 deletions(-) diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index 11fff4e60..22771443d 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -400,30 +400,28 @@ atomic_cond_broadcast :: proc(c: ^Atomic_Cond) { // // An Atomic_Sema must not be copied after first use Atomic_Sema :: struct { - mutex: Atomic_Mutex, - cond: Atomic_Cond, - count: int, + count: Futex, } atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) { - atomic_mutex_lock(&s.mutex) - defer atomic_mutex_unlock(&s.mutex) - - s.count += count - atomic_cond_signal(&s.cond) + atomic_add_explicit(&s.count, Futex(count), .Release) + if count == 1 { + futex_signal(&s.count) + } else { + futex_broadcast(&s.count) + } } atomic_sema_wait :: proc(s: ^Atomic_Sema) { - atomic_mutex_lock(&s.mutex) - defer atomic_mutex_unlock(&s.mutex) - - for s.count == 0 { - atomic_cond_wait(&s.cond, &s.mutex) - } - - s.count -= 1 - if s.count > 0 { - atomic_cond_signal(&s.cond) + for { + original_count := atomic_load_explicit(&s.count, .Relaxed) + for original_count == 0 { + futex_wait(&s.count, u32(original_count)) + original_count = s.count + } + if original_count == atomic_compare_exchange_strong_explicit(&s.count, original_count, original_count-1, .Acquire, .Acquire) { + return + } } } @@ -431,25 +429,22 @@ atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) if duration <= 0 { return false } - atomic_mutex_lock(&s.mutex) - defer atomic_mutex_unlock(&s.mutex) - - start := time.tick_now() + for { - for s.count == 0 { - remaining := duration - time.tick_since(start) - if remaining < 0 { - return false + original_count := atomic_load_explicit(&s.count, .Relaxed) + for start := time.tick_now(); original_count == 0; /**/ { + remaining := duration - time.tick_since(start) + if remaining < 0 { + return false + } + + if !futex_wait_with_timeout(&s.count, u32(original_count), remaining) { + return false + } + original_count = s.count } - - if !atomic_cond_wait_with_timeout(&s.cond, &s.mutex, remaining) { - return false + if original_count == atomic_compare_exchange_strong_explicit(&s.count, original_count, original_count-1, .Acquire, .Acquire) { + return true } } - - s.count -= 1 - if s.count > 0 { - atomic_cond_signal(&s.cond) - } - return true } diff --git a/core/sync/sema_internal.odin b/core/sync/sema_internal.odin index e4a3c0bfc..5e2203c34 100644 --- a/core/sync/sema_internal.odin +++ b/core/sync/sema_internal.odin @@ -6,53 +6,19 @@ import "core:time" when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { _Sema :: struct { - count: Futex, + atomic: Atomic_Sema, } _sema_post :: proc(s: ^Sema, count := 1) { - atomic_add_explicit(&s.impl.count, Futex(count), .Release) - if count == 1 { - futex_signal(&s.impl.count) - } else { - futex_broadcast(&s.impl.count) - } + atomic_sema_post(&s.impl.atomic, count) } _sema_wait :: proc(s: ^Sema) { - for { - original_count := atomic_load_explicit(&s.impl.count, .Relaxed) - for original_count == 0 { - futex_wait(&s.impl.count, u32(original_count)) - original_count = s.impl.count - } - if original_count == atomic_compare_exchange_strong_explicit(&s.impl.count, original_count, original_count-1, .Acquire, .Acquire) { - return - } - } + atomic_sema_wait(&s.impl.atomic) } _sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { - if duration <= 0 { - return false - } - for { - - original_count := atomic_load_explicit(&s.impl.count, .Relaxed) - for start := time.tick_now(); original_count == 0; /**/ { - remaining := duration - time.tick_since(start) - if remaining < 0 { - return false - } - - if !futex_wait_with_timeout(&s.impl.count, u32(original_count), remaining) { - return false - } - original_count = s.impl.count - } - if original_count == atomic_compare_exchange_strong_explicit(&s.impl.count, original_count, original_count-1, .Acquire, .Acquire) { - return true - } - } + return atomic_sema_wait_with_timeout(&s.impl.atomic, duration) } } else { _Sema :: struct { From 305510bea0cd8493ffab32a50516d8fde8611e4c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 15:25:56 +0100 Subject: [PATCH 0604/1052] Update intrinsics.odin --- core/intrinsics/intrinsics.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index beb6f3f31..7e75aecc4 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -141,6 +141,7 @@ type_is_valid_matrix_elements :: proc($T: typeid) -> bool --- type_is_named :: proc($T: typeid) -> bool --- type_is_pointer :: proc($T: typeid) -> bool --- +type_is_multi_pointer :: proc($T: typeid) -> bool --- type_is_array :: proc($T: typeid) -> bool --- type_is_enumerated_array :: proc($T: typeid) -> bool --- type_is_slice :: proc($T: typeid) -> bool --- From d6cfb6050613872c3ae70cbbe446276cec4ded12 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 15:29:21 +0100 Subject: [PATCH 0605/1052] Remove `prev` from `Atomic_Cond` --- core/sync/primitives_atomic.odin | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index 812e5ae97..665b515ba 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -287,12 +287,10 @@ atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool { // An Atomic_Cond must not be copied after first use Atomic_Cond :: struct { state: Futex, - prev: u32, } atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) { - state := u32(atomic_load(&c.state)) - atomic_store(&c.prev, state) + state := u32(atomic_load_explicit(&c.state, .Relaxed)) unlock(m) futex_wait(&c.state, state) lock(m) @@ -309,14 +307,12 @@ atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duratio atomic_cond_signal :: proc(c: ^Atomic_Cond) { - state := 1 + atomic_load(&c.prev) - atomic_store(&c.state, Futex(state)) + atomic_add_explicit(&c.state, 1, .Relaxed) futex_signal(&c.state) } atomic_cond_broadcast :: proc(c: ^Atomic_Cond) { - state := 1 + atomic_load(&c.prev) - atomic_store(&c.state, Futex(state)) + atomic_add_explicit(&c.state, 1, .Relaxed) futex_broadcast(&c.state) } From 10cd294cf2b64ae6d5c7e8a470d074e2c48eb4cb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Apr 2022 15:57:47 +0100 Subject: [PATCH 0606/1052] Use Acquire semantics for the `futex_wait` load shortcut --- core/sync/primitives.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sync/primitives.odin b/core/sync/primitives.odin index 483f85343..bfbdc6f9b 100644 --- a/core/sync/primitives.odin +++ b/core/sync/primitives.odin @@ -195,7 +195,7 @@ sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { Futex :: distinct u32 futex_wait :: proc(f: ^Futex, expected: u32) { - if u32(atomic_load(f)) != expected { + if u32(atomic_load_explicit(f, .Acquire)) != expected { return } @@ -204,7 +204,7 @@ futex_wait :: proc(f: ^Futex, expected: u32) { // returns true if the wait happened within the duration, false if it exceeded the time duration futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { - if u32(atomic_load(f)) != expected { + if u32(atomic_load_explicit(f, .Acquire)) != expected { return true } if duration <= 0 { From cd13dedb36799d1b6e2f674d95fd820babff5e16 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 27 Apr 2022 20:06:43 +0200 Subject: [PATCH 0607/1052] D3D12 binding fixes: Added dxgi.IID versions of all the UUIDs in d3d12.odin so that the IIDs can be used to fetch interfaces properly. Also fixed an issue where GetDesc, GetCPUDescriptorHandleForHeapStart and GetGPUDescriptorHandleForHeapStart had the wrong signature due to an old D3D12 header bug, more info: https://stackoverflow.com/questions/34118929/getcpudescriptorhandleforheapstart-stack-corruption --- vendor/directx/d3d12/d3d12.odin | 184 +++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 64 deletions(-) diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin index f3885ed63..739606249 100644 --- a/vendor/directx/d3d12/d3d12.odin +++ b/vendor/directx/d3d12/d3d12.odin @@ -189,7 +189,8 @@ SRV_DIMENSION :: enum i32 { PFN_DESTRUCTION_CALLBACK :: #type proc "c" (a0: rawptr) -ID3DDestructionNotifier_UUID :: "a06eb39a-50da-425b-8c31-4eecd6c270f3" +ID3DDestructionNotifier_UUID_STRING :: "a06eb39a-50da-425b-8c31-4eecd6c270f3" +ID3DDestructionNotifier_UUID := &IID{0xa06eb39a, 0x50da, 0x425b, {0x8c, 0x31, 0x4e, 0xec, 0xd6, 0xc2, 0x70, 0xf3}} ID3DDestructionNotifier :: struct #raw_union { #subtype iunknown: IUnknown, using id3ddestructionnotifier_vtable: ^ID3DDestructionNotifier_VTable, @@ -658,7 +659,8 @@ RASTERIZER_DESC :: struct { } -IObject_UUID :: "c4fec28f-7966-4e95-9f94-f431cb56c3b8" +IObject_UUID_STRING :: "c4fec28f-7966-4e95-9f94-f431cb56c3b8" +IObject_UUID := &IID{0xc4fec28f, 0x7966, 0x4e95, {0x9f, 0x94, 0xf4, 0x31, 0xcb, 0x56, 0xc3, 0xb8}} IObject :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12object_vtable: ^IObject_VTable, @@ -672,7 +674,8 @@ IObject_VTable :: struct { } -IDeviceChild_UUID :: "905db94b-a00c-4140-9df5-2b64ca9ea357" +IDeviceChild_UUID_STRING :: "905db94b-a00c-4140-9df5-2b64ca9ea357" +IDeviceChild_UUID := &IID{0x905db94b, 0xa00c, 0x4140, {0x9d, 0xf5, 0x2b, 0x64, 0xca, 0x9e, 0xa3, 0x57}} IDeviceChild :: struct #raw_union { #subtype id3d12object: IObject, using id3d12devicechild_vtable: ^IDeviceChild_VTable, @@ -683,7 +686,8 @@ IDeviceChild_VTable :: struct { } -IRootSignature_UUID :: "c54a6b66-72df-4ee8-8be5-a946a1429214" +IRootSignature_UUID_STRING :: "c54a6b66-72df-4ee8-8be5-a946a1429214" +IRootSignature_UUID := &IID{0xc54a6b66, 0x72df, 0x4ee8, {0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14}} IRootSignature :: struct { using id3d12devicechild: IDeviceChild, } @@ -2058,7 +2062,8 @@ VERSIONED_ROOT_SIGNATURE_DESC :: struct { } -IRootSignatureDeserializer_UUID :: "34AB647B-3CC8-46AC-841B-C0965645C046" +IRootSignatureDeserializer_UUID_STRING :: "34AB647B-3CC8-46AC-841B-C0965645C046" +IRootSignatureDeserializer_UUID := &IID{0x34AB647B, 0x3CC8, 0x46AC, {0x84, 0x1B, 0xC0, 0x96, 0x56, 0x45, 0xC0, 0x46}} IRootSignatureDeserializer :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12rootsignaturedeserializer_vtable: ^IRootSignatureDeserializer_VTable, @@ -2069,7 +2074,8 @@ IRootSignatureDeserializer_VTable :: struct { } -IVersionedRootSignatureDeserializer_UUID :: "7F91CE67-090C-4BB7-B78E-ED8FF2E31DA0" +IVersionedRootSignatureDeserializer_UUID_STRING :: "7F91CE67-090C-4BB7-B78E-ED8FF2E31DA0" +IVersionedRootSignatureDeserializer_UUID := &IID{0x7F91CE67, 0x090C, 0x4BB7, {0xB7, 0x8E, 0xED, 0x8F, 0xF2, 0xE3, 0x1D, 0xA0}} IVersionedRootSignatureDeserializer :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12versionedrootsignaturedeserializer_vtable: ^IVersionedRootSignatureDeserializer_VTable, @@ -2236,13 +2242,15 @@ COMMAND_SIGNATURE_DESC :: struct { } -IPageable_UUID :: "63ee58fb-1268-4835-86da-f008ce62f0d6" +IPageable_UUID_STRING :: "63ee58fb-1268-4835-86da-f008ce62f0d6" +IPageable_UUID := &IID{0x63ee58fb, 0x1268, 0x4835, {0x86, 0xda, 0xf0, 0x08, 0xce, 0x62, 0xf0, 0xd6}} IPageable :: struct { using id3d12devicechild: IDeviceChild, } -IHeap_UUID :: "6b3b2502-6e51-45b3-90ee-9884265e8df3" +IHeap_UUID_STRING :: "6b3b2502-6e51-45b3-90ee-9884265e8df3" +IHeap_UUID := &IID{0x6b3b2502, 0x6e51, 0x45b3, {0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3}} IHeap :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12heap_vtable: ^IHeap_VTable, @@ -2253,7 +2261,8 @@ IHeap_VTable :: struct { } -IResource_UUID :: "696442be-a72e-4059-bc79-5b5c98040fad" +IResource_UUID_STRING :: "696442be-a72e-4059-bc79-5b5c98040fad" +IResource_UUID := &IID{0x696442be, 0xa72e, 0x4059, {0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad}} IResource :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12resource_vtable: ^IResource_VTable, @@ -2270,7 +2279,8 @@ IResource_VTable :: struct { } -ICommandAllocator_UUID :: "6102dee4-af59-4b09-b999-b44d73f09b24" +ICommandAllocator_UUID_STRING :: "6102dee4-af59-4b09-b999-b44d73f09b24" +ICommandAllocator_UUID := &IID{0x6102dee4, 0xaf59, 0x4b09, {0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24}} ICommandAllocator :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12commandallocator_vtable: ^ICommandAllocator_VTable, @@ -2281,7 +2291,8 @@ ICommandAllocator_VTable :: struct { } -IFence_UUID :: "0a753dcf-c4d8-4b91-adf6-be5a60d95a76" +IFence_UUID_STRING :: "0a753dcf-c4d8-4b91-adf6-be5a60d95a76" +IFence_UUID := &IID {0x0a753dcf, 0xc4d8, 0x4b91, {0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76}} IFence :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12fence_vtable: ^IFence_VTable, @@ -2294,7 +2305,8 @@ IFence_VTable :: struct { } -IFence1_UUID :: "433685fe-e22b-4ca0-a8db-b5b4f4dd0e4a" +IFence1_UUID_STRING :: "433685fe-e22b-4ca0-a8db-b5b4f4dd0e4a" +IFence1_UUID := &IID{0x433685fe, 0xe22b, 0x4ca0, {0xa8, 0xdb, 0xb5, 0xb4, 0xf4, 0xdd, 0x0e, 0x4a}} IFence1 :: struct #raw_union { #subtype id3d12fence: IFence, using id3d12fence1_vtable: ^IFence1_VTable, @@ -2305,7 +2317,8 @@ IFence1_VTable :: struct { } -IPipelineState_UUID :: "765a30f3-f624-4c6f-a828-ace948622445" +IPipelineState_UUID_STRING :: "765a30f3-f624-4c6f-a828-ace948622445" +IPipelineState_UUID := &IID{0x765a30f3, 0xf624, 0x4c6f, {0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45}} IPipelineState :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12pipelinestate_vtable: ^IPipelineState_VTable, @@ -2316,32 +2329,35 @@ IPipelineState_VTable :: struct { } -IDescriptorHeap_UUID :: "8efb471d-616c-4f49-90f7-127bb763fa51" +IDescriptorHeap_UUID_STRING :: "8efb471d-616c-4f49-90f7-127bb763fa51" +IDescriptorHeap_UUID := &IID{0x8efb471d, 0x616c, 0x4f49, { 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51}} IDescriptorHeap :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12descriptorheap_vtable: ^IDescriptorHeap_VTable, } IDescriptorHeap_VTable :: struct { using id3d12devicechild_vtable: IDeviceChild_VTable, - GetDesc: proc "stdcall" (this: ^IDescriptorHeap) -> DESCRIPTOR_HEAP_DESC, - GetCPUDescriptorHandleForHeapStart: proc "stdcall" (this: ^IDescriptorHeap) -> CPU_DESCRIPTOR_HANDLE, - GetGPUDescriptorHandleForHeapStart: proc "stdcall" (this: ^IDescriptorHeap) -> GPU_DESCRIPTOR_HANDLE, -} + GetDesc: proc "stdcall" (this: ^IDescriptorHeap, desc: ^DESCRIPTOR_HEAP_DESC), + GetCPUDescriptorHandleForHeapStart: proc "stdcall" (this: ^IDescriptorHeap, handle: ^CPU_DESCRIPTOR_HANDLE), + GetGPUDescriptorHandleForHeapStart: proc "stdcall" (this: ^IDescriptorHeap, handle: ^GPU_DESCRIPTOR_HANDLE), +} - -IQueryHeap_UUID :: "0d9658ae-ed45-469e-a61d-970ec583cab4" +IQueryHeap_UUID_STRING :: "0d9658ae-ed45-469e-a61d-970ec583cab4" +IQueryHeap_UUID := &IID{0x0d9658ae, 0xed45, 0x469e, {0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4}} IQueryHeap :: struct { #subtype id3d12pageable: IPageable, } -ICommandSignature_UUID :: "c36a797c-ec80-4f0a-8985-a7b2475082d1" +ICommandSignature_UUID_STRING :: "c36a797c-ec80-4f0a-8985-a7b2475082d1" +ICommandSignature_UUID := &IID{0xc36a797c, 0xec80, 0x4f0a, {0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1}} ICommandSignature :: struct { #subtype id3d12pageable: IPageable, } -ICommandList_UUID :: "7116d91c-e7e4-47ce-b8c6-ec8168f437e5" +ICommandList_UUID_STRING :: "7116d91c-e7e4-47ce-b8c6-ec8168f437e5" +ICommandList_UUID := &IID {0x7116d91c, 0xe7e4, 0x47ce, {0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5}} ICommandList :: struct #raw_union { #subtype id3d12devicechild: IDeviceChild, using id3d12commandlist_vtable: ^ICommandList_VTable, @@ -2352,7 +2368,8 @@ ICommandList_VTable :: struct { } -IGraphicsCommandList_UUID :: "5b160d0f-ac1b-4185-8ba8-b3ae42a5a455" +IGraphicsCommandList_UUID_STRING :: "5b160d0f-ac1b-4185-8ba8-b3ae42a5a455" +IGraphicsCommandList_UUID := &IID{0x5b160d0f, 0xac1b, 0x4185, {0x8b, 0xa8, 0xb3, 0xae, 0x42, 0xa5, 0xa4, 0x55}} IGraphicsCommandList :: struct #raw_union { #subtype id3d12commandlist: ICommandList, using id3d12graphicscommandlist_vtable: ^IGraphicsCommandList_VTable, @@ -2413,7 +2430,8 @@ IGraphicsCommandList_VTable :: struct { } -IGraphicsCommandList1_UUID :: "553103fb-1fe7-4557-bb38-946d7d0e7ca7" +IGraphicsCommandList1_UUID_STRING :: "553103fb-1fe7-4557-bb38-946d7d0e7ca7" +IGraphicsCommandList1_UUID := &IID{0x553103fb, 0x1fe7, 0x4557, {0xbb, 0x38, 0x94, 0x6d, 0x7d, 0x0e, 0x7c, 0xa7}} IGraphicsCommandList1 :: struct #raw_union { #subtype id3d12graphicscommandlist: IGraphicsCommandList, using id3d12graphicscommandlist1_vtable: ^IGraphicsCommandList1_VTable, @@ -2440,7 +2458,8 @@ WRITEBUFFERIMMEDIATE_MODE :: enum i32 { } -IGraphicsCommandList2_UUID :: "38C3E585-FF17-412C-9150-4FC6F9D72A28" +IGraphicsCommandList2_UUID_STRING :: "38C3E585-FF17-412C-9150-4FC6F9D72A28" +IGraphicsCommandList2_UUID := &IID{0x38C3E585, 0xFF17, 0x412C, {0x91, 0x50, 0x4F, 0xC6, 0xF9, 0xD7, 0x2A, 0x28}} IGraphicsCommandList2 :: struct #raw_union { #subtype id3d12graphicscommandlist1: IGraphicsCommandList1, using id3d12graphicscommandlist2_vtable: ^IGraphicsCommandList2_VTable, @@ -2451,7 +2470,8 @@ IGraphicsCommandList2_VTable :: struct { } -ICommandQueue_UUID :: "0ec870a6-5d7e-4c22-8cfc-5baae07616ed" +ICommandQueue_UUID_STRING :: "0ec870a6-5d7e-4c22-8cfc-5baae07616ed" +ICommandQueue_UUID := &IID{0x0ec870a6, 0x5d7e, 0x4c22, { 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed}} ICommandQueue :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12commandqueue_vtable: ^ICommandQueue_VTable, @@ -2472,7 +2492,8 @@ ICommandQueue_VTable :: struct { } -IDevice_UUID :: "189819f1-1db6-4b57-be54-1821339b85f7" +IDevice_UUID_STRING :: "189819f1-1db6-4b57-be54-1821339b85f7" +IDevice_UUID := &IID{0x189819f1, 0x1db6, 0x4b57, { 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7}} IDevice :: struct #raw_union { #subtype id3d12object: IObject, using id3d12device_vtable: ^IDevice_VTable, @@ -2519,7 +2540,8 @@ IDevice_VTable :: struct { } -IPipelineLibrary_UUID :: "c64226a8-9201-46af-b4cc-53fb9ff7414f" +IPipelineLibrary_UUID_STRING :: "c64226a8-9201-46af-b4cc-53fb9ff7414f" +IPipelineLibrary_UUID := &IID{0xc64226a8, 0x9201, 0x46af, {0xb4, 0xcc, 0x53, 0xfb, 0x9f, 0xf7, 0x41, 0x4f}} IPipelineLibrary :: struct #raw_union { #subtype id3d12devicechild: IDeviceChild, using id3d12pipelinelibrary_vtable: ^IPipelineLibrary_VTable, @@ -2534,7 +2556,8 @@ IPipelineLibrary_VTable :: struct { } -IPipelineLibrary1_UUID :: "80eabf42-2568-4e5e-bd82-c37f86961dc3" +IPipelineLibrary1_UUID_STRING :: "80eabf42-2568-4e5e-bd82-c37f86961dc3" +IPipelineLibrary1_UUID := &IID{0x80eabf42, 0x2568, 0x4e5e, {0xbd, 0x82, 0xc3, 0x7f, 0x86, 0x96, 0x1d, 0xc3}} IPipelineLibrary1 :: struct #raw_union { #subtype id3d12pipelinelibrary: IPipelineLibrary, using id3d12pipelinelibrary1_vtable: ^IPipelineLibrary1_VTable, @@ -2559,7 +2582,8 @@ RESIDENCY_PRIORITY :: enum i32 { } -IDevice1_UUID :: "77acce80-638e-4e65-8895-c1f23386863e" +IDevice1_UUID_STRING :: "77acce80-638e-4e65-8895-c1f23386863e" +IDevice1_UUID := &IID{0x77acce80, 0x638e, 0x4e65, {0x88, 0x95, 0xc1, 0xf2, 0x33, 0x86, 0x86, 0x3e}} IDevice1 :: struct #raw_union { #subtype id3d12device: IDevice, using id3d12device1_vtable: ^IDevice1_VTable, @@ -2572,7 +2596,8 @@ IDevice1_VTable :: struct { } -IDevice2_UUID :: "30baa41e-b15b-475c-a0bb-1af5c5b64328" +IDevice2_UUID_STRING :: "30baa41e-b15b-475c-a0bb-1af5c5b64328" +IDevice2_UUID := &IID{0x30baa41e, 0xb15b, 0x475c, {0xa0, 0xbb, 0x1a, 0xf5, 0xc5, 0xb6, 0x43, 0x28}} IDevice2 :: struct #raw_union { #subtype id3d12device1: IDevice1, using id3d12device2_vtable: ^IDevice2_VTable, @@ -2588,7 +2613,8 @@ RESIDENCY_FLAGS :: enum u32 { // TODO: make bit_set } -IDevice3_UUID :: "81dadc15-2bad-4392-93c5-101345c4aa98" +IDevice3_UUID_STRING :: "81dadc15-2bad-4392-93c5-101345c4aa98" +IDevice3_UUID := &IID{0x81dadc15, 0x2bad, 0x4392, {0x93, 0xc5, 0x10, 0x13, 0x45, 0xc4, 0xaa, 0x98}} IDevice3 :: struct #raw_union { #subtype id3d12device2: IDevice2, using id3d12device3_vtable: ^IDevice3_VTable, @@ -2618,7 +2644,8 @@ PROTECTED_SESSION_STATUS :: enum i32 { } -IProtectedSession_UUID :: "A1533D18-0AC1-4084-85B9-89A96116806B" +IProtectedSession_UUID_STRING :: "A1533D18-0AC1-4084-85B9-89A96116806B" +IProtectedSession_UUID := &IID{0xA1533D18, 0x0AC1, 0x4084, {0x85, 0xB9, 0x89, 0xA9, 0x61, 0x16, 0x80, 0x6B}} IProtectedSession :: struct #raw_union { #subtype id3d12devicechild: IDeviceChild, using id3d12protectedsession_vtable: ^IProtectedSession_VTable, @@ -2649,7 +2676,8 @@ PROTECTED_RESOURCE_SESSION_DESC :: struct { } -IProtectedResourceSession_UUID :: "6CD696F4-F289-40CC-8091-5A6C0A099C3D" +IProtectedResourceSession_UUID_STRING :: "6CD696F4-F289-40CC-8091-5A6C0A099C3D" +IProtectedResourceSession_UUID := &IID{0x6CD696F4, 0xF289, 0x40CC, {0x80, 0x91, 0x5A, 0x6C, 0x0A, 0x09, 0x9C, 0x3D}} IProtectedResourceSession :: struct #raw_union { #subtype id3d12protectedsession: IProtectedSession, using id3d12protectedresourcesession_vtable: ^IProtectedResourceSession_VTable, @@ -2660,7 +2688,8 @@ IProtectedResourceSession_VTable :: struct { } -IDevice4_UUID :: "e865df17-a9ee-46f9-a463-3098315aa2e5" +IDevice4_UUID_STRING :: "e865df17-a9ee-46f9-a463-3098315aa2e5" +IDevice4_UUID := &IID{0xe865df17, 0xa9ee, 0x46f9, {0xa4, 0x63, 0x30, 0x98, 0x31, 0x5a, 0xa2, 0xe5}} IDevice4 :: struct #raw_union { #subtype id3d12device3: IDevice3, using id3d12device4_vtable: ^IDevice4_VTable, @@ -2681,7 +2710,8 @@ LIFETIME_STATE :: enum i32 { } -ILifetimeOwner_UUID :: "e667af9f-cd56-4f46-83ce-032e595d70a8" +ILifetimeOwner_UUID_STRING :: "e667af9f-cd56-4f46-83ce-032e595d70a8" +ILifetimeOwner_UUID := &IID{0xe667af9f, 0xcd56, 0x4f46, {0x83, 0xce, 0x03, 0x2e, 0x59, 0x5d, 0x70, 0xa8}} ILifetimeOwner :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12lifetimeowner_vtable: ^ILifetimeOwner_VTable, @@ -2692,7 +2722,8 @@ ILifetimeOwner_VTable :: struct { } -ISwapChainAssistant_UUID :: "f1df64b6-57fd-49cd-8807-c0eb88b45c8f" +ISwapChainAssistant_UUID_STRING :: "f1df64b6-57fd-49cd-8807-c0eb88b45c8f" +ISwapChainAssistant_UUID := &IID{0xf1df64b6, 0x57fd, 0x49cd, {0x88, 0x07, 0xc0, 0xeb, 0x88, 0xb4, 0x5c, 0x8f}} ISwapChainAssistant :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12swapchainassistant_vtable: ^ISwapChainAssistant_VTable, @@ -2706,7 +2737,8 @@ ISwapChainAssistant_VTable :: struct { } -ILifetimeTracker_UUID :: "3fd03d36-4eb1-424a-a582-494ecb8ba813" +ILifetimeTracker_UUID_STRING :: "3fd03d36-4eb1-424a-a582-494ecb8ba813" +ILifetimeTracker_UUID := &IID{0x3fd03d36, 0x4eb1, 0x424a, {0xa5, 0x82, 0x49, 0x4e, 0xcb, 0x8b, 0xa8, 0x13}} ILifetimeTracker :: struct #raw_union { #subtype id3d12devicechild: IDeviceChild, using id3d12lifetimetracker_vtable: ^ILifetimeTracker_VTable, @@ -2772,13 +2804,15 @@ META_COMMAND_DESC :: struct { } -IStateObject_UUID :: "47016943-fca8-4594-93ea-af258b55346d" +IStateObject_UUID_STRING :: "47016943-fca8-4594-93ea-af258b55346d" +IStateObject_UUID := &IID{0x47016943, 0xfca8, 0x4594, {0x93, 0xea, 0xaf, 0x25, 0x8b, 0x55, 0x34, 0x6d}} IStateObject :: struct #raw_union { #subtype id3d12pageable: IPageable, } -IStateObjectProperties_UUID :: "de5fa827-9bf9-4f26-89ff-d7f56fde3860" +IStateObjectProperties_UUID_STRING :: "de5fa827-9bf9-4f26-89ff-d7f56fde3860" +IStateObjectProperties_IID := &IID{0xde5fa827, 0x9bf9, 0x4f26, {0x89, 0xff, 0xd7, 0xf5, 0x6f, 0xde, 0x38, 0x60}} IStateObjectProperties :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12stateobjectproperties_vtable: ^IStateObjectProperties_VTable, @@ -3119,7 +3153,8 @@ HIT_KIND :: enum i32 { } -IDevice5_UUID :: "8b4f173b-2fea-4b80-8f58-4307191ab95d" +IDevice5_UUID_STRING :: "8b4f173b-2fea-4b80-8f58-4307191ab95d" +IDevice5_UUID := &IID{0x8b4f173b, 0x2fea, 0x4b80, {0x8f, 0x58, 0x43, 0x07, 0x19, 0x1a, 0xb9, 0x5d}} IDevice5 :: struct #raw_union { #subtype id3d12device4: IDevice4, using id3d12device5_vtable: ^IDevice5_VTable, @@ -3325,7 +3360,8 @@ VERSIONED_DEVICE_REMOVED_EXTENDED_DATA :: struct { } -IDeviceRemovedExtendedDataSettings_UUID :: "82BC481C-6B9B-4030-AEDB-7EE3D1DF1E63" +IDeviceRemovedExtendedDataSettings_UUID_SRING :: "82BC481C-6B9B-4030-AEDB-7EE3D1DF1E63" +IDeviceRemovedExtendedDataSettings_UUID := &IID{0x82BC481C, 0x6B9B, 0x4030, {0xAE, 0xDB, 0x7E, 0xE3, 0xD1, 0xDF, 0x1E, 0x63}} IDeviceRemovedExtendedDataSettings :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12deviceremovedextendeddatasettings_vtable: ^IDeviceRemovedExtendedDataSettings_VTable, @@ -3338,7 +3374,8 @@ IDeviceRemovedExtendedDataSettings_VTable :: struct { } -IDeviceRemovedExtendedDataSettings1_UUID :: "DBD5AE51-3317-4F0A-ADF9-1D7CEDCAAE0B" +IDeviceRemovedExtendedDataSettings1_UUID_STRING :: "DBD5AE51-3317-4F0A-ADF9-1D7CEDCAAE0B" +IDeviceRemovedExtendedDataSettings1_UUID := &IID{0xDBD5AE51, 0x3317, 0x4F0A, {0xAD, 0xF9, 0x1D, 0x7C, 0xED, 0xCA, 0xAE, 0x0B}} IDeviceRemovedExtendedDataSettings1 :: struct #raw_union { #subtype id3d12deviceremovedextendeddatasettings: IDeviceRemovedExtendedDataSettings, using id3d12deviceremovedextendeddatasettings1_vtable: ^IDeviceRemovedExtendedDataSettings1_VTable, @@ -3349,7 +3386,8 @@ IDeviceRemovedExtendedDataSettings1_VTable :: struct { } -IDeviceRemovedExtendedData_UUID :: "98931D33-5AE8-4791-AA3C-1A73A2934E71" +IDeviceRemovedExtendedData_UUID_STRING :: "98931D33-5AE8-4791-AA3C-1A73A2934E71" +IDeviceRemovedExtendedData_UUID := &IID{0x98931D33, 0x5AE8, 0x4791, {0xAA, 0x3C, 0x1A, 0x73, 0xA2, 0x93, 0x4E, 0x71}} IDeviceRemovedExtendedData :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12deviceremovedextendeddata_vtable: ^IDeviceRemovedExtendedData_VTable, @@ -3361,7 +3399,8 @@ IDeviceRemovedExtendedData_VTable :: struct { } -IDeviceRemovedExtendedData1_UUID :: "9727A022-CF1D-4DDA-9EBA-EFFA653FC506" +IDeviceRemovedExtendedData1_UUID_STRING :: "9727A022-CF1D-4DDA-9EBA-EFFA653FC506" +IDeviceRemovedExtendedData1_UUID := &IID{0x9727A022, 0xCF1D, 0x4DDA, {0x9E, 0xBA, 0xEF, 0xFA, 0x65, 0x3F, 0xC5, 0x06}} IDeviceRemovedExtendedData1 :: struct #raw_union { #subtype id3d12deviceremovedextendeddata: IDeviceRemovedExtendedData, using id3d12deviceremovedextendeddata1_vtable: ^IDeviceRemovedExtendedData1_VTable, @@ -3387,7 +3426,8 @@ MEASUREMENTS_ACTION :: enum i32 { } -IDevice6_UUID :: "c70b221b-40e4-4a17-89af-025a0727a6dc" +IDevice6_UUID_STRING :: "c70b221b-40e4-4a17-89af-025a0727a6dc" +IDevice6_UUID := &IID{0xc70b221b, 0x40e4, 0x4a17, {0x89, 0xaf, 0x02, 0x5a, 0x07, 0x27, 0xa6, 0xdc}} IDevice6 :: struct #raw_union { #subtype id3d12device5: IDevice5, using id3d12device6_vtable: ^IDevice6_VTable, @@ -3415,7 +3455,8 @@ PROTECTED_RESOURCE_SESSION_DESC1 :: struct { } -IProtectedResourceSession1_UUID :: "D6F12DD6-76FB-406E-8961-4296EEFC0409" +IProtectedResourceSession1_UUID_STRING :: "D6F12DD6-76FB-406E-8961-4296EEFC0409" +IProtectedResourceSession1_UUID := &IID{0xD6F12DD6, 0x76FB, 0x406E, {0x89, 0x61, 0x42, 0x96, 0xEE, 0xFC, 0x04, 0x09}} IProtectedResourceSession1 :: struct #raw_union { #subtype id3d12protectedresourcesession: IProtectedResourceSession, using id3d12protectedresourcesession1_vtable: ^IProtectedResourceSession1_VTable, @@ -3426,7 +3467,8 @@ IProtectedResourceSession1_VTable :: struct { } -IDevice7_UUID :: "5c014b53-68a1-4b9b-8bd1-dd6046b9358b" +IDevice7_UUID_STRING :: "5c014b53-68a1-4b9b-8bd1-dd6046b9358b" +IDevice7_UUID := &IID{0x5c014b53, 0x68a1, 0x4b9b, {0x8b, 0xd1, 0xdd, 0x60, 0x46, 0xb9, 0x35, 0x8b}} IDevice7 :: struct #raw_union { #subtype id3d12device6: IDevice6, using id3d12device7_vtable: ^IDevice7_VTable, @@ -3438,7 +3480,8 @@ IDevice7_VTable :: struct { } -IDevice8_UUID :: "9218E6BB-F944-4F7E-A75C-B1B2C7B701F3" +IDevice8_UUID_STRING :: "9218E6BB-F944-4F7E-A75C-B1B2C7B701F3" +IDevice8_UUID := &IID{0x9218E6BB, 0xF944, 0x4F7E, {0xA7, 0x5C, 0xB1, 0xB2, 0xC7, 0xB7, 0x01, 0xF3}} IDevice8 :: struct #raw_union { #subtype id3d12device7: IDevice7, using id3d12device8_vtable: ^IDevice8_VTable, @@ -3453,7 +3496,8 @@ IDevice8_VTable :: struct { } -IResource1_UUID :: "9D5E227A-4430-4161-88B3-3ECA6BB16E19" +IResource1_UUID_STRING :: "9D5E227A-4430-4161-88B3-3ECA6BB16E19" +IResource1_UUID := &IID{0x9D5E227A, 0x4430, 0x4161, {0x88, 0xB3, 0x3E, 0xCA, 0x6B, 0xB1, 0x6E, 0x19}} IResource1 :: struct #raw_union { #subtype id3d12resource: IResource, using id3d12resource1_vtable: ^IResource1_VTable, @@ -3464,7 +3508,8 @@ IResource1_VTable :: struct { } -IResource2_UUID :: "BE36EC3B-EA85-4AEB-A45A-E9D76404A495" +IResource2_UUID_STRING :: "BE36EC3B-EA85-4AEB-A45A-E9D76404A495" +IResource2_UUID := &IID{0xBE36EC3B, 0xEA85, 0x4AEB, {0xA4, 0x5A, 0xE9, 0xD7, 0x64, 0x04, 0xA4, 0x95}} IResource2 :: struct #raw_union { #subtype id3d12resource1: IResource1, using id3d12resource2_vtable: ^IResource2_VTable, @@ -3475,7 +3520,8 @@ IResource2_VTable :: struct { } -IHeap1_UUID :: "572F7389-2168-49E3-9693-D6DF5871BF6D" +IHeap1_UUID_STRING :: "572F7389-2168-49E3-9693-D6DF5871BF6D" +IHeap1_UUID := &IID{0x572F7389, 0x2168, 0x49E3, {0x96, 0x93, 0xD6, 0xDF, 0x58, 0x71, 0xBF, 0x6D}} IHeap1 :: struct #raw_union { #subtype id3d12heap: IHeap, using id3d12heap1_vtable: ^IHeap1_VTable, @@ -3486,7 +3532,8 @@ IHeap1_VTable :: struct { } -IGraphicsCommandList3_UUID :: "6FDA83A7-B84C-4E38-9AC8-C7BD22016B3D" +IGraphicsCommandList3_UUID_STRING :: "6FDA83A7-B84C-4E38-9AC8-C7BD22016B3D" +IGraphicsCommandList3_UUID := &IID{0x6FDA83A7, 0xB84C, 0x4E38, {0x9A, 0xC8, 0xC7, 0xBD, 0x22, 0x01, 0x6B, 0x3D}} IGraphicsCommandList3 :: struct #raw_union { #subtype id3d12graphicscommandlist2: IGraphicsCommandList2, using id3d12graphicscommandlist3_vtable: ^IGraphicsCommandList3_VTable, @@ -3568,7 +3615,8 @@ RENDER_PASS_FLAGS :: enum u32 { // TODO: make bit_set } -IMetaCommand_UUID :: "DBB84C27-36CE-4FC9-B801-F048C46AC570" +IMetaCommand_UUID_STRING :: "DBB84C27-36CE-4FC9-B801-F048C46AC570" +IMetaCommand_UUID := &IID{0xDBB84C27, 0x36CE, 0x4FC9, {0xB8, 0x01, 0xF0, 0x48, 0xC4, 0x6A, 0xC5, 0x70}} IMetaCommand :: struct #raw_union { #subtype id3d12pageable: IPageable, using id3d12metacommand_vtable: ^IMetaCommand_VTable, @@ -3589,7 +3637,8 @@ DISPATCH_RAYS_DESC :: struct { } -IGraphicsCommandList4_UUID :: "8754318e-d3a9-4541-98cf-645b50dc4874" +IGraphicsCommandList4_UUID_STRING :: "8754318e-d3a9-4541-98cf-645b50dc4874" +IGraphicsCommandList4_UUID := &IID{0x8754318e, 0xd3a9, 0x4541, {0x98, 0xcf, 0x64, 0x5b, 0x50, 0xdc, 0x48, 0x74}} IGraphicsCommandList4 :: struct #raw_union { #subtype id3d12graphicscommandlist3: IGraphicsCommandList3, using id3d12graphicscommandlist4_vtable: ^IGraphicsCommandList4_VTable, @@ -3608,7 +3657,8 @@ IGraphicsCommandList4_VTable :: struct { } -ITools_UUID :: "7071e1f0-e84b-4b33-974f-12fa49de65c5" +ITools_UUID_STRING :: "7071e1f0-e84b-4b33-974f-12fa49de65c5" +ITools_UUID := &IID{0x7071e1f0, 0xe84b, 0x4b33, {0x97, 0x4f, 0x12, 0xfa, 0x49, 0xde, 0x65, 0xc5}} ITools :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12tools_vtable: ^ITools_VTable, @@ -3632,7 +3682,8 @@ MEMCPY_DEST :: struct { } -IDebug_UUID :: "344488b7-6846-474b-b989-f027448245e0" +IDebug_UUID_STRING :: "344488b7-6846-474b-b989-f027448245e0" +IDebug_UUID := &IID{0x344488b7, 0x6846, 0x474b, {0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0}} IDebug :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12debug_vtable: ^IDebug_VTable, @@ -3648,7 +3699,8 @@ GPU_BASED_VALIDATION_FLAGS :: enum u32 { // TODO: make bit_set } -IDebug1_UUID :: "affaa4ca-63fe-4d8e-b8ad-159000af4304" +IDebug1_UUID_STRING :: "affaa4ca-63fe-4d8e-b8ad-159000af4304" +IDebug1_UUID := &IID{0xaffaa4ca, 0x63fe, 0x4d8e, {0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04}} IDebug1 :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12debug1_vtable: ^IDebug1_VTable, @@ -3672,7 +3724,8 @@ IDebug2_VTable :: struct { } -IDebug3_UUID :: "5cf4e58f-f671-4ff1-a542-3686e3d153d1" +IDebug3_UUID_STRING :: "5cf4e58f-f671-4ff1-a542-3686e3d153d1" +IDebug3_UUID := &IID{0x5cf4e58f, 0xf671, 0x4ff1, {0xa5, 0x42, 0x36, 0x86, 0xe3, 0xd1, 0x53, 0xd1}} IDebug3 :: struct #raw_union { #subtype id3d12debug: IDebug, using id3d12debug3_vtable: ^IDebug3_VTable, @@ -3732,7 +3785,8 @@ DEBUG_DEVICE_GPU_SLOWDOWN_PERFORMANCE_FACTOR :: struct { } -IDebugDevice1_UUID :: "a9b71770-d099-4a65-a698-3dee10020f88" +IDebugDevice1_UUID_STRING :: "a9b71770-d099-4a65-a698-3dee10020f88" +IDebugDevice1_UUID := &IID{0xa9b71770, 0xd099, 0x4a65, {0xa6, 0x98, 0x3d, 0xee, 0x10, 0x02, 0x0f, 0x88}} IDebugDevice1 :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12debugdevice1_vtable: ^IDebugDevice1_VTable, @@ -3745,7 +3799,8 @@ IDebugDevice1_VTable :: struct { } -IDebugDevice_UUID :: "3febd6dd-4973-4787-8194-e45f9e28923e" +IDebugDevice_UUID_STRING :: "3febd6dd-4973-4787-8194-e45f9e28923e" +IDebugDevice_UUID := &IID{0x3febd6dd, 0x4973, 0x4787, {0x81, 0x94, 0xe4, 0x5f, 0x9e, 0x28, 0x92, 0x3e}} IDebugDevice :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12debugdevice_vtable: ^IDebugDevice_VTable, @@ -3758,7 +3813,8 @@ IDebugDevice_VTable :: struct { } -IDebugDevice2_UUID :: "60eccbc1-378d-4df1-894c-f8ac5ce4d7dd" +IDebugDevice2_UUID_STRING :: "60eccbc1-378d-4df1-894c-f8ac5ce4d7dd" +IDebugDevice2_UUID := &IID{0x60eccbc1, 0x378d, 0x4df1, {0x89, 0x4c, 0xf8, 0xac, 0x5c, 0xe4, 0xd7, 0xdd}} IDebugDevice2 :: struct #raw_union { #subtype id3d12debugdevice: IDebugDevice, using id3d12debugdevice2_vtable: ^IDebugDevice2_VTable, @@ -3770,8 +3826,8 @@ IDebugDevice2_VTable :: struct { } - -IDebugCommandQueue_UUID :: "09e0bf36-54ac-484f-8847-4baeeab6053a" +IDebugCommandQueue_UUID_STRING :: "09e0bf36-54ac-484f-8847-4baeeab6053a" +IDebugCommandQueue_UUID := &IID{0x09e0bf36, 0x54ac, 0x484f, {0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3a}} IDebugCommandQueue :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12debugcommandqueue_vtable: ^IDebugCommandQueue_VTable, From 67689ecb21bc1735871b36fdf1411fbffb02e8fb Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 27 Apr 2022 20:47:05 +0200 Subject: [PATCH 0608/1052] Typo fix in d3d12.odin --- vendor/directx/d3d12/d3d12.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin index 739606249..9b3ebbe78 100644 --- a/vendor/directx/d3d12/d3d12.odin +++ b/vendor/directx/d3d12/d3d12.odin @@ -3360,7 +3360,7 @@ VERSIONED_DEVICE_REMOVED_EXTENDED_DATA :: struct { } -IDeviceRemovedExtendedDataSettings_UUID_SRING :: "82BC481C-6B9B-4030-AEDB-7EE3D1DF1E63" +IDeviceRemovedExtendedDataSettings_UUID_STRING :: "82BC481C-6B9B-4030-AEDB-7EE3D1DF1E63" IDeviceRemovedExtendedDataSettings_UUID := &IID{0x82BC481C, 0x6B9B, 0x4030, {0xAE, 0xDB, 0x7E, 0xE3, 0xD1, 0xDF, 0x1E, 0x63}} IDeviceRemovedExtendedDataSettings :: struct #raw_union { #subtype iunknown: IUnknown, From 03c921260091d7dd8b7834163ed3fbdaa4cd46e2 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 27 Apr 2022 22:30:28 +0200 Subject: [PATCH 0609/1052] Added some additional IID versions of Direct3D 12 UUIDs that I missed during my first pass. All are accounted for now. --- vendor/directx/d3d12/d3d12.odin | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin index 9b3ebbe78..c61b6cfb5 100644 --- a/vendor/directx/d3d12/d3d12.odin +++ b/vendor/directx/d3d12/d3d12.odin @@ -3846,7 +3846,8 @@ DEBUG_COMMAND_LIST_GPU_BASED_VALIDATION_SETTINGS :: struct { } -IDebugCommandList1_UUID :: "102ca951-311b-4b01-b11f-ecb83e061b37" +IDebugCommandList1_UUID_STRING :: "102ca951-311b-4b01-b11f-ecb83e061b37" +IDebugCommandList1_UUID := &IID{0x102ca951, 0x311b, 0x4b01, {0xb1, 0x1f, 0xec, 0xb8, 0x3e, 0x06, 0x1b, 0x37}} IDebugCommandList1 :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12debugcommandlist1_vtable: ^IDebugCommandList1_VTable, @@ -3859,7 +3860,8 @@ IDebugCommandList1_VTable :: struct { } -IDebugCommandList_UUID :: "09e0bf36-54ac-484f-8847-4baeeab6053f" +IDebugCommandList_UUID_STRING :: "09e0bf36-54ac-484f-8847-4baeeab6053f" +IDebugCommandList_UUID := &IID{0x09e0bf36, 0x54ac, 0x484f, {0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3f}} IDebugCommandList :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12debugcommandlist_vtable: ^IDebugCommandList_VTable, @@ -3872,7 +3874,8 @@ IDebugCommandList_VTable :: struct { } -IDebugCommandList2_UUID :: "aeb575cf-4e06-48be-ba3b-c450fc96652e" +IDebugCommandList2_UUID_STRING :: "aeb575cf-4e06-48be-ba3b-c450fc96652e" +IDebugCommandList2_UUID := &IID{0xaeb575cf, 0x4e06, 0x48be, {0xba, 0x3b, 0xc4, 0x50, 0xfc, 0x96, 0x65, 0x2e}} IDebugCommandList2 :: struct #raw_union { #subtype id3d12debugcommandlist: IDebugCommandList, using id3d12debugcommandlist2_vtable: ^IDebugCommandList2_VTable, @@ -3884,7 +3887,8 @@ IDebugCommandList2_VTable :: struct { } -ISharingContract_UUID :: "0adf7d52-929c-4e61-addb-ffed30de66ef" +ISharingContract_UUID_STRING :: "0adf7d52-929c-4e61-addb-ffed30de66ef" +ISharingContract_UUID := &IID{0x0adf7d52, 0x929c, 0x4e61, {0xad, 0xdb, 0xff, 0xed, 0x30, 0xde, 0x66, 0xef}} ISharingContract :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12sharingcontract_vtable: ^ISharingContract_VTable, @@ -4789,7 +4793,8 @@ INFO_QUEUE_FILTER :: struct { } -IInfoQueue_UUID :: "0742a90b-c387-483f-b946-30a7e4e61458" +IInfoQueue_UUID_STRING :: "0742a90b-c387-483f-b946-30a7e4e61458" +IInfoQueue_UUID := &IID{0x0742a90b, 0xc387, 0x483f, {0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58}} IInfoQueue :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12infoqueue_vtable: ^IInfoQueue_VTable, @@ -4861,7 +4866,8 @@ SHADING_RATE_COMBINER :: enum i32 { } -IGraphicsCommandList5_UUID :: "55050859-4024-474c-87f5-6472eaee44ea" +IGraphicsCommandList5_UUID_STRING :: "55050859-4024-474c-87f5-6472eaee44ea" +IGraphicsCommandList5_UUID := &IID{0x55050859, 0x4024, 0x474c, {0x87, 0xf5, 0x64, 0x72, 0xea, 0xee, 0x44, 0xea}} IGraphicsCommandList5 :: struct #raw_union { #subtype id3d12graphicscommandlist4: IGraphicsCommandList4, using id3d12graphicscommandlist5_vtable: ^IGraphicsCommandList5_VTable, @@ -4879,7 +4885,8 @@ DISPATCH_MESH_ARGUMENTS :: struct { } -IGraphicsCommandList6_UUID :: "c3827890-e548-4cfa-96cf-5689a9370f80" +IGraphicsCommandList6_UUID_STRING :: "c3827890-e548-4cfa-96cf-5689a9370f80" +IGraphicsCommandList6_UUID := &IID{0xc3827890, 0xe548, 0x4cfa, {0x96, 0xcf, 0x56, 0x89, 0xa9, 0x37, 0x0f, 0x80}} IGraphicsCommandList6 :: struct #raw_union { #subtype id3d12graphicscommandlist5: IGraphicsCommandList5, using id3d12graphicscommandlist6_vtable: ^IGraphicsCommandList6_VTable, From 80878264b63cd8476def629526b294b8e129791a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Apr 2022 15:29:00 +0200 Subject: [PATCH 0610/1052] [xml] Speedup. --- core/encoding/xml/debug_print.odin | 18 +- core/encoding/xml/example/xml_example.odin | 77 ++++-- core/encoding/xml/helpers.odin | 28 +-- core/encoding/xml/tokenizer.odin | 11 + core/encoding/xml/xml_reader.odin | 278 +++++++++++---------- tests/core/encoding/xml/test_core_xml.odin | 17 +- 6 files changed, 246 insertions(+), 183 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index e6a8c9433..7c20ac123 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -1,8 +1,7 @@ -package xml /* An XML 1.0 / 1.1 parser - Copyright 2021 Jeroen van Rijn . + Copyright 2021-2022 Jeroen van Rijn . Made available under Odin's BSD-3 license. A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). @@ -10,6 +9,8 @@ package xml List of contributors: Jeroen van Rijn: Initial implementation. */ +package xml + import "core:io" import "core:fmt" @@ -40,17 +41,16 @@ print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error written += wprintf(writer, "[Pre-root comment] %v\n", comment) } - if doc.root != nil { + if len(doc.elements) > 0 { + wprintln(writer, " --- ") + print_element(writer, doc, 0) wprintln(writer, " --- ") - print_element(writer, doc.root) - wprintln(writer, " --- ") } return written, .None } -print_element :: proc(writer: io.Writer, element: ^Element, indent := 0) -> (written: int, err: io.Error) { - if element == nil { return } +print_element :: proc(writer: io.Writer, doc: ^Document, element_id: Element_ID, indent := 0) -> (written: int, err: io.Error) { using fmt tab :: proc(writer: io.Writer, indent: int) { @@ -61,6 +61,8 @@ print_element :: proc(writer: io.Writer, element: ^Element, indent := 0) -> (wri tab(writer, indent) + element := doc.elements[element_id] + if element.kind == .Element { wprintf(writer, "<%v>\n", element.ident) if len(element.value) > 0 { @@ -74,7 +76,7 @@ print_element :: proc(writer: io.Writer, element: ^Element, indent := 0) -> (wri } for child in element.children { - print_element(writer, child, indent + 1) + print_element(writer, doc, child, indent + 1) } } else if element.kind == .Comment { wprintf(writer, "[COMMENT] %v\n", element.value) diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index daa3c5dab..cadfcfb43 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -1,52 +1,85 @@ package xml_example import "core:encoding/xml" -import "core:os" import "core:mem" import "core:fmt" import "core:time" import "core:strings" import "core:hash" +N :: 1 + example :: proc() { using fmt - doc: ^xml.Document - err: xml.Error + docs: [N]^xml.Document + errs: [N]xml.Error + times: [N]time.Duration + + defer for round in 0..` tag.") - os.exit(1) + eprintln("Could not locate top-level `` tag.") + return } - printf("Found `` with %v children.\n", len(charlist.children)) + printf("Found `` with %v children, %v elements total\n", len(docs[0].elements[charlist].children), docs[0].element_count) - crc32 := doc_hash(doc) + crc32 := doc_hash(docs[0]) printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0xcaa042b9 else "🤬", crc32) + + for round in 0.. (crc32: u32) { diff --git a/core/encoding/xml/helpers.odin b/core/encoding/xml/helpers.odin index 14597ddbd..48f058334 100644 --- a/core/encoding/xml/helpers.odin +++ b/core/encoding/xml/helpers.odin @@ -1,22 +1,20 @@ -package xml /* An XML 1.0 / 1.1 parser - Copyright 2021 Jeroen van Rijn . + Copyright 2021-2022 Jeroen van Rijn . Made available under Odin's BSD-3 license. This file contains helper functions. */ +package xml - -/* - Find `tag`'s nth child with a given ident. -*/ -find_child_by_ident :: proc(tag: ^Element, ident: string, nth := 0) -> (res: ^Element, found: bool) { - if tag == nil { return nil, false } +// Find parent's nth child with a given ident. +find_child_by_ident :: proc(doc: ^Document, parent_id: Element_ID, ident: string, nth := 0) -> (res: Element_ID, found: bool) { + tag := doc.elements[parent_id] count := 0 - for child in tag.children { + for child_id in tag.children { + child := doc.elements[child_id] /* Skip commments. They have no name. */ @@ -26,18 +24,16 @@ find_child_by_ident :: proc(tag: ^Element, ident: string, nth := 0) -> (res: ^El If the ident matches and it's the nth such child, return it. */ if child.ident == ident { - if count == nth { return child, true } + if count == nth { return child_id, true } count += 1 } } - return nil, false + return 0, false } -/* - Find an attribute by key. -*/ -find_attribute_val_by_key :: proc(tag: ^Element, key: string) -> (val: string, found: bool) { - if tag == nil { return "", false } +// Find an attribute by key. +find_attribute_val_by_key :: proc(doc: ^Document, parent_id: Element_ID, key: string) -> (val: string, found: bool) { + tag := doc.elements[parent_id] for attr in tag.attribs { /* diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 2da3b7683..c3fece76e 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -1,3 +1,14 @@ +/* + An XML 1.0 / 1.1 parser + + Copyright 2021-2022 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ package xml import "core:fmt" diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 0315b0e05..636dd0ae4 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -1,8 +1,7 @@ -package xml /* An XML 1.0 / 1.1 parser - Copyright 2021 Jeroen van Rijn . + Copyright 2021-2022 Jeroen van Rijn . Made available under Odin's BSD-3 license. A from-scratch XML implementation, loosely modelled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). @@ -25,12 +24,17 @@ package xml List of contributors: Jeroen van Rijn: Initial implementation. */ +package xml +// An XML 1.0 / 1.1 parser import "core:bytes" -import "core:strings" import "core:encoding/entity" +import "core:intrinsics" import "core:mem" import "core:os" +import "core:strings" + +likely :: intrinsics.expect DEFAULT_Options :: Options{ flags = { @@ -88,7 +92,9 @@ Option_Flag :: enum { Option_Flags :: bit_set[Option_Flag; u16] Document :: struct { - root: ^Element, + elements: [dynamic]Element, + element_count: Element_ID, + prolog: Attributes, encoding: Encoding, @@ -129,8 +135,8 @@ Element :: struct { Comment, }, - parent: ^Element, - children: [dynamic]^Element, + parent: Element_ID, + children: [dynamic]Element_ID, } Attr :: struct { @@ -185,7 +191,7 @@ Error :: enum { No_DocType, Too_Many_DocTypes, - DocType_Must_Proceed_Elements, + DocType_Must_Preceed_Elements, /* If a DOCTYPE is present _or_ the caller @@ -237,12 +243,16 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err doc.tokenizer = t doc.input = data + doc.elements = make([dynamic]Element, 1024, 1024, allocator) + // strings.intern_init(&doc.intern, allocator, allocator) err = .Unexpected_Token - element, parent: ^Element + element, parent: Element_ID - tag_is_open := false + tag_is_open := false + first_element := true + open: Token /* If a DOCTYPE is present, the root tag has to match. @@ -252,6 +262,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err loop: for { skip_whitespace(t) + // NOTE(Jeroen): This is faster as a switch. switch t.ch { case '<': /* @@ -259,35 +270,85 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err */ advance_rune(t) - open := scan(t) - #partial switch open.kind { - - case .Question: + open = scan(t) + // NOTE(Jeroen): We're not using a switch because this if-else chain ordered by likelihood is 2.5% faster at -o:size and -o:speed. + if likely(open.kind, Token_Kind.Ident) == .Ident { /* - 0 { - /* - We've already seen a prolog. - */ - return doc, .Too_Many_Prologs - } else { - /* - Could be ` 0 && expected_doctype != open.text { + error(t, t.offset, "Root Tag doesn't match DOCTYPE. Expected: %v, got: %v\n", expected_doctype, open.text) + return doc, .Invalid_DocType } + } + + /* + One of these should follow: + - `>`, which means we've just opened this tag and expect a later element to close it. + - `/>`, which means this is an 'empty' or self-closing tag. + */ + end_token := scan(t) + #partial switch end_token.kind { + case .Gt: + /* + We're now the new parent. + */ + parent = element + + case .Slash: + /* + Empty tag. Close it. + */ + expect(t, .Gt) or_return + parent = doc.elements[element].parent + element = parent + tag_is_open = false + case: - error(t, t.offset, "Expected \" 0 { return doc, .Too_Many_DocTypes } - if doc.root != nil { - return doc, .DocType_Must_Proceed_Elements + if doc.element_count > 0 { + return doc, .DocType_Must_Preceed_Elements } parse_doctype(doc) or_return @@ -327,14 +388,14 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err comment := scan_comment(t) or_return if .Intern_Comments in opts.flags { - if doc.root == nil { + if len(doc.elements) == 0 { append(&doc.comments, comment) } else { - el := new(Element) - el.parent = element - el.kind = .Comment - el.value = comment - append(&element.children, el) + el := new_element(doc) + doc.elements[el].parent = element + doc.elements[el].kind = .Comment + doc.elements[el].value = comment + append(&doc.elements[element].children, el) } } @@ -343,83 +404,32 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err return } - case .Ident: + } else if open.kind == .Question { /* - e.g. 0 && expected_doctype != open.text { - error(t, t.offset, "Root Tag doesn't match DOCTYPE. Expected: %v, got: %v\n", expected_doctype, open.text) - return doc, .Invalid_DocType + next := scan(t) + #partial switch next.kind { + case .Ident: + if len(next.text) == 3 && strings.to_lower(next.text, context.temp_allocator) == "xml" { + parse_prolog(doc) or_return + } else if len(doc.prolog) > 0 { + /* + We've already seen a prolog. + */ + return doc, .Too_Many_Prologs + } else { + /* + Could be ``, which means we've just opened this tag and expect a later element to close it. - - `/>`, which means this is an 'empty' or self-closing tag. - */ - end_token := scan(t) - #partial switch end_token.kind { - case .Gt: - /* - We're now the new parent. - */ - parent = element - - case .Slash: - /* - Empty tag. Close it. - */ - expect(t, .Gt) or_return - parent = element.parent - element = parent - tag_is_open = false - case: - error(t, t.offset, "Expected close tag, got: %#v\n", end_token) + error(t, t.offset, "Expected \" (err: Error) { */ doc.doctype.rest = string(t.src[offset : t.offset - 1]) return .None +} + +Element_ID :: u32 + +new_element :: proc(doc: ^Document) -> (id: Element_ID) { + element_space := len(doc.elements) + + // Need to resize + if int(doc.element_count) + 1 > element_space { + if element_space < 65536 { + element_space *= 2 + } else { + element_space += 65536 + } + resize(&doc.elements, element_space) + } + + cur := doc.element_count + doc.element_count += 1 + + return cur } \ No newline at end of file diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 7669afe97..82386b2bb 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -224,7 +224,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) if len(doc.doctype.rest) > 0 { - wprintf(writer, "\t%v\n", doc.doctype.rest) + wprintf(writer, "\t%v\n", doc.doctype.rest) } } @@ -232,17 +232,16 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { written += wprintf(writer, "[Pre-root comment] %v\n", comment) } - if doc.root != nil { - wprintln(writer, " --- ") - print_element(writer, doc.root) - wprintln(writer, " --- ") + if doc.element_count > 0 { + wprintln(writer, " --- ") + print_element(writer, doc, 0) + wprintln(writer, " --- ") } return written, .None } - print_element :: proc(writer: io.Writer, element: ^xml.Element, indent := 0) -> (written: int, err: io.Error) { - if element == nil { return } + print_element :: proc(writer: io.Writer, doc: ^xml.Document, element_id: xml.Element_ID, indent := 0) -> (written: int, err: io.Error) { using fmt tab :: proc(writer: io.Writer, indent: int) { @@ -253,6 +252,8 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { tab(writer, indent) + element := doc.elements[element_id] + if element.kind == .Element { wprintf(writer, "<%v>\n", element.ident) if len(element.value) > 0 { @@ -266,7 +267,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { } for child in element.children { - print_element(writer, child, indent + 1) + print_element(writer, doc, child, indent + 1) } } else if element.kind == .Comment { wprintf(writer, "[COMMENT] %v\n", element.value) From 127b0ba65e473ae54fe514ea3e695959cefc3b68 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Apr 2022 15:46:36 +0200 Subject: [PATCH 0611/1052] [xml] Enable tests. --- tests/core/build.bat | 16 +++++++++------- tests/core/encoding/xml/test_core_xml.odin | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/tests/core/build.bat b/tests/core/build.bat index b03fef4bb..8e4ba1d15 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,5 +1,6 @@ @echo off -set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. +set COMMON=-no-bounds-check -vet -strict-style +set COLLECTION=-collection:tests=.. set PATH_TO_ODIN==..\..\odin python3 download_assets.py echo --- @@ -35,9 +36,10 @@ echo --- echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding/hxa %COMMON% -out:test_hxa.exe -%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe +%PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe +%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe %PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe +%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe echo --- echo Running core:math/noise tests @@ -47,19 +49,19 @@ echo --- echo --- echo Running core:math tests echo --- -%PATH_TO_ODIN% run math %COMMON% -out:test_core_math.exe +%PATH_TO_ODIN% run math %COMMON% %COLLECTION% -out:test_core_math.exe echo --- echo Running core:math/linalg/glsl tests echo --- -%PATH_TO_ODIN% run math/linalg/glsl %COMMON% -out:test_linalg_glsl.exe +%PATH_TO_ODIN% run math/linalg/glsl %COMMON% %COLLECTION% -out:test_linalg_glsl.exe echo --- echo Running core:path/filepath tests echo --- -%PATH_TO_ODIN% run path/filepath %COMMON% -out:test_core_filepath.exe +%PATH_TO_ODIN% run path/filepath %COMMON% %COLLECTION% -out:test_core_filepath.exe echo --- echo Running core:reflect tests echo --- -%PATH_TO_ODIN% run reflect %COMMON% -out:test_core_reflect.exe \ No newline at end of file +%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe \ No newline at end of file diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 82386b2bb..a79c939c8 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -168,6 +168,21 @@ TESTS :: []TEST{ err = .Invalid_DocType, crc32 = 0x49b83d0a, }, + + /* + Parse the 8.2 MiB unicode.xml for good measure. + */ + { + filename = "unicode.xml", + options = { + flags = { + .Ignore_Unsupported, + }, + expected_doctype = "", + }, + err = .None, + crc32 = 0xcaa042b9, + }, } when ODIN_TEST { From a1002e69606cf1d60a5936ddd8ab9d069b5d499b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Apr 2022 17:46:36 +0200 Subject: [PATCH 0612/1052] Fix -error-pos-style:unix --- src/main.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 7b0364149..c9e908f11 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -630,6 +630,7 @@ enum BuildFlagKind { BuildFlag_IgnoreWarnings, BuildFlag_WarningsAsErrors, BuildFlag_VerboseErrors, + BuildFlag_ErrorPosStyle, // internal use only BuildFlag_InternalIgnoreLazy, @@ -793,6 +794,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); @@ -1472,6 +1474,15 @@ bool parse_build_flags(Array args) { case BuildFlag_VerboseErrors: build_context.show_error_line = true; break; + + case BuildFlag_ErrorPosStyle: + GB_ASSERT(value.kind == ExactValue_String); + build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Default; + if (value.value_string == "unix" || value.value_string == "UNIX") { + build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Unix; + } + break; + case BuildFlag_InternalIgnoreLazy: build_context.ignore_lazy = true; break; From 1ed84a064bd0d64ba4deba56d5a2704350866d1f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Apr 2022 18:12:55 +0200 Subject: [PATCH 0613/1052] Make -error-pos-style case-insensitive. --- src/main.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c9e908f11..ff7bb9f67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1477,9 +1477,14 @@ bool parse_build_flags(Array args) { case BuildFlag_ErrorPosStyle: GB_ASSERT(value.kind == ExactValue_String); - build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Default; - if (value.value_string == "unix" || value.value_string == "UNIX") { + + if (str_eq_ignore_case(value.value_string, str_lit("odin"))) { + build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Default; + } else if (str_eq_ignore_case(value.value_string, str_lit("unix"))) { build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Unix; + } else { + gb_printf_err("-error-pos-style options are 'unix' and 'odin'\n"); + bad_flags = true; } break; From e53ba3b11612db5c52ecf9b523e4d0ed87f7b1ad Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Apr 2022 18:18:25 +0200 Subject: [PATCH 0614/1052] Allow -error-pos-style:default as an alias for odin --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ff7bb9f67..818a783e1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1478,12 +1478,12 @@ bool parse_build_flags(Array args) { case BuildFlag_ErrorPosStyle: GB_ASSERT(value.kind == ExactValue_String); - if (str_eq_ignore_case(value.value_string, str_lit("odin"))) { + if (str_eq_ignore_case(value.value_string, str_lit("odin")) || str_eq_ignore_case(value.value_string, str_lit("default"))) { build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Default; } else if (str_eq_ignore_case(value.value_string, str_lit("unix"))) { build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Unix; } else { - gb_printf_err("-error-pos-style options are 'unix' and 'odin'\n"); + gb_printf_err("-error-pos-style options are 'unix', 'odin' and 'default' (odin)\n"); bad_flags = true; } break; From 2fae6eda2321881ccf8d942e2c27e6a7c29aebfd Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Apr 2022 18:58:49 +0200 Subject: [PATCH 0615/1052] [i18n] Initial i18n support. - Add initial GetText .MO parser - Add translation struct and helpers - Pluralized lookup TODO: - Support for more translation catalog file formats. --- core/i18n/example/i18n_example.odin | 64 +++++++++++ core/i18n/example/messages.pot | 30 +++++ core/i18n/example/nl_NL.mo | Bin 0 -> 672 bytes core/i18n/example/nl_NL.po | 33 ++++++ core/i18n/gettext.odin | 163 ++++++++++++++++++++++++++++ core/i18n/i18n.odin | 116 ++++++++++++++++++++ 6 files changed, 406 insertions(+) create mode 100644 core/i18n/example/i18n_example.odin create mode 100644 core/i18n/example/messages.pot create mode 100644 core/i18n/example/nl_NL.mo create mode 100644 core/i18n/example/nl_NL.po create mode 100644 core/i18n/gettext.odin create mode 100644 core/i18n/i18n.odin diff --git a/core/i18n/example/i18n_example.odin b/core/i18n/example/i18n_example.odin new file mode 100644 index 000000000..f9fb2a353 --- /dev/null +++ b/core/i18n/example/i18n_example.odin @@ -0,0 +1,64 @@ +package i18n_example + +import "core:mem" +import "core:fmt" +import "core:i18n" + +LOC :: i18n.get + +_main :: proc() { + using fmt + + err: i18n.Error + + /* + Parse MO file and set it as the active translation so we can omit `get`'s "catalog" parameter. + */ + i18n.ACTIVE, err = i18n.parse_mo(#load("nl_NL.mo")) + defer i18n.destroy() + + if err != .None { return } + + /* + These are in the .MO catalog. + */ + println("-----") + println(LOC("")) + println("-----") + println(LOC("There are 69,105 leaves here.")) + println("-----") + println(LOC("Hellope, World!")) + + /* + For ease of use, pluralized lookup can use both singular and plural form as key for the same translation. + */ + println("-----") + printf(LOC("There is %d leaf.\n", 1), 1) + printf(LOC("There is %d leaf.\n", 42), 42) + + printf(LOC("There are %d leaves.\n", 1), 1) + printf(LOC("There are %d leaves.\n", 42), 42) + + /* + This isn't. + */ + println("-----") + println(LOC("Come visit us on Discord!")) +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + _main() + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } +} \ No newline at end of file diff --git a/core/i18n/example/messages.pot b/core/i18n/example/messages.pot new file mode 100644 index 000000000..53d521b6b --- /dev/null +++ b/core/i18n/example/messages.pot @@ -0,0 +1,30 @@ +# Odin i18n Example +# Copyright (C) 2021 Jeroen van Rijn +# This file is distributed under the same license as the PACKAGE package. +# Jeroen van Rijn , 2021. +# +#, fuzzy +msgid "" +msgstr "Project-Id-Version: Example 0.0.1\n" + "Report-Msgid-Bugs-To: Jeroen van Rijn \n" + "POT-Creation-Date: 2021-11-27 19:23+0100\n" + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" + "Last-Translator: FULL NAME \n" + "Language: en-GB\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + +#: i18n_example.odin:28 +msgid "There are 69,105 leaves here." +msgstr "Er zijn hier 69.105 bladeren." + +#: i18n_example.odin:30 +msgid "Hellope, World!" +msgstr "Hallo, Wereld!" + +#: i18n_example.odin:36 +msgid "There is %d leaf.\n" +msgid_plural "There are %d leaves.\n" +msgstr[0] "Er is %d blad.\n" +msgstr[1] "Er zijn %d bladeren.\n" \ No newline at end of file diff --git a/core/i18n/example/nl_NL.mo b/core/i18n/example/nl_NL.mo new file mode 100644 index 0000000000000000000000000000000000000000..0b1a668f4d225e8695e479d6135779288870ac39 GIT binary patch literal 672 zcmZ9J&u$Yj5XKiM7au_44AS&asfgO_2DJ*Crb0kU3ki*)<+lpj3*#GPkbdF5#NYS;wSO_ zR+9Xp^&T;~-RZ})ZqWIHR+5uDL<~A!zL6ZD*0#Yd_+*_f*OOw24nYz-&$qI48#Kxl zdWdQ9S5+Q1$|#%&_D@5XqhiWVojt`x;D;suh|Vi(au}V-y3q)!NJYkG*jN|%#8;~1 zFWbuV!shT6okasHX<(*K4eY){t!iq2(R#W^80)an=b}f6x^+_Xed}tUgJ~|0e%Kp8w;gU8SRX?6cyK)hmFX|<$1FLJ r#*sB9{CC6VbdO literal 0 HcmV?d00001 diff --git a/core/i18n/example/nl_NL.po b/core/i18n/example/nl_NL.po new file mode 100644 index 000000000..1b8acbcc1 --- /dev/null +++ b/core/i18n/example/nl_NL.po @@ -0,0 +1,33 @@ +# Odin i18n Example +# Copyright (C) 2021 Jeroen van Rijn +# This file is distributed under the same license as the PACKAGE package. +# Jeroen van Rijn , 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Example 0.0.1\n" +"Report-Msgid-Bugs-To: Jeroen van Rijn \n" +"POT-Creation-Date: 2021-11-27 19:23+0100\n" +"PO-Revision-Date: 2021-11-28 02:56+0100\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language-Team: Odin Language Team\n" +"X-Generator: Poedit 3.0\n" +"Last-Translator: Jeroen van Rijn\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Language: nl_NL\n" + +#: i18n_example.odin:28 +msgid "There are 69,105 leaves here." +msgstr "Er zijn hier 69.105 bladeren." + +#: i18n_example.odin:30 +msgid "Hellope, World!" +msgstr "Hallo, Wereld!" + +#: i18n_example.odin:36 +msgid "There is %d leaf.\n" +msgid_plural "There are %d leaves.\n" +msgstr[0] "Er is %d blad.\n" +msgstr[1] "Er zijn %d bladeren.\n" diff --git a/core/i18n/gettext.odin b/core/i18n/gettext.odin new file mode 100644 index 000000000..7918e217e --- /dev/null +++ b/core/i18n/gettext.odin @@ -0,0 +1,163 @@ +package i18n +/* + A parser for GNU GetText .MO files. + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + A from-scratch implementation based after the specification found here: + https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +import "core:os" +import "core:strings" +import "core:bytes" + +parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { + context.allocator = allocator + /* + An MO file should have at least a 4-byte magic, 2 x 2 byte version info, + a 4-byte number of strings value, and 2 x 4-byte offsets. + */ + if len(data) < 20 { + return {}, .MO_File_Invalid + } + + /* + Check magic. Should be 0x950412de in native Endianness. + */ + native := true + magic := read_u32(data, native) or_return + + if magic != 0x950412de { + native = false + magic = read_u32(data, native) or_return + + if magic != 0x950412de { return {}, .MO_File_Invalid_Signature } + } + + /* + We can ignore version_minor at offset 6. + */ + version_major := read_u16(data[4:]) or_return + if version_major > 1 { return {}, .MO_File_Unsupported_Version } + + count := read_u32(data[ 8:]) or_return + original_offset := read_u32(data[12:]) or_return + translated_offset := read_u32(data[16:]) or_return + + if count == 0 { return {}, .Empty_Translation_Catalog } + + /* + Initalize Translation, interner and optional pluralizer. + */ + translation = new(Translation) + translation.pluralize = pluralizer + strings.intern_init(&translation.intern, allocator, allocator) + + for n := u32(0); n < count; n += 1 { + /* + Grab string's original length and offset. + */ + offset := original_offset + 8 * n + if len(data) < int(offset + 8) { return translation, .MO_File_Invalid } + + o_length := read_u32(data[offset :], native) or_return + o_offset := read_u32(data[offset + 4:], native) or_return + + offset = translated_offset + 8 * n + if len(data) < int(offset + 8) { return translation, .MO_File_Invalid } + + t_length := read_u32(data[offset :], native) or_return + t_offset := read_u32(data[offset + 4:], native) or_return + + max_offset := int(max(o_offset + o_length + 1, t_offset + t_length + 1)) + if len(data) < max_offset { return translation, .Premature_EOF } + + key := data[o_offset:][:o_length] + val := data[t_offset:][:t_length] + + /* + Could be a pluralized string. + */ + zero := []byte{0} + + keys := bytes.split(key, zero) + vals := bytes.split(val, zero) + + if len(keys) != len(vals) || max(len(keys), len(vals)) > MAX_PLURALS { + return translation, .MO_File_Incorrect_Plural_Count + } + + for k in keys { + interned_key := strings.intern_get(&translation.intern, string(k)) + + interned_vals: [MAX_PLURALS]string = {} + last_val: string + + i := 0 + for v in vals { + interned_vals[i] = strings.intern_get(&translation.intern, string(v)) + last_val = interned_vals[i] + i += 1 + } + for ; i < MAX_PLURALS; i += 1 { + interned_vals[i] = last_val + } + translation.k_v[interned_key] = interned_vals + } + delete(vals) + delete(keys) + } + return +} + +parse_mo_file :: proc(filename: string, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { + context.allocator = allocator + + data, data_ok := os.read_entire_file(filename) + defer delete(data) + + if !data_ok { return {}, .File_Error } + + return parse_mo_from_slice(data, pluralizer) +} + +parse_mo :: proc { parse_mo_file, parse_mo_from_slice } + +/* + Helpers. +*/ +read_u32 :: proc(data: []u8, native_endian := true) -> (res: u32, err: Error) { + if len(data) < size_of(u32) { return 0, .Premature_EOF } + + val := (^u32)(raw_data(data))^ + + if native_endian { + return val, .None + } else { + when ODIN_ENDIAN == .Little { + return u32(transmute(u32be)val), .None + } else { + return u32(transmute(u32le)val), .None + } + } +} + +read_u16 :: proc(data: []u8, native_endian := true) -> (res: u16, err: Error) { + if len(data) < size_of(u16) { return 0, .Premature_EOF } + + val := (^u16)(raw_data(data))^ + + if native_endian { + return val, .None + } else { + when ODIN_ENDIAN == .Little { + return u16(transmute(u16be)val), .None + } else { + return u16(transmute(u16le)val), .None + } + } +} \ No newline at end of file diff --git a/core/i18n/i18n.odin b/core/i18n/i18n.odin new file mode 100644 index 000000000..7c72f9858 --- /dev/null +++ b/core/i18n/i18n.odin @@ -0,0 +1,116 @@ +package i18n +/* + Internationalization helpers. + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +import "core:strings" + +/* + TODO: + - Support for more translation catalog file formats. +*/ + +MAX_PLURALS :: 10 + +/* + Currently active catalog. +*/ +ACTIVE: ^Translation + +/* + The main data structure. This can be generated from various different file formats, as long as we have a parser for them. +*/ +Translation :: struct { + k_v: map[string][MAX_PLURALS]string, + intern: strings.Intern, + + pluralize: proc(number: int) -> int, +} + +Error :: enum { + /* + General return values. + */ + None = 0, + Empty_Translation_Catalog, + + /* + Couldn't find, open or read file. + */ + File_Error, + + /* + File too short. + */ + Premature_EOF, + + /* + GNU Gettext *.MO file errors. + */ + MO_File_Invalid_Signature, + MO_File_Unsupported_Version, + MO_File_Invalid, + MO_File_Incorrect_Plural_Count, +} + +/* + Several ways to use: + - get(key), which defaults to the singular form and i18n.ACTIVE catalog, or + - get(key, number), which returns the appropriate plural from the active catalog, or + - get(key, number, catalog) to grab text from a specific one. +*/ +get :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: string) { + /* + A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule. + */ + plural := 1 if number != 1 else 0 + + if catalog.pluralize != nil { + plural = catalog.pluralize(number) + } + return get_by_slot(key, plural, catalog) +} + +/* + Several ways to use: + - get_by_slot(key), which defaults to the singular form and i18n.ACTIVE catalog, or + - get_by_slot(key, slot), which returns the requested plural from the active catalog, or + - get_by_slot(key, slot, catalog) to grab text from a specific one. + + If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string. +*/ +get_by_slot :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) { + if catalog == nil { + /* + Return the key if the catalog catalog hasn't been initialized yet. + */ + return key + } + + /* + Return the translation from the requested slot if this key is known, else return the key. + */ + if translations, ok := catalog.k_v[key]; ok { + plural := min(max(0, slot), MAX_PLURALS - 1) + return translations[plural] + } + return key +} + +/* + Same for destroy: + - destroy(), to clean up the currently active catalog catalog i18n.ACTIVE + - destroy(catalog), to clean up a specific catalog. +*/ +destroy :: proc(catalog: ^Translation = ACTIVE) { + if catalog != nil { + strings.intern_destroy(&catalog.intern) + delete(catalog.k_v) + free(catalog) + } +} \ No newline at end of file From ba23bfb7b9eb32eb9bcf22b0364a25b6ae32203e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Apr 2022 20:12:32 +0200 Subject: [PATCH 0616/1052] [i18n] Allow multiple sections. --- core/i18n/gettext.odin | 11 ++++---- core/i18n/i18n.odin | 57 +++++++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/core/i18n/gettext.odin b/core/i18n/gettext.odin index 7918e217e..70c922cfb 100644 --- a/core/i18n/gettext.odin +++ b/core/i18n/gettext.odin @@ -57,6 +57,10 @@ parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allo translation.pluralize = pluralizer strings.intern_init(&translation.intern, allocator, allocator) + // Gettext MO files only have one section. + translation.k_v[""] = {} + section := &translation.k_v[""] + for n := u32(0); n < count; n += 1 { /* Grab string's original length and offset. @@ -94,7 +98,7 @@ parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allo for k in keys { interned_key := strings.intern_get(&translation.intern, string(k)) - interned_vals: [MAX_PLURALS]string = {} + interned_vals := make([]string, len(keys)) last_val: string i := 0 @@ -103,10 +107,7 @@ parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allo last_val = interned_vals[i] i += 1 } - for ; i < MAX_PLURALS; i += 1 { - interned_vals[i] = last_val - } - translation.k_v[interned_key] = interned_vals + section[interned_key] = interned_vals } delete(vals) delete(keys) diff --git a/core/i18n/i18n.odin b/core/i18n/i18n.odin index 7c72f9858..1ee19c2b4 100644 --- a/core/i18n/i18n.odin +++ b/core/i18n/i18n.odin @@ -15,18 +15,19 @@ import "core:strings" - Support for more translation catalog file formats. */ -MAX_PLURALS :: 10 - /* Currently active catalog. */ ACTIVE: ^Translation +// Allow between 1 and 255 plural forms. Default: 10. +MAX_PLURALS :: min(max(#config(ODIN_i18N_MAX_PLURAL_FORMS, 10), 1), 255) + /* The main data structure. This can be generated from various different file formats, as long as we have a parser for them. */ Translation :: struct { - k_v: map[string][MAX_PLURALS]string, + k_v: map[string]map[string][]string, intern: strings.Intern, pluralize: proc(number: int) -> int, @@ -64,7 +65,7 @@ Error :: enum { - get(key, number), which returns the appropriate plural from the active catalog, or - get(key, number, catalog) to grab text from a specific one. */ -get :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: string) { +get_single_section :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: string) { /* A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule. */ @@ -76,6 +77,25 @@ get :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: return get_by_slot(key, plural, catalog) } +/* + Several ways to use: + - get(section, key), which defaults to the singular form and i18n.ACTIVE catalog, or + - get(section, key, number), which returns the appropriate plural from the active catalog, or + - get(section, key, number, catalog) to grab text from a specific one. +*/ +get_by_section :: proc(section, key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: string) { + /* + A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule. + */ + plural := 1 if number != 1 else 0 + + if catalog.pluralize != nil { + plural = catalog.pluralize(number) + } + return get_by_slot(key, plural, catalog) +} +get :: proc{get_single_section, get_by_section} + /* Several ways to use: - get_by_slot(key), which defaults to the singular form and i18n.ACTIVE catalog, or @@ -84,10 +104,22 @@ get :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string. */ -get_by_slot :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) { - if catalog == nil { +get_by_slot_single_section :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) { + return get_by_slot_by_section("", key, slot, catalog) +} + +/* + Several ways to use: + - get_by_slot(key), which defaults to the singular form and i18n.ACTIVE catalog, or + - get_by_slot(key, slot), which returns the requested plural from the active catalog, or + - get_by_slot(key, slot, catalog) to grab text from a specific one. + + If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string. +*/ +get_by_slot_by_section :: proc(section, key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) { + if catalog == nil || section not_in catalog.k_v { /* - Return the key if the catalog catalog hasn't been initialized yet. + Return the key if the catalog catalog hasn't been initialized yet, or the section is not present. */ return key } @@ -95,12 +127,13 @@ get_by_slot :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> ( /* Return the translation from the requested slot if this key is known, else return the key. */ - if translations, ok := catalog.k_v[key]; ok { - plural := min(max(0, slot), MAX_PLURALS - 1) + if translations, ok := catalog.k_v[section][key]; ok { + plural := min(max(0, slot), len(catalog.k_v[section][key]) - 1) return translations[plural] } return key } +get_by_slot :: proc{get_by_slot_single_section, get_by_slot_by_section} /* Same for destroy: @@ -110,6 +143,12 @@ get_by_slot :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> ( destroy :: proc(catalog: ^Translation = ACTIVE) { if catalog != nil { strings.intern_destroy(&catalog.intern) + for section in &catalog.k_v { + for key in &catalog.k_v[section] { + delete(catalog.k_v[section][key]) + } + delete(catalog.k_v[section]) + } delete(catalog.k_v) free(catalog) } From 1289c96e2cf9fdcdb9c4fb4988f73c0e319fb329 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 00:29:55 +0200 Subject: [PATCH 0617/1052] [i18n] QT Linguist TS reader. --- core/encoding/xml/xml_reader.odin | 1 - core/i18n/example/i18n_example.odin | 56 ++++++++-- core/i18n/gettext.odin | 2 +- core/i18n/i18n.odin | 21 +++- core/i18n/qt_linguist.odin | 153 +++++++++++++++++++++++++++ tests/core/assets/XML/nl_NL-qt-ts.ts | 52 ++++----- 6 files changed, 243 insertions(+), 42 deletions(-) create mode 100644 core/i18n/qt_linguist.odin diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 636dd0ae4..6d0d4e1aa 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -87,7 +87,6 @@ Option_Flag :: enum { If a tag body has a comment, it will be stripped unless this option is given. */ Keep_Tag_Body_Comments, - } Option_Flags :: bit_set[Option_Flag; u16] diff --git a/core/i18n/example/i18n_example.odin b/core/i18n/example/i18n_example.odin index f9fb2a353..8c173ee4a 100644 --- a/core/i18n/example/i18n_example.odin +++ b/core/i18n/example/i18n_example.odin @@ -4,9 +4,9 @@ import "core:mem" import "core:fmt" import "core:i18n" -LOC :: i18n.get +_T :: i18n.get -_main :: proc() { +mo :: proc() { using fmt err: i18n.Error @@ -23,27 +23,60 @@ _main :: proc() { These are in the .MO catalog. */ println("-----") - println(LOC("")) + println(_T("")) println("-----") - println(LOC("There are 69,105 leaves here.")) + println(_T("There are 69,105 leaves here.")) println("-----") - println(LOC("Hellope, World!")) + println(_T("Hellope, World!")) /* For ease of use, pluralized lookup can use both singular and plural form as key for the same translation. */ println("-----") - printf(LOC("There is %d leaf.\n", 1), 1) - printf(LOC("There is %d leaf.\n", 42), 42) + printf(_T("There is %d leaf.\n", 1), 1) + printf(_T("There is %d leaf.\n", 42), 42) - printf(LOC("There are %d leaves.\n", 1), 1) - printf(LOC("There are %d leaves.\n", 42), 42) + printf(_T("There are %d leaves.\n", 1), 1) + printf(_T("There are %d leaves.\n", 42), 42) /* This isn't. */ println("-----") - println(LOC("Come visit us on Discord!")) + println(_T("Come visit us on Discord!")) +} + +qt :: proc() { + using fmt + + err: i18n.Error + + /* + Parse QT file and set it as the active translation so we can omit `get`'s "catalog" parameter. + */ + i18n.ACTIVE, err = i18n.parse_qt(#load("../../../tests/core/assets/XML/nl_NL-qt-ts.ts")) + defer i18n.destroy() + + fmt.printf("parse_qt returned %v\n", err) + if err != .None { + return + } + + /* + These are in the .TS catalog. + */ + println("--- Page section ---") + println("Page:Text for translation =", _T("Page", "Text for translation")) + println("-----") + println("Page:Also text to translate =", _T("Page", "Also text to translate")) + println("-----") + println("--- installscript section ---") + println("installscript:99 bottles of beer on the wall =", _T("installscript", "99 bottles of beer on the wall")) + println("-----") + println("--- apple_count section ---") + println("apple_count:%d apple(s) =") + println("\t 1 =", _T("apple_count", "%d apple(s)", 1)) + println("\t 42 =", _T("apple_count", "%d apple(s)", 42)) } main :: proc() { @@ -53,7 +86,8 @@ main :: proc() { mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) - _main() + // mo() + qt() if len(track.allocation_map) > 0 { println() diff --git a/core/i18n/gettext.odin b/core/i18n/gettext.odin index 70c922cfb..54c5a1111 100644 --- a/core/i18n/gettext.odin +++ b/core/i18n/gettext.odin @@ -2,7 +2,7 @@ package i18n /* A parser for GNU GetText .MO files. - Copyright 2021 Jeroen van Rijn . + Copyright 2021-2022 Jeroen van Rijn . Made available under Odin's BSD-3 license. A from-scratch implementation based after the specification found here: diff --git a/core/i18n/i18n.odin b/core/i18n/i18n.odin index 1ee19c2b4..36204efd9 100644 --- a/core/i18n/i18n.odin +++ b/core/i18n/i18n.odin @@ -2,7 +2,7 @@ package i18n /* Internationalization helpers. - Copyright 2021 Jeroen van Rijn . + Copyright 2021-2022 Jeroen van Rijn . Made available under Odin's BSD-3 license. List of contributors: @@ -26,8 +26,11 @@ MAX_PLURALS :: min(max(#config(ODIN_i18N_MAX_PLURAL_FORMS, 10), 1), 255) /* The main data structure. This can be generated from various different file formats, as long as we have a parser for them. */ + +Section :: map[string][]string + Translation :: struct { - k_v: map[string]map[string][]string, + k_v: map[string]Section, // k_v[section][key][plural_form] = ... intern: strings.Intern, pluralize: proc(number: int) -> int, @@ -39,6 +42,7 @@ Error :: enum { */ None = 0, Empty_Translation_Catalog, + Duplicate_Key, /* Couldn't find, open or read file. @@ -57,6 +61,17 @@ Error :: enum { MO_File_Unsupported_Version, MO_File_Invalid, MO_File_Incorrect_Plural_Count, + + /* + Qt Linguist *.TS file errors. + */ + TS_File_Parse_Error, + TS_File_Expected_Context, + TS_File_Expected_Context_Name, + TS_File_Expected_Source, + TS_File_Expected_Translation, + TS_File_Expected_NumerusForm, + } /* @@ -92,7 +107,7 @@ get_by_section :: proc(section, key: string, number := 0, catalog: ^Translation if catalog.pluralize != nil { plural = catalog.pluralize(number) } - return get_by_slot(key, plural, catalog) + return get_by_slot(section, key, plural, catalog) } get :: proc{get_single_section, get_by_section} diff --git a/core/i18n/qt_linguist.odin b/core/i18n/qt_linguist.odin new file mode 100644 index 000000000..65d51444e --- /dev/null +++ b/core/i18n/qt_linguist.odin @@ -0,0 +1,153 @@ +package i18n +/* + A parser for Qt Linguist TS files. + + Copyright 2022 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + A from-scratch implementation based after the specification found here: + https://doc.qt.io/qt-5/linguist-ts-file-format.html + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +import "core:os" +import "core:encoding/xml" +import "core:strings" + +TS_XML_Options := xml.Options{ + flags = { + .Input_May_Be_Modified, + .Must_Have_Prolog, + .Must_Have_DocType, + .Ignore_Unsupported, + .Unbox_CDATA, + .Decode_SGML_Entities, + }, + expected_doctype = "TS", +} + +parse_qt_linguist_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { + context.allocator = allocator + + ts, xml_err := xml.parse(data, TS_XML_Options) + defer xml.destroy(ts) + + if xml_err != .None || ts.element_count < 1 || ts.elements[0].ident != "TS" || len(ts.elements[0].children) == 0 { + return nil, .TS_File_Parse_Error + } + + /* + Initalize Translation, interner and optional pluralizer. + */ + translation = new(Translation) + translation.pluralize = pluralizer + strings.intern_init(&translation.intern, allocator, allocator) + + section: ^Section + + for child_id in ts.elements[0].children { + // These should be s. + child := ts.elements[child_id] + if child.ident != "context" { + return translation, .TS_File_Expected_Context + } + + // Find section name. + section_name_id, section_name_found := xml.find_child_by_ident(ts, child_id, "name") + if !section_name_found { + return translation, .TS_File_Expected_Context_Name, + } + + section_name := ts.elements[section_name_id].value + + if section_name not_in translation.k_v { + translation.k_v[section_name] = {} + } + section = &translation.k_v[section_name] + + // Find messages in section. + nth: int + for { + message_id, message_found := xml.find_child_by_ident(ts, child_id, "message", nth) + if !message_found { + break + } + + numerus_tag, _ := xml.find_attribute_val_by_key(ts, message_id, "numerus") + has_plurals := numerus_tag == "yes" + + // We must have a = key + source_id, source_found := xml.find_child_by_ident(ts, message_id, "source") + if !source_found { + return translation, .TS_File_Expected_Source + } + + // We must have a + translation_id, translation_found := xml.find_child_by_ident(ts, message_id, "translation") + if !translation_found { + return translation, .TS_File_Expected_Translation + } + + source := ts.elements[source_id] + xlat := ts.elements[translation_id] + + if source.value in section { + return translation, .Duplicate_Key + } + + if has_plurals { + if xlat.value != "" { + return translation, .TS_File_Expected_NumerusForm + } + + num_plurals: int + for { + numerus_id, numerus_found := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) + if !numerus_found { + break + } + num_plurals += 1 + } + + if num_plurals < 2 { + return translation, .TS_File_Expected_NumerusForm + } + section[source.value] = make([]string, num_plurals) + + num_plurals = 0 + for { + numerus_id, numerus_found := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) + if !numerus_found { + break + } + numerus := ts.elements[numerus_id] + section[source.value][num_plurals] = strings.intern_get(&translation.intern, numerus.value) + + num_plurals += 1 + } + } else { + // Single translation + section[source.value] = make([]string, 1) + section[source.value][0] = strings.intern_get(&translation.intern, xlat.value) + } + + nth += 1 + } + } + + return +} + +parse_qt_linguist_file :: proc(filename: string, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { + context.allocator = allocator + + data, data_ok := os.read_entire_file(filename) + defer delete(data) + + if !data_ok { return {}, .File_Error } + + return parse_qt_linguist_from_slice(data, pluralizer) +} + +parse_qt :: proc { parse_qt_linguist_file, parse_qt_linguist_from_slice } \ No newline at end of file diff --git a/tests/core/assets/XML/nl_NL-qt-ts.ts b/tests/core/assets/XML/nl_NL-qt-ts.ts index 6ec3f2f47..36c95ce2e 100644 --- a/tests/core/assets/XML/nl_NL-qt-ts.ts +++ b/tests/core/assets/XML/nl_NL-qt-ts.ts @@ -2,34 +2,34 @@ - Page - - Text for translation - commenting - Tekst om te vertalen - - - Also text to translate - some text - Ook tekst om te vertalen - + Page + + Text for translation + commenting + Tekst om te vertalen + + + Also text to translate + some text + Ook tekst om te vertalen + - installscript - - 99 bottles of beer on the wall - some new comments here - 99 flessen bier op de muur - + installscript + + 99 bottles of beer on the wall + some new comments here + 99 flessen bier op de muur + - apple_count - - %d apple(s) - - %d appel - %d appels - - - + apple_count + + %d apple(s) + + %d appel + %d appels + + + From 9ce64916e6f6db558d53b9a852e2169b937317f8 Mon Sep 17 00:00:00 2001 From: sduman Date: Thu, 28 Apr 2022 17:08:48 -0600 Subject: [PATCH 0618/1052] Add missing result parameter names This adds some missing result parameters names back to pop_front_safe. Currently it the procedure won't compile since it's referencing missing variable names. --- core/container/small_array/small_array.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index 5cd421c84..4dd16f30c 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -86,7 +86,7 @@ pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) { return } -pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (T, bool) { +pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) { if N > 0 && a.len > 0 { item = a.data[0] s := slice(a) @@ -114,4 +114,4 @@ push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) { append_elem :: push_back append_elems :: push_back_elems push :: proc{push_back, push_back_elems} -append :: proc{push_back, push_back_elems} \ No newline at end of file +append :: proc{push_back, push_back_elems} From 789ab99c4d2052f555721683ea0df8304508c9d1 Mon Sep 17 00:00:00 2001 From: awwdev Date: Fri, 29 Apr 2022 11:21:23 +0200 Subject: [PATCH 0619/1052] replaced a few [^]u8 with cstring --- vendor/OpenGL/impl.odin | 6 +++--- vendor/OpenGL/wrappers.odin | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/vendor/OpenGL/impl.odin b/vendor/OpenGL/impl.odin index 966f8467d..4c5ff57a3 100644 --- a/vendor/OpenGL/impl.odin +++ b/vendor/OpenGL/impl.odin @@ -1250,14 +1250,14 @@ impl_VertexAttribLFormat: proc "c" (attribindex: u32, size: i32, typ impl_VertexAttribBinding: proc "c" (attribindex: u32, bindingindex: u32) impl_VertexBindingDivisor: proc "c" (bindingindex: u32, divisor: u32) impl_DebugMessageControl: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool) -impl_DebugMessageInsert: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: [^]u8) +impl_DebugMessageInsert: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, message: cstring) impl_DebugMessageCallback: proc "c" (callback: debug_proc_t, userParam: rawptr) impl_GetDebugMessageLog: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8) -> u32 impl_PushDebugGroup: proc "c" (source: u32, id: u32, length: i32, message: cstring) impl_PopDebugGroup: proc "c" () -impl_ObjectLabel: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8) +impl_ObjectLabel: proc "c" (identifier: u32, name: u32, length: i32, label: cstring) impl_GetObjectLabel: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8) -impl_ObjectPtrLabel: proc "c" (ptr: rawptr, length: i32, label: [^]u8) +impl_ObjectPtrLabel: proc "c" (ptr: rawptr, length: i32, label: cstring) impl_GetObjectPtrLabel: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8) load_4_3 :: proc(set_proc_address: Set_Proc_Address_Type) { diff --git a/vendor/OpenGL/wrappers.odin b/vendor/OpenGL/wrappers.odin index 10a601eec..6113cf998 100644 --- a/vendor/OpenGL/wrappers.odin +++ b/vendor/OpenGL/wrappers.odin @@ -589,14 +589,14 @@ when !ODIN_DEBUG { VertexAttribBinding :: proc "c" (attribindex: u32, bindingindex: u32) { impl_VertexAttribBinding(attribindex, bindingindex) } VertexBindingDivisor :: proc "c" (bindingindex: u32, divisor: u32) { impl_VertexBindingDivisor(bindingindex, divisor) } DebugMessageControl :: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool) { impl_DebugMessageControl(source, type, severity, count, ids, enabled) } - DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8) { impl_DebugMessageInsert(source, type, id, severity, length, buf) } + DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, message: cstring) { impl_DebugMessageInsert(source, type, id, severity, length, message) } DebugMessageCallback :: proc "c" (callback: debug_proc_t, userParam: rawptr) { impl_DebugMessageCallback(callback, userParam) } GetDebugMessageLog :: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret } PushDebugGroup :: proc "c" (source: u32, id: u32, length: i32, message: cstring) { impl_PushDebugGroup(source, id, length, message) } PopDebugGroup :: proc "c" () { impl_PopDebugGroup() } - ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8) { impl_ObjectLabel(identifier, name, length, label) } + ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: cstring) { impl_ObjectLabel(identifier, name, length, label) } GetObjectLabel :: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectLabel(identifier, name, bufSize, length, label) } - ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: [^]u8) { impl_ObjectPtrLabel(ptr, length, label) } + ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: cstring) { impl_ObjectPtrLabel(ptr, length, label) } GetObjectPtrLabel :: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectPtrLabel(ptr, bufSize, length, label) } // VERSION_4_4 @@ -1389,14 +1389,14 @@ when !ODIN_DEBUG { VertexAttribBinding :: proc "c" (attribindex: u32, bindingindex: u32, loc := #caller_location) { impl_VertexAttribBinding(attribindex, bindingindex); debug_helper(loc, 0, attribindex, bindingindex) } VertexBindingDivisor :: proc "c" (bindingindex: u32, divisor: u32, loc := #caller_location) { impl_VertexBindingDivisor(bindingindex, divisor); debug_helper(loc, 0, bindingindex, divisor) } DebugMessageControl :: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool, loc := #caller_location) { impl_DebugMessageControl(source, type, severity, count, ids, enabled); debug_helper(loc, 0, source, type, severity, count, ids, enabled) } - DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8, loc := #caller_location) { impl_DebugMessageInsert(source, type, id, severity, length, buf); debug_helper(loc, 0, source, type, id, severity, length, buf) } + DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, message: cstring, loc := #caller_location) { impl_DebugMessageInsert(source, type, id, severity, length, message); debug_helper(loc, 0, source, type, id, severity, length, message) } DebugMessageCallback :: proc "c" (callback: debug_proc_t, userParam: rawptr, loc := #caller_location) { impl_DebugMessageCallback(callback, userParam); debug_helper(loc, 0, callback, userParam) } GetDebugMessageLog :: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8, loc := #caller_location) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); debug_helper(loc, 1, ret, count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret } PushDebugGroup :: proc "c" (source: u32, id: u32, length: i32, message: cstring, loc := #caller_location) { impl_PushDebugGroup(source, id, length, message); debug_helper(loc, 0, source, id, length, message) } PopDebugGroup :: proc "c" (loc := #caller_location) { impl_PopDebugGroup(); debug_helper(loc, 0) } - ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectLabel(identifier, name, length, label); debug_helper(loc, 0, identifier, name, length, label) } + ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: cstring, loc := #caller_location) { impl_ObjectLabel(identifier, name, length, label); debug_helper(loc, 0, identifier, name, length, label) } GetObjectLabel :: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectLabel(identifier, name, bufSize, length, label); debug_helper(loc, 0, identifier, name, bufSize, length, label) } - ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectPtrLabel(ptr, length, label); debug_helper(loc, 0, ptr, length, label) } + ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: cstring, loc := #caller_location) { impl_ObjectPtrLabel(ptr, length, label); debug_helper(loc, 0, ptr, length, label) } GetObjectPtrLabel :: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectPtrLabel(ptr, bufSize, length, label); debug_helper(loc, 0, ptr, bufSize, length, label) } // VERSION_4_4 From e9cfcf9eccb5af63ce0aa6a71894322f16beedc5 Mon Sep 17 00:00:00 2001 From: awwdev Date: Fri, 29 Apr 2022 11:26:57 +0200 Subject: [PATCH 0620/1052] fix typo in TexImage3D --- vendor/OpenGL/impl.odin | 2 +- vendor/OpenGL/wrappers.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/OpenGL/impl.odin b/vendor/OpenGL/impl.odin index 4c5ff57a3..530865cb0 100644 --- a/vendor/OpenGL/impl.odin +++ b/vendor/OpenGL/impl.odin @@ -199,7 +199,7 @@ load_1_1 :: proc(set_proc_address: Set_Proc_Address_Type) { // VERSION_1_2 impl_DrawRangeElements: proc "c" (mode: u32, start: u32, end: u32, count: i32, type: u32, indices: rawptr) -impl_TexImage3D: proc "c" (target: u32, level: i32, internalformat: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, type: u32, pixels: rawptr) +impl_TexImage3D: proc "c" (target: u32, level: i32, internalformat: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, type: u32, data: rawptr) impl_TexSubImage3D: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, pixels: rawptr) impl_CopyTexSubImage3D: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, x: i32, y: i32, width: i32, height: i32) diff --git a/vendor/OpenGL/wrappers.odin b/vendor/OpenGL/wrappers.odin index 6113cf998..c0b5304b0 100644 --- a/vendor/OpenGL/wrappers.odin +++ b/vendor/OpenGL/wrappers.odin @@ -70,7 +70,7 @@ when !ODIN_DEBUG { // VERSION_1_2 DrawRangeElements :: proc "c" (mode, start, end: u32, count: i32, type: u32, indices: rawptr) { impl_DrawRangeElements(mode, start, end, count, type, indices) } - TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels) } + TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, data: rawptr) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, data) } TexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: u32, pixels: rawptr) { impl_TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } CopyTexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, x, y, width, height: i32) { impl_CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height) } From 2e11a8da5b3d0031f99a7534b029f08dc0fe5a36 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 13:02:40 +0200 Subject: [PATCH 0621/1052] [i18n] Move to `core:text/i18n`. --- core/{ => text}/i18n/example/i18n_example.odin | 5 +++-- core/{ => text}/i18n/example/messages.pot | 0 core/{ => text}/i18n/example/nl_NL.mo | Bin core/{ => text}/i18n/example/nl_NL.po | 0 core/{ => text}/i18n/gettext.odin | 0 core/{ => text}/i18n/i18n.odin | 0 core/{ => text}/i18n/qt_linguist.odin | 0 7 files changed, 3 insertions(+), 2 deletions(-) rename core/{ => text}/i18n/example/i18n_example.odin (91%) rename core/{ => text}/i18n/example/messages.pot (100%) rename core/{ => text}/i18n/example/nl_NL.mo (100%) rename core/{ => text}/i18n/example/nl_NL.po (100%) rename core/{ => text}/i18n/gettext.odin (100%) rename core/{ => text}/i18n/i18n.odin (100%) rename core/{ => text}/i18n/qt_linguist.odin (100%) diff --git a/core/i18n/example/i18n_example.odin b/core/text/i18n/example/i18n_example.odin similarity index 91% rename from core/i18n/example/i18n_example.odin rename to core/text/i18n/example/i18n_example.odin index 8c173ee4a..32eb38a7d 100644 --- a/core/i18n/example/i18n_example.odin +++ b/core/text/i18n/example/i18n_example.odin @@ -2,7 +2,7 @@ package i18n_example import "core:mem" import "core:fmt" -import "core:i18n" +import "core:text/i18n" _T :: i18n.get @@ -31,6 +31,7 @@ mo :: proc() { /* For ease of use, pluralized lookup can use both singular and plural form as key for the same translation. + This is a quirk of the GetText format which has separate keys for their different plurals. */ println("-----") printf(_T("There is %d leaf.\n", 1), 1) @@ -54,7 +55,7 @@ qt :: proc() { /* Parse QT file and set it as the active translation so we can omit `get`'s "catalog" parameter. */ - i18n.ACTIVE, err = i18n.parse_qt(#load("../../../tests/core/assets/XML/nl_NL-qt-ts.ts")) + i18n.ACTIVE, err = i18n.parse_qt(#load("../../../../tests/core/assets/XML/nl_NL-qt-ts.ts")) defer i18n.destroy() fmt.printf("parse_qt returned %v\n", err) diff --git a/core/i18n/example/messages.pot b/core/text/i18n/example/messages.pot similarity index 100% rename from core/i18n/example/messages.pot rename to core/text/i18n/example/messages.pot diff --git a/core/i18n/example/nl_NL.mo b/core/text/i18n/example/nl_NL.mo similarity index 100% rename from core/i18n/example/nl_NL.mo rename to core/text/i18n/example/nl_NL.mo diff --git a/core/i18n/example/nl_NL.po b/core/text/i18n/example/nl_NL.po similarity index 100% rename from core/i18n/example/nl_NL.po rename to core/text/i18n/example/nl_NL.po diff --git a/core/i18n/gettext.odin b/core/text/i18n/gettext.odin similarity index 100% rename from core/i18n/gettext.odin rename to core/text/i18n/gettext.odin diff --git a/core/i18n/i18n.odin b/core/text/i18n/i18n.odin similarity index 100% rename from core/i18n/i18n.odin rename to core/text/i18n/i18n.odin diff --git a/core/i18n/qt_linguist.odin b/core/text/i18n/qt_linguist.odin similarity index 100% rename from core/i18n/qt_linguist.odin rename to core/text/i18n/qt_linguist.odin From 957ef8e8fe885fed32b62d532e642be5e756ea67 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 13:16:30 +0200 Subject: [PATCH 0622/1052] [i18n/xml] Move I18N XML files to their own assets directory. --- .../core/assets/I18N}/messages.pot | 0 .../core/assets/{XML => I18N}/nl_NL-qt-ts.ts | 0 .../{XML => I18N}/nl_NL-xliff-1.2.xliff | 0 .../{XML => I18N}/nl_NL-xliff-2.0.xliff | 0 .../core/assets/I18N}/nl_NL.mo | Bin .../core/assets/I18N}/nl_NL.po | 0 tests/core/encoding/xml/test_core_xml.odin | 33 ++++++------------ 7 files changed, 11 insertions(+), 22 deletions(-) rename {core/text/i18n/example => tests/core/assets/I18N}/messages.pot (100%) rename tests/core/assets/{XML => I18N}/nl_NL-qt-ts.ts (100%) rename tests/core/assets/{XML => I18N}/nl_NL-xliff-1.2.xliff (100%) rename tests/core/assets/{XML => I18N}/nl_NL-xliff-2.0.xliff (100%) rename {core/text/i18n/example => tests/core/assets/I18N}/nl_NL.mo (100%) rename {core/text/i18n/example => tests/core/assets/I18N}/nl_NL.po (100%) diff --git a/core/text/i18n/example/messages.pot b/tests/core/assets/I18N/messages.pot similarity index 100% rename from core/text/i18n/example/messages.pot rename to tests/core/assets/I18N/messages.pot diff --git a/tests/core/assets/XML/nl_NL-qt-ts.ts b/tests/core/assets/I18N/nl_NL-qt-ts.ts similarity index 100% rename from tests/core/assets/XML/nl_NL-qt-ts.ts rename to tests/core/assets/I18N/nl_NL-qt-ts.ts diff --git a/tests/core/assets/XML/nl_NL-xliff-1.2.xliff b/tests/core/assets/I18N/nl_NL-xliff-1.2.xliff similarity index 100% rename from tests/core/assets/XML/nl_NL-xliff-1.2.xliff rename to tests/core/assets/I18N/nl_NL-xliff-1.2.xliff diff --git a/tests/core/assets/XML/nl_NL-xliff-2.0.xliff b/tests/core/assets/I18N/nl_NL-xliff-2.0.xliff similarity index 100% rename from tests/core/assets/XML/nl_NL-xliff-2.0.xliff rename to tests/core/assets/I18N/nl_NL-xliff-2.0.xliff diff --git a/core/text/i18n/example/nl_NL.mo b/tests/core/assets/I18N/nl_NL.mo similarity index 100% rename from core/text/i18n/example/nl_NL.mo rename to tests/core/assets/I18N/nl_NL.mo diff --git a/core/text/i18n/example/nl_NL.po b/tests/core/assets/I18N/nl_NL.po similarity index 100% rename from core/text/i18n/example/nl_NL.po rename to tests/core/assets/I18N/nl_NL.po diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index a79c939c8..07cbc1779 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -27,7 +27,7 @@ TEST :: struct { /* Relative to ODIN_ROOT */ -TEST_FILE_PATH_PREFIX :: "tests/core/assets/XML" +TEST_FILE_PATH_PREFIX :: "tests/core/assets" TESTS :: []TEST{ /* @@ -35,23 +35,12 @@ TESTS :: []TEST{ */ { - /* - - - <恥ずべきフクロウ 올빼미_id="Foozle Hello, world!"]]>Barzle"> - <부끄러운:barzle> - ရှက်စရာ ဇီးကွက် - Owl of Shame - More CDATA Hello, world! Nonsense. - - */ - /* Tests UTF-8 idents and values. Test namespaced ident. Tests that nested partial CDATA start doesn't trip up parser. */ - filename = "utf8.xml", + filename = "XML/utf8.xml", options = { flags = { .Ignore_Unsupported, .Intern_Comments, @@ -66,7 +55,7 @@ TESTS :: []TEST{ Same as above. Unbox CDATA in data tag. */ - filename = "utf8.xml", + filename = "XML/utf8.xml", options = { flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, @@ -81,7 +70,7 @@ TESTS :: []TEST{ Simple Qt TS translation file. `core:i18n` requires it to be parsed properly. */ - filename = "nl_NL-qt-ts.ts", + filename = "I18N/nl_NL-qt-ts.ts", options = { flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, @@ -96,7 +85,7 @@ TESTS :: []TEST{ Simple XLiff 1.2 file. `core:i18n` requires it to be parsed properly. */ - filename = "nl_NL-xliff-1.2.xliff", + filename = "I18N/nl_NL-xliff-1.2.xliff", options = { flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, @@ -111,7 +100,7 @@ TESTS :: []TEST{ Simple XLiff 2.0 file. `core:i18n` requires it to be parsed properly. */ - filename = "nl_NL-xliff-2.0.xliff", + filename = "I18N/nl_NL-xliff-2.0.xliff", options = { flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, @@ -122,7 +111,7 @@ TESTS :: []TEST{ }, { - filename = "entities.html", + filename = "XML/entities.html", options = { flags = { .Ignore_Unsupported, .Intern_Comments, @@ -133,7 +122,7 @@ TESTS :: []TEST{ }, { - filename = "entities.html", + filename = "XML/entities.html", options = { flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, @@ -144,7 +133,7 @@ TESTS :: []TEST{ }, { - filename = "entities.html", + filename = "XML/entities.html", options = { flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, @@ -158,7 +147,7 @@ TESTS :: []TEST{ Then we test that certain errors are returned as expected. */ { - filename = "utf8.xml", + filename = "XML/utf8.xml", options = { flags = { .Ignore_Unsupported, .Intern_Comments, @@ -173,7 +162,7 @@ TESTS :: []TEST{ Parse the 8.2 MiB unicode.xml for good measure. */ { - filename = "unicode.xml", + filename = "XML/unicode.xml", options = { flags = { .Ignore_Unsupported, From 09e1c0fa27a262d7fbfaa5b3e305054304847e75 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 16:19:13 +0200 Subject: [PATCH 0623/1052] [i18n] Add tests. --- core/text/i18n/doc.odin | 111 ++++++++++++ core/text/i18n/example/i18n_example.odin | 99 ----------- core/text/i18n/gettext.odin | 9 +- core/text/i18n/i18n.odin | 8 + core/text/i18n/qt_linguist.odin | 8 +- examples/all/all_main.odin | 4 + tests/core/Makefile | 5 +- tests/core/assets/I18N/duplicate-key.ts | 22 +++ tests/core/build.bat | 7 +- tests/core/text/i18n/test_core_text_i18n.odin | 165 ++++++++++++++++++ 10 files changed, 329 insertions(+), 109 deletions(-) create mode 100644 core/text/i18n/doc.odin delete mode 100644 core/text/i18n/example/i18n_example.odin create mode 100644 tests/core/assets/I18N/duplicate-key.ts create mode 100644 tests/core/text/i18n/test_core_text_i18n.odin diff --git a/core/text/i18n/doc.odin b/core/text/i18n/doc.odin new file mode 100644 index 000000000..cff1ce11f --- /dev/null +++ b/core/text/i18n/doc.odin @@ -0,0 +1,111 @@ +//+ignore +package i18n + +/* + The i18n package is flexible and easy to use. + + It has one call to get a translation: `get`, which the user can alias into something like `T`. + + `get`, referred to as `T` here, has a few different signatures. + All of them will return the key if the entry can't be found in the active translation catalog. + + - `T(key)` returns the translation of `key`. + - `T(key, n)` returns a pluralized translation of `key` according to value `n`. + + - `T(section, key)` returns the translation of `key` in `section`. + - `T(section, key, n)` returns a pluralized translation of `key` in `section` according to value `n`. + + By default lookup take place in the global `i18n.ACTIVE` catalog for ease of use. + If you want to override which translation to use, for example in a language preview dialog, you can use the following: + + - `T(key, n, catalog)` returns the pluralized version of `key` from explictly supplied catalog. + - `T(section, key, n, catalog)` returns the pluralized version of `key` in `section` from explictly supplied catalog. + + If a catalog has translation contexts or sections, then ommitting it in the above calls looks up in section "". + + The default pluralization rule is n != 1, which is to say that passing n == 1 (or not passing n) returns the singular form. + Passing n != 1 returns plural form 1. + + Should a language not conform to this rule, you can pass a pluralizer procedure to the catalog parser. + This is a procedure that maps an integer to an integer, taking a value and returning which plural slot should be used. + + You can also assign it to a loaded catalog after parsing, of course. + + Some code examples follow. +*/ + +/* +```cpp +import "core:fmt" +import "core:text/i18n" + +T :: i18n.get + +mo :: proc() { + using fmt + + err: i18n.Error + + /* + Parse MO file and set it as the active translation so we can omit `get`'s "catalog" parameter. + */ + i18n.ACTIVE, err = i18n.parse_mo(#load("translations/nl_NL.mo")) + defer i18n.destroy() + + if err != .None { return } + + /* + These are in the .MO catalog. + */ + println("-----") + println(T("")) + println("-----") + println(T("There are 69,105 leaves here.")) + println("-----") + println(T("Hellope, World!")) + println("-----") + // We pass 1 into `T` to get the singular format string, then 1 again into printf. + printf(T("There is %d leaf.\n", 1), 1) + // We pass 42 into `T` to get the plural format string, then 42 again into printf. + printf(T("There is %d leaf.\n", 42), 42) + + /* + This isn't in the translation catalog, so the key is passed back untranslated. + */ + println("-----") + println(T("Come visit us on Discord!")) +} + +qt :: proc() { + using fmt + + err: i18n.Error + + /* + Parse QT file and set it as the active translation so we can omit `get`'s "catalog" parameter. + */ + i18n.ACTIVE, err = i18n.parse_qt(#load("translations/nl_NL-qt-ts.ts")) + defer i18n.destroy() + + if err != .None { + return + } + + /* + These are in the .TS catalog. As you can see they have sections. + */ + println("--- Page section ---") + println("Page:Text for translation =", T("Page", "Text for translation")) + println("-----") + println("Page:Also text to translate =", T("Page", "Also text to translate")) + println("-----") + println("--- installscript section ---") + println("installscript:99 bottles of beer on the wall =", T("installscript", "99 bottles of beer on the wall")) + println("-----") + println("--- apple_count section ---") + println("apple_count:%d apple(s) =") + println("\t 1 =", T("apple_count", "%d apple(s)", 1)) + println("\t 42 =", T("apple_count", "%d apple(s)", 42)) +} +``` +*/ \ No newline at end of file diff --git a/core/text/i18n/example/i18n_example.odin b/core/text/i18n/example/i18n_example.odin deleted file mode 100644 index 32eb38a7d..000000000 --- a/core/text/i18n/example/i18n_example.odin +++ /dev/null @@ -1,99 +0,0 @@ -package i18n_example - -import "core:mem" -import "core:fmt" -import "core:text/i18n" - -_T :: i18n.get - -mo :: proc() { - using fmt - - err: i18n.Error - - /* - Parse MO file and set it as the active translation so we can omit `get`'s "catalog" parameter. - */ - i18n.ACTIVE, err = i18n.parse_mo(#load("nl_NL.mo")) - defer i18n.destroy() - - if err != .None { return } - - /* - These are in the .MO catalog. - */ - println("-----") - println(_T("")) - println("-----") - println(_T("There are 69,105 leaves here.")) - println("-----") - println(_T("Hellope, World!")) - - /* - For ease of use, pluralized lookup can use both singular and plural form as key for the same translation. - This is a quirk of the GetText format which has separate keys for their different plurals. - */ - println("-----") - printf(_T("There is %d leaf.\n", 1), 1) - printf(_T("There is %d leaf.\n", 42), 42) - - printf(_T("There are %d leaves.\n", 1), 1) - printf(_T("There are %d leaves.\n", 42), 42) - - /* - This isn't. - */ - println("-----") - println(_T("Come visit us on Discord!")) -} - -qt :: proc() { - using fmt - - err: i18n.Error - - /* - Parse QT file and set it as the active translation so we can omit `get`'s "catalog" parameter. - */ - i18n.ACTIVE, err = i18n.parse_qt(#load("../../../../tests/core/assets/XML/nl_NL-qt-ts.ts")) - defer i18n.destroy() - - fmt.printf("parse_qt returned %v\n", err) - if err != .None { - return - } - - /* - These are in the .TS catalog. - */ - println("--- Page section ---") - println("Page:Text for translation =", _T("Page", "Text for translation")) - println("-----") - println("Page:Also text to translate =", _T("Page", "Also text to translate")) - println("-----") - println("--- installscript section ---") - println("installscript:99 bottles of beer on the wall =", _T("installscript", "99 bottles of beer on the wall")) - println("-----") - println("--- apple_count section ---") - println("apple_count:%d apple(s) =") - println("\t 1 =", _T("apple_count", "%d apple(s)", 1)) - println("\t 42 =", _T("apple_count", "%d apple(s)", 42)) -} - -main :: proc() { - using fmt - - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - - // mo() - qt() - - if len(track.allocation_map) > 0 { - println() - for _, v in track.allocation_map { - printf("%v Leaked %v bytes.\n", v.location, v.size) - } - } -} \ No newline at end of file diff --git a/core/text/i18n/gettext.odin b/core/text/i18n/gettext.odin index 54c5a1111..eed73855b 100644 --- a/core/text/i18n/gettext.odin +++ b/core/text/i18n/gettext.odin @@ -8,6 +8,9 @@ package i18n A from-scratch implementation based after the specification found here: https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html + Options are ignored as they're not applicable to this format. + They're part of the signature for consistency with other catalog formats. + List of contributors: Jeroen van Rijn: Initial implementation. */ @@ -15,7 +18,7 @@ import "core:os" import "core:strings" import "core:bytes" -parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { +parse_mo_from_slice :: proc(data: []u8, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { context.allocator = allocator /* An MO file should have at least a 4-byte magic, 2 x 2 byte version info, @@ -115,7 +118,7 @@ parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allo return } -parse_mo_file :: proc(filename: string, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { +parse_mo_file :: proc(filename: string, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { context.allocator = allocator data, data_ok := os.read_entire_file(filename) @@ -123,7 +126,7 @@ parse_mo_file :: proc(filename: string, pluralizer: proc(int) -> int = nil, allo if !data_ok { return {}, .File_Error } - return parse_mo_from_slice(data, pluralizer) + return parse_mo_from_slice(data, options, pluralizer, allocator) } parse_mo :: proc { parse_mo_file, parse_mo_from_slice } diff --git a/core/text/i18n/i18n.odin b/core/text/i18n/i18n.odin index 36204efd9..e007401af 100644 --- a/core/text/i18n/i18n.odin +++ b/core/text/i18n/i18n.odin @@ -74,6 +74,14 @@ Error :: enum { } +Parse_Options :: struct { + merge_sections: bool, +} + +DEFAULT_PARSE_OPTIONS :: Parse_Options{ + merge_sections = false, +} + /* Several ways to use: - get(key), which defaults to the singular form and i18n.ACTIVE catalog, or diff --git a/core/text/i18n/qt_linguist.odin b/core/text/i18n/qt_linguist.odin index 65d51444e..0a241c1aa 100644 --- a/core/text/i18n/qt_linguist.odin +++ b/core/text/i18n/qt_linguist.odin @@ -27,7 +27,7 @@ TS_XML_Options := xml.Options{ expected_doctype = "TS", } -parse_qt_linguist_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { +parse_qt_linguist_from_slice :: proc(data: []u8, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { context.allocator = allocator ts, xml_err := xml.parse(data, TS_XML_Options) @@ -59,7 +59,7 @@ parse_qt_linguist_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = return translation, .TS_File_Expected_Context_Name, } - section_name := ts.elements[section_name_id].value + section_name := "" if options.merge_sections else ts.elements[section_name_id].value if section_name not_in translation.k_v { translation.k_v[section_name] = {} @@ -139,7 +139,7 @@ parse_qt_linguist_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = return } -parse_qt_linguist_file :: proc(filename: string, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { +parse_qt_linguist_file :: proc(filename: string, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { context.allocator = allocator data, data_ok := os.read_entire_file(filename) @@ -147,7 +147,7 @@ parse_qt_linguist_file :: proc(filename: string, pluralizer: proc(int) -> int = if !data_ok { return {}, .File_Error } - return parse_qt_linguist_from_slice(data, pluralizer) + return parse_qt_linguist_from_slice(data, options, pluralizer, allocator) } parse_qt :: proc { parse_qt_linguist_file, parse_qt_linguist_from_slice } \ No newline at end of file diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 27f199062..36acf7714 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -56,6 +56,7 @@ import csv "core:encoding/csv" import hxa "core:encoding/hxa" import json "core:encoding/json" import varint "core:encoding/varint" +import xml "core:encoding/xml" import fmt "core:fmt" import hash "core:hash" @@ -100,6 +101,7 @@ import strings "core:strings" import sync "core:sync" import testing "core:testing" import scanner "core:text/scanner" +import i18n "core:text/i18n" import thread "core:thread" import time "core:time" @@ -158,6 +160,7 @@ _ :: csv _ :: hxa _ :: json _ :: varint +_ :: xml _ :: fmt _ :: hash _ :: image @@ -192,6 +195,7 @@ _ :: strings _ :: sync _ :: testing _ :: scanner +_ :: i18n _ :: thread _ :: time _ :: unicode diff --git a/tests/core/Makefile b/tests/core/Makefile index 2c24fef75..1405ae5c6 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -26,9 +26,10 @@ noise_test: $(ODIN) run math/noise -out:test_noise encoding_test: - $(ODIN) run encoding/hxa -collection:tests=.. -out:test_hxa - $(ODIN) run encoding/json -out:test_json + $(ODIN) run encoding/hxa -out:test_hxa -collection:tests=.. + $(ODIN) run encoding/json -out:test_json $(ODIN) run encoding/varint -out:test_varint + $(ODIN) run encoding/xml -out:test_xml math_test: $(ODIN) run math/test_core_math.odin -file -collection:tests=.. -out:test_core_math diff --git a/tests/core/assets/I18N/duplicate-key.ts b/tests/core/assets/I18N/duplicate-key.ts new file mode 100644 index 000000000..a38824d01 --- /dev/null +++ b/tests/core/assets/I18N/duplicate-key.ts @@ -0,0 +1,22 @@ + + + + + Page + + %d apple(s) + commenting + Tekst om te vertalen + + + + apple_count + + %d apple(s) + + %d appel + %d appels + + + + diff --git a/tests/core/build.bat b/tests/core/build.bat index 8e4ba1d15..77ff38038 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -64,4 +64,9 @@ echo --- echo --- echo Running core:reflect tests echo --- -%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe \ No newline at end of file +%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe + +echo --- +echo Running core:text/i18n tests +echo --- +%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe \ No newline at end of file diff --git a/tests/core/text/i18n/test_core_text_i18n.odin b/tests/core/text/i18n/test_core_text_i18n.odin new file mode 100644 index 000000000..ba668c4fd --- /dev/null +++ b/tests/core/text/i18n/test_core_text_i18n.odin @@ -0,0 +1,165 @@ +package test_core_text_i18n + +import "core:mem" +import "core:fmt" +import "core:os" +import "core:testing" +import "core:text/i18n" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} +T :: i18n.get + +Test :: struct { + section: string, + key: string, + val: string, + n: int, +} + +Test_Suite :: struct { + file: string, + loader: proc(string, i18n.Parse_Options, proc(int) -> int, mem.Allocator) -> (^i18n.Translation, i18n.Error), + err: i18n.Error, + options: i18n.Parse_Options, + tests: []Test, +} + +TESTS := []Test_Suite{ + { + file = "assets/I18N/nl_NL.mo", + loader = i18n.parse_mo_file, + tests = { + // These are in the catalog. + { "", "There are 69,105 leaves here.", "Er zijn hier 69.105 bladeren.", 1 }, + { "", "Hellope, World!", "Hallo, Wereld!", 1 }, + { "", "There is %d leaf.\n", "Er is %d blad.\n", 1 }, + { "", "There are %d leaves.\n", "Er is %d blad.\n", 1 }, + { "", "There is %d leaf.\n", "Er zijn %d bladeren.\n", 42 }, + { "", "There are %d leaves.\n", "Er zijn %d bladeren.\n", 42 }, + + // This isn't in the catalog, so should ruturn the key. + { "", "Come visit us on Discord!", "Come visit us on Discord!", 1 }, + }, + }, + + // QT Linguist with default loader options. + { + file = "assets/I18N/nl_NL-qt-ts.ts", + loader = i18n.parse_qt_linguist_file, + tests = { + // These are in the catalog. + { "Page", "Text for translation", "Tekst om te vertalen", 1}, + { "Page", "Also text to translate", "Ook tekst om te vertalen", 1}, + { "installscript", "99 bottles of beer on the wall", "99 flessen bier op de muur", 1}, + { "apple_count", "%d apple(s)", "%d appel", 1}, + { "apple_count", "%d apple(s)", "%d appels", 42}, + + // These aren't in the catalog, so should ruturn the key. + { "", "Come visit us on Discord!", "Come visit us on Discord!", 1 }, + { "Fake_Section", "Come visit us on Discord!", "Come visit us on Discord!", 1 }, + }, + }, + + // QT Linguist, merging sections. + { + file = "assets/I18N/nl_NL-qt-ts.ts", + loader = i18n.parse_qt_linguist_file, + options = {merge_sections = true}, + tests = { + // All of them are now in section "", lookup with original section should return the key. + { "", "Text for translation", "Tekst om te vertalen", 1}, + { "", "Also text to translate", "Ook tekst om te vertalen", 1}, + { "", "99 bottles of beer on the wall", "99 flessen bier op de muur", 1}, + { "", "%d apple(s)", "%d appel", 1}, + { "", "%d apple(s)", "%d appels", 42}, + + // All of them are now in section "", lookup with original section should return the key. + { "Page", "Text for translation", "Text for translation", 1}, + { "Page", "Also text to translate", "Also text to translate", 1}, + { "installscript", "99 bottles of beer on the wall", "99 bottles of beer on the wall", 1}, + { "apple_count", "%d apple(s)", "%d apple(s)", 1}, + { "apple_count", "%d apple(s)", "%d apple(s)", 42}, + }, + }, + + // QT Linguist, merging sections. Expecting .Duplicate_Key error because same key exists in more than 1 section. + { + file = "assets/I18N/duplicate-key.ts", + loader = i18n.parse_qt_linguist_file, + options = {merge_sections = true}, + err = .Duplicate_Key, + }, + + // QT Linguist, not merging sections. Shouldn't return error despite same key existing in more than 1 section. + { + file = "assets/I18N/duplicate-key.ts", + loader = i18n.parse_qt_linguist_file, + }, +} + +@test +tests :: proc(t: ^testing.T) { + using fmt + + cat: ^i18n.Translation + err: i18n.Error + + for suite in TESTS { + cat, err = suite.loader(suite.file, suite.options, nil, context.allocator) + + msg := fmt.tprintf("Expected loading %v to return %v, got %v", suite.file, suite.err, err) + expect(t, err == suite.err, msg) + + if err == .None { + for test in suite.tests { + val := T(test.section, test.key, test.n, cat) + + msg = fmt.tprintf("Expected key `%v` from section `%v`'s form for value `%v` to equal `%v`, got `%v`", test.key, test.section, test.n, test.val, val) + expect(t, val == test.val, msg) + } + } + i18n.destroy(cat) + } +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + t := testing.T{} + tests(&t) + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } +} \ No newline at end of file From ff0f0c447fb52b5836edb603e1fb8c3ae4ed4b50 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 18:10:13 +0200 Subject: [PATCH 0624/1052] [i18n] Fix segfault on destroy on Linux Forgot to intern the section string in QT TS loader. --- core/text/i18n/i18n.odin | 26 ++++++++++++++----------- core/text/i18n/qt_linguist.odin | 5 ++++- tests/core/assets/I18N/duplicate-key.ts | 18 ++++++++--------- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/core/text/i18n/i18n.odin b/core/text/i18n/i18n.odin index e007401af..9d030db16 100644 --- a/core/text/i18n/i18n.odin +++ b/core/text/i18n/i18n.odin @@ -163,16 +163,20 @@ get_by_slot :: proc{get_by_slot_single_section, get_by_slot_by_section} - destroy(), to clean up the currently active catalog catalog i18n.ACTIVE - destroy(catalog), to clean up a specific catalog. */ -destroy :: proc(catalog: ^Translation = ACTIVE) { - if catalog != nil { - strings.intern_destroy(&catalog.intern) - for section in &catalog.k_v { - for key in &catalog.k_v[section] { - delete(catalog.k_v[section][key]) - } - delete(catalog.k_v[section]) - } - delete(catalog.k_v) - free(catalog) +destroy :: proc(catalog: ^Translation = ACTIVE, allocator := context.allocator) { + context.allocator = allocator + + if catalog == nil { + return } + + for section in &catalog.k_v { + for key in &catalog.k_v[section] { + delete(catalog.k_v[section][key]) + } + delete(catalog.k_v[section]) + } + delete(catalog.k_v) + strings.intern_destroy(&catalog.intern) + free(catalog) } \ No newline at end of file diff --git a/core/text/i18n/qt_linguist.odin b/core/text/i18n/qt_linguist.odin index 0a241c1aa..e23e9aef4 100644 --- a/core/text/i18n/qt_linguist.odin +++ b/core/text/i18n/qt_linguist.odin @@ -59,7 +59,10 @@ parse_qt_linguist_from_slice :: proc(data: []u8, options := DEFAULT_PARSE_OPTION return translation, .TS_File_Expected_Context_Name, } - section_name := "" if options.merge_sections else ts.elements[section_name_id].value + section_name := strings.intern_get(&translation.intern, "") + if !options.merge_sections { + section_name = strings.intern_get(&translation.intern, ts.elements[section_name_id].value) + } if section_name not_in translation.k_v { translation.k_v[section_name] = {} diff --git a/tests/core/assets/I18N/duplicate-key.ts b/tests/core/assets/I18N/duplicate-key.ts index a38824d01..44c09d91d 100644 --- a/tests/core/assets/I18N/duplicate-key.ts +++ b/tests/core/assets/I18N/duplicate-key.ts @@ -10,13 +10,13 @@ - apple_count - - %d apple(s) - - %d appel - %d appels - - - + apple_count + + %d apple(s) + + %d appel + %d appels + + + From 36263399a0159d9ca3a109b50542638264e5642b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 18:13:46 +0200 Subject: [PATCH 0625/1052] [i18n] Enable i18n test on Linux. --- tests/core/Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 1405ae5c6..5c2918e30 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -2,7 +2,7 @@ ODIN=../../odin PYTHON=$(shell which python3) all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test + math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test download_test_assets: $(PYTHON) download_assets.py @@ -44,4 +44,7 @@ reflect_test: $(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect os_exit_test: - $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 \ No newline at end of file + $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 + +i18n_test: + $(ODIN) run text/i18n -out:test_core_i18n \ No newline at end of file From 819345caa6dccb983e496682a78829074f777011 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 18:28:42 +0200 Subject: [PATCH 0626/1052] Disable i18n test for *nix for now. --- tests/core/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 5c2918e30..2e1e4f78d 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -2,7 +2,7 @@ ODIN=../../odin PYTHON=$(shell which python3) all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test + math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test download_test_assets: $(PYTHON) download_assets.py From 9c9c2b483c93be2f6e78911d997229a4b543c66d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 29 Apr 2022 18:41:21 +0200 Subject: [PATCH 0627/1052] [i18n] Enable *nix tests again. --- core/text/i18n/qt_linguist.odin | 18 +++++++++--------- tests/core/Makefile | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/text/i18n/qt_linguist.odin b/core/text/i18n/qt_linguist.odin index e23e9aef4..15a88a42f 100644 --- a/core/text/i18n/qt_linguist.odin +++ b/core/text/i18n/qt_linguist.odin @@ -92,15 +92,15 @@ parse_qt_linguist_from_slice :: proc(data: []u8, options := DEFAULT_PARSE_OPTION return translation, .TS_File_Expected_Translation } - source := ts.elements[source_id] - xlat := ts.elements[translation_id] + source := strings.intern_get(&translation.intern, ts.elements[source_id].value) + xlat := strings.intern_get(&translation.intern, ts.elements[translation_id].value) - if source.value in section { + if source in section { return translation, .Duplicate_Key } if has_plurals { - if xlat.value != "" { + if xlat != "" { return translation, .TS_File_Expected_NumerusForm } @@ -116,7 +116,7 @@ parse_qt_linguist_from_slice :: proc(data: []u8, options := DEFAULT_PARSE_OPTION if num_plurals < 2 { return translation, .TS_File_Expected_NumerusForm } - section[source.value] = make([]string, num_plurals) + section[source] = make([]string, num_plurals) num_plurals = 0 for { @@ -124,15 +124,15 @@ parse_qt_linguist_from_slice :: proc(data: []u8, options := DEFAULT_PARSE_OPTION if !numerus_found { break } - numerus := ts.elements[numerus_id] - section[source.value][num_plurals] = strings.intern_get(&translation.intern, numerus.value) + numerus := strings.intern_get(&translation.intern, ts.elements[numerus_id].value) + section[source][num_plurals] = numerus num_plurals += 1 } } else { // Single translation - section[source.value] = make([]string, 1) - section[source.value][0] = strings.intern_get(&translation.intern, xlat.value) + section[source] = make([]string, 1) + section[source][0] = xlat } nth += 1 diff --git a/tests/core/Makefile b/tests/core/Makefile index 2e1e4f78d..5c2918e30 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -2,7 +2,7 @@ ODIN=../../odin PYTHON=$(shell which python3) all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test + math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test download_test_assets: $(PYTHON) download_assets.py From a223340c4498f49633d4108bb1ea5024071b1d53 Mon Sep 17 00:00:00 2001 From: bkrypt <4868093+bkrypt@users.noreply.github.com> Date: Fri, 15 Apr 2022 13:38:58 +0200 Subject: [PATCH 0628/1052] Update `vendor/miniaudio` to v0.11.9 --- vendor/miniaudio/common.odin | 108 +- vendor/miniaudio/data_conversion.odin | 291 +- vendor/miniaudio/decoding.odin | 102 +- vendor/miniaudio/device_io_procs.odin | 786 +- vendor/miniaudio/device_io_types.odin | 365 +- vendor/miniaudio/doc.odin | 2955 +- vendor/miniaudio/effects.odin | 300 + vendor/miniaudio/encoding.odin | 23 +- vendor/miniaudio/engine.odin | 341 + vendor/miniaudio/filtering.odin | 129 +- vendor/miniaudio/generation.odin | 28 +- vendor/miniaudio/job_queue.odin | 239 + vendor/miniaudio/lib/miniaudio.lib | Bin 1873426 -> 2767136 bytes vendor/miniaudio/logging.odin | 30 + vendor/miniaudio/node_graph.odin | 469 + vendor/miniaudio/resource_manager.odin | 288 + vendor/miniaudio/src/miniaudio.h | 34632 ++++++++++++++++++----- vendor/miniaudio/synchronization.odin | 152 + vendor/miniaudio/utilities.odin | 175 +- vendor/miniaudio/vfs.odin | 10 +- 20 files changed, 32998 insertions(+), 8425 deletions(-) create mode 100644 vendor/miniaudio/effects.odin create mode 100644 vendor/miniaudio/engine.odin create mode 100644 vendor/miniaudio/job_queue.odin create mode 100644 vendor/miniaudio/node_graph.odin create mode 100644 vendor/miniaudio/resource_manager.odin create mode 100644 vendor/miniaudio/synchronization.odin diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index 89e3d6bd2..d7b901714 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -13,13 +13,15 @@ when ODIN_OS == .Windows { handle :: distinct rawptr -/* SIMD alignment in bytes. Currently set to 64 bytes in preparation for future AVX-512 optimizations. */ -SIMD_ALIGNMENT :: 64 +/* SIMD alignment in bytes. Currently set to 32 bytes in preparation for future AVX optimizations. */ +SIMD_ALIGNMENT :: 32 -LOG_LEVEL_DEBUG :: 4 -LOG_LEVEL_INFO :: 3 -LOG_LEVEL_WARNING :: 2 -LOG_LEVEL_ERROR :: 1 +log_level :: enum c.int { + LOG_LEVEL_DEBUG = 4, + LOG_LEVEL_INFO = 3, + LOG_LEVEL_WARNING = 2, + LOG_LEVEL_ERROR = 1, +} channel :: enum u8 { @@ -158,13 +160,13 @@ result :: enum c.int { FAILED_TO_STOP_BACKEND_DEVICE = -303, } + MIN_CHANNELS :: 1 -MAX_CHANNELS :: 32 +MAX_CHANNELS :: 254 MAX_FILTER_ORDER :: 8 - stream_format :: enum c.int { pcm = 0, } @@ -175,9 +177,9 @@ stream_layout :: enum c.int { } dither_mode :: enum c.int { - none = 0, - rectangle, - triangle, + none = 0, + rectangle, + triangle, } format :: enum c.int { @@ -191,6 +193,7 @@ format :: enum c.int { s24 = 3, /* Tightly packed. 3 bytes per sample. */ s32 = 4, f32 = 5, + count, } standard_sample_rate :: enum u32 { @@ -224,7 +227,6 @@ channel_mix_mode :: enum c.int { rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */ simple, /* Drop excess channels; zeroed out extra channels. */ custom_weights, /* Use custom weights specified in ma_channel_router_config. */ - planar_blend = rectangular, default = rectangular, } @@ -257,6 +259,10 @@ lcg :: struct { state: i32, } + +/* Spinlocks are 32-bit for compatibility reasons. */ +spinlock :: distinct u32 + NO_THREADING :: false when !NO_THREADING { @@ -272,8 +278,6 @@ thread_priority :: enum c.int { default = 0, } -/* Spinlocks are 32-bit for compatibility reasons. */ -spinlock :: distinct u32 when ODIN_OS == .Windows { thread :: distinct rawptr @@ -297,69 +301,6 @@ when ODIN_OS == .Windows { } } - -@(default_calling_convention="c", link_prefix="ma_") -foreign lib { - /* - Locks a spinlock. - */ - spinlock_lock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result --- - - /* - Locks a spinlock, but does not yield() when looping. - */ - spinlock_lock_noyield :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result --- - - /* - Unlocks a spinlock. - */ - spinlock_unlock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result --- - - - /* - Creates a mutex. - - A mutex must be created from a valid context. A mutex is initially unlocked. - */ - mutex_init :: proc(pMutex: ^mutex) -> result --- - - /* - Deletes a mutex. - */ - mutex_uninit :: proc(pMutex: ^mutex) --- - - /* - Locks a mutex with an infinite timeout. - */ - mutex_lock :: proc(pMutex: ^mutex) --- - - /* - Unlocks a mutex. - */ - mutex_unlock :: proc(pMutex: ^mutex) --- - - - /* - Initializes an auto-reset event. - */ - event_init :: proc(pEvent: ^event) -> result --- - - /* - Uninitializes an auto-reset event. - */ - event_uninit :: proc(pEvent: ^event) --- - - /* - Waits for the specified auto-reset event to become signalled. - */ - event_wait :: proc(pEvent: ^event) -> result --- - - /* - Signals the specified auto-reset event. - */ - event_signal :: proc(pEvent: ^event) -> result --- -} - } /* NO_THREADING */ @@ -385,17 +326,22 @@ foreign lib { result_description :: proc(result: result) -> cstring --- /* - malloc(). Calls MA_MALLOC(). + malloc() */ malloc :: proc(sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr --- /* - realloc(). Calls MA_REALLOC(). + calloc() + */ + calloc :: proc(sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr --- + + /* + realloc() */ realloc :: proc(p: rawptr, sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr --- /* - free(). Calls MA_FREE(). + free() */ free :: proc(p: rawptr, pAllocationCallbacks: ^allocation_callbacks) --- @@ -417,7 +363,7 @@ foreign lib { /* Blends two frames in floating point format. */ - blend_f32 :: proc(pOut, pInA, pInB: ^f32, factor: f32, channels: u32) --- + blend_f32 :: proc(pOut, pInA, pInB: [^]f32, factor: f32, channels: u32) --- /* Retrieves the size of a sample in bytes for the given format. diff --git a/vendor/miniaudio/data_conversion.odin b/vendor/miniaudio/data_conversion.odin index 7167270a1..ffcf2fcb3 100644 --- a/vendor/miniaudio/data_conversion.odin +++ b/vendor/miniaudio/data_conversion.odin @@ -36,77 +36,106 @@ linear_resampler_config :: struct { } linear_resampler :: struct { - config: linear_resampler_config, + config: linear_resampler_config, inAdvanceInt: u32, inAdvanceFrac: u32, inTimeInt: u32, inTimeFrac: u32, x0: struct #raw_union { - f32: [MAX_CHANNELS]f32, - s16: [MAX_CHANNELS]i16, + f32: [^]f32, + s16: [^]i16, }, /* The previous input frame. */ x1: struct #raw_union { - f32: [MAX_CHANNELS]f32, - s16: [MAX_CHANNELS]i16, + f32: [^]f32, + s16: [^]i16, }, /* The next input frame. */ lpf: lpf, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, +} + +resampling_backend :: struct {} +resampling_backend_vtable :: struct { + onGetHeapSize: proc "c" (pUserData: rawptr, pConfig: ^resampler_config, pHeapSizeInBytes: ^c.size_t) -> result, + onInit: proc "c" (pUserData: rawptr, pConfig: ^resampler_config, pHeap: rawptr, ppBackend: ^^resampling_backend) -> result, + onUninit: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, pAllocationCallbacks: ^allocation_callbacks), + onProcess: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result, + onSetRate: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, sampleRateIn: u32, sampleRateOut: u32) -> result, /* Optional. Rate changes will be disabled. */ + onGetInputLatency: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> u64, /* Optional. Latency will be reported as 0. */ + onGetOutputLatency: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> u64, /* Optional. Latency will be reported as 0. */ + onGetRequiredInputFrameCount: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, outputFrameCount: u64, pInputFrameCount: ^u64) -> result, /* Optional. Latency mitigation will be disabled. */ + onGetExpectedOutputFrameCount: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result, /* Optional. Latency mitigation will be disabled. */ + onReset: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> result, } resample_algorithm :: enum { linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */ - speex, + custom, } resampler_config :: struct { - format: format, /* Must be either ma_format_f32 or ma_format_s16. */ - channels: u32, - sampleRateIn: u32, - sampleRateOut: u32, - algorithm: resample_algorithm, + format: format, /* Must be either ma_format_f32 or ma_format_s16. */ + channels: u32, + sampleRateIn: u32, + sampleRateOut: u32, + algorithm: resample_algorithm, /* When set to ma_resample_algorithm_custom, pBackendVTable will be used. */ + pBackendVTable: ^resampling_backend_vtable, + pBackendUserData: rawptr, linear: struct { lpfOrder: u32, - lpfNyquistFactor: f64, - }, - speex: struct { - quality: c.int, /* 0 to 10. Defaults to 3. */ }, } resampler :: struct { - config: resampler_config, + pBackend: ^resampling_backend, + pBackendVTable: ^resampling_backend_vtable, + pBackendUserData: rawptr, + format: format, + channels: u32, + sampleRateIn: u32, + sampleRateOut: u32, state: struct #raw_union { linear: linear_resampler, - speex: struct { - pSpeexResamplerState: rawptr, /* SpeexResamplerState* */ - }, - }, + }, /* State for stock resamplers so we can avoid a malloc. For stock resamplers, pBackend will point here. */ + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } @(default_calling_convention="c", link_prefix="ma_") foreign lib { linear_resampler_config_init :: proc(format: format, channels: u32, sampleRateIn, sampleRateOut: u32) -> linear_resampler_config --- - linear_resampler_init :: proc(pConfig: ^linear_resampler_config, pResampler: ^linear_resampler) -> result --- - linear_resampler_uninit :: proc(pResampler: ^linear_resampler) --- + linear_resampler_get_heap_size :: proc(pConfig: ^linear_resampler_config, pHeapSizeInBytes: ^c.size_t) -> result --- + linear_resampler_init_preallocated :: proc(pConfig: ^linear_resampler_config, pHeap: rawptr, pResampler: ^linear_resampler) -> result --- + linear_resampler_init :: proc(pConfig: ^linear_resampler_config, pAllocationCallbacks: ^allocation_callbacks, pResampler: ^linear_resampler) -> result --- + linear_resampler_uninit :: proc(pResampler: ^linear_resampler, pAllocationCallbacks: ^allocation_callbacks) --- linear_resampler_process_pcm_frames :: proc(pResampler: ^linear_resampler, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result --- linear_resampler_set_rate :: proc(pResampler: ^linear_resampler, sampleRateIn, sampleRateOut: u32) -> result --- linear_resampler_set_rate_ratio :: proc(pResampler: ^linear_resampler, ratioInOut: f32) -> result --- - linear_resampler_get_required_input_frame_count :: proc(pResampler: ^linear_resampler, outputFrameCount: u64) -> u64 --- - linear_resampler_get_expected_output_frame_count :: proc(pResampler: ^linear_resampler, inputFrameCount: u64) -> u64 --- linear_resampler_get_input_latency :: proc(pResampler: ^linear_resampler) -> u64 --- linear_resampler_get_output_latency :: proc(pResampler: ^linear_resampler) -> u64 --- + linear_resampler_get_required_input_frame_count :: proc(pResampler: ^linear_resampler, outputFrameCount: u64, pInputFrameCount: ^u64) -> result --- + linear_resampler_get_expected_output_frame_count :: proc(pResampler: ^linear_resampler, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result --- + linear_resampler_reset :: proc(pResampler: ^linear_resampler) -> result --- resampler_config_init :: proc(format: format, channels: u32, sampleRateIn, sampleRateOut: u32, algorithm: resample_algorithm) -> resampler_config --- + resampler_get_heap_size :: proc(pConfig: ^resampler_config, pHeapSizeInBytes: ^c.size_t) -> result --- + resampler_init_preallocated :: proc(pConfig: ^resampler_config, pHeap: rawptr, pResampler: ^resampler) -> result --- + /* Initializes a new resampler object from a config. */ - resampler_init :: proc(pConfig: ^resampler_config, pResampler: ^resampler) -> result --- + resampler_init :: proc(pConfig: ^resampler_config, pAllocationCallbacks: ^allocation_callbacks, pResampler: ^resampler) -> result --- /* Uninitializes a resampler. */ - resampler_uninit :: proc(pResampler: ^resampler) --- + resampler_uninit :: proc(pResampler: ^resampler, pAllocationCallbacks: ^allocation_callbacks) --- /* Converts the given input data. @@ -145,23 +174,6 @@ foreign lib { */ resampler_set_rate_ratio :: proc(pResampler: ^resampler, ratio: f32) -> result --- - - /* - Calculates the number of whole input frames that would need to be read from the client in order to output the specified - number of output frames. - - The returned value does not include cached input frames. It only returns the number of extra frames that would need to be - read from the input buffer in order to output the specified number of output frames. - */ - resampler_get_required_input_frame_count :: proc(pResampler: ^resampler, outputFrameCount: u64) -> u64 --- - - /* - Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of - input frames. - */ - resampler_get_expected_output_frame_count :: proc(pResampler: ^resampler, inputFrameCount: u64) -> u64 --- - - /* Retrieves the latency introduced by the resampler in input frames. */ @@ -171,6 +183,26 @@ foreign lib { Retrieves the latency introduced by the resampler in output frames. */ resampler_get_output_latency :: proc(pResampler: ^resampler) -> u64 --- + + /* + Calculates the number of whole input frames that would need to be read from the client in order to output the specified + number of output frames. + + The returned value does not include cached input frames. It only returns the number of extra frames that would need to be + read from the input buffer in order to output the specified number of output frames. + */ + resampler_get_required_input_frame_count :: proc(pResampler: ^resampler, outputFrameCount: u64, pInputFrameCount: ^u64) -> result --- + + /* + Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of + input frames. + */ + resampler_get_expected_output_frame_count :: proc(pResampler: ^resampler, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result --- + + /* + Resets the resampler's timer and clears it's internal cache. + */ + resampler_reset :: proc(pResampler: ^resampler) -> result --- } @@ -179,42 +211,63 @@ foreign lib { Channel Conversion **************************************************************************************************************************************************************/ +channel_conversion_path :: enum c.int { + unknown, + passthrough, + mono_out, /* Converting to mono. */ + mono_in, /* Converting from mono. */ + shuffle, /* Simple shuffle. Will use this when all channels are present in both input and output channel maps, but just in a different order. */ + weights, /* Blended based on weights. */ +} + +mono_expansion_mode :: enum c.int { + duplicate = 0, /* The default. */ + average, /* Average the mono channel across all channels. */ + stereo_only, /* Duplicate to the left and right channels only and ignore the others. */ + default = duplicate, +} + channel_converter_config :: struct { - format: format, - channelsIn: u32, - channelsOut: u32, - channelMapIn: [MAX_CHANNELS]channel, - channelMapOut: [MAX_CHANNELS]channel, - mixingMode: channel_mix_mode, - weights: [MAX_CHANNELS][MAX_CHANNELS]f32, /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ + format: format, + channelsIn: u32, + channelsOut: u32, + pChannelMapIn: [^]channel, + pChannelMapOut: [^]channel, + mixingMode: channel_mix_mode, + ppWeights: ^[^]f32, /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ } channel_converter :: struct { - format: format, - channelsIn: u32, - channelsOut: u32, - channelMapIn: [MAX_CHANNELS]channel, - channelMapOut: [MAX_CHANNELS]channel, - mixingMode: channel_mix_mode, - weights: struct #raw_union { - f32: [MAX_CHANNELS][MAX_CHANNELS]f32, - s16: [MAX_CHANNELS][MAX_CHANNELS]i32, + format: format, + channelsIn: u32, + channelsOut: u32, + mixingMode: channel_mix_mode, + conversionPath: channel_conversion_path, + pChannelMapIn: [^]channel, + pChannelMapOut: [^]channel, + pShuffleTable: [^]u8, + weights: struct #raw_union { /* [in][out] */ + f32: ^[^]f32, + s16: ^[^]i32, }, - isPassthrough: b8, - isSimpleShuffle: b8, - isSimpleMonoExpansion: b8, - isStereoToMono: b8, - shuffleTable: [MAX_CHANNELS]u8, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } @(default_calling_convention="c", link_prefix="ma_") foreign lib { - channel_converter_config_init :: proc(format: format, channelsIn: u32, pChannelMapIn: ^channel, channelsOut: u32, pChannelMapOut: ^channel, mixingMode: channel_mix_mode) -> channel_converter_config --- + channel_converter_config_init :: proc(format: format, channelsIn: u32, pChannelMapIn: [^]channel, channelsOut: u32, pChannelMapOut: [^]channel, mixingMode: channel_mix_mode) -> channel_converter_config --- - channel_converter_init :: proc(pConfig: ^channel_converter_config, pConverter: ^channel_converter) -> result --- - channel_converter_uninit :: proc(pConverter: ^channel_converter) --- - channel_converter_process_pcm_frames :: proc(pConverter: ^channel_converter, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- + channel_converter_get_heap_size :: proc(pConfig: ^channel_converter_config, pHeapSizeInBytes: ^c.size_t) -> result --- + channel_converter_init_preallocated :: proc(pConfig: ^channel_converter_config, pHeap: rawptr, pConverter: ^channel_converter) -> result --- + channel_converter_init :: proc(pConfig: ^channel_converter_config, pAllocationCallbacks: ^allocation_callbacks, pConverter: ^channel_converter) -> result --- + channel_converter_uninit :: proc(pConverter: ^channel_converter, pAllocationCallbacks: ^allocation_callbacks) --- + channel_converter_process_pcm_frames :: proc(pConverter: ^channel_converter, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result --- + channel_converter_get_input_channel_map :: proc(pConverter: ^channel_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- + channel_converter_get_output_channel_map :: proc(pConverter: ^channel_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- } @@ -224,32 +277,39 @@ Data Conversion **************************************************************************************************************************************************************/ data_converter_config :: struct { - formatIn: format, - formatOut: format, - channelsIn: u32, - channelsOut: u32, - sampleRateIn: u32, - sampleRateOut: u32, - channelMapIn: [MAX_CHANNELS]channel, - channelMapOut: [MAX_CHANNELS]channel, - ditherMode: dither_mode, - channelMixMode: channel_mix_mode, - channelWeights: [MAX_CHANNELS][MAX_CHANNELS]f32, /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */ - resampling: struct { - algorithm: resample_algorithm, - allowDynamicSampleRate: b32, - linear: struct { - lpfOrderL: u32, - lpfNyquistFactor: f64, - }, - speex: struct { - quality: c.int, - }, - }, + formatIn: format, + formatOut: format, + channelsIn: u32, + channelsOut: u32, + sampleRateIn: u32, + sampleRateOut: u32, + pChannelMapIn: [^]channel, + pChannelMapOut: [^]channel, + ditherMode: dither_mode, + channelMixMode: channel_mix_mode, + ppChannelWeights: ^[^]f32, /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */ + allowDynamicSampleRate: b32, + resampling: resampler_config, +} + +data_converter_execution_path :: enum c.int { + passthrough, /* No conversion. */ + format_only, /* Only format conversion. */ + channels_only, /* Only channel conversion. */ + resample_only, /* Only resampling. */ + resample_first, /* All conversions, but resample as the first step. */ + channels_first, /* All conversions, but channels as the first step. */ } data_converter :: struct { - config: data_converter_config, + formatIn: format, + formatOut: format, + channelsIn: u32, + channelsOut: u32, + sampleRateIn: u32, + sampleRateOut: u32, + ditherMode: dither_mode, + executionPath: data_converter_execution_path, /* The execution path the data converter will follow when processing. */ channelConverter: channel_converter, resampler: resampler, hasPreFormatConversion: b8, @@ -257,6 +317,10 @@ data_converter :: struct { hasChannelConverter: b8, hasResampler: b8, isPassthrough: b8, + + /* Memory management. */ + _ownsHeap: b8, + _pHeap: rawptr, } @@ -265,15 +329,20 @@ foreign lib { data_converter_config_init_default :: proc() -> data_converter_config --- data_converter_config_init :: proc(formatIn, formatOut: format, channelsIn, channelsOut: u32, sampleRateIn, sampleRateOut: u32) -> data_converter_config --- - data_converter_init :: proc(pConfig: ^data_converter_config, pConverter: ^data_converter) -> result --- - data_converter_uninit :: proc(pConverter: ^data_converter) --- + data_converter_get_heap_size :: proc(pConfig: ^data_converter_config, pHeapSizeInBytes: ^c.size_t) -> result --- + data_converter_init_preallocated :: proc(pConfig: ^data_converter_config, pHeap: rawptr, pConverter: ^data_converter) -> result --- + data_converter_init :: proc(pConfig: ^data_converter_config, pAllocationCallbacks: ^allocation_callbacks, pConverter: ^data_converter) -> result --- + data_converter_uninit :: proc(pConverter: ^data_converter, pAllocationCallbacks: ^allocation_callbacks) --- data_converter_process_pcm_frames :: proc(pConverter: ^data_converter, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result --- data_converter_set_rate :: proc(pConverter: ^data_converter, sampleRateIn, sampleRateOut: u32) -> result --- data_converter_set_rate_ratio :: proc(pConverter: ^data_converter, ratioInOut: f32) -> result --- - data_converter_get_required_input_frame_count :: proc(pConverter: ^data_converter, outputFrameCount: u64) -> u64 --- - data_converter_get_expected_output_frame_count :: proc(pConverter: ^data_converter, inputFrameCount: u64) -> u64 --- data_converter_get_input_latency :: proc(pConverter: ^data_converter) -> u64 --- data_converter_get_output_latency :: proc(pConverter: ^data_converter) -> u64 --- + data_converter_get_required_input_frame_count :: proc(pConverter: ^data_converter, outputFrameCount: u64, pInputFrameCount: ^u64) -> result --- + data_converter_get_expected_output_frame_count :: proc(pConverter: ^data_converter, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result --- + data_converter_get_input_channel_map :: proc(pConverter: ^data_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- + data_converter_get_output_channel_map :: proc(pConverter: ^data_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- + data_converter_reset :: proc(pConverter: ^data_converter) -> result --- } /************************************************************************************************************************************************************ @@ -332,43 +401,40 @@ CHANNEL_INDEX_NULL :: 255 @(default_calling_convention="c", link_prefix="ma_") foreign lib { - /* Retrieves the channel position of the specified channel based on miniaudio's default channel map. */ - channel_map_get_default_channel :: proc(channelCount: u32, channelIndex: u32) -> channel --- - /* Retrieves the channel position of the specified channel in the given channel map. The pChannelMap parameter can be null, in which case miniaudio's default channel map will be assumed. */ - channel_map_get_channel :: proc(pChannelMap: ^channel, channelCount: u32, channelIndex: u32) -> channel --- + channel_map_get_channel :: proc(pChannelMap: [^]channel, channelCount: u32, channelIndex: u32) -> channel --- /* Initializes a blank channel map. When a blank channel map is specified anywhere it indicates that the native channel map should be used. */ - channel_map_init_blank :: proc(channels: u32, pChannelMap: ^channel) --- + channel_map_init_blank :: proc(pChannelMap: [^]channel, channels: u32) --- /* Helper for retrieving a standard channel map. - The output channel map buffer must have a capacity of at least `channels`. + The output channel map buffer must have a capacity of at least `channelMapCap`. */ - get_standard_channel_map :: proc(standardChannelMap: standard_channel_map, channels: u32, pChannelMap: ^channel) --- + channel_map_init_standard :: proc(standardChannelMap: standard_channel_map, pChannelMap: [^]channel, channelMapCap: c.size_t, channels: u32) --- /* Copies a channel map. Both input and output channel map buffers must have a capacity of at at least `channels`. */ - channel_map_copy :: proc(pOut: ^channel, pIn: ^channel, channels: u32) --- + channel_map_copy :: proc(pOut: [^]channel, pIn: [^]channel, channels: u32) --- /* Copies a channel map if one is specified, otherwise copies the default channel map. The output buffer must have a capacity of at least `channels`. If not NULL, the input channel map must also have a capacity of at least `channels`. */ - channel_map_copy_or_default :: proc(pOut: ^channel, pIn: ^channel, channels: u32) --- + channel_map_copy_or_default :: proc(pOut: [^]channel, channelMapCapOut: c.size_t, pIn: [^]channel, channels: u32) --- /* @@ -378,12 +444,12 @@ foreign lib { is usually treated as a passthrough. Invalid channel maps: - - A channel map with no channels - - A channel map with more than one channel and a mono channel + - A channel map with no channels + - A channel map with more than one channel and a mono channel The channel map buffer must have a capacity of at least `channels`. */ - channel_map_valid :: proc(channels: u32, pChannelMap: ^channel) -> b32 --- + channel_map_is_valid :: proc(pChannelMap: [^]channel, channels: u32) -> b32 --- /* Helper for comparing two channel maps for equality. @@ -392,23 +458,24 @@ foreign lib { Both channels map buffers must have a capacity of at least `channels`. */ - channel_map_equal :: proc(channels: u32, pChannelMapA, pChannelMapB: ^channel) -> b32 --- + channel_map_is_equal :: proc(pChannelMapA, pChannelMapB: [^]channel, channels: u32) -> b32 --- /* Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE). The channel map buffer must have a capacity of at least `channels`. */ - channel_map_blank :: proc(channels: u32, pChannelMap: ^channel) -> b32 --- + channel_map_is_blank :: proc(pChannelMap: [^]channel, channels: u32) -> b32 --- /* Helper for determining whether or not a channel is present in the given channel map. The channel map buffer must have a capacity of at least `channels`. */ - channel_map_contains_channel_position :: proc(channels: u32, pChannelMap: ^channel, channelPosition: channel) -> b32 --- + channel_map_contains_channel_position :: proc(channels: u32, pChannelMap: [^]channel, channelPosition: channel) -> b32 --- } + /************************************************************************************************************************************************************ Conversion Helpers @@ -461,9 +528,9 @@ foreign lib { rb_uninit :: proc(pRB: ^rb) --- rb_reset :: proc(pRB: ^rb) --- rb_acquire_read :: proc(pRB: ^rb, pSizeInBytes: ^c.size_t, ppBufferOut: ^rawptr) -> result --- - rb_commit_read :: proc(pRB: ^rb, sizeInBytes: c.size_t, pBufferOut: rawptr) -> result --- + rb_commit_read :: proc(pRB: ^rb, sizeInBytes: c.size_t) -> result --- rb_acquire_write :: proc(pRB: ^rb, pSizeInBytes: ^c.size_t, ppBufferOut: ^rawptr) -> result --- - rb_commit_write :: proc(pRB: ^rb, sizeInBytes: c.size_t, pBufferOut: rawptr) -> result --- + rb_commit_write :: proc(pRB: ^rb, sizeInBytes: c.size_t) -> result --- rb_seek_read :: proc(pRB: ^rb, offsetInBytes: c.size_t) -> result --- rb_seek_write :: proc(pRB: ^rb, offsetInBytes: c.size_t) -> result --- rb_pointer_distance :: proc(pRB: ^rb) -> i32 --- /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. Will return the number of bytes that can be read before the read pointer hits the write pointer. */ diff --git a/vendor/miniaudio/decoding.odin b/vendor/miniaudio/decoding.odin index dcf3b7a1a..003f6f950 100644 --- a/vendor/miniaudio/decoding.odin +++ b/vendor/miniaudio/decoding.odin @@ -22,68 +22,63 @@ you do your own synchronization. decoding_backend_config :: struct { preferredFormat: format, + seekPointCount: u32, /* Set to > 0 to generate a seektable if the decoding backend supports it. */ } @(default_calling_convention="c", link_prefix="ma_") foreign lib { - decoding_backend_config_init :: proc(preferredFormat: format) -> decoding_backend_config --- + decoding_backend_config_init :: proc(preferredFormat: format, seekPointCount: u32) -> decoding_backend_config --- } decoding_backend_vtable :: struct { onInit: proc "c" (pUserData: rawptr, onRead: decoder_read_proc, onSeek: decoder_seek_proc, onTell: decoder_tell_proc, pReadSeekTellUserData: rawptr, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, - onInitFile: proc "c" (pUserData: rawptr, pFilePath: cstring, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */ + onInitFile: proc "c" (pUserData: rawptr, pFilePath: cstring, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */ onInitFileW: proc "c" (pUserData: rawptr, pFilePath: [^]c.wchar_t, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */ onInitMemory: proc "c" (pUserData: rawptr, pData: rawptr, dataSize: c.size_t, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */ onUninit: proc "c" (pUserData: rawptr, pBackend: ^data_source, pAllocationCallbacks: ^allocation_callbacks), - onGetChannelMap: proc "c" (pUserData: rawptr, pBackend: ^data_source, pChannelMap: ^channel, channelMapCap: c.size_t) -> result, } -/* TODO: Convert read and seek to be consistent with the VFS API (ma_result return value, bytes read moved to an output parameter). */ -decoder_read_proc :: proc "c" (pDecoder: ^decoder, pBufferOut: rawptr, bytesToRead: c.size_t) -> c.size_t /* Returns the number of bytes read. */ -decoder_seek_proc :: proc "c" (pDecoder: ^decoder, byteOffset: i64, origin: seek_origin) -> b32 +decoder_read_proc :: proc "c" (pDecoder: ^decoder, pBufferOut: rawptr, bytesToRead: c.size_t, pBytesRead: ^c.size_t) -> result /* Returns the number of bytes read. */ +decoder_seek_proc :: proc "c" (pDecoder: ^decoder, byteOffset: i64, origin: seek_origin) -> result decoder_tell_proc :: proc "c" (pDecoder: ^decoder, pCursor: ^i64) -> result decoder_config :: struct { - format: format, /* Set to 0 or ma_format_unknown to use the stream's internal format. */ - channels: u32, /* Set to 0 to use the stream's internal channels. */ - sampleRate: u32, /* Set to 0 to use the stream's internal sample rate. */ - channelMap: [MAX_CHANNELS]channel, - channelMixMode: channel_mix_mode, - ditherMode: dither_mode, - resampling: struct { - algorithm: resample_algorithm, - linear: struct { - lpfOrder: u32, - }, - speex: struct { - quality: c.int, - }, - }, + format: format, /* Set to 0 or ma_format_unknown to use the stream's internal format. */ + channels: u32, /* Set to 0 to use the stream's internal channels. */ + sampleRate: u32, /* Set to 0 to use the stream's internal sample rate. */ + channelMap: [^]channel, + channelMixMode: channel_mix_mode, + ditherMode: dither_mode, + resampling: resampler_config, allocationCallbacks: allocation_callbacks, encodingFormat: encoding_format, - ppCustomBackendVTables: ^^decoding_backend_vtable, + seekPointCount: u32, /* When set to > 0, specifies the number of seek points to use for the generation of a seek table. Not all decoding backends support this. */ + ppCustomBackendVTables: ^[^]decoding_backend_vtable, customBackendCount: u32, pCustomBackendUserData: rawptr, } decoder :: struct { - ds: data_source_base, - pBackend: ^data_source, /* The decoding backend we'll be pulling data from. */ - pBackendVTable: ^^decoding_backend_vtable, /* The vtable for the decoding backend. This needs to be stored so we can access the onUninit() callback. */ - pBackendUserData: rawptr, - onRead: decoder_read_proc, - onSeek: decoder_seek_proc, - onTell: decoder_tell_proc, - pUserData: rawptr, + ds: data_source_base, + pBackend: ^data_source, /* The decoding backend we'll be pulling data from. */ + pBackendVTable: ^decoding_backend_vtable, /* The vtable for the decoding backend. This needs to be stored so we can access the onUninit() callback. */ + pBackendUserData: rawptr, + onRead: decoder_read_proc, + onSeek: decoder_seek_proc, + onTell: decoder_tell_proc, + pUserData: rawptr, readPointerInPCMFrames: u64, /* In output sample rate. Used for keeping track of how many frames are available for decoding. */ - outputFormat: format, - outputChannels: u32, - outputSampleRate: u32, - outputChannelMap: [MAX_CHANNELS]channel, - converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */ - allocationCallbacks: allocation_callbacks, + outputFormat: format, + outputChannels: u32, + outputSampleRate: u32, + converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */ + pInputCache: rawptr, /* In input format. Can be null if it's not needed. */ + inputCacheCap: u64, /* The capacity of the input cache. */ + inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */ + inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */ + allocationCallbacks: allocation_callbacks, data: struct #raw_union { vfs: struct { pVFS: ^vfs, @@ -114,6 +109,25 @@ foreign lib { */ decoder_uninit :: proc(pDecoder: ^decoder) -> result --- + /* + Reads PCM frames from the given decoder. + + This is not thread safe without your own synchronization. + */ + decoder_read_pcm_frames :: proc(pDecoder: ^decoder, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + + /* + Seeks to a PCM frame based on it's absolute index. + + This is not thread safe without your own synchronization. + */ + decoder_seek_to_pcm_frame :: proc(pDecoder: ^decoder, frameIndex: u64) -> result --- + + /* + Retrieves the decoder's output data format. + */ + decoder_get_data_format :: proc(pDecoder: ^decoder, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: ^channel, channelMapCap: c.size_t) -> result --- + /* Retrieves the current position of the read cursor in PCM frames. */ @@ -133,21 +147,7 @@ foreign lib { This function is not thread safe without your own synchronization. */ - decoder_get_length_in_pcm_frames :: proc(pDecoder: ^decoder) -> u64 --- - - /* - Reads PCM frames from the given decoder. - - This is not thread safe without your own synchronization. - */ - decoder_read_pcm_frames :: proc(pDecoder: ^decoder, pFramesOut: rawptr, frameCount: u64) -> u64 --- - - /* - Seeks to a PCM frame based on it's absolute index. - - This is not thread safe without your own synchronization. - */ - decoder_seek_to_pcm_frame :: proc(pDecoder: ^decoder, frameIndex: u64) -> result --- + decoder_get_length_in_pcm_frames :: proc(pDecoder: ^decoder, pLength: ^u64) -> result --- /* Retrieves the number of frames that can be read before reaching the end. diff --git a/vendor/miniaudio/device_io_procs.odin b/vendor/miniaudio/device_io_procs.odin index 7cff3f621..de60645e4 100644 --- a/vendor/miniaudio/device_io_procs.odin +++ b/vendor/miniaudio/device_io_procs.odin @@ -12,6 +12,12 @@ import "core:c" @(default_calling_convention="c", link_prefix="ma_") foreign lib { + device_job_thread_config_init :: proc() -> device_job_thread_config --- + + device_job_thread_init :: proc(pConfig: ^device_job_thread_config, pAllocationCallbacks: ^allocation_callbacks, pJobThread: ^device_job_thread) -> result --- + device_job_thread_uninit :: proc(pJobThread: ^device_job_thread, pAllocationCallbacks: ^allocation_callbacks) --- + device_job_thread_post :: proc(pJobThread: ^device_job_thread, pJob: ^job) -> result --- + device_job_thread_next :: proc(pJobThread: ^device_job_thread, pJob: ^job) -> result --- /* Initializes a `ma_context_config` object. @@ -46,16 +52,16 @@ foreign lib { Parameters ---------- backends (in, optional) - A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order. + A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order. backendCount (in, optional) - The number of items in `backend`. Ignored if `backend` is NULL. + The number of items in `backend`. Ignored if `backend` is NULL. pConfig (in, optional) - The context configuration. + The context configuration. pContext (in) - A pointer to the context object being initialized. + A pointer to the context object being initialized. Return Value @@ -72,107 +78,116 @@ foreign lib { ------- When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order: - |-------------|-----------------------|--------------------------------------------------------| - | Name | Enum Name | Supported Operating Systems | - |-------------|-----------------------|--------------------------------------------------------| - | WASAPI | ma_backend_wasapi | Windows Vista+ | - | DirectSound | ma_backend_dsound | Windows XP+ | - | WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) | - | Core Audio | ma_backend_coreaudio | macOS, iOS | - | ALSA | ma_backend_alsa | Linux | - | PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) | - | JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) | - | sndio | ma_backend_sndio | OpenBSD | - | audio(4) | ma_backend_audio4 | NetBSD, OpenBSD | - | OSS | ma_backend_oss | FreeBSD | - | AAudio | ma_backend_aaudio | Android 8+ | - | OpenSL|ES | ma_backend_opensl | Android (API level 16+) | - | Web Audio | ma_backend_webaudio | Web (via Emscripten) | - | Null | ma_backend_null | Cross Platform (not used on Web) | - |-------------|-----------------------|--------------------------------------------------------| + |-------------|-----------------------|--------------------------------------------------------| + | Name | Enum Name | Supported Operating Systems | + |-------------|-----------------------|--------------------------------------------------------| + | WASAPI | ma_backend_wasapi | Windows Vista+ | + | DirectSound | ma_backend_dsound | Windows XP+ | + | WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) | + | Core Audio | ma_backend_coreaudio | macOS, iOS | + | ALSA | ma_backend_alsa | Linux | + | PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) | + | JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) | + | sndio | ma_backend_sndio | OpenBSD | + | audio(4) | ma_backend_audio4 | NetBSD, OpenBSD | + | OSS | ma_backend_oss | FreeBSD | + | AAudio | ma_backend_aaudio | Android 8+ | + | OpenSL|ES | ma_backend_opensl | Android (API level 16+) | + | Web Audio | ma_backend_webaudio | Web (via Emscripten) | + | Null | ma_backend_null | Cross Platform (not used on Web) | + |-------------|-----------------------|--------------------------------------------------------| The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings can then be set directly on the structure. Below are the members of the `ma_context_config` object. - pLog - A pointer to the `ma_log` to post log messages to. Can be NULL if the application does not - require logging. See the `ma_log` API for details on how to use the logging system. + pLog + A pointer to the `ma_log` to post log messages to. Can be NULL if the application does not + require logging. See the `ma_log` API for details on how to use the logging system. - threadPriority - The desired priority to use for the audio thread. Allowable values include the following: + threadPriority + The desired priority to use for the audio thread. Allowable values include the following: - |--------------------------------------| - | Thread Priority | - |--------------------------------------| - | ma_thread_priority_idle | - | ma_thread_priority_lowest | - | ma_thread_priority_low | - | ma_thread_priority_normal | - | ma_thread_priority_high | - | ma_thread_priority_highest (default) | - | ma_thread_priority_realtime | - | ma_thread_priority_default | - |--------------------------------------| + |--------------------------------------| + | Thread Priority | + |--------------------------------------| + | ma_thread_priority_idle | + | ma_thread_priority_lowest | + | ma_thread_priority_low | + | ma_thread_priority_normal | + | ma_thread_priority_high | + | ma_thread_priority_highest (default) | + | ma_thread_priority_realtime | + | ma_thread_priority_default | + |--------------------------------------| - pUserData - A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`. + threadStackSize + The desired size of the stack for the audio thread. Defaults to the operating system's default. - allocationCallbacks - Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation - callbacks will be used for anything tied to the context, including devices. + pUserData + A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`. - alsa.useVerboseDeviceEnumeration - ALSA will typically enumerate many different devices which can be intrusive and not user-friendly. To combat this, miniaudio will enumerate only unique - card/device pairs by default. The problem with this is that you lose a bit of flexibility and control. Setting alsa.useVerboseDeviceEnumeration makes - it so the ALSA backend includes all devices. Defaults to false. + allocationCallbacks + Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation + callbacks will be used for anything tied to the context, including devices. - pulse.pApplicationName - PulseAudio only. The application name to use when initializing the PulseAudio context with `pa_context_new()`. + alsa.useVerboseDeviceEnumeration + ALSA will typically enumerate many different devices which can be intrusive and not user-friendly. To combat this, miniaudio will enumerate only unique + card/device pairs by default. The problem with this is that you lose a bit of flexibility and control. Setting alsa.useVerboseDeviceEnumeration makes + it so the ALSA backend includes all devices. Defaults to false. - pulse.pServerName - PulseAudio only. The name of the server to connect to with `pa_context_connect()`. + pulse.pApplicationName + PulseAudio only. The application name to use when initializing the PulseAudio context with `pa_context_new()`. - pulse.tryAutoSpawn - PulseAudio only. Whether or not to try automatically starting the PulseAudio daemon. Defaults to false. If you set this to true, keep in mind that - miniaudio uses a trial and error method to find the most appropriate backend, and this will result in the PulseAudio daemon starting which may be - intrusive for the end user. + pulse.pServerName + PulseAudio only. The name of the server to connect to with `pa_context_connect()`. - coreaudio.sessionCategory - iOS only. The session category to use for the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents. + pulse.tryAutoSpawn + PulseAudio only. Whether or not to try automatically starting the PulseAudio daemon. Defaults to false. If you set this to true, keep in mind that + miniaudio uses a trial and error method to find the most appropriate backend, and this will result in the PulseAudio daemon starting which may be + intrusive for the end user. - |-----------------------------------------|-------------------------------------| - | miniaudio Token | Core Audio Token | - |-----------------------------------------|-------------------------------------| - | ma_ios_session_category_ambient | AVAudioSessionCategoryAmbient | - | ma_ios_session_category_solo_ambient | AVAudioSessionCategorySoloAmbient | - | ma_ios_session_category_playback | AVAudioSessionCategoryPlayback | - | ma_ios_session_category_record | AVAudioSessionCategoryRecord | - | ma_ios_session_category_play_and_record | AVAudioSessionCategoryPlayAndRecord | - | ma_ios_session_category_multi_route | AVAudioSessionCategoryMultiRoute | - | ma_ios_session_category_none | AVAudioSessionCategoryAmbient | - | ma_ios_session_category_default | AVAudioSessionCategoryAmbient | - |-----------------------------------------|-------------------------------------| + coreaudio.sessionCategory + iOS only. The session category to use for the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents. - coreaudio.sessionCategoryOptions - iOS only. Session category options to use with the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents. + |-----------------------------------------|-------------------------------------| + | miniaudio Token | Core Audio Token | + |-----------------------------------------|-------------------------------------| + | ma_ios_session_category_ambient | AVAudioSessionCategoryAmbient | + | ma_ios_session_category_solo_ambient | AVAudioSessionCategorySoloAmbient | + | ma_ios_session_category_playback | AVAudioSessionCategoryPlayback | + | ma_ios_session_category_record | AVAudioSessionCategoryRecord | + | ma_ios_session_category_play_and_record | AVAudioSessionCategoryPlayAndRecord | + | ma_ios_session_category_multi_route | AVAudioSessionCategoryMultiRoute | + | ma_ios_session_category_none | AVAudioSessionCategoryAmbient | + | ma_ios_session_category_default | AVAudioSessionCategoryAmbient | + |-----------------------------------------|-------------------------------------| - |---------------------------------------------------------------------------|------------------------------------------------------------------| - | miniaudio Token | Core Audio Token | - |---------------------------------------------------------------------------|------------------------------------------------------------------| - | ma_ios_session_category_option_mix_with_others | AVAudioSessionCategoryOptionMixWithOthers | - | ma_ios_session_category_option_duck_others | AVAudioSessionCategoryOptionDuckOthers | - | ma_ios_session_category_option_allow_bluetooth | AVAudioSessionCategoryOptionAllowBluetooth | - | ma_ios_session_category_option_default_to_speaker | AVAudioSessionCategoryOptionDefaultToSpeaker | - | ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers | - | ma_ios_session_category_option_allow_bluetooth_a2dp | AVAudioSessionCategoryOptionAllowBluetoothA2DP | - | ma_ios_session_category_option_allow_air_play | AVAudioSessionCategoryOptionAllowAirPlay | - |---------------------------------------------------------------------------|------------------------------------------------------------------| + coreaudio.sessionCategoryOptions + iOS only. Session category options to use with the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents. - jack.pClientName - The name of the client to pass to `jack_client_open()`. + |---------------------------------------------------------------------------|------------------------------------------------------------------| + | miniaudio Token | Core Audio Token | + |---------------------------------------------------------------------------|------------------------------------------------------------------| + | ma_ios_session_category_option_mix_with_others | AVAudioSessionCategoryOptionMixWithOthers | + | ma_ios_session_category_option_duck_others | AVAudioSessionCategoryOptionDuckOthers | + | ma_ios_session_category_option_allow_bluetooth | AVAudioSessionCategoryOptionAllowBluetooth | + | ma_ios_session_category_option_default_to_speaker | AVAudioSessionCategoryOptionDefaultToSpeaker | + | ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers | + | ma_ios_session_category_option_allow_bluetooth_a2dp | AVAudioSessionCategoryOptionAllowBluetoothA2DP | + | ma_ios_session_category_option_allow_air_play | AVAudioSessionCategoryOptionAllowAirPlay | + |---------------------------------------------------------------------------|------------------------------------------------------------------| - jack.tryStartServer - Whether or not to try auto-starting the JACK server. Defaults to false. + coreaudio.noAudioSessionActivate + iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. + + coreaudio.noAudioSessionDeactivate + iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. + + jack.pClientName + The name of the client to pass to `jack_client_open()`. + + jack.tryStartServer + Whether or not to try auto-starting the JACK server. Defaults to false. It is recommended that only a single context is active at any given time because it's a bulky data structure which performs run-time linking for the @@ -190,7 +205,7 @@ foreign lib { ma_context context; ma_result result = ma_context_init(NULL, 0, NULL, &context); if (result != MA_SUCCESS) { - // Error. + // Error. } ``` @@ -205,24 +220,30 @@ foreign lib { ```c ma_backend backends[] = { - ma_backend_alsa, - ma_backend_pulseaudio, - ma_backend_wasapi, - ma_backend_dsound + ma_backend_alsa, + ma_backend_pulseaudio, + ma_backend_wasapi, + ma_backend_dsound }; + ma_log log; + ma_log_init(&log); + ma_log_register_callback(&log, ma_log_callback_init(my_log_callbac, pMyLogUserData)); + ma_context_config config = ma_context_config_init(); - config.logCallback = my_log_callback; - config.pUserData = pMyUserData; + config.pLog = &log; // Specify a custom log object in the config so any logs that are posted from ma_context_init() are captured. ma_context context; ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context); if (result != MA_SUCCESS) { - // Error. - if (result == MA_NO_BACKEND) { - // Couldn't find an appropriate backend. - } + // Error. + if (result == MA_NO_BACKEND) { + // Couldn't find an appropriate backend. + } } + + // You could also attach a log callback post-initialization: + ma_log_register_callback(ma_context_get_log(&context), ma_log_callback_init(my_log_callback, pMyLogUserData)); ``` @@ -298,13 +319,13 @@ foreign lib { Parameters ---------- pContext (in) - A pointer to the context performing the enumeration. + A pointer to the context performing the enumeration. callback (in) - The callback to fire for each enumerated device. + The callback to fire for each enumerated device. pUserData (in) - A pointer to application-defined data passed to the callback. + A pointer to application-defined data passed to the callback. Return Value @@ -331,15 +352,15 @@ foreign lib { Example 1 - Simple Enumeration ------------------------------ - ma_bool32 ma_device_enum_callback(pContext: ^context_type, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData) + ma_bool32 ma_device_enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData) { - printf("Device Name: %s\n", pInfo->name); - return MA_TRUE; + printf("Device Name: %s\n", pInfo->name); + return MA_TRUE; } ma_result result = ma_context_enumerate_devices(&context, my_device_enum_callback, pMyUserData); if (result != MA_SUCCESS) { - // Error. + // Error. } @@ -359,19 +380,19 @@ foreign lib { Parameters ---------- pContext (in) - A pointer to the context performing the enumeration. + A pointer to the context performing the enumeration. ppPlaybackDeviceInfos (out) - A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for playback devices. + A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for playback devices. pPlaybackDeviceCount (out) - A pointer to an unsigned integer that will receive the number of playback devices. + A pointer to an unsigned integer that will receive the number of playback devices. ppCaptureDeviceInfos (out) - A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for capture devices. + A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for capture devices. pCaptureDeviceCount (out) - A pointer to an unsigned integer that will receive the number of capture devices. + A pointer to an unsigned integer that will receive the number of capture devices. Return Value @@ -407,20 +428,16 @@ foreign lib { Parameters ---------- pContext (in) - A pointer to the context performing the query. + A pointer to the context performing the query. deviceType (in) - The type of the device being queried. Must be either `ma_device_type_playback` or `ma_device_type_capture`. + The type of the device being queried. Must be either `ma_device_type_playback` or `ma_device_type_capture`. pDeviceID (in) - The ID of the device being queried. - - shareMode (in) - The share mode to query for device capabilities. This should be set to whatever you're intending on using when initializing the device. If you're unsure, - set this to `ma_share_mode_shared`. + The ID of the device being queried. pDeviceInfo (out) - A pointer to the `ma_device_info` structure that will receive the device information. + A pointer to the `ma_device_info` structure that will receive the device information. Return Value @@ -444,7 +461,7 @@ foreign lib { This leaves pDeviceInfo unmodified in the result of an error. */ - context_get_device_info :: proc(pContext: ^context_type, deviceType: device_type, pDeviceID: ^device_id, shareMode: share_mode, pDeviceInfo: ^device_info) -> result --- + context_get_device_info :: proc(pContext: ^context_type, deviceType: device_type, pDeviceID: ^device_id, pDeviceInfo: ^device_info) -> result --- /* Determines if the given context supports loopback mode. @@ -471,16 +488,16 @@ foreign lib { Parameters ---------- deviceType (in) - The type of the device this config is being initialized for. This must set to one of the following: + The type of the device this config is being initialized for. This must set to one of the following: - |-------------------------| - | Device Type | - |-------------------------| - | ma_device_type_playback | - | ma_device_type_capture | - | ma_device_type_duplex | - | ma_device_type_loopback | - |-------------------------| + |-------------------------| + | Device Type | + |-------------------------| + | ma_device_type_playback | + | ma_device_type_capture | + | ma_device_type_duplex | + | ma_device_type_loopback | + |-------------------------| Return Value @@ -554,13 +571,13 @@ foreign lib { Parameters ---------- pContext (in, optional) - A pointer to the context that owns the device. This can be null, in which case it creates a default context internally. + A pointer to the context that owns the device. This can be null, in which case it creates a default context internally. pConfig (in) - A pointer to the device configuration. Cannot be null. See remarks for details. + A pointer to the device configuration. Cannot be null. See remarks for details. pDevice (out) - A pointer to the device object being initialized. + A pointer to the device object being initialized. Return Value @@ -583,9 +600,9 @@ foreign lib { ------- Setting `pContext` to NULL will result in miniaudio creating a default context internally and is equivalent to passing in a context initialized like so: - ```c - ma_context_init(NULL, 0, NULL, &context); - ``` + ```c + ma_context_init(NULL, 0, NULL, &context); + ``` Do not set `pContext` to NULL if you are needing to open multiple devices. You can, however, use NULL when initializing the first device, and then use device.pContext for the initialization of other devices. @@ -593,136 +610,173 @@ foreign lib { The device can be configured via the `pConfig` argument. The config object is initialized with `ma_device_config_init()`. Individual configuration settings can then be set directly on the structure. Below are the members of the `ma_device_config` object. - deviceType - Must be `ma_device_type_playback`, `ma_device_type_capture`, `ma_device_type_duplex` of `ma_device_type_loopback`. + deviceType + Must be `ma_device_type_playback`, `ma_device_type_capture`, `ma_device_type_duplex` of `ma_device_type_loopback`. - sampleRate - The sample rate, in hertz. The most common sample rates are 48000 and 44100. Setting this to 0 will use the device's native sample rate. + sampleRate + The sample rate, in hertz. The most common sample rates are 48000 and 44100. Setting this to 0 will use the device's native sample rate. - periodSizeInFrames - The desired size of a period in PCM frames. If this is 0, `periodSizeInMilliseconds` will be used instead. If both are 0 the default buffer size will - be used depending on the selected performance profile. This value affects latency. See below for details. + periodSizeInFrames + The desired size of a period in PCM frames. If this is 0, `periodSizeInMilliseconds` will be used instead. If both are 0 the default buffer size will + be used depending on the selected performance profile. This value affects latency. See below for details. - periodSizeInMilliseconds - The desired size of a period in milliseconds. If this is 0, `periodSizeInFrames` will be used instead. If both are 0 the default buffer size will be - used depending on the selected performance profile. The value affects latency. See below for details. + periodSizeInMilliseconds + The desired size of a period in milliseconds. If this is 0, `periodSizeInFrames` will be used instead. If both are 0 the default buffer size will be + used depending on the selected performance profile. The value affects latency. See below for details. - periods - The number of periods making up the device's entire buffer. The total buffer size is `periodSizeInFrames` or `periodSizeInMilliseconds` multiplied by - this value. This is just a hint as backends will be the ones who ultimately decide how your periods will be configured. + periods + The number of periods making up the device's entire buffer. The total buffer size is `periodSizeInFrames` or `periodSizeInMilliseconds` multiplied by + this value. This is just a hint as backends will be the ones who ultimately decide how your periods will be configured. - performanceProfile - A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or - `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value. + performanceProfile + A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or + `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value. - noPreZeroedOutputBuffer - When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of - the output buffer will be cleared the zero. You can use this to avoid the overhead of zeroing out the buffer if you can guarantee that your data - callback will write to every sample in the output buffer, or if you are doing your own clearing. + noPreSilencedOutputBuffer + When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of + the output buffer will be cleared the zero. You can use this to avoid the overhead of zeroing out the buffer if you can guarantee that your data + callback will write to every sample in the output buffer, or if you are doing your own clearing. - noClip - When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. When set to false (default), the - contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only - applies when the playback sample format is f32. + noClip + When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. When set to false (default), the + contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only + applies when the playback sample format is f32. - dataCallback - The callback to fire whenever data is ready to be delivered to or from the device. + noDisableDenormals + By default, miniaudio will disable denormals when the data callback is called. Setting this to true will prevent the disabling of denormals. - stopCallback - The callback to fire whenever the device has stopped, either explicitly via `ma_device_stop()`, or implicitly due to things like the device being - disconnected. + noFixedSizedCallback + Allows miniaudio to fire the data callback with any frame count. When this is set to true, the data callback will be fired with a consistent frame + count as specified by `periodSizeInFrames` or `periodSizeInMilliseconds`. When set to false, miniaudio will fire the callback with whatever the + backend requests, which could be anything. - pUserData - The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`. + dataCallback + The callback to fire whenever data is ready to be delivered to or from the device. - resampling.algorithm - The resampling algorithm to use when miniaudio needs to perform resampling between the rate specified by `sampleRate` and the device's native rate. The - default value is `ma_resample_algorithm_linear`, and the quality can be configured with `resampling.linear.lpfOrder`. + notificationCallback + The callback to fire when something has changed with the device, such as whether or not it has been started or stopped. - resampling.linear.lpfOrder - The linear resampler applies a low-pass filter as part of it's procesing for anti-aliasing. This setting controls the order of the filter. The higher - the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is - `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. + pUserData + The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`. - playback.pDeviceID - A pointer to a `ma_device_id` structure containing the ID of the playback device to initialize. Setting this NULL (default) will use the system's - default playback device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration. + resampling.algorithm + The resampling algorithm to use when miniaudio needs to perform resampling between the rate specified by `sampleRate` and the device's native rate. The + default value is `ma_resample_algorithm_linear`, and the quality can be configured with `resampling.linear.lpfOrder`. - playback.format - The sample format to use for playback. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after - initialization from the device object directly with `device.playback.format`. + resampling.pBackendVTable + A pointer to an optional vtable that can be used for plugging in a custom resampler. - playback.channels - The number of channels to use for playback. When set to 0 the device's native channel count will be used. This can be retrieved after initialization - from the device object directly with `device.playback.channels`. + resampling.pBackendUserData + A pointer that will passed to callbacks in pBackendVTable. - playback.channelMap - The channel map to use for playback. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the - device object direct with `device.playback.channelMap`. + resampling.linear.lpfOrder + The linear resampler applies a low-pass filter as part of it's procesing for anti-aliasing. This setting controls the order of the filter. The higher + the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is + `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. - playback.shareMode - The preferred share mode to use for playback. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify - exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to - ma_share_mode_shared and reinitializing. + playback.pDeviceID + A pointer to a `ma_device_id` structure containing the ID of the playback device to initialize. Setting this NULL (default) will use the system's + default playback device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration. - capture.pDeviceID - A pointer to a `ma_device_id` structure containing the ID of the capture device to initialize. Setting this NULL (default) will use the system's - default capture device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration. + playback.format + The sample format to use for playback. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after + initialization from the device object directly with `device.playback.format`. - capture.format - The sample format to use for capture. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after - initialization from the device object directly with `device.capture.format`. + playback.channels + The number of channels to use for playback. When set to 0 the device's native channel count will be used. This can be retrieved after initialization + from the device object directly with `device.playback.channels`. - capture.channels - The number of channels to use for capture. When set to 0 the device's native channel count will be used. This can be retrieved after initialization - from the device object directly with `device.capture.channels`. + playback.pChannelMap + The channel map to use for playback. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the + device object direct with `device.playback.pChannelMap`. When set, the buffer should contain `channels` items. - capture.channelMap - The channel map to use for capture. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the - device object direct with `device.capture.channelMap`. + playback.shareMode + The preferred share mode to use for playback. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify + exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to + ma_share_mode_shared and reinitializing. - capture.shareMode - The preferred share mode to use for capture. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify - exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to - ma_share_mode_shared and reinitializing. + capture.pDeviceID + A pointer to a `ma_device_id` structure containing the ID of the capture device to initialize. Setting this NULL (default) will use the system's + default capture device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration. - wasapi.noAutoConvertSRC - WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false. + capture.format + The sample format to use for capture. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after + initialization from the device object directly with `device.capture.format`. - wasapi.noDefaultQualitySRC - WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`. - You should usually leave this set to false, which is the default. + capture.channels + The number of channels to use for capture. When set to 0 the device's native channel count will be used. This can be retrieved after initialization + from the device object directly with `device.capture.channels`. - wasapi.noAutoStreamRouting - WASAPI only. When set to true, disables automatic stream routing on the WASAPI backend. Defaults to false. + capture.pChannelMap + The channel map to use for capture. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the + device object direct with `device.capture.pChannelMap`. When set, the buffer should contain `channels` items. - wasapi.noHardwareOffloading - WASAPI only. When set to true, disables the use of WASAPI's hardware offloading feature. Defaults to false. + capture.shareMode + The preferred share mode to use for capture. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify + exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to + ma_share_mode_shared and reinitializing. - alsa.noMMap - ALSA only. When set to true, disables MMap mode. Defaults to false. + wasapi.noAutoConvertSRC + WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false. - alsa.noAutoFormat - ALSA only. When set to true, disables ALSA's automatic format conversion by including the SND_PCM_NO_AUTO_FORMAT flag. Defaults to false. + wasapi.noDefaultQualitySRC + WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`. + You should usually leave this set to false, which is the default. - alsa.noAutoChannels - ALSA only. When set to true, disables ALSA's automatic channel conversion by including the SND_PCM_NO_AUTO_CHANNELS flag. Defaults to false. + wasapi.noAutoStreamRouting + WASAPI only. When set to true, disables automatic stream routing on the WASAPI backend. Defaults to false. - alsa.noAutoResample - ALSA only. When set to true, disables ALSA's automatic resampling by including the SND_PCM_NO_AUTO_RESAMPLE flag. Defaults to false. + wasapi.noHardwareOffloading + WASAPI only. When set to true, disables the use of WASAPI's hardware offloading feature. Defaults to false. - pulse.pStreamNamePlayback - PulseAudio only. Sets the stream name for playback. + alsa.noMMap + ALSA only. When set to true, disables MMap mode. Defaults to false. - pulse.pStreamNameCapture - PulseAudio only. Sets the stream name for capture. + alsa.noAutoFormat + ALSA only. When set to true, disables ALSA's automatic format conversion by including the SND_PCM_NO_AUTO_FORMAT flag. Defaults to false. - coreaudio.allowNominalSampleRateChange - Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This - is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate - that is known to be natively supported by the hardware thereby avoiding the cost of resampling. When set to true, miniaudio will - find the closest match between the sample rate requested in the device config and the sample rates natively supported by the - hardware. When set to false, the sample rate currently set by the operating system will always be used. + alsa.noAutoChannels + ALSA only. When set to true, disables ALSA's automatic channel conversion by including the SND_PCM_NO_AUTO_CHANNELS flag. Defaults to false. + + alsa.noAutoResample + ALSA only. When set to true, disables ALSA's automatic resampling by including the SND_PCM_NO_AUTO_RESAMPLE flag. Defaults to false. + + pulse.pStreamNamePlayback + PulseAudio only. Sets the stream name for playback. + + pulse.pStreamNameCapture + PulseAudio only. Sets the stream name for capture. + + coreaudio.allowNominalSampleRateChange + Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This + is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate + that is known to be natively supported by the hardware thereby avoiding the cost of resampling. When set to true, miniaudio will + find the closest match between the sample rate requested in the device config and the sample rates natively supported by the + hardware. When set to false, the sample rate currently set by the operating system will always be used. + + opensl.streamType + OpenSL only. Explicitly sets the stream type. If left unset (`ma_opensl_stream_type_default`), the + stream type will be left unset. Think of this as the type of audio you're playing. + + opensl.recordingPreset + OpenSL only. Explicitly sets the type of recording your program will be doing. When left + unset, the recording preset will be left unchanged. + + aaudio.usage + AAudio only. Explicitly sets the nature of the audio the program will be consuming. When + left unset, the usage will be left unchanged. + + aaudio.contentType + AAudio only. Sets the content type. When left unset, the content type will be left unchanged. + + aaudio.inputPreset + AAudio only. Explicitly sets the type of recording your program will be doing. When left + unset, the input preset will be left unchanged. + + aaudio.noAutoStartAfterReroute + AAudio only. Controls whether or not the device should be automatically restarted after a + stream reroute. When set to false (default) the device will be restarted automatically; + otherwise the device will be stopped. Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device. @@ -767,7 +821,7 @@ foreign lib { ma_device device; ma_result result = ma_device_init(NULL, &config, &device); if (result != MA_SUCCESS) { - // Error + // Error } ``` @@ -782,14 +836,14 @@ foreign lib { ma_context context; ma_result result = ma_context_init(NULL, 0, NULL, &context); if (result != MA_SUCCESS) { - // Error + // Error } ma_device_info* pPlaybackDeviceInfos; ma_uint32 playbackDeviceCount; result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); if (result != MA_SUCCESS) { - // Error + // Error } // ... choose a device from pPlaybackDeviceInfos ... @@ -807,7 +861,7 @@ foreign lib { ma_device device; result = ma_device_init(&context, &config, &device); if (result != MA_SUCCESS) { - // Error + // Error } ``` @@ -833,19 +887,19 @@ foreign lib { Parameters ---------- backends (in, optional) - A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order. + A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order. backendCount (in, optional) - The number of items in `backend`. Ignored if `backend` is NULL. + The number of items in `backend`. Ignored if `backend` is NULL. pContextConfig (in, optional) - The context configuration. + The context configuration. pConfig (in) - A pointer to the device configuration. Cannot be null. See remarks for details. + A pointer to the device configuration. Cannot be null. See remarks for details. pDevice (out) - A pointer to the device object being initialized. + A pointer to the device object being initialized. Return Value @@ -890,7 +944,7 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device to stop. + A pointer to the device to stop. Return Value @@ -927,6 +981,95 @@ foreign lib { device_get_log :: proc(pDevice: ^device) -> ^log --- + /* + Retrieves information about the device. + + + Parameters + ---------- + pDevice (in) + A pointer to the device whose information is being retrieved. + + type (in) + The device type. This parameter is required for duplex devices. When retrieving device + information, you are doing so for an individual playback or capture device. + + pDeviceInfo (out) + A pointer to the `ma_device_info` that will receive the device information. + + + Return Value + ------------ + MA_SUCCESS if successful; any other error code otherwise. + + + Thread Safety + ------------- + Unsafe. This should be considered unsafe because it may be calling into the backend which may or + may not be safe. + + + Callback Safety + --------------- + Unsafe. You should avoid calling this in the data callback because it may call into the backend + which may or may not be safe. + */ + device_get_info :: proc(pDevice: ^device, type: device_type, pDeviceInfo: ^device_info) -> result --- + + + /* + Retrieves the name of the device. + + + Parameters + ---------- + pDevice (in) + A pointer to the device whose information is being retrieved. + + type (in) + The device type. This parameter is required for duplex devices. When retrieving device + information, you are doing so for an individual playback or capture device. + + pName (out) + A pointer to the buffer that will receive the name. + + nameCap (in) + The capacity of the output buffer, including space for the null terminator. + + pLengthNotIncludingNullTerminator (out, optional) + A pointer to the variable that will receive the length of the name, not including the null + terminator. + + + Return Value + ------------ + MA_SUCCESS if successful; any other error code otherwise. + + + Thread Safety + ------------- + Unsafe. This should be considered unsafe because it may be calling into the backend which may or + may not be safe. + + + Callback Safety + --------------- + Unsafe. You should avoid calling this in the data callback because it may call into the backend + which may or may not be safe. + + + Remarks + ------- + If the name does not fully fit into the output buffer, it'll be truncated. You can pass in NULL to + `pName` if you want to first get the length of the name for the purpose of memory allocation of the + output buffer. Allocating a buffer of size `MA_MAX_DEVICE_NAME_LENGTH + 1` should be enough for + most cases and will avoid the need for the inefficiency of calling this function twice. + + This is implemented in terms of `ma_device_get_info()`. + */ + device_get_name :: proc(pDevice: ^device, type: device_type, pName: [^]c.char, nameCap: c.size_t, pLengthNotIncludingNullTerminator: ^c.size_t) -> result --- + + /* Starts the device. For playback devices this begins playback. For capture devices it begins recording. @@ -936,7 +1079,7 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device to start. + A pointer to the device to start. Return Value @@ -979,7 +1122,7 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device to stop. + A pointer to the device to stop. Return Value @@ -1025,7 +1168,7 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device whose start state is being retrieved. + A pointer to the device whose start state is being retrieved. Return Value @@ -1059,24 +1202,24 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device whose state is being retrieved. + A pointer to the device whose state is being retrieved. Return Value ------------ The current state of the device. The return value will be one of the following: - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_UNINITIALIZED | Will only be returned if the device is in the middle of initialization. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STOPPED | The device is stopped. The initial state of the device after initialization. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STARTED | The device started and requesting and/or delivering audio data. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STARTING | The device is in the process of starting. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STOPPING | The device is in the process of stopping. | - +------------------------+------------------------------------------------------------------------------+ + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_uninitialized | Will only be returned if the device is in the middle of initialization. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_stopped | The device is stopped. The initial state of the device after initialization. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_started | The device started and requesting and/or delivering audio data. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_starting | The device is in the process of starting. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_stopping | The device is in the process of stopping. | + +-------------------------------+------------------------------------------------------------------------------+ Thread Safety @@ -1094,40 +1237,89 @@ foreign lib { ------- The general flow of a devices state goes like this: - ``` - ma_device_init() -> MA_STATE_UNINITIALIZED -> MA_STATE_STOPPED - ma_device_start() -> MA_STATE_STARTING -> MA_STATE_STARTED - ma_device_stop() -> MA_STATE_STOPPING -> MA_STATE_STOPPED - ``` + ``` + ma_device_init() -> ma_device_state_uninitialized -> ma_device_state_stopped + ma_device_start() -> ma_device_state_starting -> ma_device_state_started + ma_device_stop() -> ma_device_state_stopping -> ma_device_state_stopped + ``` When the state of the device is changed with `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, the value returned by this function could potentially be out of sync. If this is significant to your program you need to implement your own synchronization. */ - device_get_state :: proc(pDevice: ^device) -> u32 --- + device_get_state :: proc(pDevice: ^device) -> device_state --- + + + /* + Performs post backend initialization routines for setting up internal data conversion. + + This should be called whenever the backend is initialized. The only time this should be called from + outside of miniaudio is if you're implementing a custom backend, and you would only do it if you + are reinitializing the backend due to rerouting or reinitializing for some reason. + + + Parameters + ---------- + pDevice [in] + A pointer to the device. + + deviceType [in] + The type of the device that was just reinitialized. + + pPlaybackDescriptor [in] + The descriptor of the playback device containing the internal data format and buffer sizes. + + pPlaybackDescriptor [in] + The descriptor of the capture device containing the internal data format and buffer sizes. + + + Return Value + ------------ + MA_SUCCESS if successful; any other error otherwise. + + + Thread Safety + ------------- + Unsafe. This will be reinitializing internal data converters which may be in use by another thread. + + + Callback Safety + --------------- + Unsafe. This will be reinitializing internal data converters which may be in use by the callback. + + + Remarks + ------- + For a duplex device, you can call this for only one side of the system. This is why the deviceType + is specified as a parameter rather than deriving it from the device. + + You do not need to call this manually unless you are doing a custom backend, in which case you need + only do it if you're manually performing rerouting or reinitialization. + */ + device_post_init :: proc(pDevice: ^device, deviceType: device_type, pPlaybackDescriptor, pCaptureDescriptor: ^device_descriptor) -> result --- /* Sets the master volume factor for the device. - The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_gain_db()` to use decibel notation, where 0 is full volume and + The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_volume_db()` to use decibel notation, where 0 is full volume and values less than 0 decreases the volume. Parameters ---------- pDevice (in) - A pointer to the device whose volume is being set. + A pointer to the device whose volume is being set. volume (in) - The new volume factor. Must be within the range of [0, 1]. + The new volume factor. Must be >= 0. Return Value ------------ MA_SUCCESS if the volume was set successfully. MA_INVALID_ARGS if pDevice is NULL. - MA_INVALID_ARGS if the volume factor is not within the range of [0, 1]. + MA_INVALID_ARGS if volume is negative. Thread Safety @@ -1150,8 +1342,8 @@ foreign lib { See Also -------- ma_device_get_master_volume() - ma_device_set_master_volume_gain_db() - ma_device_get_master_volume_gain_db() + ma_device_set_master_volume_db() + ma_device_get_master_volume_db() */ device_set_master_volume :: proc(pDevice: ^device, volume: f32) -> result --- @@ -1162,10 +1354,10 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device whose volume factor is being retrieved. + A pointer to the device whose volume factor is being retrieved. pVolume (in) - A pointer to the variable that will receive the volume factor. The returned value will be in the range of [0, 1]. + A pointer to the variable that will receive the volume factor. The returned value will be in the range of [0, 1]. Return Value @@ -1207,10 +1399,10 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device whose gain is being set. + A pointer to the device whose gain is being set. gainDB (in) - The new volume as gain in decibels. Must be less than or equal to 0, where 0 is full volume and anything less than 0 decreases the volume. + The new volume as gain in decibels. Must be less than or equal to 0, where 0 is full volume and anything less than 0 decreases the volume. Return Value @@ -1243,7 +1435,7 @@ foreign lib { ma_device_set_master_volume() ma_device_get_master_volume() */ - device_set_master_gain_db :: proc(pDevice: ^device, gainDB: f32) -> result --- + device_set_master_volume_db :: proc(pDevice: ^device, gainDB: f32) -> result --- /* Retrieves the master gain in decibels. @@ -1252,10 +1444,10 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to the device whose gain is being retrieved. + A pointer to the device whose gain is being retrieved. pGainDB (in) - A pointer to the variable that will receive the gain in decibels. The returned value will be <= 0. + A pointer to the variable that will receive the gain in decibels. The returned value will be <= 0. Return Value @@ -1282,11 +1474,11 @@ foreign lib { See Also -------- - ma_device_set_master_volume_gain_db() + ma_device_set_master_volume_db() ma_device_set_master_volume() ma_device_get_master_volume() */ - device_get_master_gain_db :: proc(pDevice: ^device, pGainDB: ^f32) -> result --- + device_get_master_volume_db :: proc(pDevice: ^device, pGainDB: ^f32) -> result --- /* @@ -1296,18 +1488,18 @@ foreign lib { Parameters ---------- pDevice (in) - A pointer to device whose processing the data callback. + A pointer to device whose processing the data callback. pOutput (out) - A pointer to the buffer that will receive the output PCM frame data. On a playback device this must not be NULL. On a duplex device - this can be NULL, in which case pInput must not be NULL. + A pointer to the buffer that will receive the output PCM frame data. On a playback device this must not be NULL. On a duplex device + this can be NULL, in which case pInput must not be NULL. pInput (in) - A pointer to the buffer containing input PCM frame data. On a capture device this must not be NULL. On a duplex device this can be - NULL, in which case `pOutput` must not be NULL. + A pointer to the buffer containing input PCM frame data. On a capture device this must not be NULL. On a duplex device this can be + NULL, in which case `pOutput` must not be NULL. frameCount (in) - The number of frames being processed. + The number of frames being processed. Return Value @@ -1334,7 +1526,7 @@ foreign lib { If you are implementing a custom backend, and that backend uses a callback for data delivery, you'll need to call this from inside that callback. */ - device_handle_backend_data_callback :: proc(pDevice: ^device, pOutput: rawptr, pInput: rawptr, frameCount: u32) -> result --- + device_handle_backend_data_callback :: proc(pDevice: ^device, pOutput, pInput: rawptr, frameCount: u32) -> result --- /* @@ -1351,18 +1543,18 @@ foreign lib { Parameters ---------- pDescriptor (in) - A pointer to device descriptor whose `periodSizeInFrames` and `periodSizeInMilliseconds` members - will be used for the calculation of the buffer size. + A pointer to device descriptor whose `periodSizeInFrames` and `periodSizeInMilliseconds` members + will be used for the calculation of the buffer size. nativeSampleRate (in) - The device's native sample rate. This is only ever used when the `periodSizeInFrames` member of - `pDescriptor` is zero. In this case, `periodSizeInMilliseconds` will be used instead, in which - case a sample rate is required to convert to a size in frames. + The device's native sample rate. This is only ever used when the `periodSizeInFrames` member of + `pDescriptor` is zero. In this case, `periodSizeInMilliseconds` will be used instead, in which + case a sample rate is required to convert to a size in frames. performanceProfile (in) - When both the `periodSizeInFrames` and `periodSizeInMilliseconds` members of `pDescriptor` are - zero, miniaudio will fall back to a buffer size based on the performance profile. The profile - to use for this calculation is determine by this parameter. + When both the `periodSizeInFrames` and `periodSizeInMilliseconds` members of `pDescriptor` are + zero, miniaudio will fall back to a buffer size based on the performance profile. The profile + to use for this calculation is determine by this parameter. Return Value @@ -1408,14 +1600,14 @@ foreign lib { Parameters ---------- pBackends (out, optional) - A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting - the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends. + A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting + the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends. backendCap (in) - The capacity of the `pBackends` buffer. + The capacity of the `pBackends` buffer. pBackendCount (out) - A pointer to the variable that will receive the enabled backend count. + A pointer to the variable that will receive the enabled backend count. Return Value @@ -1463,7 +1655,7 @@ foreign lib { result = ma_get_enabled_backends(enabledBackends, MA_BACKEND_COUNT, &enabledBackendCount); if (result != MA_SUCCESS) { - // Failed to retrieve enabled backends. Should never happen in this example since all inputs are valid. + // Failed to retrieve enabled backends. Should never happen in this example since all inputs are valid. } ``` diff --git a/vendor/miniaudio/device_io_types.odin b/vendor/miniaudio/device_io_types.odin index e05f94665..b3ecb2301 100644 --- a/vendor/miniaudio/device_io_types.odin +++ b/vendor/miniaudio/device_io_types.odin @@ -18,12 +18,13 @@ SUPPORT_WEBAUDIO :: false // ODIN_OS == .Emscripten SUPPORT_CUSTOM :: true SUPPORT_NULL :: true // ODIN_OS != .Emscripten -STATE_UNINITIALIZED :: 0 -STATE_STOPPED :: 1 /* The device's default state after initialization. */ -STATE_STARTED :: 2 /* The device is started and is requesting and/or delivering audio data. */ -STATE_STARTING :: 3 /* Transitioning from a stopped state to started. */ -STATE_STOPPING :: 4 /* Transitioning from a started state to stopped. */ - +device_state :: enum c.int { + uninitialized = 0, + stopped = 1, /* The device's default state after initialization. */ + started = 2, /* The device is started and is requesting and/or delivering audio data. */ + starting = 3, /* Transitioning from a stopped state to started. */ + stopping = 4, /* Transitioning from a started state to stopped. */ +} when SUPPORT_WASAPI { @@ -56,6 +57,96 @@ backend :: enum c.int { BACKEND_COUNT :: len(backend) +/* +Device job thread. This is used by backends that require asynchronous processing of certain +operations. It is not used by all backends. + +The device job thread is made up of a thread and a job queue. You can post a job to the thread with +ma_device_job_thread_post(). The thread will do the processing of the job. +*/ +device_job_thread_config :: struct { + noThread: b32, /* Set this to true if you want to process jobs yourself. */ + jobQueueCapacity: u32, + jobQueueFlags: u32, +} + +device_job_thread :: struct { + thread: thread, + jobQueue: job_queue, + _hasThread: b32, +} + + +/* Device notification types. */ +device_notification_type :: enum c.int { + started, + stopped, + rerouted, + interruption_began, + interruption_ended, +} + +device_notification :: struct { + pDevice: ^device, + type: device_notification_type, + data: struct #raw_union { + started: struct { + _unused: c.int, + }, + stopped: struct { + _unused: c.int, + }, + rerouted: struct { + _unused: c.int, + }, + interruption: struct { + _unused: c.int, + }, + }, +} + +/* +The notification callback for when the application should be notified of a change to the device. + +This callback is used for notifying the application of changes such as when the device has started, +stopped, rerouted or an interruption has occurred. Note that not all backends will post all +notification types. For example, some backends will perform automatic stream routing without any +kind of notification to the host program which means miniaudio will never know about it and will +never be able to fire the rerouted notification. You should keep this in mind when designing your +program. + +The stopped notification will *not* get fired when a device is rerouted. + + +Parameters +---------- +pNotification (in) + A pointer to a structure containing information about the event. Use the `pDevice` member of + this object to retrieve the relevant device. The `type` member can be used to discriminate + against each of the notification types. + + +Remarks +------- +Do not restart or uninitialize the device from the callback. + +Not all notifications will be triggered by all backends, however the started and stopped events +should be reliable for all backends. Some backends do not have a good way to detect device +stoppages due to unplugging the device which may result in the stopped callback not getting +fired. This has been observed with at least one BSD variant. + +The rerouted notification is fired *after* the reroute has occurred. The stopped notification will +*not* get fired when a device is rerouted. The following backends are known to do automatic stream +rerouting, but do not have a way to be notified of the change: + + * DirectSound + +The interruption notifications are used on mobile platforms for detecting when audio is interrupted +due to things like an incoming phone call. Currently this is only implemented on iOS. None of the +Android backends will report this notification. +*/ +device_notification_proc :: proc "c" (pNotification: ^device_notification) + /* The callback for processing audio data from the device. @@ -96,9 +187,11 @@ callback. The following APIs cannot be called from inside the callback: The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread. */ -device_callback_proc :: proc "c" (pDevice: ^device, pOutput: rawptr, pInput: rawptr, frameCount: u32) +device_data_proc :: proc "c" (pDevice: ^device, pOutput, pInput: rawptr, frameCount: u32) /* +DEPRECATED. Use ma_device_notification_proc instead. + The callback for when the device has been stopped. This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces @@ -108,48 +201,15 @@ such as being unplugged or an internal error occuring. Parameters ---------- pDevice (in) - A pointer to the device that has just stopped. + A pointer to the device that has just stopped. Remarks ------- Do not restart or uninitialize the device from the callback. */ -stop_proc :: proc "c" (pDevice: ^device) +stop_proc :: proc "c" (pDevice: ^device) /* DEPRECATED. Use ma_device_notification_proc instead. */ -/* -The callback for handling log messages. - - -Parameters ----------- -pContext (in) - A pointer to the context the log message originated from. - -pDevice (in) - A pointer to the device the log message originate from, if any. This can be null, in which case the message came from the context. - -logLevel (in) - The log level. This can be one of the following: - - +----------------------+ - | Log Level | - +----------------------+ - | MA_LOG_LEVEL_DEBUG | - | MA_LOG_LEVEL_INFO | - | MA_LOG_LEVEL_WARNING | - | MA_LOG_LEVEL_ERROR | - +----------------------+ - -message (in) - The log message. - - -Remarks -------- -Do not modify the state of the device from inside the callback. -*/ -log_proc :: proc "c" (pContext: context_type, pDevice: ^device, logLevel: u32, message: cstring) device_type :: enum c.int { playback = 1, @@ -279,29 +339,14 @@ device_id :: struct #raw_union { DATA_FORMAT_FLAG_EXCLUSIVE_MODE :: 1 << 1 /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */ +MAX_DEVICE_NAME_LENGTH :: 255 + device_info :: struct { /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */ id: device_id, - name: [256]byte, + name: [MAX_DEVICE_NAME_LENGTH + 1]c.char, /* +1 for null terminator. */ isDefault: b32, - /* - Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize - a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion - pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided - here mainly for informational purposes or in the rare case that someone might find it useful. - - These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices(). - */ - formatCount: u32, - formats: [format]format, - minChannels: u32, - maxChannels: u32, - minSampleRate: u32, - maxSampleRate: u32, - - - /* Experimental. Don't use these right now. */ nativeDataFormatCount: u32, nativeDataFormats: [/*len(format_count) * standard_sample_rate.rate_count * MAX_CHANNELS*/ 64]struct { /* Not sure how big to make this. There can be *many* permutations for virtual devices which can support anything. */ format: format, /* Sample format. If set to ma_format_unknown, all sample formats are supported. */ @@ -312,31 +357,26 @@ device_info :: struct { } device_config :: struct { - deviceType: device_type, - sampleRate: u32, - periodSizeInFrames: u32, - periodSizeInMilliseconds: u32, - periods: u32, - performanceProfile: performance_profile, - noPreZeroedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */ - noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ - dataCallback: device_callback_proc, - stopCallback: stop_proc, - pUserData: rawptr, - resampling: struct { - algorithm: resample_algorithm, - linear: struct { - lpfOrder: u32, - }, - speex: struct { - quality: c.int, - }, - }, + deviceType: device_type, + sampleRate: u32, + periodSizeInFrames: u32, + periodSizeInMilliseconds: u32, + periods: u32, + performanceProfile: performance_profile, + noPreSilencedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */ + noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ + noDisableDenormals: b8, /* Do not disable denormals when firing the data callback. */ + noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */ + dataCallback: device_data_proc, + notificationCallback: device_notification_proc, + stopCallback: stop_proc, + pUserData: rawptr, + resampling: resampler_config, playback: struct { pDeviceID: ^device_id, format: format, channels: u32, - channelMap: [MAX_CHANNELS]channel, + channelMap: [^]channel, channelMixMode: channel_mix_mode, shareMode: share_mode, }, @@ -344,7 +384,7 @@ device_config :: struct { pDeviceID: ^device_id, format: format, channels: u32, - channelMap: [MAX_CHANNELS]channel, + channelMap: [^]channel, channelMixMode: channel_mix_mode, shareMode: share_mode, }, @@ -373,9 +413,10 @@ device_config :: struct { recordingPreset: opensl_recording_preset, }, aaudio: struct { - usage: aaudio_usage, - contentType: aaudio_content_type, - inputPreset: aaudio_input_preset, + usage: aaudio_usage, + contentType: aaudio_content_type, + inputPreset: aaudio_input_preset, + noAutoStartAfterReroute: b32, }, } @@ -425,14 +466,14 @@ to many devices. A device is created from a context. The general flow goes like this: 1) A context is created with `onContextInit()` - 1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required. - 1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required. + 1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required. + 1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required. 2) A device is created from the context that was created in the first step using `onDeviceInit()`, and optionally a device ID that was - selected from device enumeration via `onContextEnumerateDevices()`. + selected from device enumeration via `onContextEnumerateDevices()`. 3) A device is started or stopped with `onDeviceStart()` / `onDeviceStop()` 4) Data is delivered to and from the device by the backend. This is always done based on the native format returned by the prior call - to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by - miniaudio internally. + to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by + miniaudio internally. Initialization of the context is quite simple. You need to do any necessary initialization of internal objects and then output the callbacks defined in this structure. @@ -440,7 +481,7 @@ callbacks defined in this structure. Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration -needs to stop and the `onContextEnumerateDevices()` function return with a success code. +needs to stop and the `onContextEnumerateDevices()` function returns with a success code. Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID, and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the @@ -455,7 +496,7 @@ internally by miniaudio. On input, if the sample format is set to `ma_format_unknown`, the backend is free to use whatever sample format it desires, so long as it's supported by miniaudio. When the channel count is set to 0, the backend should use the device's native channel count. The same applies for -sample rate. For the channel map, the default should be used when `ma_channel_map_blank()` returns true (all channels set to +sample rate. For the channel map, the default should be used when `ma_channel_map_is_blank()` returns true (all channels set to `MA_CHANNEL_NONE`). On input, the `periodSizeInFrames` or `periodSizeInMilliseconds` option should always be set. The backend should inspect both of these variables. If `periodSizeInFrames` is set, it should take priority, otherwise it needs to be derived from the period size in milliseconds (`periodSizeInMilliseconds`) and the sample rate, keeping in mind that the sample rate may be 0, in which case the @@ -474,14 +515,17 @@ This allows miniaudio to then process any necessary data conversion and then pas If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional. -The audio thread should run data delivery logic in a loop while `ma_device_get_state() == MA_STATE_STARTED` and no errors have been +The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback. The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this -callback. When the device is stopped, the `ma_device_get_state() == MA_STATE_STARTED` condition will fail and the loop will be terminated +callback. When the device is stopped, the `ma_device_get_state() == ma_device_state_started` condition will fail and the loop will be terminated which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback, look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to wake up the audio thread. + +If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the +`onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient. */ backend_callbacks :: struct { onContextInit: proc "c" (pContext: ^context_type, pConfig: ^context_config, pCallbacks: ^backend_callbacks) -> result, @@ -496,10 +540,10 @@ backend_callbacks :: struct { onDeviceWrite: proc "c" (pDevice: ^device, pFrames: rawptr, frameCount: u32, pFramesWritten: ^u32) -> result, onDeviceDataLoop: proc "c" (pDevice: ^device) -> result, onDeviceDataLoopWakeup: proc "c" (pDevice: ^device) -> result, + onDeviceGetInfo: proc "c" (pDevice: ^device, type: device_type, pDeviceInfo: ^device_info) -> result, } context_config :: struct { - logCallback: log_proc, /* Legacy logging callback. Will be removed in version 0.11. */ pLog: ^log, threadPriority: thread_priority, threadStackSize: c.size_t, @@ -538,7 +582,7 @@ context_command__wasapi :: struct { deviceType: device_type, pAudioClient: rawptr, ppAudioClientService: ^rawptr, - pResult: ^rawptr, /* The result from creating the audio client service. */ + pResult: ^result, /* The result from creating the audio client service. */ }, releaseAudioClient: struct { pDevice: ^device, @@ -548,21 +592,20 @@ context_command__wasapi :: struct { } context_type :: struct { - callbacks: backend_callbacks, - backend: backend, /* DirectSound, ALSA, etc. */ - pLog: ^log, - log: log, /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */ - logCallback: log_proc, /* Legacy callback. Will be removed in version 0.11. */ - threadPriority: thread_priority, - threadStackSize: c.size_t, - pUserData: rawptr, - allocationCallbacks: allocation_callbacks, - deviceEnumLock: mutex, /* Used to make ma_context_get_devices() thread safe. */ - deviceInfoLock: mutex, /* Used to make ma_context_get_device_info() thread safe. */ - deviceInfoCapacity: u32, /* Total capacity of pDeviceInfos. */ + callbacks: backend_callbacks, + backend: backend, /* DirectSound, ALSA, etc. */ + pLog: ^log, + log: log, /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */ + threadPriority: thread_priority, + threadStackSize: c.size_t, + pUserData: rawptr, + allocationCallbacks: allocation_callbacks, + deviceEnumLock: mutex, /* Used to make ma_context_get_devices() thread safe. */ + deviceInfoLock: mutex, /* Used to make ma_context_get_device_info() thread safe. */ + deviceInfoCapacity: u32, /* Total capacity of pDeviceInfos. */ playbackDeviceInfoCount: u32, - captureDeviceInfoCount: u32, - pDeviceInfos: [^]device_info, /* Playback devices first, then capture. */ + captureDeviceInfoCount: u32, + pDeviceInfos: [^]device_info, /* Playback devices first, then capture. */ using _: struct #raw_union { wasapi: (struct { @@ -575,7 +618,7 @@ context_type :: struct { } when SUPPORT_WASAPI else struct {}), dsound: (struct { - DSoundDLL: handle, + hDSoundDLL: handle, DirectSoundCreate: proc "system" (), DirectSoundEnumerateA: proc "system" (), DirectSoundCaptureCreate: proc "system" (), @@ -741,6 +784,8 @@ context_type :: struct { /*pa_mainloop**/ pMainLoop: rawptr, /*pa_context**/ pPulseContext: rawptr, + pApplicationName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */ + pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */ } when SUPPORT_PULSEAUDIO else struct {}), jack: (struct { @@ -762,7 +807,7 @@ context_type :: struct { jack_port_get_buffer: proc "system" (), jack_free: proc "system" (), - pClientName: [^]c.char, + pClientName: cstring, tryStartServer: b32, } when SUPPORT_JACK else struct {}), @@ -817,7 +862,7 @@ context_type :: struct { } when SUPPORT_SNDIO else struct {}), audio4: (struct { - _unused: cint, + _unused: c.int, } when SUPPORT_AUDIO4 else struct {}), oss: (struct { @@ -855,6 +900,7 @@ context_type :: struct { AAudioStream_getFramesPerBurst: proc "system" (), AAudioStream_requestStart: proc "system" (), AAudioStream_requestStop: proc "system" (), + jobThread: device_job_thread, /* For processing operations outside of the error callback, specifically device disconnections and rerouting. */ } when SUPPORT_AAUDIO else struct {}), opensl: (struct { @@ -921,37 +967,40 @@ context_type :: struct { } device :: struct { - pContext: ^context_type, - type: device_type, - sampleRate: u32, - state: u32, /*atomic*/ /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ - onData: device_callback_proc, /* Set once at initialization time and should not be changed after. */ - onStop: stop_proc, /* Set once at initialization time and should not be changed after. */ - pUserData: rawptr, /* Application defined data. */ - startStopLock: mutex, - wakeupEvent: event, - startEvent: event, - stopEvent: event, - device_thread: thread, - workResult: result, /* This is set by the worker thread after it's finished doing a job. */ - isOwnerOfContext: b8, /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ - noPreZeroedOutputBuffer: b8, - noClip: b8, - masterVolumeFactor: f32, /*atomic*/ /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ - duplexRB: duplex_rb, /* Intermediary buffer for duplex device on asynchronous backends. */ + pContext: ^context_type, + type: device_type, + sampleRate: u32, + state: u32, /*atomic*/ /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ + onData: device_data_proc, /* Set once at initialization time and should not be changed after. */ + onNotification: device_notification_proc, /* Set once at initialization time and should not be changed after. */ + onStop: stop_proc, /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */ + pUserData: rawptr, /* Application defined data. */ + startStopLock: mutex, + wakeupEvent: event, + startEvent: event, + stopEvent: event, + device_thread: thread, + workResult: result, /* This is set by the worker thread after it's finished doing a job. */ + isOwnerOfContext: b8, /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ + noPreSilencedOutputBuffer: b8, + noClip: b8, + noDisableDenormals: b8, + noFixedSizedCallback: b8, + masterVolumeFactor: f32, /*atomic*/ /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ + duplexRB: duplex_rb, /* Intermediary buffer for duplex device on asynchronous backends. */ resampling: struct { - algorithm: resample_algorithm, + algorithm: resample_algorithm, + pBackendVTable: ^resampling_backend_vtable, + pBackendUserData: rawptr, linear: struct { lpfOrder: u32, }, - speex: struct { - quality: c.int, - }, }, playback: struct { - id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ - name: [256]byte, /* Maybe temporary. Likely to be replaced with a query API. */ - shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */ + pID: ^device_id, /* Set to NULL if using default ID, otherwise set to the address of "id". */ + id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ + name: [MAX_DEVICE_NAME_LENGTH + 1]c.char, /* Maybe temporary. Likely to be replaced with a query API. */ + shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */ playback_format: format, channels: u32, channelMap: [MAX_CHANNELS]channel, @@ -963,11 +1012,19 @@ device :: struct { internalPeriods: u32, channelMixMode: channel_mix_mode, converter: data_converter, + pIntermediaryBuffer: rawptr, /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */ + intermediaryBufferCap: u32, + intermediaryBufferLen: u32, /* How many valid frames are sitting in the intermediary buffer. */ + pInputCache: rawptr, /* In external format. Can be null. */ + inputCacheCap: u64, + inputCacheConsumed: u64, + inputCacheRemaining: u64, }, capture: struct { - id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ - name: [256]byte, /* Maybe temporary. Likely to be replaced with a query API. */ - shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */ + pID: ^device_id, /* Set to NULL if using default ID, otherwise set to the address of "id". */ + id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ + name: [MAX_DEVICE_NAME_LENGTH + 1]c.char, /* Maybe temporary. Likely to be replaced with a query API. */ + shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */ capture_format: format, channels: u32, channelMap: [MAX_CHANNELS]channel, @@ -979,6 +1036,9 @@ device :: struct { internalPeriods: u32, channelMixMode: channel_mix_mode, converter: data_converter, + pIntermediaryBuffer: rawptr, /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */ + intermediaryBufferCap: u32, + intermediaryBufferLen: u32, /* How many valid frames are sitting in the intermediary buffer. */ }, using _: struct #raw_union { @@ -991,7 +1051,7 @@ device :: struct { notificationClient: IMMNotificationClient, /*HANDLE*/ hEventPlayback: handle, /* Auto reset. Initialized to signaled. */ /*HANDLE*/ hEventCapture: handle, /* Auto reset. Initialized to unsignaled. */ - actualPeriodSizeInFramesPlayback: u32, /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */ + actualPeriodSizeInFramesPlayback: u32, /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */ actualPeriodSizeInFramesCapture: u32, originalPeriodSizeInFrames: u32, originalPeriodSizeInMilliseconds: u32, @@ -999,8 +1059,14 @@ device :: struct { originalPerformanceProfile: performance_profile, periodSizeInFramesPlayback: u32, periodSizeInFramesCapture: u32, - isStartedCapture: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ - isStartedPlayback: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ + pMappedBufferCapture: rawptr, + mappedBufferCaptureCap: u32, + mappedBufferCaptureLen: u32, + pMappedBufferPlayback: rawptr, + mappedBufferPlaybackCap: u32, + mappedBufferPlaybackLen: u32, + isStartedCapture: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ + isStartedPlayback: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ noAutoConvertSRC: b8, /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */ noDefaultQualitySRC: b8, /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */ noHardwareOffloading: b8, @@ -1049,14 +1115,16 @@ device :: struct { } when SUPPORT_ALSA else struct {}), pulse: (struct { + /*pa_mainloop**/ pMainLoop: rawptr, + /*pa_context**/ pPulseContext: rawptr, /*pa_stream**/ pStreamPlayback: rawptr, /*pa_stream**/ pStreamCapture: rawptr, } when SUPPORT_PULSEAUDIO else struct {}), jack: (struct { /*jack_client_t**/ pClient: rawptr, - /*jack_port_t**/ pPortsPlayback: [MAX_CHANNELS]rawptr, - /*jack_port_t**/ pPortsCapture: [MAX_CHANNELS]rawptr, + /*jack_port_t**/ pPortsPlayback: [^]rawptr, + /*jack_port_t**/ pPortsCapture: [^]rawptr, pIntermediaryBufferPlayback: [^]f32, /* Typed as a float because JACK is always floating point. */ pIntermediaryBufferCapture: [^]f32, } when SUPPORT_JACK else struct {}), @@ -1079,6 +1147,7 @@ device :: struct { isSwitchingCaptureDevice: b32, /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */ pRouteChangeHandler: rawptr, /* Only used on mobile platforms. Obj-C object for handling route changes. */ } when SUPPORT_COREAUDIO else struct {}), + sndio: (struct { handlePlayback: rawptr, handleCapture: rawptr, @@ -1099,6 +1168,10 @@ device :: struct { aaudio: (struct { /*AAudioStream**/ pStreamPlayback: rawptr, /*AAudioStream**/ pStreamCapture: rawptr, + usage: aaudio_usage, + contentType: aaudio_content_type, + inputPreset: aaudio_input_preset, + noAutoStartAfterReroute: b32, } when SUPPORT_AAUDIO else struct {}), opensl: (struct { diff --git a/vendor/miniaudio/doc.odin b/vendor/miniaudio/doc.odin index 887e5d149..c6de0ec61 100644 --- a/vendor/miniaudio/doc.odin +++ b/vendor/miniaudio/doc.odin @@ -2,7 +2,7 @@ package miniaudio /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.10.42 - 2021-08-22 +miniaudio - v0.11.9 - 2022-04-20 David Reid - mackron@gmail.com @@ -14,7 +14,8 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -miniaudio is a single file library for audio playback and capture. To use it, do the following in one .c file: +miniaudio is a single file library for audio playback and capture. To use it, do the following in +one .c file: ```c #define MINIAUDIO_IMPLEMENTATION @@ -23,16 +24,44 @@ miniaudio is a single file library for audio playback and capture. To use it, do You can do `#include "miniaudio.h"` in other parts of the program just like any other header. -miniaudio uses the concept of a "device" as the abstraction for physical devices. The idea is that you choose a physical device to emit or capture audio from, -and then move data to/from the device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a callback which you specify when -initializing the device. +miniaudio includes both low level and high level APIs. The low level API is good for those who want +to do all of their mixing themselves and only require a light weight interface to the underlying +audio device. The high level API is good for those who have complex mixing and effect requirements. -When initializing the device you first need to configure it. The device configuration allows you to specify things like the format of the data delivered via -the callback, the size of the internal buffer and the ID of the device you want to emit or capture audio from. +In miniaudio, objects are transparent structures. Unlike many other libraries, there are no handles +to opaque objects which means you need to allocate memory for objects yourself. In the examples +presented in this documentation you will often see objects declared on the stack. You need to be +careful when translating these examples to your own code so that you don't accidentally declare +your objects on the stack and then cause them to become invalid once the function returns. In +addition, you must ensure the memory address of your objects remain the same throughout their +lifetime. You therefore cannot be making copies of your objects. -Once you have the device configuration set up you can initialize the device. When initializing a device you need to allocate memory for the device object -beforehand. This gives the application complete control over how the memory is allocated. In the example below we initialize a playback device on the stack, -but you could allocate it on the heap if that suits your situation better. +A config/init pattern is used throughout the entire library. The idea is that you set up a config +object and pass that into the initialization routine. The advantage to this system is that the +config object can be initialized with logical defaults and new properties added to it without +breaking the API. The config object can be allocated on the stack and does not need to be +maintained after initialization of the corresponding object. + + +1.1. Low Level API +------------------ +The low level API gives you access to the raw audio data of an audio device. It supports playback, +capture, full-duplex and loopback (WASAPI only). You can enumerate over devices to determine which +physical device(s) you want to connect to. + +The low level API uses the concept of a "device" as the abstraction for physical devices. The idea +is that you choose a physical device to emit or capture audio from, and then move data to/from the +device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a +callback which you specify when initializing the device. + +When initializing the device you first need to configure it. The device configuration allows you to +specify things like the format of the data delivered via the callback, the size of the internal +buffer and the ID of the device you want to emit or capture audio from. + +Once you have the device configuration set up you can initialize the device. When initializing a +device you need to allocate memory for the device object beforehand. This gives the application +complete control over how the memory is allocated. In the example below we initialize a playback +device on the stack, but you could allocate it on the heap if that suits your situation better. ```c void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) @@ -65,20 +94,27 @@ but you could allocate it on the heap if that suits your situation better. } ``` -In the example above, `data_callback()` is where audio data is written and read from the device. The idea is in playback mode you cause sound to be emitted -from the speakers by writing audio data to the output buffer (`pOutput` in the example). In capture mode you read data from the input buffer (`pInput`) to -extract sound captured by the microphone. The `frameCount` parameter tells you how many frames can be written to the output buffer and read from the input -buffer. A "frame" is one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 samples: one for the left, one for the right. -The channel count is defined by the device config. The size in bytes of an individual sample is defined by the sample format which is also specified in the -device config. Multi-channel audio data is always interleaved, which means the samples for each frame are stored next to each other in memory. For example, in -a stereo stream the first pair of samples will be the left and right samples for the first frame, the second pair of samples will be the left and right samples -for the second frame, etc. +In the example above, `data_callback()` is where audio data is written and read from the device. +The idea is in playback mode you cause sound to be emitted from the speakers by writing audio data +to the output buffer (`pOutput` in the example). In capture mode you read data from the input +buffer (`pInput`) to extract sound captured by the microphone. The `frameCount` parameter tells you +how many frames can be written to the output buffer and read from the input buffer. A "frame" is +one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 +samples: one for the left, one for the right. The channel count is defined by the device config. +The size in bytes of an individual sample is defined by the sample format which is also specified +in the device config. Multi-channel audio data is always interleaved, which means the samples for +each frame are stored next to each other in memory. For example, in a stereo stream the first pair +of samples will be the left and right samples for the first frame, the second pair of samples will +be the left and right samples for the second frame, etc. -The configuration of the device is defined by the `ma_device_config` structure. The config object is always initialized with `ma_device_config_init()`. It's -important to always initialize the config with this function as it initializes it with logical defaults and ensures your program doesn't break when new members -are added to the `ma_device_config` structure. The example above uses a fairly simple and standard device configuration. The call to `ma_device_config_init()` -takes a single parameter, which is whether or not the device is a playback, capture, duplex or loopback device (loopback devices are not supported on all -backends). The `config.playback.format` member sets the sample format which can be one of the following (all formats are native-endian): +The configuration of the device is defined by the `ma_device_config` structure. The config object +is always initialized with `ma_device_config_init()`. It's important to always initialize the +config with this function as it initializes it with logical defaults and ensures your program +doesn't break when new members are added to the `ma_device_config` structure. The example above +uses a fairly simple and standard device configuration. The call to `ma_device_config_init()` takes +a single parameter, which is whether or not the device is a playback, capture, duplex or loopback +device (loopback devices are not supported on all backends). The `config.playback.format` member +sets the sample format which can be one of the following (all formats are native-endian): +---------------+----------------------------------------+---------------------------+ | Symbol | Description | Range | @@ -90,22 +126,30 @@ backends). The `config.playback.format` member sets the sample format which can | ma_format_u8 | 8-bit unsigned integer | [0, 255] | +---------------+----------------------------------------+---------------------------+ -The `config.playback.channels` member sets the number of channels to use with the device. The channel count cannot exceed MA_MAX_CHANNELS. The -`config.sampleRate` member sets the sample rate (which must be the same for both playback and capture in full-duplex configurations). This is usually set to -44100 or 48000, but can be set to anything. It's recommended to keep this between 8000 and 384000, however. +The `config.playback.channels` member sets the number of channels to use with the device. The +channel count cannot exceed MA_MAX_CHANNELS. The `config.sampleRate` member sets the sample rate +(which must be the same for both playback and capture in full-duplex configurations). This is +usually set to 44100 or 48000, but can be set to anything. It's recommended to keep this between +8000 and 384000, however. -Note that leaving the format, channel count and/or sample rate at their default values will result in the internal device's native configuration being used -which is useful if you want to avoid the overhead of miniaudio's automatic data conversion. +Note that leaving the format, channel count and/or sample rate at their default values will result +in the internal device's native configuration being used which is useful if you want to avoid the +overhead of miniaudio's automatic data conversion. -In addition to the sample format, channel count and sample rate, the data callback and user data pointer are also set via the config. The user data pointer is -not passed into the callback as a parameter, but is instead set to the `pUserData` member of `ma_device` which you can access directly since all miniaudio -structures are transparent. +In addition to the sample format, channel count and sample rate, the data callback and user data +pointer are also set via the config. The user data pointer is not passed into the callback as a +parameter, but is instead set to the `pUserData` member of `ma_device` which you can access +directly since all miniaudio structures are transparent. -Initializing the device is done with `ma_device_init()`. This will return a result code telling you what went wrong, if anything. On success it will return -`MA_SUCCESS`. After initialization is complete the device will be in a stopped state. To start it, use `ma_device_start()`. Uninitializing the device will stop -it, which is what the example above does, but you can also stop the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again. -Note that it's important to never stop or start the device from inside the callback. This will result in a deadlock. Instead you set a variable or signal an -event indicating that the device needs to stop and handle it in a different thread. The following APIs must never be called inside the callback: +Initializing the device is done with `ma_device_init()`. This will return a result code telling you +what went wrong, if anything. On success it will return `MA_SUCCESS`. After initialization is +complete the device will be in a stopped state. To start it, use `ma_device_start()`. +Uninitializing the device will stop it, which is what the example above does, but you can also stop +the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again. +Note that it's important to never stop or start the device from inside the callback. This will +result in a deadlock. Instead you set a variable or signal an event indicating that the device +needs to stop and handle it in a different thread. The following APIs must never be called inside +the callback: ```c ma_device_init() @@ -115,12 +159,14 @@ event indicating that the device needs to stop and handle it in a different thre ma_device_stop() ``` -You must never try uninitializing and reinitializing a device inside the callback. You must also never try to stop and start it from inside the callback. There -are a few other things you shouldn't do in the callback depending on your requirements, however this isn't so much a thread-safety thing, but rather a -real-time processing thing which is beyond the scope of this introduction. +You must never try uninitializing and reinitializing a device inside the callback. You must also +never try to stop and start it from inside the callback. There are a few other things you shouldn't +do in the callback depending on your requirements, however this isn't so much a thread-safety +thing, but rather a real-time processing thing which is beyond the scope of this introduction. -The example above demonstrates the initialization of a playback device, but it works exactly the same for capture. All you need to do is change the device type -from `ma_device_type_playback` to `ma_device_type_capture` when setting up the config, like so: +The example above demonstrates the initialization of a playback device, but it works exactly the +same for capture. All you need to do is change the device type from `ma_device_type_playback` to +`ma_device_type_capture` when setting up the config, like so: ```c ma_device_config config = ma_device_config_init(ma_device_type_capture); @@ -128,8 +174,9 @@ from `ma_device_type_playback` to `ma_device_type_capture` when setting up the c config.capture.channels = MY_CHANNEL_COUNT; ``` -In the data callback you just read from the input buffer (`pInput` in the example above) and leave the output buffer alone (it will be set to NULL when the -device type is set to `ma_device_type_capture`). +In the data callback you just read from the input buffer (`pInput` in the example above) and leave +the output buffer alone (it will be set to NULL when the device type is set to +`ma_device_type_capture`). These are the available device types and how you should handle the buffers in the callback: @@ -142,23 +189,29 @@ These are the available device types and how you should handle the buffers in th | ma_device_type_loopback | Read from input buffer, leave output buffer untouched. | +-------------------------+--------------------------------------------------------+ -You will notice in the example above that the sample format and channel count is specified separately for playback and capture. This is to support different -data formats between the playback and capture devices in a full-duplex system. An example may be that you want to capture audio data as a monaural stream (one -channel), but output sound to a stereo speaker system. Note that if you use different formats between playback and capture in a full-duplex configuration you -will need to convert the data yourself. There are functions available to help you do this which will be explained later. +You will notice in the example above that the sample format and channel count is specified +separately for playback and capture. This is to support different data formats between the playback +and capture devices in a full-duplex system. An example may be that you want to capture audio data +as a monaural stream (one channel), but output sound to a stereo speaker system. Note that if you +use different formats between playback and capture in a full-duplex configuration you will need to +convert the data yourself. There are functions available to help you do this which will be +explained later. -The example above did not specify a physical device to connect to which means it will use the operating system's default device. If you have multiple physical -devices connected and you want to use a specific one you will need to specify the device ID in the configuration, like so: +The example above did not specify a physical device to connect to which means it will use the +operating system's default device. If you have multiple physical devices connected and you want to +use a specific one you will need to specify the device ID in the configuration, like so: ```c config.playback.pDeviceID = pMyPlaybackDeviceID; // Only if requesting a playback or duplex device. config.capture.pDeviceID = pMyCaptureDeviceID; // Only if requesting a capture, duplex or loopback device. ``` -To retrieve the device ID you will need to perform device enumeration, however this requires the use of a new concept called the "context". Conceptually -speaking the context sits above the device. There is one context to many devices. The purpose of the context is to represent the backend at a more global level -and to perform operations outside the scope of an individual device. Mainly it is used for performing run-time linking against backend libraries, initializing -backends and enumerating devices. The example below shows how to enumerate devices. +To retrieve the device ID you will need to perform device enumeration, however this requires the +use of a new concept called the "context". Conceptually speaking the context sits above the device. +There is one context to many devices. The purpose of the context is to represent the backend at a +more global level and to perform operations outside the scope of an individual device. Mainly it is +used for performing run-time linking against backend libraries, initializing backends and +enumerating devices. The example below shows how to enumerate devices. ```c ma_context context; @@ -199,44 +252,236 @@ backends and enumerating devices. The example below shows how to enumerate devic ma_context_uninit(&context); ``` -The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. The first parameter is a pointer to a list of `ma_backend` -values which are used to override the default backend priorities. When this is NULL, as in this example, miniaudio's default priorities are used. The second -parameter is the number of backends listed in the array pointed to by the first parameter. The third parameter is a pointer to a `ma_context_config` object -which can be NULL, in which case defaults are used. The context configuration is used for setting the logging callback, custom memory allocation callbacks, -user-defined data and some backend-specific configurations. +The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. +The first parameter is a pointer to a list of `ma_backend` values which are used to override the +default backend priorities. When this is NULL, as in this example, miniaudio's default priorities +are used. The second parameter is the number of backends listed in the array pointed to by the +first parameter. The third parameter is a pointer to a `ma_context_config` object which can be +NULL, in which case defaults are used. The context configuration is used for setting the logging +callback, custom memory allocation callbacks, user-defined data and some backend-specific +configurations. -Once the context has been initialized you can enumerate devices. In the example above we use the simpler `ma_context_get_devices()`, however you can also use a -callback for handling devices by using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer to a pointer that will, -upon output, be set to a pointer to a buffer containing a list of `ma_device_info` structures. You also provide a pointer to an unsigned integer that will -receive the number of items in the returned buffer. Do not free the returned buffers as their memory is managed internally by miniaudio. +Once the context has been initialized you can enumerate devices. In the example above we use the +simpler `ma_context_get_devices()`, however you can also use a callback for handling devices by +using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer +to a pointer that will, upon output, be set to a pointer to a buffer containing a list of +`ma_device_info` structures. You also provide a pointer to an unsigned integer that will receive +the number of items in the returned buffer. Do not free the returned buffers as their memory is +managed internally by miniaudio. -The `ma_device_info` structure contains an `id` member which is the ID you pass to the device config. It also contains the name of the device which is useful -for presenting a list of devices to the user via the UI. +The `ma_device_info` structure contains an `id` member which is the ID you pass to the device +config. It also contains the name of the device which is useful for presenting a list of devices +to the user via the UI. -When creating your own context you will want to pass it to `ma_device_init()` when initializing the device. Passing in NULL, like we do in the first example, -will result in miniaudio creating the context for you, which you don't want to do since you've already created a context. Note that internally the context is -only tracked by it's pointer which means you must not change the location of the `ma_context` object. If this is an issue, consider using `malloc()` to -allocate memory for the context. +When creating your own context you will want to pass it to `ma_device_init()` when initializing the +device. Passing in NULL, like we do in the first example, will result in miniaudio creating the +context for you, which you don't want to do since you've already created a context. Note that +internally the context is only tracked by it's pointer which means you must not change the location +of the `ma_context` object. If this is an issue, consider using `malloc()` to allocate memory for +the context. + + +1.2. High Level API +------------------- +The high level API consists of three main parts: + + * Resource management for loading and streaming sounds. + * A node graph for advanced mixing and effect processing. + * A high level "engine" that wraps around the resource manager and node graph. + +The resource manager (`ma_resource_manager`) is used for loading sounds. It supports loading sounds +fully into memory and also streaming. It will also deal with reference counting for you which +avoids the same sound being loaded multiple times. + +The node graph is used for mixing and effect processing. The idea is that you connect a number of +nodes into the graph by connecting each node's outputs to another node's inputs. Each node can +implement it's own effect. By chaining nodes together, advanced mixing and effect processing can +be achieved. + +The engine encapsulates both the resource manager and the node graph to create a simple, easy to +use high level API. The resource manager and node graph APIs are covered in more later sections of +this manual. + +The code below shows how you can initialize an engine using it's default configuration. + + ```c + ma_result result; + ma_engine engine; + + result = ma_engine_init(NULL, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +This creates an engine instance which will initialize a device internally which you can access with +`ma_engine_get_device()`. It will also initialize a resource manager for you which can be accessed +with `ma_engine_get_resource_manager()`. The engine itself is a node graph (`ma_node_graph`) which +means you can pass a pointer to the engine object into any of the `ma_node_graph` APIs (with a +cast). Alternatively, you can use `ma_engine_get_node_graph()` instead of a cast. + +Note that all objects in miniaudio, including the `ma_engine` object in the example above, are +transparent structures. There are no handles to opaque structures in miniaudio which means you need +to be mindful of how you declare them. In the example above we are declaring it on the stack, but +this will result in the struct being invalidated once the function encapsulating it returns. If +allocating the engine on the heap is more appropriate, you can easily do so with a standard call +to `malloc()` or whatever heap allocation routine you like: + + ```c + ma_engine* pEngine = malloc(sizeof(*pEngine)); + ``` + +The `ma_engine` API uses the same config/init pattern used all throughout miniaudio. To configure +an engine, you can fill out a `ma_engine_config` object and pass it into the first parameter of +`ma_engine_init()`: + + ```c + ma_result result; + ma_engine engine; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.pResourceManager = &myCustomResourceManager; // <-- Initialized as some earlier stage. + + result = ma_engine_init(&engineConfig, &engine); + if (result != MA_SUCCESS) { + return result; + } + ``` + +This creates an engine instance using a custom config. In this particular example it's showing how +you can specify a custom resource manager rather than having the engine initialize one internally. +This is particularly useful if you want to have multiple engine's share the same resource manager. + +The engine must be uninitialized with `ma_engine_uninit()` when it's no longer needed. + +By default the engine will be started, but nothing will be playing because no sounds have been +initialized. The easiest but least flexible way of playing a sound is like so: + + ```c + ma_engine_play_sound(&engine, "my_sound.wav", NULL); + ``` + +This plays what miniaudio calls an "inline" sound. It plays the sound once, and then puts the +internal sound up for recycling. The last parameter is used to specify which sound group the sound +should be associated with which will be explained later. This particular way of playing a sound is +simple, but lacks flexibility and features. A more flexible way of playing a sound is to first +initialize a sound: + + ```c + ma_result result; + ma_sound sound; + + result = ma_sound_init_from_file(&engine, "my_sound.wav", 0, NULL, NULL, &sound); + if (result != MA_SUCCESS) { + return result; + } + + ma_sound_start(&sound); + ``` + +This returns a `ma_sound` object which represents a single instance of the specified sound file. If +you want to play the same file multiple times simultaneously, you need to create one sound for each +instance. + +Sounds should be uninitialized with `ma_sound_uninit()`. + +Sounds are not started by default. Start a sound with `ma_sound_start()` and stop it with +`ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use +`ma_sound_seek_to_pcm_frames(&sound, 0)` to seek back to the start of a sound. By default, starting +and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound +the be started and/or stopped at a specific time. This can be done with the following functions: + + ```c + ma_sound_set_start_time_in_pcm_frames() + ma_sound_set_start_time_in_milliseconds() + ma_sound_set_stop_time_in_pcm_frames() + ma_sound_set_stop_time_in_milliseconds() + ``` + +The start/stop time needs to be specified based on the absolute timer which is controlled by the +engine. The current global time time in PCM frames can be retrieved with `ma_engine_get_time()`. +The engine's global time can be changed with `ma_engine_set_time()` for synchronization purposes if +required. Note that scheduling a start time still requires an explicit call to `ma_sound_start()` +before anything will play: + + ```c + ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 2); + ma_sound_start(&sound); + ``` + +The third parameter of `ma_sound_init_from_file()` is a set of flags that control how the sound be +loaded and a few options on which features should be enabled for that sound. By default, the sound +is synchronously loaded fully into memory straight from the file system without any kind of +decoding. If you want to decode the sound before storing it in memory, you need to specify the +`MA_SOUND_FLAG_DECODE` flag. This is useful if you want to incur the cost of decoding at an earlier +stage, such as a loading stage. Without this option, decoding will happen dynamically at mixing +time which might be too expensive on the audio thread. + +If you want to load the sound asynchronously, you can specify the `MA_SOUND_FLAG_ASYNC` flag. This +will result in `ma_sound_init_from_file()` returning quickly, but the sound will not start playing +until the sound has had some audio decoded. + +The fourth parameter is a pointer to sound group. A sound group is used as a mechanism to organise +sounds into groups which have their own effect processing and volume control. An example is a game +which might have separate groups for sfx, voice and music. Each of these groups have their own +independent volume control. Use `ma_sound_group_init()` or `ma_sound_group_init_ex()` to initialize +a sound group. + +Sounds and sound groups are nodes in the engine's node graph and can be plugged into any `ma_node` +API. This makes it possible to connect sounds and sound groups to effect nodes to produce complex +effect chains. + +A sound can have it's volume changed with `ma_sound_set_volume()`. If you prefer decibel volume +control you can use `ma_volume_db_to_linear()` to convert from decibel representation to linear. + +Panning and pitching is supported with `ma_sound_set_pan()` and `ma_sound_set_pitch()`. If you know +a sound will never have it's pitch changed with `ma_sound_set_pitch()` or via the doppler effect, +you can specify the `MA_SOUND_FLAG_NO_PITCH` flag when initializing the sound for an optimization. + +By default, sounds and sound groups have spatialization enabled. If you don't ever want to +spatialize your sounds, initialize the sound with the `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. The +spatialization model is fairly simple and is roughly on feature parity with OpenAL. HRTF and +environmental occlusion are not currently supported, but planned for the future. The supported +features include: + + * Sound and listener positioning and orientation with cones + * Attenuation models: none, inverse, linear and exponential + * Doppler effect + +Sounds can be faded in and out with `ma_sound_set_fade_in_pcm_frames()`. + +To check if a sound is currently playing, you can use `ma_sound_is_playing()`. To check if a sound +is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled with +`ma_sound_set_looping()`. Use `ma_sound_is_looping()` to check whether or not the sound is looping. 2. Building =========== -miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. +miniaudio should work cleanly out of the box without the need to download or install any +dependencies. See below for platform-specific details. 2.1. Windows ------------ -The Windows build should compile cleanly on all popular compilers without the need to configure any include paths nor link to any libraries. +The Windows build should compile cleanly on all popular compilers without the need to configure any +include paths nor link to any libraries. + +The UWP build may require linking to mmdevapi.lib if you get errors about an unresolved external +symbol for `ActivateAudioInterfaceAsync()`. + 2.2. macOS and iOS ------------------ -The macOS build should compile cleanly without the need to download any dependencies nor link to any libraries or frameworks. The iOS build needs to be -compiled as Objective-C and will need to link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling through the command line -requires linking to `-lpthread` and `-lm`. +The macOS build should compile cleanly without the need to download any dependencies nor link to +any libraries or frameworks. The iOS build needs to be compiled as Objective-C and will need to +link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling +through the command line requires linking to `-lpthread` and `-lm`. -Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's notarization process. To fix this there are two options. The -first is to use the `MA_NO_RUNTIME_LINKING` option, like so: +Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's +notarization process. To fix this there are two options. The first is to use the +`MA_NO_RUNTIME_LINKING` option, like so: ```c #ifdef __APPLE__ @@ -246,8 +491,9 @@ first is to use the `MA_NO_RUNTIME_LINKING` option, like so: #include "miniaudio.h" ``` -This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. Alternatively, if you would rather keep using runtime -linking you can add the following to your entitlements.xcent file: +This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. +Alternatively, if you would rather keep using runtime linking you can add the following to your +entitlements.xcent file: ``` com.apple.security.cs.allow-dyld-environment-variables @@ -256,26 +502,37 @@ linking you can add the following to your entitlements.xcent file: ``` +See this discussion for more info: https://github.com/mackron/miniaudio/issues/203. + 2.3. Linux ---------- -The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any development packages. +The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any +development packages. You may need to link with `-latomic` if you're compiling for 32-bit ARM. + 2.4. BSD -------- -The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS. +The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses +sndio and FreeBSD uses OSS. You may need to link with `-latomic` if you're compiling for 32-bit +ARM. + 2.5. Android ------------ -AAudio is the highest priority backend on Android. This should work out of the box without needing any kind of compiler configuration. Support for AAudio -starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+. +AAudio is the highest priority backend on Android. This should work out of the box without needing +any kind of compiler configuration. Support for AAudio starts with Android 8 which means older +versions will fall back to OpenSL|ES which requires API level 16+. + +There have been reports that the OpenSL|ES backend fails to initialize on some Android based +devices due to `dlopen()` failing to open "libOpenSLES.so". If this happens on your platform +you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES. -There have been reports that the OpenSL|ES backend fails to initialize on some Android based devices due to `dlopen()` failing to open "libOpenSLES.so". If -this happens on your platform you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES. 2.6. Emscripten --------------- -The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use -std=c* compiler flags, nor -ansi. +The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. +You cannot use `-std=c*` compiler flags, nor `-ansi`. 2.7. Build Options @@ -368,28 +625,26 @@ The Emscripten build emits Web Audio JavaScript directly and should compile clea +----------------------------------+--------------------------------------------------------------------+ | MA_NO_MP3 | Disables the built-in MP3 decoder. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_DEVICE_IO | Disables playback and recording. This will disable ma_context and | - | | ma_device APIs. This is useful if you only want to use miniaudio's | - | | data conversion and/or decoding APIs. | + | MA_NO_DEVICE_IO | Disables playback and recording. This will disable `ma_context` | + | | and `ma_device` APIs. This is useful if you only want to use | + | | miniaudio's data conversion and/or decoding APIs. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_THREADING | Disables the ma_thread, ma_mutex, ma_semaphore and ma_event APIs. | - | | This option is useful if you only need to use miniaudio for data | - | | conversion, decoding and/or encoding. Some families of APIs | - | | require threading which means the following options must also be | - | | set: | + | MA_NO_THREADING | Disables the `ma_thread`, `ma_mutex`, `ma_semaphore` and | + | | `ma_event` APIs. This option is useful if you only need to use | + | | miniaudio for data conversion, decoding and/or encoding. Some | + | | families of APIsrequire threading which means the following | + | | options must also be set: | | | | | | ``` | | | MA_NO_DEVICE_IO | | | ``` | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_GENERATION | Disables generation APIs such a ma_waveform and ma_noise. | + | MA_NO_GENERATION | Disables generation APIs such a `ma_waveform` and `ma_noise`. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_SSE2 | Disables SSE2 optimizations. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_AVX2 | Disables AVX2 optimizations. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_AVX512 | Disables AVX-512 optimizations. | - +----------------------------------+--------------------------------------------------------------------+ | MA_NO_NEON | Disables NEON optimizations. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_RUNTIME_LINKING | Disables runtime linking. This is useful for passing Apple's | @@ -401,47 +656,47 @@ The Emscripten build emits Web Audio JavaScript directly and should compile clea | | You may need to enable this if your target platform does not allow | | | runtime linking via `dlopen()`. | +----------------------------------+--------------------------------------------------------------------+ - | MA_DEBUG_OUTPUT | Enable processing of MA_LOG_LEVEL_DEBUG messages and `printf()` | - | | output. | + | MA_DEBUG_OUTPUT | Enable `printf()` output of debug logs (`MA_LOG_LEVEL_DEBUG`). | +----------------------------------+--------------------------------------------------------------------+ | MA_COINIT_VALUE | Windows only. The value to pass to internal calls to | | | `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`. | +----------------------------------+--------------------------------------------------------------------+ | MA_API | Controls how public APIs should be decorated. Default is `extern`. | +----------------------------------+--------------------------------------------------------------------+ - | MA_DLL | If set, configures MA_API to either import or export APIs | - | | depending on whether or not the implementation is being defined. | - | | If defining the implementation, MA_API will be configured to | - | | export. Otherwise it will be configured to import. This has no | - | | effect if MA_API is defined externally. | - +----------------------------------+--------------------------------------------------------------------+ 3. Definitions ============== -This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this -section is intended to clarify how miniaudio uses each term. +This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity +in the use of terms throughout the audio space, so this section is intended to clarify how miniaudio +uses each term. 3.1. Sample ----------- -A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit floating point number. +A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit +floating point number. 3.2. Frame / PCM Frame ---------------------- -A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 samples, a mono frame is 1 sample, a 5.1 surround sound frame -is 6 samples, etc. The terms "frame" and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio -needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it's referring to with something like "FLAC frame". +A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 +samples, a mono frame is 1 sample, a 5.1 surround sound frame is 6 samples, etc. The terms "frame" +and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. +If ever miniaudio needs to refer to a compressed frame, such as a FLAC frame, it will always +clarify what it's referring to with something like "FLAC frame". 3.3. Channel ------------ -A stream of monaural audio that is emitted from an individual speaker in a speaker system, or received from an individual microphone in a microphone system. A -stereo stream has two channels (a left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio systems refer to a channel as -a complex audio stream that's mixed with other channels to produce the final mix - this is completely different to miniaudio's use of the term "channel" and -should not be confused. +A stream of monaural audio that is emitted from an individual speaker in a speaker system, or +received from an individual microphone in a microphone system. A stereo stream has two channels (a +left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio +systems refer to a channel as a complex audio stream that's mixed with other channels to produce +the final mix - this is completely different to miniaudio's use of the term "channel" and should +not be confused. 3.4. Sample Rate ---------------- -The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number of PCM frames that are processed per second. +The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number +of PCM frames that are processed per second. 3.5. Formats ------------ @@ -461,10 +716,1685 @@ All formats are native-endian. -4. Decoding +4. Data Sources +=============== +The data source abstraction in miniaudio is used for retrieving audio data from some source. A few +examples include `ma_decoder`, `ma_noise` and `ma_waveform`. You will need to be familiar with data +sources in order to make sense of some of the higher level concepts in miniaudio. + +The `ma_data_source` API is a generic interface for reading from a data source. Any object that +implements the data source interface can be plugged into any `ma_data_source` function. + +To read data from a data source: + + ```c + ma_result result; + ma_uint64 framesRead; + + result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, &framesRead, loop); + if (result != MA_SUCCESS) { + return result; // Failed to read data from the data source. + } + ``` + +If you don't need the number of frames that were successfully read you can pass in `NULL` to the +`pFramesRead` parameter. If this returns a value less than the number of frames requested it means +the end of the file has been reached. `MA_AT_END` will be returned only when the number of frames +read is 0. + +When calling any data source function, with the exception of `ma_data_source_init()` and +`ma_data_source_uninit()`, you can pass in any object that implements a data source. For example, +you could plug in a decoder like so: + + ```c + ma_result result; + ma_uint64 framesRead; + ma_decoder decoder; // <-- This would be initialized with `ma_decoder_init_*()`. + + result = ma_data_source_read_pcm_frames(&decoder, pFramesOut, frameCount, &framesRead, loop); + if (result != MA_SUCCESS) { + return result; // Failed to read data from the decoder. + } + ``` + +If you want to seek forward you can pass in `NULL` to the `pFramesOut` parameter. Alternatively you +can use `ma_data_source_seek_pcm_frames()`. + +To seek to a specific PCM frame: + + ```c + result = ma_data_source_seek_to_pcm_frame(pDataSource, frameIndex); + if (result != MA_SUCCESS) { + return result; // Failed to seek to PCM frame. + } + ``` + +You can retrieve the total length of a data source in PCM frames, but note that some data sources +may not have the notion of a length, such as noise and waveforms, and others may just not have a +way of determining the length such as some decoders. To retrieve the length: + + ```c + ma_uint64 length; + + result = ma_data_source_get_length_in_pcm_frames(pDataSource, &length); + if (result != MA_SUCCESS) { + return result; // Failed to retrieve the length. + } + ``` + +Care should be taken when retrieving the length of a data source where the underlying decoder is +pulling data from a data stream with an undefined length, such as internet radio or some kind of +broadcast. If you do this, `ma_data_source_get_length_in_pcm_frames()` may never return. + +The current position of the cursor in PCM frames can also be retrieved: + + ```c + ma_uint64 cursor; + + result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursor); + if (result != MA_SUCCESS) { + return result; // Failed to retrieve the cursor. + } + ``` + +You will often need to know the data format that will be returned after reading. This can be +retrieved like so: + + ```c + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_channel channelMap[MA_MAX_CHANNELS]; + + result = ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS); + if (result != MA_SUCCESS) { + return result; // Failed to retrieve data format. + } + ``` + +If you do not need a specific data format property, just pass in NULL to the respective parameter. + +There may be cases where you want to implement something like a sound bank where you only want to +read data within a certain range of the underlying data. To do this you can use a range: + + ```c + result = ma_data_source_set_range_in_pcm_frames(pDataSource, rangeBegInFrames, rangeEndInFrames); + if (result != MA_SUCCESS) { + return result; // Failed to set the range. + } + ``` + +This is useful if you have a sound bank where many sounds are stored in the same file and you want +the data source to only play one of those sub-sounds. + +Custom loop points can also be used with data sources. By default, data sources will loop after +they reach the end of the data source, but if you need to loop at a specific location, you can do +the following: + + ```c + result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); + if (result != MA_SUCCESS) { + return result; // Failed to set the loop point. + } + ``` + +The loop point is relative to the current range. + +It's sometimes useful to chain data sources together so that a seamless transition can be achieved. +To do this, you can use chaining: + + ```c + ma_decoder decoder1; + ma_decoder decoder2; + + // ... initialize decoders with ma_decoder_init_*() ... + + result = ma_data_source_set_next(&decoder1, &decoder2); + if (result != MA_SUCCESS) { + return result; // Failed to set the next data source. + } + + result = ma_data_source_read_pcm_frames(&decoder1, pFramesOut, frameCount, pFramesRead, MA_FALSE); + if (result != MA_SUCCESS) { + return result; // Failed to read from the decoder. + } + ``` + +In the example above we're using decoders. When reading from a chain, you always want to read from +the top level data source in the chain. In the example above, `decoder1` is the top level data +source in the chain. When `decoder1` reaches the end, `decoder2` will start seamlessly without any +gaps. + +Note that the `loop` parameter is set to false in the example above. When this is set to true, only +the current data source will be looped. You can loop the entire chain by linking in a loop like so: + + ```c + ma_data_source_set_next(&decoder1, &decoder2); // decoder1 -> decoder2 + ma_data_source_set_next(&decoder2, &decoder1); // decoder2 -> decoder1 (loop back to the start). + ``` + +Note that setting up chaining is not thread safe, so care needs to be taken if you're dynamically +changing links while the audio thread is in the middle of reading. + +Do not use `ma_decoder_seek_to_pcm_frame()` as a means to reuse a data source to play multiple +instances of the same sound simultaneously. Instead, initialize multiple data sources for each +instance. This can be extremely inefficient depending on the data source and can result in +glitching due to subtle changes to the state of internal filters. + + +4.1. Custom Data Sources +------------------------ +You can implement a custom data source by implementing the functions in `ma_data_source_vtable`. +Your custom object must have `ma_data_source_base` as it's first member: + + ```c + struct my_data_source + { + ma_data_source_base base; + ... + }; + ``` + +In your initialization routine, you need to call `ma_data_source_init()` in order to set up the +base object (`ma_data_source_base`): + + ```c + static ma_result my_data_source_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) + { + // Read data here. Output in the same format returned by my_data_source_get_data_format(). + } + + static ma_result my_data_source_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) + { + // Seek to a specific PCM frame here. Return MA_NOT_IMPLEMENTED if seeking is not supported. + } + + static ma_result my_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) + { + // Return the format of the data here. + } + + static ma_result my_data_source_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) + { + // Retrieve the current position of the cursor here. Return MA_NOT_IMPLEMENTED and set *pCursor to 0 if there is no notion of a cursor. + } + + static ma_result my_data_source_get_length(ma_data_source* pDataSource, ma_uint64* pLength) + { + // Retrieve the length in PCM frames here. Return MA_NOT_IMPLEMENTED and set *pLength to 0 if there is no notion of a length or if the length is unknown. + } + + static g_my_data_source_vtable = + { + my_data_source_read, + my_data_source_seek, + my_data_source_get_data_format, + my_data_source_get_cursor, + my_data_source_get_length + }; + + ma_result my_data_source_init(my_data_source* pMyDataSource) + { + ma_result result; + ma_data_source_config baseConfig; + + baseConfig = ma_data_source_config_init(); + baseConfig.vtable = &g_my_data_source_vtable; + + result = ma_data_source_init(&baseConfig, &pMyDataSource->base); + if (result != MA_SUCCESS) { + return result; + } + + // ... do the initialization of your custom data source here ... + + return MA_SUCCESS; + } + + void my_data_source_uninit(my_data_source* pMyDataSource) + { + // ... do the uninitialization of your custom data source here ... + + // You must uninitialize the base data source. + ma_data_source_uninit(&pMyDataSource->base); + } + ``` + +Note that `ma_data_source_init()` and `ma_data_source_uninit()` are never called directly outside +of the custom data source. It's up to the custom data source itself to call these within their own +init/uninit functions. + + + +5. Engine +========= +The `ma_engine` API is a high level API for managing and mixing sounds and effect processing. The +`ma_engine` object encapsulates a resource manager and a node graph, both of which will be +explained in more detail later. + +Sounds are called `ma_sound` and are created from an engine. Sounds can be associated with a mixing +group called `ma_sound_group` which are also created from the engine. Both `ma_sound` and +`ma_sound_group` objects are nodes within the engine's node graph. + +When the engine is initialized, it will normally create a device internally. If you would rather +manage the device yourself, you can do so and just pass a pointer to it via the engine config when +you initialize the engine. You can also just use the engine without a device, which again can be +configured via the engine config. + +The most basic way to initialize the engine is with a default config, like so: + + ```c + ma_result result; + ma_engine engine; + + result = ma_engine_init(NULL, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +This will result in the engine initializing a playback device using the operating system's default +device. This will be sufficient for many use cases, but if you need more flexibility you'll want to +configure the engine with an engine config: + + ```c + ma_result result; + ma_engine engine; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.pPlaybackDevice = &myDevice; + + result = ma_engine_init(&engineConfig, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +In the example above we're passing in a pre-initialized device. Since the caller is the one in +control of the device's data callback, it's their responsibility to manually call +`ma_engine_read_pcm_frames()` from inside their data callback: + + ```c + void playback_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) + { + ma_engine_read_pcm_frames(&g_Engine, pOutput, frameCount, NULL); + } + ``` + +You can also use the engine independent of a device entirely: + + ```c + ma_result result; + ma_engine engine; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.noDevice = MA_TRUE; + engineConfig.channels = 2; // Must be set when not using a device. + engineConfig.sampleRate = 48000; // Must be set when not using a device. + + result = ma_engine_init(&engineConfig, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +Note that when you're not using a device, you must set the channel count and sample rate in the +config or else miniaudio won't know what to use (miniaudio will use the device to determine this +normally). When not using a device, you need to use `ma_engine_read_pcm_frames()` to process audio +data from the engine. This kind of setup is useful if you want to do something like offline +processing. + +When a sound is loaded it goes through a resource manager. By default the engine will initialize a +resource manager internally, but you can also specify a pre-initialized resource manager: + + ```c + ma_result result; + ma_engine engine1; + ma_engine engine2; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.pResourceManager = &myResourceManager; + + ma_engine_init(&engineConfig, &engine1); + ma_engine_init(&engineConfig, &engine2); + ``` + +In this example we are initializing two engines, both of which are sharing the same resource +manager. This is especially useful for saving memory when loading the same file across multiple +engines. If you were not to use a shared resource manager, each engine instance would use their own +which would result in any sounds that are used between both engine's being loaded twice. By using +a shared resource manager, it would only be loaded once. Using multiple engine's is useful when you +need to output to multiple playback devices, such as in a local multiplayer game where each player +is using their own set of headphones. + +By default an engine will be in a started state. To make it so the engine is not automatically +started you can configure it as such: + + ```c + engineConfig.noAutoStart = MA_TRUE; + + // The engine will need to be started manually. + ma_engine_start(&engine); + + // Later on the engine can be stopped with ma_engine_stop(). + ma_engine_stop(&engine); + ``` + +The concept of starting or stopping an engine is only relevant when using the engine with a +device. Attempting to start or stop an engine that is not associated with a device will result in +`MA_INVALID_OPERATION`. + +The master volume of the engine can be controlled with `ma_engine_set_volume()` which takes a +linear scale, with 0 resulting in silence and anything above 1 resulting in amplification. If you +prefer decibel based volume control, use `ma_volume_db_to_linear()` to convert from dB to linear. + +When a sound is spatialized, it is done so relative to a listener. An engine can be configured to +have multiple listeners which can be configured via the config: + + ```c + engineConfig.listenerCount = 2; + ``` + +The maximum number of listeners is restricted to `MA_ENGINE_MAX_LISTENERS`. By default, when a +sound is spatialized, it will be done so relative to the closest listener. You can also pin a sound +to a specific listener which will be explained later. Listener's have a position, direction, cone, +and velocity (for doppler effect). A listener is referenced by an index, the meaning of which is up +to the caller (the index is 0 based and cannot go beyond the listener count, minus 1). The +position, direction and velocity are all specified in absolute terms: + + ```c + ma_engine_listener_set_position(&engine, listenerIndex, worldPosX, worldPosY, worldPosZ); + ``` + +The direction of the listener represents it's forward vector. The listener's up vector can also be +specified and defaults to +1 on the Y axis. + + ```c + ma_engine_listener_set_direction(&engine, listenerIndex, forwardX, forwardY, forwardZ); + ma_engine_listener_set_world_up(&engine, listenerIndex, 0, 1, 0); + ``` + +The engine supports directional attenuation. The listener can have a cone the controls how sound is +attenuated based on the listener's direction. When a sound is between the inner and outer cones, it +will be attenuated between 1 and the cone's outer gain: + + ```c + ma_engine_listener_set_cone(&engine, listenerIndex, innerAngleInRadians, outerAngleInRadians, outerGain); + ``` + +When a sound is inside the inner code, no directional attenuation is applied. When the sound is +outside of the outer cone, the attenuation will be set to `outerGain` in the example above. When +the sound is in between the inner and outer cones, the attenuation will be interpolated between 1 +and the outer gain. + +The engine's coordinate system follows the OpenGL coordinate system where positive X points right, +positive Y points up and negative Z points forward. + +The simplest and least flexible way to play a sound is like so: + + ```c + ma_engine_play_sound(&engine, "my_sound.wav", pGroup); + ``` + +This is a "fire and forget" style of function. The engine will manage the `ma_sound` object +internally. When the sound finishes playing, it'll be put up for recycling. For more flexibility +you'll want to initialize a sound object: + + ```c + ma_sound sound; + + result = ma_sound_init_from_file(&engine, "my_sound.wav", flags, pGroup, NULL, &sound); + if (result != MA_SUCCESS) { + return result; // Failed to load sound. + } + ``` + +Sounds need to be uninitialized with `ma_sound_uninit()`. + +The example above loads a sound from a file. If the resource manager has been disabled you will not +be able to use this function and instead you'll need to initialize a sound directly from a data +source: + + ```c + ma_sound sound; + + result = ma_sound_init_from_data_source(&engine, &dataSource, flags, pGroup, &sound); + if (result != MA_SUCCESS) { + return result; + } + ``` + +Each `ma_sound` object represents a single instance of the sound. If you want to play the same +sound multiple times at the same time, you need to initialize a separate `ma_sound` object. + +For the most flexibility when initializing sounds, use `ma_sound_init_ex()`. This uses miniaudio's +standard config/init pattern: + + ```c + ma_sound sound; + ma_sound_config soundConfig; + + soundConfig = ma_sound_config_init(); + soundConfig.pFilePath = NULL; // Set this to load from a file path. + soundConfig.pDataSource = NULL; // Set this to initialize from an existing data source. + soundConfig.pInitialAttachment = &someNodeInTheNodeGraph; + soundConfig.initialAttachmentInputBusIndex = 0; + soundConfig.channelsIn = 1; + soundConfig.channelsOut = 0; // Set to 0 to use the engine's native channel count. + + result = ma_sound_init_ex(&soundConfig, &sound); + if (result != MA_SUCCESS) { + return result; + } + ``` + +In the example above, the sound is being initialized without a file nor a data source. This is +valid, in which case the sound acts as a node in the middle of the node graph. This means you can +connect other sounds to this sound and allow it to act like a sound group. Indeed, this is exactly +what a `ma_sound_group` is. + +When loading a sound, you specify a set of flags that control how the sound is loaded and what +features are enabled for that sound. When no flags are set, the sound will be fully loaded into +memory in exactly the same format as how it's stored on the file system. The resource manager will +allocate a block of memory and then load the file directly into it. When reading audio data, it +will be decoded dynamically on the fly. In order to save processing time on the audio thread, it +might be beneficial to pre-decode the sound. You can do this with the `MA_SOUND_FLAG_DECODE` flag: + + ```c + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE, pGroup, NULL, &sound); + ``` + +By default, sounds will be loaded synchronously, meaning `ma_sound_init_*()` will not return until +the sound has been fully loaded. If this is prohibitive you can instead load sounds asynchronously +by specificying the `MA_SOUND_FLAG_ASYNC` flag: + + ```c + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, NULL, &sound); + ``` + +This will result in `ma_sound_init_*()` returning quickly, but the sound won't yet have been fully +loaded. When you start the sound, it won't output anything until some sound is available. The sound +will start outputting audio before the sound has been fully decoded when the `MA_SOUND_FLAG_DECODE` +is specified. + +If you need to wait for an asynchronously loaded sound to be fully loaded, you can use a fence. A +fence in miniaudio is a simple synchronization mechanism which simply blocks until it's internal +counter hit's zero. You can specify a fence like so: + + ```c + ma_result result; + ma_fence fence; + ma_sound sounds[4]; + + result = ma_fence_init(&fence); + if (result != MA_SUCCES) { + return result; + } + + // Load some sounds asynchronously. + for (int iSound = 0; iSound < 4; iSound += 1) { + ma_sound_init_from_file(&engine, mySoundFilesPaths[iSound], MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, &fence, &sounds[iSound]); + } + + // ... do some other stuff here in the mean time ... + + // Wait for all sounds to finish loading. + ma_fence_wait(&fence); + ``` + +If loading the entire sound into memory is prohibitive, you can also configure the engine to stream +the audio data: + + ```c + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_STREAM, pGroup, NULL, &sound); + ``` + +When streaming sounds, 2 seconds worth of audio data is stored in memory. Although it should work +fine, it's inefficient to use streaming for short sounds. Streaming is useful for things like music +tracks in games. + +When you initialize a sound, if you specify a sound group the sound will be attached to that group +automatically. If you set it to NULL, it will be automatically attached to the engine's endpoint. +If you would instead rather leave the sound unattached by default, you can can specify the +`MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT` flag. This is useful if you want to set up a complex node +graph. + +Sounds are not started by default. To start a sound, use `ma_sound_start()`. Stop a sound with +`ma_sound_stop()`. + +Sounds can have their volume controlled with `ma_sound_set_volume()` in the same way as the +engine's master volume. + +Sounds support stereo panning and pitching. Set the pan with `ma_sound_set_pan()`. Setting the pan +to 0 will result in an unpanned sound. Setting it to -1 will shift everything to the left, whereas ++1 will shift it to the right. The pitch can be controlled with `ma_sound_set_pitch()`. A larger +value will result in a higher pitch. The pitch must be greater than 0. + +The engine supports 3D spatialization of sounds. By default sounds will have spatialization +enabled, but if a sound does not need to be spatialized it's best to disable it. There are two ways +to disable spatialization of a sound: + + ```c + // Disable spatialization at initialization time via a flag: + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, NULL, &sound); + + // Dynamically disable or enable spatialization post-initialization: + ma_sound_set_spatialization_enabled(&sound, isSpatializationEnabled); + ``` + +By default sounds will be spatialized based on the closest listener. If a sound should always be +spatialized relative to a specific listener it can be pinned to one: + + ```c + ma_sound_set_pinned_listener_index(&sound, listenerIndex); + ``` + +Like listeners, sounds have a position. By default, the position of a sound is in absolute space, +but it can be changed to be relative to a listener: + + ```c + ma_sound_set_positioning(&sound, ma_positioning_relative); + ``` + +Note that relative positioning of a sound only makes sense if there is either only one listener, or +the sound is pinned to a specific listener. To set the position of a sound: + + ```c + ma_sound_set_position(&sound, posX, posY, posZ); + ``` + +The direction works the same way as a listener and represents the sound's forward direction: + + ```c + ma_sound_set_direction(&sound, forwardX, forwardY, forwardZ); + ``` + +Sound's also have a cone for controlling directional attenuation. This works exactly the same as +listeners: + + ```c + ma_sound_set_cone(&sound, innerAngleInRadians, outerAngleInRadians, outerGain); + ``` + +The velocity of a sound is used for doppler effect and can be set as such: + + ```c + ma_sound_set_velocity(&sound, velocityX, velocityY, velocityZ); + ``` + +The engine supports different attenuation models which can be configured on a per-sound basis. By +default the attenuation model is set to `ma_attenuation_model_inverse` which is the equivalent to +OpenAL's `AL_INVERSE_DISTANCE_CLAMPED`. Configure the attenuation model like so: + + ```c + ma_sound_set_attenuation_model(&sound, ma_attenuation_model_inverse); + ``` + +The supported attenuation models include the following: + + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_none | No distance attenuation. | + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_inverse | Equivalent to `AL_INVERSE_DISTANCE_CLAMPED`. | + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_linear | Linear attenuation. | + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_exponential | Exponential attenuation. | + +----------------------------------+----------------------------------------------+ + +To control how quickly a sound rolls off as it moves away from the listener, you need to configure +the rolloff: + + ```c + ma_sound_set_rolloff(&sound, rolloff); + ``` + +You can control the minimum and maximum gain to apply from spatialization: + + ```c + ma_sound_set_min_gain(&sound, minGain); + ma_sound_set_max_gain(&sound, maxGain); + ``` + +Likewise, in the calculation of attenuation, you can control the minimum and maximum distances for +the attenuation calculation. This is useful if you want to ensure sounds don't drop below a certain +volume after the listener moves further away and to have sounds play a maximum volume when the +listener is within a certain distance: + + ```c + ma_sound_set_min_distance(&sound, minDistance); + ma_sound_set_max_distance(&sound, maxDistance); + ``` + +The engine's spatialization system supports doppler effect. The doppler factor can be configure on +a per-sound basis like so: + + ```c + ma_sound_set_doppler_factor(&sound, dopplerFactor); + ``` + +You can fade sounds in and out with `ma_sound_set_fade_in_pcm_frames()` and +`ma_sound_set_fade_in_milliseconds()`. Set the volume to -1 to use the current volume as the +starting volume: + + ```c + // Fade in over 1 second. + ma_sound_set_fade_in_milliseconds(&sound, 0, 1, 1000); + + // ... sometime later ... + + // Fade out over 1 second, starting from the current volume. + ma_sound_set_fade_in_milliseconds(&sound, -1, 0, 1000); + ``` + +By default sounds will start immediately, but sometimes for timing and synchronization purposes it +can be useful to schedule a sound to start or stop: + + ```c + // Start the sound in 1 second from now. + ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 1)); + + // Stop the sound in 2 seconds from now. + ma_sound_set_stop_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 2)); + ``` + +Note that scheduling a start time still requires an explicit call to `ma_sound_start()` before +anything will play. + +The time is specified in global time which is controlled by the engine. You can get the engine's +current time with `ma_engine_get_time()`. The engine's global time is incremented automatically as +audio data is read, but it can be reset with `ma_engine_set_time()` in case it needs to be +resynchronized for some reason. + +To determine whether or not a sound is currently playing, use `ma_sound_is_playing()`. This will +take the scheduled start and stop times into account. + +Whether or not a sound should loop can be controlled with `ma_sound_set_looping()`. Sounds will not +be looping by default. Use `ma_sound_is_looping()` to determine whether or not a sound is looping. + +Use `ma_sound_at_end()` to determine whether or not a sound is currently at the end. For a looping +sound this should never return true. + +Internally a sound wraps around a data source. Some APIs exist to control the underlying data +source, mainly for convenience: + + ```c + ma_sound_seek_to_pcm_frame(&sound, frameIndex); + ma_sound_get_data_format(&sound, &format, &channels, &sampleRate, pChannelMap, channelMapCapacity); + ma_sound_get_cursor_in_pcm_frames(&sound, &cursor); + ma_sound_get_length_in_pcm_frames(&sound, &length); + ``` + +Sound groups have the same API as sounds, only they are called `ma_sound_group`, and since they do +not have any notion of a data source, anything relating to a data source is unavailable. + +Internally, sound data is loaded via the `ma_decoder` API which means by default in only supports +file formats that have built-in support in miniaudio. You can extend this to support any kind of +file format through the use of custom decoders. To do this you'll need to use a self-managed +resource manager and configure it appropriately. See the "Resource Management" section below for +details on how to set this up. + + +6. Resource Management +====================== +Many programs will want to manage sound resources for things such as reference counting and +streaming. This is supported by miniaudio via the `ma_resource_manager` API. + +The resource manager is mainly responsible for the following: + + * Loading of sound files into memory with reference counting. + * Streaming of sound data + +When loading a sound file, the resource manager will give you back a `ma_data_source` compatible +object called `ma_resource_manager_data_source`. This object can be passed into any +`ma_data_source` API which is how you can read and seek audio data. When loading a sound file, you +specify whether or not you want the sound to be fully loaded into memory (and optionally +pre-decoded) or streamed. When loading into memory, you can also specify whether or not you want +the data to be loaded asynchronously. + +The example below is how you can initialize a resource manager using it's default configuration: + + ```c + ma_resource_manager_config config; + ma_resource_manager resourceManager; + + config = ma_resource_manager_config_init(); + result = ma_resource_manager_init(&config, &resourceManager); + if (result != MA_SUCCESS) { + ma_device_uninit(&device); + printf("Failed to initialize the resource manager."); + return -1; + } + ``` + +You can configure the format, channels and sample rate of the decoded audio data. By default it +will use the file's native data format, but you can configure it to use a consistent format. This +is useful for offloading the cost of data conversion to load time rather than dynamically +converting at mixing time. To do this, you configure the decoded format, channels and sample rate +like the code below: + + ```c + config = ma_resource_manager_config_init(); + config.decodedFormat = device.playback.format; + config.decodedChannels = device.playback.channels; + config.decodedSampleRate = device.sampleRate; + ``` + +In the code above, the resource manager will be configured so that any decoded audio data will be +pre-converted at load time to the device's native data format. If instead you used defaults and +the data format of the file did not match the device's data format, you would need to convert the +data at mixing time which may be prohibitive in high-performance and large scale scenarios like +games. + +Internally the resource manager uses the `ma_decoder` API to load sounds. This means by default it +only supports decoders that are built into miniaudio. It's possible to support additional encoding +formats through the use of custom decoders. To do so, pass in your `ma_decoding_backend_vtable` +vtables into the resource manager config: + + ```c + ma_decoding_backend_vtable* pCustomBackendVTables[] = + { + &g_ma_decoding_backend_vtable_libvorbis, + &g_ma_decoding_backend_vtable_libopus + }; + + ... + + resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables; + resourceManagerConfig.customDecodingBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]); + resourceManagerConfig.pCustomDecodingBackendUserData = NULL; + ``` + +This system can allow you to support any kind of file format. See the "Decoding" section for +details on how to implement custom decoders. The miniaudio repository includes examples for Opus +via libopus and libopusfile and Vorbis via libvorbis and libvorbisfile. + +Asynchronicity is achieved via a job system. When an operation needs to be performed, such as the +decoding of a page, a job will be posted to a queue which will then be processed by a job thread. +By default there will be only one job thread running, but this can be configured, like so: + + ```c + config = ma_resource_manager_config_init(); + config.jobThreadCount = MY_JOB_THREAD_COUNT; + ``` + +By default job threads are managed internally by the resource manager, however you can also self +manage your job threads if, for example, you want to integrate the job processing into your +existing job infrastructure, or if you simply don't like the way the resource manager does it. To +do this, just set the job thread count to 0 and process jobs manually. To process jobs, you first +need to retrieve a job using `ma_resource_manager_next_job()` and then process it using +`ma_job_process()`: + + ```c + config = ma_resource_manager_config_init(); + config.jobThreadCount = 0; // Don't manage any job threads internally. + config.flags = MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; // Optional. Makes `ma_resource_manager_next_job()` non-blocking. + + // ... Initialize your custom job threads ... + + void my_custom_job_thread(...) + { + for (;;) { + ma_job job; + ma_result result = ma_resource_manager_next_job(pMyResourceManager, &job); + if (result != MA_SUCCESS) { + if (result == MA_NOT_DATA_AVAILABLE) { + // No jobs are available. Keep going. Will only get this if the resource manager was initialized + // with MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. + continue; + } else if (result == MA_CANCELLED) { + // MA_JOB_TYPE_QUIT was posted. Exit. + break; + } else { + // Some other error occurred. + break; + } + } + + ma_job_process(&job); + } + } + ``` + +In the example above, the `MA_JOB_TYPE_QUIT` event is the used as the termination +indicator, but you can use whatever you would like to terminate the thread. The call to +`ma_resource_manager_next_job()` is blocking by default, but can be configured to be non-blocking +by initializing the resource manager with the `MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING` configuration +flag. Note that the `MA_JOB_TYPE_QUIT` will never be removed from the job queue. This +is to give every thread the opportunity to catch the event and terminate naturally. + +When loading a file, it's sometimes convenient to be able to customize how files are opened and +read instead of using standard `fopen()`, `fclose()`, etc. which is what miniaudio will use by +default. This can be done by setting `pVFS` member of the resource manager's config: + + ```c + // Initialize your custom VFS object. See documentation for VFS for information on how to do this. + my_custom_vfs vfs = my_custom_vfs_init(); + + config = ma_resource_manager_config_init(); + config.pVFS = &vfs; + ``` + +This is particularly useful in programs like games where you want to read straight from an archive +rather than the normal file system. If you do not specify a custom VFS, the resource manager will +use the operating system's normal file operations. This is default. + +To load a sound file and create a data source, call `ma_resource_manager_data_source_init()`. When +loading a sound you need to specify the file path and options for how the sounds should be loaded. +By default a sound will be loaded synchronously. The returned data source is owned by the caller +which means the caller is responsible for the allocation and freeing of the data source. Below is +an example for initializing a data source: + + ```c + ma_resource_manager_data_source dataSource; + ma_result result = ma_resource_manager_data_source_init(pResourceManager, pFilePath, flags, &dataSource); + if (result != MA_SUCCESS) { + // Error. + } + + // ... + + // A ma_resource_manager_data_source object is compatible with the `ma_data_source` API. To read data, just call + // the `ma_data_source_read_pcm_frames()` like you would with any normal data source. + result = ma_data_source_read_pcm_frames(&dataSource, pDecodedData, frameCount, &framesRead); + if (result != MA_SUCCESS) { + // Failed to read PCM frames. + } + + // ... + + ma_resource_manager_data_source_uninit(pResourceManager, &dataSource); + ``` + +The `flags` parameter specifies how you want to perform loading of the sound file. It can be a +combination of the following flags: + + ``` + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT + ``` + +When no flags are specified (set to 0), the sound will be fully loaded into memory, but not +decoded, meaning the raw file data will be stored in memory, and then dynamically decoded when +`ma_data_source_read_pcm_frames()` is called. To instead decode the audio data before storing it in +memory, use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` flag. By default, the sound file will +be loaded synchronously, meaning `ma_resource_manager_data_source_init()` will only return after +the entire file has been loaded. This is good for simplicity, but can be prohibitively slow. You +can instead load the sound asynchronously using the `MA_RESOURCE_MANAGER_DATA_SOURCE_ASYNC` flag. +This will result in `ma_resource_manager_data_source_init()` returning quickly, but no data will be +returned by `ma_data_source_read_pcm_frames()` until some data is available. When no data is +available because the asynchronous decoding hasn't caught up, `MA_BUSY` will be returned by +`ma_data_source_read_pcm_frames()`. + +For large sounds, it's often prohibitive to store the entire file in memory. To mitigate this, you +can instead stream audio data which you can do by specifying the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. When streaming, data will be decoded in 1 +second pages. When a new page needs to be decoded, a job will be posted to the job queue and then +subsequently processed in a job thread. + +For in-memory sounds, reference counting is used to ensure the data is loaded only once. This means +multiple calls to `ma_resource_manager_data_source_init()` with the same file path will result in +the file data only being loaded once. Each call to `ma_resource_manager_data_source_init()` must be +matched up with a call to `ma_resource_manager_data_source_uninit()`. Sometimes it can be useful +for a program to register self-managed raw audio data and associate it with a file path. Use the +`ma_resource_manager_register_*()` and `ma_resource_manager_unregister_*()` APIs to do this. +`ma_resource_manager_register_decoded_data()` is used to associate a pointer to raw, self-managed +decoded audio data in the specified data format with the specified name. Likewise, +`ma_resource_manager_register_encoded_data()` is used to associate a pointer to raw self-managed +encoded audio data (the raw file data) with the specified name. Note that these names need not be +actual file paths. When `ma_resource_manager_data_source_init()` is called (without the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag), the resource manager will look for these +explicitly registered data buffers and, if found, will use it as the backing data for the data +source. Note that the resource manager does *not* make a copy of this data so it is up to the +caller to ensure the pointer stays valid for it's lifetime. Use +`ma_resource_manager_unregister_data()` to unregister the self-managed data. You can also use +`ma_resource_manager_register_file()` and `ma_resource_manager_unregister_file()` to register and +unregister a file. It does not make sense to use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` +flag with a self-managed data pointer. + + +6.1. Asynchronous Loading and Synchronization +--------------------------------------------- +When loading asynchronously, it can be useful to poll whether or not loading has finished. Use +`ma_resource_manager_data_source_result()` to determine this. For in-memory sounds, this will +return `MA_SUCCESS` when the file has been *entirely* decoded. If the sound is still being decoded, +`MA_BUSY` will be returned. Otherwise, some other error code will be returned if the sound failed +to load. For streaming data sources, `MA_SUCCESS` will be returned when the first page has been +decoded and the sound is ready to be played. If the first page is still being decoded, `MA_BUSY` +will be returned. Otherwise, some other error code will be returned if the sound failed to load. + +In addition to polling, you can also use a simple synchronization object called a "fence" to wait +for asynchronously loaded sounds to finish. This is called `ma_fence`. The advantage to using a +fence is that it can be used to wait for a group of sounds to finish loading rather than waiting +for sounds on an individual basis. There are two stages to loading a sound: + + * Initialization of the internal decoder; and + * Completion of decoding of the file (the file is fully decoded) + +You can specify separate fences for each of the different stages. Waiting for the initialization +of the internal decoder is important for when you need to know the sample format, channels and +sample rate of the file. + +The example below shows how you could use a fence when loading a number of sounds: + + ```c + // This fence will be released when all sounds are finished loading entirely. + ma_fence fence; + ma_fence_init(&fence); + + // This will be passed into the initialization routine for each sound. + ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init(); + notifications.done.pFence = &fence; + + // Now load a bunch of sounds: + for (iSound = 0; iSound < soundCount; iSound += 1) { + ma_resource_manager_data_source_init(pResourceManager, pSoundFilePaths[iSound], flags, ¬ifications, &pSoundSources[iSound]); + } + + // ... DO SOMETHING ELSE WHILE SOUNDS ARE LOADING ... + + // Wait for loading of sounds to finish. + ma_fence_wait(&fence); + ``` + +In the example above we used a fence for waiting until the entire file has been fully decoded. If +you only need to wait for the initialization of the internal decoder to complete, you can use the +`init` member of the `ma_resource_manager_pipeline_notifications` object: + + ```c + notifications.init.pFence = &fence; + ``` + +If a fence is not appropriate for your situation, you can instead use a callback that is fired on +an individual sound basis. This is done in a very similar way to fences: + + ```c + typedef struct + { + ma_async_notification_callbacks cb; + void* pMyData; + } my_notification; + + void my_notification_callback(ma_async_notification* pNotification) + { + my_notification* pMyNotification = (my_notification*)pNotification; + + // Do something in response to the sound finishing loading. + } + + ... + + my_notification myCallback; + myCallback.cb.onSignal = my_notification_callback; + myCallback.pMyData = pMyData; + + ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init(); + notifications.done.pNotification = &myCallback; + + ma_resource_manager_data_source_init(pResourceManager, "my_sound.wav", flags, ¬ifications, &mySound); + ``` + +In the example above we just extend the `ma_async_notification_callbacks` object and pass an +instantiation into the `ma_resource_manager_pipeline_notifications` in the same way as we did with +the fence, only we set `pNotification` instead of `pFence`. You can set both of these at the same +time and they should both work as expected. If using the `pNotification` system, you need to ensure +your `ma_async_notification_callbacks` object stays valid. + + + +6.2. Resource Manager Implementation Details +-------------------------------------------- +Resources are managed in two main ways: + + * By storing the entire sound inside an in-memory buffer (referred to as a data buffer) + * By streaming audio data on the fly (referred to as a data stream) + +A resource managed data source (`ma_resource_manager_data_source`) encapsulates a data buffer or +data stream, depending on whether or not the data source was initialized with the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. If so, it will make use of a +`ma_resource_manager_data_stream` object. Otherwise it will use a `ma_resource_manager_data_buffer` +object. Both of these objects are data sources which means they can be used with any +`ma_data_source_*()` API. + +Another major feature of the resource manager is the ability to asynchronously decode audio files. +This relieves the audio thread of time-consuming decoding which can negatively affect scalability +due to the audio thread needing to complete it's work extremely quickly to avoid glitching. +Asynchronous decoding is achieved through a job system. There is a central multi-producer, +multi-consumer, fixed-capacity job queue. When some asynchronous work needs to be done, a job is +posted to the queue which is then read by a job thread. The number of job threads can be +configured for improved scalability, and job threads can all run in parallel without needing to +worry about the order of execution (how this is achieved is explained below). + +When a sound is being loaded asynchronously, playback can begin before the sound has been fully +decoded. This enables the application to start playback of the sound quickly, while at the same +time allowing to resource manager to keep loading in the background. Since there may be less +threads than the number of sounds being loaded at a given time, a simple scheduling system is used +to keep decoding time balanced and fair. The resource manager solves this by splitting decoding +into chunks called pages. By default, each page is 1 second long. When a page has been decoded, a +new job will be posted to start decoding the next page. By dividing up decoding into pages, an +individual sound shouldn't ever delay every other sound from having their first page decoded. Of +course, when loading many sounds at the same time, there will always be an amount of time required +to process jobs in the queue so in heavy load situations there will still be some delay. To +determine if a data source is ready to have some frames read, use +`ma_resource_manager_data_source_get_available_frames()`. This will return the number of frames +available starting from the current position. + + +6.2.1. Job Queue +---------------- +The resource manager uses a job queue which is multi-producer, multi-consumer, and fixed-capacity. +This job queue is not currently lock-free, and instead uses a spinlock to achieve thread-safety. +Only a fixed number of jobs can be allocated and inserted into the queue which is done through a +lock-free data structure for allocating an index into a fixed sized array, with reference counting +for mitigation of the ABA problem. The reference count is 32-bit. + +For many types of jobs it's important that they execute in a specific order. In these cases, jobs +are executed serially. For the resource manager, serial execution of jobs is only required on a +per-object basis (per data buffer or per data stream). Each of these objects stores an execution +counter. When a job is posted it is associated with an execution counter. When the job is +processed, it checks if the execution counter of the job equals the execution counter of the +owning object and if so, processes the job. If the counters are not equal, the job will be posted +back onto the job queue for later processing. When the job finishes processing the execution order +of the main object is incremented. This system means the no matter how many job threads are +executing, decoding of an individual sound will always get processed serially. The advantage to +having multiple threads comes into play when loading multiple sounds at the same time. + +The resource manager's job queue is not 100% lock-free and will use a spinlock to achieve +thread-safety for a very small section of code. This is only relevant when the resource manager +uses more than one job thread. If only using a single job thread, which is the default, the +lock should never actually wait in practice. The amount of time spent locking should be quite +short, but it's something to be aware of for those who have pedantic lock-free requirements and +need to use more than one job thread. There are plans to remove this lock in a future version. + +In addition, posting a job will release a semaphore, which on Win32 is implemented with +`ReleaseSemaphore` and on POSIX platforms via a condition variable: + + ```c + pthread_mutex_lock(&pSemaphore->lock); + { + pSemaphore->value += 1; + pthread_cond_signal(&pSemaphore->cond); + } + pthread_mutex_unlock(&pSemaphore->lock); + ``` + +Again, this is relevant for those with strict lock-free requirements in the audio thread. To avoid +this, you can use non-blocking mode (via the `MA_JOB_QUEUE_FLAG_NON_BLOCKING` +flag) and implement your own job processing routine (see the "Resource Manager" section above for +details on how to do this). + + + +6.2.2. Data Buffers +------------------- +When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag is excluded at initialization time, the +resource manager will try to load the data into an in-memory data buffer. Before doing so, however, +it will first check if the specified file is already loaded. If so, it will increment a reference +counter and just use the already loaded data. This saves both time and memory. When the data buffer +is uninitialized, the reference counter will be decremented. If the counter hits zero, the file +will be unloaded. This is a detail to keep in mind because it could result in excessive loading and +unloading of a sound. For example, the following sequence will result in a file be loaded twice, +once after the other: + + ```c + ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer0); // Refcount = 1. Initial load. + ma_resource_manager_data_source_uninit(pResourceManager, &myDataBuffer0); // Refcount = 0. Unloaded. + + ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer1); // Refcount = 1. Reloaded because previous uninit() unloaded it. + ma_resource_manager_data_source_uninit(pResourceManager, &myDataBuffer1); // Refcount = 0. Unloaded. + ``` + +A binary search tree (BST) is used for storing data buffers as it has good balance between +efficiency and simplicity. The key of the BST is a 64-bit hash of the file path that was passed +into `ma_resource_manager_data_source_init()`. The advantage of using a hash is that it saves +memory over storing the entire path, has faster comparisons, and results in a mostly balanced BST +due to the random nature of the hash. The disadvantage is that file names are case-sensitive. If +this is an issue, you should normalize your file names to upper- or lower-case before initializing +your data sources. + +When a sound file has not already been loaded and the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` +flag is excluded, the file will be decoded synchronously by the calling thread. There are two +options for controlling how the audio is stored in the data buffer - encoded or decoded. When the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` option is excluded, the raw file data will be stored +in memory. Otherwise the sound will be decoded before storing it in memory. Synchronous loading is +a very simple and standard process of simply adding an item to the BST, allocating a block of +memory and then decoding (if `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` is specified). + +When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag is specified, loading of the data buffer +is done asynchronously. In this case, a job is posted to the queue to start loading and then the +function immediately returns, setting an internal result code to `MA_BUSY`. This result code is +returned when the program calls `ma_resource_manager_data_source_result()`. When decoding has fully +completed `MA_SUCCESS` will be returned. This can be used to know if loading has fully completed. + +When loading asynchronously, a single job is posted to the queue of the type +`MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE`. This involves making a copy of the file path and +associating it with job. When the job is processed by the job thread, it will first load the file +using the VFS associated with the resource manager. When using a custom VFS, it's important that it +be completely thread-safe because it will be used from one or more job threads at the same time. +Individual files should only ever be accessed by one thread at a time, however. After opening the +file via the VFS, the job will determine whether or not the file is being decoded. If not, it +simply allocates a block of memory and loads the raw file contents into it and returns. On the +other hand, when the file is being decoded, it will first allocate a decoder on the heap and +initialize it. Then it will check if the length of the file is known. If so it will allocate a +block of memory to store the decoded output and initialize it to silence. If the size is unknown, +it will allocate room for one page. After memory has been allocated, the first page will be +decoded. If the sound is shorter than a page, the result code will be set to `MA_SUCCESS` and the +completion event will be signalled and loading is now complete. If, however, there is more to +decode, a job with the code `MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE` is posted. This job +will decode the next page and perform the same process if it reaches the end. If there is more to +decode, the job will post another `MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE` job which will +keep on happening until the sound has been fully decoded. For sounds of an unknown length, each +page will be linked together as a linked list. Internally this is implemented via the +`ma_paged_audio_buffer` object. + + +6.2.3. Data Streams +------------------- +Data streams only ever store two pages worth of data for each instance. They are most useful for +large sounds like music tracks in games that would consume too much memory if fully decoded in +memory. After every frame from a page has been read, a job will be posted to load the next page +which is done from the VFS. + +For data streams, the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag will determine whether or +not initialization of the data source waits until the two pages have been decoded. When unset, +`ma_resource_manager_data_source_init()` will wait until the two pages have been loaded, otherwise +it will return immediately. + +When frames are read from a data stream using `ma_resource_manager_data_source_read_pcm_frames()`, +`MA_BUSY` will be returned if there are no frames available. If there are some frames available, +but less than the number requested, `MA_SUCCESS` will be returned, but the actual number of frames +read will be less than the number requested. Due to the asynchronous nature of data streams, +seeking is also asynchronous. If the data stream is in the middle of a seek, `MA_BUSY` will be +returned when trying to read frames. + +When `ma_resource_manager_data_source_read_pcm_frames()` results in a page getting fully consumed +a job is posted to load the next page. This will be posted from the same thread that called +`ma_resource_manager_data_source_read_pcm_frames()`. + +Data streams are uninitialized by posting a job to the queue, but the function won't return until +that job has been processed. The reason for this is that the caller owns the data stream object and +therefore miniaudio needs to ensure everything completes before handing back control to the caller. +Also, if the data stream is uninitialized while pages are in the middle of decoding, they must +complete before destroying any underlying object and the job system handles this cleanly. + +Note that when a new page needs to be loaded, a job will be posted to the resource manager's job +thread from the audio thread. You must keep in mind the details mentioned in the "Job Queue" +section above regarding locking when posting an event if you require a strictly lock-free audio +thread. + + + +7. Node Graph +============= +miniaudio's routing infrastructure follows a node graph paradigm. The idea is that you create a +node whose outputs are attached to inputs of another node, thereby creating a graph. There are +different types of nodes, with each node in the graph processing input data to produce output, +which is then fed through the chain. Each node in the graph can apply their own custom effects. At +the start of the graph will usually be one or more data source nodes which have no inputs, but +instead pull their data from a data source. At the end of the graph is an endpoint which represents +the end of the chain and is where the final output is ultimately extracted from. + +Each node has a number of input buses and a number of output buses. An output bus from a node is +attached to an input bus of another. Multiple nodes can connect their output buses to another +node's input bus, in which case their outputs will be mixed before processing by the node. Below is +a diagram that illustrates a hypothetical node graph setup: + + ``` + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Data flows left to right >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + +---------------+ +-----------------+ + | Data Source 1 =----+ +----------+ +----= Low Pass Filter =----+ + +---------------+ | | =----+ +-----------------+ | +----------+ + +----= Splitter | +----= ENDPOINT | + +---------------+ | | =----+ +-----------------+ | +----------+ + | Data Source 2 =----+ +----------+ +----= Echo / Delay =----+ + +---------------+ +-----------------+ + ``` + +In the above graph, it starts with two data sources whose outputs are attached to the input of a +splitter node. It's at this point that the two data sources are mixed. After mixing, the splitter +performs it's processing routine and produces two outputs which is simply a duplication of the +input stream. One output is attached to a low pass filter, whereas the other output is attached to +a echo/delay. The outputs of the the low pass filter and the echo are attached to the endpoint, and +since they're both connected to the same input but, they'll be mixed. + +Each input bus must be configured to accept the same number of channels, but the number of channels +used by input buses can be different to the number of channels for output buses in which case +miniaudio will automatically convert the input data to the output channel count before processing. +The number of channels of an output bus of one node must match the channel count of the input bus +it's attached to. The channel counts cannot be changed after the node has been initialized. If you +attempt to attach an output bus to an input bus with a different channel count, attachment will +fail. + +To use a node graph, you first need to initialize a `ma_node_graph` object. This is essentially a +container around the entire graph. The `ma_node_graph` object is required for some thread-safety +issues which will be explained later. A `ma_node_graph` object is initialized using miniaudio's +standard config/init system: + + ```c + ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(myChannelCount); + + result = ma_node_graph_init(&nodeGraphConfig, NULL, &nodeGraph); // Second parameter is a pointer to allocation callbacks. + if (result != MA_SUCCESS) { + // Failed to initialize node graph. + } + ``` + +When you initialize the node graph, you're specifying the channel count of the endpoint. The +endpoint is a special node which has one input bus and one output bus, both of which have the +same channel count, which is specified in the config. Any nodes that connect directly to the +endpoint must be configured such that their output buses have the same channel count. When you read +audio data from the node graph, it'll have the channel count you specified in the config. To read +data from the graph: + + ```c + ma_uint32 framesRead; + result = ma_node_graph_read_pcm_frames(&nodeGraph, pFramesOut, frameCount, &framesRead); + if (result != MA_SUCCESS) { + // Failed to read data from the node graph. + } + ``` + +When you read audio data, miniaudio starts at the node graph's endpoint node which then pulls in +data from it's input attachments, which in turn recusively pull in data from their inputs, and so +on. At the start of the graph there will be some kind of data source node which will have zero +inputs and will instead read directly from a data source. The base nodes don't literally need to +read from a `ma_data_source` object, but they will always have some kind of underlying object that +sources some kind of audio. The `ma_data_source_node` node can be used to read from a +`ma_data_source`. Data is always in floating-point format and in the number of channels you +specified when the graph was initialized. The sample rate is defined by the underlying data sources. +It's up to you to ensure they use a consistent and appropraite sample rate. + +The `ma_node` API is designed to allow custom nodes to be implemented with relative ease, but +miniaudio includes a few stock nodes for common functionality. This is how you would initialize a +node which reads directly from a data source (`ma_data_source_node`) which is an example of one +of the stock nodes that comes with miniaudio: + + ```c + ma_data_source_node_config config = ma_data_source_node_config_init(pMyDataSource); + + ma_data_source_node dataSourceNode; + result = ma_data_source_node_init(&nodeGraph, &config, NULL, &dataSourceNode); + if (result != MA_SUCCESS) { + // Failed to create data source node. + } + ``` + +The data source node will use the output channel count to determine the channel count of the output +bus. There will be 1 output bus and 0 input buses (data will be drawn directly from the data +source). The data source must output to floating-point (`ma_format_f32`) or else an error will be +returned from `ma_data_source_node_init()`. + +By default the node will not be attached to the graph. To do so, use `ma_node_attach_output_bus()`: + + ```c + result = ma_node_attach_output_bus(&dataSourceNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0); + if (result != MA_SUCCESS) { + // Failed to attach node. + } + ``` + +The code above connects the data source node directly to the endpoint. Since the data source node +has only a single output bus, the index will always be 0. Likewise, the endpoint only has a single +input bus which means the input bus index will also always be 0. + +To detach a specific output bus, use `ma_node_detach_output_bus()`. To detach all output buses, use +`ma_node_detach_all_output_buses()`. If you want to just move the output bus from one attachment to +another, you do not need to detach first. You can just call `ma_node_attach_output_bus()` and it'll +deal with it for you. + +Less frequently you may want to create a specialized node. This will be a node where you implement +your own processing callback to apply a custom effect of some kind. This is similar to initalizing +one of the stock node types, only this time you need to specify a pointer to a vtable containing a +pointer to the processing function and the number of input and output buses. Example: + + ```c + static void my_custom_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) + { + // Do some processing of ppFramesIn (one stream of audio data per input bus) + const float* pFramesIn_0 = ppFramesIn[0]; // Input bus @ index 0. + const float* pFramesIn_1 = ppFramesIn[1]; // Input bus @ index 1. + float* pFramesOut_0 = ppFramesOut[0]; // Output bus @ index 0. + + // Do some processing. On input, `pFrameCountIn` will be the number of input frames in each + // buffer in `ppFramesIn` and `pFrameCountOut` will be the capacity of each of the buffers + // in `ppFramesOut`. On output, `pFrameCountIn` should be set to the number of input frames + // your node consumed and `pFrameCountOut` should be set the number of output frames that + // were produced. + // + // You should process as many frames as you can. If your effect consumes input frames at the + // same rate as output frames (always the case, unless you're doing resampling), you need + // only look at `ppFramesOut` and process that exact number of frames. If you're doing + // resampling, you'll need to be sure to set both `pFrameCountIn` and `pFrameCountOut` + // properly. + } + + static ma_node_vtable my_custom_node_vtable = + { + my_custom_node_process_pcm_frames, // The function that will be called process your custom node. This is where you'd implement your effect processing. + NULL, // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames. + 2, // 2 input buses. + 1, // 1 output bus. + 0 // Default flags. + }; + + ... + + // Each bus needs to have a channel count specified. To do this you need to specify the channel + // counts in an array and then pass that into the node config. + ma_uint32 inputChannels[2]; // Equal in size to the number of input channels specified in the vtable. + ma_uint32 outputChannels[1]; // Equal in size to the number of output channels specicied in the vtable. + + inputChannels[0] = channelsIn; + inputChannels[1] = channelsIn; + outputChannels[0] = channelsOut; + + ma_node_config nodeConfig = ma_node_config_init(); + nodeConfig.vtable = &my_custom_node_vtable; + nodeConfig.pInputChannels = inputChannels; + nodeConfig.pOutputChannels = outputChannels; + + ma_node_base node; + result = ma_node_init(&nodeGraph, &nodeConfig, NULL, &node); + if (result != MA_SUCCESS) { + // Failed to initialize node. + } + ``` + +When initializing a custom node, as in the code above, you'll normally just place your vtable in +static space. The number of input and output buses are specified as part of the vtable. If you need +a variable number of buses on a per-node bases, the vtable should have the relevant bus count set +to `MA_NODE_BUS_COUNT_UNKNOWN`. In this case, the bus count should be set in the node config: + + ```c + static ma_node_vtable my_custom_node_vtable = + { + my_custom_node_process_pcm_frames, // The function that will be called process your custom node. This is where you'd implement your effect processing. + NULL, // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames. + MA_NODE_BUS_COUNT_UNKNOWN, // The number of input buses is determined on a per-node basis. + 1, // 1 output bus. + 0 // Default flags. + }; + + ... + + ma_node_config nodeConfig = ma_node_config_init(); + nodeConfig.vtable = &my_custom_node_vtable; + nodeConfig.inputBusCount = myBusCount; // <-- Since the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN, the input bus count should be set here. + nodeConfig.pInputChannels = inputChannels; // <-- Make sure there are nodeConfig.inputBusCount elements in this array. + nodeConfig.pOutputChannels = outputChannels; // <-- The vtable specifies 1 output bus, so there must be 1 element in this array. + ``` + +In the above example it's important to never set the `inputBusCount` and `outputBusCount` members +to anything other than their defaults if the vtable specifies an explicit count. They can only be +set if the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN in the relevant bus count. + +Most often you'll want to create a structure to encapsulate your node with some extra data. You +need to make sure the `ma_node_base` object is your first member of the structure: + + ```c + typedef struct + { + ma_node_base base; // <-- Make sure this is always the first member. + float someCustomData; + } my_custom_node; + ``` + +By doing this, your object will be compatible with all `ma_node` APIs and you can attach it to the +graph just like any other node. + +In the custom processing callback (`my_custom_node_process_pcm_frames()` in the example above), the +number of channels for each bus is what was specified by the config when the node was initialized +with `ma_node_init()`. In addition, all attachments to each of the input buses will have been +pre-mixed by miniaudio. The config allows you to specify different channel counts for each +individual input and output bus. It's up to the effect to handle it appropriate, and if it can't, +return an error in it's initialization routine. + +Custom nodes can be assigned some flags to describe their behaviour. These are set via the vtable +and include the following: + + +-----------------------------------------+---------------------------------------------------+ + | Flag Name | Description | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_PASSTHROUGH | Useful for nodes that do not do any kind of audio | + | | processing, but are instead used for tracking | + | | time, handling events, etc. Also used by the | + | | internal endpoint node. It reads directly from | + | | the input bus to the output bus. Nodes with this | + | | flag must have exactly 1 input bus and 1 output | + | | bus, and both buses must have the same channel | + | | counts. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_CONTINUOUS_PROCESSING | Causes the processing callback to be called even | + | | when no data is available to be read from input | + | | attachments. This is useful for effects like | + | | echos where there will be a tail of audio data | + | | that still needs to be processed even when the | + | | original data sources have reached their ends. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_ALLOW_NULL_INPUT | Used in conjunction with | + | | `MA_NODE_FLAG_CONTINUOUS_PROCESSING`. When this | + | | is set, the `ppFramesIn` parameter of the | + | | processing callback will be set to NULL when | + | | there are no input frames are available. When | + | | this is unset, silence will be posted to the | + | | processing callback. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES | Used to tell miniaudio that input and output | + | | frames are processed at different rates. You | + | | should set this for any nodes that perform | + | | resampling. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_SILENT_OUTPUT | Used to tell miniaudio that a node produces only | + | | silent output. This is useful for nodes where you | + | | don't want the output to contribute to the final | + | | mix. An example might be if you want split your | + | | stream and have one branch be output to a file. | + | | When using this flag, you should avoid writing to | + | | the output buffer of the node's processing | + | | callback because miniaudio will ignore it anyway. | + +-----------------------------------------+---------------------------------------------------+ + + +If you need to make a copy of an audio stream for effect processing you can use a splitter node +called `ma_splitter_node`. This takes has 1 input bus and splits the stream into 2 output buses. +You can use it like this: + + ```c + ma_splitter_node_config splitterNodeConfig = ma_splitter_node_config_init(channelsIn, channelsOut); + + ma_splitter_node splitterNode; + result = ma_splitter_node_init(&nodeGraph, &splitterNodeConfig, NULL, &splitterNode); + if (result != MA_SUCCESS) { + // Failed to create node. + } + + // Attach your output buses to two different input buses (can be on two different nodes). + ma_node_attach_output_bus(&splitterNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0); // Attach directly to the endpoint. + ma_node_attach_output_bus(&splitterNode, 1, &myEffectNode, 0); // Attach to input bus 0 of some effect node. + ``` + +The volume of an output bus can be configured on a per-bus basis: + + ```c + ma_node_set_output_bus_volume(&splitterNode, 0, 0.5f); + ma_node_set_output_bus_volume(&splitterNode, 1, 0.5f); + ``` + +In the code above we're using the splitter node from before and changing the volume of each of the +copied streams. + +You can start and stop a node with the following: + + ```c + ma_node_set_state(&splitterNode, ma_node_state_started); // The default state. + ma_node_set_state(&splitterNode, ma_node_state_stopped); + ``` + +By default the node is in a started state, but since it won't be connected to anything won't +actually be invoked by the node graph until it's connected. When you stop a node, data will not be +read from any of it's input connections. You can use this property to stop a group of sounds +atomically. + +You can configure the initial state of a node in it's config: + + ```c + nodeConfig.initialState = ma_node_state_stopped; + ``` + +Note that for the stock specialized nodes, all of their configs will have a `nodeConfig` member +which is the config to use with the base node. This is where the initial state can be configured +for specialized nodes: + + ```c + dataSourceNodeConfig.nodeConfig.initialState = ma_node_state_stopped; + ``` + +When using a specialized node like `ma_data_source_node` or `ma_splitter_node`, be sure to not +modify the `vtable` member of the `nodeConfig` object. + + +7.1. Timing +----------- +The node graph supports starting and stopping nodes at scheduled times. This is especially useful +for data source nodes where you want to get the node set up, but only start playback at a specific +time. There are two clocks: local and global. + +A local clock is per-node, whereas the global clock is per graph. Scheduling starts and stops can +only be done based on the global clock because the local clock will not be running while the node +is stopped. The global clocks advances whenever `ma_node_graph_read_pcm_frames()` is called. On the +other hand, the local clock only advances when the node's processing callback is fired, and is +advanced based on the output frame count. + +To retrieve the global time, use `ma_node_graph_get_time()`. The global time can be set with +`ma_node_graph_set_time()` which might be useful if you want to do seeking on a global timeline. +Getting and setting the local time is similar. Use `ma_node_get_time()` to retrieve the local time, +and `ma_node_set_time()` to set the local time. The global and local times will be advanced by the +audio thread, so care should be taken to avoid data races. Ideally you should avoid calling these +outside of the node processing callbacks which are always run on the audio thread. + +There is basic support for scheduling the starting and stopping of nodes. You can only schedule one +start and one stop at a time. This is mainly intended for putting nodes into a started or stopped +state in a frame-exact manner. Without this mechanism, starting and stopping of a node is limited +to the resolution of a call to `ma_node_graph_read_pcm_frames()` which would typically be in blocks +of several milliseconds. The following APIs can be used for scheduling node states: + + ```c + ma_node_set_state_time() + ma_node_get_state_time() + ``` + +The time is absolute and must be based on the global clock. An example is below: + + ```c + ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1); // Delay starting to 1 second. + ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5); // Delay stopping to 5 seconds. + ``` + +An example for changing the state using a relative time. + + ```c + ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1 + ma_node_graph_get_time(&myNodeGraph)); + ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5 + ma_node_graph_get_time(&myNodeGraph)); + ``` + +Note that due to the nature of multi-threading the times may not be 100% exact. If this is an +issue, consider scheduling state changes from within a processing callback. An idea might be to +have some kind of passthrough trigger node that is used specifically for tracking time and handling +events. + + + +7.2. Thread Safety and Locking +------------------------------ +When processing audio, it's ideal not to have any kind of locking in the audio thread. Since it's +expected that `ma_node_graph_read_pcm_frames()` would be run on the audio thread, it does so +without the use of any locks. This section discusses the implementation used by miniaudio and goes +over some of the compromises employed by miniaudio to achieve this goal. Note that the current +implementation may not be ideal - feedback and critiques are most welcome. + +The node graph API is not *entirely* lock-free. Only `ma_node_graph_read_pcm_frames()` is expected +to be lock-free. Attachment, detachment and uninitialization of nodes use locks to simplify the +implementation, but are crafted in a way such that such locking is not required when reading audio +data from the graph. Locking in these areas are achieved by means of spinlocks. + +The main complication with keeping `ma_node_graph_read_pcm_frames()` lock-free stems from the fact +that a node can be uninitialized, and it's memory potentially freed, while in the middle of being +processed on the audio thread. There are times when the audio thread will be referencing a node, +which means the uninitialization process of a node needs to make sure it delays returning until the +audio thread is finished so that control is not handed back to the caller thereby giving them a +chance to free the node's memory. + +When the audio thread is processing a node, it does so by reading from each of the output buses of +the node. In order for a node to process data for one of it's output buses, it needs to read from +each of it's input buses, and so on an so forth. It follows that once all output buses of a node +are detached, the node as a whole will be disconnected and no further processing will occur unless +it's output buses are reattached, which won't be happening when the node is being uninitialized. +By having `ma_node_detach_output_bus()` wait until the audio thread is finished with it, we can +simplify a few things, at the expense of making `ma_node_detach_output_bus()` a bit slower. By +doing this, the implementation of `ma_node_uninit()` becomes trivial - just detach all output +nodes, followed by each of the attachments to each of it's input nodes, and then do any final clean +up. + +With the above design, the worst-case scenario is `ma_node_detach_output_bus()` taking as long as +it takes to process the output bus being detached. This will happen if it's called at just the +wrong moment where the audio thread has just iterated it and has just started processing. The +caller of `ma_node_detach_output_bus()` will stall until the audio thread is finished, which +includes the cost of recursively processing it's inputs. This is the biggest compromise made with +the approach taken by miniaudio for it's lock-free processing system. The cost of detaching nodes +earlier in the pipeline (data sources, for example) will be cheaper than the cost of detaching +higher level nodes, such as some kind of final post-processing endpoint. If you need to do mass +detachments, detach starting from the lowest level nodes and work your way towards the final +endpoint node (but don't try detaching the node graph's endpoint). If the audio thread is not +running, detachment will be fast and detachment in any order will be the same. The reason nodes +need to wait for their input attachments to complete is due to the potential for desyncs between +data sources. If the node was to terminate processing mid way through processing it's inputs, +there's a chance that some of the underlying data sources will have been read, but then others not. +That will then result in a potential desynchronization when detaching and reattaching higher-level +nodes. A possible solution to this is to have an option when detaching to terminate processing +before processing all input attachments which should be fairly simple. + +Another compromise, albeit less significant, is locking when attaching and detaching nodes. This +locking is achieved by means of a spinlock in order to reduce memory overhead. A lock is present +for each input bus and output bus. When an output bus is connected to an input bus, both the output +bus and input bus is locked. This locking is specifically for attaching and detaching across +different threads and does not affect `ma_node_graph_read_pcm_frames()` in any way. The locking and +unlocking is mostly self-explanatory, but a slightly less intuitive aspect comes into it when +considering that iterating over attachments must not break as a result of attaching or detaching a +node while iteration is occuring. + +Attaching and detaching are both quite simple. When an output bus of a node is attached to an input +bus of another node, it's added to a linked list. Basically, an input bus is a linked list, where +each item in the list is and output bus. We have some intentional (and convenient) restrictions on +what can done with the linked list in order to simplify the implementation. First of all, whenever +something needs to iterate over the list, it must do so in a forward direction. Backwards iteration +is not supported. Also, items can only be added to the start of the list. + +The linked list is a doubly-linked list where each item in the list (an output bus) holds a pointer +to the next item in the list, and another to the previous item. A pointer to the previous item is +only required for fast detachment of the node - it is never used in iteration. This is an +important property because it means from the perspective of iteration, attaching and detaching of +an item can be done with a single atomic assignment. This is exploited by both the attachment and +detachment process. When attaching the node, the first thing that is done is the setting of the +local "next" and "previous" pointers of the node. After that, the item is "attached" to the list +by simply performing an atomic exchange with the head pointer. After that, the node is "attached" +to the list from the perspective of iteration. Even though the "previous" pointer of the next item +hasn't yet been set, from the perspective of iteration it's been attached because iteration will +only be happening in a forward direction which means the "previous" pointer won't actually ever get +used. The same general process applies to detachment. See `ma_node_attach_output_bus()` and +`ma_node_detach_output_bus()` for the implementation of this mechanism. + + + +8. Decoding =========== -The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from devices and can be used independently. The following formats are -supported: +The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from +devices and can be used independently. The following formats are supported: +---------+------------------+----------+ | Format | Decoding Backend | Built-In | @@ -475,7 +2405,8 @@ supported: | Vorbis | stb_vorbis | No | +---------+------------------+----------+ -Vorbis is supported via stb_vorbis which can be enabled by including the header section before the implementation of miniaudio, like the following: +Vorbis is supported via stb_vorbis which can be enabled by including the header section before the +implementation of miniaudio, like the following: ```c #define STB_VORBIS_HEADER_ONLY @@ -491,8 +2422,9 @@ Vorbis is supported via stb_vorbis which can be enabled by including the header A copy of stb_vorbis is included in the "extras" folder in the miniaudio repository (https://github.com/mackron/miniaudio). -Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the built-in decoders by specifying one or more of the -following options before the miniaudio implementation: +Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the +built-in decoders by specifying one or more of the following options before the miniaudio +implementation: ```c #define MA_NO_WAV @@ -500,10 +2432,12 @@ following options before the miniaudio implementation: #define MA_NO_FLAC ``` -Disabling built-in decoding libraries is useful if you use these libraries independantly of the `ma_decoder` API. +Disabling built-in decoding libraries is useful if you use these libraries independantly of the +`ma_decoder` API. -A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with `ma_decoder_init_memory()`, or from data delivered via callbacks -with `ma_decoder_init()`. Here is an example for loading a decoder from a file: +A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with +`ma_decoder_init_memory()`, or from data delivered via callbacks with `ma_decoder_init()`. Here is +an example for loading a decoder from a file: ```c ma_decoder decoder; @@ -517,20 +2451,23 @@ with `ma_decoder_init()`. Here is an example for loading a decoder from a file: ma_decoder_uninit(&decoder); ``` -When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object (the `NULL` argument in the example above) which allows you -to configure the output format, channel count, sample rate and channel map: +When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object +(the `NULL` argument in the example above) which allows you to configure the output format, channel +count, sample rate and channel map: ```c ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, 48000); ``` -When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the same as that defined by the decoding backend. +When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the +same as that defined by the decoding backend. -Data is read from the decoder as PCM frames. This will return the number of PCM frames actually read. If the return value is less than the requested number of -PCM frames it means you've reached the end: +Data is read from the decoder as PCM frames. This will output the number of PCM frames actually +read. If this is less than the requested number of PCM frames it means you've reached the end. The +return value will be `MA_AT_END` if no samples have been read and the end has been reached. ```c - ma_uint64 framesRead = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead); + ma_result result = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead, &framesRead); if (framesRead < framesToRead) { // Reached the end. } @@ -551,8 +2488,10 @@ If you want to loop back to the start, you can simply seek back to the first PCM ma_decoder_seek_to_pcm_frame(pDecoder, 0); ``` -When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding backend. This can be unnecessarily inefficient if the type -is already known. In this case you can use `encodingFormat` variable in the device config to specify a specific encoding format you want to decode: +When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding +backend. This can be unnecessarily inefficient if the type is already known. In this case you can +use `encodingFormat` variable in the device config to specify a specific encoding format you want +to decode: ```c decoderConfig.encodingFormat = ma_encoding_format_wav; @@ -560,24 +2499,95 @@ is already known. In this case you can use `encodingFormat` variable in the devi See the `ma_encoding_format` enum for possible encoding formats. -The `ma_decoder_init_file()` API will try using the file extension to determine which decoding backend to prefer. +The `ma_decoder_init_file()` API will try using the file extension to determine which decoding +backend to prefer. + + +8.1. Custom Decoders +-------------------- +It's possible to implement a custom decoder and plug it into miniaudio. This is extremely useful +when you want to use the `ma_decoder` API, but need to support an encoding format that's not one of +the stock formats supported by miniaudio. This can be put to particularly good use when using the +`ma_engine` and/or `ma_resource_manager` APIs because they use `ma_decoder` internally. If, for +example, you wanted to support Opus, you can do so with a custom decoder (there if a reference +Opus decoder in the "extras" folder of the miniaudio repository which uses libopus + libopusfile). + +A custom decoder must implement a data source. A vtable called `ma_decoding_backend_vtable` needs +to be implemented which is then passed into the decoder config: + + ```c + ma_decoding_backend_vtable* pCustomBackendVTables[] = + { + &g_ma_decoding_backend_vtable_libvorbis, + &g_ma_decoding_backend_vtable_libopus + }; + + ... + + decoderConfig = ma_decoder_config_init_default(); + decoderConfig.pCustomBackendUserData = NULL; + decoderConfig.ppCustomBackendVTables = pCustomBackendVTables; + decoderConfig.customBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]); + ``` + +The `ma_decoding_backend_vtable` vtable has the following functions: + + ``` + onInit + onInitFile + onInitFileW + onInitMemory + onUninit + ``` + +There are only two functions that must be implemented - `onInit` and `onUninit`. The other +functions can be implemented for a small optimization for loading from a file path or memory. If +these are not specified, miniaudio will deal with it for you via a generic implementation. + +When you initialize a custom data source (by implementing the `onInit` function in the vtable) you +will need to output a pointer to a `ma_data_source` which implements your custom decoder. See the +section about data sources for details on how to implemen this. Alternatively, see the +"custom_decoders" example in the miniaudio repository. + +The `onInit` function takes a pointer to some callbacks for the purpose of reading raw audio data +from some abitrary source. You'll use these functions to read from the raw data and perform the +decoding. When you call them, you will pass in the `pReadSeekTellUserData` pointer to the relevant +parameter. + +The `pConfig` parameter in `onInit` can be used to configure the backend if appropriate. It's only +used as a hint and can be ignored. However, if any of the properties are relevant to your decoder, +an optimal implementation will handle the relevant properties appropriately. + +If memory allocation is required, it should be done so via the specified allocation callbacks if +possible (the `pAllocationCallbacks` parameter). + +If an error occurs when initializing the decoder, you should leave `ppBackend` unset, or set to +NULL, and make sure everything is cleaned up appropriately and an appropriate result code returned. +When multiple custom backends are specified, miniaudio will cycle through the vtables in the order +they're listed in the array that's passed into the decoder config so it's important that your +initialization routine is clean. + +When a decoder is uninitialized, the `onUninit` callback will be fired which will give you an +opportunity to clean up and internal data. -5. Encoding +9. Encoding =========== -The `ma_encoding` API is used for writing audio files. The only supported output format is WAV which is achieved via dr_wav which is amalgamated into the -implementation section of miniaudio. This can be disabled by specifying the following option before the implementation of miniaudio: +The `ma_encoding` API is used for writing audio files. The only supported output format is WAV +which is achieved via dr_wav which is amalgamated into the implementation section of miniaudio. +This can be disabled by specifying the following option before the implementation of miniaudio: ```c #define MA_NO_WAV ``` -An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data delivered via callbacks with `ma_encoder_init()`. Below is an -example for initializing an encoder to output to a file. +An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data +delivered via callbacks with `ma_encoder_init()`. Below is an example for initializing an encoder +to output to a file. ```c - ma_encoder_config config = ma_encoder_config_init(ma_resource_format_wav, FORMAT, CHANNELS, SAMPLE_RATE); + ma_encoder_config config = ma_encoder_config_init(ma_encoding_format_wav, FORMAT, CHANNELS, SAMPLE_RATE); ma_encoder encoder; ma_result result = ma_encoder_init_file("my_file.wav", &config, &encoder); if (result != MA_SUCCESS) { @@ -589,17 +2599,20 @@ example for initializing an encoder to output to a file. ma_encoder_uninit(&encoder); ``` -When initializing an encoder you must specify a config which is initialized with `ma_encoder_config_init()`. Here you must specify the file type, the output -sample format, output channel count and output sample rate. The following file types are supported: +When initializing an encoder you must specify a config which is initialized with +`ma_encoder_config_init()`. Here you must specify the file type, the output sample format, output +channel count and output sample rate. The following file types are supported: +------------------------+-------------+ | Enum | Description | +------------------------+-------------+ - | ma_resource_format_wav | WAV | + | ma_encoding_format_wav | WAV | +------------------------+-------------+ -If the format, channel count or sample rate is not supported by the output file type an error will be returned. The encoder will not perform data conversion so -you will need to convert it before outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the example below: +If the format, channel count or sample rate is not supported by the output file type an error will +be returned. The encoder will not perform data conversion so you will need to convert it before +outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the +example below: ```c framesWritten = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite); @@ -608,21 +2621,25 @@ you will need to convert it before outputting any audio data. To output audio da Encoders must be uninitialized with `ma_encoder_uninit()`. -6. Data Conversion -================== -A data conversion API is included with miniaudio which supports the majority of data conversion requirements. This supports conversion between sample formats, -channel counts (with channel mapping) and sample rates. + +10. Data Conversion +=================== +A data conversion API is included with miniaudio which supports the majority of data conversion +requirements. This supports conversion between sample formats, channel counts (with channel +mapping) and sample rates. -6.1. Sample Format Conversion ------------------------------ -Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and `ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()` -to convert between two specific formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use `ma_convert_pcm_frames_format()` to convert -PCM frames where you want to specify the frame count and channel count as a variable instead of the total sample count. +10.1. Sample Format Conversion +------------------------------ +Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and +`ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()` to convert between two specific +formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use +`ma_convert_pcm_frames_format()` to convert PCM frames where you want to specify the frame count +and channel count as a variable instead of the total sample count. -6.1.1. Dithering ----------------- +10.1.1. Dithering +----------------- Dithering can be set using the ditherMode parameter. The different dithering modes include the following, in order of efficiency: @@ -635,8 +2652,9 @@ The different dithering modes include the following, in order of efficiency: | Triangle | ma_dither_mode_triangle | +-----------+--------------------------+ -Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be ignored for conversions where dithering is not needed. -Dithering is available for the following conversions: +Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be +ignored for conversions where dithering is not needed. Dithering is available for the following +conversions: ``` s16 -> u8 @@ -648,14 +2666,16 @@ Dithering is available for the following conversions: f32 -> s16 ``` -Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored. +Note that it is not an error to pass something other than ma_dither_mode_none for conversions where +dither is not used. It will just be ignored. -6.2. Channel Conversion ------------------------ -Channel conversion is used for channel rearrangement and conversion from one channel count to another. The `ma_channel_converter` API is used for channel -conversion. Below is an example of initializing a simple channel converter which converts from mono to stereo. +10.2. Channel Conversion +------------------------ +Channel conversion is used for channel rearrangement and conversion from one channel count to +another. The `ma_channel_converter` API is used for channel conversion. Below is an example of +initializing a simple channel converter which converts from mono to stereo. ```c ma_channel_converter_config config = ma_channel_converter_config_init( @@ -666,7 +2686,7 @@ conversion. Below is an example of initializing a simple channel converter which NULL, // Output channel map ma_channel_mix_mode_default); // The mixing algorithm to use when combining channels. - result = ma_channel_converter_init(&config, &converter); + result = ma_channel_converter_init(&config, NULL, &converter); if (result != MA_SUCCESS) { // Error. } @@ -681,34 +2701,43 @@ To perform the conversion simply call `ma_channel_converter_process_pcm_frames() } ``` -It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM frames. +It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM +frames. Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported. -6.2.1. Channel Mapping ----------------------- -In addition to converting from one channel count to another, like the example above, the channel converter can also be used to rearrange channels. When -initializing the channel converter, you can optionally pass in channel maps for both the input and output frames. If the channel counts are the same, and each -channel map contains the same channel positions with the exception that they're in a different order, a simple shuffling of the channels will be performed. If, -however, there is not a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed based on a mixing mode which is -specified when initializing the `ma_channel_converter_config` object. +10.2.1. Channel Mapping +----------------------- +In addition to converting from one channel count to another, like the example above, the channel +converter can also be used to rearrange channels. When initializing the channel converter, you can +optionally pass in channel maps for both the input and output frames. If the channel counts are the +same, and each channel map contains the same channel positions with the exception that they're in +a different order, a simple shuffling of the channels will be performed. If, however, there is not +a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed +based on a mixing mode which is specified when initializing the `ma_channel_converter_config` +object. -When converting from mono to multi-channel, the mono channel is simply copied to each output channel. When going the other way around, the audio of each output -channel is simply averaged and copied to the mono channel. +When converting from mono to multi-channel, the mono channel is simply copied to each output +channel. When going the other way around, the audio of each output channel is simply averaged and +copied to the mono channel. -In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess channels and silence extra channels. For example, converting -from 4 to 2 channels, the 3rd and 4th channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and 4th channels. +In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess +channels and silence extra channels. For example, converting from 4 to 2 channels, the 3rd and 4th +channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and +4th channels. -The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a simple distribution between input and output. Imagine sitting -in the middle of a room, with speakers on the walls representing channel positions. The MA_CHANNEL_FRONT_LEFT position can be thought of as being in the corner -of the front and left walls. +The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a +simple distribution between input and output. Imagine sitting in the middle of a room, with +speakers on the walls representing channel positions. The `MA_CHANNEL_FRONT_LEFT` position can be +thought of as being in the corner of the front and left walls. -Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined weights. Custom weights can be passed in as the last parameter of +Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined +weights. Custom weights can be passed in as the last parameter of `ma_channel_converter_config_init()`. -Predefined channel maps can be retrieved with `ma_get_standard_channel_map()`. This takes a `ma_standard_channel_map` enum as it's first parameter, which can -be one of the following: +Predefined channel maps can be retrieved with `ma_channel_map_init_standard()`. This takes a +`ma_standard_channel_map` enum as it's first parameter, which can be one of the following: +-----------------------------------+-----------------------------------------------------------+ | Name | Description | @@ -780,9 +2809,10 @@ Below are the channel maps used by default in miniaudio (`ma_standard_channel_ma -6.3. Resampling ---------------- -Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something like the following: +10.3. Resampling +---------------- +Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something +like the following: ```c ma_resampler_config config = ma_resampler_config_init( @@ -819,104 +2849,128 @@ The following example shows how data can be processed // number of output frames written. ``` -To initialize the resampler you first need to set up a config (`ma_resampler_config`) with `ma_resampler_config_init()`. You need to specify the sample format -you want to use, the number of channels, the input and output sample rate, and the algorithm. +To initialize the resampler you first need to set up a config (`ma_resampler_config`) with +`ma_resampler_config_init()`. You need to specify the sample format you want to use, the number of +channels, the input and output sample rate, and the algorithm. -The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format you will need to perform pre- and post-conversions yourself -where necessary. Note that the format is the same for both input and output. The format cannot be changed after initialization. +The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format +you will need to perform pre- and post-conversions yourself where necessary. Note that the format +is the same for both input and output. The format cannot be changed after initialization. -The resampler supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization. +The resampler supports multiple channels and is always interleaved (both input and output). The +channel count cannot be changed after initialization. -The sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the -only configuration property that can be changed after initialization. +The sample rates can be anything other than zero, and are always specified in hertz. They should be +set to something like 44100, etc. The sample rate is the only configuration property that can be +changed after initialization. -The miniaudio resampler supports multiple algorithms: +The miniaudio resampler has built-in support for the following algorithms: +-----------+------------------------------+ | Algorithm | Enum Token | +-----------+------------------------------+ | Linear | ma_resample_algorithm_linear | - | Speex | ma_resample_algorithm_speex | + | Custom | ma_resample_algorithm_custom | +-----------+------------------------------+ -Because Speex is not public domain it is strictly opt-in and the code is stored in separate files. if you opt-in to the Speex backend you will need to consider -it's license, the text of which can be found in it's source files in "extras/speex_resampler". Details on how to opt-in to the Speex resampler is explained in -the Speex Resampler section below. - The algorithm cannot be changed after initialization. -Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process -frames, use `ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number of -input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the -number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large -buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek. +Processing always happens on a per PCM frame basis and always assumes interleaved input and output. +De-interleaved processing is not supported. To process frames, use +`ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you +can fit in the output buffer and the number of input frames contained in the input buffer. On +output these variables contain the number of output frames that were written to the output buffer +and the number of input frames that were consumed in the process. You can pass in NULL for the +input buffer in which case it will be treated as an infinitely large buffer of zeros. The output +buffer can also be NULL, in which case the processing will be treated as seek. -The sample rate can be changed dynamically on the fly. You can change this with explicit sample rates with `ma_resampler_set_rate()` and also with a decimal -ratio with `ma_resampler_set_rate_ratio()`. The ratio is in/out. +The sample rate can be changed dynamically on the fly. You can change this with explicit sample +rates with `ma_resampler_set_rate()` and also with a decimal ratio with +`ma_resampler_set_rate_ratio()`. The ratio is in/out. -Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with -`ma_resampler_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of -input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`. +Sometimes it's useful to know exactly how many input frames will be required to output a specific +number of frames. You can calculate this with `ma_resampler_get_required_input_frame_count()`. +Likewise, it's sometimes useful to know exactly how many frames would be output given a certain +number of input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`. -Due to the nature of how resampling works, the resampler introduces some latency. This can be retrieved in terms of both the input rate and the output rate -with `ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`. +Due to the nature of how resampling works, the resampler introduces some latency. This can be +retrieved in terms of both the input rate and the output rate with +`ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`. -6.3.1. Resampling Algorithms ----------------------------- -The choice of resampling algorithm depends on your situation and requirements. The linear resampler is the most efficient and has the least amount of latency, -but at the expense of poorer quality. The Speex resampler is higher quality, but slower with more latency. It also performs several heap allocations internally -for memory management. +10.3.1. Resampling Algorithms +----------------------------- +The choice of resampling algorithm depends on your situation and requirements. -6.3.1.1. Linear Resampling --------------------------- -The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, some control over the quality of the linear resampler which -may make it a suitable option depending on your requirements. +10.3.1.1. Linear Resampling +--------------------------- +The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, +some control over the quality of the linear resampler which may make it a suitable option depending +on your requirements. -The linear resampler performs low-pass filtering before or after downsampling or upsampling, depending on the sample rates you're converting between. When -decreasing the sample rate, the low-pass filter will be applied before downsampling. When increasing the rate it will be performed after upsampling. By default -a fourth order low-pass filter will be applied. This can be configured via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. +The linear resampler performs low-pass filtering before or after downsampling or upsampling, +depending on the sample rates you're converting between. When decreasing the sample rate, the +low-pass filter will be applied before downsampling. When increasing the rate it will be performed +after upsampling. By default a fourth order low-pass filter will be applied. This can be configured +via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. -The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of the input and output sample rates (Nyquist Frequency). This -can be controlled with the `lpfNyquistFactor` config variable. This defaults to 1, and should be in the range of 0..1, although a value of 0 does not make -sense and should be avoided. A value of 1 will use the Nyquist Frequency as the cutoff. A value of 0.5 will use half the Nyquist Frequency as the cutoff, etc. -Values less than 1 will result in more washed out sound due to more of the higher frequencies being removed. This config variable has no impact on performance -and is a purely perceptual configuration. +The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of +the input and output sample rates (Nyquist Frequency). -The API for the linear resampler is the same as the main resampler API, only it's called `ma_linear_resampler`. +The API for the linear resampler is the same as the main resampler API, only it's called +`ma_linear_resampler`. -6.3.1.2. Speex Resampling +10.3.2. Custom Resamplers ------------------------- -The Speex resampler is made up of third party code which is released under the BSD license. Because it is licensed differently to miniaudio, which is public -domain, it is strictly opt-in and all of it's code is stored in separate files. If you opt-in to the Speex resampler you must consider the license text in it's -source files. To opt-in, you must first `#include` the following file before the implementation of miniaudio.h: +You can implement a custom resampler by using the `ma_resample_algorithm_custom` resampling +algorithm and setting a vtable in the resampler config: ```c - #include "extras/speex_resampler/ma_speex_resampler.h" + ma_resampler_config config = ma_resampler_config_init(..., ma_resample_algorithm_custom); + config.pBackendVTable = &g_customResamplerVTable; ``` -Both the header and implementation is contained within the same file. The implementation can be included in your program like so: +Custom resamplers are useful if the stock algorithms are not appropriate for your use case. You +need to implement the required functions in `ma_resampling_backend_vtable`. Note that not all +functions in the vtable need to be implemented, but if it's possible to implement, they should be. - ```c - #define MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION - #include "extras/speex_resampler/ma_speex_resampler.h" - ``` +You can use the `ma_linear_resampler` object for an example on how to implement the vtable. The +`onGetHeapSize` callback is used to calculate the size of any internal heap allocation the custom +resampler will need to make given the supplied config. When you initialize the resampler via the +`onInit` callback, you'll be given a pointer to a heap allocation which is where you should store +the heap allocated data. You should not free this data in `onUninit` because miniaudio will manage +it for you. -Note that even if you opt-in to the Speex backend, miniaudio won't use it unless you explicitly ask for it in the respective config of the object you are -initializing. If you try to use the Speex resampler without opting in, initialization of the `ma_resampler` object will fail with `MA_NO_BACKEND`. +The `onProcess` callback is where the actual resampling takes place. On input, `pFrameCountIn` +points to a variable containing the number of frames in the `pFramesIn` buffer and +`pFrameCountOut` points to a variable containing the capacity in frames of the `pFramesOut` buffer. +On output, `pFrameCountIn` should be set to the number of input frames that were fully consumed, +whereas `pFrameCountOut` should be set to the number of frames that were written to `pFramesOut`. -The only configuration option to consider with the Speex resampler is the `speex.quality` config variable. This is a value between 0 and 10, with 0 being -the fastest with the poorest quality and 10 being the slowest with the highest quality. The default value is 3. +The `onSetRate` callback is optional and is used for dynamically changing the sample rate. If +dynamic rate changes are not supported, you can set this callback to NULL. + +The `onGetInputLatency` and `onGetOutputLatency` functions are used for retrieving the latency in +input and output rates respectively. These can be NULL in which case latency calculations will be +assumed to be NULL. + +The `onGetRequiredInputFrameCount` callback is used to give miniaudio a hint as to how many input +frames are required to be available to produce the given number of output frames. Likewise, the +`onGetExpectedOutputFrameCount` callback is used to determine how many output frames will be +produced given the specified number of input frames. miniaudio will use these as a hint, but they +are optional and can be set to NULL if you're unable to implement them. -6.4. General Data Conversion ----------------------------- -The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and resampling into one operation. This is what miniaudio uses -internally to convert between the format requested when the device was initialized and the format of the backend's native device. The API for general data -conversion is very similar to the resampling API. Create a `ma_data_converter` object like this: +10.4. General Data Conversion +----------------------------- +The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and +resampling into one operation. This is what miniaudio uses internally to convert between the format +requested when the device was initialized and the format of the backend's native device. The API +for general data conversion is very similar to the resampling API. Create a `ma_data_converter` +object like this: ```c ma_data_converter_config config = ma_data_converter_config_init( @@ -929,14 +2983,15 @@ conversion is very similar to the resampling API. Create a `ma_data_converter` o ); ma_data_converter converter; - ma_result result = ma_data_converter_init(&config, &converter); + ma_result result = ma_data_converter_init(&config, NULL, &converter); if (result != MA_SUCCESS) { // An error occurred... } ``` -In the example above we use `ma_data_converter_config_init()` to initialize the config, however there's many more properties that can be configured, such as -channel maps and resampling quality. Something like the following may be more suitable depending on your requirements: +In the example above we use `ma_data_converter_config_init()` to initialize the config, however +there's many more properties that can be configured, such as channel maps and resampling quality. +Something like the following may be more suitable depending on your requirements: ```c ma_data_converter_config config = ma_data_converter_config_init_default(); @@ -946,14 +3001,14 @@ channel maps and resampling quality. Something like the following may be more su config.channelsOut = outputChannels; config.sampleRateIn = inputSampleRate; config.sampleRateOut = outputSampleRate; - ma_get_standard_channel_map(ma_standard_channel_map_flac, config.channelCountIn, config.channelMapIn); + ma_channel_map_init_standard(ma_standard_channel_map_flac, config.channelMapIn, sizeof(config.channelMapIn)/sizeof(config.channelMapIn[0]), config.channelCountIn); config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER; ``` Do the following to uninitialize the data converter: ```c - ma_data_converter_uninit(&converter); + ma_data_converter_uninit(&converter, NULL); ``` The following example shows how data can be processed @@ -970,33 +3025,42 @@ The following example shows how data can be processed // of output frames written. ``` -The data converter supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization. +The data converter supports multiple channels and is always interleaved (both input and output). +The channel count cannot be changed after initialization. -Sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the only -configuration property that can be changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of `ma_data_converter_config` is -set to `MA_TRUE`. To change the sample rate, use `ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. The -resampling algorithm cannot be changed after initialization. +Sample rates can be anything other than zero, and are always specified in hertz. They should be set +to something like 44100, etc. The sample rate is the only configuration property that can be +changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of +`ma_data_converter_config` is set to `MA_TRUE`. To change the sample rate, use +`ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. +The resampling algorithm cannot be changed after initialization. -Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process -frames, use `ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number -of input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the -number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large -buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek. +Processing always happens on a per PCM frame basis and always assumes interleaved input and output. +De-interleaved processing is not supported. To process frames, use +`ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames +you can fit in the output buffer and the number of input frames contained in the input buffer. On +output these variables contain the number of output frames that were written to the output buffer +and the number of input frames that were consumed in the process. You can pass in NULL for the +input buffer in which case it will be treated as an infinitely large +buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated +as seek. -Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with -`ma_data_converter_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of -input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`. +Sometimes it's useful to know exactly how many input frames will be required to output a specific +number of frames. You can calculate this with `ma_data_converter_get_required_input_frame_count()`. +Likewise, it's sometimes useful to know exactly how many frames would be output given a certain +number of input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`. -Due to the nature of how resampling works, the data converter introduces some latency if resampling is required. This can be retrieved in terms of both the -input rate and the output rate with `ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`. +Due to the nature of how resampling works, the data converter introduces some latency if resampling +is required. This can be retrieved in terms of both the input rate and the output rate with +`ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`. -7. Filtering -============ +11. Filtering +============= -7.1. Biquad Filtering ---------------------- +11.1. Biquad Filtering +---------------------- Biquad filtering is achieved with the `ma_biquad` API. Example: ```c @@ -1011,28 +3075,33 @@ Biquad filtering is achieved with the `ma_biquad` API. Example: ma_biquad_process_pcm_frames(&biquad, pFramesOut, pFramesIn, frameCount); ``` -Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, b1 and b2, and the denominator coefficients are a0, a1 and -a2. The a0 coefficient is required and coefficients must not be pre-normalized. +Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, +b1 and b2, and the denominator coefficients are a0, a1 and a2. The a0 coefficient is required and +coefficients must not be pre-normalized. -Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. When using -`ma_format_s16` the biquad filter will use fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used. +Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format +you need to convert it yourself beforehand. When using `ma_format_s16` the biquad filter will use +fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used. Input and output frames are always interleaved. -Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so: +Filtering can be applied in-place by passing in the same pointer for both the input and output +buffers, like so: ```c ma_biquad_process_pcm_frames(&biquad, pMyData, pMyData, frameCount); ``` -If you need to change the values of the coefficients, but maintain the values in the registers you can do so with `ma_biquad_reinit()`. This is useful if you -need to change the properties of the filter while keeping the values of registers valid to avoid glitching. Do not use `ma_biquad_init()` for this as it will -do a full initialization which involves clearing the registers to 0. Note that changing the format or channel count after initialization is invalid and will -result in an error. +If you need to change the values of the coefficients, but maintain the values in the registers you +can do so with `ma_biquad_reinit()`. This is useful if you need to change the properties of the +filter while keeping the values of registers valid to avoid glitching. Do not use +`ma_biquad_init()` for this as it will do a full initialization which involves clearing the +registers to 0. Note that changing the format or channel count after initialization is invalid and +will result in an error. -7.2. Low-Pass Filtering ------------------------ +11.2. Low-Pass Filtering +------------------------ Low-pass filtering is achieved with the following APIs: +---------+------------------------------------------+ @@ -1057,16 +3126,18 @@ Low-pass filter example: ma_lpf_process_pcm_frames(&lpf, pFramesOut, pFramesIn, frameCount); ``` -Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. Input and output -frames are always interleaved. +Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format +you need to convert it yourself beforehand. Input and output frames are always interleaved. -Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so: +Filtering can be applied in-place by passing in the same pointer for both the input and output +buffers, like so: ```c ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount); ``` -The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more, you can chain first and second order filters together. +The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more, +you can chain first and second order filters together. ```c for (iFilter = 0; iFilter < filterCount; iFilter += 1) { @@ -1074,19 +3145,22 @@ The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. } ``` -If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with `ma_lpf_reinit()`. This may be -useful if you need to change the sample rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the format or channel -count after initialization is invalid and will result in an error. +If you need to change the configuration of the filter, but need to maintain the state of internal +registers you can do so with `ma_lpf_reinit()`. This may be useful if you need to change the sample +rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the +format or channel count after initialization is invalid and will result in an error. -The `ma_lpf` object supports a configurable order, but if you only need a first order filter you may want to consider using `ma_lpf1`. Likewise, if you only -need a second order filter you can use `ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient. +The `ma_lpf` object supports a configurable order, but if you only need a first order filter you +may want to consider using `ma_lpf1`. Likewise, if you only need a second order filter you can use +`ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient. -If an even filter order is specified, a series of second order filters will be processed in a chain. If an odd filter order is specified, a first order filter -will be applied, followed by a series of second order filters in a chain. +If an even filter order is specified, a series of second order filters will be processed in a +chain. If an odd filter order is specified, a first order filter will be applied, followed by a +series of second order filters in a chain. -7.3. High-Pass Filtering ------------------------- +11.3. High-Pass Filtering +------------------------- High-pass filtering is achieved with the following APIs: +---------+-------------------------------------------+ @@ -1097,12 +3171,12 @@ High-pass filtering is achieved with the following APIs: | ma_hpf | High order high-pass filter (Butterworth) | +---------+-------------------------------------------+ -High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, `ma_hpf2` and `ma_hpf`. See example code for low-pass filters -for example usage. +High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, +`ma_hpf2` and `ma_hpf`. See example code for low-pass filters for example usage. -7.4. Band-Pass Filtering ------------------------- +11.4. Band-Pass Filtering +------------------------- Band-pass filtering is achieved with the following APIs: +---------+-------------------------------+ @@ -1112,13 +3186,14 @@ Band-pass filtering is achieved with the following APIs: | ma_bpf | High order band-pass filter | +---------+-------------------------------+ -Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and `ma_hpf`. See example code for low-pass filters for example -usage. Note that the order for band-pass filters must be an even number which means there is no first order band-pass filter, unlike low-pass and high-pass -filters. +Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and +`ma_hpf`. See example code for low-pass filters for example usage. Note that the order for +band-pass filters must be an even number which means there is no first order band-pass filter, +unlike low-pass and high-pass filters. -7.5. Notch Filtering --------------------- +11.5. Notch Filtering +--------------------- Notch filtering is achieved with the following APIs: +-----------+------------------------------------------+ @@ -1128,7 +3203,7 @@ Notch filtering is achieved with the following APIs: +-----------+------------------------------------------+ -7.6. Peaking EQ Filtering +11.6. Peaking EQ Filtering ------------------------- Peaking filtering is achieved with the following APIs: @@ -1139,8 +3214,8 @@ Peaking filtering is achieved with the following APIs: +----------+------------------------------------------+ -7.7. Low Shelf Filtering ------------------------- +11.7. Low Shelf Filtering +------------------------- Low shelf filtering is achieved with the following APIs: +-------------+------------------------------------------+ @@ -1149,11 +3224,12 @@ Low shelf filtering is achieved with the following APIs: | ma_loshelf2 | Second order low shelf filter | +-------------+------------------------------------------+ -Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to just turn them down rather than eliminate them entirely. +Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to +just turn them down rather than eliminate them entirely. -7.8. High Shelf Filtering -------------------------- +11.8. High Shelf Filtering +-------------------------- High shelf filtering is achieved with the following APIs: +-------------+------------------------------------------+ @@ -1162,18 +3238,20 @@ High shelf filtering is achieved with the following APIs: | ma_hishelf2 | Second order high shelf filter | +-------------+------------------------------------------+ -The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` instead of `ma_loshelf`. Where a low shelf filter is used to -adjust the volume of low frequencies, the high shelf filter does the same thing for high frequencies. +The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` +instead of `ma_loshelf`. Where a low shelf filter is used to adjust the volume of low frequencies, +the high shelf filter does the same thing for high frequencies. -8. Waveform and Noise Generation -================================ +12. Waveform and Noise Generation +================================= -8.1. Waveforms --------------- -miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved with the `ma_waveform` API. Example: +12.1. Waveforms +--------------- +miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved +with the `ma_waveform` API. Example: ```c ma_waveform_config config = ma_waveform_config_init( @@ -1195,11 +3273,12 @@ miniaudio supports generation of sine, square, triangle and sawtooth waveforms. ma_waveform_read_pcm_frames(&waveform, pOutput, frameCount); ``` -The amplitude, frequency, type, and sample rate can be changed dynamically with `ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`, -`ma_waveform_set_type()`, and `ma_waveform_set_sample_rate()` respectively. +The amplitude, frequency, type, and sample rate can be changed dynamically with +`ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`, `ma_waveform_set_type()`, and +`ma_waveform_set_sample_rate()` respectively. -You can invert the waveform by setting the amplitude to a negative value. You can use this to control whether or not a sawtooth has a positive or negative -ramp, for example. +You can invert the waveform by setting the amplitude to a negative value. You can use this to +control whether or not a sawtooth has a positive or negative ramp, for example. Below are the supported waveform types: @@ -1214,8 +3293,8 @@ Below are the supported waveform types: -8.2. Noise ----------- +12.2. Noise +----------- miniaudio supports generation of white, pink and Brownian noise via the `ma_noise` API. Example: ```c @@ -1237,13 +3316,16 @@ miniaudio supports generation of white, pink and Brownian noise via the `ma_nois ma_noise_read_pcm_frames(&noise, pOutput, frameCount); ``` -The noise API uses simple LCG random number generation. It supports a custom seed which is useful for things like automated testing requiring reproducibility. -Setting the seed to zero will default to `MA_DEFAULT_LCG_SEED`. +The noise API uses simple LCG random number generation. It supports a custom seed which is useful +for things like automated testing requiring reproducibility. Setting the seed to zero will default +to `MA_DEFAULT_LCG_SEED`. -The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`, `ma_noise_set_seed()`, and `ma_noise_set_type()` respectively. +The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`, +`ma_noise_set_seed()`, and `ma_noise_set_type()` respectively. -By default, the noise API will use different values for different channels. So, for example, the left side in a stereo stream will be different to the right -side. To instead have each channel use the same random value, set the `duplicateChannels` member of the noise config to true, like so: +By default, the noise API will use different values for different channels. So, for example, the +left side in a stereo stream will be different to the right side. To instead have each channel use +the same random value, set the `duplicateChannels` member of the noise config to true, like so: ```c config.duplicateChannels = MA_TRUE; @@ -1261,10 +3343,11 @@ Below are the supported noise types. -9. Audio Buffers -================ -miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can read from memory that's managed by the application, but -can also handle the memory management for you internally. Memory management is flexible and should support most use cases. +13. Audio Buffers +================= +miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can +read from memory that's managed by the application, but can also handle the memory management for +you internally. Memory management is flexible and should support most use cases. Audio buffers are initialised using the standard configuration system used everywhere in miniaudio: @@ -1287,11 +3370,14 @@ Audio buffers are initialised using the standard configuration system used every ma_audio_buffer_uninit(&buffer); ``` -In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an application can do self-managed memory allocation. If you -would rather make a copy of the data, use `ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`. +In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an +application can do self-managed memory allocation. If you would rather make a copy of the data, use +`ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`. -Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the raw audio data in a contiguous block of memory. That is, -the raw audio data will be located immediately after the `ma_audio_buffer` structure. To do this, use `ma_audio_buffer_alloc_and_init()`: +Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the +raw audio data in a contiguous block of memory. That is, the raw audio data will be located +immediately after the `ma_audio_buffer` structure. To do this, use +`ma_audio_buffer_alloc_and_init()`: ```c ma_audio_buffer_config config = ma_audio_buffer_config_init( @@ -1312,13 +3398,18 @@ the raw audio data will be located immediately after the `ma_audio_buffer` struc ma_audio_buffer_uninit_and_free(&buffer); ``` -If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it with `ma_audio_buffer_uninit_and_free()`. In the example above, -the memory pointed to by `pExistingData` will be copied into the buffer, which is contrary to the behavior of `ma_audio_buffer_init()`. +If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it +with `ma_audio_buffer_uninit_and_free()`. In the example above, the memory pointed to by +`pExistingData` will be copied into the buffer, which is contrary to the behavior of +`ma_audio_buffer_init()`. -An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the cursor moves forward. The last parameter (`loop`) can be -used to determine if the buffer should loop. The return value is the number of frames actually read. If this is less than the number of frames requested it -means the end has been reached. This should never happen if the `loop` parameter is set to true. If you want to manually loop back to the start, you can do so -with with `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an audio buffer. +An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the +cursor moves forward. The last parameter (`loop`) can be used to determine if the buffer should +loop. The return value is the number of frames actually read. If this is less than the number of +frames requested it means the end has been reached. This should never happen if the `loop` +parameter is set to true. If you want to manually loop back to the start, you can do so with with +`ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an +audio buffer. ```c ma_uint64 framesRead = ma_audio_buffer_read_pcm_frames(pAudioBuffer, pFramesOut, desiredFrameCount, isLooping); @@ -1327,8 +3418,8 @@ with with `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an exam } ``` -Sometimes you may want to avoid the cost of data movement between the internal buffer and the output buffer. Instead you can use memory mapping to retrieve a -pointer to a segment of data: +Sometimes you may want to avoid the cost of data movement between the internal buffer and the +output buffer. Instead you can use memory mapping to retrieve a pointer to a segment of data: ```c void* pMappedFrames; @@ -1344,23 +3435,30 @@ pointer to a segment of data: } ``` -When you use memory mapping, the read cursor is increment by the frame count passed in to `ma_audio_buffer_unmap()`. If you decide not to process every frame -you can pass in a value smaller than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is that it does not handle looping -for you. You can determine if the buffer is at the end for the purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of -`ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` as an error when returned by `ma_audio_buffer_unmap()`. +When you use memory mapping, the read cursor is increment by the frame count passed in to +`ma_audio_buffer_unmap()`. If you decide not to process every frame you can pass in a value smaller +than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is +that it does not handle looping for you. You can determine if the buffer is at the end for the +purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of +`ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` +as an error when returned by `ma_audio_buffer_unmap()`. -10. Ring Buffers +14. Ring Buffers ================ -miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates -on bytes, whereas the `ma_pcm_rb` operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around `ma_rb`. +miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via +the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates on bytes, whereas the `ma_pcm_rb` +operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around +`ma_rb`. -Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved streams. The caller can also allocate their own backing memory for -the ring buffer to use internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for you. +Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved +streams. The caller can also allocate their own backing memory for the ring buffer to use +internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for +you. -The examples below use the PCM frame variant of the ring buffer since that's most likely the one you will want to use. To initialize a ring buffer, do -something like the following: +The examples below use the PCM frame variant of the ring buffer since that's most likely the one +you will want to use. To initialize a ring buffer, do something like the following: ```c ma_pcm_rb rb; @@ -1370,39 +3468,53 @@ something like the following: } ``` -The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because it's the PCM varient of the ring buffer API. For the regular -ring buffer that operates on bytes you would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes instead of frames. The -fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation -routines. Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used. +The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because +it's the PCM varient of the ring buffer API. For the regular ring buffer that operates on bytes you +would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes +instead of frames. The fourth parameter is an optional pre-allocated buffer and the fifth parameter +is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation routines. +Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used. -Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. To manage your -sub-buffers you can use `ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and `ma_pcm_rb_get_subbuffer_ptr()`. +Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is +offset from each other based on the stride. To manage your sub-buffers you can use +`ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and +`ma_pcm_rb_get_subbuffer_ptr()`. -Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section of the ring buffer. You specify the number of frames you -need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of frames requested will require -a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you're given may be less than the number you requested. +Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section +of the ring buffer. You specify the number of frames you need, and on output it will set to what +was actually acquired. If the read or write pointer is positioned such that the number of frames +requested will require a loop, it will be clamped to the end of the buffer. Therefore, the number +of frames you're given may be less than the number you requested. -After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the buffer and then "commit" it with `ma_pcm_rb_commit_read()` or -`ma_pcm_rb_commit_write()`. This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier -call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and -`ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was originally requested. +After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the +buffer and then "commit" it with `ma_pcm_rb_commit_read()` or `ma_pcm_rb_commit_write()`. This is +where the read/write pointers are updated. When you commit you need to pass in the buffer that was +returned by the earlier call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is +only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and +`ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was +originally requested. -If you want to correct for drift between the write pointer and the read pointer you can use a combination of `ma_pcm_rb_pointer_distance()`, -`ma_pcm_rb_seek_read()` and `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only move the read pointer forward via -the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If +If you want to correct for drift between the write pointer and the read pointer you can use a +combination of `ma_pcm_rb_pointer_distance()`, `ma_pcm_rb_seek_read()` and +`ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only +move the read pointer forward via the consumer thread, and the write pointer forward by the +producer thread. If there is too much space between the pointers, move the read pointer forward. If there is too little space between the pointers, move the write pointer forward. -You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` API. This is exactly the same, only you will use the `ma_rb` -functions instead of `ma_pcm_rb` and instead of frame counts you will pass around byte counts. +You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` +API. This is exactly the same, only you will use the `ma_rb` functions instead of `ma_pcm_rb` and +instead of frame counts you will pass around byte counts. -The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most significant bit being used to encode a loop flag and the internally -managed buffers always being aligned to MA_SIMD_ALIGNMENT. +The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most +significant bit being used to encode a loop flag and the internally managed buffers always being +aligned to `MA_SIMD_ALIGNMENT`. -Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread. +Note that the ring buffer is only thread safe when used by a single consumer thread and single +producer thread. -11. Backends +15. Backends ============ The following backends are supported by miniaudio. @@ -1428,28 +3540,36 @@ The following backends are supported by miniaudio. Some backends have some nuance details you may want to be aware of. -11.1. WASAPI +15.1. WASAPI ------------ -- Low-latency shared mode will be disabled when using an application-defined sample rate which is different to the device's native sample rate. To work around - this, set `wasapi.noAutoConvertSRC` to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing when the - `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC will result in miniaudio's internal resampler being used instead - which will in turn enable the use of low-latency shared mode. +- Low-latency shared mode will be disabled when using an application-defined sample rate which is + different to the device's native sample rate. To work around this, set `wasapi.noAutoConvertSRC` + to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing + when the `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC + will result in miniaudio's internal resampler being used instead which will in turn enable the + use of low-latency shared mode. -11.2. PulseAudio +15.2. PulseAudio ---------------- - If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki: - https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. Alternatively, consider using a different backend such as ALSA. + https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. + Alternatively, consider using a different backend such as ALSA. -11.3. Android +15.3. Android ------------- -- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: `` -- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES. -- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however - perform your own device enumeration through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it to ma_device_init(). -- The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio's built-in resampler is to take advantage of any - potential device-specific optimizations the driver may implement. +- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: + `` +- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a + limitation with OpenSL|ES. +- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration + API (devices are enumerated through Java). You can however perform your own device enumeration + through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it + to ma_device_init(). +- The backend API will perform resampling where possible. The reason for this as opposed to using + miniaudio's built-in resampler is to take advantage of any potential device-specific + optimizations the driver may implement. -11.4. UWP +15.4. UWP --------- - UWP only supports default playback and capture devices. - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest): @@ -1463,28 +3583,49 @@ Some backends have some nuance details you may want to be aware of. ``` -11.5. Web Audio / Emscripten +15.5. Web Audio / Emscripten ---------------------------- - You cannot use `-std=c*` compiler flags, nor `-ansi`. This only applies to the Emscripten build. -- The first time a context is initialized it will create a global object called "miniaudio" whose primary purpose is to act as a factory for device objects. -- Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated. -- Google has implemented a policy in their browsers that prevent automatic media output without first receiving some kind of user input. The following web page - has additional details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device may fail if you try to start playback - without first handling some kind of user input. +- The first time a context is initialized it will create a global object called "miniaudio" whose + primary purpose is to act as a factory for device objects. +- Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as + they've been deprecated. +- Google has implemented a policy in their browsers that prevent automatic media output without + first receiving some kind of user input. The following web page has additional details: + https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device + may fail if you try to start playback without first handling some kind of user input. -12. Miscellaneous Notes +16. Optimization Tips +===================== + +16.1. High Level API +-------------------- +- If a sound does not require doppler or pitch shifting, consider disabling pitching by + initializing the sound with the `MA_SOUND_FLAG_NO_PITCH` flag. +- If a sound does not require spatialization, disable it by initialzing the sound with the + `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. It can be renabled again post-initialization with + `ma_sound_set_spatialization_enabled()`. + + + +17. Miscellaneous Notes ======================= -- Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as - PulseAudio may naturally support it, though not all have been tested. -- The contents of the output buffer passed into the data callback will always be pre-initialized to silence unless the `noPreZeroedOutputBuffer` config variable - in `ma_device_config` is set to true, in which case it'll be undefined which will require you to write something to the entire buffer. -- By default miniaudio will automatically clip samples. This only applies when the playback sample format is configured as `ma_format_f32`. If you are doing - clipping yourself, you can disable this overhead by setting `noClip` to true in the device config. -- The sndio backend is currently only enabled on OpenBSD builds. -- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it. +- Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for + WASAPI and Core Audio, however other backends such as PulseAudio may naturally support it, though + not all have been tested. +- The contents of the output buffer passed into the data callback will always be pre-initialized to + silence unless the `noPreSilencedOutputBuffer` config variable in `ma_device_config` is set to + true, in which case it'll be undefined which will require you to write something to the entire + buffer. +- By default miniaudio will automatically clip samples. This only applies when the playback sample + format is configured as `ma_format_f32`. If you are doing clipping yourself, you can disable this + overhead by setting `noClip` to true in the device config. - Note that GCC and Clang requires `-msse2`, `-mavx2`, etc. for SIMD optimizations. -- When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This is due to 64-bit file APIs not being available. +- The sndio backend is currently only enabled on OpenBSD builds. +- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can + use it. +- When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This + is due to 64-bit file APIs not being available. */ - diff --git a/vendor/miniaudio/effects.odin b/vendor/miniaudio/effects.odin new file mode 100644 index 000000000..e86d670d9 --- /dev/null +++ b/vendor/miniaudio/effects.odin @@ -0,0 +1,300 @@ +package miniaudio + +import c "core:c/libc" + +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} + +/* +Delay +*/ +delay_config :: struct { + channels: u32, + sampleRate: u32, + delayInFrames: u32, + delayStart: b32, /* Set to true to delay the start of the output; false otherwise. */ + wet: f32, /* 0..1. Default = 1. */ + dry: f32, /* 0..1. Default = 1. */ + decay: f32, /* 0..1. Default = 0 (no feedback). Feedback decay. Use this for echo. */ +} + +delay :: struct { + config: delay_config, + cursor: u32, /* Feedback is written to this cursor. Always equal or in front of the read cursor. */ + bufferSizeInFrames: u32, /* The maximum of config.startDelayInFrames and config.feedbackDelayInFrames. */ + pBuffer: [^]f32, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + delay_config_init :: proc(channels, sampleRate, delayInFrames: u32, decay: f32) -> delay_config --- + + delay_init :: proc(pConfig: ^delay_config, pAllocationCallbacks: ^allocation_callbacks, pDelay: ^delay) -> result --- + delay_uninit :: proc(pDelay: ^delay, pAllocationCallbacks: ^allocation_callbacks) --- + delay_process_pcm_frames :: proc(pDelay: ^delay, pFramesOut, pFramesIn: rawptr, frameCount: u32) -> result --- + delay_set_wet :: proc(pDelay: ^delay, value: f32) --- + delay_get_wet :: proc(pDelay: ^delay) -> f32 --- + delay_set_dry :: proc(pDelay: ^delay, value: f32) --- + delay_get_dry :: proc(pDelay: ^delay) -> f32 --- + delay_set_decay :: proc(pDelay: ^delay, value: f32) --- + delay_get_decay :: proc(pDelay: ^delay) -> f32 --- +} + + +/* Gainer for smooth volume changes. */ +gainer_config :: struct { + channels: u32, + smoothTimeInFrames: u32, +} + +gainer :: struct { + config: gainer_config, + t: u32, + pOldGains: [^]f32, + pNewGains: [^]f32, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + gainer_config_init :: proc(channels, smoothTimeInFrames: u32) -> gainer_config --- + + gainer_get_heap_size :: proc(pConfig: ^gainer_config, pHeapSizeInBytes: ^c.size_t) -> result --- + gainer_init_preallocated :: proc(pConfig: ^gainer_config, pHeap: rawptr, pGainer: ^gainer) -> result --- + gainer_init :: proc(pConfig: ^gainer_config, pAllocationCallbacks: ^allocation_callbacks, pGainer: ^gainer) -> result --- + gainer_uninit :: proc(pGainer: ^gainer, pAllocationCallbacks: ^allocation_callbacks) --- + gainer_process_pcm_frames :: proc(pGainer: ^gainer, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- + gainer_set_gain :: proc(pGainer: ^gainer, newGain: f32) -> result --- + gainer_set_gains :: proc(pGainer: ^gainer, pNewGains: [^]f32) -> result --- +} + + +/* Stereo panner. */ +pan_mode :: enum c.int { + balance = 0, /* Does not blend one side with the other. Technically just a balance. Compatible with other popular audio engines and therefore the default. */ + pan, /* A true pan. The sound from one side will "move" to the other side and blend with it. */ +} + +panner_config :: struct { + format: format, + channels: u32, + mode: pan_mode, + pan: f32, +} + +panner :: struct { + format: format, + channels: u32, + mode: pan_mode, + pan: f32, /* -1..1 where 0 is no pan, -1 is left side, +1 is right side. Defaults to 0. */ +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + panner_config_init :: proc(format: format, channels: u32) -> panner_config --- + + panner_init :: proc(pConfig: ^panner_config, pPanner: ^panner) -> result --- + panner_process_pcm_frames :: proc(pPanner: ^panner, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result --- + panner_set_mode :: proc(pPanner: ^panner, mode: pan_mode) --- + panner_get_mode :: proc(pPanner: ^panner) -> pan_mode --- + panner_set_pan :: proc(pPanner: ^panner, pan: f32) --- + panner_get_pan :: proc(pPanner: ^panner) -> f32 --- +} + + +/* Fader. */ +fader_config :: struct { + format: format, + channels: u32, + sampleRate: u32, +} + +fader :: struct { + config: fader_config, + volumeBeg: f32, /* If volumeBeg and volumeEnd is equal to 1, no fading happens (ma_fader_process_pcm_frames() will run as a passthrough). */ + volumeEnd: f32, + lengthInFrames: u64, /* The total length of the fade. */ + cursorInFrames: u64, /* The current time in frames. Incremented by ma_fader_process_pcm_frames(). */ +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + fader_config_init :: proc(format: format, channels, sampleRate: u32) -> fader_config --- + + fader_init :: proc(pConfig: ^fader_config, pFader: ^fader) -> result --- + fader_process_pcm_frames :: proc(pFader: ^fader, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result --- + fader_get_data_format :: proc(pFader: ^fader, pFormat: ^format, pChannels, pSampleRate: ^u32) --- + fader_set_fade :: proc(pFader: ^fader, volumeBeg, volumeEnd: f32, lengthInFrames: u64) --- + fader_get_current_volume :: proc(pFader: ^fader) -> f32 --- +} + + +/* Spatializer. */ +vec3f :: struct { + x: f32, + y: f32, + z: f32, +} + +attenuation_model :: enum c.int { + none, /* No distance attenuation and no spatialization. */ + inverse, /* Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED. */ + linear, /* Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED. */ + exponential, /* Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED. */ +} + +positioning :: enum c.int { + absolute, + relative, +} + +handedness :: enum c.int { + right, + left, +} + +spatializer_listener_config :: struct { + channelsOut: u32, + pChannelMapOut: [^]channel, + handedness: handedness, /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ + coneInnerAngleInRadians: f32, + coneOuterAngleInRadians: f32, + coneOuterGain: f32, + speedOfSound: f32, + worldUp: vec3f, +} + +spatializer_listener :: struct { + config: spatializer_listener_config, + position: vec3f, /* The absolute position of the listener. */ + direction: vec3f, /* The direction the listener is facing. The world up vector is config.worldUp. */ + velocity: vec3f, + isEnabled: b32, + + /* Memory management. */ + _ownsHeap: b32, + _pHeap: rawptr, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + spatializer_listener_config_init :: proc(channelsOut: u32) -> spatializer_listener_config --- + + spatializer_listener_get_heap_size :: proc(pConfig: ^spatializer_listener_config, pHeapSizeInBytes: ^c.size_t) -> result --- + spatializer_listener_init_preallocated :: proc(pConfig: ^spatializer_listener_config, pHeap: rawptr, pListener: ^spatializer_listener) -> result --- + spatializer_listener_init :: proc(pConfig: ^spatializer_listener_config, pAllocationCallbacks: ^allocation_callbacks, pListener: ^spatializer_listener) -> result --- + spatializer_listener_uninit :: proc(pListener: ^spatializer_listener, pAllocationCallbacks: ^allocation_callbacks) --- + spatializer_listener_get_channel_map :: proc(pListener: ^spatializer_listener) -> ^channel --- + spatializer_listener_set_cone :: proc(pListener: ^spatializer_listener, innerAngleInRadians, outerAngleInRadians, outerGain: f32) --- + spatializer_listener_get_cone :: proc(pListener: ^spatializer_listener, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) --- + spatializer_listener_set_position :: proc(pListener: ^spatializer_listener, x, y, z: f32) --- + spatializer_listener_get_position :: proc(pListener: ^spatializer_listener) -> vec3f --- + spatializer_listener_set_direction :: proc(pListener: ^spatializer_listener, x, y, z: f32) --- + spatializer_listener_get_direction :: proc(pListener: ^spatializer_listener) -> vec3f --- + spatializer_listener_set_velocity :: proc(pListener: ^spatializer_listener, x, y, z: f32) --- + spatializer_listener_get_velocity :: proc(pListener: ^spatializer_listener) -> vec3f --- + spatializer_listener_set_speed_of_sound :: proc(pListener: ^spatializer_listener, speedOfSound: f32) --- + spatializer_listener_get_speed_of_sound :: proc(pListener: ^spatializer_listener) -> f32 --- + spatializer_listener_set_world_up :: proc(pListener: ^spatializer_listener, x, y, z: f32) --- + spatializer_listener_get_world_up :: proc(pListener: ^spatializer_listener) -> vec3f --- + spatializer_listener_set_enabled :: proc(pListener: ^spatializer_listener, isEnabled: b32) --- + spatializer_listener_is_enabled :: proc(pListener: ^spatializer_listener) -> b32 --- +} + +spatializer_config :: struct { + channelsIn: u32, + channelsOut: u32, + pChannelMapIn: [^]channel, + attenuationModel: attenuation_model, + positioning: positioning, + handedness: handedness, /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ + minGain: f32, + maxGain: f32, + minDistance: f32, + maxDistance: f32, + rolloff: f32, + coneInnerAngleInRadians: f32, + coneOuterAngleInRadians: f32, + coneOuterGain: f32, + dopplerFactor: f32, /* Set to 0 to disable doppler effect. */ + directionalAttenuationFactor: f32, /* Set to 0 to disable directional attenuation. */ + gainSmoothTimeInFrames: u32, /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ +} + +spatializer :: struct { + channelsIn: u32, + channelsOut: u32, + pChannelMapIn: [^]channel, + attenuationModel: attenuation_model, + positioning: positioning, + handedness: handedness, /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ + minGain: f32, + maxGain: f32, + minDistance: f32, + maxDistance: f32, + rolloff: f32, + coneInnerAngleInRadians: f32, + coneOuterAngleInRadians: f32, + coneOuterGain: f32, + dopplerFactor: f32, /* Set to 0 to disable doppler effect. */ + directionalAttenuationFactor: f32, /* Set to 0 to disable directional attenuation. */ + gainSmoothTimeInFrames: u32, /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ + position: vec3f, + direction: vec3f, + velocity: vec3f, /* For doppler effect. */ + dopplerPitch: f32, /* Will be updated by ma_spatializer_process_pcm_frames() and can be used by higher level functions to apply a pitch shift for doppler effect. */ + gainer: gainer, /* For smooth gain transitions. */ + pNewChannelGainsOut: [^]f32, /* An offset of _pHeap. Used by ma_spatializer_process_pcm_frames() to store new channel gains. The number of elements in this array is equal to config.channelsOut. */ + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + spatializer_config_init :: proc(channelsIn, channelsOut: u32) -> spatializer_config --- + + spatializer_get_heap_size :: proc(pConfig: ^spatializer_config, pHeapSizeInBytes: ^c.size_t) -> result --- + spatializer_init_preallocated :: proc(pConfig: ^spatializer_config, pHeap: rawptr, pSpatializer: ^spatializer) -> result --- + spatializer_init :: proc(pConfig: ^spatializer_config, pAllocationCallbacks: ^allocation_callbacks, pSpatializer: ^spatializer) -> result --- + spatializer_uninit :: proc(pSpatializer: ^spatializer, pAllocationCallbacks: ^allocation_callbacks) --- + spatializer_process_pcm_frames :: proc(pSpatializer: ^spatializer, pListener: ^spatializer_listener, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result --- + spatializer_get_input_channels :: proc(pSpatializer: ^spatializer) -> u32 --- + spatializer_get_output_channels :: proc(pSpatializer: ^spatializer) -> u32 --- + spatializer_set_attenuation_model :: proc(pSpatializer: ^spatializer, attenuationModel: attenuation_model) --- + spatializer_get_attenuation_model :: proc(pSpatializer: ^spatializer) -> attenuation_model --- + spatializer_set_positioning :: proc(pSpatializer: ^spatializer, positioning: positioning) --- + spatializer_get_positioning :: proc(pSpatializer: ^spatializer) -> positioning --- + spatializer_set_rolloff :: proc(pSpatializer: ^spatializer, rolloff: f32) --- + spatializer_get_rolloff :: proc(pSpatializer: ^spatializer) -> f32 --- + spatializer_set_min_gain :: proc(pSpatializer: ^spatializer, minGain: f32) --- + spatializer_get_min_gain :: proc(pSpatializer: ^spatializer) -> f32 --- + spatializer_set_max_gain :: proc(pSpatializer: ^spatializer, maxGain: f32) --- + spatializer_get_max_gain :: proc(pSpatializer: ^spatializer) -> f32 --- + spatializer_set_min_distance :: proc(pSpatializer: ^spatializer, minDistance: f32) --- + spatializer_get_min_distance :: proc(pSpatializer: ^spatializer) -> f32 --- + spatializer_set_max_distance :: proc(pSpatializer: ^spatializer, maxDistance: f32) --- + spatializer_get_max_distance :: proc(pSpatializer: ^spatializer) -> f32 --- + spatializer_set_cone :: proc(pSpatializer: ^spatializer, innerAngleInRadians, outerAngleInRadians, outerGain: f32) --- + spatializer_get_cone :: proc(pSpatializer: ^spatializer, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) --- + spatializer_set_doppler_factor :: proc(pSpatializer: ^spatializer, dopplerFactor: f32) --- + spatializer_get_doppler_factor :: proc(pSpatializer: ^spatializer) -> f32 --- + spatializer_set_directional_attenuation_factor :: proc(pSpatializer: ^spatializer, directionalAttenuationFactor: f32) --- + spatializer_get_directional_attenuation_factor :: proc(pSpatializer: ^spatializer) -> f32 --- + spatializer_set_position :: proc(pSpatializer: ^spatializer, x, y, z: f32) --- + spatializer_get_position :: proc(pSpatializer: ^spatializer) -> vec3f --- + spatializer_set_direction :: proc(pSpatializer: ^spatializer, x, y, z: f32) --- + spatializer_get_direction :: proc(pSpatializer: ^spatializer) -> vec3f --- + spatializer_set_velocity :: proc(pSpatializer: ^spatializer, x, y, z: f32) --- + spatializer_get_velocity :: proc(pSpatializer: ^spatializer) -> vec3f --- + spatializer_get_relative_position_and_direction :: proc(pSpatializer: ^spatializer, pListener: ^spatializer_listener, pRelativePos, pRelativeDir: ^vec3f) --- +} diff --git a/vendor/miniaudio/encoding.odin b/vendor/miniaudio/encoding.odin index 9b84108dc..ee396466a 100644 --- a/vendor/miniaudio/encoding.odin +++ b/vendor/miniaudio/encoding.odin @@ -19,14 +19,14 @@ Encoders do not perform any format conversion for you. If your target format doe ************************************************************************************************************************************************************/ -encoder_write_proc :: proc "c" (pEncoder: ^encoder, pBufferIn: rawptr, bytesToWrite: c.size_t) -> c.size_t /* Returns the number of bytes written. */ -encoder_seek_proc :: proc "c" (pEncoder: ^encoder, byteOffset: c.int, origin: seek_origin) -> b32 +encoder_write_proc :: proc "c" (pEncoder: ^encoder, pBufferIn: rawptr, bytesToWrite: c.size_t, pBytesWritten: ^c.size_t) -> result +encoder_seek_proc :: proc "c" (pEncoder: ^encoder, offset: i64, origin: seek_origin) -> result encoder_init_proc :: proc "c" (pEncoder: ^encoder) -> result -encoder_uninit_proc :: proc "c" (pEncoder: ^encoder) -encoder_write_pcm_frames_proc :: proc "c" (pEncoder: ^encoder, pFramesIn: rawptr, frameCount: u64) -> u64 +encoder_uninit_proc :: proc "c" (pEncoder: ^encoder) +encoder_write_pcm_frames_proc :: proc "c" (pEncoder: ^encoder, pFramesIn: rawptr, frameCount: u64, pFramesWritten: ^u64) -> result encoder_config :: struct { - resourceFormat: resource_format, + encodingFormat: encoding_format, format: format, channels: u32, sampleRate: u32, @@ -42,16 +42,23 @@ encoder :: struct { onWritePCMFrames: encoder_write_pcm_frames_proc, pUserData: rawptr, pInternalEncoder: rawptr, /* <-- The drwav/drflac/stb_vorbis/etc. objects. */ - pFile: rawptr, /* FILE*. Only used when initialized with ma_encoder_init_file(). */ + data: struct #raw_union { + vfs: struct { + pVFS: ^vfs, + file: vfs_file, + }, + }, } @(default_calling_convention="c", link_prefix="ma_") foreign lib { - encoder_config_init :: proc(resourceFormat: resource_format, format: format, channels: u32, sampleRate: u32) -> encoder_config --- + encoder_config_init :: proc(encodingFormat: encoding_format, format: format, channels: u32, sampleRate: u32) -> encoder_config --- encoder_init :: proc(onWrite: encoder_write_proc, onSeek: encoder_seek_proc, pUserData: rawptr, pConfig: ^encoder_config, pEncoder: ^encoder) -> result --- + encoder_init_vfs :: proc(pVFS: ^vfs, pFilePath: cstring, pConfig: ^encoder_config, pEncoder: ^encoder) -> result --- + encoder_init_vfs_w :: proc(pVFS: ^vfs, pFilePath: [^]c.wchar_t, pConfig: ^encoder_config, pEncoder: ^encoder) -> result --- encoder_init_file :: proc(pFilePath: cstring, pConfig: ^encoder_config, pEncoder: ^encoder) -> result --- encoder_init_file_w :: proc(pFilePath: [^]c.wchar_t, pConfig: ^encoder_config, pEncoder: ^encoder) -> result --- encoder_uninit :: proc(pEncoder: ^encoder) --- - encoder_write_pcm_frames :: proc(pEncoder: ^encoder, FramesIn: rawptr, frameCount: u64) -> u64 --- + encoder_write_pcm_frames :: proc(pEncoder: ^encoder, FramesIn: rawptr, frameCount: u64, pFramesWritten: ^u64) -> result --- } diff --git a/vendor/miniaudio/engine.odin b/vendor/miniaudio/engine.odin new file mode 100644 index 000000000..935d54744 --- /dev/null +++ b/vendor/miniaudio/engine.odin @@ -0,0 +1,341 @@ +package miniaudio + +import "core:c" + +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} + +/************************************************************************************************************************************************************ + +Engine + +************************************************************************************************************************************************************/ + +/* Sound flags. */ +sound_flags :: enum c.int { + STREAM = 0x00000001, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */ + DECODE = 0x00000002, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */ + ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */ + WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */ + NO_DEFAULT_ATTACHMENT = 0x00000010, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */ + NO_PITCH = 0x00000020, /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */ + NO_SPATIALIZATION = 0x00000040, /* Disable spatialization. */ +} + +ENGINE_MAX_LISTENERS :: 4 + +LISTENER_INDEX_CLOSEST :: 255 + +engine_node_type :: enum c.int { + sound, + group, +} + +engine_node_config :: struct { + pEngine: ^engine, + type: engine_node_type, + channelsIn: u32, + channelsOut: u32, + sampleRate: u32, /* Only used when the type is set to ma_engine_node_type_sound. */ + isPitchDisabled: b8, /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ + isSpatializationDisabled: b8, /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */ + pinnedListenerIndex: u8, /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ +} + +/* Base node object for both ma_sound and ma_sound_group. */ +engine_node :: struct { + baseNode: node_base, /* Must be the first member for compatiblity with the ma_node API. */ + pEngine: ^engine, /* A pointer to the engine. Set based on the value from the config. */ + sampleRate: u32, /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */ + fader: fader, + resampler: linear_resampler, /* For pitch shift. */ + spatializer: spatializer, + panner: panner, + pitch: f32, /*atomic*/ + oldPitch: f32, /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */ + oldDopplerPitch: f32, /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */ + isPitchDisabled: b32, /*atomic*/ /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */ + isSpatializationDisabled: b32, /*atomic*/ /* Set to false by default. When set to false, will not have spatialisation applied. */ + pinnedListenerIndex: u32, /*atomic*/ /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ + + /* Memory management. */ + _ownsHeap: b8, + _pHeap: rawptr, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + engine_node_config_init :: proc(pEngine: ^engine, type: engine_node_type, flags: u32) -> engine_node_config --- + + engine_node_get_heap_size :: proc(pConfig: ^engine_node_config, pHeapSizeInBytes: ^c.size_t) -> result --- + engine_node_init_preallocated :: proc(pConfig: ^engine_node_config, pHeap: rawptr, pEngineNode: ^engine_node) -> result --- + engine_node_init :: proc(pConfig: ^engine_node_config, pAllocationCallbacks: ^allocation_callbacks, pEngineNode: ^engine_node) -> result --- + engine_node_uninit :: proc(pEngineNode: ^engine_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +SOUND_SOURCE_CHANNEL_COUNT :: 0xFFFFFFFF + +sound_config :: struct { + pFilePath: cstring, /* Set this to load from the resource manager. */ + pFilePathW: [^]c.wchar_t, /* Set this to load from the resource manager. */ + pDataSource: ^data_source, /* Set this to load from an existing data source. */ + pInitialAttachment: ^node, /* If set, the sound will be attached to an input of this node. This can be set to a ma_sound. If set to NULL, the sound will be attached directly to the endpoint unless MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT is set in `flags`. */ + initialAttachmentInputBusIndex: u32, /* The index of the input bus of pInitialAttachment to attach the sound to. */ + channelsIn: u32, /* Ignored if using a data source as input (the data source's channel count will be used always). Otherwise, setting to 0 will cause the engine's channel count to be used. */ + channelsOut: u32, /* Set this to 0 (default) to use the engine's channel count. Set to MA_SOUND_SOURCE_CHANNEL_COUNT to use the data source's channel count (only used if using a data source as input). */ + flags: u32, /* A combination of MA_SOUND_FLAG_* flags. */ + initialSeekPointInPCMFrames: u64, /* Initializes the sound such that it's seeked to this location by default. */ + rangeBegInPCMFrames: u64, + rangeEndInPCMFrames: u64, + loopPointBegInPCMFrames: u64, + loopPointEndInPCMFrames: u64, + isLooping: b32, + pDoneFence: ^fence, /* Released when the resource manager has finished decoding the entire sound. Not used with streams. */ +} + +sound :: struct { + engineNode: engine_node, /* Must be the first member for compatibility with the ma_node API. */ + pDataSource: ^data_source, + seekTarget: u64, /*atomic*/ /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */ + atEnd: b32, /*atomic*/ + ownsDataSource: b8, + + /* + We're declaring a resource manager data source object here to save us a malloc when loading a + sound via the resource manager, which I *think* will be the most common scenario. + */ + pResourceManagerDataSource: ^resource_manager_data_source, +} + +/* Structure specifically for sounds played with ma_engine_play_sound(). Making this a separate structure to reduce overhead. */ +sound_inlined :: struct { + sound: sound, + pNext: ^sound_inlined, + pPrev: ^sound_inlined, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + sound_config_init :: proc() -> sound_config --- + + sound_init_from_file :: proc(pEngine: ^engine, pFilePath: cstring, flags: u32, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result --- + sound_init_from_file_w :: proc(pEngine: ^engine, pFilePath: [^]c.wchar_t, flags: u32, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result --- + sound_init_copy :: proc(pEngine: ^engine, pExistingSound: ^sound, flags: u32, pGroup: ^sound_group, pSound: ^sound) -> result --- + sound_init_from_data_source :: proc(pEngine: ^engine, pDataSource: ^data_source, flags: u32, pGroup: ^sound_group, pSound: ^sound) -> result --- + sound_init_ex :: proc(pEngine: ^engine, pConfig: ^sound_config, pSound: ^sound) -> result --- + sound_uninit :: proc(pSound: ^sound) --- + sound_get_engine :: proc(pSound: ^sound) -> ^engine --- + sound_get_data_source :: proc(pSound: ^sound) -> ^data_source --- + sound_start :: proc(pSound: ^sound) -> result --- + sound_stop :: proc(pSound: ^sound) -> result --- + sound_set_volume :: proc(pSound: ^sound, volume: f32) --- + sound_get_volume :: proc(pSound: ^sound) -> f32 --- + sound_set_pan :: proc(pSound: ^sound, pan: f32) --- + sound_get_pan :: proc(pSound: ^sound) -> f32 --- + sound_set_pan_mode :: proc(pSound: ^sound, panMode: pan_mode) --- + sound_get_pan_mode :: proc(pSound: ^sound) -> pan_mode --- + sound_set_pitch :: proc(pSound: ^sound, pitch: f32) --- + sound_get_pitch :: proc(pSound: ^sound) -> f32 --- + sound_set_spatialization_enabled :: proc(pSound: ^sound, enabled: b32) --- + sound_is_spatialization_enabled :: proc(pSound: ^sound) -> b32 --- + sound_set_pinned_listener_index :: proc(pSound: ^sound, listenerIndex: u32) --- + sound_get_pinned_listener_index :: proc(pSound: ^sound) -> u32 --- + sound_get_listener_index :: proc(pSound: ^sound) -> u32 --- + sound_get_direction_to_listener :: proc(pSound: ^sound) -> vec3f --- + sound_set_position :: proc(pSound: ^sound, x, y, z: f32) --- + sound_get_position :: proc(pSound: ^sound) -> vec3f --- + sound_set_direction :: proc(pSound: ^sound, x, y, z: f32) --- + sound_get_direction :: proc(pSound: ^sound) -> vec3f --- + sound_set_velocity :: proc(pSound: ^sound, x, y, z: f32) --- + sound_get_velocity :: proc(pSound: ^sound) -> vec3f --- + sound_set_attenuation_model :: proc(pSound: ^sound, attenuationModel: attenuation_model) --- + sound_get_attenuation_model :: proc(pSound: ^sound) -> attenuation_model --- + sound_set_positioning :: proc(pSound: ^sound, positioning: positioning) --- + sound_get_positioning :: proc(pSound: ^sound) -> positioning --- + sound_set_rolloff :: proc(pSound: ^sound, rolloff: f32) --- + sound_get_rolloff :: proc(pSound: ^sound) -> f32 --- + sound_set_min_gain :: proc(pSound: ^sound, minGain: f32) --- + sound_get_min_gain :: proc(pSound: ^sound) -> f32 --- + sound_set_max_gain :: proc(pSound: ^sound, maxGain: f32) --- + sound_get_max_gain :: proc(pSound: ^sound) -> f32 --- + sound_set_min_distance :: proc(pSound: ^sound, minDistance: f32) --- + sound_get_min_distance :: proc(pSound: ^sound) -> f32 --- + sound_set_max_distance :: proc(pSound: ^sound, maxDistance: f32) --- + sound_get_max_distance :: proc(pSound: ^sound) -> f32 --- + sound_set_cone :: proc(pSound: ^sound, innerAngleInRadians, outerAngleInRadians, outerGain: f32) --- + sound_get_cone :: proc(pSound: ^sound, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) --- + sound_set_doppler_factor :: proc(pSound: ^sound, dopplerFactor: f32) --- + sound_get_doppler_factor :: proc(pSound: ^sound) -> f32 --- + sound_set_directional_attenuation_factor :: proc(pSound: ^sound, directionalAttenuationFactor: f32) --- + sound_get_directional_attenuation_factor :: proc(pSound: ^sound) -> f32 --- + sound_set_fade_in_pcm_frames :: proc(pSound: ^sound, volumeBeg, volumeEnd: f32, fadeLengthInFrames: u64) --- + sound_set_fade_in_milliseconds :: proc(pSound: ^sound, volumeBeg, volumeEnd: f32, fadeLengthInMilliseconds: u64) --- + sound_get_current_fade_volume :: proc(pSound: ^sound) -> f32 --- + sound_set_start_time_in_pcm_frames :: proc(pSound: ^sound, absoluteGlobalTimeInFrames: u64) --- + sound_set_start_time_in_milliseconds :: proc(pSound: ^sound, absoluteGlobalTimeInMilliseconds: u64) --- + sound_set_stop_time_in_pcm_frames :: proc(pSound: ^sound, absoluteGlobalTimeInFrames: u64) --- + sound_set_stop_time_in_milliseconds :: proc(pSound: ^sound, absoluteGlobalTimeInMilliseconds: u64) --- + sound_is_playing :: proc(pSound: ^sound) -> b32 --- + sound_get_time_in_pcm_frames :: proc(pSound: ^sound) -> u64 --- + sound_set_looping :: proc(pSound: ^sound, isLooping: b32) --- + sound_is_looping :: proc(pSound: ^sound) -> b32 --- + sound_at_end :: proc(pSound: ^sound) -> b32 --- + sound_seek_to_pcm_frame :: proc(pSound: ^sound, frameIndex: u64) -> result --- /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ + sound_get_data_format :: proc(pSound: ^sound, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: ^channel, channelMapCap: c.size_t) -> result --- + sound_get_cursor_in_pcm_frames :: proc(pSound: ^sound, pCursor: ^u64) -> result --- + sound_get_length_in_pcm_frames :: proc(pSound: ^sound, pLength: ^u64) -> result --- + sound_get_cursor_in_seconds :: proc(pSound: ^sound, pCursor: ^f32) -> result --- + sound_get_length_in_seconds :: proc(pSound: ^sound, pLength: ^f32) -> result --- +} + + +/* A sound group is just a sound. */ +sound_group_config :: distinct sound_config +sound_group :: distinct sound + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + sound_group_config_init :: proc() -> sound_group_config --- + + sound_group_init :: proc(pEngine: ^engine, flags: u32, pParentGroup, pGroup: ^sound_group) -> result --- + sound_group_init_ex :: proc(pEngine: ^engine, pConfig: ^sound_group_config, pGroup: ^sound_group) -> result --- + sound_group_uninit :: proc(pGroup: ^sound_group) --- + sound_group_get_engine :: proc(pGroup: ^sound_group) -> ^engine --- + sound_group_start :: proc(pGroup: ^sound_group) -> result --- + sound_group_stop :: proc(pGroup: ^sound_group) -> result --- + sound_group_set_volume :: proc(pGroup: ^sound_group, volume: f32) --- + sound_group_get_volume :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_pan :: proc(pGroup: ^sound_group, pan: f32) --- + sound_group_get_pan :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_pan_mode :: proc(pGroup: ^sound_group, panMode: pan_mode) --- + sound_group_get_pan_mode :: proc(pGroup: ^sound_group) -> pan_mode --- + sound_group_set_pitch :: proc(pGroup: ^sound_group, pitch: f32) --- + sound_group_get_pitch :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_spatialization_enabled :: proc(pGroup: ^sound_group, enabled: b32) --- + sound_group_is_spatialization_enabled :: proc(pGroup: ^sound_group) -> b32 --- + sound_group_set_pinned_listener_index :: proc(pGroup: ^sound_group, listenerIndex: u32) --- + sound_group_get_pinned_listener_index :: proc(pGroup: ^sound_group) -> u32 --- + sound_group_get_listener_index :: proc(pGroup: ^sound_group) -> u32 --- + sound_group_get_direction_to_listener :: proc(pGroup: ^sound_group) -> vec3f --- + sound_group_set_position :: proc(pGroup: ^sound_group, x, y, z: f32) --- + sound_group_get_position :: proc(pGroup: ^sound_group) -> vec3f --- + sound_group_set_direction :: proc(pGroup: ^sound_group, x, y, z: f32) --- + sound_group_get_direction :: proc(pGroup: ^sound_group) -> vec3f --- + sound_group_set_velocity :: proc(pGroup: ^sound_group, x, y, z: f32) --- + sound_group_get_velocity :: proc(pGroup: ^sound_group) -> vec3f --- + sound_group_set_attenuation_model :: proc(pGroup: ^sound_group, attenuationModel: attenuation_model) --- + sound_group_get_attenuation_model :: proc(pGroup: ^sound_group) -> attenuation_model --- + sound_group_set_positioning :: proc(pGroup: ^sound_group, positioning: positioning) --- + sound_group_get_positioning :: proc(pGroup: ^sound_group) -> positioning --- + sound_group_set_rolloff :: proc(pGroup: ^sound_group, rolloff: f32) --- + sound_group_get_rolloff :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_min_gain :: proc(pGroup: ^sound_group, minGain: f32) --- + sound_group_get_min_gain :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_max_gain :: proc(pGroup: ^sound_group, maxGain: f32) --- + sound_group_get_max_gain :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_min_distance :: proc(pGroup: ^sound_group, minDistance: f32) --- + sound_group_get_min_distance :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_max_distance :: proc(pGroup: ^sound_group, maxDistance: f32) --- + sound_group_get_max_distance :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_cone :: proc(pGroup: ^sound_group, innerAngleInRadians, outerAngleInRadians, outerGain: f32) --- + sound_group_get_cone :: proc(pGroup: ^sound_group, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) --- + sound_group_set_doppler_factor :: proc(pGroup: ^sound_group, dopplerFactor: f32) --- + sound_group_get_doppler_factor :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_directional_attenuation_factor :: proc(pGroup: ^sound_group, directionalAttenuationFactor: f32) --- + sound_group_get_directional_attenuation_factor :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_fade_in_pcm_frames :: proc(pGroup: ^sound_group, volumeBeg, volumeEnd: f32, fadeLengthInFrames: u64) --- + sound_group_set_fade_in_milliseconds :: proc(pGroup: ^sound_group, volumeBeg, volumeEnd: f32, fadeLengthInMilliseconds: u64) --- + sound_group_get_current_fade_volume :: proc(pGroup: ^sound_group) -> f32 --- + sound_group_set_start_time_in_pcm_frames :: proc(pGroup: ^sound_group, absoluteGlobalTimeInFrames: u64) --- + sound_group_set_start_time_in_milliseconds :: proc(pGroup: ^sound_group, absoluteGlobalTimeInMilliseconds: u64) --- + sound_group_set_stop_time_in_pcm_frames :: proc(pGroup: ^sound_group, absoluteGlobalTimeInFrames: u64) --- + sound_group_set_stop_time_in_milliseconds :: proc(pGroup: ^sound_group, absoluteGlobalTimeInMilliseconds: u64) --- + sound_group_is_playing :: proc(pGroup: ^sound_group) -> b32 --- + sound_group_get_time_in_pcm_frames :: proc(pGroup: ^sound_group) -> u64 --- +} + + +engine_config :: struct { + pResourceManager: ^resource_manager, /* Can be null in which case a resource manager will be created for you. */ + pContext: ^context_type, + pDevice: ^device, /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */ + pPlaybackDeviceID: ^device_id, /* The ID of the playback device to use with the default listener. */ + pLog: ^log, /* When set to NULL, will use the context's log. */ + listenerCount: u32, /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ + channels: u32, /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ + sampleRate: u32, /* The sample rate. When set to 0 will use the native channel count of the device. */ + periodSizeInFrames: u32, /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ + periodSizeInMilliseconds: u32, /* Used if periodSizeInFrames is unset. */ + gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ + gainSmoothTimeInMilliseconds: u32, /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */ + allocationCallbacks: allocation_callbacks, + noAutoStart: b32, /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */ + noDevice: b32, /* When set to true, don't create a default device. ma_engine_read_pcm_frames() can be called manually to read data. */ + monoExpansionMode: mono_expansion_mode, /* Controls how the mono channel should be expanded to other channels when spatialization is disabled on a sound. */ + pResourceManagerVFS: ^vfs, /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */ +} + +engine :: struct { + nodeGraph: node_graph, /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */ + pResourceManager: ^resource_manager, + pDevice: ^device, /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ + pLog: ^log, + sampleRate: u32, + listenerCount: u32, + listeners: [ENGINE_MAX_LISTENERS]spatializer_listener, + allocationCallbacks: allocation_callbacks, + ownsResourceManager: b8, + ownsDevice: b8, + inlinedSoundLock: spinlock, /* For synchronizing access so the inlined sound list. */ + pInlinedSoundHead: ^sound_inlined, /* The first inlined sound. Inlined sounds are tracked in a linked list. */ + inlinedSoundCount: u32, /*atomic*/ /* The total number of allocated inlined sound objects. Used for debugging. */ + gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. */ + monoExpansionMode: mono_expansion_mode, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + engine_config_init :: proc() -> engine_config --- + + engine_init :: proc(pConfig: ^engine_config, pEngine: ^engine) -> result --- + engine_uninit :: proc(pEngine: ^engine) --- + engine_read_pcm_frames :: proc(pEngine: ^engine, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + engine_get_node_graph :: proc(pEngine: ^engine) -> ^node_graph --- + engine_get_resource_manager :: proc(pEngine: ^engine) -> ^resource_manager --- + engine_get_device :: proc(pEngine: ^engine) -> ^device --- + engine_get_log :: proc(pEngine: ^engine) -> ^log --- + engine_get_endpoint :: proc(pEngine: ^engine) -> ^node --- + engine_get_time :: proc(pEngine: ^engine) -> u64 --- + engine_set_time :: proc(pEngine: ^engine, globalTime: u64) -> result --- + engine_get_channels :: proc(pEngine: ^engine) -> u32 --- + engine_get_sample_rate :: proc(pEngine: ^engine) -> u32 --- + + engine_start :: proc(pEngine: ^engine) -> result --- + engine_stop :: proc(pEngine: ^engine) -> result --- + engine_set_volume :: proc(pEngine: ^engine, volume: f32) -> result --- + engine_set_gain_db :: proc(pEngine: ^engine, gainDB: f32) -> result --- + + engine_get_listener_count :: proc(pEngine: ^engine) -> u32 --- + engine_find_closest_listener :: proc(pEngine: ^engine, absolutePosX, absolutePosY, absolutePosZ: f32) -> u32 --- + engine_listener_set_position :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) --- + engine_listener_get_position :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f --- + engine_listener_set_direction :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) --- + engine_listener_get_direction :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f --- + engine_listener_set_velocity :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) --- + engine_listener_get_velocity :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f --- + engine_listener_set_cone :: proc(pEngine: ^engine, listenerIndex: u32, innerAngleInRadians, outerAngleInRadians, outerGain: f32) --- + engine_listener_get_cone :: proc(pEngine: ^engine, listenerIndex: u32, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) --- + engine_listener_set_world_up :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) --- + engine_listener_get_world_up :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f --- + engine_listener_set_enabled :: proc(pEngine: ^engine, listenerIndex: u32, isEnabled: b32) --- + engine_listener_is_enabled :: proc(pEngine: ^engine, listenerIndex: u32) -> b32 --- + + engine_play_sound_ex :: proc(pEngine: ^engine, pFilePath: cstring, pNode: ^node, nodeInputBusIndex: u32) -> result --- + engine_play_sound :: proc(pEngine: ^engine, pFilePath: cstring, pGroup: ^sound_group) -> result --- /* Fire and forget. */ +} diff --git a/vendor/miniaudio/filtering.odin b/vendor/miniaudio/filtering.odin index 9949f6338..b8175c372 100644 --- a/vendor/miniaudio/filtering.odin +++ b/vendor/miniaudio/filtering.odin @@ -1,5 +1,7 @@ package miniaudio +import c "core:c/libc" + when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } else when ODIN_OS == .Linux { @@ -19,14 +21,14 @@ biquad_coefficient :: struct #raw_union { } biquad_config :: struct { - format: format, + format: format, channels: u32, - b0: f64, - b1: f64, - b2: f64, - a0: f64, - a1: f64, - a2: f64, + b0: f64, + b1: f64, + b2: f64, + a0: f64, + a1: f64, + a2: f64, } biquad :: struct { @@ -37,17 +39,25 @@ biquad :: struct { b2: biquad_coefficient, a1: biquad_coefficient, a2: biquad_coefficient, - r1: [MAX_CHANNELS]biquad_coefficient, - r2: [MAX_CHANNELS]biquad_coefficient, + pR1: ^biquad_coefficient, + pR2: ^biquad_coefficient, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } @(default_calling_convention="c", link_prefix="ma_") foreign lib { biquad_config_init :: proc(format: format, channels: u32, b0, b1, b2, a0, a1, a2: f64) -> biquad_config --- - biquad_init :: proc(pConfig: ^biquad_config, pBQ: ^biquad) -> result --- + biquad_get_heap_size :: proc(pConfig: ^biquad_config, pHeapSizeInBytes: ^c.size_t) -> result --- + biquad_init_preallocated :: proc(pConfig: ^biquad_config, pHeap: rawptr, pBQ: ^biquad) -> result --- + biquad_init :: proc(pConfig: ^biquad_config, pAllocationCallbacks: ^allocation_callbacks, pBQ: ^biquad) -> result --- + biquad_uninit :: proc(pBQ: ^biquad, pAllocationCallbacks: ^allocation_callbacks) --- biquad_reinit :: proc(pConfig: ^biquad_config, pBQ: ^biquad) -> result --- - biquad_process_pcm_frames :: proc(pBQ: ^biquad, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- + biquad_clear_cache :: proc(pBQ: ^biquad) -> result --- + biquad_process_pcm_frames :: proc(pBQ: ^biquad, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result --- biquad_get_latency :: proc(pBQ: ^biquad) -> u32 --- } @@ -70,7 +80,11 @@ lpf1 :: struct { format: format, channels: u32, a: biquad_coefficient, - r1: [MAX_CHANNELS]biquad_coefficient, + pR1: ^biquad_coefficient, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } lpf2 :: struct { @@ -91,8 +105,12 @@ lpf :: struct { sampleRate: u32, lpf1Count: u32, lpf2Count: u32, - lpf1: [1]lpf1, - lpf2: [MAX_FILTER_ORDER/2]lpf2, + pLPF1: ^lpf1, + pLPF2: ^lpf2, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } @@ -101,20 +119,32 @@ foreign lib { lpf1_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64) -> lpf1_config --- lpf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency, q: f64) -> lpf2_config --- - lpf1_init :: proc(pConfig: ^lpf1_config, pLPF: ^lpf1) -> result --- + lpf1_get_heap_size :: proc(pConfig: ^lpf1_config, pHeapSizeInBytes: ^c.size_t) -> result --- + lpf1_init_preallocated :: proc(pConfig: ^lpf1_config, pHeap: rawptr, pLPF: ^lpf1) -> result --- + lpf1_init :: proc(pConfig: ^lpf1_config, pAllocationCallbacks: ^allocation_callbacks, pLPF: ^lpf1) -> result --- + lpf1_uninit :: proc(pLPF: ^lpf1, pAllocationCallbacks: ^allocation_callbacks) --- lpf1_reinit :: proc(pConfig: ^lpf1_config, pLPF: ^lpf1) -> result --- + lpf1_clear_cache :: proc(pLPF: ^lpf1) -> result --- lpf1_process_pcm_frames :: proc(pLPF: ^lpf1, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- lpf1_get_latency :: proc(pLPF: ^lpf1) -> u32 --- - lpf2_init :: proc(pConfig: ^lpf2_config, pLPF: ^lpf2) -> result --- + lpf2_get_heap_size :: proc(pConfig: ^lpf2_config, pHeapSizeInBytes: ^c.size_t) -> result --- + lpf2_init_preallocated :: proc(pConfig: ^lpf2_config, pHeap: rawptr, pHPF: ^lpf2) -> result --- + lpf2_init :: proc(pConfig: ^lpf2_config, pAllocationCallbacks: ^allocation_callbacks, pLPF: ^lpf2) -> result --- + lpf2_uninit :: proc(pLPF: ^lpf2, pAllocationCallbacks: ^allocation_callbacks) --- lpf2_reinit :: proc(pConfig: ^lpf2_config, pLPF: ^lpf2) -> result --- + lpf2_clear_cache :: proc(pLPF: ^lpf2) -> result --- lpf2_process_pcm_frames :: proc(pLPF: ^lpf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- lpf2_get_latency :: proc(pLPF: ^lpf2) -> u32 --- lpf_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, order: u32) -> lpf_config --- - lpf_init :: proc(pConfig: ^lpf_config, pLPF: ^lpf) -> result --- + lpf_get_heap_size :: proc(pConfig: ^lpf_config, pHeapSizeInBytes: ^c.size_t) -> result --- + lpf_init_preallocated :: proc(pConfig: ^lpf_config, pHeap: rawptr, pLPF: ^lpf) -> result --- + lpf_init :: proc(pConfig: ^lpf_config, pAllocationCallbacks: ^allocation_callbacks, pLPF: ^lpf) -> result --- + lpf_uninit :: proc(pLPF: ^lpf, pAllocationCallbacks: ^allocation_callbacks) --- lpf_reinit :: proc(pConfig: ^lpf_config, pLPF: ^lpf) -> result --- + lpf_clear_cache :: proc(pLPF: ^lpf) -> result --- lpf_process_pcm_frames :: proc(pLPF: ^lpf, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- lpf_get_latency :: proc(pLPF: ^lpf) -> u32 --- } @@ -138,7 +168,11 @@ hpf1 :: struct { format: format, channels: u32, a: biquad_coefficient, - r1: [MAX_CHANNELS]biquad_coefficient, + pR1: ^biquad_coefficient, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } hpf2 :: struct { @@ -159,8 +193,12 @@ hpf :: struct { sampleRate: u32, hpf1Count: u32, hpf2Count: u32, - hpf1: [1]hpf1, - hpf2: [MAX_FILTER_ORDER/2]hpf2, + pHPF1: ^hpf1, + pHPF2: ^hpf2, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } @@ -169,19 +207,28 @@ foreign lib { hpf1_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64) -> hpf1_config --- hpf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency, q: f64) -> hpf2_config --- - hpf1_init :: proc(pConfig: ^hpf1_config, pHPF: ^hpf1) -> result --- + hpf1_get_heap_size :: proc(pConfig: ^hpf1_config, pHeapSizeInBytes: ^c.size_t) -> result --- + hpf1_init_preallocated :: proc(pConfig: ^hpf1_config, pHeap: rawptr, pLPF: ^hpf1) -> result --- + hpf1_init :: proc(pConfig: ^hpf1_config, pAllocationCallbacks: ^allocation_callbacks, pHPF: ^hpf1) -> result --- + hpf1_uninit :: proc(pHPF: ^hpf1, pAllocationCallbacks: ^allocation_callbacks) --- hpf1_reinit :: proc(pConfig: ^hpf1_config, pHPF: ^hpf1) -> result --- hpf1_process_pcm_frames :: proc(pHPF: ^hpf1, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- hpf1_get_latency :: proc(pHPF: ^hpf1) -> u32 --- - hpf2_init :: proc(pConfig: ^hpf2_config, pHPF: ^hpf2) -> result --- + hpf2_get_heap_size :: proc(pConfig: ^hpf2_config, pHeapSizeInBytes: ^c.size_t) -> result --- + hpf2_init_preallocated :: proc(pConfig: ^hpf2_config, pHeap: rawptr, pHPF: ^hpf2) -> result --- + hpf2_init :: proc(pConfig: ^hpf2_config, pAllocationCallbacks: ^allocation_callbacks, pHPF: ^hpf2) -> result --- + hpf2_uninit :: proc(pHPF: ^hpf2, pAllocationCallbacks: ^allocation_callbacks) --- hpf2_reinit :: proc(pConfig: ^hpf2_config, pHPF: ^hpf2) -> result --- hpf2_process_pcm_frames :: proc(pHPF: ^hpf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- hpf2_get_latency :: proc(pHPF: ^hpf2) -> u32 --- hpf_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, order: u32) -> hpf_config --- - hpf_init :: proc(pConfig: ^hpf_config, pHPF: ^hpf) -> result --- + hpf_get_heap_size :: proc(pConfig: ^hpf_config, pHeapSizeInBytes: ^c.size_t) -> result --- + hpf_init_preallocated :: proc(pConfig: ^hpf_config, pHeap: rawptr, pLPF: ^hpf) -> result --- + hpf_init :: proc(pConfig: ^hpf_config, pAllocationCallbacks: ^allocation_callbacks, pHPF: ^hpf) -> result --- + hpf_uninit :: proc(pHPF: ^hpf, pAllocationCallbacks: ^allocation_callbacks) --- hpf_reinit :: proc(pConfig: ^hpf_config, pHPF: ^hpf) -> result --- hpf_process_pcm_frames :: proc(pHPF: ^hpf, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- hpf_get_latency :: proc(pHPF: ^hpf) -> u32 --- @@ -217,21 +264,31 @@ bpf :: struct { format: format, channels: u32, bpf2Count: u32, - bpf2: [MAX_FILTER_ORDER/2]bpf2, + pBPF2: ^bpf2, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } @(default_calling_convention="c", link_prefix="ma_") foreign lib { bpf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, q: f64) -> bpf2_config --- - bpf2_init :: proc(pConfig: ^bpf2_config, pBPF: ^bpf2) -> result --- + bpf2_get_heap_size :: proc(pConfig: ^bpf2_config, pHeapSizeInBytes: ^c.size_t) -> result --- + bpf2_init_preallocated :: proc(pConfig: ^bpf2_config, pHeap: rawptr, pBPF: ^bpf2) -> result --- + bpf2_init :: proc(pConfig: ^bpf2_config, pAllocationCallbacks: ^allocation_callbacks, pBPF: ^bpf2) -> result --- + bpf2_uninit :: proc(pBPF: ^bpf2, pAllocationCallbacks: ^allocation_callbacks) --- bpf2_reinit :: proc(pConfig: ^bpf2_config, pBPF: ^bpf2) -> result --- bpf2_process_pcm_frames :: proc(pBPF: ^bpf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- bpf2_get_latency :: proc(pBPF: ^bpf2) -> u32 --- bpf_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, order: u32) -> bpf_config --- - bpf_init :: proc(pConfig: ^bpf_config, pBPF: ^bpf) -> result --- + bpf_get_heap_size :: proc(pConfig: ^bpf_config, pHeapSizeInBytes: ^c.size_t) -> result --- + bpf_init_preallocated :: proc(pConfig: ^bpf_config, pHeap: rawptr, pBPF: ^bpf) -> result --- + bpf_init :: proc(pConfig: ^bpf_config, pAllocationCallbacks: ^allocation_callbacks, pBPF: ^bpf) -> result --- + bpf_uninit :: proc(pBPF: ^bpf, pAllocationCallbacks: ^allocation_callbacks) --- bpf_reinit :: proc(pConfig: ^bpf_config, pBPF: ^bpf) -> result --- bpf_process_pcm_frames :: proc(pBPF: ^bpf, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- bpf_get_latency :: proc(pBPF: ^bpf) -> u32 --- @@ -260,7 +317,10 @@ notch2 :: struct { foreign lib { notch2_config_init :: proc(format: format, channels: u32, sampleRate: u32, q: f64, frequency: f64) -> notch2_config --- - notch2_init :: proc(pConfig: ^notch2_config, pFilter: ^notch2) -> result --- + notch2_get_heap_size :: proc(pConfig: ^notch2_config, pHeapSizeInBytes: ^c.size_t) -> result --- + notch2_init_preallocated :: proc(pConfig: ^notch2_config, pHeap: rawptr, pFilter: ^notch2) -> result --- + notch2_init :: proc(pConfig: ^notch2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^notch2) -> result --- + notch2_uninit :: proc(pFilter: ^notch2, pAllocationCallbacks: ^allocation_callbacks) --- notch2_reinit :: proc(pConfig: ^notch2_config, pFilter: ^notch2) -> result --- notch2_process_pcm_frames :: proc(pFilter: ^notch2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- notch2_get_latency :: proc(pFilter: ^notch2) -> u32 --- @@ -290,7 +350,10 @@ peak2 :: struct { foreign lib { peak2_config_init :: proc(format: format, channels: u32, sampleRate: u32, gainDB, q, frequency: f64) -> peak2_config --- - peak2_init :: proc(pConfig: ^peak2_config, pFilter: ^peak2) -> result --- + peak2_get_heap_size :: proc(pConfig: ^peak2_config, pHeapSizeInBytes: ^c.size_t) -> result --- + peak2_init_preallocated :: proc(pConfig: ^peak2_config, pHeap: rawptr, pFilter: ^peak2) -> result --- + peak2_init :: proc(pConfig: ^peak2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^peak2) -> result --- + peak2_uninit :: proc(pFilter: ^peak2, pAllocationCallbacks: ^allocation_callbacks) --- peak2_reinit :: proc(pConfig: ^peak2_config, pFilter: ^peak2) -> result --- peak2_process_pcm_frames :: proc(pFilter: ^peak2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- peak2_get_latency :: proc(pFilter: ^peak2) -> u32 --- @@ -320,7 +383,10 @@ loshelf2 :: struct { foreign lib { loshelf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, gainDB, shelfSlope, frequency: f64) -> loshelf2_config --- - loshelf2_init :: proc(pConfig: ^loshelf2_config, pFilter: ^loshelf2) -> result --- + loshelf2_get_heap_size :: proc(pConfig: ^loshelf2_config, pHeapSizeInBytes: ^c.size_t) -> result --- + loshelf2_init_preallocated :: proc(pConfig: ^loshelf2_config, pHeap: rawptr, pFilter: ^loshelf2) -> result --- + loshelf2_init :: proc(pConfig: ^loshelf2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^loshelf2) -> result --- + loshelf2_uninit :: proc(pFilter: ^loshelf2, pAllocationCallbacks: ^allocation_callbacks) --- loshelf2_reinit :: proc(pConfig: ^loshelf2_config, pFilter: ^loshelf2) -> result --- loshelf2_process_pcm_frames :: proc(pFilter: ^loshelf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- loshelf2_get_latency :: proc(pFilter: ^loshelf2) -> u32 --- @@ -350,7 +416,10 @@ hishelf2 :: struct { foreign lib { hishelf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, gainDB, shelfSlope, frequency: f64) -> hishelf2_config --- - hishelf2_init :: proc(pConfig: ^hishelf2_config, pFilter: ^hishelf2) -> result --- + hishelf2_get_heap_size :: proc(pConfig: ^hishelf2_config, pHeapSizeInBytes: ^c.size_t) -> result --- + hishelf2_init_preallocated :: proc(pConfig: ^hishelf2_config, pHeap: rawptr, pFilter: ^hishelf2) -> result --- + hishelf2_init :: proc(pConfig: ^hishelf2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^hishelf2) -> result --- + hishelf2_uninit :: proc(pFilter: ^hishelf2, pAllocationCallbacks: ^allocation_callbacks) --- hishelf2_reinit :: proc(pConfig: ^hishelf2_config, pFilter: ^hishelf2) -> result --- hishelf2_process_pcm_frames :: proc(pFilter: ^hishelf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result --- hishelf2_get_latency :: proc(pFilter: ^hishelf2) -> u32 --- diff --git a/vendor/miniaudio/generation.odin b/vendor/miniaudio/generation.odin index 97b7d453c..305090c7d 100644 --- a/vendor/miniaudio/generation.odin +++ b/vendor/miniaudio/generation.odin @@ -56,14 +56,18 @@ noise :: struct { lcg: lcg, state: struct #raw_union { pink: struct { - bin: [MAX_CHANNELS][16]f64, - accumulation: [MAX_CHANNELS]f64, - counter: [MAX_CHANNELS]u32, + bin: ^[^]f64, + accumulation: [^]f64, + counter: [^]u32, }, brownian: struct { - accumulation: [MAX_CHANNELS]f64, + accumulation: [^]f64, }, }, + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, } @(default_calling_convention="c", link_prefix="ma_") @@ -72,7 +76,7 @@ foreign lib { waveform_init :: proc(pConfig: ^waveform_config, pWaveform: ^waveform) -> result --- waveform_uninit :: proc(pWaveform: ^waveform) --- - waveform_read_pcm_frames :: proc(pWaveform: ^waveform, pFramesOut: rawptr, frameCount: u64) -> u64 --- + waveform_read_pcm_frames :: proc(pWaveform: ^waveform, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- waveform_seek_to_pcm_frame :: proc(pWaveform: ^waveform, frameIndex: u64) -> result --- waveform_set_amplitude :: proc(pWaveform: ^waveform, amplitude: f64) -> result --- waveform_set_frequency :: proc(pWaveform: ^waveform, frequency: f64) -> result --- @@ -81,10 +85,12 @@ foreign lib { noise_config_init :: proc(format: format, channels: u32, type: noise_type, seed: i32, amplitude: f64) -> noise_config --- - noise_init :: proc(pConfig: ^noise_config, pNoise: ^noise) -> result --- - noise_uninit :: proc(pNoise: ^noise) --- - noise_read_pcm_frames :: proc(pNoise: ^noise, pFramesOut: rawptr, frameCount: u64) -> u64 --- - noise_set_amplitude :: proc(pNoise: ^noise, amplitude: f64) -> result --- - noise_set_seed :: proc(pNoise: ^noise, seed: i32) -> result --- - noise_set_type :: proc(pNoise: ^noise, type: noise_type) -> result --- + noise_get_heap_size :: proc(pConfig: ^noise_config, pHeapSizeInBytes: ^c.size_t) -> result --- + noise_init_preallocated :: proc(pConfig: ^noise_config, pHeap: rawptr, pNoise: ^noise) -> result --- + noise_init :: proc(pConfig: ^noise_config, pAllocationCallbacks: ^allocation_callbacks, pNoise: ^noise) -> result --- + noise_uninit :: proc(pNoise: ^noise, pAllocationCallbacks: ^allocation_callbacks) --- + noise_read_pcm_frames :: proc(pNoise: ^noise, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + noise_set_amplitude :: proc(pNoise: ^noise, amplitude: f64) -> result --- + noise_set_seed :: proc(pNoise: ^noise, seed: i32) -> result --- + noise_set_type :: proc(pNoise: ^noise, type: noise_type) -> result --- } diff --git a/vendor/miniaudio/job_queue.odin b/vendor/miniaudio/job_queue.odin new file mode 100644 index 000000000..99899fdbd --- /dev/null +++ b/vendor/miniaudio/job_queue.odin @@ -0,0 +1,239 @@ +package miniaudio + +import c "core:c/libc" + +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} + +/* +Slot Allocator +-------------- +The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocator an index that can be used +as the insertion point for an object. + +Slots are reference counted to help mitigate the ABA problem in the lock-free queue we use for tracking jobs. + +The slot index is stored in the low 32 bits. The reference counter is stored in the high 32 bits: + + +-----------------+-----------------+ + | 32 Bits | 32 Bits | + +-----------------+-----------------+ + | Reference Count | Slot Index | + +-----------------+-----------------+ +*/ +slot_allocator_config :: struct { + capacity: u32, /* The number of slots to make available. */ +} + +slot_allocator_group :: struct { + bitfield: u32, /*atomic*/ /* Must be used atomically because the allocation and freeing routines need to make copies of this which must never be optimized away by the compiler. */ +} + +slot_allocator :: struct { + pGroups: [^]slot_allocator_group, /* Slots are grouped in chunks of 32. */ + pSlots: [^]u32, /* 32 bits for reference counting for ABA mitigation. */ + count: u32, /* Allocation count. */ + capacity: u32, + + /* Memory management. */ + _ownsHeap: b32, + _pHeap: rawptr, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + slot_allocator_config_init :: proc(capacity: u32) -> slot_allocator_config --- + + slot_allocator_get_heap_size :: proc(pConfig: ^slot_allocator_config, pHeapSizeInBytes: ^c.size_t) -> result --- + slot_allocator_init_preallocated :: proc(pConfig: ^slot_allocator_config, pHeap: rawptr, pAllocator: ^slot_allocator) -> result --- + slot_allocator_init :: proc(pConfig: ^slot_allocator_config, pAllocationCallbacks: ^allocation_callbacks, pAllocator: ^slot_allocator) -> result --- + slot_allocator_uninit :: proc(pAllocator: ^slot_allocator, pAllocationCallbacks: ^allocation_callbacks) --- + slot_allocator_alloc :: proc(pAllocator: ^slot_allocator, pSlot: ^u64) -> result --- + slot_allocator_free :: proc(pAllocator: ^slot_allocator, slot: u64) -> result --- +} + +/* +Callback for processing a job. Each job type will have their own processing callback which will be +called by ma_job_process(). +*/ +job_proc :: proc "c" (pJob: ^job) + +/* When a job type is added here an callback needs to be added go "g_jobVTable" in the implementation section. */ +job_type :: enum c.int { + /* Miscellaneous. */ + QUIT = 0, + CUSTOM, + + /* Resource Manager. */ + RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE, + RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE, + RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE, + RESOURCE_MANAGER_LOAD_DATA_BUFFER, + RESOURCE_MANAGER_FREE_DATA_BUFFER, + RESOURCE_MANAGER_LOAD_DATA_STREAM, + RESOURCE_MANAGER_FREE_DATA_STREAM, + RESOURCE_MANAGER_PAGE_DATA_STREAM, + RESOURCE_MANAGER_SEEK_DATA_STREAM, + + /* Device. */ + DEVICE_AAUDIO_REROUTE, + + /* Count. Must always be last. */ + COUNT, +} + +job :: struct { + toc: struct #raw_union { /* 8 bytes. We encode the job code into the slot allocation data to save space. */ + breakup: struct { + code: u16, /* Job type. */ + slot: u16, /* Index into a ma_slot_allocator. */ + refcount: u32, + }, + allocation: u64, + }, + next: u64, /*atomic*/ /* refcount + slot for the next item. Does not include the job code. */ + order: u32, /* Execution order. Used to create a data dependency and ensure a job is executed in order. Usage is contextual depending on the job type. */ + + data: struct #raw_union { + /* Miscellaneous. */ + custom: struct { + proc_: job_proc, + data0: uintptr, + data1: uintptr, + }, + + /* Resource Manager */ + resourceManager: struct #raw_union { + loadDataBufferNode: struct { + pResourceManager: rawptr /*ma_resource_manager**/, + pDataBufferNode: rawptr /*ma_resource_manager_data_buffer_node**/, + pFilePath: cstring, + pFilePathW: [^]c.wchar_t, + flags: u32, /* Resource manager data source flags that were used when initializing the data buffer. */ + pInitNotification: ^async_notification, /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */ + pDoneNotification: ^async_notification, /* Signalled when the data buffer has been fully decoded. Will be passed through to MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE when decoding. */ + pInitFence: ^fence, /* Released when initialization of the decoder is complete. */ + pDoneFence: ^fence, /* Released if initialization of the decoder fails. Passed through to PAGE_DATA_BUFFER_NODE untouched if init is successful. */ + }, + freeDataBufferNode: struct { + pResourceManager: rawptr /*ma_resource_manager**/, + pDataBufferNode: rawptr /*ma_resource_manager_data_buffer_node**/, + pDoneNotification: ^async_notification, + pDoneFence: ^fence, + }, + pageDataBufferNode: struct { + pResourceManager: rawptr /*ma_resource_manager**/, + pDataBufferNode: rawptr /*ma_resource_manager_data_buffer_node**/, + pDecoder: rawptr /*ma_decoder**/, + pDoneNotification: ^async_notification, /* Signalled when the data buffer has been fully decoded. */ + pDoneFence: ^fence, /* Passed through from LOAD_DATA_BUFFER_NODE and released when the data buffer completes decoding or an error occurs. */ + }, + + loadDataBuffer: struct { + pDataBuffer: rawptr /*ma_resource_manager_data_buffer**/, + pInitNotification: ^async_notification, /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */ + pDoneNotification: ^async_notification, /* Signalled when the data buffer has been fully decoded. */ + pInitFence: ^fence, /* Released when the data buffer has been initialized and the format/channels/rate can be retrieved. */ + pDoneFence: ^fence, /* Released when the data buffer has been fully decoded. */ + rangeBegInPCMFrames: u64, + rangeEndInPCMFrames: u64, + loopPointBegInPCMFrames: u64, + loopPointEndInPCMFrames: u64, + isLooping: u32, + }, + freeDataBuffer: struct { + pDataBuffer: rawptr /*ma_resource_manager_data_buffer**/, + pDoneNotification: ^async_notification, + pDoneFence: ^fence, + }, + + loadDataStream: struct { + pDataStream: rawptr /*ma_resource_manager_data_stream**/, + pFilePath: cstring, /* Allocated when the job is posted, freed by the job thread after loading. */ + pFilePathW: [^]c.wchar_t, /* ^ As above ^. Only used if pFilePath is NULL. */ + initialSeekPoint: u64, + pInitNotification: ^async_notification, /* Signalled after the first two pages have been decoded and frames can be read from the stream. */ + pInitFence: ^fence, + }, + freeDataStream: struct { + pDataStream: rawptr /*ma_resource_manager_data_stream**/, + pDoneNotification: ^async_notification, + pDoneFence: ^fence, + }, + pageDataStream: struct { + pDataStream: rawptr /*ma_resource_manager_data_stream**/, + pageIndex: u32, /* The index of the page to decode into. */ + }, + seekDataStream: struct { + pDataStream: rawptr /*ma_resource_manager_data_stream**/, + frameIndex: u64, + }, + }, + + /* Device. */ + device: struct #raw_union { + aaudio: struct #raw_union { + reroute: struct { + pDevice: rawptr /*ma_device**/, + deviceType: u32 /*ma_device_type*/, + }, + }, + }, + }, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + job_init :: proc(code: u16) -> job --- + job_process :: proc(pJob: ^job) -> result --- +} + + +/* +When set, ma_job_queue_next() will not wait and no semaphore will be signaled in +ma_job_queue_post(). ma_job_queue_next() will return MA_NO_DATA_AVAILABLE if nothing is available. + +This flag should always be used for platforms that do not support multithreading. +*/ +job_queue_flags :: enum c.int { + NON_BLOCKING = 0x00000001, +} + +job_queue_config :: struct { + flags: u32, + capacity: u32, /* The maximum number of jobs that can fit in the queue at a time. */ +} + +USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE :: false + +job_queue :: struct { + flags: u32, /* Flags passed in at initialization time. */ + capacity: u32, /* The maximum number of jobs that can fit in the queue at a time. Set by the config. */ + head: u64, /*atomic*/ /* The first item in the list. Required for removing from the top of the list. */ + tail: u64, /*atomic*/ /* The last item in the list. Required for appending to the end of the list. */ + sem: (struct {} when NO_THREADING else semaphore), /* Only used when MA_JOB_QUEUE_FLAG_NON_BLOCKING is unset. */ + allocator: slot_allocator, + pJobs: [^]job, + lock: (struct {} when USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE else spinlock), + + /* Memory management. */ + _pHeap: rawptr, + _ownsHeap: b32, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + job_queue_config_init :: proc(flags, capacity: u32) -> job_queue_config --- + + job_queue_get_heap_size :: proc(pConfig: ^job_queue_config, pHeapSizeInBytes: ^c.size_t) -> result --- + job_queue_init_preallocated :: proc(pConfig: ^job_queue_config, pHeap: rawptr, pQueue: ^job_queue) -> result --- + job_queue_init :: proc(pConfig: ^job_queue_config, pAllocationCallbacks: ^allocation_callbacks, pQueue: ^job_queue) -> result --- + job_queue_uninit :: proc(pQueue: ^job_queue, pAllocationCallbacks: ^allocation_callbacks) --- + job_queue_post :: proc(pQueue: ^job_queue, pJob: ^job) -> result --- + job_queue_next :: proc(pQueue: ^job_queue, pJob: ^job) -> result --- /* Returns MA_CANCELLED if the next job is a quit job. */ +} diff --git a/vendor/miniaudio/lib/miniaudio.lib b/vendor/miniaudio/lib/miniaudio.lib index 3d7c8327f6b3432b3c9fc8054061d0b9dc5c07c8..400cb9608cb9090e57467eb2fc0beb292eb2f139 100644 GIT binary patch literal 2767136 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%0Ar_2;=kL}#vW|1GF*Wp$YtK_8X#DH^ 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ξ@;HA>VBS|}aeS=Uv|xfq=-J1<7wbuc%p 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

aEt++c2PL-egrh%C38M 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 z z_GTUowQe~p=;cO0kEXHTcW`SyyI5eT^`EoMs}%G5y=v7G3kmIfKj34!eS}()`L#_L;>^dynpnZ3> zVqWoP9t^b}P^(DmwV~C@Cl(lLJ*4BR*{Ei5wHk>9hFXuPwJcZQ3AF;n0z<9Gux5WfsP%?gS8C^+sjb&yfuYu0Saxj$MyQ-qtytH*nFm9ychsubxS-Ej z&MOueYQ1-s*`sb2tGu$VTO0Mo0z<72&N6$H`5rp8{uT=iwLZGzGOcu1izlq*S{uXy zL#W378q*% zbS-n1?+@CMMXi6t0z<8UpoOb{{}pG>pg^_OiUo#R!C=`nzbb0tbZQ+H3k!Mcd8{UcnL#w{Qe zs1*s8?;NTXkF!EHKoH0n5(e(mk&dsC8H@Fw}}ktuMvy zcTnqrSYW6Xi&`Par)a2F$Xnj|0z<9X)Y^9J!56iXiv@;SaemP%EEX7Q#iiDm79l=s ztASWxs1*-Z&<|W+=JlakeZ>Mpt@zZcyQ;?uwWf;&hFS@nW!FXsw>CD51%_G)on_aC zT9?EEL#;%xeAk9r@5KT`t;EzaYeTJA|9NK_47HL_%d8Exa*73pT1ly8)`nWu#R5aE zWWQ*26AKKrl2gm94Q)*p3kh@+y;xwV^&7R`%~^X-tthv>^96=lshwrkVX70gQ^j}xmYqf{Fw{!pEVB;H-_fg8 zUMw)wN((FK2Ohgt-yb;I{hmVyvA|F(9kq%Ksh(S{31WevR(e==&4<3S{-#E{g?*S{Y&4_sjY7)NZQQH?hD_D-*S*T{u@*t)zFn^96=lnd!J%XH4Ee zt>R*Vp;i`ZbshWr0kv9+1%_H#VFmrbnqSpE_!zZDi3NsQ*{F5?#nSO=trZIlwX(aG zSsWwQHP183t&Q_yfuU9oYW1snVyIeA!~#RDoUrV_1so0?@KCLvVu7JnE^4*;mZYj$ zvG0243k=C35w+AJ0r zY89l`n16R3QR|FYV5n7yTIR1L)OsQo7-|)!R>&HsI;s`op0_r@P^-ub`fD!BDF#wYF8NmR_yYVu7JnIav0%8r{j9Q>`*$fuUA;YTbEIxR_dP z!~#RD3b2BH{6EJvS}ZWs`h!~eJ2zgftu*ivGYmUtp+Jg<7+Em&v474za*ct12w}8X#fD+#}Vh zAr=^FRioB`i3_%>)l)1m)T$0E=m*YMr*Vm=s5Mdf|SYW7C6IN1b z#e8ca~9f%7%uMGK!fTrL(EYBiu%;!+R4XzPSn zV5rs5SwXpg2k9Q%3VIu0{?DMtE3v>(tC6$J>v{8O{A$H`wymUEy~F}Ttv1xUc{c4SwPuM0hFWc@)%M!{%4+Qq3kNoi_r(H3t@hOV(y>NTwW2)nW*!W+I{3Bjx>g>sz)-6rweD7JQAVw% zVu7JnCu+sdIVjzA*BUDp7;1HkSVA*}6ZIh=h)v7HP7;1H=R>;4;wpVM6SYW8tgIZ%=HeRjPKC!@1 zt0%QGq^UJStxsZsp;j+gK|gRUKbpMql3E#`d9wkATD_^&H$*{2h0LVu7L77{8WUU&R7Lt+BAo>NSt;c{<)2;96;4c{2}&TH~m-EXKV~YSk4B z47J8n>&wNMMP|9yD6zm$YXY^*ckHUQO)N0fn&?{Q6>O95^`EKrSS&EqnnbPnzfU=$ zR=n5VY=EKGWLQBzaHW{ppI&;F@9G6Z zBb*A$+~G8jYz1B%p5|tLnY6&r2&d5qgC|Y-RIS@$fuRvjhZWvS1%$eAqn&5@jt~ru za0V>94$bca%y1)&`^KAjFf_uMG{T>$dRJ7didbN1gtK7T9pLjnarS$b?+C%r2xrp> z%a7~+qOTj_NNItg5ze6z7MOS^K&^dZfuYu1*D|X&;URw+?&qj|%mx^m!}YN2x4aE5f9ASc z!9IA$3x-Cx0hZY_%;R#+mx(>gcQ(M#2sgqq_bSa})W3@Zx497(kQNvk;s0oa;eV`+ zr&c?$z)))wEc8D!b#R5aE9k7Ca{6ELF zS1d5p+DWZ&#f~S^)?2Z_(2Cjx%f8;2@~rnp&+=VSU}%K9VfnsV-s)CV%1_=Lf}s)a zp%F&ddUSt-XG&?XJ~NEHKpC=hsqerC4C7wI5c{4?I3?9Y5-jYh4u!47CnW zYj(Aw5!4Fz*_#b8)H(>uuBd-z*Q}~mZn3~n>kzf#mR>kRtrlW|q1ItoK|ipfI`53N zPOT|ofuYtBYK_Zvy}nw9!~#Pr>L{#`GKa-(X1(HBzAFk0jqn&O`?pK24-Tlf$Ibjl zX@Q{;9;XpTfB3MuTA9CiGY^JZCt%r`A2s!Ub+wv{1%_HDskJIZ*O+R}5ep2pPPyYU zyLOGK!@sF@Su8NrI!&#Om-Yu&E817@xWG{B3>{ap3;_exDk~NkYMrIlif%&+sWn(E zFw{B+E9eJSRP6#2x2d&VEHKnMPp!IzGS5-#y;xwVb%9z%9;aBPR;F*>Y=EKGMQV*n z)IYjfEyMyttxMGU5ozr$wdRTihFX`YRibz5NNQaX3k+Q;S761KD3k;3$I;`k2!hXkk4)HAC5rUx+ z-hgGUFFc;C{qKKnghQnThDLakMz~Qst?mR-T{U zY=EKGLu&o6>yaC3^%e^ZwH{Gx)0c72)Y>i<7-~KKMeB!HV5s$kT3KH_c(1L(0p3aj zL#?NEO23Q5w!-11%_JBsFfgNi(6{#7YhunsOPY}84d_|cBI(|&+=VSV90tw zmU$<&7c0uw0z=kIvdlZFgMJnmvR;v8KHYt%p9O}j*Rbp>hXKvnh1%d}fuWgy11so< zyOx*0GXFDlFzWE(Ahl-Y)v)vCnypvkj!~#RD z@6m18KHTs91{7^0ypzBqy>gX7#xwa$qJhFT$D+24

zMJ_M(gH&x3`Zke+qA$fwK9kD#sG#! z7#@~=y|Fp+#}S_8J3=rt!U(YJ>kaeSEDPNTJ4g!*jW8mO(0q@oT5H7uLnDj?%RYZa zS+rxbXZem03|Wz3*_jVByz|Lb7@@BPhO8*ms=V?1yET3m7_y>LtI(G5ZAKIHGFw}}k ztuUhsZMo`N#l!+btyt8G{PMwmwK|FghFY5?DKNTj~UanaIH&XfuUABYJJ!6O7*dbbwm%!+0|fhFS@z z)n&roK(z{p1%_G)VcF-D_~~y&SF4d&V5pUdTCbNq8miV{vA|F(F)TZWyE{xN+1$*DXhvwNq zt*>H%p;iiNtw{ZGy;{-2dS@97wNg6ET)lm7&z?Qh&0%V>z)&ldv&?M7S$8a)S_Q=d zL#^Ln*?q&jLoDN3)x-irt<=;qpPHyvcd@`wD-A5W=HKM+*;1`3Vu7JnT54TRoVm7I zTg3uHt#s6ibuqzGwQh(7hFa;V_4GodV`>G2^UfC-YGr`s)<)2$3#yeuEHKo{NUga^ z&Q({dq*!36l?j$TU)djr8dSlZuU2A#p;l&UnNL4cYou6UsFeklechYjO|^MytrQCk zwX#yHL8|`+sC7y#Fx1LMt-e1OO;qcRSYW7?omzQ|#BHKhtnl9X0z<7FuQ zwepAshFUqPRVv4u*=p4l3kDvB1y>^V0~UB|I3> zvwTMghDP|iYnlD9%I7Sp2DlN%h~S-NFf_sf&NBPq$~@<{s+CtPFw`mt%dYvO4=d+W ztASWxs8xts`yOQKqt;Ndz)-6&EV~X1pB)@Rt(9Vdp;i%Ubsq9`s#@p70z)%j6qbFp z{Ac5~2|deq=E0CvjI0_{+s3GYnfJB8kX4+l;aAR18R%z$A*%#g=FU+ z_uu}5{46kJl_Kluy&LW7`dMJeDh>KMM@4!}74~zwGZ{)MQIzSmtW`A}b0Et-}hi?0bh}p$D~9D^^7B zssux=KVaGCudknzv}xvAnZ*J_t%}q#-*=-{d9lDys}d}GEwA2JBAQw)#R5aE%G7!k zdFLaw0>uJDtt!+CKJlOGYAqBC47I9K>%#QgA=TO|78q((gJt&(^Bpv5{U;U}YE`FJ z)qAB1sr5rFFx0Byj?1iuTcH~k{?nbWgps_n42D`Ysdc8v^LlC(6$=ctYQeIv59_6W z^gyi^Vu7JnZE9sqnX#@~W5fbOtvc?w%=Mh3Zt@ChZ4?U(wdzub^t?GV_5c?$ULVs^4p`pko6~7hlZXT+|#pai3NsQ&0yKP-#Zc==$zfPUWf&TTFt3t?&_-* zC5pE;z)-6NEW5Lf*b}*#TA9THL#>w7s&MPkdbKKx1%_I!VA<81=f^)I)aoJ@7;3eq zR)a~e)~PjFEHKn+<1Dk=n0LOp+#GHa3kz+5DXnxM>?+GzqdW3Rtex^-jhY7K;C|4l06t-#r8Wfuz!wFXgZNy3jG)T$&F7-|isRLaoXXnuSwqgjisxH58WJ=T8?n6+x{fVu7JnAhpu$pVdXJ{bGTk)-Y$8 zwP8L#s=Pa2x5WZOt>MlxYvbLqS}D}}DHa%N{p~E%n$T|A!V0dHFot)Q!BA_2vrMaE zoAqzi$|n{WYK??t_rnC0)_hm1rdVL8HHumf|Bkdkt?puhq1I?v_IxcEc(1Hllf?o< ztufTf676FMwKj+ahFW7``96Q8a_<7pi3NsQF3-A6tzu$ws8bs5Q-5 z=6v0WIB|9wcfM|k1%_JFon@{sb9YXyFJghA)(lwo`WkcRP+GNO#`4w%7;4R=R`e^k z2CJ1tEHKoXMXf2tnif&3yjWnUHJe&X{+M%At(Ibeq1GH~9X>tBr!_<@Fw~k$ty4*h z__XGV1%_JlVA-`%ZsFlBI>PN@fuYuXYDIWDt%O>a#R5aE1=RYHeRw{#-iZZ>+r zy;rR|Vu7L7zp(7}W%gdRx{3vcTI;A~_FlEdhy{jP>z!rJm)Uz)yYsbFEHKpC;4HiM zs1&o2g~?UbV7{ z1%_H%sAcwEwJL}OhFV*xW%gdRT8RaQTH9dRwPE&NwT6lXhFaUHW%gdR=7|M{T05v^ z_FlDihy{jPJE>*%UbU`>1%_I?VA-`{_FlE#iv@;SyQyXNUbUjd^Ug9DYVD!pGJCID z8N~uat-aJTd#_q$!~#RDeXxA@-WKk?Lo>0!P-{Q6%-*ZkP_e*J>i{e>hvsqU+41Zx zU2CCOV5oJFS`o$-Jgn9ZvA|I4kZYM8;LMZdkJP##78q(BrdHoasg|krQYt*by6!_eD5rSq1I7q1ur_Jp;{@#0z<81bX*Bq#+{&60kObP>o~RgWUf>}t(szi zq1K6C99Ji?z)}fyU(k&TP!ft zIs?mI%X|7QYNys!vA|I4EVc6P9XC_04`P9#);Vfzua&-mTG11DYXc0m&Qt4s;Q8fh zWfBVvwJyN2>+nLFL#fm%D;5}PU8Gi`k86EK*jy|y)Vf5+)h=WAwAvaZ78q(>rq+n- zj}NFdTP!ftxs<+~p)aIKtTfuYt-YMK2|tx95nq1G+eviqT0t;GUEt^cTH_CvJ- z#R5aE+pz39H2a}i^Th%~tvl2*`=MGp#R5aEyL4P;KUC|gSYW7ik6LCwRO^FSV5oKf z7snMnk$0BCQ0oD;%zmh?Ok#nd)q}=&XtrlW| zq1IzqNrMbywMtR^gj$2e0z<7Q)S7f_XHm80i3NsQPhr`;cT}2F?bX^P78q(hqt<{W z;rpp|Lo6`VdhV>C!@_;hMQ#qiiUo#RFPvp&!`v5DD{f-%EQ6ueOFAxdUsSCeVu7L7 zD{7hhqH0wU3kkYNceNnZ>hy{jPZ(;fFhsE7*!mkty47J`- zYv1MAv(-8w78q*1hh_J}f={E4E8$wt#R5aE57g@NXkVaOVUl>~3k|I#Wt&LA&fuUAF(4S=M_kWrFP_39ry|n>`TESqY4C-Fre<<;se78q(pa>r%PSG=kxo(6ZV$zp+_ zR%B|Wx>!es&xs>YRwZ147K9G$`E82E9ud69o5<;78q*9rB=xy(eA2s zODr(diU-T?Q4#x9Tcp-cvA|F(KD8=^4UDZ;k`&%q21Bg`&I&p#>`@`z92OD_47CzE z%kEKXH4qC7wGz>BnLSFazG8u)R$^+IJxZ;aVu7Jn5?FQ}nmtOb?P7tUR#Ix2JxZ``hZP3fI4Fw{!nj?4Vl%^o$6$=ctexsJzqtu!%78q)!rk2^G)Y>c-7;2@Vmf54!x+oSH zYNdr`*M`}n)Osft7;2@Xmf54!ik`|lUtp+}-dW~+nLTQhJ6~DE0z<6~&a!)yS{20t zL#>RkeD^4|+KB~*TA8S2_9(SRiv@;SnPK_vQEIIc3k>j07#NWL01%_JL>A1`urB*tzz)&j(wagx+R#~yYP%9@ayAI7B zrB-XPz)&j}wagx+)(Ek{P%Aeq-#u!i`#sp@Vu7Jn9%`A-kyh)tSYW7?7gkbpvVtCo zN>q6_*0r9C1%_JrsP$pjq$p~IP3@g8Fx1NLEYmV;W1?#%7Yhuves`8#8)_923k!ZhAl21Bjl)Y^M^$WygS zhy{jPC1Ba-uVwqj6jiI8SYW7Cl3Kk!uMMZx6tTcis}wAIzA`00S4FKoVu7JnX=)W% zbz`JjPsIX5tul06$A{mjq*ko7-W-CVR#|GbZ5n->T7|>{L#=YZIIdP=fuUA;YK5-- zzjNA}C>9uMRd6k{HdZW6R3)`r8#}}TL#;okHM{@+TB>zLEHKon2+Ll}7qT4OtJXWQ zz)-6awPrR?H%qN(>AaZ-L#@j0xXfx-P+YCsVu7JnEo$Z5{&KZi0qMQ-1%_I+sWmXnnA&P35ep2p>QJlQ zgCr}|Dkv5hYSo2h_l+wxHpfw`zF1(WRgYQ~cZChDR$sBeP^&(*zTW-#POTYYfuU9d zYRztb>8@H^#R5aEhSWOrI__e%u80MOT8*fcH`ScdYJCz547D1=GWQS7-`+e}-)C$r zx8~zy@Xj(AYW+#ATvLm;Q7e;JVCb)Pn!rjN)G?2G-K!n&EZ@KJ0Yf8f3d=sjUW%1v zUT!zS;?e>`BWy+^9F}6nBDLy^1%_J9Vc9F?_P4~T)aoV{7;3ekRl*)H~JcB^DTJb)r^;3yHd_HBl@u)ane&?rd$298aj$DzU&&s|&T_ zU+57{twUmgp{uehEc@Lb@ynJt;aR>{B^a{0!Selky_mQveJwC#btlXG-Dq|{3k=Oh z4_I~wFrSK()9nDa<+#AmZ1jX>|86v1{fsBn`YaY0YW4DK<#Mg4nY`5thFZP-T56>h z3k zVcD4<+$8e$Y;J_zr3HpY_!o^Zpnt-JYE2Rg47CQpvU~4}Cbd7P^{-f9s5OvU)dn@| zs@7?-z)))twZdc{u}-a*Vu7L7U~1hOd3Ls1ku!U10}Rdl5LkBRf9wt2%CmfD9t@3e zsB4+EQKU}Z!V%oeXOtEg8eyQb%xlpvb>!esEW3JNzlmNduA9T8 zS-kTFhFYVj_57c1FVre678q)c_G`s)tqx*=q1G5`B^}x6l3G*60z<8_eyw<}wOcGO z)EY-Eb6jdY5(^Bq#{0G6yH=E}-W-CV)&y!z9yckZTDipnL#>Ih?0z`l)a>S2T&sat zV5l{TTISR0)aox57-~(1Wp|q-HFmU8YnE7GsPzxE#_inoOs$<_fuYtESoU7Z{IY-6 zQR|jiV5l{fS}XeJIImVfHgD#^P-_|;*R1!as;ZStEHKoXPOa5Bi*{10s90dAH3OEt zmP<`)(oU@=Vu7L7OllQq-|neeL&O3@tyy$j)sM_Ltkxp2z))*8wc7s~bDLTR#R5aE zIk4>SRD8&^bi7&*#R5aExztKEU|$Bc!e;l*7Z_^IgJt*L`DtbjR4c7mV5l{pT8;BO zucTI4vA|Gk0W5pI%%>)*)kZ8Z)LKZbw^b@mP;0bUVCY$I5iI*X2%)3C{_a`6&w5~J zgo|OBtI|By7oOYVPxlw`YorB+M!1AVST<&xpK6^F3k)_~ouhl9q78q)+bS?85;O@n%gVky-78q)+ zqSo4qYa**PNGveaS`Evt-bQ(fk5_B9SYW8NhFX`d*Se+FRm=89nJ0 zwPNP-&N3KkZHHxFIh37RaDrOt#R5aE9n@;MeNh6nii-t?T05z=w7}MkYSkAD47GMq zt8d{sqt)sz78q*nhGnniv!UakQ){ePV5qf+T9-T5rVyL#+eUN;79+RJ9`J_SOa%Y8|B3xaEg) zsFg}AFw{Ckt^1eG&QhzOSYW7im|8<>yqT|7O|igG>jzt zky?L?1%_J3sMRN4@%L)Y7YhuvjyucjQD3GGcs#^i%iF{PL#-3eGS7Nz|2VQ;t+Qf* zp;svdl|y-!@2eCrWSxR#-_e`zPZ^34`dVPvyrhQ0qJ_ zdwtzJoA#7iwZ#HMtqasz9AkbpwYrN1hGzaEEIaeT>NR=bS-vw5hOA3unY)gu{LU8` zvM&2sz5FaNWL+W4d;)3`KMM?5SIIKpQrgeY0z=j{KdXhG1%|BaWSLJ|>*;5KA?pTN z=JQ|^`&nRUZQO)qpO?)i{>6c1u7HVhmch{4xCP7Jxy4-(XKfM-42|$V8ljnaujRWo zz|aV9yOtSK{;KsKM{}*K(gH&xyyGm~XX{uasam1(dRHYFYTbopugbw!cZF0dvshrL zb&pzi7cF?8R$Z~cQ0qRmGLL9mSgm1VfuYs|YUMsN!H3!uwfZ$oftrG{@E6&jLf%53=4z3OhQ6p9O}jpJbUbUzCWS;5E}`>u7zzx*sPWCbT{-Ia(3`}pP^ zEYlj`XMrIr6fFC_OC|4?D%sr60z+14YMIYzPvK{QAu9}7H;e2X(#g*PLsnR_%%|2j z^RvK^6^<;^3gc&iAuBvt<~3U@KMM>!e?@?0@1~~AU*kq(SmtV*AkRc#==m!mEc@zf z=dJA5)mkqW7-~g=W$zxOyE-nETIa+9L#@cv8kVrxC$-*-1%_HtVA*#ZRdP0MrdFK% z-fI9b)QU>28E?W@Q7f-lV5k)hmVIqwzTqXJo5Q+dfuUA(YMFO!Y7G?&47Fmwvab)5 zhkn;at<_?Ip;k<4{oNpWezmTM1%_I&s5PcW>db0|{N0;FFw}}ot>k47o=_{ZSYW6X z2bNtMQ@*9Es#YDbz)&kLwMHe_RZOj+Vu7JnJZhb4G4`%nYsCUXt@zaX_g;-cYF!fx z47C!#vTGyv!lNZ4xwR3xfH#L=sFjdfW^JgIQ7kajN(9TUjb%q>d{nEdSYW7?m|A9S zsMSX-Fw{yytx(fSuUBh$)!|D11X6%z{#wNg^+Qr#Mf)oLRa7;2@WR*7&md}e;4SYW928@1wGxiL{& z+r$Dxt<VTy9D<=%T3B|?SKZLBZfv*abBYCqTIr}| z*1THv!~#RD^mJVFt9F>H)*!LKP%8tq%$iqgxmaMRm62MJLu|jN)>*N@P%9I)%$is0 zi&$W&l^K>@hjEtuJ5{aZg}s>vL#-^-YMtm^GquW!1%_H#sZ}vs%rt6s77GluvQevc z>82ainl2U?YGsFIo|nzT{OeLdw>I{Q1%_HVsFk~2m3V616blTsa>BB&Z65dEvZ9b{ zeHIH0wQ^Cbai=`R)rwohn|Uzw>MJ)a`^wzh@2!WH?|XAFG{QWtWoE6->cRgvB1#G7ldVJ-rVo?EZ><2LslWO%>CX1e&-7eS%v+qN`4j?vWk#p?mFi7 zv%rv5lq_?|pNq zW`kAC6jZ(1eJC0G)Do0i;vshqggr#YO{mx&F?^(WU0}PF@3@p1xO~{b` zReCqVTG9eTBP>fJ%+z#B47L6i3kxNihs8zwQ zmCm&Sig_~+hFX76tJdgo1=LC<78q((^lSa@T4lrnL#;~GGRLJ>JF&pfS*{Gr?f~Xq zWl^+z&oUUYs*q*wz@+xGz>rmyEYqsuXMrKB8d;{5*Uth&R&_tCs-FdhtQusQ`)v9A zEHGr%B+HDjyq^VztXgE5R(3xN3|Y0wGOerm+EYm9EXMrKB0a>P%#m@pmRzq06_eG2OSzyR&M3%WPn#RupLsnxNp*gOS zeij(A{v^xX7tQErfg!62S*BIO&jLeMQ?kr`(F}eT7_yp?W$snh@Uy^>)toGIud=$I z1%|8^WSLeiKMM?5Ey*&intm1-vRc9Ny)RnW&jLeMYigO-8~Ob#FtpFNfn}e+A_f0` zGraqJfN`>8gQ0!CEiC(NzOmWo9%{`K3k+#T0tvA|HPBejOr9~Mll_hNyeRwuvKWA`~`(TaP|%V4P0 znOf!>qSeYI78q)E@oPPCb68d^Fx2WwE%V(UYSj}947IxXwaU2TY9|&LYIUd9-Hd&n ztJO~|Fx2Yd*Lv!XYm``EsMV8N@ls@MrPge*z)-6fwal8oi7Umtf?XpP7;5#VR`h9K z_o}sDEHKpSL#=QxBP8D9j_a~mV5rrXTITvv>xo!ksMQaaeTTSjP0B55eH9A~wfa-* zX`RErsTH||w|c=)>o008e9<$jTFJx$L#+YSI)1kKceQee1%_G!VcB=1Vb;!>qgE-g zz)))twYr3uHCwGZVu7L7U^=c2KR^16u$@?7s5OLI^W*&3q^$vBfuYt=I=-uQRchG z!nnQnj#yx*HNsiuRnen;wFj#8Su8Nr8VSq3*E7F?9M-j>l=N0F7;258mU*wIRvNLu zP-`?SJBQ{urJlQ%3yTGYT4Sgc=lG>nYE>2s47JAkwK9dXpPANJEHKm>=hsrJi&$W& zH6E6o!{1J8)AW> z)*NS<^JVs^P_Fe+EHKoX>nwA=B9H&lNUa#9y|n>`TJ!vlE4XWA5(^Bq=2OcYms+L7 z0z<6@&a%gK+U-#d#R5aEh0Zd^Wxh{JtuA7Lq1Ga2nO2O09|yd0`$nKxV5qg&S*Dfu zV!ilkEfNb1y}MZg%ibe0y;0_Jeij(AHjtI@$Bzet{46kJZ6vGH>Zj5E z^0UB@^*^#qYk;2xhOA9~)<8cC3|X6D*{jm5s7Zbn7_zpIWzN~(eij(Aw)%~5u%88n ztZmdXBb?}Gfgx)KO|Q+FmyfK z3(I{krQ5W7Db)HR78qLLK3ML1L^sxa3py0+-5xNs!u_z^XL_X)H5mNBz6wZF&bfbq zp%osW6*f(MeyCdihy{jP2VuF>Fn9AOw$(x`Fw{CktqbiE6jf`eSYW7iI9RKM{gmbf zVu7L75o(!FXjE&DSYW7iG*~OYy~ExR3kYNUdvPfuYuQYW=QJ{)1W{ z!~#RD8`N4jElx(YB2{$GG8k&zgyp`HdL2|DiCU?}0z<7^)QW$-_<6O8iUo#Rw_&;0 z-ges$C3$SmS3R-7Q0or0%qNAa)mbbs)VfP8^H~01_xuR4z)ylVtsP!;d>yvH077Glu9#PBu^&hn&RC4wP7-~HZ)=Ffb zIiwZ~47Hw6>*$S(dDN;Y78q(hwU&A2WnTG)uzO>OSYW92%v$DocF#TUUZ}NNEHKo1 z9_+aG+Iz|svA|I41+~mQMXirwfuYvRV6Av~&Ss7>YGr5gV5s#fSWB&pVu7L7YigN2 zAK$jhhy{jPZ>ZJnVBRNcwG;~swcf&Ve+q7KC7;m=Y-^ZUV5s$uTIMJ2)H*B{7;3$T z<$fkc>A35ssTHbx5WfsPzMuJB^#8+H6!Sd^Kkp zV5s$zS{H^qc&=7CvA|I47qu=|I`BZP(PDw2)^BP($W!QwTBpPUL#;os+&gUH)?2Ho z6}h@|Twtj6AGOkV@6$xBN@9Vb)?aD`z1~_wt?^=kp_Y$l==%4+nqS>;O09EZfuS80 z0#;PBojhM>o+lsRSl&Ad46QIEEOVC4*Xw|&)e_kq6}^Tt4KTFAP_#ndFCDt6RaGo7 z)CvvDeJscRSS7w%6T|{TtuWMj*=o~Owa$wLhFW1^dA{K<4K=8qdx}~yYC6XShFamM zl|5pQ>1tIM3k(+ucv+Xl0z<8c)HR;g86EHJdAB3sMsjS$VQPIfHs9R-F~7zLK+8@^soIdvql-BHt}1%_4_ z)wawvYVX3Vz16xX78q(pgXP|duI-(lP_4+dooRrfR&;8;?vrJKT4luoL#-Ipx}Ps^ zPql`L1%_HNsnxnvo;_;q7YhtcK9;r25Jy&Bzs0eK+7;2@W*4&TTvudlaSYW7?np)*LRC%e^R4Er>b8Yw8HFmg=X{zAcUok} z@?IerT4AnWD@<-zI7nJxXob0Hh4Z85+o9GjvB1y@^S}!0EYK&+yv4;F%X@`jXoY!U zxqIHcvy{TF@Qbv-&3e7teYNcxAOdbri@>|O+(%j7t*mp&$iv@;S1*~PJAM@F> zmTL793k*%8AT0M^=*;g)?L*6Z8enLJgJhFD;zRhn9bRt$@) zRxh!@Q0pISnHdgB8s_a4+nOa77;2TVmf5{WKc%Uq)?Tr|P^)aP<63N655xjPt#Z^# z{dvVLwL&*>&N3Kkm8X{ZI|$2cD~(uSs8xYl=C`ZVswNf~YE=x@T5enY!~#RDO2Jxc zEfot4wJHZ|Ew!!lVu7Jnm0&Hkev1W$T2+I!me^L>rq1NSP^((7mRf#dfuUCQV6A^` zYqD5is8u6aOReK#fuUASSe|eA3M}dWd68}X5ep2pYEf(1?~q&6O4`hs1{iA9hGky) znyYq>$4j~|w5=jyfuU9%YWZE?U0tnuVu7JnU09xPcy+V5Yuy@ZbrTB=wdzqTL6KE= z)tVp{7;4pr<-SMMYWJ(0YON9r47D0iE7Sak`PDim78q(ZgylYG`*QhrE43bp1%_IF z)XLVT*;}>#iUo#Rji|LD$E#OrCGvO9G8k$#rk2mV`?b`{D;5}PHG$W!z-}1=V^a78q)E zrB?n_Nyn%at)(-0Fx2V>%kvGpx9!z(-_$B778q)Er&i?5H*8$y;shb z%c0g3vA|HPC$&nn2pw9jePV&3RxfI0jlZRoTCcR!*c)qYv8W4;T_BS3IK*yI0TmY3omAccW-tHm}6HsUs_;j zg+pnDi;H#5sMbZXz|abZ!7`IKUvU#G8Rl5tD+EK0` zx%XxHu)-c!=r+#z0z=0YNXIq2|KgWwr4^k6MSt z0z<8Fwq;(!9;~-1np$7Q0z<9w)Jk$AMPjuwv~|uG7-~&`D7VoLZB`0z<7ybX=cnd|ji~QL(^KYcjPmZJm}wt)F6nq1KfDaa>v2Inw|`tsrWZ z&%B_hwwj3rhIZ6cSk8ab^P3_kHx6(t?;Qn(RyfVJJSW*_S)TgOAKD!?O9uM z{Y$NvODtCm<`sI`h(1=km%;;>t+lW`-!Q|k*9L}D>x@`nsI`t-v9HCRqSh<1 zz))+wwLCdIzHZt*AEA?TzQ9mxgSE`#tI)L>8`VlH78traY=q@L`!b)+;#l5y2Qak4 zO|ZP*X}@PzSV~%8XoZ_;h30p_)oLmh7+T>LTH(y8JI^_m_X@$#3b)#pnc>=ZyJo+% zE9@^VFtoyL)-p5PlIY1LwPuS2hFaTU`Fadv9lCd}om$()0z<7G)XKN+ZZ@^9i3NsQ zJ7Iagp%ryjt*UB$6$=ctc2R5js`eSwiqqNIQDCUG8xURw7}2`57G+F=fSFVMl3MYIt0sC&T^5q2ZpNkLM$-UI!vu9 zm*RV^FkBbsEQ6ue5m=sY*in6+PFbm~)MA05)=_GOFV;VfS|!B-L#<=5+#R(zf0b@( zH5CgCwT@Hkd+RQp)EX!j7;2rMmihEfwdRTihFT}7_3l)MLu&033k>b3Q?T4uZLdGX zTY~@H8y%tLQ8Hob86Rz|acM&oA7X)_*4bdK+qMC(Hg2XSS&Eqx)|)Z{OnH= ztQ89kwJuTXd{+N)YF!iy47D!9@_fVBntx+Gy=<=lU&I1Ktt-@Ok!wUFwc>SiCJ%;M zS7Et(!~7&har=`P`NRT4t!vb}_w!L>wOWe>hIa3DSnhKG^Qmqn(DL5BV92@w%bY8G zEsMLiWH1X19oJ1*=6SFAs`B6DN~P>^O_vpdq2szm#}%~lV@$Qqhy{jLc$<#v^2JLd z9LxK-z|acsz;a(nwJp82VHvx^klmg01%_65msU8W=eCn-6%Y#yweG?4e8aW(@roSf z)#@S^7;4?8R?Lf8`>VB5EHKo10L#7hcARs+n_7>=0z<8b)JpZNSR1tx_i&~GhFXtc zdA{Me%Kmr|RjpcLfuYu8YK8AnD~4L*#R5ZT`3Wp{_rARt<(gx8pJgz#!l$s@vz&NL zwck(eHR_nOz|abx(F!9?EOK0}cVdB|)^k{%ZAkPOBB6moq~!)OtrP{~7(itCd46Fw}Zat%5O9 zj8vm#)mFX&Z5tu!w&>sPz+;d)+YavxT+C6|Ijm4KURD zMJ@9Qa%xo<3k!}9g)d2@Bku((K!^R^Wv78q*%p;o&OK|j>GAQl*E{RhkQ4Uex_ z+Y(<_D@tGIxWG{BFSW{?PZCe93SxnwmQNf{C4{>V0}~x8rq(F2z)&j$EcX*au12qM zSFK}WfuUANSnl31&!ZmMy%DCLb6jAk6^dFv>n|#)R(i3(P%E@OF3%W!9(K#NaHl}8}q@3Sbt!rX|p;ioPg-pKVt6I?pIL8HsS}|d{kLAjRTO3oXj96f( z6^mLovZX$x)lUEvA|F(4J`M%F{{q@s%qU63k9ucry>_D_g&%{Tkp?yEbn(Jz|abF!*ZXcnBQxgX;-*UT3~2} zd1!^3BlTLU);qDlP%AIB-ge$n{g!Pd9p;=bFx1LNt-P@+?@_CWSYT)x`C&Q#P0ypU z&PQLz@}345T44cN;jUVl%igyu^ph4CT46z2VdZ|wN2nDb78q(3g5^HGO1|3auhuNF zz)-6&wXRnVu|=(&Vu7Jn5m@FLW$q5Ax`tk%)=ja%P^&1l7N$C0T&pREtex!h*6_$hL>)B1_u6OU}zIqqzBPHPo=PZMv6_%$JzWtbSn_BtB z0z)gT0LygDS7o1OA05kkgtcbSRyAsUt+#NI zT0g`BL#^s`T=n+u3s5UzpmUbNP^$*DnvO4jM6H5ifuXZp6PA0HKUZtl&au4DG8kH6 zEm-b5Fy^;tH`w#lP+DMUg|%sgyB54UuU4Q~V5n8cT4o=n+_cm0wS5(^K`b!Ts%tH? zH->~?)lscWVu7JnJy`Bf_xbz3-h9WlK8pp0TJ@=Aev(kF*dv|u1%_G;V7YgP7bTBw zRV$}hV5rrQTJL9M>Z?{wvA|Hv50-n^o9mysyjnfP0z<7v)LPa5cpbH-i3NsQjbXWu zl*C>89a3wXSYW8tgj(NQ=R2;}b+N!ut0}cA#H|%stsi26p;j|$wVpZNN3DdTobv^S zTK=%yJ5kveQwOS5P%JRiYEG@~+n3f?tD#t6sMP|NyEpO;&-_QN{$hclR!eGC2%K?U zt$AXBp;jwc?qk`!o7&0#Yx_R2z)-6-wc^bv+E%UCVu7Jn8(3x^ny<2l&J5pSA7AlD zJCg@Pt+vz(5q)wGwaSPEhFa~Ybt6N;8ryBFhge{!)t*}Bom;h5i3NsQ9box-j>%j} zpTt`C?V4@f7YhuvI#O%Forho5N;$@v1{i8}g5_SLUd&4|@1Sk95DN^oI#a7@v{d)i znk^O>YIT9-zD{Y~Y5b7gwsl@CFx2WwE%WM%Fw`1K$7MdlzlUwz5DN^ohEc0V-ulzjN<6`tAsA{6hvh!L{v^7*d%vAwBeB3x zYXr6O57~T2t^Q(xp;jO)_g;CkevXi8%@zv`wMJ5_ZicBL)Y>H$7;24zy}txs5P2e!}2VOs@5;Dz)))ptaP$B;x?(6V7;ATqKVGr!BA@~wMv(rQ&Fv=Vu7Jo z0pnmf|4kpC7)i=*aV+mw0bpo_<6(I}QeM~{)l6DoXoVAKg%jUZ46oKOvA|GkA}n*3 z&6oLno13=vuUKHHHHligSN(mj))BG5P-`+QbC%7cGWq^PuX@{OM32P+L#-*)O1+?X zVzt6ga%KyLT0ypDj?3Kj8rfDxvA|GkDz(gSbF0-rEHKoX2FuLQ99P;aD`H->GaM}z z7-~(YmifCCYV8sW47Fz1mU;cvG3CxPYP}K*47Fxb>s8R^>1rjJ?931hwPwL`@38N$ z9&e^r6|uljYc{nuj|g91t-)e}q1GH&?iC>1fJa%>+9VbjYR#qAj(E|ptMx=IFw~ky zt-^yVk5DV#6lWS>s5PHj+Y07PtyVd)z)))eEcZ@y?QZu?m+ju@Cl(lLEu_}p1}$Hy zwO%YR)LIm*b;-6Kiv@;Si-Wb)iXY@m0}Qp6z;gdBVAYRQE%w`11+ltAYpeHCzA ztzKe*q1IAZ?p<$glorL#+SVemz)))$walvkk6{@e+6|uljYb`8uzRcIHGhJ8Rwylq1fuYtqYRxJbzN=a>ra3bN zL#_4JGOc`#o4$KsTUo^dL#++gGUuz)<_wS2sw5T|YHft&J|p^8e%A!G+KL5+TAQe~ zzR-+_YK;;L47E1Ha<9FQ!wn0q)^f4HP-_ddww)NdLak$BfuYt`SnjpA;nj1S)Osow z7;0^!R-Ah2`l=OXx^uq3P-{E2hBoS7U#(PPfuYt8YCZTiZLL}*#R5aEov_?%Z{eUp zNnhK&(M&8b)Y?U@=BZ+5RBNzUV5qelmak_wnH@E{+xS&#%@+#{wf0c!dF5Fv)Y>N& z7;5c>z-I(sI`w;pCfl&tkz$#z))*HEO&2&UUDY7TFGWOXBiB&4p3|G z!Ap76Dk>HjY8|B3$g?FUtJPR6Fw{Ckt!*I}7gKAXSYYUx`C(Yj`h9$c4$4r{vAmy| zgP|23f#toUF4`S6Us_;jg-2 z<-McSia*nt5*TWoq*kHm8*`|YS1d5pIt9ynN2yg?EHKnMO|5i!QdLr`hge{!b%t7I zN2wJg78q)srB>3fH4Cb>Nh~n5qt3x{cT||Po#Qx`_l^QXD?AU&eGXvW6?tQy16-6A z7+T>4TA_KZr`9L2z)G`@zAN*YUL0M47D!9a-Xv$ zs9P`16WgjP78q(>p;r7>6>h23Lo6`Vx=Jnc*%5neYo=IWsCA86=CdQzIxH3#YF&qA zt^npMbEkmRr)=x3SYW7igIdww&&FnSYv zxoE@wqpqm+RxB{odPc3%kNQtgEAm`t@?fa-9F}``c>gCuPqi|L1%_HLs5NitzR+rw z6$=ctUQ#QtO2$C7T8agRTCb?}K6UQ~Y7G+$47FavGJD>fuj{|sM^I~#SYW92hFV`* z{O6#emsDSRH$4Z9ETiUo#R@2q83SohP|nQHwO3k>-y3FbLx z84R^PQ0qsZA~Ds=E^2;72 zzGHbm(*r}+Us&cHV)K=;;?@Xrv7@{#Fmzl#aXnXz5bg}k^TT&`hC5}2VCc9)z;b{8 z%Y4?oTF=D-L#>do+!>nBtiEqsaTYjx0}Qo7QEUC9cYoC?E*2PSg${OHZ*8l+SYW6X zhFa#h)S4m|7;1$L)_Q1LJH!G*t#H&Tetyq;wH}KFhFalanfsUdYL~3-?-TaA5p|(6 zLon2eKrQoFRx7($V5k)lmisuG-_OAr=^FMWWWNeSW3Y8Y~tVYDK2wN^@po z>;m?0o30fL47H+A>q5~F-_<%Q78q(ph2_2)JyI)l2(|8r1%_JDsMX8A{z$dHiUo#R z(d}`Wt7zdXON*-&ZIN@nz)&j&wH^g+ZK+l|vA|F(CM@@{9Ak6ifjR9Ai;D$@TCu1# zFGHhsYPApx47Fmza-XvWuA8z}t&w7Zp;jDf4Om*Iky>lS0z<91u-xZtUH3!ioa>7 zR-z@&EHKo{0Lz`Bd48D9&Tx%bV5pUmT1i??=%&^M zvA|F(Q?OQ6+xjdP7;0q>)>13}QfKmDsFeklIbY_>{DkEDuzS zEq}4VP%E2lnfuqf`P~B58Z8zWYGtR^ha|r@skKQgFx1Kc%iSBV_wE~@)@`xCP%9_3 zu5@~GRjn|~oEd_lRxW#7?hN1A8D9?ZCD>{UC%dt!m1RzYe_oK$tS zS`n5z=L-zA3I%Ijv8^0pfuUC6U@f&8iUo#RMS`_1+tzTgz)-7bu$Ed&!~#RDV$|AH zI#a)B_PTLUEHKn6POX9?o7Yn7saRmBRU%j`s%=GB;Y=P3wMqtSsg+qQFw`nVE%SK} zVQs6bSYW7Cnp)=fiPUN<78q*%1Iv9rpRHH^aB2+|3k@)Vu7Jn6>5!& zykWUoE5!mst*WrRXBf%O@Vr=Hs8x+xW`=5g5ep2ps>AZ0p;`%6Igp4nEASYW8-7p$e$9qX78q(Z4%SjD)EZ}oV5rq3SnG^!`HBUG zT1}}Hb<)o!YE=*m47HjCYn`^O9%6x^mVdC8S_{MiL#^h)TBmI5q*!36)go9+t(Rhf zp;k+3ndbnB?VgXY)|osQYPF(Pg)C8CsFhhPFw|-ttd+>Ns)_}MT5W>0)aou47;3c* z){0|W)5QWqt#;Jf79)29wRVdIhFa}|wPM@WeX+n$t3$AsT4B~XlLtesj?^;GZQ|Ni zda=Mzs}r@%a~riviUo#Rond)Dw^6I1SYW8tg<9shjat3L0z<8?_PE^VHfl{43k zvA|GkD79++de%s-FdLm2f}z$hSndq#O;~$Yt*l~!q1JF}l`S@}o?7+90z<74_PE>` zzO*wODi#=O1yak*P_5NsfuYt&+j3{9)@8B4P-_&m%na4~Pb@Ih8V$>PhH9nT4(%uucBVu7L7SbJRV3}4t828acQTH~l?W~kOIvA|GkyluHNRBM}9V5l{LT4si7 zT@?!qwI;&yo}pS_!~#RDNz^hkR4evoXYydEHQ8EbhDV}D{C3{XFsE2xs5Qk}W*RwS zj*g>NBeB3xD+rda$1qmj>Fai>HBu}v)S61Iv|&1YQfsqVV5l_>mOI0{-|wte>%LfE zs5PBh)eg_-r&i=G&J4j&YlgKvhlLrQvop*m78q*Hw3a(Vwfw~bL#4q1GH&-ZNC|iCAE$HJ4guhHAyw>dX)fwdPsNo#9zK!@^>Lq1JqB zxieJDPb@IhS^&#?hH3?f1%_G+sbyxU)?Bf`P-_t^?-{DKS1d5pT1+i7L$&US1%_Hn zY|G5>)YKwD>FskHpKZ?M!BFd8YE6DJXOLQ{!~#RDrLf%RHtiC=?W9&2vA|Gk8MWrd zemqyL_F{pd)^dAX<}440b}GMGlf(i;trgU|Kkm|WwYG`{hFU9a%bj65JHuOIfuYta zYMB|T^;aw~)LIS8dxmPI*zTM!Fw|N@Ei*&4%7_JqT5IibxieI&y;xwVwT@b5hH6a` z3kEwS`(4Th!R4Rx`1{P-`nJ_cd(D>VYVD!c%2gMNt5sVpFx1)$%e~Go zUKKsPS^;8#q1HZX)jslIyIPCH0z<9+u)JrO)Xwm@SYW7ifLdmTYP}H)47Coz@}8ku zF?KnV2Scqx)G{+vE3a5!sC5{Y_YBqY6AKKrj!?_YP_3b2fuYt>+cJ-3^FH=l`+Q@C zSYW7ij9TX3Vb!`Q78q(B57v5PTR+7DL#-3RT56@-?MxmFwN3_Wy|%3iVu7L7sbDR& z+K2^)TBn1xF4@)yvA|I447JS9605aAEHKnM8?1HFwr+_9hFa%>wbTl`$C)7*YMl?( zx?o$`!~#RD3&C1yRTT>iwJyRk*Lm|b%=h8nhql#8EHKo%M6F$)L&Z~TidbN%b=kJe zb^h<^K8@AdDi#=OU7^;dD%r!SbxSNT)VfNo-EZ$zQOjqqGkGx7x<;*0x7!D(m0Bz? z)VdDKy>2xAx8+{7%8LbtS~sZW+pTmQwK|CfhFUjax!1$a8)q(6D@ZIb)Vf8j0+(i{ zR%?e?V5oJQj_dTyn5)&gD;5}P-Jw?g%9V$z6>6U|c`($vORYLdYpzu*omgO~b&pz^ z+n*YyRwc2(Q0qP{?>+y(?)k1_fuYs|YMDK+)-xqDu%9b$o@)+1_}J+IbX zvA|I4F}2K|S1Z(hXYydE^@Lhx&#RSAEHKo13d?)Xt5r!XFw}ZREwks<>M9l(YCVVL zz30`ME*2PSy`Yxa^J?uD3kBlPSYW92g<55&M%P%E%kw`OX^I^;|q47Gm3av#e-)7Jl`R$j5d zQ0o`9iVqpzMlCrG3k(xqj#F;!8YK5oPtl>-hs#RJnFw}}bt*3eN#a64GSYW6X5te(t zb}XwJL9Iz*fuU9;Y6Vp)9#gGtVu7JnWNJk_mZ_#%cf$9GJ8X< zy<&l(RxE0ny`k1)vA|F(HZ1SGp;p9W&g8*RD-N~H-cT!>SYW6Xms)0Ts8w4mFw}}i zEweY&3J?nnwc^{Bd3s~s7rkcp#v-x6P%8no%=@Bh?G_6RwGzT|@5|Z9J`?OD~)?~53P%AmL>K;k;MXlXpfuU9kSni%* zd?oTYwVsLvhFU49)g|4EAhn{Oa3&9iTB)q%IV{ZZv7KQ7vA|F(wYA(Cs^u>h7;2?~ zi2tmV$|k)2^q zvA|F(qqW=_s#Q%aFx1Kf%X@}ubrcH>wK7x7%uuayVu7Jn7FgahRBN?ZV5pUqT4si7 zoe~QSwX#{uo#9D4!K# zZfE#eEHKn6Y%O<&YQ;X|%n%H_YBqQAr=^F z6{nV&p<2_#0z<75)-p3Rp953cexAcNvA|HPq_xZp_l~)hNUa-UfuU9@Sng*>Tn-tg zTov2;DHa%Nm8O>Yd%kKFI_sP-Fx2`7mak`ZW`(ChZb+YvZJ+c?t^Hzw zp;lQ~?)fr*V^^(E=bROSp;kF+g&1GxgP_e*Jt3E968LG8fEHKn+KrJ&vwXTQ-hFT4+<+()R z+8fT^zy1>o47L2MWv*1VwbqFRhFZ;Fx##P3P=zFFT@?!q zwfw2oWXp!LYW)!l47Hlumglg1%y$DT@{d-ll2~A<)sI>;r?fAxR!6bGP%8jdCeJaMX*@2Hc7s|I!~#RD z{?t10;pu#}Hi!j=S_5FY`>;o!f}hm7Bo-KI4Ww53xA9x3^+hZ&)EY#swx3o;R4d+f z=X`;o)?jK?KGZxwt^8tvq1F&srDTR#Z}mx{Rs*rXP-`f)qLr-ER;~VGfuYv0|8ZRN z#R5aE;neC-W=}6|9S{o)wMM}5^&FSk^RsGA@J(;`{3EfzP%DsH`L8xis8;wJ&g8*R zYa}f9o-(9W;&*Cg5(^BqMp0|a@laRPsxB57YK?~F?!zmEA}v;{w^(4PHHKP6uO)1u z);zJmP-`qKGeh(EDxJC48?_FL1%_JVs1-2nM-H`KiUo#R`zM$%CQR z1ZoBLNV{IGJYs>N)DcFhr$``-e@Qm7-~(TR)~({FQ_$GEHKoXY+GiAQ37*3 zSL{P-`x= z%xed=3W)`VTJvnnb69xoFxAe`Uo0@xnolkB+Ci;RVu7L70$AR!9cJ3rTCu=TYaz8N zhbf#wtqWp-q1Ga5nb!^rZ0nO)V5qg2TIRKbS_$qrlLtesC9vGE0ts-K9q1M0D zGOr!fY9SUFYAuE3?hW(WL9MZ3fuYtiYMIv#YHbn=47HZS@_y|w-_G!+SYW8Nf?DRa zgIYd!of(3m)=F5uo;_$DU*>&LwNi@(hFYtrWnMd|RZ%Q3)LIS8ouPT{pjJ1rz)))q zwajY=wPuM0hFWWF%X3(G?Xbko@PJrgsI`t-=6a~s3$egZYrVBh%e;12YFp9oIgEwS`*SMm_tZ)*7+EP-`nJ_qD^|fMOBVIx7|!YHg#|(|X;Cs`XwhFx1)(%iV_! z{MVOKE9QOYe1W0X4r(p0dgirSxx@lPt)0{|uN~B?EfyGR?V{G^m({YX)mtnu)Y=Wp z`?Z5wv%~^Jtv%FwU-I1)wRVdIhFW|7$8p^i3k z>kPHb{Y$N=kDSSaq1IVzc@7QtlxB8@xy1rQt#j5g)7ZN(Yj3q`iUo#R=V7_`l&Ycg z_;s+Yu3~|q)&**<3Au5#T9d^BL#>Ojig{LNR@me7j{vnchy{jPm#8)2?$#}8T@nin zwJyVQ&sXv1PvWTcMJzDXxTDOC>2HRHLC(h)-Q0q>xmRg0y0z<94)-uOs zp0hQxEq}4VQ0tzx%4a8{4`d78q(hqSn!6XD6%mR4g#mdK|3v(zbqz1%_HrsP%bEsX(=& zKXuMB7-~JWmN{QNS`Dl7-nLSU1%_JBtYyyE8UOfm)hZ?y7-~I-Wv(0ME7Qdz$zRx3 zeX+n$>jkyU@A<0LMJzDXdI`(@o5<6fbbLI$q58sP%?gLu+4{qt;8Yz)nkkx8g(K6k!Y#xK1}@FIbUF? z^^IC>Pknr+R#CCQQ0qG^Geh$gdHAvzU+mu}YAO~OYW<+r!;)VLsnu63Fx2`<$CdL% zm?7Qmb$+r~V5s$rTIRhYD%EN%78q*%rPh~aoeQfqMJzDX^6^|ULWMBD$z{IGy>g+w9v%}547Ea7 z%S0 zFw_b|E%WzN)LI}G7;1&JmOI1owsll2Fw_cXEi=PI*W=Dp>y21os1+WTd;c2usBo@M z_OTr6l`}&y)QUi@pY<1&R4cbwV5k)lmggJpDZ9Uy3sS4LSYW6XiCXXK9Q>?SAF;qt zD>5wi+8gUdm4#}}5ep2pqEKtsqBn8W+9wtmYDN7Yt%qWPp;k0%jh~PvjkdzPb|w#o zTG9VUE1g(is1<`+69?B1p{)vHfuUARSnhQr?)oo3)#@k~7;43$)|34=!mBk&EHKoH z4aUWx^VT5;`hna9`Oy8nH8W?RYLIFkoMt$5Vx z_`Yg2wJM1PhFbBhWm@KXc-gl4iUo#R39Mxv%jWf$T1&+OL#>3cJm2tT{$BPS+qxhY z7-}V=*3oeVKB)CYEHKnc49mT4w0`k4`EA>Z|JIoy7-}V<*5^}oQ>s;7EHKnc3d`4X zRAw4Snye3_RzI=8P%9a=sugHoN3FGDfuWW!Ecd!mD^lViYCRAO47HL|>z`v$JF6A@ zoihzE)Jg%%eSF1F9&MIdWyAtQt(4SS-EzZVwfc$$hFYm?%WRJ3=f|G7WzW|dvA|F( zHMMq)PPR#{dt!m1RvK9D42wix(nYQ4@11FYp;lUIJsSD4jante0z<8I_PEU6sMDlu zM74T~1%_JbskL#-pw?=w5DN^oGSG2loF99OTDQdlL#>R|GCvQXR#0~^ zsFe+t=Nlf&$zJqMr&h|3&NRSKD?7DzWVyIft!83@p;iu9?&B+H^2%>&Effn3wQ^GH z#k1+f)VePg7;5E$<<2nY#9J*M+ZiVN>L*uYUQU^ved(Js#QrWFw`ml z%YChPB1wWi5A6&`iv@;S1*uhhSgpKj?GXzMwF<%V^~})xj9JmBt&88ct#@L9p;lpP zttbSg)Jpr+IW92NDgn!VKPv2mv~wQV8MYJ)47Ey9D{;dYE!0{h78q)k zvMqC+KR7Mt1-0&o1%_Issa2y$=Zb12{N@}N7;60k%bnr-t$S~)RYxo^)G9-*2&K-X zRx3y>Fw`mw%X`n?vopLP78q)kqn6q8YK8vp92XdBm51d%$2RZVbhG~!kVh;q)T%(O zx}V0*RI8O(V5n7*S}8ZZj?>AAzFx09+tz>vUMH@?wFZRzq0s3^&w# zR9CIuVu7KSAGH!E?m17brDB1hRwFvDW4B%(QR}i;V5rrYTJhqy_gZ1d-_A6^P^$?n z_Zl_SKkDut_VJZXEHKn+N-e+ZyQ{0!NGveaYDO*d?_WJ_Ym8W6sO3+s3+)mVRcohM zV5rrcTIT(YzP9yTEHKn+L9Khk{{B)c%O7WkV5rp+mU~YLEb0HboxRR?6AKKrT2X6# zkiVflJGrgh{~tJG>$5DN^oI#BCO=3bH1>M9l(YITI= zUZc$C5ves(EHKpSM6JJ>%b!+jzgS?X)ftw%H#W@c({rXhU(dt>L#-~mYmEHKpSMXgC`YRyn9KK@HSK47TT8`l4ST&2VU zL#;m4di(Kwd~J0W3kb@kshv{V)sThvA|GkIJL~@n5i{TEHKm>0n76Z=PN~>MOD>W zEfyGR1ybwno%z+(x+NAEYK?^Do-gzF9n^{#%9#cjYK@{+iI*+Msg++WFw`1tEi=R7 zC&$j1XlK}3EHKm>V=b&E!)JfBri%rJT4Q1P$_#VWIF(kdBVvJ});MZCXde5wT3^Hh zL#^?!+!?;!zxbwFsY5$61VgO})cUe8QX92ui3NsQ6Rl-tIONpxwUg`&hl>S_fFKhy{jPGhq38 zI>uVMGFD`@{)z>LS~ICN$3OdCwX%kFW(bB_vtYS1H2YAk#$th?)@*9U%NOUES`)+q zL#;X1@*EasIKj?vpIBh1HP>414Apuo78q*HgXQb#7|T4C)k+-BnFbhY&8JqPwvBqL zRZ%Q3)LH<`dxmNShy{jP3#oNv!lJ@ztriOmwHCqhe8bn!hoiQRw==vg78q(RrdF~2 zS%<3?F1#}hFw|NC%YDA_?}V;B)XFXv7;61Xt$4qarB=&NEHKns3d^10>I}ULsWnP0 zFw|N`tvBrxS5#|@SYW8N+*)Rcu>+=U9A{_vKrArST460Sul_a83|A{s1ZRd|sI?N7 z`8N(jR6n=>hg!MB0z<7;)S5K5TsO5Eiv@;St6{n4>&)|qlhhh578q)+q1Kdh>$9k} zMJzDXS_{iPU;SGqJ*n1xvA|Gk9kqV_x;kF1ND-YGf}z%WYE9ZPtB_iG!~#RD4b)os zcZiqOR4g#m+Gs7$>GFyFr0V;zc5jRo3k8{>)Y>8z7;0^XW&SO|Sjh|f zEKuu?SYW8Ng<7T4J+Gx!xJb?n!BA@}EcbkU+19taTG_<{L#=JpnsA_JWVITI1%_JN zVY#oD!;bUq+1t)=xL9DQwS!vbZxg7sM=UVZ+6l|^4Kws>GoYASpTz=0tzFb=QFmMl zwK7L`W(bB_yJ5LAJofMVrfRhm3ke4Vu7L7L0Fz|_!_gN;r#%+ zH+G8!hFXWHwRG~>=4!nV3k2KyjWnUbsm=c_=-5$ zr=VKL#R5aE3)E`*EpL0ZLdI~83kvFJGB->gc78q(>p;rDOoA0P~Lo6`Vx@s-66;p27>DSlpjqov@X@H^DHES6nOo+qF z)v72K7;0U&mfLD!|1DsGSYW7i!&;_wIrf2^YMl}b47F}r%d|SaK3p%lonhEm&T)aE z)-7upBG#xj+tkV?78q*XhGq7=d3;rD*(^yC+o~rP7;4?2R$$86|Ee`bEHKo%3(MEj zF)NJwwQ*jxPKyPGTKA|m;^D@vYK4pKOalzH?!)qYLu+jMH>1@mAr=^FJ)l;=?lT?L z>Ms@;YCVMIK9<{te-cft?P7tU)+1_#+!sBxTA#!ML#@ZK+-p>?c#lG8ts8&s}z)qYuBW7K*l78q)MpjO|;!)mLQA-*#WFx2`;$7S}RS}nu^L#xfujsP!F|d)@f&Q=VUH#ZKs~5Dc|`P;21a^Ly3u7Yhuve!_D1Vaa9H z>Z`R;EHKpiMXf4R&Q4P+L?UN}V5s$*j;r68CUw-RDi#=O{h`*efXQdnnlBa@YW+vY z)o$DQ?P|Rh3k|L7A zwx);$hFS@zW&ZY}TF1l!L#>3iWmb4H{>Job{S*rfwGvTlexZ27)XJLNnLHS3C8k!( zvQ0av)m$tv)Jj6FNU3_iP-~`GV5pT8mU}%ke=Ae1vtogvRx)Z0S{AXtTA@-n#|4HS zDZa4W$MTlXo0B`1_ag-ituVQ5nX_zmRCfE*efgvXhE|xuT4ptG4$e)lRvWRvP%9-Y z?<-qQ+nOmB7;2@W)}j?zZmM-fEHKnc4a$6y3sFnGD99NuF&iMjEtt`}< z*z#>BZRHUQ47IXa%k25D{j=;SX7@%NvA|F(o3+epjyJoVTdh7~fuUA*SnjKUOGg(C zRBM)4V5pUYTH(ST&Z^cPvA|F(CoFewq#8M9tXlWQ0z<7_)OuR6UUIcUrFJF{hFZB{ zxsT--n;Q=-Y#+;M!~#RDJk*N!H04>f>WKx0T6tl)GmPs0_MBQ{!~#RDeAJp1;m!oL z_K5|CTKTEfF2%NwYJCz547CbS>&1>;x7A9U#+e})x?&fE<@~Rn_YZI6_H!)nD>fKf zVIf%Vz7zys8t-6=LMgSnPcgP^#`k!EUhzJFw`nR ztv;de{ZXs5SYW7Cl3Me#AHJ$qJF&n}s}!|HM6Q@utw~~mp;l>F?w-$=^HpcHwuuFX zTK`b1#-^+j)w&}V7;2S)BRy=t#Z_=lKI<4 zwW^2(hFayR)je0$cWU(z3kq%*nK!#EHKonNUa?0r)^McpIBh1RmobO zZRj&^P>2+L?X%^FVu7JnWowx!kDXa9s#;;vJCg@Ptt!@XTLHF}RxB{os%kB_rB+3; zz)-6iEO&yH?P^&(*HdZU^wZipcfuU9dYJGV$ zd6Tv-iv@;S4XHIc)}~8peHRN1wfwAQ_Qt_^gYOQrdn0j1XYydE)yP`z-cYNUSYW8t z7?!&?HvArRK`no=z)-6Rwang7You6UsMQpfd!0Xh_+x#w)`$g$TFt1{xj>pAwJwSU zhFboxy!VD$-^2n#t>)BP9{E>0wGwA?CJ%;MEvRMohFZnN0z<8q)Y_HspG<1C6blTs zTEX(ZMh&uiV~ki}sMVTU_s+*Fq}E!oz)-6Vwal}xA+~j1EHKn+ORdy*{kE(1Nh~nb zY6r`lFY~HC{h-cGd)Zc;%+BP&P^&$)qE7nRM6G;cfuU9hYnjKFxqtPst@>htp;kw0 znbr7y>CjEBo??NaRwrw@t$wyONh~nb>TE5yrPeyJz)-6TEbqP1-L_7P1%_H(sbxMT zOsyAUfuUA6Smu10ueD3IpXqN~VX`>q3k1Gh%_ERzGUh`?vlYwO)z^hFSsC3hJN3SFLbaowE#vTK!?U zuZglmJ9B!d-5aUI0z<6<)H1)lsFvrgDeN;a)Ea18hDZ|jV>Y$?!~#RDLDc$ttZPfP z`iTXGT7#)|rNq?)YRwc247G+(YtENgJ=EGJ78q&`h2`#zSeaAbQ|pRYV5l{WTFINO zY^K&HvA|GkIJL}gWvUe;n=^SZ)EYsp?v*o#Rx7JmV5k*nEptN4zBqbmpxqml!~#RD zk=8P+F|X*=Y9kgHYK^j%X_@zX2iw*#vA|Gkw6#nt-i)Gc)mk7H7;24y<$eF^XI*w=a=#R5aE@zyfO^)zgSG-}1j?wn;X)S6%| zxAmWGWfcnywI*82{C77;>a|p@s$zkm)+AWo_pe{J)mbbs)S67KQBOyORBNJGV5l_( zmV5tdU!=>1zqYkbEHKmxqSmtCA-AY?RxB{onhMLke}zAOu7O&w#R5aEY212w{Ht1# zb2#S<47H}ia_?XFsx)q-Rwl8)P-_OY!o}M(NUe%ufuYt+Snf5dg3tUaYPA;&47Fxa ztNpxRIn^2~78q*H=2qNVk=0r)78q*Hq1N?*v2&|+S}ZWsnrmBT&!0`TGg8P1?x*6s z77Glu=26T1r6IK<=XA~&7;4Rj<({wWJ3h8oE2CIosI`DvO=>rPr&dL=z)));EO#HK z-Qyoytqx*=q1Ga54IZ`2Pp$D{fuYu7Snl2!yE|uXwbqFRhFVMhkFRr#j;!0-XwtUL zv^#CvwvDuH+qP}nwr$&Xr}eh`Wt8 zGXHL|U*qzsRYfc?)LLaN(;Ap4L?Z%YOS`GY3+ZI^{!eI!~#RDHL%=!HuKvA zrGmM8ew|ogsI`__8#7&tqt-#Oz))+QSF4O|T^0)rwboP1{N-!4UWx^VS{uAtjcx0X zSYW8Nky?!+Cx56`qU_Gz07I=!Uacm!RX{8-)Y?p~$p5--Qmdv|V5qgltJTc5I*0{^ zT3e|#^6rNiYE2Of47IkwGS?{cbs^V>j?HaryI5eTwVhfg=B*s6)-$odP-}mcD#A^BEbj}wTY8|B3y8X$csufEtFw{C^kITGA)aFF&9@Fd$(}@L! zT8F9ia$oTjY84d=47HBHa-S=o{9IFAt=eLNq1I7q1teYbT&+%GfuYthdt7E-D;ma$ ztkx*8z)GU8 zX0*9#y%GxywN6v(Qk%uY)bh>c>?knQIs?mnESvA$^s;*+u2^8Gb(UIR9<42;R!*_N zQ0p8lcW)H@Su%-Q)x-irt@G3h8MWI1wYrD}hFTY>HD&eGW@=3q3kk2IQe3@(S5PQBN<#x_87;0Um zmicQ9uM-GJp6^f)%xsN_o@ z9A98t6U72Ut((-^k@rw8wKj?chFZ5^dCqXHZCwxx47F}k%l!1LS}()`L#;co%-%3x zt&6X(x5~EuiUo#Rcd2FGTUIM!9_K8Bq1HWE?&E9juvACX$}1KaYTc*Sy$*W^t5sJl zFw}ZrkISsa{PhI2`iKRFS`Voe$#=;=wdRNghFXuTWoG!e`0#vd>qKe512>jNzJ8fAWVZi#Iz6blTs zK2mFbnt%;z?Gy_PwE|(e*NqVyrmR=%f>>av^@&>jm)8tX>!ny=sP!3^d%ij!3>!-= z-~7(`0z<7Y)Ovm>$riQZi3NsQUtxL9aGsrERl?MqbzZGV0z<9u)C$NKm`<(!Vu7L74_NLD3$0zSLamu%fuYt<+o)rrWwSHU6oKf?aP}F)R78q*%f#v>8MWg;Xva0n*EHKpiOReg@=U=H6 zyMVK!z)V>&R46fSYW8-Yb|$%1?&u)i3NsQ z!K`JD!TdacTK&ZWL#^Pj+-vXo9JybpHC-$))CxhZE(sPrS8JnKV5k)mmOH~!*~0m% zby_Si)CxtddO3fuRqLr(V5k+^9+!Fk+SDk@kv?{Yf5iertuWNOed)?nwfqV?djkx$ z!oqU*;oecbKB-k$EHKmxN3BQK{YR3WoD>W!s5>4!B8u&SF4t7JZk0z<8;bX@WOwENfIwqlfa zW(bB_)u4N6%z{#wW@m^S7+PmA{H2G)u5I+F14131%_HRy;_}Y>#|s2s8!3W zrB;YC&NRSKt2Qim&zl)`u&wN3fuU9%YMB|T)j}*V)T--sTwQEyrdVL8RgYR`hH9M_ z3kUX`HZT%7p47CEN_3B5#8EU03>&y@gwHkP}y4qHNSYW8tkXmEj)*h|a zM6tk7tC3f$yKNm33k+p z78q(Z^J?X?t+HZ)p;mKhJ?S+ijan_l0z<79Uaj1=HCQY#)N1L~QfsMLV5rr~tCiQb zj)?_^TCJ&7vCWpxYJCt347J)&D_OC+rz6`|obt~30z<8~)XEZVbWF9X~+K_H|cD06x1%_Ik zV7c!RCF?mRf?Bi00z<9N)C%*xdrGx7hy{jPU8r^c`@OYl9TN)-wYpL(R`t4V)Vd=U z7;1HcWzLtm-#BzT#@iZpZv=`3hFaaJWqvO}tr!)Y9R-G3Jz$x88$;}EG@-j%Im7}( zt)A3s5-oFCwd#lkhFZN~x#z1{g!_Bc>Ms@;YW1epj>FA5skK-vFx2V;%bj8U-wi&O zwlh2~78q*vrPjNbt;(qNN-Qwc>Ici6;lqtvm#7uKqBD6g)ap;Iz^4`Ns+CbJFw`1A zt&Mkk+*hlrSYW6%kXq&a7Q7kaj8cD63HO>xKYpPgas5Q#Af)35+{o+e0 zn%Wue6blTsMpMiDC1tg4i3NsQV_><@DFxDnjjPrVvA|GkEVaHDtrbG8_?4aW1%_JV zs5QCo?fPov7Yhuv##8HLf4@v>H4qC7wI)z2Z^)?~)EXof7-~(V)~*#%zN@uFEHKoX zM6DUsOQu!pm{?$_HJMtULM<4f)(f$~P-_Y-cOPzzd&f_$uvMJNgQ3<`YJJ#Hxr$n8 z#R5aEX|UXT(IzR14ozqGVR^B@P-{B1iVd5zK&|FtfuYt6uU018>Ms@;YR&X&sWnS1 zFw~j_%goSxRd~AQR%YAUA{H2G&8C+5>)~qM77Glu=6JQT*p^RK=X`;o)?BZaTK-~z zq1HTD?)geOW8Jx|wpCdyFw~k)t?v6iyi%*JSYW8Nz^j$hwuXxZhFS}$Wqzhztqo#< zq1GZ;?)jRWF73y(wsk`+Fw|O1t?o18k5(&qHD~f*sI|namBzL*hy{jPOTAiZ)e#E} zwU&9c{B3KPSYW8N+^eP5Cb7U!YX!B;p3i7ocf|rjt(Da3+4D~YwIWt`W(bB_tGrqn zY%9N5V5qg)tEE<)T&y#L>9Fwiv@;S+hF+xUE|HY=+y&1ubj87E@FY9)^=)L z-SwiQT9d>AL#-XK%zc#kGM`Mo*0$D*1%_HXsr7E}pmAy)5(^Bqc2UcG?`ETIT@ecm zwRTf$_tQy@)p{ou7;5c-uoE$ zSYW8N->aooMX|t8>i{fwAGX{Fw{B(%Y99h?d!u? zJ8f%{SYW7im|COG_G_fp7O}uk>j*6Oe!g9(p~cm@Di#=O9i>*p)Tm;=X-MHUe zts!E8q1GvCHA|W1rdrFz0z<9S)T(&qI_5cL z&ba%-X4+PWy3XXmQ0pqS+U@_@My=FhfuYtlSngvv*tMY%)G8|$7;0UoR@_00uBp{g zEHKo%0n2@S4XU>8vRc!`0z<8v)Y_FiPI|R=iv@;Sw_y3n3=1be^?9?M;RCV2Q0q3e zqMeH#Qmt_HoXLZs)*Y|b7Td}u78q*X^=hfrKrArSx<{=+cb6C6Zd;?o0z<9))XL$X zdW~9p!~#RD2VSimw)IvlFw}bJ)lw@_eP@PXsPzbz`~3AbVY&KSZL6YKV5s$&TCEqv zORd%bvA|I4iC1fzZLJpz47HwmwbZ&V78q(hgXMWWY->OJC}My!4KUPtPAzi}pjKM3 zz)z8TKwmDLbaNU1%_I$tQGVS!*fbU+ZrMk7;3$?mO1iB zAD$moYmr!BsPzVxyEht4j+DN%ZS5Be47J`;%lt(iwVsOwhFb4nx!1!(l_G9dD`ErZ ze1W0Xdujzl-``xV9Abf?)(2Sbz0Ld>v6HFQKrArS`be!m!?veWYou6Us1*pyz4mVY z@#=wEo5TV`txweIHL>0dwQh?AhFYJgW&XmZTEQDSGXz7eFVsp=v42^$(uoCzT3=!L z1??vD@2;!Mg-sP)6Pf)2~a+()&td;W)5V5s$zT8oF=-lbNGM$Y8HQ0o^g&+A5O+o~iM7;62d zmibI4wfc$$hFX8DWsb|-i?*??6=H#*)?aIxV=(V;sC7jwFx2`-$JMgH$JLE(>#tZ~ zsO1yi^Y_2ZUmR8|X=7)GV5sE_%Uq+(*X~#Y_XpTkak0QqD;TwkANX&STJ6OGL#^P{ z>Q`jbxk&c2kEV+ShFT%072#Qqa%!y>3kyB7ps1=o3=6tF3pIBh16^&Zve5n<^sk1l0 zP%Ant&-0~LMzO$9D+aa9`BJN_SYW6X(;k;OU;8UAj1bM9uNGo~p;jzv&97D@yjp|B z0z<9Xwq=gI^0rnt)S4?67;43#*4Z%QI;gc%EHKoH3(K8h=lwA^t94Z@Fw}}it;{>O zlvnGcSYW6XpN{L#v)xnFiqOnC%V4OLfLe+Aj+>)aYO%mjE8+h+u3}<=p;jVlU2PSr zj-uO&Zrf)xpS7mP%DMkan-SZB`2p? zV5pUnTIRUasvs5^YNdkZ-UC$pJGp#a+iEHn7;2@amif#ywT6oYhFbox+~;NUdx&A} z3|EK+hFWQ;W&ZAxS|`Nk}QEkg#EHKo{U@i0S*1x&8idrSa0z<8gu-x-y?xOfeq%eswqk*y zRz7Q))tJv`Q){YNV5pVfTBbFmNv$s}?dz01Vu7Jn0c)9-`7Bel9*G5pS_Q3TS|_U& zOkFjk`*Y@@T01iYL#;yAGQ^1;^~&qO#$th?RxxTF3$=H=TK&WVL#^V}N_=qjWVL3B1%_HBs8uOK zy(emI5ep2pO2TsYy!qT7wa$wLhFYblH7|BDkK=kJ78q)khUIy_s@wAwqK&gRz)-6U zwaoca%TFvY)G7+y+d5|% z47IAla?jU+h2Q(COLa9|pEHKonL9H+OQ{_;r zhge{!RrCL}riulITD7QEDbbtE+S()*7;4pq%3TCs8xqrAxpQpsMZ^? zz)-8Mwaj(i+_TlPdm~Ic=PZMvRy}JO!n{APR%)@pP^&&HcORP9DYb2@q*!366+kU> zKd)9RvA|HP0W8ngDV1$&v{+!M)sR|MbJm%z)@rf9P^*!(+!;2p_W-BF0z<9F)-p3p z&^=)&wH}EDhFVQvdCst@ZG9ID47Hk4%gj)%DD9oI42D|GV7d2)<~30>+e#%C7-}`A zmbu?htBhD+sMP|N+4JVhye6t(&sSTqz)-6twajZGwZ@ADhFYy)dEU=gw5<(dfuUAw zYMIwWYF!cw47J+8a%UK9f3J-#?F>JO1%_H}sTCq>jeBav?ckg*Fw|;C#}#+z>wm3m ztDsn5sMX%9rB)lUz)-7$SF5#cO&1FcwK{sW)H*5_7;1Hb<<9WMylH3J*jAueV5rrZ zTII8k*{fFKj?N6hP^*iz%sw>t^KEUboLFF})zw<&-!=F1YIPF}47Ivh%e2h>d?R~5 zKTj+$)aq_6(=v}QwT_AfhFU#fx!1#*YX`2*9m>6*e=QamYW1Yn(JR6BtMykbFx2V= z%Y7`*dffd(9@~oA$(cMDYW1d;xkjm#Ml3MY>I2K{4fF5To1LtlT1CVHL#@8ls(0(h zV72Or1%_JvsMY<;=$dME7Yhuv`co_Mh4pjPnkW_+Y7Kzp-UHkpekhDutHlCCt%204 zJUw;}wT_AfhFXJcD`zp4XnQ`(lBi)?jLx`$M&Uhy{jPLtwe*tAGDsdDV*E z+1VRls5O*YpNlT2tyV^{z)))#EcagYN|8U))ha6%7-|itR;-*p9o1?f78q)cfaRXA z#H&s|RBMP>V5l{cTE|0&@KbAnSYW6%ijHeQv<#Qk+9MViYK^AW!vo73s&zvwFw`3J ze~#<3SYW6%mRifo{|%3k*mO@iVkF zRV*;nnqw_%hlV5qgkS~y=pua^th^VLi&Fw|OVEpz0n+I_#K)=;s)P-_`1 z&)0edZELYuV5qg6TIN1Vts`QAq1Fmm?){EHKpCOf9ny)v75L7;0^SWuCvxmwC^jqiwYl z3k9nfGn7+Q)JuvA|GkFSX43HfjwP3k^47Cne%N&<^eC4yPCt`u2)N(yFw{CqE%SYIwMK{qhFZtyxXk$qVOwj( z0z<9i)H2^USL=pYV5oJ%s}<6=e0w{S2ScrsUM;mUhy{jPr(n4=oH=+vnNYS>M=UVZ zI!&#rO*U6nYlK)}sCC9#*oQ&)hoNn2i&$W&b=F$u$j$wsT6e?(L#=bL+-sD%KU6DN zA7_SOsCAxNuS;I~p;lV4z)Gt1%_Hzt!1Wc-qTYnQD0~BV5oHs zmS2!ze%Gw>;FWpL*}wH%R4g#mx=yXz8!lv0tG-xZsC5ID`?@mUs8Ze3>Mj--YTcyP zqU)Jkt2Ie1Fx0vQ%iS9}iq9OS)>^T^Q0q3eK6lO$QLPhVfuYtNI<9zmKfF-uu~=ZJ zb(dOuFE)9n)*rFJQ0w0RIj%VUoU;suTKB1SAol(z+R7>x7-~JRR?ybK^VfO1H!6q) zhFTA;WmaSU9*0`(!~#RDNA|c(%lz)rMcW!978q(hrdEbb1FovIRxB{odSWfp`qnSQ zuB*0nRxB{odTK3mT;_VH)=RO#Q0o~i_j-6`a+#fK1@G^iFEG@4POTkhhP748Pb@Ih zdI8Jb^X7V}R(`R-Q0pbNDm5m%QEHKpi1Iyj>b>0p-tyU+oz)+XN-Qwc@`dI3-q#sB!>EIu8G@l!Flv=4uwbrQIm7}(t>CcS z_fpK?hdpasb;JTgtq|0TefGvWwML2shFT$Exvx{qdnw`UYlm%OfuU9?YMsmZv5s2z z!~#RD&|b$C!L~vSab^gHT4AWQ=S%R|YNZkj47I{~wJz8hmKF;PwZc*B!OtfR)M_gh z7;1(0YF)Ce@nV6YRs?F9zptm(IwK%$Io|AhK-@5ep2pqETyI zjXG`A+AbCtYDKq}X-#f7YiShQdMOqdYQ?aYIdXGz`O)s1=V|(eB(Tp;m_B&J4j&E55bN`7*DUTiDmj^~C~1tpwIG|E_txtk!U`z)&lp zwM=XNK;NXLY-_z(V5pVITBfxwb%_gV-4zQAwGzW}uk+?-9i!WQ7 zXSMQ)1%_HlV7brBMgBByqE>scz)&kGwbC4zQ&z3TVu7JnGHShFw<(oc*Tn)ut>n}? zUT)%OwZe^brU8apDgIBZfLLItm6BR7UqyVWtwM)d-J?~u`!LcdXBuFrm4;fmc3wWCRvNLuP%Evq%$_&zV^^}R z;$nfJRyu2$)x0}A&tI*^Vu7JndRXpr%C)bXuGP1#{$hclRt9R#Njp2VS_{PjL#>Rk z%nZ#6V+A%irq&^`z)&j_wE|<+e5uw`vA|F(vpp`;>T&4Yezii6cFq?VYGt8Th;r5b zsg*`7Fx1LQ#}$|$Ur4peiv@;S*{Jn8L6~7`brcH>wX*-8i729ee78q*fqgKX%z>sPU7Yhuv^273cPC0D9Pqb1jFw`nQ ztr5xQEK}>GSYW7C&>okWM!8%akE-=TEHKn6M6HXfGo@22%vfjgV5n6XmV51ObLwmY zwfw~bL#-mzYQ3`SZ?(#Z1%_HhVR_E*h@D{@vA|HP7`4m{)fy)j7-|)V>gmJrfuUA; zSndoT>|K#atvzCap;iTIRk<4Bfm(OP0z<8ewq<5$UVoLhGyEeK7;06b*7I}+imR1y zymP+5P^+@FOlx4GknbznRz9)7P^*fy%)e{i-%zWbSYW7C6_$IQ?=yRKwyL((M=UVZ zszxpI`8I0J5ep2ps(ZDn+175cz)-6OwanjmQtPf*V5n6SmisrkniY+lucU4L5ep2p zYEdi7i6i6GN%3TCs8!##%zKsD=9CHiXsugRZGea=cY5>bG zsAGsOgPMF(E4x@=sMU~KpUx~;pjHjBz)-6ZEcd!$zF(pw{LJ^g&Z|{bEHKn+Nv)=NN7hzrpjcq2)e4q-zIK1h|5UAY zVu7JnYie!I_5G(>x5WZOtv0ZN{)2s3bH@3wYK5NcOalzH+EQ!j_6(cU$|e>VYPEyq z`B?U~zt`4CEHKn+Pc8HJVbvNU78q)EfaPAJat()*_OT_|1t&Y?(k7c!vi3NsQ zo$PU$c~vgk`JYQ1e&KT?-aYl2u{sMUj7<{G8eCb7U!t0%P{znkz) ztt(=Ip;j+g?mf2o9>*`cH@=DmhFZO;W&ZYuS}~_O=L-zA`dBMyYv6jA%)ZZ-O)N0f z>T50Y@0!mFR;#{PV5rs4>$p1TdiGUfuYs_YnkIJ@~!Utl=ic9 z-iif=S_7?xdG$}QRIRYnoEd_l)*x%StyH#^LM$-U8f-1|?{2FYF@{=2!~#RDA+X&0 zsDX=H%0b+rn)=+BItQF;hS|h~*L#<)3+}B@E%im9`)+VvQP-{4~>Q?`LMXkGH zfuYt2YISLOXr5Z3r#q7eL#>h23OLmNgj!j|0z<7)u-xa$h`zUns#RYsFw`1Nt%QG< z_f~79SYW6%29|q`+ML$Ezgk(@C`PbCSCKecKO@I~jAAH}uNv;AR6WV>)KrArSnnb zJhhgI1%_JlV43TNdHt2MU$6a%?4G|Y78q*Hr(Ybmt~G(CJ;tvGX>8G@nKGFa}OFMhE5Rkccr1%_J7sdaK#%ercH7Yhuv zR!}QnvylF3EfWh2wN_GV#Ql}C)w(Jc7;3GeR^h!7FRK-Nt}_iV)LKogaS0#BS1XHH zV5qeQmb>ROufDV`zTNYU!~#RDwbXib<;)kgCWr-wTI*oBd;a;ST+7tjD;5}Pt*6$Z z@0}Z}^+qf()Y<^c&)tUyejHOP-aKc9V5qf`S|i{hGbxPWuHCs=#Gdv|0 z7-}7)*82t#zo_+5EHKnM1k0Uaq(P~C)QYvxnIRZz9j4ZQ^LOa3hju@=XOCE5sCAZFCrhQSp;qX{&NRSK>zr5XifvU93k>avb(LDhevQkkR@kM^ae<-MHLunr+bSX!7;0Uomie81 zwR(vKhFUjZx%<$(r#Hs7Hi!j=S~scn;9~52YCRJR47F}~wMN@kyk*Wbz)pb%n_h`G&<8WLJf|zzqo&OaK zSr5rF)C?~R3?0`ayFz1_pD`P6XV_U*2!@X9v9-*Rf7w=Sgj(yw0z)f&LMv?CsBHqr z@;ojuw8E#h<*sm)UEvF9fuR*XvzA$5q)9&;s+DwwbH2dP3ZKJr{=YsxneSyS>{y;F z1Vbx)VOwT}Q#hYVu7L7D_HLRM)xk{9EHKo1 zO|4vSMm$vOlUQJ=^#+#R^PTb~RV&3xXG&nG^_E)88n5$MVJ)%1Q0pBm_j&oM@5S2M z8Y31MYQ3jcm#%F$skL7$Fx2`$t#wfnrBN$TEHKpiNUijjt5i@c`6_1`U}#4L!U|_L zM$p&uGh4$tmgkNFLo56Q%kzpo&F-k0(gH&({7ftSS!Z!kwZ@1AhF16mmV31+^keT@ z$MReu7+T?1uN7XjE8H(FFtoyNw8Ex!!c0)>gIHjw^&c$Hdw{dHm3Xx?c`(%aPOUgu zmn2ZDnpj|{^}|}`e3|RvIold378q*%w3b=TmjxT2s&zmtFx2`5%RIi!*Q@@!)||Jk zuVR6r)^BP(j-BwAT4~le(*Q%QKh`oWb6gi}D?ltT)cR{J^Y7LgH!;6j^Th%~t$(mQ zcW)2dx+fMGYWXA#dSA{rLQu!FrcIn0Laj(^o#O&SEnirkt)8}3KrArS3P!CXWB=Ax ztCLt@s1+QRyARtWZvFd`Z7mTC47EZ~>-e}lfoh!=3kK8gi~ zTA{3E=4DdB9u*v|R^;{0ae<*LTXWQ6T%^%e^ZwIadtGp9J{Yir4Kzq;DiYO%mjD>Ahb#+h07{SYW6Xm0De19vQAy)(y_&!B8t2tf0#PzG@b4^Jsu=wG;~swW3oi zZL_L-)LI}G7;43U<=&-C>{@!6TGzw^L#>$9+7dFEk6IBoI>!ZuTCrfcyZ6L|5W&{AuRV%XxT@ zw7}2`6VVFI=TxY5UMw)Q!o;xLJEHXY+l6r~&lQ5975aItaEe`FsLjp{!O#km&vVu7Jn8d&aiBledGrPPYN)j2LO)JjXOKSw(h zSF5sEU}*B`V7Zg;5TVXt$MT#!7+PU^SY~gSeP3Wg=s_dxXe6_&Y=GGA|_UR^reu5gyLz|ab_(Fz|7{r5|)^J0Oa zR(4qK?(J6K+6uLTZFi;thFUqO^)J(y`)cJ93kRg3Z>QnvA|HP04#U%^_I>Lsn!m$z)-6owbG9r zdqJ%aVu7JnAv&(W+tc2tm1?Im4KUOyOs%R52gg^dfmmRuRpkF1*9@`1P^&1l4uyYO zR$CXu0z*5h7%X>hyzBS1hGTi|C@{3b;;=mLH-_0A6?&I54KTFA60}0|Y_3)@vB1y@ zOTu#RH_WrSV|lI+46U$~ZJDc$c}1Veeg}M@w7}2`OIynvgZXU&wRVaHhE`YxRxlF^ z`r4f0P)En|Tp<`*VOd!2+73TiEvX@$^cRP~@L#^_#+(+fG z<&lP|)le)j)T%(O!Z9MORBN_aV5n7*T1PXT7^l`%vA|HP61Cc)0z<9J zu-q%ay1#X!s#QuXFx09-tu}e{HBxJ^SYW7Cm0H(g{X3}EUa`PXs~WZbbh`Ift#4w1 zp&eD-T4qO$F4yy#V|nfSkqdDFrSK}R!gzK&(gH&(tV1jG3HsS@wN8lzhFW#06)*eX zH1}-llUQJ=RgYTc_rKIizt5Q=7;4q`YCW{A7Gi;+Rsgk9+^@e=t;J%2p;iNGnb&#; zZR@UBV5rrQTIOfk)rz~{IW91CmK(ux&$7ApI+o{I216@s?6tyuc7@fY1%_7GgjQ%i zg-@*sVu7I*Hl-Ds_vanUbA@1Nh0VNHc*L&oq_n`$3Y&YaP^~{=fuR+)@LHi`d9Dx) zt*|95bH&Ej>x~a{+2^m!2b}W-hE~{$R=8x>-VJKC6AKKjur)0A`Kx!vpM4z5bA@1N zg>7uhtkC@KZEm~5mC^!3D{N~ma}4Hh>!|fkEHKn+2g`l_dKB=ims*(*I@16{t@hNq zJa%e6wR(sJhFTq{RX$RV{A%qJ3k3c?7N-Au{_T*7+PUhSnd_uyf2!^p5<%O0z)h8Mk}n*xcd*a z;vII@0ESxKVYz2{UaxsG)d~;`47GYtt7W!+QPf&078q*vq*iAC3U}3dEfyGR^`h2? zA}tT9mFb9cTwtix`~S4Miv@;SeW*31R<-)t+A9_qI?H`wxmWBq+rlk#EYGtHhE~|m zw#;MM+%4y|XF1qW=eWSo3j15j5azRV)XF0k7+T=~T4A?(4~jdM=L*4)HIS@|^?YL- z!xh`p0z=0&2$s8h&2!~0d!6qjD+EKwHJFaed|rxLo5TV`ts$_?{k)m}tlf!=?6j?q zVu7L7P-@le{B*2Z8IC!V2Scr4u-s<{^SSz)ZL5t~V5l{mT3_#+uA$aEvB1#eN5FEw zN57`a@*ox`Wm>gH ziv@;SpcQ($;6%Iwlqv+ELT26?D3M zz6_2R=vbaR3Jk4qIxKfb&5pZ!?n%3&K1mA!w&>s5K9kdH35`tN+|TuU7C=&J4j&Yd*E=4|-5gtxRHp zq1FOe?&E9HuG#t2sxKB8YAvMJsp%=lsWn?o#oZA-0$5iuY7TZV|kusFtoxoc7^6F|811Gc2WCT1bd|g zhE}+iR%kx^NUgVGfuYtqSnhpP)U6E$WU)Ic{u$?dfuYuVYMGyrRx7tyV5qeLmV1_u zSHGQKtr}v1q1Hxf{h5;Lv|8Q70z<7$)LIf_h>u!R#R5aE&D6?JyvroDwul9WT3cYb zJ1T3QLc`R$EEX7QZKc+w>cjV|6(|-MYHhPt(AL2Hd=q=VqMUWk7Z_@7x0WF)7A`qa zt?Xifq20R!mivms+|N6f=k5hVE8Gdo-BISwytIAAQCnJIXob6Yg>ANcR%?Vg5=P-~C1%rs6WI54lc(jsip05m@d%%rf#$q<&r&7_yGSa(@ag zvVX$Iy}c|jWF4cH`5lDrUKSX#j+15P*vHEPL)HnhOsl7t1%}SoNm%CRMa|dZWT{K` zg=PM)q%wIhbiPhm%bc6zpHo&>tCUz^XoaU~g^9Oq59L^%=L-y3XUH zwJS77V&17}XOF9$tPl(x*EwsM<1# zb&;$IUs`wU=w*Q+>k=&IaTIi5D`M^M&>oT>>J&vh17Z=78qLLHCTS;pAP!^bYlH8$MW1!U}%NcVY%-)v>*5WN=v)K z=og$RfuR-NpcO7Tu`s+^*~9`vE4&FSsk1SobOpOT&J3NK0v46X1Xt*~$G9XZwd zDHa%NJ+dt``FXc8?oun+MQ2BWq1Iz+J-M;DxLOs&0z<7Qu-s?!iGLoBSF4v;V5s$! zS_Rv;t)|vevB1#epTSBkySGn*tKS^UbMjzlh0kHRuT!d?EwQkio%{u9fuR+?pcQWF zx?#0iZ^QyaD|`vdeJrQgxO=o?d9Dx)t?(5rGeh$ge)!xl73>N_U2@JB7+T?LTA_K? zQ!A}lV5s#5mV2jHwAH*BYE={q47J`;tMczVr`75v78q*1v&UtQAx+#)Z`GP378q*1 zr&g*S`HHJ`NGvea`e0jThIwNj`CHM>@P$}lsP&OrD+VWus#e6y&g8*RD-f1D!=!PR zT~RBGSYW92iCRt8#eAh!ZLz>m>$5#BvzoFkORrRGpjcq2^@UqsqvTL)g;-#y_0_h_ z49)v&L+uRDiv@;S->7x5&zLf5eHIH0wf^&JRkE$vSDeX%q1Jb54M^p?O0Aq?fuYt9 zSmu10uTu%*_Udn2HN*l#t)J9NF?!nowFZj?hFZU_~ogRxKs}Gea=ciVe%XMw!1Usa658z)&j=wGti4TTHE%Vu7JnT-!3&sABQ! z4$5FZM|!eYV5k+3TEDWTo2=GhvB1zBYmLT(Rn#SZX~G3k(D>tps z++)|WtyyA$p;jJhT`lDQMXl>%fuU*Sh2=hfH7j@Zmt%QO0}QP&A1wFzEAxPnIg{#@ z?Y=X4Ftoz_w8A~36K_$gpjcq2RREURhvsYP?%+p~+g2N~z)-6owc-blIasa9Vu7Jn zA#0hIc}{6*|61-&vA|HPu(iyQo6iSO>ylVts8s}(``*{Y>8m0)vaMHQfuUAWYQ-sk zV5eGfA2^c-L#<-AWr&!gzC}^1lvrS>Rh(M+mqa|SRxh!@P^$zi_qy?A#Y|%kTR$1FJ|L)Iq!G@|;Uo0@xDo3qWp<_)}YlK)}s8t@8JNdu0YsFD( zlUQJ=Re@S#di^e`)*Z3HP^%&=&nv)fU-$c~As;z21VgP#)XKV{Kr*$GiUo#Rm0`Kp zUh`e)=)v4p0kObPs|vNkPb_d!t)^mup;lE`?mb(V+J{Pxw5?HMfuUA4Y8?;oiKW(7 zvA|HPI<*Q^NgaHIZQU0O47F-dYvZZ-bJYs@*qJ;SYSo10&hXlwqa~W!R$8&ZP^%WT zzC2o6NUaKDfuUAy+cK*uROj3dwK|FghFW!~HK|Bxf3>EH1%_I6VYz!gPWWFx)Y>T) z7;4p{*2MOUtEhEXEHKon56fIP%=6{LRc|7Mu`~2};!GY4wF0PR-m6qAiCAE$)xaKC zPzvv}#kQ@&Vu7JnLu#4N;8Lr;SYW8t$g35{wt9*MhFXoO75;tFwrb4~3k|ZO zfuU9lSngelxo7)qTT!1ndjkx$T2ianut^Kl$|e>VYPGVK*&F6}vI1?ZhFD;z)!JHS zHL;&3JFiw(vA|HP4J`N7P0@P=52`guEHKn+ORaF5dlgb^qgY_5)ee^XSpF5EYY(+9 zhy{jP?WuJ++VHMwy%!4%wK~A^+#6r*3?n{s&KDSJb);6|q1AJ$m02t>)anGweKoqE zb?s_V?VhhD78q)Erq+(UhjOXaPb@Ih>H^C>U$H}`zpBOsz|W-_=tq)JtcE zV5l_&mb*7jKbsOuEq}4VP-`f)ZuFlJN39BCfuYtgYE`Hf|Cm}`!~#RD;neEgy5=9X zW{L%dS|eb&`!Mg+n~T)iCl(lLjigqzINiRh^;j%0)EY&t{A+eUQ!DfW}bMYqMBjs5QY_=D5r|6`5`8l2~A$_%y@ z?X`2hz))*4wf?2(T~V#9Vu7L76jZB-Qu47H|GD?u3F#cK5w3k6A#SYW6%lUl78#7nJKq&Lpw z!BA_KJuX8G+3|jWS~Jnja!{p>%LfEs5PHjzlYTAt5%q|&J4j&YXL0xI^Saaq)=*Q z5ep2p7Eat zw$;PBEfyGREv4419HmxjE5tizhG3|*?Ef5B2C=|UYdN*f)oPzqTeZXjL#-9|xPrEZ zPuWmSGDonFufbx0q1H-jbsk>6rdqqi0z<7;wq@Q2h!XTGg%NG*gIHjwwVGPP{L7|S zE8Tl%hG3|*##-jM%;)O=XYXxViUo#RYpsQUH|Vo;)S4+47;3G9x5Wf zsI{J2!M6S?qt{wH^_KF3DT3cYbkLA>bHoR8romgO~wUt^iE?tSPR-%v2G{8`68@1jC zto^K3MX|t8Ydf`ke|H+B)SVu7L7 zK3MMFFyG}=>#SH{sI{M3dr#*6rq(a9z)W*47!~#RDYhJBnwzW$vFx0wEE%Ta4ttVoEq1Fwr zR&v{l@YR_-7;4?5R+s4ylB$(MEHKo%Wi5Aa_}NwivA|I4wzbS^%x^EMHA*Zn)Vc%9 z-5Z1E<|&fYwl<3ehFW*2b+Yl@>}tId3kTOZZxDi#=OJ%i=GHa`_| z;tjRtiUo#R`7a)=6Q9Tf`g34=Ir%qZ50a) zwcb(dV(h#v)w(Md7;3$z*1Qczcc~TPhciPk)cOF+^Ew~X?)h|LfuYt%YQ?Re{+wEs z!~#RDK(AH|+v*|~7;1f@mQS^pC)AoD78q)MhGibh=BruNm| z3k3)hFZyBxj#n~rsUK2!|k3=>EryK5g2MErVu7JnZfco5uhw$0z)&j>wbCaob4jfWVu7JnURa)cew5ww-^Bt$ zt$frndtR+1A)LvBp;mrao_k)c(qe(3Rsm|6J+D?5vA|HPAhpb%S8JYFV5n7yT4v9y zbwVsK)GACZv**I}iv@;S#i(WWyjmT^0z<9h z)G~WstyyA$p;ifMnLV%85wXBft0c9|o>%LgSYW7CidtsRs}(zxGea=cDs5Xqw`@N9 zZca-V-0u0pVu7Jn8EQ>?KXRd3b;SZht+KF^%l+Yp!+qbY)m1Do)G9}=oicT(wq<1%_G`sP(ABzs+hL6AKKrD#CKF8#Q*kZ9UM=@S#{>s8xwt z=66)p3LV-xUtp+J8J2t92(|6YBDKAy7Yhuvs>1S<^Hn?1{RV3F z6AKKrs!^+A{fC*q^j;BfY?Vdj-78q)^r&jk@p);uUPAo9g>Hy2#^PR%akE~XV2+j<_P^%-g!W2KA zPp$l7fuU9>SnhMm+?aU|snuL8Fx2Wyt*XEL9;-D$EHKpS0?XZpPd7{&rq)iez)-6z zwdTIq*-NcQVu7JnH)_oeUTKC};UYRS1VgRv)VkTKS2VSI-t=N&B$%CQR5LoW{Ix{Wvezh`*1%_HfskLay z?6PW=6$=cthS}pX_crh6&zYuHbFsisYdEz=zO3IwtwCaeq1Fgk?&HhcZ%no`oGTU> zYK^3px!+Lhh*)5#H42vd_%in!YP}K*47Em6%iM3M6*Y=;zQ9mx47JSthFZDB0z<8_ z)H3%QYBdrI47J9=^1R{0z<7Cu*~aa^H^RtdS7X^Qbzk9Uv~j! zRlToqe1M@55CjS7lvYyd4rvgOZlt@ULumn#2I=nZZt0c|kp@Xc%DaB=`u*2$zmMm+ z`+1J{oVo93zI&~`X74?t4*r?PhFX)Tm9@?8Jf>=>!iHLtq1?4`VBV8PrhZU`4Yj6F zYws`jvzc123L9!o4US8`PwCg>-Qv-~IlQe38){9Xmi+SoreeqU&jvQsnhxcjHwqV9 z-Pu%bRoGDL7i#UO`Rxu<^;Ka*tr<}6Yq{c`&Sy;xQH2e)W>V{yJH=X>TB!;fYR!Uj zk5{#Ag`=3dpb8sm&8Ak;N>gW=iujR#4zZ!u9BSqHutP;tnN?v!t+~{yRD1I>Q`J>r zL#=sG?(3_;!_s?x46cnns<5Hfd}=+t{_R~;^HgC&tp!l-+NiUCMn+RdRAED{h142< z=jvEfFI8bftwm7oYq@yzfA^Y7p1?oz*idURwR(SjETO5=s<5Hf5-4|V^!#90$Z>U0 zg$=cqQY+DcE3>UNSrs5 z4Yf8w$vKqUj_N-)j1ycN>r`Pwtm_iV?5)&o`8P-{1}5~umBrK#wN{WFgZwe~={ujNzu zE=DtzUKKXf+DolC=ZdT_RZTtPQ7E^;%VMDD0 zLCZ_w-!)4R{4;^GRbfM|gVf4ds4VxtwT`m+K_*~cYpAB9a4o2wSJ{myY2%! zn)*W(Hq<&CC^;_qT~&Vvt*|8iql^u;js!~1y!@^zQyEoZL#?Aw?%I&wRb{G@Dr~5A zj9R;2S4n89hbnBSb(~s%j(RxQ)GSrlQ0oM>CQgrd+|;kCu%Xt;|EKj_6*km5MXgmU zBNwyQCrSM?j}5g>L&?{&+~jxZ{1rT2B~@WVtuxfxJLG;(Q;k(&L#?w=?mhOS(>Fgh z)mIfZ)H+A4;v*AXH#JQaHq<%~CD(@BPF!rZ?@4f6n^j>$t>37X_lwO}O`TJP4Ye)= zExCF>|7*&5Q%_Z4L#>O{%2%OVd{ePM@gFa2sC5a-y$85-`cVs0nN?v!t;^K<_4gNN zOqEfE4YjU7$>SxrNVhI6z89RsW~#8E)>Ud%taA1bQ~gz8L#=C2?rXVVztbl>B=a9-Y^ZgMT7%!7t)6*km*K`r@{HB4Pqg$=b{Lb=zkwpn7=GWEAAY^e1YwYs#f z9?ev|6#lh=4YmHJ*6>|zCz;Bs3L9#@qE>_m^&6ThqY4{p{R5R!9xU%Ra?QEC`+{@W zL=`sFdQGh+*~4O*8m9^yYP|`LOIq?fTHgh&-Kwym)>~>FZIWoZse7uhq1L-VNlSib zT7=*|cAS*{na74&?*k=Ym6=j~8r@VDRoGDLU#N_pknf2~_Uqs9d2n21RAED{u$12G zY6SVySMdxmIQCsr?Nwnztq4%=by?2gil8-K6*kn02<2Me_nC9w)HYSvP%9FYdrgtw z#l13U-BN`OwZf^@zjupbredY?&pbBNiVWpmE7w(@m;PbU%Bcz)YDJ;exLO(4o2sD- z8)`+RR@+NMV!jVrJyc;st!UIbJfL!UQh|tP_8mcMgDPyO6@yyG$3z)x z>a8kls1*~+JzhVq*>G=r&?=JJKl9j7D;BjP#QmwOsa~qEq1FdMORnB_w}vD%wN4c_ z)QU~5^lA6cH}zB%Hq?p(#SqRAED{c+`^LzhUa8Dr~3~A4(oCIfqF$PW;|f^0fYOVMDEts8yw2o9|53 zRfP?;5tkw_InX7Csf6kLeRa1mLD;1QSL%DVP`_oz5f>t+GsZz>UM79o1 z8+BLs-*ib7ywX%e_NocCODr~5g;s0qZQH2e)GE%Eh!qKy>bxjpE)cO?4 zU55#$M3`(U{-^%gz=m3xsC7B@h*hRatHOp_nW5Z!fZDNtt#~)MHhQVThFV#u^>^vIoSYw-QwcbM9v z3L9$W43xyWwisMO|r={+--W0S(sKSO?`KT57>n!a}tx|;zwZ4Gz{(|ov zcITfrb#u@a{9tsFfcoqqYu4n||Rz&`OrYKl9j7s{pl5UhMj> zsj{lDp;kdC?=QH`9s9|H$3d%$Dr~4#$OCpAMqimEjj741u%T9AD0gk#&(QnP-k`Nj z6*kl=LaiK$YEL(HMHM#GDoU*>i;|7{H)y?8g$=ceQR}-}7v`BtlGQ)+*ifrDlsxxF z@cy%|^H+tA1g*TPu%T87YCYOIV3etjs<5F}NhrDIr6s@Tc74!VtO^@ym7~+h8iEDr~4#j#^Fb zHpybDhAM2R^%azRt-N1l$YN7HRbfM|^3+N)`r;K+(^O$YtqRn7aL` z%Cj%sG*dTKVMDD-Q10;>Q1xPeQ<1a#XC51BRi@UM7#qS(WmJU?wW|C-$MuyeY^YV0 zTC-~uV@?4(}9* zvD(xLRoGCg2DQpR9$CuNQ&redt0t7Y4nNMYZiT6MIsC^98*0^}R<}k+GnmS$3L9#D z6STs-oBWQT+rc@kt_mA!)uz_P@AFqPHCPok)T;BJ*3qD~Min;Hs!Od}qsA08^+**q z)T$S#Fz+TmKa3ds{4o7z{yD^kTJ-}Z?`_6xnS0z+IaSzDs{vFrPsmOF9(|;s)m9ZY z)M}VA^tDp{ED2NNRbfM|Mo@BX$ZbmA3A5h@=Wwg4Mk&3|Os&T9k>F>Q^3QLWx}ypk zYBhn9*AzJ$3u2e6XX?Yx{d0&7wVG1v($?wuOchjx4YisqE@QoF`JqCS`{|bY7G^79c~D&jS;G_p;jAe$+cnXh$?KT)fOskn18#`;%uGB z!EwdPelCC|Nb%bRK8;qaiX0(@ns1u+qs*pO zs=|g^9iiOwe8e|nmzcV)3L9#5qSlLeosXD`m)k!Z*ifr8l)L7K9xMKnsS>KNp;i}a zZP|9Rt*LIRu%T90D0j^#8l5R))ZiR0RD}(-x>0NRxx&*-ol}JkwYmq#73SUKHRV=t z9Y)IIpABrN)q`5{d!$X}P=yV(dP2$LCGP>wZCKd)QP8TZ3L9#DN39v{(k3(2TNO6c z>J_xSRG9qzl$Swksw!-#)tg%Kdjd`ER)r0<`asFommJrpSu;HSBWT@Kg$=d(QY-rQ z9gR(WnAbn^*ifqIsMViZc|Og!#8iD%*idUgpu)V{*Bx7KN)cR# z165%|t$~4(S0ed6(xw)v!iHLdpxilp@$-!BX@b^qRoGB#Ftz%Y9o@rJjC}q%#D-em zL&A5q1I4pg=Kot z#MCNP*idU2lsm4GaZ26E5VX#y!iHMIsU^SH(bOwd*idT(lzY66ZXR1KUC>JUg@5L; zq1H%hm1(%(w5cMhu%Xr{I<88oXY9QeT=Pv;VMDDSsWp31wu`3vtHOp_ql1=Qy(QA* z7;9>(Dr~4VhFU8p48CD%qbh8uH5SUfrc^B6vx%v*s<5HfPt@AjY574@&s1SUt#MFt zZOC!m?fm;$Q*plZA1`dE^)t1eM9A0FR2Eg(P-{HY|30p=s<5Hf1Zu?^x@EexnybQw zS`(qWvYE6am{({$(;(z?x_jGVvk@NeH7dF(IMy*Sw#_ckdK@~RCnoh0f zl`^$E8MMl%!iHMEP^;AFq92=TrV1Ns%?MPOca!h+P6Vw1s<5Hf%s|Q2oATP^xTa>R z!iHM2pfY+Qg7=?HyX$=TW$<`ySA`9=W<$mDgtRW_oLbV$~VMDFC)RNy>Z7RJgY^XKwKdlx)>q}MGP;35wTBa(i!iHK4pxkSUypQ@lc)Xga z!iHK4sU<%bH8n^THq=@KCC?jjllP)mgVsz{*idV6%FwUn5-Xa$HMK((Hq=@I723KH zw63VahFVLhwS89h9;V)^!iHMQsFk)(`W$tF$16!e|JuNYTFa@`d3WAFOx09{4YgK4 z$#axky{pD;|IXAnRoGB#CAEIpHFKM(ld7{k) zGMTEN3L9#zfpX9DmEQkUp>A*vN2tPvT5GA*yI}F^ruM7ChFa@_;|lX`LozI#TRUil z750w{8)~hm)}dHcZ<)%i3L9!|fO3yl$J3({m};pC8)|K&)`eIzzcDpK6*kn`1SMa~ za&63&LIbye6<>j<@Wrn-2?)W;?Kvw;n@jzYO>?7{bQT@ zUKKXfI!>)i|0E7KwN({1)H*?}&W#$~F!fv&Hq<&9w8Few*Rq)l*AK3ZOeOuZfep1z zQL9h2qu-lqt_mA!ord!Mg6H1jtyiruHA@vX)H*}0^c#kLW$LObY^Ze>$~|6VH%%#E zDrqVIxUiwtIcjCTG$Wd+TB@+2)_JJVujK~8IUKJF8*2SVt(ku(9B=BlDr~5A0ZOiU zx$XZkQ{H+(D_Uv)xUiwt#gw7%4-;%mI>1x`RoGDL5|kX5yjBkHvU8lN_NuU<)@5o9 zPxAeFQ*%{eL#-=N?(zDkYWaMoE~vtWT34x+tYzhxrec@z&jvQsx)!v;yxaH>!VlC6 z&S7y?*ih>_wPNp!x4_geRoGDL29);~oWlf{H-2vFm?~_jbrULlU?U^mzH$)ErgVQ0tGN<=x4!H6^q3`X)Gs_f=s-t=rU^ z+ON}2Q`yS-$At~G?ojLQ;rJVC2Ca^&u%XsnYL)w_^}nW8sKSO?_n_SC*U{;p)iCu? z6*knmPpvD{_Jo_t{FQ%P*ih>MlzaV}n|2CL#>C@n$a@#SEd%J!iHLppxm|b zS+}3JnYybA8)`kK*14E73!BPN-ajsEsP!kc=D#mc%2abz*ih>UwMKpadB{DSrwSWt zJq=o6-tGCB&Fd=$*TyYX*ih>kwQ61H@!C|X3jT3nL#^jf?%J5s=5>5i^;BU)trygK zIB-e~Q&Ux8L#>xk?(tfiGkbAU7gS+Gt-q+%ws5WzrarFd9~U;%`WwolL*URoJo7)EHIRQ0t%IxWc?!%)9CPRtQ?Zs=|g^uc?(YaGeKYDJ{h zkuAS=Gqp?=Hq?p~w8FgG@L2CoRu8U?-&J8lt#E3|>$0g-Rs6Go4YeXexv%9~Yu~Rh zRbLf0)QUo_-mz+&F*RKkHq?q59GAS0lGkNZmsMdyt!UILx^qK4Q%S4($At~GqC}RbfM|IMjOhZQJsu7OTRBT5+kB^L(M9 zrf#UhhFTv&xv#Gkza(95Dp7U+Y+ysJc+?vFO^?#1DyhPTTJfnh=H2xlP5qz>8)|(- zt$$v{dTVN%Dr~5gAZW?85gzlwxGKT5@j?|g)JjOL-?R35WGctk{@K8WS|3BD^g42F z6sWjskg3+Hu%T8WYMuS8;WJYURbfM|#KCb%E6#x|)lL1O3L9!Ap;qhINj8~EUBf>v zY^aqKD)ei)YH$u4sKSO?pHQp8(hhx1O;&{swUR-(?<>z-9?+(8&^o0G8)_w|*1XH< z>zj&F(?2e3sFfl(E;)xOuI?Ca>I+raP%9<11~n~S$y7U4*ib7Kl>7QBo2TO)Q*%^d zL#@=*x}5uLJyXA_!iHLDf|hq!crW@@a1KAH<(~~~sFjvl@?O+bHC5P9D;<=3{gU^h zrY5PvhFa;Vbzn`ZZl(ihm z=P>QYmfw~S&f!{B*ib7IwdBtZHuXvsHq^=t<-Y$KQs&Eqrt;VJj|&@WWueyM>+@ci z>aPkLYGnt zT{Tl>RAED{T-4f7v*UYHLsVfyt=v%Vd1Kt>x?@c3SA`9=@=)tS)S8D(MXu)`7dF(& zORX0dUd%I9LKQaD%15n+sjHqgHAodU)cOL-JP35oepABrNRe)OQ-pqMos;4S!s8tZkJznzfjhfn^3L9z_qE`Hg z1G<`esR|ov6%LL|zP{w|!xjt9Va^8rabZKPBGi)KV`i$IDr~4#6v{nbWrv@cRU~LF zRD}(-ic#ygc_}uUx}pjjY84NTOP-^umVCX<)Q1iIQu9@V2Q;tx<&ywMs*|b12t*>EImRQ-uw+%1}%G%pg-48u@1f z8)}t>a@YLDTmRNH)l?NW)G9}4GEg$=c8 zLb>l#B2Ua;phWO^jZ}pVwQ5nT#?*~{OdV8(4Yj_Z*37oQlqngsA~o}m3ma#P!%@Rsskn0p*&uBqAqJY*xZ zs8yd@E1L|dXDUN;|7>7Gtp;>l52I$;VXCnzY^c?cT9HpS{>RjGRoGCg5gk|EVJB{x z`b`x!)M`wvHtkQeFcrUre_Ys5s|l354sTt)+r4;jZB$f+4Yit5>+2r5!c7fSg$=cu zLAh(=eY1`=Os!Le4Yit6YxdHgrklF23L9#*fO6Nyrk|Q@GnL|7|7>7Gt#7H7 zrmCyLhFUFymUqdA_1V@cQK8@*4pW5@#s<5F}M=1Axqh-$iUz*yW3L9#5qSl-(n_HQB zs|p)xbqldnQQ6?RoGCgYtWK&n6~H61OeXj}|YW0M2k5`{I z15%pWs|p)xeMha4DHnvCjYw_%7VMDEcP-(sEB7*my2@%dGIUM|R%Z1wcX9F8* z^`}t+ zwFXm5j>}Ydd;e@;L#^)vC0}3i@3k!mzP>W6!iHKu1WKL(dh~c#(NtMg*idT-R5S^B zw_{aKylfM+nybQwT0^PTyXBH`rbep5hFZe{C9R{mbChl!v{tFYhFZe|CCBwkrur*P zomGVmwMIat^n|F*rQW_a^-2{s)EY^x4=Voro2g_S{KpF$YK?+&U(20#Mo(y}m?~_j z^&_=1#{IIEsTQiRq1I?9_daUy;^Mhl1?O<2Dr~4VhFZ-g&rD`&xhia^HI`a^_uu=b zWzagV3L9$uM6KdaCMPxZLKQaD8V4okP;Tbx9RA)S5!A;~$?{Wh$(bf9A2F)>J5WTo0Dc zIoK&^rB#IuwWd*P`?Z{xO%+sy4Yj62x%U7~()5gP>T6ZlQ0o_J{l05QO;hbvVMDDM zQ0{BFYVM}ZObt_o4Yg)cE7!J-y-m$gg$=c4LAmGNLygC_>lK{CZK|-L)@*8}9MSQ- zsVl0mq1GHI_kRBM%dA~Yy;X$`wdPW5*yT38O(pB>UmMs^YaWz4hesNv4>_(vs<5Hf zd}__j)&HKg8mPjCS_`1uIg~%|W>9br`>Vo+S_`SQXXN{DOwCe-4Yd|Qx#x{HeHOnM z7_@e&!iHLlsr7lO#-~i(P=yV(mO#nZvb=sJjl61@sjx2ona74&OR2T}dFc|SQmMj* zTFao^<8^gu?$)M?sltX@%c+%X*qk+{nyA8tS}TI%ir^iW{JWezf^#@n6*kmbNv-gb z+mo1@uL>J#t%7pb#<(%#KkOH@4yeM0TC1rwq74PuDI;P@v^&e$ysI?BtJzlM+r@dqF1@8)|K)*5_>| ztTMGw6*kn`0+q|_$k$itk2~)*wNn)~)Y?j|!!66UHFZ%HHq_b%V+z7 zsI{G1e?(}%%v9`d{!1(^satsltX@d!X`pLR8Npe?~R+lPYYewU=7&Zj3r@ zYNaY{sI?EuJzfRR&M#`}m?~_jwVztOtG{S(>X9mJsC59!y^oTAzPDR&4r6uqA7yN) zb&y(LEG)9!RC-m|Q0q{jyioAnO-;kU9 zuB!e)tFJ0-sC9%|y!F!f9oHq<&ntzyp>#4;7LhyN&JL#>lg?mDcL_3zcD(yGFSTBoR0Z$YD! zrV6UUhFYhCX0gIsC5CVh<8kKOZIeI z%)`MsyrBvkYF(t(n1lmIn)*u>Hq^QlC~0NCx904TpcSL1e??(Kt;>OuGoLwWr4*(z zsKSO?SD;dQLR8qWtdUF=SA`9=u2Spf(r!CUHByBQwXQ+Audlw16&HC+`p)VcxXu8r8GQbjSfMHM#Gx=F3sOEQL>!waggq1NxzI`A~nd~5x!3L9$O zqE^l>xk{T#@SXoCV?(V!phBN}4+YmoPF2`Y>o&FI&p|L%Q581Sx&!5&dt-lk`p&_i z^{pywsCAcG@zYj%VQQc%Y^Ze)O0EsL$?y6Y7qq6T!iHM+sU^QN&D1Vc*ih>Ml>6R6 zeh=q}pmkdnHq?4ZE%|d)O}$fv4YeLY$#p0<`PtWxK`VYQ|53(vn}sZy%2q1N9}q1WM*p!KaPY^e2$TA3>?_|4Q%RoGDLA1L?rwW!gO zCo6*10#(>h>ov7rJ}s2n)E-sXQ0om;=runwXkAr>4Yl4<>*AXXf17%%3L9#@`%i03 z&`R9Lf4s1v)_ZET|20o(Q+ZWkL#=c*%Y*5_w}z0Y^W8DTJpP{P32I9 z4Yi^NEqMkQk>cX_rmCpIhFUSG)vNI9`=+|6!iHKgq1=0$-c_D=Gc{2aHq?qmtp!Ee zFEF)P6*koR0Lop5a&2r0&fyhR*ib7rwQ4;dIoZ@xRoGA~&VO3FgI0Jy|M9|xT5+kh zXMT(?O=VJr4YfXma@WSG=E;j}4_cK}VMDEW)RN!7Vd{HT*ib8e(2{H8)uC>sO>I_% z4YfX^R;O#(zBKhz6*kmL0OhU?`TZNFGWPe+AvV-XNUgHF#>F(%KovIB`Z!SXS}E^0 zb_VBgf+}pNl_*ehHstX#wMP{;)Jhy2m$c-4)GtBnPgU4ZD+#r}7`XO|sRRT3vw;n@ zl0v!n*iUY!DY`3YeW?l?YJEa2`S&YLHCKfVwUR-}btq@!+tcqRni{JL8)_w|R``P% zT}^FQg$=b*1T8s-qd)km#^B(%9;m{GS}Ca|kC&-r1O0P|4Yg81$@dNsy#MrR`?md% zpjA;7Hq=T@t)*=W^fA>{6*kmL1C`S2$T>_f{lGy}Q&nL@t+dpt_t~w{ruL}9hFa;M z+~f6qqk$PsJy3-WwbE1T$4^omGZlZ3e-5#sRt6~dwY=)mnmnfRtHOp_8L9QA?TeD8 znyA8tTA$K!19wRAED{%ye8uerUbd)FoBeP%8_yMr0nB zz*MBc{yD^kT3Mme>a~%u@aZ2+Wmbg^wX#ubQ1%B&O;uBc4YjgExodt_x4!#^2G@Kq zRoGA~2estqY^G+b!iHL(LAmR2`?+qpOdV8(4YfX}*7$!LL^kzA6*kn$Nv)ZwTTL{T z=zIUnV?(W6)apJw;@75%sKSO?xuM+O%Z{FGaeY(Ys=|g^d8pO--utnp#;C%ET6v+| z*VojBUq3XpQ581S%15nJ{T`k%bzK!U)cS&2JrhLRYAV_f{yD^kT3=FYa<$UWOyy98 z4Yl%9OMWhDs+KBjs8xVkXVOF)WU9X^Y^YTb%Dq37?}?U2jO=~2$!(!3Y^YU;TEmX? zX=G}LDr~4#7)t*Bm%OIDoiwTc^x&V; zRD8&c z^y-Y@xcaKXhFYblwWj)rqNb*+!iHLRp6L#?t< z?mgT5DFfro3XbcpDr~4#j#~12ZcRlS>OacZQ0prw_uO0Nb)r9d4L#?l&QhFVEyoS7w^2StMRoGCg2DOe)o7mV?7gg9$ zt7dRq(%L*URS{DoRbfM|TGWcQd{Yfmb5&tOt#6>*^St~VU|Mhvx2nR1TD7TlwCuz8 zrp~LvhFW!?+;h~reDSO944yZhs=|g^b*Z(iM(x(7q7C=24Q!}Y56V4WV~DP;y-I^Np23>%J;%sP%22Xx+vnp(;)fOuB@hTX!@~XmyTJ5MMf98UzN~*A-R{Q_7#s|+)%~fGTtq#H2R78bV=9p@sMUj7E0d(^ zWva9)Y^c=}N}hY=_SdVfck%?SMyjx()_2re7IF1bQ{7ZyL#x*ifrC zwYuGln$6T~RoGCg&wpBLg4QNg*ifr4wdBw8Gj&uIHq`0|<*s@8=h;>Tt?R0=p;mut zJ^iIic~dV{VMDC}|2eJ|K`Z(w|2o8mS_7#SbMvoDOeI%^4YdXZO0JDtu~$D|7qmWC zg$=a^2TGm~Pqt26*i>;<*ih?xDEA)V*W)d^nyRJ>8*2SPtYM3f)s5R{WX-!py4Yh_-t4FdeYpk_Q6*klw0Tue1@@4R~ zyh9Z>)EY^xshOulHFZW6Hq;sw9G6@h7c%9qHYs>bxvL5rYW+y9de6#yW-8{7{?&^O zwMGXmxuRBoak`_atg5h~));C<`S7c)rmCpIhFW8x-21~-iBb$T)m0TX)cT29hfg&w zU}~}|Y^XJkjw^Y~u-vA$sltX@KU3?`k_r1w-B5)MwZ{KH#}#?Bf9A2F)&y$3eLShD zwLVpa4Yei)Ex9)2?@3J#u8j(+u%Xr@YSpY2_fJ!;RbfM|$x!a~D|5Yr?^nJzg1?_djZ?lqzhfwU}Ck^DeAs>Kj$qP-_X4d%O~L zy%VC^sKSO?OR3c=$NbvX>Zb}DYAu6uKNr2-dE21;!E5DDs<5Hfa%#!<4yG2V!iHKa zpfY;bh5UT}>ad$*76y;k4prDtYbCY*+<*7FsdK8Zq1GxWIfrtS=icqXd$xzFu%Xs! zYHj#1cO6qPfAX&=Y^b#+I4)^bZS%Oo)}ZyNDr~5=mRcRB#aV2soGNUnwJuQ7>U6bo z);&S1l`3qgwLVbt&Y|9KTdSJ-P8BxP+7KvdU5~S?>$adZOcgfN+88KlrMp^hqp6ju zu%Xr_s9c^9)$2j!W~R=m!iHL#sTHyR^75wMtHOp_TcF(6*P&c7BA7})&VQ7#q1IMv zZF*Ecm#K=Xu%XsAr~=+G$u+<9t1T6F1?RAvDr~5=omvN4?I~(%geq*PwIet#FBNv^ zuSPo-1z%q?RAED{oz#+lp3T%sRoGB#7nFNGTvtC=ZBsi{VMDFm)T;gD>1b1@RAED{ zJy0pVW0Gs**820SOx;q24Yl@Ct6HfsuT1@=3L9$egL2o#`Xux7n2PqZe{Enxt^L$W zJYwQFQ%O`|L#+eUl7CLmR2Eg(Q0pMIT4qihat;fr!iHLhf|hp*!;S(H+Dr~5A7|OjrELpL@BU2+(VMDDW)G9ovVmDKZRbfM|qfqWT{Jvn{ zWu^|P!iHMMsMW7=->atXs=|g^$Dz`C=TE+te@*ktS1p2b7@)?S@U72d#3du%Xr|YIU2KbhxP&s<5HfX(;zvd8_>HUaf-GAXV5< z>kPGCtSd3Z)C^VFQ0r`PT=KR2>$M&+O>I_%4YkfuEAQe#c}$&Gg$=dNL&^I?X$?5F z@P(-ts<5HfZ`3+}JJ}LbA5QQeWo)Q*0m?mZTq<&Aw5e>Wu%XsPYW?|U(|A)~sltX@ zm#CGfLHt6dzEy<{wJuYuK;KtSOnt8k8){t%THYxP`{d!Uhi!suW40=6sCAWE-S#}M zU~0E2Y^Ze&O1_rm_V49nm3IfPl{ZvjL#^x7dUz^MT~iSz`i~bj)Vcvx#Ouh{a^?y@ zH!l$!S4vgbQ0peOA`PCC+f*J^*ih?tDEITIK}}+B{WfTQr3xEr-J;fz=mA1`LX3YLqH$sC5U*J@;m7-!qq~xvH?C)?I21>78bR zsV%Coq1HWW4O|mxhN)Aku%Xs{YRw*epn<7-s<5Hf18S}KsPbl0VUzqT3L9!Yq*mLh zzwI{lu_|n+^@v)fllR_cDw`^7sP&jy@HgJ)ui>QyW!bL#-Fo z`ndGz$fk~~!iHKesr6UuGpkJ9R)r0<{-RdA?>;YR>YXZVsP#9sTK}G}pQ(=~`_~~h z)Otm&RIB2yFqK6WHq`njP~Oua{$6(L;5n*ch?=HO ztHOp_|3b-gue7dr$d+w=@cQ*Y6*klgOXIyi3I6@BY)M9JFcoEr|0rWatq4%=xi|US zn`ca=RD}(-B2uf*rFDZ%6;Oo@wIV^e=Z)P@F2^=iOBFWM3a3`o1j}EV>Y@r8YDErO z-YE==li|RjO~E-FqY4{pMWI%_qwyn~TC55iYDI<0AtCQ}|Mt2j1%hj1k1A}a6^&Xa z_ZRMM>V_(8s1-d>((2k`aLv3y>%A&$s1+knkvx_6i_KR}C7J498`w}QW}u`cze93f z@N$RO_fuH4YfXia@Tz7Yuhvb613{8!iHM0skLS1gA=B@sltX@ zaiG$A_fGEN%s=yQG&M>UHq?qst>(>+yfZal6*koR5XxQiHOp;nX=;ZmY^W8FT1#r= zYH#W{RoGA~K9qdFEYBN5=O3>*GdPD&RbfM|kEm7j#I`4<;!g9g4Q!~DAZSJMT2p2v z9A+w;Dr~5gkXrdu)IDITqAF~t^)Zw?hs(aaU)EGRRoGA~5w+TOIu*^-kE*btR$?f* z4&^q!WBlrKgLAlC6*kmLLailS5?V|RZ1v# zggxhdna|WqRkC4~3d-HXZn>k6HWlX={~XFDVpxj?Z5x#@UOKFecQpPP3q8`*_&kI4 zNUJa2a>71O2K_v;;d&Y<`TG}g%Na4v5mO^n$%a*0DF42Nh0S`E`H895s$|0|9aJ7a z71lM`+%Bf#&G0{)Y*?j-O0H^B`z}*WeWyw`{F80RBf%ln=$hPQ(w>Y@3U-JeG28S)k^hSBCyxHdR2CY*=N7a@Sabb4k6w;o$CJJyo({l>^Eh*R+y{j+*MMN;a%MgK}T* zCwm+UdA!D|k`1fRN!_`)xw5qusFDqJ=s8R{aY4v+ zcwUukSmh?wY(o7P*7{48Y*^)ia`$lEfj4(d#h>jzBC=tX7s{Q(mNOTGoWm@tWWy>S zlzYyMlIG1<)+(k-HlAwSxw9UA*cVVa+{NKOjQ?9#6*lx*@Fi3NT^D*7ZHToxsFDre z!~9V4PDXBNNA@pkYNjgLuqps0-^MrTA+SF-PvSC#m>PuDiHzp2g6`JSYL)ow@0aZ>_ zfz$tdZLMEa$%a))sPw9$tUXx5)O%I3VO0t$ud2eg8izcKc9`$qL)ow@4du>8g@FgQ zS!*N;a&@Lb+GH1wFfuG*xVYe-CBDsvJ}fZKY{7bcCt- zs$|3JD^dryKWT01qlJD;Hmu4+xv%ByW6oSLHBgmoSXF>>UzN3B^y@Np}f0=Tj#>HJ~VY#m2CX;lWs|P*a>f$$@@96~rG85`tZG3OQsC^4IbXbdy#bau$L;?u&M{;uFU6)yLhkaPF+$Z8&>t9+&%1F_4;8`iI@BL zP&TX@K)L74T^>)Rmp}`b13&J+%W0tccwO~k`1dCQ1TNaySZ!QlU4pblntwIq1@MU;SXz;vQ~Cg zvSHN{%Dr0swIEZ-bKP`RvSHN<$~_yOi=8;FwJxcW4Xf5rrS+g*7TrG4RN~eCamj{N z8&YW>wD-P+a%ZEaD%r4V3+0}pl2^O5$JBULvSHN@s=D68O+Wk{@~-K$D%r4V59Qw1 z?bteFinZdb@sCS3tU5rY*4CBFl|o*H%d3(NtBz1fRCP_iF}AgatC9_?PNbeEUQx-^ z9#yho)fvhiSN{kPy*C=}%)eD78&+LN6`Py-lBv9F{j(t(R$ZZL>v7$V+dV{eQ6(Ez z-Jp7^`ljzV?{vC*xI&d|SapZ0rD{XHTQN;NR3#f$J)m-{>Rz_T22<(R`Nt(2Ry|40 z|9#P?rkbjf4Xf{<+}GE@=f$s^nypGUta?FxsrNAd<;-rtbyU8cIJk`1eVP}#I~;OyRz*RQpz zWW%aIl>0f`tRMHbwAM3KvSBp<%6mz`?SA*AJxtZ!;GYfIuo?)JUsd%VS9*u&&c<|A zvSBp{%Dw8{U3ty(PF++b8&-p%a%yYu^#;vNCEDoUL)ozU9_lkybyGh&WU7WL*|7Qn z%H6|vQ_>|f^|LD3uo^;Y&%7y%O`TFD8&*T1+;K&IKO^L;GVUh-xMag>7*s<&t`*09CSK zH4e(1!@4D#UNyBCfoB^y@bp-SjIEIQ=7C8la_^^Z$7tR_Ht zZ`5#`)ARJlrhZZ-8&(sc-214AXQFvOZgh|GGgY!-H3=$_wweqnyvx!4Xepe z-rd6OKsrn;bvk@L=N zuSzzorb9K;*2t*egdA7??f%)24XagzphoA~Evrn2quk4rYJW<%vub@cmIg-x|oB^y?A zpc<*#zd7?MQ*%|xhSgjs?q?-RJk>#8c*uv!G=&f&Tb ze(7i`F_o7gfoI)p{uR zGlv`zhTb(5bFY6kWW#C$ly@27Hmq0!@9w#K*i)5kSZ##*T-C*cFI$8mFMOqWtRLL)ox83KdV)xs`|Gno6TeHmr_8x$mTM^k{g%R9RKBVRanJ`$h=2 zuPTrD%TxzdvSD=s%6+ew;P&s8O^sG18&)Twg1=)}r|BzGD^$sb)hQ_VUBKnS>9?Bt zO_gj|orZGvF!lb*-V3|?`igYeKl8F-b%xZ6qI>t6N~20PtjNhC&DF3rM$`{sJs!BGjE2;Q zBUQ3tbsft6^!vr*D&E^1clAa;>YokSu(|=2Nblk8#J8fDDy2#`tZqWN*X4xuB1|#W zO_gj|{SK8)TUpa=_ul5Xd$?AWY*^ibN~`Lpa<5LCN`1^fF4?g91Il|b#;tnueBO^A zT&tlf*|53|l}=T<*cU>cH-1qi8&-Fq+}Zf>@qO>1bFIs&WW(w%l)HyVHq5GND(P|m zxMaiX9#k~FhwFYj+`?3CRkC4qAIkg26}P6PZif6_vo5M+!|DN4bX6IWzX|!t(rQ(* zVf7Ho9aojr#X?>kj;fLkt4C1YC5zkm%vnR;rNlbnpAFftdJL6P)q!p`m&n4ul~W}f zR)0ddSM#R_qYp7POqFa{J%K8xpZ#_Ij&n>MR3#f$Podni%{LndPBWF|q<>tpVf73u zwzg_4?>pI4c~!Du^&HB*ru43qc#Wxcs$|3J1(bVDiF`8YT~p&!$%fTSDEExLdgG>> zrZ%aP4XeMPlIU@joqF*TQ@^W{4XeMQ+%sG6NfAS?`43O|=TJ7RUO~CDv2k$Dkk_x` zs$|3JA1L>JJ60lrHI>`HA7pQ+N4T0tlmPo zYom7a&RtDiQY9N!@1WdkWwyhmy)QNQmGV}VY*@XAa_@*9|9Rz!sg$SvGcOxf|3bNU zmC@fsnro_%D%r3KODq5OnL8UPM%G$ys+lU;u!;cX9gx|yUN?0_m26mrLzPe!DeL*{rm~+2$H!&EDl(Ki8<7h1sbp%L zD%r4#0_7g%=|^jY{H$`lD%r4#3e`#PVb@zZ5dM+I2P&TaMK*iL@YigT8A>R{a zRwWx&aiQEh^VJ*s_pp0dPL*s}eF){w;r>q&b~M#Vm26nWgL2OsGt-UgV``!**|3Ta z<<5Nl?6X5&9X6_x4Xcl!+$-$Py+{AG)&*6vVU+;N9oG-9Y85s0N|kI_C4_Q6-{^Dg zT*y13Waq>2h{%T3$518o@ru}g^*7cUs!BGj5<$72_VkbQeaLa$RV5o%iJ=;4t5cQT z-V3{Xo=@{zI6f{LR!N|~RrUHq`4d~6s-sFatdc^x_W&z`v;~Lsgez=v``&XwJd+`dsDYm$%a)rDDRs|-0DPZIn-2%i{bdFY*?j-il*xK z&D(x4)m)WqSY?26&xc#Txw+X?KUK0}l@Thbwz}n9w!qXfRkC6ADXIPoJBGAgsFDq< zOr)w8T@dm;(HED(aUW#EDl?S(dmKMTsIk=UVQ*EkVU-2SJ+t*~k$=CbgQ{f1Dl3$` zHVVC%yvfvaRkC4~jnw$P4eFW7bvYczB^y@RNv&?@ven?-w?QG>~hz`aSvs~ zDnFDvuA5g&KR2~bm26lQAXQ>Q;Zdei-UvraHhzDE_mQ{}{@1?&Q4pWU9clha9YcN^ zHcLN`Y`9(sDkUo3@6TMYwuviw|MzA%J}w(pg`wP$u56g*XH(r&$%a)CsL!=kd|jW$ zrf#T`4XdJ1U#hC!bXRs$m3|M$$7RE+7?e93%`y&}V`_~m*{~`Ol}B5nelFpiboaP_ zbSoSmmyQ3i9^Oa#doSzW+mtZ=w^2&q^W@OaQ+eEgMb3Et2ETqD*>Jrilsl{Qwk!{M zWsLMkI6j+f{CYd@BPaf6y%c?(H;31UJRg3qpGP)aFAe1$opP5aFLb4_uqUcy!>SBa zQ$5lGzwHaT&-HJISyYaD%r5A098U&^~7s0n5uF&93PhrtBO!%R3-kY z(PUGrRLO=_C8(jQD*w^CxTz2Ch2!J0VO1H*`*OvtY2Gp+uU}nN$%a)GQZdTj`NLWl zRLO=_Rj3Ktdh$=4XQm3?568!4!>SsTyN9tOznyDpmMYn>st)D8-Z#dme$!Os2jOVR zhSk?l-YLMX(XYosj;pyU*|4esq8?*|4eu z<-Rws*f*kgXWc#QtV%Yl>O#4DxcUBPk4%kMB^y@tpc3hERr|F^$oG|7Rmp}`eNsyw z964;Q2dZSlssYqT+WKgD&XAuuBz_c*kIRNtLnwDPhF$M+-dZJ8$%a)Us2JKRQY(JQ zcLB{*$%a*9DED|B=y@dMJNkjDWW%ZnsiMPoMzec3PnB#~HHC_+_ps=c>fY0^dz25V zk`1e7Q0}L5TQAmrW9qRg*|2I3<<5NMq<1@+iuX7i_dzzST0lkBdpN&JwzsAVsFDq< zZ=u}JmJgS^m(5fSRkC5#63ShN6GjeSVXChx*|2IwtwHBghy1K^nJU?^Y7OOn9<`uV zm5bIor%E=g+CaIVV;9X)Cgi)(m#SpLsx6c|uDkQMuC!K)Kf`fuWy7i+l)HzKMzjsN zHY%!;4XgH0?klB5zVz*_)lQXcSaqOQ?^Vr0em*~1m26mbgmTZ=`^q1yVXYOaWW%Zx zl)HN8wupSn)UT>!!>Tis`%0N`{Pc8Fk5$QrRTn7t(}Og%j(u$^{*!Q=dD*b)3gudT zJH@|uV0sblibueRkC5#1Il}f!EMEj zbCpf4RV5o%J)zt)K$6ni2b(&kN;a&%gK|H&nf0K0M^k^Rk`1d~P$~2tZftO+x~YUu z!|`$1u<8w!OjWW@g9ezYph`BZ`arqXSC1MrGu2;}Y*_V$`dC}NdMq4nYJ)1-u8nQ^Fm*|lY*>wia@R(I zk5^t*vSIZjlzZOD(d);MXVDg_WW#DSlzY!s zb@9d>*7`w}Y*>wfa#z&b2ggI+1I$q+8&+eX+@pNDaDOlBj%&Xv*|7Qv$~|wSjWX?` zsb{KW!)hFqyLy|QNFVa^-V`sxac*V9>SrkT3{YqPxg6Fiqe?cc#zVPho4xQzaW#lc3x=Y`?i)3sWin3dh-y4Xepe z?(sSwX^wYd+~ZY2m26l|fy$s)@5<~oqL}(lm26l|rPjk^F+#p4TCYkrtfoP^_Zy>6 z{+!KPzpIiBtLaegIqGhi1R+0FOZay{-e?SRe0D+?{G4Cd;SUDEPNjCa>T7*%Sa)w zxuZQLH`(}~=TGk=cmL<-nT^j=1N*SB3Poyp|J7XyN&fLak8JoT=0N?T>gcUKQB8fP zN;a(KLU~_!xDDD{Kjhdis*(+>c~IWNkK47=Q94_z%F1G+|9SGg@qWW+@OcD%<9(!m@R88pX}JKOS&DLd_x-p9?z4o2 zwe^(TWaEG4OWsE|2A@a%fA74HTn|1H`k5EvGrRk|`*DQj?z4o2#eM64X4&|kxu5ru zL^0g4%V(bHeWXb6kilYVB|@MEzU%3bqW%d`u3?Xa-)@4Wxv z-DKn6pW)s|dIWX(|E=;qGBfx{=>1uO&-|l|yj$Yjizm9z;{6G(`k7_J_h%`TJBr;K zJBPea$n!oNpG!8ZmO=UV5fkq(?tjfyB^y@Dp>ioGJvD!SQyWythSdtFa8(X_?tnGgY!- zwFb(2C~-Sk@`qKXhNzMatF_d+^=H-Drk1Oc4Xbrf?)mxC+h6=;>VzuUuv!o0o^9@& zy7tmk4*jjcvhg2z`EAj^1y`mV)DG_>alJQPnY{nb&%GP)nTyECyX{GMcDVa2VPRMF zGs}kW&qh+|z9_iURQ?G5V=Wt2o1nf#DJ(2ww5^X#O;sfuR-2&;se19xiDjn#RV5o% zTcF%mciTK)lrYsme;2%LSZ#$WudUBx4Gj4%X@@G=u-ZoI!`0U|S}RQ?|7^&H)pn?= z+N!@c%05#=RLO?b4yaD5A}xRAolf`len*vTSnY&zuhbP2cfMw-bhv*HWy5M0)VJEY z+%C&4QwvndhShE;cMiKRi#^v=)X08IHmvqQxoczEfg=@7wNND+R(qjR>ph&7d*oD8 zhgHdj)jp^;s!pbwUe;9RDE>W^4Xgc7?wxRWvb)1fO;#lvRtKO`YOCgk#S2YcS0x)( z2cb%;nmPL4HKsB~_3xo3G_ns%*6?I6JY*-zJ z`dsf}+)INu3U4oj|`zS2}_RkC4q0?OUPKE>m%GqpsOZ2bOB?;~aY z=dUH^u>M;fP} zM>bqP2USc}l^M-ixl&lz->PK8>O9m)RRzjT@_y*0f!~r1tBX+XHLm5EY2G2ad)QBvY*<}_a?k3u=Tb5G` zu(}N8-b)ND61|tHQnCGeC>vH+pgz;%%G2nR{HFSEiguB^y>Zpxis*8LRs>wAS~kWaB>?PrQ$8 z{GZqJO?)1?&gFKxUAo)OgoQ(^z&_1~eqr!(B1RIZ!FRCiUfVRZ}2J!8Lk8m+0R z^QvUS>JKRI2e`Oh`KtXkQ+Yr1@1bn`Bc14dwl zcc9$)S<&r`_jKj1@D%aqkm3pZ>Cc^&MpN;a(SK_%BCojGts$ZPHmRkC4q zAIiO=4eRUwJI4MeDH`9uhq7Vy0Lq<>n@>}pkcEF+p-MKa9zwZi(d{XkrZJV|BfljZ zR*#^H>1U7o;8e)Z90sbA4Xejc?zk#F%(lx~w^hl8)t^uWv~}X23xArbp1{9{vSIZE z$~}(_FVQ08HD#SD*|2&FRYY4$vrMRDtpo}EmTXu(gL2QbXRj=ZYpRt#YhaWxtW^@jCxOrQC3VIjt|zDcapB^sZ( z&$XY+Xs!RqdCPl$`bF1f){3wY<5~YrEG@6s{lnwUO!%F`LX2l!ORUF; zhtK=yOP-O_y5}9)L&SL2{}5{+tmoh6i$9iG&kz=3JnP%U(lPE;>vwrUW_?yzi1DoN z5KG6n$N$vN{&HrWb0_u?G2Bvr2P9tz`?~AMj^^|=UpVwhwX`$_7XCwwkI&M* zA*a{VTKBE}FI>;84+{%1o^?H9okcd6mQEbL7+#xj1ecZ`a#v0ZF)Vu-Nd8~)8A*Q* zk{iQpmE&x4aecB3lS2CU(UoVes+FasPl#p2cz6eP`sfeok13@vLQH{kWv{nLpluOlsc0E-b`&){Te-%h~krKd<``Of;0W@CAF)^q-}pXs4!q)1)>DOr7|*&fvDCwVnLgUo`4RgbrWK32xi%r<5@Q)miDVZ`q9UIC$l~vEW~)$&4@LXv_A09 z@A-CSJ@6jOBu9*A-JDoIDXjh9{`rq))~^c-F`jh`VrdN5@A$(n$*k`R3o)K`OJZp~ zT)N-Y=80_Up3CF|Vm#{y9IN+N-!bFhCxnF<&$<<{pc>J?FTdKJyE$~PWs)Msvwo0R zuNKzz-uUBYR`7aZA;z zw#3p>9$)))^A7Pd!a|H^-HupK6zgw!`^U`adGOxLBu9*A-JV#ih3|=f;__hZy3G17VIjt|?&VmQ|JSeoaAw`)KFd^R5aU@VIo3IkJJYn3 zdk70Lo^@}>`uTUg=1w`S(}jf?&-!7<`s(^C|2nfS5*A`S>pqV4Bai&ZlQL^fScvhg zA91Wx-Zr^UW<6C{i1DoZI@T+$dEIYj){BIN7|;4q$2xfMUBk@!U11@{vwqC6KK1u! zY-QFvg@qW;`f*}iAU(i2=h{13KPD{1c-H+~T3>m=w~ywu&iIjKvW6JXy1!%n#@C)` z=5-ef3o)Mc0LS{vYhDS?YLC4xEW~)$$&U4-Z~XdmGwW%>LX2naBi30Gjki9H*P8j~ zi-m<4&)QF{2MOz&o40}o3-$0iVIjt|4iF0(75#hY|GfLk%o^NxnWTvEtW$^u3DCc* zSD*Bu%=(b95aU^=5{sW6mX_}ProRBTdiWDRx=gkZ<5{N>>qeZ^(m5}@<|CPPp|B9+ zSq~(ZruF}h?ScVK>q=oE#kMK&Lp=Ps@4oDfIjvt87GgZ> zLBx86ux^Eq*vZ513JWow^>JB)Im?PZOxT{*S}+ zmyV zi*ITDxeO&RGiDEM>JOpRZ-$28-+$d^w52I6Ev*9!{~^Z5=b^;Xx!=3~V`S#)FA)}E zJnKwi-I#2`4w74a#H^ew-G7x1tfO>*%|lJXW`R8au+AL2qbrRk`YL-j5F)y zAi?LuTsnV-R>4A z4>RlF1DJ&v&pL-#=Lzc{e&!dT3^^7{OK%nyVm#|yVqu=~-`D=^lMm0VyPv#FQp9-H zdBoDS%Kv@CuOG~;7Yhq9o^_B|FksWa2fXCAX{UDEpO1HNfS;XCeMCOKj}>kzT@x#_D{-teV4 zt)~eKF`o4ZVrjmXZu6CEGwaL3LX2lUl2}-e@!u;iJMpm0denhsk|M^lE+Cesb>PdN zc~oY-PFRTXtP6>yY3<+lKEt}%Da(`=Vm#|n#M0H&7rywtZ_R04DJ;Zz)-nblJN49M@(?ke^=M*gtNipSSHCiQ_}juljAva!tm9;J zY3avb|C?rQ`CGz5jAtDtmac2P^dCNcPEPBJ)0W8^Vm#|oVyTB;dhtd7o>^}f7GgZ> zGGgiM;(4!q?j1Ah)(>2!v=HN2mlI3t#tS|$HXhD|g&5Def>;lgXng!upM)%G`}(l3 z5W}+5PKVXPu!npM+4*s?^NL@5!*`Xlv@`=2{zHsU{jtPSpP%y1cY-6D`e%fN7|(i~ zW8LANKmF*;I`52SN((Wb^>|`o|BwGZ@u=UwduF{xScvhgpCp#fzQ(6tx|~_JeGvSB ze~9s{ClE_#4nOnG_k1|Bc7%l(&-y81X$(L68#jM;W_?gti1DnRW4-o~uYu~OG5m=K zFO!FeVc9D|^69VypXlst{m2dsL2BpCVh1rk^**sQs!uxm(nn<0y?$buQb&wutq|)R z(k?B%V*M-EWY+VAg&5CTCDwjn4c~niI|>U6F`hLbmbSrvd)nxYIju)OWSOiX#T?Y{3erhonoVIjt| zju7i~N$Ur{^qHT^9^UY*Ws)Ptvo?t}7S;I3g^>c-9uNbS`?`_uuQ6a$4^f z7GgYWOf2Z~=-=%9um5UhopSavNfF~&6UVyAxxWTDZ7IJhEW~)$HnF~slUn+#D{pz< z%=(V75aU@_5ldtE?b-9pO3v-iSte_U@vJGaG+#gWuh)aE6YAkJgoPN-nh{G!;h+4< z6HV>?s<05_Sv$mn&Vv5k=8V5LGqg+2T_!1FJZqO&R|@N&AGS2e9{#DY5aU@#iKV6d zt2h1E<;=RvdGG`NA;zDXeC(T5ulc#m`hc(y!(N~AFnBu&Ddgv` zhl1qOkSO+7e!ub4$ntNAKOflrgZHbIrKL-Oh5r!a{rPEPX2lheA(!K)VIhXSe#9e|m(GJ{Q7%DrBl zKUWh=pE&;est21Vsecw0Vm#~F#Dd_`zYpB;fzQloo%_gTk|M^lex6u5*Lvx-}ne|~|A;zC<)=Pzj7|(h> zu{5gh|LW&Hms$TSEW~)$3y7t4^+j*I_M4e?#YM~HA!0o1g~U2bqVbMn!WkQ9Jqr^ zScvgC{Z+^My^}u%i{;9Cy|57DSub&{H+}t$_sFcb2@5fv^=ppx@;6@}Iv!2yeZoSF zXZ^Zkz3%_M!_4A7B`m~v)=M4hs%IR8!ql|BA}qvs*2{=>V~OC^PnkR*v#t{sVm#~R zF0IG@$=iQDvu=CIGFd~6XZ?m_efJhGcxz_eTUdzktXDYJ@7}flmzi~{un^-}zez03 zmuDRm7GgZ>w_IAE{NQi>OHS(v!a|H^{kCKM+x4D#uguyK7GgZ>m5%j<^UnO4%zCP@ z5aU^|a;)(y&oHY!&k+`4JnPlO(rA48S)cu%oYu>Pg&5CzjZ5p@=N$b)X1z&Ri1Dn~ zI@ax8_kPnuUL!2Tc-HG2>mm1B`;(m3hlGU~&-xw5`n4N97G?@s=RYqj#CX>4I@b2z ztvxrhz9B5cc-HSZ);~Vy2L_q7e0Z7aJYqcS^^W!B7hd+enRQ!XA;z=b;8_22!DWA& zS@#weVm#~j9qYpPf8m0wf@{kzB{un6Bc4T z>yI4kZ@+d^vt~XN7GgZ>j~(mC4L|aToYtF?#VUMwucc-Egd)@5tA`18zqm9P-wS$|3_ZI!eCdFfL#>rKK!jAy;sv7URApZ}Z8 zdY`Zm<5_QUtbh2YJD9fod0`>Ov)<}hcYDprH^^ySCoIHx)}J}n)8G5?-^#4pUb;*z z1u>rW=Z^K9cYph`%(|bj5aU^IbF7Qr^q+?^>!7d@<5_>Qm(Kp=(ad^|un^-}f9Y6vzRj=xN@l%EScvhgcRJSRPk#61 zne{edA;z=bVm#~Jj&<5APPsa>z9KBdc-A$Jwf;xnd|zfQU$#tj z12LZUSB~}kzx&(IX4YMWg&5EJYhvmA@Wgw^W+r^9un^-}f8)}6z%%dh?3~s?VIjt| z{??~;-6uYpSx*oaVm#|TF0K1K?asr@+7cFGJnQd>rTMzzz@y=zTt~fU2@5fv^&3!CjAy;iu|9wGb*A>dURa3ntiLCgdiWpj`{eKEw5|~rVm#~pF0KDO z_e#@?en?n|@vILx))$}gs$Nd(E5bsIXZ-`Q)Wgr-_$j7+EnmJ&^$;x6|E&-#pGU9fX&SO(K*-294Vs>X=%tj{{u)nELqc{abR zun^-}|KeCj{^d@8l+(JOun^-}pL48Buf5vTsD}s(F`o5#$GZ8${?e=oUnnfZc-Fr< z)`1Vc`3u>@CkP8Mp7n2zb@i)%`kKtz5*A`S>kE#x_Lv)+r_rYh3o)Mc?~Zl5C%*dZ zoYr%Mg&5EJqGLU4>1Jl;@G@Z`#v(vmg9)=nS+*y-iq% z@vN^n*4>}^=C5Sd`-FuU&-$uk{l$addQE11N?3^Ttp9MV*L?RQ@64>P2n#Wu_5U2} z^3$I1#LT)*ScvhguMtc8!-t;q?5}3l%^$N&?F%uU^`DOQii=h*%B*_}3o)McU&PX} z@(+3Ep&$>`pi1Dm%IM$WV`YgQS(NZ1?3o)McO~?Aa>wf#$ne|j* zA;z=5)Vd?ozIv%c$CKXs4qzcRDlA}qvs z))I^=H@Kcg{;fB??}Ibz)51cGXI;;+&V0}KrJ418k6We;BF3}uJApZ^7k%f(f0DLq7|&XEtS{Z@1^3CU-xd~P zJnKe|^_~9o)0y=iVIjt|zR$59u(bZP%=((J5aU@lcC3%x<8EKetUElOBaax*`hLgy z5?#CX=N9P3UO-Oa4Y91|8|JnIJ?>mh$}{DSP^%Y}s)&$_i^ zy=m$5qs+QSScvhg+c?&Zzxf+x2J&TLA;zsbH%t8e(toYt+Mz>!CcXWh=RzWuSs zn>o^hgoPN-y1irFY4;lQq>+ZMs{9`if_l1QR z&$^RiO`iFcU&yQv3kxxxb!W%=;_dpsmRZ*c3o)K`7svYZd!F>3%sT0(IP!?`th+ka z8P}d+O8Jq(LX2nK&9VOd&>y`#r!^H8Vmu4)>B*zR?tB01Z!+s8!s5Gp?C5ZJ$9nR8 zFE&pu?+_MZd|LN#tjFJI@R^*}zX=O5o^?;hdfVH-@3Wb8iyp@iF`jiV$NHh2qc6y; zQ-y^X&pOGmW_Nu4<1*_fg@qW;y0>Fp^qd?2V`e>5Sctj)Qg3Z@XLmLn$YccVtZp2c zoyL19f0*o?yzhFdmj8bTY;5&=gW>9AFdDD-R{E<)hT}nRG#>5rdRyBE+S;|z=5P_n zu{ofv;nrk&q7B*|J7;D)D@P~OmC>v>nDwT^{s296!r5?mq!O+VcY1^VPQSM{nQrxW zLjCIQbT*lWs?FheeP;tzjZh^I+87Sl0zi#OH&o+NqlVKS=XEyOovsdhlW__Zc^~LC zW-WaXzAk8vWEV<;I+z~oAAQ(mhtBI=aoQ=pOAeiX{*o76arWg03(@%(URp}dKDQK| zclM=cV{u$LS?O(0C#%ERtk=70cSNP{gsZ!=oyk^(oem{}Tm5l=9mBRc=?^%zE4yoJ zAQ?{v!v%P2)8X)Y;cY{*-wUtw^Lub{0ZL9~wgXLZkpSjEEKJEUSeSyP8)F)ty*d z`f}z*e{*fx-x;2D=Dst}9896>?`;gGy_L}pN_$6Ewr6LZb;em|ES7V=+?=fTF4%Y0nfuk|1^f2*X1gmZeHdg|z0+UW9F~;*7w$jn%maHSK}x6W zodm7=7-#*oMahHVRgf?6F$D`VhQm>Bw%XquuJu=UCes`-2qWhf#@S&HvfO0C(7QHC z;h3$ifp_C|3qK&~jKER_o^4E~I}4+?M#qPPh0w#}+fY4LJ$7>d;@(yJ+1(4z?oluP z$ivw2o`2CL7oL4-@9<^kT>99H5B4rT_rj%4z@dW&5BAQ#;G(lH#TthB-tJF#MmwX) zc;-{(AtjD8@K$+%8JUKQ-0{te!xtm~WCz9=tga^Fv5^!TU4Q=$dcXp@4LUrMV zkDBa^)<&y+Y#~{B?gfXz!wWCu{2d(cZVjPpn@oF$#6l%ZEU zG2Yoo0p99E1$&gXfJ%$hSPQeUYEng`noOrwS9;vLZLeo4%AJh zEyOAZ!9`L+4iC)G`R4Q%a}&ut>-`?cGbB$Y+wh!*x#O9O#BDlUYfca50(GV^7Z}8A zAx@siECkOFTXDJbG_bd)x?(tcs4IpQ)>0dmZY!9b9Cob=A z?plBG(H2J4{`Lkv%?$uU*UdBAmeJl@7SY=PLer$bmznL^((8gK9J@QB@81+%bvm`L!DYZvR}r}iT9 zGw3OdCiezLm|HwO64dLLfJLWcEicE-hrs$}CrDT8S|DAg6aCs|AD&S1(xv{^aOm$K z9#)kDVx@Be z)*o%cgV7SM%EFopyad3dyzMEBKx@6pHmw{i^^UE<=r-=n0LFmT$<`LEh##FXa_Q)7 zEPugDdQaXhaA4OaON9){_>@n*R7NPH@Pv-#W0ly} zc>pP;lRSQ>ItTIDs5RvhYCHwIpMjRy{crNj|kgSBm!L{`xf8#FtZqrglMCu1gn z1*}wwU(kDk`7Rp{*s?O$6SYD>?Dvljr!$Ou{u6=;Ery;bHz(^oXh@s*5)gdj_arE^ ze{&~?22e8{u8(k8DDhOWJ8r7BCo_5jgM9p(#%TRP6K|Q`LGi4Oa_S<*2&ax8lM^}h z+PFH0i_Xv+(!|E-3^eCK^wXhcQ3R_{vY098XbeyLZa-la3i>6TDg|MCZ6EY=E(b6v z-5<#I^{PApavy~q`ZJ%Sq)Cb7+>kEkg?<(}Az7RcQq{TGA9}aH=^bmtyZt@q9WIe; zq#-#7hL1DJn%=P|KE^>fLw}p@=E@Coe&?+BHE^}@oCBF47mTCuxKULGkX4m|a8+d> zX;{6J2E$E1at`Qc4mbUbLrbcn;6WA?JV{%g zhG>l${_PwyF+*L`tukix*jzWhJ3J zt_2|%eOZOo@$qo8x7DZB#Sn)D`vw3ndiEn0!6k!}!L8o+udKfJa| z0!__Fp{=7scvczhP&*AXkEZ5=(9&#sh>I+1c}=%zZ$T(pJvNzc4tl)w+q5?qgqC1| z0Jiz?X3ePf!hX&Mr08F*8yFq;C}@>)Yq2(1ON#4k+?Xv7J>i8osnYT)BezpT$QoD+ zf^q7@tB>(6z0{|UX|t@bXlE`6Eoo(zhx^jo4mGl;6L^eXqo?tb*-#;C3tow9S6 zyvhs@Exa054d0a>({$ZRg$VnW5QTxL6uFnFRB=~R!7ya_ejqfjN<@q%Aq2DNUK})0 z{&hhU)_zIQq;$L*2s!jZ05#2$%!;ZAvnnh*ul9-L(#oi~n6h4rz*|yjE||;+OT??| zqVW3eGVs_r!Ovj$i=Rext_FP@tRmBzuV3A)0aYo~kgzmj7{;>JCK41m{CbKqmt~OG)9b!{AuhcqgGR^9%xcO@;Oh&{5Dbr~Ib0@41eCQWM zY6li$W~r;S^F0k?-kIwqz2R|;z;uN(?tY0PcRYYf%>n-IuhLc`knx#55aHW)IEQE? z3OY6&@#H6?tcczv8yfw#0NSSp6LCAaM<0&Do&tPOb!jG{wSY|?53=wvFx-S987vg= zc9j=&z`R$<%YKfRS8eam!vXdQK%=U{u{07)PJZT?iXg>Rerwn?BqA>2TYyt;J-QUT zSPRt0TZB=}HOUm>!oyr3WwJhC8h^1@C{r1P>Rb+?TFPRu3r}vxwKy>NS(4)qfrqV^ z&_-vg(-Cb!LF5*_lg7XB_48Eh>F?~dSp8a_d51@M;T#AvuF zOE`kuB?8*qg7b67sjB8*IWDYKyZkG2!4+8F#A=RQ{*}4>`&i#uXjk5rr8g&mZ3)Ffa&N-~&`=oTV0``|_Qh{kmFj+}5JIX|<_39KdYb_p0*pexrID@Ll&Vij}`#f6?asdBSIfC)_JTow4#LJGMy z3p~TCC2!92ViNfCs@>u4u*_CgR5{A3Ff(556UkY~C>S`YK4-~zcwAoW(CJfD>}+6< zS2{W1(@6%P*{n4==~|~Q)EadKhkNjV1mg-l3t#Y z06h~gF?l1E{27V*Xhhmoi->ovWjk=>oZfnf8Zt!)mlN~=q&(LVAQoz>_G%k&TYcJz zm0uHy4sEn___XG9y}?S6)ebdGbO$h3(n}-w;RzZo3aGsLo2$F{l-D!UBye3$cENv> ztu$8hdMG-p_B4JF85Nm#1c;QMs-|kytQ;`*#@=j=HsLKA?*?R_%>1@RVhF>n0j{Up zCyED&8SasUfeNP>**Z@>jIbxOjamWq5Q@F228B)rI=Bj1-5kNjX*#q$lV?XKk_Rm> z<3}womNL&) zyBLkFj(U|*sSlxB5`xBpvwVG+?~EK8aIKTW61T((+*w0vbXNtb(OvbULNAs{A3+`n z_3aBRlJU?c;sMOPCVIL62W7k*Nbc4s=MP4eCJ{zv<_$(l^E&U5O@khh=cvKKgupss z`8fR1@4ShmRP!Mh9B-2q8X-#@j7)I3(R^ICCxd0=Q#RHB;grK1W46x7&@FGQt%g^X z;pE4BFX@0tH%wiCmxi#w*Nw$Eqq~b>(XQ;)i9*v*Axo#@HqV%HBv-uKa~}~Mz#aa@ zvQ^0aa=oW@C*IeHcsuZZS z8_gjE=LM=ft8>7jFLAoC2v7)59lQYS;Pg056R42bC^r@pO`n^c)p^A>zsRCOiHoXH zObZv$!o`EYsAz(-#Ba z;*d{U$=|(WSU#xXBZBe+^Pq~f(v2u|TNOLQO{zL5*X0IHgGzxSL5J?Zth^_pv^2EU zN$8?f`1oJ76c~urJo=_;mkP{K@pn(o3>Gl-s-%*q6dr4^m-B;nXNgrhMCh=&iYPm% z7pe*?gDSBGP^VyKR(L-qq}^3HEWK4DEGFunSkH?JEB3?)S{M`X6#33Bzmanq z=o(?Y7>-b5wRD=D6Wi3OIw3Efq&--C$zG8!7RtcD2i4Iyi>Yyx>*ZOMfjI`O4FbRl zoSeD*WibSXx|b}`Ou-8)z9dwyxZECX4{^JhdkKR54ZmQi@OI)^D{zF{o@} zcx5%V(xoG)T8+CAT&LR@Zk>GpCzj7*$az+|#VlggA{$oCvD;>z3(R~=I^(bMYb;SU zpboi0kxCYTsn*N3fU@S5xG=;esNsDD(+PE_cOBKt8Vp)sr`fPu>SP2%&|G}$8D}oB zHCS~LK?yIq=N1w6N#z={2GiE?tbx&aPYLvhhu2F*D zLyZ!~!Zpg^_g13}ac?zBi1TWcz!s`ef?cFW8MpUPqj=1mU!yXvqef*=XN@wj?%qsB z^tpA94K7~y7{8ag$Bf16UdHdS?q%X0>mC#5);)$TR`(dYP~FRJFI4yF%`a>U20x~`e&#p#r8k(1LW|tAGa%u;Bw>0xBR)Cmfi3aMi8&g0?t!)V6ag%5mjWj21bmHP zSXJnPL980t9Er+mKtfCj7Mf_?zQ70l80R(-<&9Y`IrggZp2ao~H2afom5dfSsq~tk zN|AF_sW3q^SE}^BNAcGr7XEmpI^(6;6S=@9%9vHD87s?Y=&dxH#=B4=yGgD_lOS76 zqHGSY=!ncExtdFYY%YniIlR3hGMD6PE(x-^B+BOK9*NMP(Wpry%0`Vao5gz{LaSM! zMzbW_%(84!?qdk8I-MGJ!fe}#vw68NAvEuFYTgO6c_+^1`J#lV;EYC18&PNhTb;XJ zf$U(;`R<}fz0PHKREQbPm zHQXcMcg(SnF7PZ>Vx=I6RD&)*b1EVT`e@N$7CD;OT^n~%QO;xvHScpPgt8`N%-eCp zh;^J25tdsaLKp1VVaUZYpxU7O>2k<*r=P09ULMVj5RXpFE(Mc@x#2-3Iig&HyYTrn z0_+S^lnH~1;3a}T(kuL=#|*;sG2MMo>Zva4A>t?jG~mwMMi%Tb-cpYSy7cG)R5_Y* zMBJ7RdG>ySh})${zS(nF(qTxhwcB_rFSj6G=@M3!V+a{QjhD7T>T+Eq=f^^$(dR!S z;=Po4|4ESsd&2nKEcrJEpMA_ED$&Rq?NQA*t=en}!A5u(za1bo4QDLb|gY`K;q*4{vX7wPbQ6*Q(`3LR>j2fd>r z@w7K`3S`*JClb06BGTPAk)XAdu=b9LjIE?<*B%?o5vp#RAWLe$!6|Q;NF43bvVAW> zyTNS{$@`X$cv|r7J0!B51+i!sFD-)BP`vlcHB0s7hG~;Wx$KCLQMW<;4~@`W33*hU z96F5M*8;{2D7FP12X^nSx?=sunM9YL=6R1}P(0*ODdb%<8cDb*x7-j~(cK&{3*fEfkr)Jr8Y>#;AV*wP`dWBAJk=7Oj|BwxOV zN#2L!WsX=iK<3mNDonE;D>JR7BVILb8eT)E=>?-?%49sg=3K&8soa5X+nHd??$TrW zetgY7M{>lsM%c{kMv#pKM^|HWPYg^$M_s>}&_>6i;sGwF4w!-TjJCFW=fdj7&hUIV=yi4_xk4ll z8}1ci>5<08HSuRk!bb73KF z=)bv=L%qfJ$m(tnW>>2;QcsiOucu$BNb9BLIW!i@uS2^dBG5BB; ztV?O(UjQEl7MPa)6>#yxxf}iIrIQO`tHkIWIG>MW%klLge8L+4+UUdM=4?nO`0?-l z(c|gw@sMxn$N3<94hc?K!t&LKuO*!wgG)#FXKxoO2A`yvVYcC0HKQ^AhMtsevKS1< zSm2xV+5i|6ndt`Wjg*}ju$e;ED6m;UWcSK+iCk&dm-(%x4$h0(xn*)CA`hybFlb# zzU_d{W63!zI)}*@0P!&`IYUKqIU$9A%lRkxUTg6ubnbl0oIX2?GbcX(B7}ALj_NMk zfv=AAcQ@oz8#-*sd{`Yoo??==o}{$1dmFA2p`u}$eX zoRJ7-FxuIG-M5e@D8W^@GY5JBEOaA>suYL~2u-b?eg=FCb8EB;PaC+P3&)AzKB&zR zT*2Bqy;BP@>LSmv4N=PMwIO~ytUnm!v>iRrJ3bVip<1`S#<}cOE#yO3ebD>MXSA?kz^~NDy6FPw+*L5( zAL8Yz3iwzOjgQ#Zq`^k7v7jlC8H7ZRmy#H1zAL5@@kv9 z#k9JT95#z6NmldBeK^6zGIYsJ55Ad|uZ{^&96Jvy?rq6+lb;h-``i6={k6Z0W`KVjA!!v89hSG%qk|0;7hRL&ZpY4CkynhKotrO$+0Qw=08RO<~bniqbqmV0Kf zYVq?a^g+_ur*~A!pzVg#)dH7qh!>S!eg@+{JiVk#2}R3iPo+!KDK)e<2uwQoCQt>9 zclq3#+MnR5I=b6<-0KxeY8I0nc&{${M&MnvitJ>Xq&_T>l9zvz++&%X5FV@&;(h7NxAXZ`IFYG6TO z`|>_c^>+@*iv;*c^Lccql=;^ECHZ={NR7y|@mtsjWhWu^&=K-sL->p`JsCPYy3&N> z)m{#8F5D5vUySHQju|y1M~gBo`k|fSmeYj>duPMvDUM28PHy%tf|IBiKm645VO#|8 zmLTmz)TbVDAeVyI0E0dmO?D_g=TdJLeQDdOZ4j&+OO(HAQdxwg&Y_Do56eB9hb$4p z#*2~{!()}KkUPYo8LS?`dfQ=pS(rnBjSEM|8C4~JSoiZd3IvfBHk|Mhy)N5H56ddo z!+EI>t51=E!^3H+I7YR~@SR))wxGp$oE+A%*@-TgRGkbLj4xm%12~|-$Z7S7nHkW+H zKp=MDyRWSzygEq31H{Fgi0eJ!c@5S|2euDVJq>^zdfF)8p;wiTa=Dk2k!6)1rffOF zRG+Ge^#@lH>e(cA*ml?oJ6g@kdNIZk*rjXwV6ln^NHLLv=fNE4{LKlS{ZoVLdeAo; zON!>?shdqc;~WSshfCd;>D?E$&;Y7aHi+I8x}6aQD{^5`IL_?n66y&D?zP8IHk@^( zaNcls1UD=!f(5V1~(j@y?9V*<(1##PB_GEX-E9qS(%!WIVOs8*XgB&sR1cIZ5MeRr5PcG&LG%H^#E zVsgLan9!|3H^%c8%fzt&o=<6Zd~|pLJd@Lgtde^eH-$qlO}l=nXEjDRNjGBDT693h zT=T}=rXywmXhzlA&;_za9#Aia2bG3%n9qfh2ViINX%MeHyDZ&pY<-i_qZJ-ia}mm~ zxDXZEC`-qklU$DVoTzxC&9d>ZsE9lwPmoL)ONh*tnur|lbr_FU;7yf&F&)2j15YbE z8?d#EUKL=iK#)9p%(&x)51V1F##gg={cCSPuecGbtx?A%K-{g&o6`yKs=@@xG?hD$F@rkKI-tHb1pbY!A@7E zLO%o(Nmw>~5^aLB3m;~YpiY%L&77tt!o{mipm9#GZwB1P$M_{>oXWDM&m7dX7lnQdI<<<3{zmdROXI$n6!U5>gguvQdOo zc_JoQZ?>_!GngC$2VhydT;)TCyNbC9+LqJ60f2K|Brf5vq!@h_YS=WMrQ93FwZpu$ zw4K)x;kX8N^8DC@4MFn{1T?`*2=w?`q^Orj!(tM*On9Sa1_w%iuNZ4UGGvU9Bf-?3@B5_Wgf?v7Vs&j2i=%Z0!VWpw#%rbd_E z8ZC#eVOd^9;@&JdAce2)q0f^fjUs&m3Em>~Xb%Hs+5qxrhnfhn4PPTFZLszHaip9Y zzTX+bJ~m#f!}N@90xu4>V9=sUWOR^1lZUz%4;*arP}ksL&{{mwRXlq5f*n-wW(l%W z+jV*kwEO%K(yGu@h$`U%p{Aj{vDibSMpu~=ovkix32Q^`pTfg3P-PfQt894@7lSb8 zmILByk4-@kpi0{VG@dTZvE>?4*)Ab!U7A{4S`b?)$;zHK(J-f0*<|vrCu;Sa4(!$m zqNcXOHY3VLX|dV)rG-_fs{ghy5K!gA12mpK&Y|TRQrRvcY8^w=Y+G4Z*%Mw|d#tj_ z40EE)Fg~i}QG?2vJ#3VgQC42qSOc!Rv=A`Ig2vOwIka3uD%&MQtz$-8rDb%LJ<-LT zget=VvC5{|Fq_H@gC|P(PqStU1eKiyLV(H}Z$a(4P{x*PNM*Z(pmn*c0$;1ZCJK0B zr}sD_#fet2u|zaFDaQIsPb)q0YCtP`^x)TnLWTv38N3_d$wL>@cv4%Y0{@;Y0~0O7 z?HT)Mjiks6$?NnWCy7;SvrQ;p43OjtCfKkTAjJK+V`&w(MCapwI^lyvBW+F;C$sWc zh}#YE>JQq!Lo1y4D<~Bd>yk3nAo(H~%4<(dTD4O02UmoIF(Y}+5|a&Ww%Ljq5TmGA zVppO?%)pw78U6}lhTK+yvU$)?|X~m#}gsS25wo znuZg2B!sVnx(@?kuYygg2{1}Hdzf1rEIK)+S0d}^aP5htKVNww_^T$dI^SIw{WAx7#9psrDwI$wE>u-UZSlj<5n14-%Ym! z@EW1{nQsLM>XXGu_24d)RxZ#Bi=eGjxb&U7S*s50=ZXrO+u_SwP^qC-qTT8X^8LY; zyRg*BTMIEu94WP^ zvRU<9P|e^$1=q;f?JznG*6#M6Ig6SH|Gx*PkhNE*BvMjr*d^(*6tyvVdBTB2?|u0m z-O*hrxw2{N(Dn)xI;BB1@Yry)zCoRX!k{|K7v%E{3{Rq9Vv50r20g-de>Q^^vB~Z_ zUG8DE;w(0J=m`M1Q$bdCN1O2aVFR`f!2zo5IBbj@!^clC4eo**L{`mgS`kXB=3JPZ z=$VryJRz0Yj}n!#o0Dj4X$zJc@w!1BC2AvtfKjYSC6||UR&zq1@lh8gfykhst+mR% zn;xHW}dIL4l< zWmpX77o(vmb}LifOn|$t?c<`k4~m5qiTLhZ*G0I0gk%KaR8)<}4N8u#gE}UZFl+*xzf1uXj zY6O@Lx|ZZ>EwSYM8`{+erd?Y z3|&PWmEkl!8DSAL#C(*yz$a%5x%yj(lgou%y)MM+cp)a=2UGZh3p@hTd~wPBf?kr2 zqO)*q3!dhoImsByLah8k(sqy))NbJT`A#3(o`tdh7Kv9kz&>6$9mbEI9Xiu8E1O}G zuunbrD75W{x2kX&JFq*d2hTkafekoQK3OY0=7uauQ9GFSkJ+EOr--FJ*q_d65j(?S zJC`V^oxqxF(uo}XhE8gRr-tmBhEeCsr4o52YHpd?TmIdEWpVbmBxHxnoZ!4a&Le1= z`3GGJ0lZ*?0AxG*S}PgW*Ck1Sk9m#)2k*TAR*{Z*$re0)6{0dLIM0u>0-9!4Kv!fX z+ks4>7e)Z@CcJ>Nk`a=XEYPfENyHwnhX?vuU*8=(O zKo&XgK<2#T4Kq^CG#q26v75>@iSmGuM0no{SKlPcW|L?auBRwbwJ3W|2Qgs+0_)yP zTf=7sxD-W1_}FFUN%m)+D3KIP0Boecq55w2aV5{n%7&HEPE&Guq9}%{W%=2q>82?*)gopE)P`0vEF%1H3{odQ*F!ut~$=7)Fu}e2MFtK4h1!c5R+rl#F*gB zZCK8!cIz)vZ34@r=eDXciuvoOW^TvrX(6a_KpHF2Xt?5~1z0%R+JYH-4@O3KOEQ^i z2w^-`YN48ld@=+aCyFJ%HaE5dnYU3IW`}OYctD z3`!w)G*6-8Kx62bq(VNXs;El-+$j4&h*bX(kscH9N7?*1l#zzZ12s|OLpeSJqyprZ z+2ST@5W#PS_+}4wPc>NWV{U#=LFv-BV{k%(_Ez9+t++$4HCQ^QjUcfJ$+;v*M^(;| znujcG&S^)d4XxvGI$w#CcA3i= zE4YJoM2mmw*#OR4$x#E``o)V*=z>$A|H_~a#Rk$v8mTVKsV7E$`jGE2%b_M& zjy3%Zf=%);+N24>o#d@}CqN_Mq+c-NgmsbCkk=ZGIcd6sP7oJ$>_oJ3>)$EnPQW2g zq8xD)<$&X_Al@hr!;Oj{+A3}ZTlI}tqk6$mBQ%V3rO-g5qKY#L*N3p?hMO8Vr}_fj z)qBLb5}3g)q4ZWGm4lb0(kR5a0J0(%LzV@Fk(FVQWOYz5UfC)hj|vM3T6soQ;mj(! ze?hCL3#Ek3MNKv5OI?j@n%D}|+L{6Y@Air_2P6iEKX3F)wv%R@;xqEUcj6%A5> zN_>Kao2?04MhouZo(HN1Z~+8=-_J|9X_5?XI~tC0qeS8*NraMTK}{oL=^2q3Hak?A zVA0(LQL`DyDUYRGGuR<7QeK0bp>)!V6Tn>0`CHl3+@vt*yvPe947wR2s8~t>FsYma zIVXt2zcZQAN;6V;f#or#hN&lYWl~LcUSeYv^jks;0mdS-KIe{d9c7@~t&y}J#w zh9O)>_{S^^1i-sps|U;y`bR#+C7XuYDf!Y4(^nDvkC;I_$%krXAP=+t^} z_Lx5!m2zGq$Xl1M3Zou&qtq)zjVGhokOr_~|1~QhWW8e>xXPNakd;zY`H?6)Pg>P` zpR+;u76VPPSc3Mvq%!B#=+nv+-Vez&)7eZdtxQ=6zH_FR&v124e;sz#ZjZKyxStH7 zl5Y}(eR!jFyeI@ZW3RxNENY{_detuMzb7MW&?@A0{DL09a@DX8<%BL6_GD+1t3TYz zy@7?eqBl8{U=8*#8ol|GUn9yj%Y+rlF_Bf-qPhDD-E9RyfM@p^Y^mfgS%!dkgn@hku=ltiUjIW~ns?I^W|`Pojh zj~QI&waNGAES3uH#HOV8%p8s3?g&}{g41D(B?jZ;UMcznK0gM4fXjPBM_}6|A0o!B zo#qo~mC@0-YLqn4#a07w9&Q)1t@q9@45nqhjznxNTETB1%3U&50wpkC#$G}58SF3& z@P)G>j+;2|z|Z5Erpp_F%ASX(4mwxj1(DFQ1BM8jAhrQ8HinJ13p6pBSu75hSbYnoba;HYx{Ken=utN?Hy^|#_oPYk%!anERAplWP!T!A3lbR&d*0y^&}|r_7V}dF zn^kxfID%CV=&a$YMV?d7cUIVoCAB+V7>;?^YuG8`!{bor@_JTh4x~zS;-|xPI0gcJ zKbBLN&5WQW#sRmX#f(bDSb##+1P0z=e~U|a;phkndQfe!`P*x8c!WW7a9Wn;10i$3 za3T8&?8}2|jAfNBjF!y@ws)+k#br8+^T-&@6c+FhR*pC4vry6o$K!I zxEsauO7ra02(->WyHaFKN|8F0VqS~>4u&hc>-dxn5z&L6yit-KF6fyGad@!B0OX;F ztmY5OL(Re@U}Q!LDPcSLHf+jY+2!j?BDs!hB|Z;hrG|zF-f2$-Q|fUdgrA&2XQC9l zbjXE#zyYiN>IR?MD9z7NqlNsLy^@T+7uwM{3{e)l2xV~*psb*dA1(&xsV#X>DB&8@ z6qu|+--v74dch7upDhevlOTNm1IixHVraG+{&S22KhTFjoVI}%J_Xg95aJ9jqa?Ny{!)M~bOj$gDO)@#r1>9~ zf(0cXVN~sap_4^y#R_%6=>?4qEM1NV(N7DVETEYIT{gyjH}{e?G2`epV*>Dw66_%S zcdLpGD!2y)UOU3FOs}_sAGD&E)A=VnR9kJ@&ca}`c~S**1d-16IbshsR~7{LPlHlhVHzqtVt7<-Ghb*3m~eXnISC6 z9_vq2g=ZPw7D)G|DU@u$=5zfG4^b%6pSrzVUI4%fuY5g4iZto5H;|VErHVf42T#f{ zd`w}=LT?iIKr=*n*h|$q*`kuGJb=$O!OD~Kj+~!uZExaMlSH4aT&ZM^&@NpX-PFVS z6zr7gFaY0+;qMp7Ui+R&0j8wzMoH7-UvSg|+B@w?qs}FzY(6q=hkzxl!6m^7-AH8taIm0H$Gh2g>#&tdFIUq$0DPjby!!%bR( zkq=Qym6C26B8F!LvydZHN~!O+LY_$B{`pi{d*>g5t902?ReAjFhOC2YBTu?_2^y~pL|u9#7Q$*R422jOa(MuPLf(CGw?BDow0;gI`Tqh zI`YEF;K8CIFJ_9YdC8*E3($1sh1B!&La>g!kiH`?oQ%y&=_l?e;FF@JKD9v*9F0mF z1gQdu_gk%Q^Ft8*!W9?#7_eyN_bK}loZ1j@aN>uO%Xx8h&j7sx-fUvUmN0! zR7rkyx_Y_}l;k1`j1t*hXAhp%7QOdiAZiuBG25K@ZPF`8QI$DK9WRI8xh&JoBk6HS8QccD!Nk}SoCsesB7 z>Vj8BJ2@8gMi-lb_Rh5Sg=GPgmq7|6J?-O;1bFMay*-)Y*ZI`x)y*gMHc{s!TeG99 zR*?Rtgy7Z}S!Tn)fJa^p9lR}93Bu0W>EslCV{B`M9>BQXj^Ojla7&Jf+AgfTzyV4y zjO!nR5x>Mq9;d75veMK#C|SL#&gjedPvI+I@Sr-~ne~q6CQP}@s+28x9mSUm$>K89 ziqQbh=)kU8v_+RA!);6Wp=*A%rv5HYPU&rJfp4ovaK#y>$8=#Ze8YEpWMTvmczl4# z+rIs|hJbK`zFb^FRcgWj*x9r{LbFD?kh8PlDf?{17bkr$DW#~)PbNXBJ*9@>izg`7IjLLnvIf@6dwllW)OOm;@(z8aB~z4Jh){eF~olME@>!* zK%Sy4)FO9@kG`ZSrF?=N&ey{>Sh!;xZW6!~b(H1ApcK=5H`cXMV{ds)3A)0Za_+g+ ze0B=f7M&mww<(T(7*~bw| zKaDsx1C~)`!2mf|a-fIJiRZMD3zy1yg^qP)A-6&N(o=4eU~;wUnrs%!t}HLsU7d|; z{nVRksN<#AL>*8ON%qZCIs<4<2_JdI&qcyJDf%d}Miyo^xFe8PM+hzwTBlOfWF5Y= zgX^~ZRX!M3c5ubTsi}3~`XUFORs>?e%47gl0&k9#8cOD=favYF7~s#DcO_X;jJ*}O zUxw8iCuX>fqtH?9*^YJV6KE3DENRz>HY0s_25;3^+T?9ylo@SuslFzLFAT$j)wnEZbGIxR$<~WWBqgA!SLB*>}9P}ftad1V^9O}wNl2UdmDaALf4tTH^ zb4lbE>-1PA)pc{YhBFX&Nhq@)4b`Hg*)UDL7osd;e~Q-`?%6BHTF|Y`S;Q~A6>hJw zGMoi{QpO@4;Z3-(Xg0tRP%g9GLpg@*1--1fO@DFmXV2BGLF)1@qAcQ6t^{)%fl0!# z7IZ6f7V%3f!d|>GoCSSS#v&fog}xWxLiU1Q*4&oAw1BqP>eeE4co$L@aVl4WdBL+u zIM#x0WzHggX+_wJSBA5oPs&)tqq@-d;#u{`TlV6b*G|@zOlihkCP46zQR$ z!9Jc(+`tbD%|=`J$cn#VCWVub{EObt@d6Uz;rt|BVy%2UPYLh$;n0wgz%mRSjy$qL z%bH5$#SprZy0`HpgXc#_Su3gJIA6ubAT=YK1w?YezWuO9wX%ZI;r$GJD=_0xOTnWL zQLVuz04Gzm<#mv6xD79}26!$G?sJ0=9l~Zm_{hCx5NUFe@9J9b!0D$bNlwGkh;5Cj z9Ok94JHvT!ptm`IOUrv#X?a`#Csg^yhsfara4_Up@00^MMZ5?Z&g5hP)OT`#N9QcZ zWg$2%xC3)>n9S2H^{^dIvU@;<_$gwHWTlX|zFA({%Nj6_$3?OLqXsD>sKh2;6mdgyW9J4 zM29<#5^Lw!XfS}?3p!Y-YjCM8d}JZPaFmx^QCp!P(n`-5KM=5jBQ2G8aueVE(B4wH z1-V@A;fhJiLa>=yw7UG1l}q~P>Jg~hTm2I&Fo%JQQenXsVhSSaFJ{AaS}KMa%;}<_ zc42-m!Qc3Xl3D!rPkz9QpzRcGT-0BISZOzcT|Ry$16o<7LO)7r`5TAZ?MmprYX!*< z;Y_EzkCFqS14xm+`>_Pg8eS#geouaD$8!deF3IQ!iNHt-!~Mx{jt;)n?Zj}<406y? zz$@sO!3vnRoObFdOY(7+9*)i!OS~)@Ylze{>2$Gj;1^lEl;e#3(@v;SA@m_5cqz*R zp_tg-g+@p_<3$dumB%(FP-Vp`gl&ee3Ak3UA5*o6afT_b*s_1~)<{vvGB)&xU=^kn z+wg7}cOEH`IyYJ~#GG^QhB%t~txu?P#NR7;d>^|H?l5H%ygI=RmrL6yE#k!c7r^T+cM9L;8hXyI_aGXY)8Ne6L<(@enq&{>pkr7!(qk;9n85K zL+FvR1jRFyrMuA`(u2mHXw$X*?D3qYzP3BX7UKTcWzIqC}uGh%` z4ij`zS_cMWh{ie|v1B>|+0j$H76AjRFjdwxU zfoV!Rf!!+j5nnq=jeYFEb12;quuuwnVQ?C*%`KG1UKpH)Ykdo)u@^>MqAs|NGA%HT z`dgs5B~&%IKrIqn^{P9d(LiTo7}Rlg(Trzv@a$~WxHU`76!ya4G@A9ZnZ{li-8Dhl z?)=~^owP_mwDh`zpticRp|<9sB!h4w8#WL_4+EHn6~e+Xi%d1n+B_w)SqRzYsS&ae*4a54&RAN?lIn(809gjEjNo1HfI193UO>x) zxEyZ+(uQz8PDbC_AX8D>Ahtxcqzz(Ab3kF%;@oHfml;rWEsxz)eCe6mrz&l-rTALT z_Ni(G_*!0NR_>q6UB8%7d0k?vsf$T9%(2d@#`GOwI#llq4Raz5r$hBW_%MNSvU}DWy%MNSv zV7Vwax7YS{_DC&2U_#p(_J3+t+a(3nNV!BxspOJ6;B0}hJgj9YV<~Qx-BQX}ib{no zrA5Yk`_rtclnv)>sJzUc%1ftJ&iL%M${EjN8fIPPjIZU4=W(sZ*YYB>a_3L((kNOg zEx_&ir%{R!WsV|DnY##6<}|{vot*0k!*+Od$B0E3w$qJaJEy0r+qTn_U8+y>CL(;;7VCg@d2kbUjY~QN8JbKLhEw~;h=Ux*orpL4lA9IAUnRNV#8%m zrBe1&o487&460S1C$;N+RBS0Nob~OU+ZFEm;D=6jBD<#Y(q)yGPOH2u3Y9ZndzqXr z<7+wNwY`=2T3%#U`x!Q`nN?}&yvj@GRnGVvUzIbymOE#<+DobP#Bw=cdrejd*dHw{ z5wbIdkdZpxIbL!HDv(n-u{tvyN1=t}If*zOIv zx`f?#kzm_KN<4zF743Axgg6VG5VpdTN9a5|%yeVKPAa&_V|Hg>Cnkq?L#I})zP<$r zOla>0g_2m>4^m|}QueZxO8#&-t+13KBV{c0x<<-&ODSWi^;g(ZT4c;O8FfshY&d5_ zi4i8{lhsky+ncYGzehfZLT%i4mgAQG_XT7h%er zMi{n}a~)yW4$bl?ViAVzbYs{K&GP2h>Bg`f>P_a@>BhLiswR7!BQB>(Sx~!Xg5Y8} zLE~I#GYlc@LMMc+XanuA(g_K&<9jMUyVJ(3QuecyMj2GAK2O>MdLI>AN(*Owd)M+( zDLau}Q+esK%1ftJUKWMQ8Lz!eIkT(fjMw&7;%j-4S?y=o9nGvtOXpQyI?lat7n3l?vvJHbIz)e!;y@tn6Z`E2fLW9 zY5h)OAL=A#+ZyR4X0+CxBxZCa_E~KA&Rku>nN^Ws+eS(}g0L0sbi;%=3!Me7(~i~+BHlNJpgbnD5EV1 zXQC6rR;ZqJTj_+b6{-T=RyrYUg}S%%8^C~Z$S2^Qzd{xf)TJD^2V-|ZNA`kO96rc*(1Fbp5 zI8liiO?@2{a)GYIJ{kpDOEQTWtp%3Ez8sU7(OO(d%;-w&1JdrsB{&hFa4&)su0{~H zLJubxzzD)tIw5R@hQMwsoe;JnFWWku>Bi*X!sT_V8}0EeR#)_32;-PQ>4=E{!nvVZ z)dsPhIUu$~jc=Z%IiN6W+N=89=mQKjB9pA5Yk8bu#g}0keSsVZ3f)jQ>px+o1w$ zV%SbMCd!nyG$^NRTbm^{Z!6|hDzPcj8cmhcio>v|A5@Yxni{GVvnQ39ZBsL?(Uq9d zG#u6FN?eA|x4{%Z6|-?_&TL#2?0TSJhKZMF1PW%DQumBN!3=81kynAD%(icNDcdUM z1WYlig0mecs!Vu>$%HDhOPiC~#&EOa>9qw2Oav{MeTF_IP_&tFayBTci4s#CvwUKzW1g>ds$*WP%T8{< zq5RGU+X4h8g0`5loXi9ullv~12}Bpn#H0&m!qWw7WK)|T6sBXl23u%2MXKF}hFzxm zTWFXQX_!OJGUP;>ATz#7+w7=@6Y_4WF3OVXqD-kS%9iSwM~yONOm)nQbi(3~HAlhbnQQ;Z!0Gr$f~^8sy!yTB^2`*ben?RhAXQcDgZahx)TQcDgZaho)+C>~v$;4o%VK*y+Zw9eRf~$4)nf z?NEO@$4)npjrS-RR6meR0tM*Dr|BD;)sRo>cgfSzaE#4WbxDs>BDDt8M4a=43^YH|x= zDtimkl^v~hsT^w~3SnnxL~esRGvzH&Q=4aL4v2lCk#e4;IUu$~W92+cb3k3;j#_9( z=p#5g+9-yI&{-rAfm3MIx`@Cj?18{3G|IM}!X5~m0`<%AXVL4lQ`iHctC+D{8;x<0 z*2K5^+nv2egE21=nF{PBm57p)!CTQy{|r6#+Nip1t_##O)#~aCV+E{fF6g#XLn=%L zP_7sAoCwXfX#`xr6Slo5x*3pi z9>`|vV3fFaNtZ~r7}bdq*$!@rYzMYPvQ3%{6hSSKY;zGL+oUJ$g={W@Y!*;s%xRTV z1Kw#q8f?1kNBEooUir3rI)0o4J|bm$yh3g&P@&^}voSsj8bFVbKISS&+e6d@&Wiz%ciqh?e^Wu6&T88xFSqh?fv zd+>3oFa%j%I+r!2Z&_2imNlhkSra-Igqj(o2q{6RnG%NDsN(DxR%(U#y>N({Nhwr$ z_W&J++Q^Hr8BGy3qhSus5wIgN8ssn8nM^!HW8dC6-N_eYE%F%MtoR9LF>R?KK>XI5;QpA|Ej zMqMjrbR}jqjWjj75?5I?5fQrUW0TCZ)Fi93rPgd#)t>cSabD(})5RA~nB%N6PFTaN zQtzTly^|_sth%XE#;Q{)Wo#*BtOnR)OR39PfAy+e*v$m50sFSUfT((n&!pG+ta=^u zXh5rMGB4JJP9B2~YufkY#-gZVHyuw4O8s=q(iz8WD4nbHeKyD9%3|f2fMb|cVBa5< z3X`u=WujlIOz=yUiG8VJRvL$E|3VeB(rlt;g{m+V+8!Zt#y8uQirCll3|Dy_HPzHX zQ%#+F)iB3qUNy|2HW_*rX_!N8Gvq{?Dq32Hi`FX!y|yC5$8fjk+uE+>3)d+ts#-29 zdXcbeTGZ}hKwTO|0vs%Ae_a+j096(wgN+<`ZAGTm90%Q~YOjs5Zh%I~Ok35AvaW|l z8N1rZCGkX85$WUOutQ=1r!e~CRom}M8Ptf%NdIVmw25D&F9#Sc#zNm=ppl21LMtP< zY&_dtS=n7%gX|Rdx``hVrt+l#?Mz35ASy9xjxqV9d!8SMekm#&8|-dx4v*^?Vmi)J z!8MB7V5u^#uT+^DT&hg{Eme_w+Ep?Qy6Q|)Rp_EBLnl>fnoDh#nbekQB{OMgs+G)a zD03#a_`~P9>{O5;_@T1Nswo~7WQd&RGngdFptb4H);Ru|)&0%U`WW`-sRJq4rJ|-3 zmX%PZ04*8zzrzxU@zcmmeKAsYgF0s;HHBuRrnHPS`-`n><;2c#1{bwJW2TS88ed{{ zi|#(M3w6@7MVrZ6yF1X<@MXS9(F!wkcyu_%9T*O3g(dV@KY+5ZgwCLl-NP{3RdI%| z4WZjEov^|Zs_iM&8wRVmgv%gpg2DJCF9~p(V%VR#8cZ%Gc}Xau!sc1X)rUGXD`wX# zv8ik|n)(JS&TjN)C&sIIv)O2Ew2Iql;e*6w_&YG2hHQ065f6-6oXPbZqzS|vq>0TO zB-^BL%|R}ZajjMJv#!Vmj20E9>1Elnn!rU$yVd??o0FZMeC`gG(t=$;Dev>4rsU^? zP2tZ6vt{a@=Y!eug5X?Wfnn2agxV%qt3xYzs&7Y35$!N3!nBRTNky;?Y7-3v+n{H_ z27+yLA=m~z6L#9@LNo(fPELvxMBR45@gonM1$s3UC&6*(0I&~yX3jS*=R*e|2jR-e zO7E)O;VzGmt?LvzQ7vPpYJ0w2!^j$6m0%uHt2pB{tkp_WjcX+{slnDtW;T>j?(pND zVeVMLiP4NXCuTXJidj_sV^*kQ7FD;H6{?s;FEwLUsER@{9v+WF!HUp5%PHKmENTJS zJYFhs?9oC@61f4k%|0-?l+Z z!Y$vyM(A+AF#<&$T3@U%IH@I7a3WN_N|mWprHWauP}E>hEUK#A8;*CkhInie-c(~JR=kR( zsuf@Yrvp^re}H0J)T?MN0~Fhuhhkf3Xs$oW?VU8^*&xth5u~GG$NW&Z(Q_qPs%&`&m zoJdmz4g1WZTb8h8O-LHU4nFflX-KT8NbojtY9G9WA!5#qEdqxR6wI(y-Z2729WckR z@p4|-j>RzoMUd@@J;0fAjnXL78SV3&@jho6U(4CPZ9TJ{jIZU4_qodWTF!X7R>%<P}w7`CnX#$r@u40cBj;6?pPfAt8yK9zm42{Ybo+$c_iM7=U{QOnbSA@<&g8Yy znQT@%=1~qS9rI{BsdUVXbvY=r5xh)>Wv4JMk|% zMsQ`p+AB_sc%3^lQmb02xor!chN=e5?{;uBQWdnYIupxk3~2&A0NyIt-`?Ilp@YI& ze{~1m8PdTNt{$}XG7q|_Ss#f`4-jfv9yRu+yV-8;r8>cEnFh~AEiVXOFcd}Uc7=kV zi-yA3ogWHgd4BGUu! z)3xr+QBINO@_Qq4ir)iqUPv*|uJ>_=gJUN{&fF>-vN&HIbva~lS{?N?WN})1W$ihD z#qblh{mQ>`U|Nvnhpau2_MWTU2{+qWohu~mIjKdObd?m57EUVco#s?_%UQg#Th`*0 z-Le+1?3T57Ww)#xKzWRm+a2NTw|k%rwH0{)Z+<6oNvxSqrYBUZ&18B+oK1G8FpH_Wjw=!GJa z&B(WB>2R%M;F=FLVV@5+F`o}+%QOR?4`#~?f;&Rt?})6@C3S;N`!8u3 zqgaM_R!USWekHCIx)RrlT8V1~ti-WB8ooO7!S?3k*dA5e1?w^{wElp80i9Ro@Dx>X}~$QT3g{ zqo!6K+Ol06TQRWia2jBDTn&&d*4<8(G+SH%$QD~gW|C%$3jiBI?C9x=UT(X;4sWhp z1*F-gmJ)jcb$A}oL~9<@#A_bZL~I_^#B3gvty2Fp56V^-g0fX=FpF7T2%1Z{Wt4h# z+#-ko^HjAUp53N?Xh8=zd; zY=fO|IQfo?TChZp@5wQid#O|vwKLiFvPw{f6}Y=vRq*b9r-FA^s0!ZQ|5Whqs#L+d z`=JWX)>|D+1!wCE!#j(VZe4)YwzOE*U3&sJJKySG0s_0g2SRtzHdAPI6#*fK=;+$4 zyd5HoJZu6jj%EQ=Kx?ppz{Czo5g?lwz{1f0-$*sK-3HoDa&S9ZkVHn+#)^j}WwSVj z_qK*xlj#YQamz~D|IganZnu%+>cZz@`T~;fq^J8=Y)i5%f1l}@J@5IYC0nwsX<5?f zBk9c5zaUT~0TLit%3iZ3ofIBC06`FBu}Um9d{j9bFRGjk5LM1bgeo_jhfcCQM-fXr zLCf?o$#NlSb}!>nPr5KpnWiBm&F(cbUDFVfCViGJ_lQDdNl6zcK1q!vR zZF$~d*`0^a0WauGx)0=~qAn#h5owA3^Ms_Oij?3;EfE+mA}yRwbq`e$Y2gjCuBD1d zt9wb663@Fq?NUXgB{E8CsiM5IjFklInhZgvakBQ!%rNA68ACjx4j4RT4DpEGH+aez z;t_ph@RTvcBYMr?DPxF7lpKSnjLAD)S?*AWv2Ir|izqH7JFGDZ(_d{!3jh_p4Lv#3LL+ITQr_R_U4tBx{B@-yk6!O%ff0H?#3pDY-$Bmvwj&Dy~8z z@(hPbE+pp+A!*`tWoa5h+ts)TgMLj}ov`3;)Kwjh+NxJk+Y}paCwIQWYm!+`bIsgm zu8Y~GFtdzPq+}P%i6SLkOG>&}LQGvtS_o7ObK1eKxv`J*a71lePLAsVi~6>_6tt+X zhb{WAhbHRV@;rEQt;^!(1ySYO?CZk4232^FZbKr?db8Y@kK!>A6h7=86T`}ii6I`W zizbG6${5z26&~zT6GJ@MZ6=2NDPy!CvwQu>?Q0#DBYv5zWS7-|dFCWWo;zu>M`xE) zr+wm)E0B@opTA75upICL!YcyOz(FagNJ9~j2J=+fPz0pGdPiy~g0$Jj9Z6_^CeKV} z2x=d*ogs(=m){hc3_%;-HPQ zB1sWaNDnzywFL19az#%Ok0~XI$8=3{yK`BKJcf9%6q^|0!3t(#h^LGp9z7|gKV=N@ z=!q$L${6Co%2jDs8B^%=-QpF_JBQ-H7s^_HB*0e6xE!mJI%o?m-CEKQwoBzKcq|qA znrLhRH{w*N@ANUEdKT^UR3c0I2&q`=sYI6aF;ubCQ;96;qpV`7r&3Eg(A`;&jFSp| zO~gznju~#GIpb2LQkf2cPL-N6E>$WO@`|NO^5~X&Dm7)CZmE)SsZt>waR0S?S3B8> z$|isu+k?2AVkxyl_aS#bS1VQKjGq)5O~@Hk8zP+Fqf0rf;Y;bN;fY^QIt^c1k7)SD z;23uf~|Vxvi8C%$GdQ=<;k=UUzYnPRDA78P4l#IRV;txSWj>x ztJKC56v?8#9Br_8f?|)fDg9=zC4Y4N9uDZwb12v?4(R$l9LS&kv>VTLYlim+s4MSy zP!&6s&TME3ua3}Ep*k{C1+t*8f-zfD1+vgXfh-h;u5O`+0$I@4AcZ#cQ0URk)mfi4 zx4x!e;D!ZDf^PKMuMaBYpdgro;)_hjcQT???GQ*Kt=9`1ylsL zETAO1hu826lZG9i?r|hWv2Dkv)9|a7+OQ}8J-R-~CB8nSC7$?8_W}}6{O$P0_`7j| zS(ly7qi-2nhxJf%O4Wp#W7s=Ekt~)LK1GWsDE0`cK6ABYpbL?%-@}2@ykp-&$B60r z1qbkmXZoI!I9NJMqXbx@+-=|!CHtxSqLcgFQmMLaGi)SY!@HUIwbHl6431!3{+Is_ zP7@}oSaPuwv=)e`j)BV~ak0X# zY7O*QtWpe{IN(cc7!C;aR}=8;aF{*6O*hBG_6Q%dJ@S{GQBMJ+zA2D2_zHwruufQp zh@}W27F^<#S&EP(DDy=nC<=faiQT9`s5wPQ8d{Sj=70hrmYB2(gnTJNh$TkfWGO=Q z(85?}IVV1pgx%QL%3%qeJCiBqZg*a>A16?Vk<0+4J!ZhtUNc~6&lxaci@j&Sl4ic{ zW?OdvnkfC)HZD<>{J1B>J|v{(Woaa&G!1~1l5R{SDJ5M?O1d$9G+j%oHrCi^kgd)@ zdJ{63-j)oeH!6b>TiUt|Mr^ToQHU}au~lKjhBsp@dknTJEOr6Eu|i_wNA2u1wH#KU zOENz*M{;T%)>i{TVJabr1IK5Pql73l#E&>~1oAR7;t`Q#zg;a4?k%u9WPzrDv51nG zN`@?;nwUjX6SGiiV$#MqYGTsH%Atu#+Z2;FjxJl<6k8$lePe{(i=+C}@;^uTfN7!Q zOoUF7bQ;&@U50VVg)C^fkV1wfBo~sVAtX&K7nY_W)El{56q@OUx~lJj&_moIFC>4l z3TR@|HN~Wjd24H%;^_8j`%+2_U96}lu?l)wJ|q&B42gtgLLy;lkVse#BoflW1V|)G zV|*8p64b|_;w7x}G8t)M&t)>!ZJCVpu+K6X>EVFNWTdCdNDoVlp{L784@a7zr^`qW zAE_96x{UPj{dhx9m&ML|D<`rpR@9S34tiN4Clb~RiG;;6k&q5XGLeuDrfVW09ZjM% z#-}SOK_Uk-FCjyiteK3obQ$SkvKo52jPx*B4Lw~(dYG(+o-QLj8DigdE&N_adYG(+ zJzYk6n5>4LE{mP_R8C}Ftf(i69Q1f1)AZsEat%#FZKFv=)6pcPgMFHKK+)GEq=Wsb z>Sz)r0KO|j@&__6Aw#mMUdEE&(38!Tdb&&thSZbc@G{cFB+h(cNu0?@k5)at!#pSH z>9QEi_2vNka)p(n1yCt?g5lk8AkUJL@p3Kft4v1i#F%F?YNsw^{bA@~e`GS!!!*of zWKWl=LGepTQj}rwGToq;>L$IEbg`qEvtCNNmQ;0EW{`B)%gAWjTV6^=Eh*`yJtlQ6 zX>@qInEhEwTtluA@C1bBM$Ig1QxR)uDq^inMWlsIOhu%HS(%DROBIn8=A^ErinLJ3 zv=PDZA~J@>DjM@ba?%izCeEvtrXkc^l?fwU^&&Eec^D0Pq1ty|NSa9(d7;{WUKm|n zZT4@ARr&VIgcvkQstOZ4TQN-(DN7F_{k&><@H5x0E3VK)&dnp;l z#8KsB+Ln_({+_y^Z_5qmeLj%+)Ojx@tJ!Kp44Ncc zg?^T;ij-Q9xvWU3?X>jg&U34llyos46=t$)NsY$(d<-2fh`p2yV>YUC(zfNKkJ(tz zx8;WOGT$Iu1-X}!am+?lPR`qM(#LEp=-cw>{Cu&ReJ@S_7C@!o83S!+x+GDRd{9Dv zGc_+`0aK(bT#A$hOOcW;hDwn}hvB0}%k_dH<=#or-kvC6bRrj(sqroaCsT0LDjd=k zB(<;wNu0RGY2s`_5+|0ACe9Wlabj6%;%q_M9mJkbr`E(vBDs*|WiF&fVB+OMmX*0s zchwISQiajS6}`|f>cxgxFDC6Qlf0O;O)+U_IU}`AF==PnA+=30X=iyLwM{W;<6NQz zmD+8Jv+hc&WJj4+$nLUqF?OrJPQKw(p=xLn(&4G++42PN64K$_<0Yh{Nl1rxiqz30 zq{F*H>Sz+u!Tmxt2AYI)aDG>HG)dNz`@?LcT;UCDNE`7xg3hZ%oacH1 z$g@2G5CgAs34j<10Ak=(Ph}_oh=JEYm7xG220mG-3Eg1w_=$){AkP6|h~(!VnS`2-RXLNf9L{8zxKC<4-8T_`ma0cqeG zPV-6;kOmeYO+yi+-Ip%xh$dUtb(h&{jA9%5+pUQFB96Rbea?khzjGmJvM%PrtpB+% zZI|1*2=gl}xRjLEAR0|rIMDaqv-KLq#<3a5EFJ}H7M=o@cv&$kV2QU4s|7(>w8eHu zp{5$5lGP;PZ(drQIIgm&1tH<2P_^sc>dk)N7QMzg=;ahkRw~f9oS}pu4pux2juJv^ zi2kcEB_29ZO+Ou~W}gmKlTU}Lxu-*kl~q$0LLEx1O;BQG^|Qv>1TA+}{z>?ld9gtO zRq3RFtMpL7Rk|nODt!}h#Fu2Q(hlOQ<0@Se>=K{Z9|1>vxR5T!nfU5B;-gh{17QPD zOPBa_%g_*VP?R|ZMeeaF)@8JUBept@_>$?t3tMHqW)Na2LiFZf9(H?L5Knd8 zh1N8nO&Qh@@|KYN1je#{qZ_-e&$#eaUQ$f6?r?)$LW>57UhDy}xKA3t!{ z{e=kGZoa)Rzv-V*j0zm!FGL8O(6WBs!e$zyVb>yXdDy_6EJOJVYy|pCY{dCXY=rqs zY()7>gu-I#FA+*yA{5T35+yDX3Ja-3iA%A8&}#ZLGixKe7J+V;W(tz!`jtV&RTV7u zg&16J2fes&(K6od-;wcKitraA1j*^+P}5&OF|t&^dLAor@-Ae_`y;Q{9OGV7RRK(m%MbW(}jBeQPj^E!UEm(kL5~c({&9t;K5mUqOh|d=< zv*U_CO@dE^!MDi6^{B9Vex1V6SE4M0OA$6-9^Tw(^uPQ(g+!gLU&SYnRcTayo~@pb zD>&Z)yqLW&;8dF98oqe;;(pl(6>IhmKXa71->48x9NzG!tk3W#n3;ZCu7BYLSQlsN z-)8U*g{3TnQT6?JSo}q2X=a*=EGjO(E+7iHQ=BO(vQ$yH6Ecbvg)CLvFJITQRo+Ze zO{7tIzj%jVqPvMlciE6@1j4=GdL$5XjbOJ}EoShUrYvreBZWkoE*Bv9yYKMA%;qot z7)ldns+47{42tyfFLL10E|E}UH3=0N-1|^wClpC$C_W!y3Hi=E7ph)r zC}-ym!7IS(0n`zg@A|o7LI0E8J@)pd7`O-f0AEOrAzS9^lYDjew2t(+J1| zECiGC)IwS78&a8U0@Kj*CK+%^kyJoZFe7S)gQ+PggFz>G| zv?Tw}adBiv_hwreE-MX8BswhLVFx$a5aJh8sC&le_M$r>GkQi~DTMjreHUNncSFkON4Zu8g@M$AH&D_I7&CUDtd9{Qm zN=o*aNODv3qKT!pw_%A_^ks#&4NJVDM=QK-SmG7^TH$TO=AE{O`bv+W_wFSpv&#&e z5?BMN3?~Dr1l2$)1Ij?=4fiAOxLv`sYG3N$FWbX$$5)c+c(D|kO}L+PRmy5&BWmPE z;Qg@fi8;KoCw}ke9nTOHU@>wsj54}1Oy&$N#=GaP{>=(loWrBAZ@Z;fpLfpHHF9U` zI=S<8ojjB4I(bglb@J@4>*RS}*C9K+EYx+#PCuP234HgjkE>N)`=vBfo^PgbFSDb^ z)l;29!(>Ew%d|PbOC7u8I^1A&vy(yGq7x0lts1=La)5Inj&RH8Ua_H^-cM8dDl#W^ zu5?3WxqjK0lm;#mb|myGu#85PX3F$(i{2SrMk&WvbzDlxWl2ew*Q8w6l9Dc;v2$HZ zO1gYj&UGy*>GI){>snIM#jU;2&+bJl9%W0Kbr9asO5M0t7eYmKv$Zv&EK|gSZfOc( z-aSH`7f~V3J4lH0(kR4v7YT7*@PwGO`C?dzN!t`>A;XDK^lz zhDZA9Bs8`Pj@0yHKe{FQ*ZKd9E+77Wcm9vj|Hmdr8xm={GSO}HfK#*mY`bJ679dhg z?(Xi{`(OjSKb!vF<6`%H;`W4IX3u=(+Xk=EKdgtixA?~a=Ewm=?p168=|*&=7E}0^ zFIntkOjDzr#u>}@Qd6XKKS7Z!;`4-4ES{i97I9`h#o`Hyu@n7>#2bs}&HFp-Jt=uz zhOtg616ik(fvgkCKw`w8mw|bc@hgM%ChIVz$vRMJvJPZf;9H^ti4l9f3?xQeb(Mj{ z*Z?F(T#L0ZHURT(@jc@2QnDKBEnC1y*;V82?fc2Odrs9A-2GxlPp>liK1$KlYz`mQ zfm^1p-M(!%o4|HX$A`BNxFu)IKPNLpCwyemI}$W2nxD^HC+I3;ptof#&?nm#`^(klTfQPtAd$wm-zVzb-4LhiQFmJlZ+F`r)}oY~qF~{~ z88XyuLc*3Y%t1ZOpGwr~lHG9Ka=_~beA@~Eb-X!Dr}Klm3tg^8rIjsx$!n}VOH->d zvP?Z?vgu(@Oesxz%2d>(r_4-EddfuAq*v}dx4DCv-?RG)dbz=Ti|Xn76stnW*eq8X zbaF#3Afna}7yCcq{KZPfmsJ|f*v-g13ecQ3Z*l-PgePEgVxA|so0m=ez6zVjNZJj1 ze~X+^8S;z(?}PDCJN@*{xScd$tV;Mg9 zxrC+3K(HcYAXvFE5Uj8m2;$(|kg2D{Q9=+0-;UHdN{B3=w3lL~pp<6H_^Ywm*V%G~ zKl=B3^A=kLp3!&vo)%pqR@Bw9)%B1&R5s=j#g=EJlvD56@;pa0eZGY)<#~Qcd7d3o zp67;?lRnQ3DJOlt5h~@RZ_7!aZ+C0@wmj=R+Fi7|UP?3NZjaZ}PQ-ca6F?sP1dvBR z0p#IN0D1fqK;8ifAPWM%0JMT%VZyZb=K@Zt3DX;K#hqA<*0W=>ibAg7Q;B{<^= zq?iJO15XE#egQxXVs$D_5JLe#3}S;rV<-TKL2PJf3SV6yO!uo!cK~x3CS^NbEiHx1~cor1=j#!+1K!O+a4Cva6tt8Kufu7O8SJ$*S_q`M4-CTcAK9 zjh`FL?63eig^W~I38XlxyKGOA;OYBe!G9cLLm~}LAMir%YW9k6c=B9@Mcs1!&VLuu z29NYU4C&Ym4;u#OkAKLafGy=)ZgmujO}nGy}kk3JgI4zc*F zM3-#z(dg0P5C8m!>vMk6R5iR&r-z}*eQ!HKB{!2VShBIr7lcsOWNuO^rY5KN23tqR)q{mJO^Uw)#9yuY-11H3J+=Ms}n-G&WkD3tY zK@(!q<}nlE7&2d5t?FjTbAoPTBni4#7t&nW{fxHz3Cwi*Z~4nNPoZFPB4vs&=uBiz znoSV~rGblt-O%^3PH0qVri|g4?%$4w`Q{r0&HkyNqt}22Wp`2*-uTp5b*w?`&z7r^ z=D3WI(nyaRm(l3p69t#j;IO2m%cqH4*OHPhpF?t8OG>)9IP5YZ*R`ai%S&{wYe};p zceA-3Wg*N%CBzhG9xEZv8!W`6&08$Qira3bV0j&7QPEcxV?65OTs;ppd-H<}qv~|I zpF;DycbT`-ud|gn$J>xc0{DE~pK#m(y)MUY^OEaPA!&^J8Jzn8BD}~9KbwIip*W$o z1)Ni3Q`?AbXinSp4ku;}F1X6iTlX+%Z6I>TbiVC2>&=nh+gFj%!)}%_kx#<*e5n4TIQC zV<5X}3}iQrf$XL+kk&MJQhKG=Qiw^zOeqmU8U~Rx`0f#$mJRPqLtWyL6jU}W3AhbR zf^Gwoz}vti_%^W6AVaAQ zOe;K5b@N*n^%P?hF>59f!$=}lVVq%eYAWE$gv_$=E+u5R5@9khB}-aeMDZy$uZWcX zb;7KjYsKoFX{jRBy>!TnWa@0Dn6&PZ`4mM=v9RkXJpeja8jBQVH;{Fb z*+7OVG?1YR4P>Z70~w0A)CMw?Y#^^g5ZtCRn&6U#RvANY7LZAU3&^C=1!TG5EJC7p zQ$mKTG@K!mUaoS6J}e+B4QJL%4fiFYo5Q6&Us{YF^SY+E*o$7f5=z_8UIFf8#Fg21rlAoxV; zQaFu~Phztly?y~uX_#j)TazZUy9ub>J*p6LBn-F`PX$CwVeplhDj?ZAjEME1$W0w$ zH!b7Qn#MqO(-??6(wfFVYSYrCpVqb%V-qoJCK1EvMB>Q{-lkLbK%{;8r!7U19t5Tp z*MN+Wv{aGmUb@86+L>bXY)DbWl%_+9((@rj>9I&rb^}=_nGIx^LIWA9&_ISNG?1YR z4P+?UK)xP;3}{*&Cb%*ovn-;P8fLf>p|8Zsa>fk>sVZlR#BJeC5m_T;u2)DIvP_yZ zGj%U*s7vC?bfZI(#L_`YUg;oW3RA2OBBlz6n8H+BVyb|M3EydOHM7K20TC0vXjNmX zfQSiSx~ef%Kr(|^<5-r7eAFT2P?$Y*kevd|7%^$R%RqJtFc2|my~{wvQ~?o_*1H)~ z1w>3*?`BLD5HV@Jn=w^DY6_$qPFfD67;-7h_+1jDC}OIi^pNXZY0OiU9`qDNex*@Q zQF_=@6mg|-Pf>c{OE;}PqzQ(c3JV+qMNZXF#FdU@w>_6n>ot_!z${0*shGRYFogy( zRH1gbkb4Aw9=enTB=C8$8HZmQAxA>1|Y?e^I?XmGPWRzGt4wq&K6|3;j9Cx zn~jDuT&3X*NsMO08M4xFh9pk2;S5=7c#@Pd(0ed1`ui{w zC0MnYFg>T?%A1KGnO#~l8JAB&6DG6EgvsnOVWOGthf&>$3j5=e8!_;Sk>mQnf5n9t zO_-#!mqm^xlS*ZOmM7lDz?qT}%0 zXu9#Sfao}UX|Op8h>oMsS_;R<0;1!^b8mboftV}DeBc>WG##9Iv;|gh;2a9plP_cn;<>iAe zPSkT(SW$+|L=pqUB2 z`SJlTisb``NxE!-z_Y8gd~lT3^iMgih$%2Q8|KPd>b zd?<4G(qMBG5S<@|)^>gr5FH0D4s=gDjshZP#FJG~LROfFgrry}AU}}D08yK;n3Q1T zQx(=l=%&@Z$O`mE*Bnp^Fv|Y^ptnk>7NVD4P-xe!l z@(&&rQIYIz*+N!CMY7k~at$ZD*t3cSh!kHJ&%eA(SBo{j_2(BAD7$YBNWS+)7w60U zAw$x|lykk=y~C+C|K(?j6A6=~O3%B^p5MlkLU%QSAveR(IkW9{_1!&%V160$E~Q<8 zG7w!#7ZAjOIbY-`A&3L(QIVsBAP%fTMUE1JIB;4ka+DCUQ)Y()99u&l5MTVY-K^m- zoTb|iPGX{Vn~3>pi}bOl3tQLZ>`aGk!ZR1_V*BYXn`j%R{GEqQ zIj)f!3X}{u5oYl+R45L;RLBb6Blfe>ON9-OepYa}w5suE3_Fu`uSaFT0Pp-$$N97ZO9hG~Bx_?^po8GJguT6JJdag5l&#yNVoJ}u3y99yKYI^-4k{TVP>KcUp0XDb$Fh6vkgV1XolYI zpu{P+Kq8Bz{ygdy+7wGkg$peuj47J(w-rs?I8Qcnx1xy~mpjeet!U!LQQFMiiY9Ix zht1rrXyV4(+-B}pG;!nG8O_|S=wfpFg4{GDGjNeQ+(0*R=jbB2t5~qDxp+P-=F`pb zusy;jBJmA)eEDqJWV4whbESJE@b%z6*_>CJL>$$jpTkx;9Dcr??e}n2`R4e_cUMaw zN)#*+B^awDB^a^c04TwTtqLPH+D)pqvkKFL*3DF37rXs(vxWd3tjMWIauM%rc!O0e zwYm*UyjWcudE2nWil zt+A249p5K7k-sfC4&Ng;390CK5=l z8Z(827H0_wEoPg9604DD5=yK_&PXV+HbIFsTfZ?l4I!TqR;xgwnt0$?FRowSI&FV?2WEG#ooM!bTRkDgt zXil?wl4`F6hF2}$XNT!#z534TK!dkJks8{Xg+jGo0t;2LitDew4wKcBRLN> z>Pf0(wKew@t0$?F)z;iste&LWD}nu-0pCkLymgakH>0~}L;aGvN=5-`P4p^VzvQpd zk$0_GU8UG}<(Djj*(I!dZ^7wl^6;DBaGcUs&*h5fSkagCY)dpYDf`6 zEI3h?S&ER@obBut-Vqd3X}<3li$7VSG;6R1H|wwnH0zKZtSrqsWT&4_ub^cEku1V) zUW1RBay0$*1(s^t#dhmVK)}KxVjbT)fm|~Y1(I*mI!(mrM9**< z$)e07Avz5%EsNd=1a%fIF}hizbkkgJ zR~e%RnHJl{C`*VDW(hLlEJ4IXD>c?I2_mKnh?uf2)0iqCV#+#1W2%7kaJ$*GJTe4A zCpj!ut1^i|=p@Va%ce{s5ITvQi&)v>c}^l*ZOZFis_2BeDi#jIWGB-V-559YNJL#v zH$yBPxt<{;O||lPi-wRiv+U+J4Iyb}*~~Q!p&lO0aPMt0cXTo%KteN%kkF+a9u{1o zYe|jp3f(Ne!fqBrp=(L?Kqc#8p1CB_)!c|Q!b>7u&5c1rjYLrm*8#gQ=_f-|l@^u7 z09DlG7)=1_FxADTeV)dUjEOc$Svsn6nmI5bRXIy5RnF!xRZjYtJgS_{T&kS(ageHV z(zoSi@I-Rw(Gw#B$6R7w=obKX00jdMP2GeYLcyTLShNDCV%-Equ>df`m<;rUJ{{|c zI2rD$w6i?leVct1=S}e|8HnBNMI2ttq4@OgeQ}t%{Ul#Tm{uZJ2;4TUrbyQfh3OvN z4w7f8aih5P%OQ0dwpD6*!;A{FMV_>s@+5OJK?$xP%#YzOYSP29dleUNl7b{`mV$v4T;o?%G z;n2-uyHQ>wc&ZRMxgc;Q(|sU3xF{V^#6q3MS(c;hvH}mbl3__&Tq?Ucm&<<6<)rTi zWG*LtTV8ZN>#dX@0c95$hvfxh@hPbql3A-l%FRi0C!=tHN^>HI*__B?HYc(aA)+}+ ziE!srMH*H)V|sarpgI2LMg#i^V^_7~Wto#1-j`h_kTGKdnSM+lTyh`N)qLXDrBhrY zhX|KQx41<5#U;Wq_{Es&7{5+Nd^d85%vUZU9bZAYgmg5CbnMqpx?}9RZ2b$9$kua7 z(wIyqG?Ph$V`-8?+hn~}0n)4rk-=0UGO8*>hF68uno}Ed&|(J>H10d(kl7bNJ52Z}HC}pJQeUvicWZJth z%4>bsK?Dsxb#~9YWFE82vXx9Ao5%#ReM}%5#{{}d`dwLgIAiMujB zr4%jSCqiVjh;8H0{1cTHe?@D$%xaf=>$Gs+iE%02T16iO%62D%S)Lg;wB(U>R~x15 zF4M?De?Q1>flIzH!niO_7ON~8$-T2sDVniU4JkofRFAjog+54~>p{wvN)=C;CsHZ* z|9$bk*@ZXwSq6K7rJ|2!(lWMMI-$rzB|~(W=?AWh3p7^3dNWCnRG3&UYUyB*iX5aO zlZ84P6hcWfU%uYJx;R@XmyvCx*+Rf1MPwT(OkOh5CMhCwQmi-O6_08R%J3fadNfRW zBP1qXk4qWe!+S`Ov^ZhlZ3Cpx!vwUrpNUSPhY1K$KNFooZlW8n?RivF=w(9BrGg0~ zn+h6wKGhULD_&N!XMCF~4pw$4hrz2PtJz=iH?Q+ufJc#{X3PmuIRVrtqA_1>4XOx~ zl;YuB*NX01Ty-L+K)MAdzZ%!h{Ayfg@~eb(H?90CVbiOGb$8x5HoYnvrrc;GeXAnK z;Ad}8#gMCI4DtNhz*ELl8Wq2J&_yV7*dc0-iY#`cBG2EQ@oi;=F#sX<|cDhOgIA&4W4Mw6q2AdWCfO^yw$$Ie@oOFL&z!xIn zt%k#H_8flq(dDO#2qf>@U*Pw5_#3==_bH`VBvc_+Oh0 z2xq$EU+}UH=T$OT!1Uuq+ezdr8S@>#Cb-q5h_8W8O9jwW<|b|v66bak5+`O8LM(1( zHX+2~Uav4A#8QM1i<`bHEJcV2tvSJy4Mi-}-FrM?n*|O^IL6<15`hZHC|q;cN$WD> z97P6DDO|CtdgG{6prDN3rNa|42VoS10)mA01=aWCQ&d)Ocju5nmGxJ zYUoUsk!_@6_pwNd$egrRj41#VBfb>UW-hrN2;LM-=Z1R->eN~cn^Brf0Lf~ z0lv)syqV+gdEqTL@sge)>^x&q96pvR7v`$?V+>1`3v*SPrtsIm@Y8oXL(^9k=9~`m zBe)9mqqqtr#_oN23aM_I7#o1Z*!@zW&e#AX#_q>Cb;brDF?K($sxvkKiIGkkfin$U zYL?>I0L)Vdzd5;{t>9=6T35i@ZhzRkE9qlH%e0vGZL|_vro|!AMk}Ej?b3bw1P=Mj zK1brtig1CahpQZ7&`|hXN5Mh15Lh*kU@pf+!t_mV7;*7Z4#QvfGCLmIU8gj{UpOQZ zHlh;=>EJv0iG*}C3F+WyR&_Lq(U`cZW=*FbF~hRjYEab58|!3NqoQ8ktf-f}AN6#Z z(l~ij!W-u$TI0M->n|@OJ^UR;h`yJRo-WgZBK2fYyo~f@!@Z2`=`tCVSJTnIC%RGz~ZN9CahPAOc?z!@Dysq+=|GC)EB$70V`t0%bO zo?@v^f;G?O1p>`=PC#-=fHhF5Ya!pFEGl9FVCl9 z;3m>~Y>k+PNE@-hvbvy0OQ2b$Xh5^t(ST;vqyb$B2xeidZd9MWltLI2Ex+DI={d(aEjKJ-G;#5QCSmf!-lpSWrcOI$+eXE@BB>J*ovBAMI%OQyJZDTk#KoX3j!4euxt35^I%LUjr& zwW^~@SXESYup}lDqcL%^fPyAeoP-SJZbvO$MtV4LWti88 z!+F5)Q#lx{UPj40c0LmnoemCqdqMUP8uX2YH#6k6uQ4vV*)#>pU+bJ=sBC zMtZu8^kfG~JzXY)Lgj*$Ru^D@kxbyygrKkznrw#UzSd1iwDx` zdNY$sWo6+Y)D^iTu;*temw&EO1X8e++}x}Ca;h$O~B z5;R%Ql|VHrT0yq(F=P`dtR9fW(Nia|>ewFbSexTDvr^uB;PKq}m^zzHW9;@ZGCqd7TPagi;ZUNh)GdNJXTD z?M_9cg{zQML|Uqdv~UfgYpEhD6zMI5r0k@ovRoIz9Gj?nxkliZAkqXR58~~Bn z3rWuqk|yS_rD+H?SF@Fm;&X-}7m|+8P{dS25f@Hmu{j1;4Mkk|WV^~$LlGC=TvWMg zDB{8!jw)9TMO?rCB(lngR}Dp6ACq)3$f~f8t=8d`79VRcEm>(1pd8I3f}xm{&4jkP3x$0Vz8GSMA>O(RW}7M(O-T6D-x?57qT zveQq8?BG&3#JCm%veQq8?BJTKr=5N}N)l{$i{xe|co0OI8dPmlFUWF5s?_oAku1kj z0EH$Fc;eA#@Ua zhq6c_5DH0`IpOy=xhE+il5A(N`wG82TCClNDW`C1j(D?D7gJ1e($N9rK>pb$S8Xbq^ifDPN|m0V|Z)BMpoZrx1c`SY-_!A!eBuTo(Y!UCcZk zKnz&GbpSCG0D2R;^|svz4$vvGlT~dp9ZGG(+QHkVgQ=a3U}DCS(8}BhHu|IFbJjOH zI1jQunZwZXZAt+-MI1=7Qh0_$POZZ^!9Y+qln}*UWnLIviHKtVF%F~C7)Lg=DEN${ zgwO*T3p+)F^@xjS6i0O!8VmQ)#q7?^m)G%U?a=1H z7iE?r`;A?unEaqFuqIoYQ#c2I9e!!eSqvb{p*BuTrW%x3aY)yotTNZ2#ERS7H7Kz* zL5USNy4zTrpu~!!rj4};s$@>yudssOHKsrZC1oSov+Z;>`@T8ypC%DuCQk{nB>MKoKGPH&vtSfXEHz}%0#Y|M0ErQ2&KAZ7 zV71BHk?!)Bp)1 zyES|M&vCh1pkFU=gC4&K26@`*kVewq6*#bVF@uukLUgh#8cD$wte#KDmlx=`HJq>j zciOYvGoK8z7?>)3%q-XY#STt!awi;>G9WW16;CiZJIS8Y>SOF>38zB6FL@292Qn)4 zHnm)DcJ6$P{qY%6c)!{83Mv{_DEhdugLB@#@;k|Td%X%3DO?=2D^V5fsnn-I%k?uj z2p>j-GVszXoQY;1qpE&X_F-I9zy&d)d?@qFD$mJy`Y+;o(@mm*s1zzjS=7foA6B)uh{A0I%1J=R^CVE>S9Y&yx)w zefGAMYEjPB*JY_*>v}HLE9N+SNPF7d-K2WO3@_-BJtIpCdaa9+)K9WkUuL9wWUs$o zW3qJbGW1TDT(8j}-ksu^){DOu&qsXU7VmjVV~(eHfuN5I80YO~vKd-Omd(&Q#%zW@9YIZ>Voq*h>#J8H=E{9c`wgdO z_+%XHu&rR*=Gl#iUM|=qC%AHoW&gwQ#{0p}UvH_eRrc}`C6Tss-s8RlE z8;@BTVOrF%`izS%GCi`^U$0lK$m}(C8`JC6aZImQHDG#VuRe3?@$9eHnk?>%52wz3 zs&1p<=O=hk$epUO*}#*M;_8{FX{Od_4rdqmn62_Vg#1<{U2qA#*2J+a)<=D=*_u4L zCZ%gVeR55*S>GedHOb~Fnq(6n3is?4vU!STV*+(c%)a@PsTIua7O%@ayjP7k>wZGg z>UIKbqQs-F=d=&d(uin7*K9FLucn@2)X*###Uimk!2aMnEuQ)owW4mLVc2q{CD?8{ zgR;7=uc14uiejTle2EpmR6`o}Y8L8Jzc6sU{xdM8N2y;Jn3x;EF%-B1lDv<~BCCtZF-&qD zK+Y5ZEb~hY7*!p>f};aiKy*M1!hG>`e09gDLFIgY@8*gremfU`#pT{>XF+L$NBZ~W zUz}I|UQ82G+ps)oVrrQwX0f%kF|wMN#Z?otsA}TaXpH&mZnk~HohP{G>fR<{fh=HD zBE)ZZ8~1)3i>S_Mf>mm`eZ*-Rs!JPvQGsYc!7R< zJisH_?36}yI}_XLZe90vvpT->v6Yf=P(rm_mmEo@rt*Aom_5Hu;oaFOb3S?71l@|1 zB^}ey?BEQg$r?$$+$3<1scdzUn#wQB-M*mRiB0v&6cJmI0a-apqL@Kx48)>eWyR^P zjkO7yG{5U+cT__fcOgpD+yed?x_U8(I}ewm+XLS%LVtBkHlhnmY!IucH14{^G~_zU zZeTZL$}QxeLK8WR{8HP3##=4 zBzR#z6DR8Vl%zdbL3fJKNK1=vT0I(iEa98bk$k^hEe~#Iz0O>RQU~K&rw*oWZUnPL zY-PrDtb=1Ho|f?A-g!eHYQRXj+P*aK6;YAwt%79E#`q(nHn>g?cQ;6_zbwz0RisI}hm*{fv(@sy zbU0=H9)3b?;dKLU-tmFxRw}qnN>d%10JxQ!l5R?wm%8sA@Rb#}Q`BI|*sR0SvRQ{E zXtNGW)n=XcpusOS#e>e8i4NZ*V8Q~78?7Y&K)|@g! zMKVk*WluS|o+{vrIQXG+zB*Rk^&p-aoaJ1b0u3EZxi$r|fKU6{6v#pk1v^Brv+5qg zWuI|R9Z7KHGA+7Y*~6rvugfP$R!EvSu^d#8#My%E8b05_KJj$=wEqT2P3&jy+g1GG zk1msnupQ#gp{54<4^)R6&W^zX394jcWeSIh!AEWOvpMW;`)Qr{%E&tD@_p7oh$umZ z2QpIUXEk40OeQMkiBeSSNx|8zA8e#|Xnqsb)!zAFT; z`+S@2!qSvngiZ9tpVJ`H)OMS9cz!+GgGxl6{e6+C8i39eEPX7@NsYnbJUd;5HbDI!c+l?aCg6Zbm;>H#Lb9u&};Gn0o$af zzLNSVE~vX1sAQky1p?QO5&_981k>ZkUuz_UsS?F=TeWcDpglT_Aff{H^+8 zG8oX3j?_w%j!aUp${F&ofF#aOKCKH#^0Ng=oS&OHTad*0YcppHk~sg?%-Mn@&fl6j zTaZd}uHc6aaMs<^Vl{=AxM7F9X%21CDjI_mLZ)t#b3bN)^BUE(s=rQ2=6p?t70xtxZR2c&Rc|< z8BbLfnnJD;{PJ^|fXh{aUq6)zxLhNE_Zo`?Laq_OWQ8wTXn}S!Stl&1PR-DJ{SHwi z5y7TB7o8Ef1h7n52~MQsz#^rHXUR(eEK<@9olC=)m?xBHd|~!Y8WnNGSH}@wm}@J1 zbsX`9^?ik}jw8M>Q&;%vIN}TI`U+niCzEBje0k~iigA>=e7ZA{a&kM8 z6gJ8rqb_fw)Uj>EmYWG@ve<~tA>23jfl~R5jrybr6dt-D<6XYGSDy+qReVNasS07H zN=>kIr8HA!)ap_V99JNM24h6#yKk(Of@uK-C7Q&k6yCg!KUa{QZGr?9Y6BJfVoK5(o#jjJxm#=NWZeA=Z)}h*;E@vF8CSE#>tt_#u1;t zHL-ETSI5b~*7$q}*f<$-8zNw)_Gh~ggj;kljauLrjrp#8Y5{%p{ zb{pqw01~6$3MrVT2sQwTv6u?n#|9uV`oUQBu>n}`mf30spDLwB7rKRDnYo#s1@r4M1Wn_8(_#01{(y+;heTU_Eu-k8Qcr;mE~eP6);p zBykqALU6VqiL;m&g0lrloW;x#oGnP=EarybY(WxdF*^ij3sNMKU*^Dug{(S4Ae$yc za>5iM>AVohX;FxTduh!DH>VCQeYH{Kf|X?{TOB8xWZRYPvvI^{P3Nh9bsX{e8)Mrp z`B%r)JEMEYZCZUT4I3lS4V@$K8-NYn!WoO*Lcn^rh}pK#FCDI-V+3QdX9Q<4;)1gUNq!b% zE;w6|4c#L+i~Z9fMF;t1!`@oEpn%-)l}OQ1MWp3Jr)a4n;a)oXf;SComxv-4tc-}b z@^lb!#Ag-xh$~OC5hnv%Ypsv6jguj_apa$mzl|e4D^p`Th_8+#J}XO8zB;a+EMhf7 zZt5imjSDn6YprE+Jh8XqiNDyX!XM&q$Jc|yXWT+m_`0Q-`<$-<*bo5DSZq1>v6$DK zu>nXv7BibOHUR70!e`t4{v7hL%U}<-T=lPOShkQ&%eb8As=0mu<6U{xPP01h^GLV7otQBK3%(k z^G;SD>HH)5DdURu2~n7^G*Bim4VeifMz@rxm?p*sATheJ+r-!a)Psm8NF{v*;{*fT z$x;k|`pbRx4Gq8?A>t{b9e(soa4c7xNjTuloK6>~=k z64TM3rT7{26gPvOF4LSOPpEAo`$&+e;2RlF%R^SwnSfdqYc3O!8C8^~WTq9H#6*dE z_@QSvMQkWM!MsFc8mEEzp^#W%bW>oq02|P zN@tDu-O`Z41;`!wCOYV@}o%Ss>JQ-Zu-eEO&i zk|wi3mm1tNSV8-wPzPitRWT^wU1Mv-1+xZrJIb-r3ReDX9`| z_Z%IVD$(|-+NTEmqzdMI&Q@aee(G=Ql>YQq`t+i=(`Tr8JNo|D8@_7+s5-5;N-d>JMo^1vq=_?#n~062tLve}kH(tBvrmuv>eS&9(y zC0lCcEJX;hWV1xhQiKpoHV5P^MM%=kn0Gmap9nH>+Bq2@?V1cg3^D2%AYEE#fTRhb zB6nGkl!Y{JtMG*04WaP#V+tp}!$-q5@XNg8ZU+MnHp1b#0G5{2P!Gk#B(@l~Mev&o zI=KolXet5mR2fX8>kgQM9h(>weIv|3>IpO`SSUs(Dte#;yRto}jP0Wbt z)9wgcN6_5oY;(Ucwbxu0>BHp*&RiLtC^PQ&8R=sF6UFAe?m z69=^5EZ4Ig92>Tn?c6ck*^d=57-3_RN7Yd5X)+zcH5dKONu1B>8WhDo8tRZqa*(&* zw;~xhMU8r(sAaP!e*T2n9~_)er}g*AeMu)f4wIP6SdExITj!4Z@lo*kidl9 z%^XG>d;v2FmWfixFs{f(OZDmO#eLfYo_ZgSJGW`=KJ~$V1dee;1Ff13Mm7Ia`t*hm ze0bW!?ll}bH{HH{-!EYUJLgd#nLiGL8DFMJAS%u428Jol#4e<|J1IsIg`a3c`x1RA zqOuYTk^l8J(=&u=K~gkh?GeIsmKMTvS{6dmjLU2xBuzt@hX*@?HPa6u;EW=v2I#Jj zc^OUOYk?#c%xgcw8gAh*_34Y*p5a=_K7ZB6xntF>q5I~>=3;&LEY?J*p4Udffo z@`=hPg}Pq}U>^4@0AAA%$%f${RVb$6=BrdQq7ucjrxICesu!uHo=WY#wOr2^aE~%~ z`|^9(by#dpSTUDKdJL8lO^;zyqUkY!N;Ex&QiW8Mmp{f5+Zu*utP2{%qrh2TY|4Z{eBjd8i(x-MaUYRc41d&;P&_ox82^`ro20+DX0Gs~F_gnyLX;>roE48nvyd9&okx%=C9gCzOL+ zwMPf$%00R9%y^<@FZsuD>n{1nPy`oLFPt`sx;Pt9&Io+_TQC0n@ zGVW>&ol|<%Tk6-Fe%SWw2XCvdR(r3-TZP6o4UeRz+#{r#dXJH!srMKvntG41qN$%4 z_I{&9816Y-qOQ-ZhVjCcPU>B6t7*jK)|!%^tDV$~et??OvYz<9ZN1gnbH(51oG?Ih z)sxKjOHgJM6)9)TRWFZgs!Bb1l4_4k)vY#VYpU9#{-mlsvNlyEt4%4Gs*=@{RQsor zA1n<;$NTArWv?9Yc6utEkTTv7 zi{~SDxvE=L&O6l1LVSD>N^}Sd-o0;snZC_;^uurb$uIkbwJH>K-fMRYIK*Z!yr~o3S3aHRD_+1qL z#b|D+17sBQ#ea@)tPA{va{3Bq104CUV?B$8$%x?B+bj4j=JU(+m*3#9ENW0}b0U`N zzjQs|ej=naBp2)Ib{~5Nfk;WZUBE)B{Nmq(l9-g}?fCNYK4U)_#X!QC@Yg9NTs==E z6gEvlI&L!7bu>xp7_5--y=!{6H0h*Yrm2`ry29U?OabI=0YD6{_7@onfV2tSYq5vT zcIpa5)`m=O5WoQi&x?Ip3x4sh-3D>ig3dqyPz+cLQUEc8p`Du`h5{gMf;(4Wy=yPAY_+-J^o9ZixtHh(_+GW|Vkk-wb6 zm+wvjXZMmHclAV`pq}B`?#x z^HOS6>Yt@*WmBxX{JPVl5A#Xh%Khx?0*d{9vHQAN=8CB}wFsIpgO?Z- zL`p(+K6Bb%rWmmhc>zU75p+?F`64w~W%dH@(tJ7`{9`(q2#4auj=URh@p{)++4T zsQu5|dE9hfkF1i)*l1+6MpqaTbvy+jKYYkdCW%P6?t6IZ8^%MB2{Tpo=m2Nar%2!x zs>uloP9Z%&!Cmu5C2*hoHNh9G?GN)MJ48o#(#eD(d<@2&P$lkoof5w;6!3;HoZ+;G zqt)1_#GR%JpvvNB5fwshEJBFI&nyL&A|z?fevvFa+(ZqR1Pr?w;smFG?hfuCIXaR^ zW~d3usnoN&ruv~|*d0(-++k(kX1lpOZ!J-hfkuy7)MW6R)ntb>tC2O|NzH0`82PC# zNg();K??<}AjZiCcd6iO38=ZsIO6m7p*D_!TE`Jz zx5Ap%`06;~>sDP=zB-Qh{7q@izdDZi{0(J|ua2uHi}-$-nJkDR=lq*@RIO6k# ztHxKy5nnN>n16K~@fDMb@zrs}S4=9#SH}@wF{v0|9oHqx3w%8bzHl`?uD7r}_7y6< z+JT=p?^}2Dr~9nVH`osft7%1$s6cgGtQI?{j`O&!Nrk~HtB{Unxqe<9akF>2XB!^b z<;1GP+6Gf;r@Y#1{yc6!PQT7p$35F~`Rjhx*6}d{5}#jBoPp0g z?G|vH{5~8@=nZg5r-V03c(f-!UNXJvTaaG&El95u{?kwCb;9S@3IEx^=hr*u*9$mu z>4`n+Vi!6H9PS)GG)8}qg80l2B<>$k6dr1T1peL$_J1z7zShv+y#UUhep$je+Pu85 zy9@ZMyxhT!GdHu#o*i#N@aWF<#vj<3oYzUWDHbLp3atp#v60=S=Rf0Zl4qxD9ozft z`xAUyRDo-fP6?09+%I1FA^7rI2XvhUhmtyr{EjoboWp(F7&J5vuEDH9v<%0tb$s-3 zObL|NqG9)8wNP-uLicY<>JLA~E510!D}?zu!|*G9FhwmtjN+Bf8Tc;RHl3&BwGQZ} z!Y7z8_=7(9C>Xo7FCl!(N*LeP5{7s_LSd|VQ^xox)_Hy|+9DoTsB8X|F;Q1Mxp z*&v~=YAD6mJ`y&McXNekiq~+HVg3tFY zx`FCDHofY7TezNZ51yQk2X{NM;c5r&9*IH7V80X|uzr}rVli~7CDoMSdndc;-c}cK zPXHFDpFepYodft!FLn<+F^}A4Zseb?=D#wn3W_5A+fSk~CR-gxe7`sH)p5SDYh12P zU28%>#I+7MhkaYxcqr?8N3sh*fuf`xmM9%H z>^Cmq%iZGPm@1+MfA9^~^bBDVXif8Hoi+)wrWrykg{1jOr=`v@gfgz%QcGJbp8z)HRAGguw%+4q=Cai>nJT`H(y6ebs?qi!mR-`x#)Ll-F;AAK|=HoKhk zmqdr2@|Tl7@|Uv#z�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 D@KzZ_ literal 1873426 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

;NuKS;8O$YhPToz-U3E_03(S-{CvP58ena|@ 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

    o;lw8PKHcb)&)L#)N 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%0Aj~NIB8k_cLR0H@0gQfJK8Mu# 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 z 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γb5c%8!N1OQwq?XkQ(EacsDq3X-Ww86H>4 z-w(i_v`UleKPr=t!-OR}u7ul(a_U+5_1k;A7X8Opv}Afv8$9B4`^!^1+^avs-;$Rm zRS8mFKHO2|=Wt)KlF3Gm&|l23)6I^BGyDm%G^t*cR_Jm5_V#DPnRviKBf z#ns{YsVte3l;N2>9`gq6wmh5uIjkZXzIrK6x72&*^XlPDRmp78b{;ENZb3Nnm}DNL z4ENB!!(=+01^aqjGIa8iTW)>%LtHphO)^C^)A;-MSA;W9NQRFK?%}6?m5+oo)g{B% zKRosg#~RZ^%wRn=B*WX2m!PE>xdua=Ur_d7#R^`$0*nI|Q)Mr)on z{MMatrj=w;)1Y`<QqTEGPo}URc9u*WZS<^^d-tn>zlYoDA{n|6kvS}W z;%EwE?%bUXL3p-1NZ z;Y@$Y@IKG`Se=6}j|pc6NMI!nNhVn{&n_B} z;H3#nCBE#IrHHgZk116e8Y@GcOwU1slLvO@N0+>Crf2v5gNAYQvWWCb9^T!8ml>Me zwTCOil9T(nGCa9|e^*8g?K9kInQwl|sfT5*%AoYN<|QgEAe&SgK@O-ihJ3G57ji|V zB_y+6_&0%+Qt1e(rcxi$Riz#D$*30#dmy=0c0)?2{GHm?Q%U6} zq@IdNV>9hk?jkcv{2-nIjV9Da#7_dL_SVH+v{6MmVB}S z&G(Q3D&Ij8RK9^UQ27DUN#!i0ugXu5(JJR5FR7e?yrJ?eWUI;xkb^2yA>XRZfLu_S z4oOQ_)x10h$)hq0^03OwkXV(MAWc+WgmhP#3mK{M3S^SX0?2HY`H*!g^B~(*(qNA| zs*(=!y~_QNODgw4?knJpJuRewN=8TpmCTUJDp?`*RI)(2t7L+VRLPEGd8Wz(kXKb6 zf~;405OP2z2jmBpmmoJ(=0Z{z^hWv$rh5aR>GT&7)Vi-f{=FjLmRe1|?MCDz` zcPj5dE~u=4+*Vl)$y(AI=}Jg3l{Jt!m5q>EDw`m!R5m~csJsE0q_PUKK;=!yMwRuD zFI3h-eoj@xv5eg@(?|m=A|hlN~Ia3sY+wWAeAPN87hyZwfop&mB%3)Rd!>o{VKm8 zb5v!sWCnEY+;eDhvQ*d?nbVp%l-l-nS>+()j>>SXl|!EjO@-s4kjfBb;#CHdq>)}5 zsq8?ehe{mU8K=@3GDD>oWU)$5$Oe^GkXkvx1IbZV3N>9J(JJXsb6u5( zAgxvMLHejvfQ(hi44JKx1+rYFIAoJbX~<5M0+8b>*&)BF6oaIH#2Z&ONHLY7kjGWB zLOQ5C0GX_k9rLqAWdJgtsk{m~qcRNgkIG_54t^4mmgCr;i>aK1R95*0(pcqhw9`T5 z7Noz*zmTyi|3Rj!G=VHoX#rWI@+4%7N;Akll}}OODU}B>W7*4jBh3M+r7|AUM&(Pi zGf*WLWU5L|$SRd6wDX}#1rqNVJgV{(GB;GlK=Sa5y0naiR8biR>7p_eGDYPS&KpZq zPC~Y-d;|GfxUqbGvw88%KAidtfOFu|ymAR;}hROm+Yn8>20V<0iGgV%N zys7dUZ$pCpzUUy67JS2a-H_~??(JGrD%~ZBP zx~lAhj8-`anW^$MWVy;#$oncgAcs`WLC&abhNMmKYJLw=TIB~w4VANyE-LRrCa5fh zysYv%WVy;R$h#`vK=!NbhMZRU9CB6V1SCVEH;T_7#Z>k~9#i=g(pKdFWR%J=$SjpZ zkTohtAUjmPgq%`24*65%FeH1DSMyOwS(UFKbyRjjx~O~z8LP4l^0LaukPRxkAfKsx z1o>HIJ0w*lufk6tg;na{9wc6+E~K_feMozi29TjDjUZE08bg+<>$a@!#dI4~3*;Na}>7RY(SeZ-wU9|hh%X`)`nz9NWKcm?;-gwBo90m9Q(tL;K94Zc;6V%wSWIX-R)W|^s>2+ zScVK6WOqUevheb_wtS5C)il&j=VASmlVz{_+RB(d$^Cn9Hj0iWFVknBfceU1XovQs zH634)=|8BKCkLzy9yH36g?6oBLxv6)`qoPKLBqVvL^_Y9;Z98xt#F&Kot|>bB3X<7 z+Ez2$CBxEP+gVnE zlc@3;q@l`QNJo_ekWnh1LtawZ16i-K53)z)2;_pwVMwNGT&FQRu?2Hi6EOQB537{N zNTXDKMW%|%1xQ1c12U_ImToHjkr|+}3Nl7zCFFUPHy{gDmO<94EQM@USq?d@vI6px z%B!gGZ35F_r6( ziYk9V8mUx4@2yoTi_kr6kN(5P4B)n_BGXMXchUO@l~k1R>RF(Y8nRX8U#xXbSm9&tRD&-&_sbqqjRLKEJSJ$hj3MwqEQXf)JB^qmW zQOOM%q4F?fhDuq;Qk6K!7L|gK&sF-O_j4-kApfcqg*;Tx8$~h5BPx$TnyHk7j8b_G zy-!u?4OyX51hQRacWS#Q98uW@xuUWalDEEB;fIjADjz}msC)pKrm_XHM&*6T9+e%C zZ&bEJuBdzh$=blH=VM4wm0gg^Dmx*qROUfOsJsGsLFHx08kJd)eJZmdzpBiIWNheF zI0sTnWg(=h$|6W}mHCj~DhnV}RbGNDSD6mkqcQ_>LFGkA>PB9LGa=j{$|^A!S4)-rkl`wYAup)pfvi;d2Q7c0QWBZ-Dvv;JsoV$2-Q272en=&i zerUO+N_$9umCe|KQ&cuWR;g@)e5~>w zfskaCK9Cnwnxd~QD$OD1RGLAuwe@;`3=*T#5b~r-EczOtk_(yDDtVFFu2Kr}waTNA z-&EousoHt<6oTYd>5slDs&s(VQRxopp;8$#Riz$ejY<^y`b6apGG|q8L(;eRD*O*p zN+lQCsiIN>(p;qsq?bw`wDXKgTgW_>{W!kfR;ifYUd4T)atmvHqcRY3SEUoAcn5D3 z9U;|J20%Kibb(A#X$e`QG6DPZPL;`!A5|to(suNEp9CqX5{;IlR4PKMs?4UfQcDAk zRGvpWeN?7Fo>iF%S*9`rvR!2s z205-$74o-A6%ubYvUKq(ERIY?m12+tgPm!dSLQbfRK<0+Za7d2sUd=Tj(JD0{EmW$L zcrEu)DTB;RmC}$6Dy6X2ew9RI&Z#6o?y6LP6zJhq7!65MiGs9JiGvJNiG|EoDM#Xs zV!29XWOl1mf}B@LBJtL`sZs=)g2`Tmg(1~c3Sq4_D*vRm_YMP9ZbR0n+=6_natD&S zr`OkikYXxdrL`?rQ~4UwN#z7&jLK=qe3es>_f&p{98~!c@|(&zNQPcsh0`Dpt2_^> zp)wQFNo5Y?DV5ofMJfv+n^aP#v131|k^%C&N_xosy}b&vL5f5$l_ltXxk`RyPN)=wWb5zsRRGdh zr4ZyfmBNtsRbGHxP?-tIKfr5w7No1ni;#ILGav_4W<$(Cubt_TIF+#&X?vB?kf&6} zL6)kFf$UTn4>_;$G$g|yulJ`QWmI0r)~Tzq6w+H|8RRLI<&Zfliy>=OmOyr^G=dyc zIghi}C6zxR83ubb-@;lYRBn@`mK&?7{DfKUt#T1ES>-Zhsmd>qZ7NqGCsh7|Tvz!6 zl68nz;SER`l?#xXD!)V8s9b^!RQVY)S>+03zRI7F^(xmOJ5;VizE=4a@~etTZ|Cr? zN-9X6q29ReV4f?gq(-KWN;*hql{Ao%Drq4vsN6-%D^+^ac26zcZc^z3*{@nhzKJ5+i>4yv?}m*{;$Pa!{omHNL!U`kbWvzArn-xLzbxIfPAd-0OV_xoRB|N zazToY_QsVLlBALc(m^FRWV%Xz$ZIMEARAQ*Lil@icqs(Api%^qd5o7S3aO;>D5Rsx zBajIy5)H{e*6TeAQcI-*WROY>WT8qNWVcEzgnw6pmv~6-ah{}s z6jS*-l|8!SRBk}(s{8|Kukt5kpvu3Hi7J0V=BoSwS*?-*^?aa`8uGcyqgd-(m2!}) zDp!mh#ch?lknB$xZ^2q+RZ>G5svO5!ZB+^)Gh8J*WR^-A$U2orAiGtrqvfwv{)YUb z@((2a(?*tmA*EDqLMo};fwWio1M-Z@HOLB;tC0OFe?hLQ{0YfB-mB*Zq`Jy~kO3;U zAq!M)L3XSB06DC34su=PCrH+3yxxC=M5~;KG*X$7%I*p6Rc1m4tIUUtSD6QytMUqD zjmj{{yDFm~dsT)*j;V}*{Gu`)azo`ANY)8PmWhzkD$hZxsq}@kQ|SX4uF@Owib`k5 zCY275PgTZ1epeX_$vV-<@-!q-Wjv&t$~ee$m8T$^R7OKSQRxNwOyzrAKc7)K1Nlqk zM@Z&LMwX2vspW5_RaTOu5vi+k3esQYG-S5QcaY60dm%?uK7d?P$%d=$|5UO=vQG9Y z%mFE?@*pHuB^RW+%0rO0DmfuTRkA>ySIG=ntCAIRK;>F0J3rS|GEydu6q|X9S92!F z!zvFzDye*n*=VEEnI8G3mIjhlxS*0CiyxDk0r9EV!N;k*`l|7h^Ln>D&_=37ql`Bj7gT5ImAsJSDyz`@WtBCM^wYgjtb-I%c^eY1vH{XmWjSP+$`jbf z=BZSJY*DEWIiyk(@~cWMNah({g$+qk%U=tt)Pp3c)P}TFsR0?Nk~_WKe_l|@16iw5 z3i7c^X~DBxQB%jKokQkLBkcKKnA;~HQAyZWfLEcm;3^}S&0P?p= zYU~>sU+^l-2q~zN0a8`v2BfY^Do8t(`yu^R(nDsb7|1e}`ylVDq=S5`@?I*tz5Y8SELWT47w$W)c3kOeAhARAR)gX~gS4mqW= z7;;f%1ti@pBg-3*LMkgEi7Lw=ja0Tkx~qHx8LP4Z@}kQ7kT+Gng&a_M2XbEJCM5f8 zBgB zDjz`_seB0Ot+E5MP~`*229<4)&s9!BE~*@XWPZuW@+G94%0WnDl{1hYDqA5FR1QIw zseA=FqVhE)-OEOnk0Iq$K7q7QSqtf{vK{iAN?L5Ml`094O)B?8_N$ylJ725(2>Ds% zcgS6pi;z5XjVzZSQ7Y#k^;OP8x~TjF8K-gqvRLIe$R{d4L(Z!F3dugt$np!Mg34(~ z1C_TRy;Qz~Oj3CpvRLI5WUI=0$T5{f%<~16Hjq@W7+F$5vZ(Zhm`+)kX0(5Lq1U11o>R00b2e|r4A(H0wYUpNLiKokOnHBq2-P$8zF;Lp1@kOR33+H zQh5w=RHZ89no1Q&j)h)@)gaL-U!eDzD(^yCtF**gBUPG17OFIZe4x@4a#E!U;SBOx7CMnMLvEP+f``3kZ~F*`x9y}OWCB=K%P}O1X-{0Ddd#O1js`xyuJ=X zYO8z!8KiO;GEZeZWTVP@$Z?hTAeU8MhooES^}Y>KP-QkGT4gDusmgZ9AeA|g87gl< z)~hUn98ft0Ii>O~>FC^+s zBTH^bN0kR4uc|xKc^R@z zLm>rJ20+TI^oP_^83O5~G6*tKWgujx%3#P6l^Do2m1xLGl_@0snmg(O-7akNOqMM zA%#@tKq{!rg*>715~Q)p%aHCWvmql@WkM%CnH1?-^O9LMo{wL)xfJ zgFL0u0J2J@F=Vew6OrVhLkA5t-ZCh)JxnD%Btr zR0iYBUrA*Mq>f5skzqqdbRC-P^;JXK=|kUHrX`!FP;(30GNhYIBedLKr59wpN-|`T zN_W(}R%Ieu-m20EYaLM;h_%kBJcqTesPw~H8Q%BC(I1jar6;6}$|SUts1k?1s;eZ5 z(2uhv+W8qSYmvl6D-E?W&}PPp4C~itu$Ag)xv92X71BkeGb$XcQU{qARBA&OsMLbI zp%M%EKqVfsS7ju|eoSQqRZxQeTE zha{efWKwMvFwa1Ws7!{GQyC-DV^HUw{Rep`ieacHQ8US?xv@$wNN<&%kf&ApLguLS zhpbhZf_iqU)I{d6N^i(_D*YfARC+-EQW*fr^`SQ#eITV&Mx*yiD&rsxRjOdEZYl|o zkt%~QW0O^SLta+t3t6W!5VAvM0OXvCA))Ue?cBY0zhT4sdE>C}J-Fdy__oX+c?oYV z`U*$;Px?Qv<^Q%*Pq5J?$r<0NSJ$HNMD0F!jBScDB*T)2`-Q$z(*9G|8rBD=A1m}F zlaUa&Q=(yGZ`UQ}-?&WAl4LXdi^C%ER+?Cej#A=ZXq8M{MHT*iVUgGb75-IXPwZO! z`@$m8_MFMT1}kD$GW;8|-deVI{&iZBC|e@`7Oj`D!oTz?l4#fB--mUji{Po(gHS;g?y28KbD}tH- zB&|xc-C%pI#MscM5L@9cD^a%hJytB3-BxTl=4NW`D=tpQe%A^zU)r^zZ12ad#Mv1; zW(75WYXxh4Zw2+7wGtJlcHRnlpK1l|%&?;8Vq>OTLGQDyV6B&}p!Zj-M8)YO&bNYg z(xtK6%Z~kiD`+RPm8go^P8KU@=Ye#=b{?`~zk=P&wGw6b)mN;<*nR9EDzrz_VJpZ? zvVtRSij^qa&RbS+bZ@kR8T-)o9%c899S}SCtq{8>Y=PKOyl(}4ePAWYu9e%)SZsoJ zme)$O-4*g#vE`V_R&2yfvJz`)niU)u&qHj5Q>>uEskXudJ7e9gMBDD$T8Xpm3=T;j zD>#q!w1SqO4#`L>Nw%+eE73{XS$Qil_6$%FVrMnRN>r5YE(NW`+qM3-W4DK(S!DMF zsqns3^y}A@NyGOSGCy1Zi=4G&AFJ#L?;G_U;ZZd5i(Ef<^NVcdWWU65$rJn%!{@`v zevwfu^^2V6SNJ8Cx8N$j#PhyU+CQ#Xo{eq(Of1*@i6eXl*yRY1bgy6Hd2XutTb5JH zDJR2gb?|3o-$5r(Q_v zL+n|iDa4Mw8N{9s8(Xnp9<#^0omBIjtBo7R&3P)^Uo{UY=8IORCw?U~$A z9Y?scCVq+M?cUlEJ_b8G!e@Y9j_`3Y$Pun^lp{PF&p5)fG1U>?d1pDoHP3g1Yku7? z3EcZ=+Pg6uvbP-dXJq2P@e6ll&iX~>`GQ|$TU_&t+*AMS2+vO{I!j=lW#72p5w0+Y zBV1x$M|ggUI>JSlafFMGa)gUca)gV1!Y^_Z)N_PuZsrJY)3%Oq&0QVgn)^7yH4kxw zYaZhW*F4b?uK9UKxaK*2k*lVKj&RM(9O0VRI>I$?bcAc(>Im1o(-E%ufFoSoTYw{?VT?&=r0Zt3HfC~k+BU+kF;(ig%t^KyvRl=;DR z??DJx*pmJXr?n#Y%lTCz_shlo!c%A-@e5C(;hMM|S&OI8@O2bK%BkTO+{31__pm$} zvJA29K;mpBiK#c;-kL;emg|j1G$t15U5?yVj_}s$>W7GG&x$VFiyp>sZ0q)7jaGw-+uCS;1QQtR&ifqk@$v`!K0^ zNJ?A5J$_M$?LMm&JmPr3id;W0rBMtZiR?dxRU-RODZj}6!&iE|mSkiy_&*TYe;)UX z>_2=jjEoG6?}a16Te-C(yp=mU!t=xT!jZLjq>EY>BG>#+kqonI$@3&NRlGf%{$cpKmop;R>mcZTv28~- zDfiCe_71V94fD6nK$=*wJCu3S3Np>CV2>Ja_h;<$U)n1x*~&bUTp`J6#qRRvDccTY zOi0FB!E;~Ztk~Vzd`U;IH+Fli-p1C9disTA0ot*lMGzhVFRxm`+4z-^{BC>4Y+SN} zwJusg&EH$Wvj?Xkb`&?PV6B^W4taN$zkQ@ogmmxVGlEWc68j`Q9U~j2wj{@wg^+VFY3TCyD6{{PJ!$N|8Wmg7DnY!lU@b5pMaCBRq=hevxMn{&j>$an}*v%M%zQlep2-nzIfq{o_zaob5pKDl zBRsC+j&RFm9N}?QaD>Md=a)q8tFj{mvh=d&1YSv&3ib?uYvYIPaVpnHvnjR59;b4T z-@`9lvUyk~a-5d-3zuxl`-L~V;Z?b1Sxf5S=NKV8g{GQc}`wOmlreEaQ!ae@A==6}Qy9#@njJo5>T@FZ4s zgr}^ABivU#zsS8q6TifAJ5TyW&a0FCg6D**q}6>4Qq_t)S1^;>Dn@6C$Ro{sDv=|l zh+kw+DCrm3?vMIK_8*=RZrPhvzNY11M0i{99u*N@qoyOgZ`5~$XSJy#yd$=9giGw; z2p@9Y9N}7eJHkctdn8bgY~|sOaLr>K;hHD-MP7m8J@XMet1=svRU)%d-4SlNo+CVV z9x1out;J(+?T9`5MKV10WGBO8@9zkYeV8L$B99C0$k-=3!WB+)gvZWjq{v!a^DB;U z&3s0RWVq&)j&RLv-RY z2#>3;BRsC5j_|l9IKtz4(Gh-O=2xnvuHEi({#i(88y2Zhu8o&E!oyhY7da!n?TE~V zBiuXx*=Nt9{13xNE{pUf=jVcck@+d^7nzMRj_}wk_(iTj_RzVdl%07whyUXjxw=TL z;_a)vN8Rric@;RjBV06JM{&#ET0GDB{37of;#WeEkyq`z`$f)veI4PJhxjFyTORHg zyz)33Gsb%YFSV@T8IQ77@W{7=6=bS}q^K3F)!z!%dORd0tYEFDtYEF`At_}AYn8Ji zYrRI}8f&+p>xqc1Cn8)= zTkT!?l6t0)JnhuOXEv5dJ;nSY_3)Vu8QEL-ybuxYy^XN%4?8Y(?(lxSf(#&~hm&cvYyom3TXh zURLC~h1+Ru1zL1p^y}@f_C^-Ua1H7r;mo@ zk&u+Lg7@533`zNrM2Cc5KbGFnPKA)fSiyUi;zAM|l6WhajVm;d?#%OZNv;^XA7U-O zD)Q#X9vH{%TG942!Ot8?CR*OqMYr>Hk|&9JG^dFO-OdX?{&ZWuPU_0v5L?hcA^Fz| z_LiGgu$Avvk+VAe!~7AFYazL61?Q;0Lh@%wZiM8&klYT*Eh{+NoVS8kZ|B(=!~0-g zv0^ul8D<4zA7us4s_}KCH_vv;MnL!;gqP_M+t4#saDL`%R%r*)#|qxX-P?-Y5lm+* z*cM|#G8V%3xx73blJQp1`?!!iWyKD{Y_yMMFo)UfeH_ll*+Y`U3f6ki3f^V<5X7t4 zn4DJd*?}xpaJK1euL10fU8YM&x>~_~L3b;7e|Qfo*b|bip!bee(9RVIUnlT#H6+&{ zw(09u@V>ztRxqwVt)TZyRZzpq|rK>_K3@3rRy;A;wkDiajBj8dl=@{i4-!(R2N@*Ljce`JK!q{37puJWUmH zMvk2r?!FxDl@Qqv`F$A?;iF&@RTmMy_Iro+rigGsm+$in9~ck#TgIzhZRp;?d-jso z;#a#MGOn_uERmy|U+sd(j=*OMh-@7m2}EXakH=4Q@X+*xZ!_+akn z2zTGz5$?W^Uu4%9-bo9rg=e?Ly0Pw&7R1BEq9M z>j;m6U+s!yxMhB|DwdwjUC6}qDEJB`BD}r$)vkze@BC_4M7U*swF`n*yCT9Z z^EFFEcz%jI!Y%WwU6Blri(l=E2#Uk|U+5Bi#E~M|fMTbcDC^A-~9#!xwZuoJF@tg>uB5px#-eLiw}> zKZ=S7w^N$hi3o4y=8o`Ie##M^`c;nb)E{w#$IhQBL(B5K=tX~paXcFXX;zVuJ$#-c zJR6@l!n1L~5gx^Z+OmvP9{E;vgh#=zrbhbWQOxm6BFh4jkLmxBIov=q#uAys}j_@4vyRITFv#g}vN7Mf!M@kR+7mHNLU73D<;jYYZ zzsQmDv|qSk^PFGgNa5K+%W|YFaD=zcGDmpptaF6t=Uqp5ezrNnMelWli$3HC7k$DJ zF8YikT=WIM$UWL0j&RNVNCM-MhiGYaR%H(5`KT<8aLu_K;hOn1#7H|_Gk=~aB3v`S zVi=J`l1h$n%{BZY=Y)oiaLxQ`Ali{*xsxM2&%GSsng=_=HS;5hNIP5)pNYrN|08=; zC(hBI$R5S7o8yN4Vyxj&RNV zXf?7H*ZhVfT=Ql}xaQrCaLs&Agmz?);?E95gloR)2-keq5uRs$-Yc>e*UZl$MTBeS zXM-S7@wD2f8K_FSMfNE9)FD4-!yb3G#y{NLep`_6`GFH zbnoD6If?Gk9O28RU;P!zr=I!!9au}A^UOt$9U{UrU(FGo`M!=&S7xqXU)=$Q<%>ek_qWe9RS^Lw;wzFGF+qk}EWa+gzc6{p<=2EIZAZ zuN@j#B}aG;XZtIZIee4m5NpXC@_Uve!gI*asYit8uw;6_@Er0d?~#!?9P0?r;Yvq% z4iEVyDuFudL67zLtfX^DO}|1TW%1^a4`!YXpHS03xk626rLp@mv~?0(p_%XE3eEiU zuF%Z$dxRtHB#=zG&l9OouIKq11(4w#!HjlWZ1mx)fKf|k2N1%2TP74(-QNwoJC z$>eV*i3+Ok3KcZm6`HUmexa=#WvV$9@Im-}ula>4Of*aV6~^&L!b;@zwH(J^G|<46czXWF6{_cTSE!x?t|ZZO7k-JaNc9w? zH?QEhi05y~sN)x^Fv09_D&(gEe<|QwD~?|T%39D7>MPL^-Z#3rLVeA2CEA!RuF&>6 z;|k4B#zMZnsKR)2#$RDP_cgMxFB8xE;Urh6uQ{$zUrSw~zBaf*+u~zaXj>d~h34n9 zD>Og9yF&AG(-Hm<=KV$dHS-f3d0e5IOSwWd$Gbu`*K&nwZs`iu+}#zbd8jK?^F&vu z=Gl($MZoK>P|a_H}7 zjdO)+uIU%rqvA}LwqDELH2`0?Z1!j36R58pu25fx9pO8t?_Ht3F1bSUbK4b~pG?L4 zltCZ2mnefnS(8=g%bY8>z3jLVewFh5E`;!aq`e!Kr{NG(V3x!dKLl zT%q}?=L*eF8&_z4dbvV1k937k7?JZ&zr3 zM!7=s^PD4me=*M$s(Ga=RP(#8P|dqsp_-4nLN%Xpg=)Uy3e|ka6{%N445q$^bOv#wChb6ugDSGYnoZ*qk1cXql$H6M0` zYX06Yv`0moGyXj)F^TFaSk^Z`iTp}&O;@O%fv!+J3;dGA=jUCnP(2r2p?Y#X;_EA^ zBF$knzfgs=T6-@e`+Oq52z`uR;+<;rkzFDmgSTCwl}eU(GSpX7SE#SCuF&>c=?ZPH zL$1*L{Nop@u%apAuP~}2UDyqz3Q!?Ql$jThX!A)xV$6kr#F_`GZht#*rfNXqO|O6? zm^qFl(r22h`72D~2kRwiY-l-&AA>Y#Cu(YzdxB(vQW+Bbd)NR-J@)oF)L;*|puW0C_BYi2o; zNYAeHw5HJr67Mw^T^U5PQV0f{x80upDY1ti{V3P^%E9gswmzLvkQMEZuUGfsuE zv>%SF?a%P%yPpn7ym>Al31(J663v2uB$;Kd(0;fsAW`PsfJB>Z0f{kt0}^Wv1tiX# z2naob4oHHz5RgRkM?jLyEm!D5Gi@Dbe&~HnSppJmas?#D6b?wNDIJhF6BUqnQz;+` zrba*#O~ZgBnI~PL3(Zaei88$c5^V+tB*u&hNUWI@kT^5Lkwp5IvMwFG`H}mtD1L(M zPbU*g?}E7h~J%P@LjwF(tarY>?_w4UvV(A`# zm@9OZ@>D>g%(DTBHZKMw#>@{$tXUe6II}h&bnXpEg83*QiDpkglFUI@=!uEr0f{m{ z1SH!08ju)sEg-SxW(}i#5fFzil0ZBB40+M7(ITAtZ5mLIMXp8@up`$63n20B%09yp=Zb)Nu>9kb?N9oN5#<-6UUrP9DP>ubU+f! zPXS3ZmjjYy{&t0*m}uai`8c}2xIZA#=7E63nEU~WH6;QPXUYX6-oyta!8{(2L{m2) zNv4@AbbrwJRnKtO;_ka(dK|e zne73IHv0k+V-5!-)|?DToH-Macyqy#L^`vbarUTqIzQKI?BDM3^ltRQ0f{z?0up2P z1SHm64oIBI)5L8#-c%0=U8_5i$PfGJ?KM-4eN{T19(?9#?zBVKeu)8zGu;9bZ)OH0 z!E6agqB#?gB$Kg)(-&R)#X6EmPi+@*Dom&tZ>qHPua!_S!PE^%qG=tFB-7Is>T5(m zqRfjuv+XE6~_5~!?91cjFIT?_6b2cCe=C^<(n(G0f{m>OUkELtvpVb69 zk7W%=w8ZDl4M%BLTBU70f{ob0}^e91SH0c z4M?n+?3W~d&q*RZ^EMr4QGWZ;%ygc3@4Mi)AMv+|b4DeBUh#2-p4Z8c-pSDEIm!{5 zc==_LNIU#-rf1zuG`)K3mn43lOdEfN@`e3%?)UY@PZ*hjexYZm==n@nsIOhFP|Fux zq1nil(bsYm-GP{DuF(AS^-B`JL435o!kCIw(C?Xj?ZnUt+dPoP5n8K?D^yQUSE!!Z zu24N6x7?*pp6$bZ2fZ=JvNkcjo57JdV&>Rb8RJdO5=T#vE6ojQPkF z+Fn1oLi3X?udlBp{@}zv{tDyyqjyX5`!e$Vz589EdagOb7x?)L_}AhOw$*Zl>KWt; z)w9r*Sb9ILUy}I49(l@pEz5ow$LEB;^qvZw6XN)s!0++!3H9}nE7aFdu25guia2Z0 zzLDe#_1@hTnx7Z^lEfeWPxM!qz+WfIul=E(1b(GvohwxHSFTXaw_Tx{A1>*%Lp3*c zg?i`L<9vNl%}f1~#2?*k<5b9RyRTWszZSnqx}Phw);w3JuTNZ|zAm`J`*T^R~n=`KH>`1{H-fg^LbaO=F6^7&Hp&UuXd$=)IS^iPN&SSP|dkqp_+@hLN%9l zg=&sFEm9JlGYgd8{i`^AuO8<`-R|nisf2H81yz z>``mz%r?W=$9nwX!1d`o(Q6WF=POsJo&Q{+v6o8ktVLtz_X%^$+769y{r~;e8{cubn7*fyKnTLi60k6`G&v zeo5kU_^CAmUnRPNyBJr>rYfPfJ&*p7DN3;&&F+bt>d9 zGtQjH-!fmf#JECzb##T=nd%Dlwb2pYH%_?{MW30?>+g%dNU?%nlK7gWx4*)8{t~wx zbOnNAP_A2kafRy1LDv$#4AoQF5#E22U7>nrxkB}9b%pkybACzUdZzg+jN=bjPN(Y) z^e)#e8(pEkPPsyTr7PmBMSWFph4ziMuF&?H>8z)S&N2lX8JQp{4ThY{@xS#g8{?oY6oj2@Ov*8xk63v zc7>Y0=m=j~}?F!At9am`TOP6)}qWNj=mn1$e@>K9L-n(M>9;Cq|zO@qhI;yoR)K^besIL*O zP+wDAp>6T9E3_?^yF&A`(Gk9~+TjY#&tX@n=I>phnlHIRHQ#oHYR*LW?=xu6lKb35 z{sNbLu29WoT%np1U7?!mIKo#}tz4m+lU<>jhr2>GPj-cBe#sT8d6_Fz^E<9k&7ZhJ zH6L3m1Gcyq|@@OK)p zc%$HU9(RP>Y2+84X8A=zti=~!rk|6cX*T@LLy-(kv;4YNM0o5AoD7eBwIe+CEsk)_ zdmZ7LzjlOcKIa!c+|3`3aLuV`yQ3cYtaNrqxaPu+aLxQ}WRbPF=Bkcx&HUYUkqp<& z-#Hf%uDP!xT=N*e@ZoNzIl?v1cZBDezheO{%eR}p=Lpxl#}TgiD@VBIA06SEuQ|ds z(~cAAOMWY=Chg(eyZ4L-_toB?;U`>8H%GXyzK(ET!yMth__Ki+mwXGvvwqn|E61t)(qd*uc%E}Q!ZjCiglpz+&yBRqHCJ?mYfkbDU$&U) zj&RNV%Oq$=z6ZFaBRtRiEm@Ha&vQ>lxaL8Ap?9Lv<8C^SJwvz19wpy!o|n?(hiS;f9)zFJc{a$$SC|0!=E|2O81^` zQC2F9;m^z-@r&FK^0zZ`MrKvMTa~|KAtF2*3usm$^6ivwr16RTc5p-L9U1x6xtC~u zBEmKE=hh)|_Pgm9d?Q&|sz7R%@6xG8|AO#@8M;&#k(znJOgX>sgvqZB@>-JN=`lPK z2>(OA?HPh^B#Q`d!3O@d_<@~#BUvQFowar{JW_gVMx-zK{<`jtaQA)uBHLn+BfPha zaD)dx&Jpf?qF>}XVX7m1e7)cZkLzVexaEb8@JL^Gg!_8K5uVmJ9pQ0p^b0?AYTkE* zd*AK|_s)AaW>wCR2OQzP4*NyUb;lgxc1}6Mqd4mbkKz|cxaCWZ@F=ePMfTNy9pO>j zb%eK9I^9=gufy-}U|jOuhWw3W5PTz9M7U-CMzVnqT`Ty~C7En@LTN@qRB{&2b+}+*X-Q6L$ySoH}1b4UK z1cJM}6I=qpEjYYBU!S^XzBOyTUMuszzu9|s-&?n;t9x3o$H_Ik$GK}Hjy=v@BXR6; z?i!g?>~ZcIx5wEvGIrVH>>3$qRk}uEvd0v^J4YGoLwWMxJ%c_C}fW_Mt-yGadwT2 z;%(4t+#cr`JQ|ff&aRQ|C3~D*BX#)iFk8{^#ldE<|@;yi9yXV8+lvSQb3g^4WZ;NX(^={F$dsE*p@?GRS zGE|6I{{JW7SfcoSI)(M!&EgXOFaQ4q6OgI1SzTa7_Wg4x-+#B)MVet&dbPj=1Z{PN z72f|#1KR(2AW<3DDxek^YIUR5yn$QWm{n6PFx2W!t;H*@y{qh69n=Cttsc}$UwQde zvnHtphFU#g`JO-y@NJlY@p-=&Z|GVZ)dEAUUeu~q_hM@;O2NwINoFO3l8TRYEN=)RMoP`EQ|E zqnpj|W>!bFz)-6{wXU8#JKU@pYJs8F0BXHR+Tky=_NxVkS_5Il^W8d(YwW62W<662 z47CPPD|^n2KbaLr4t>507-|iM72W^O0fVpJY**H8uOe!Jq1F&;wYwX3yjjiF0z<8# zuoC)OGOn$)>JKq%gj!&zHH=zCLOvX0)=IU&P-{4~>aVZa*sN1(fuWYX(#zIHqGfd= zn)O;OFw`0eOXg6k)$#aOde--Qdta*92 zy&9?ohFW8sCAaW?_10z08mJZ+YK?{EZLh))@|7@ao?2k2HI7=7DlJH4)?T&1P-{H3 z&WFq~%dC59fuYs}YF&vICdh1r-h+t`07I>bt|iCA0fT-tXyE2Bm0Dn^^((c$CrMb> ztdeShp_V+$VB0I@sk$layH<0xz))+lvt)bKS>B?NS;N%=LoIo<87hPvH{`M>!GVl* zU2BP2V5l{PTGvP9uWr^pwZKqoDlAzW-W=9*t($6rq1H5Nm9O$sMYBTgm0Rt54UjO@ znhwhwSHgn5&Np_gRC~qoeb$@b3UUtcJGHV@*jUf35_=&9fT7k5Sl;pQ;*Jdc8@X0f zwZPE0W>Ra~i_r_r>Z2AIYR!V>oo~oFKoi%Rq!t)z&8F77yK9P=wN5QC)S3fJ&ZA^| z9og_;XH(ZYp%xfw&83zc=gs<{78q*Hb1hlDA&ZO%VOFwzzN>r}Fw~k)t)`palrgKa zT41QP0G4-OdGGf<`^@UE78q(Rq}KH^{j-?0QY|pll276b6~a5tPpG@}wONw$7}rYJs8F3TMg4<@~UUYu!}~47FA|OIFmRLw~k6EA#>X9D(ywNvQVR^VR#R)(xyAR*DyJ40YOSGG>(j+gnAK4&Fw|O0t(RK@mO5gWaPGP9E zfm-8dR*h;_F15f=Ya=Z0vEKD`%PQ1ztvYIfq1Gm9$zunz#;65`TAN)fly3yz)}?=L z)^@ePP-_dd9*&-H+pMQ*fuYt`YUR!_^LMin9l{g_fT7klYTZmT^NU%P)dEAUKVf;t zsJct*tuAc~E0bDasI`k){l^{(Z&nSpz))*9EN>3`XMTC!tiEc2q1GO1 zHIAAvlvxYZ0z<96u-uw&9QUU>ZVnHt1%_JtsP(yXtw6Irs0D^v`&~=suy52Pf0~v0 zi0>-j1q`(gP^k)9fal0VVqeZW|}olEilwNM6Ka-Hgz*=ms((`b=Zwd zM$o&;-^*&dIee)W7-}7%mOO7`R;;7)n|$X`db?V)7W(`*h47E;B>-CdD*UVa_78q)sbe4=;9;fUH9Y+4A?{Zcx zFw{EbESZhNZ&TGY>w#KesCC+nOMd%@YKQI}a;*<)fuYtJY7OX<_mNrgqt?O%tRKrmr%zCaC7;4>u z%1>n^pfo;&^C ztio!6q1L_s)2g8s7;4?8R;)XRr&z14T41R40G79ZwcmF3PqPN91%_G=sWq=;&Lw6| zQ40*U9>J3B6~gyluRPy=J?PfP3bnvc>mO?E9(Utsvv#QkhFXtddC%$PU%zChS?AOO zL#-#&x?Z|!O|$+{3k!#zePuPZz)mw|0|4RJl{yt`{Q40*UK2hsph$|P&IPNUoc7N=7;1fm<*khd@w%oltCU(`sP&Cnbst-w*uYYD`j6k?~WVy)B;1T z5YF=UWwSo01%_H7oh7p@t;?1 zp{-CL2h9mwZKp-Dy-yvP)N|7JfAf5g*64@lf{d$*T41OZ$F*bx->VN=ddtmWE49E-D=xKUUp8xiT41OZ50*EFH@cMC zX4Vw7z)&kbwKCuA^VzJ`YJs6v0yi#i9h!AOEilyjnOd*gc6e&m4Yj~fE1|Pw4&~T; z*UjNuwZKp-k+b9$F8X#jky+u+%Wv|%PEi!!UmtD#z8sFjpjbFTE7Z`NS7z)&k0tQ5X6%WPCyyDqy~i`4={ zt>n~t^C@Fqvkt2ThFU3LMb}p6f`O^bdZHE>YNe#so!=77F)Q)~-!JoBz)&j{Ebl&L z(TC5M%*w157;2@aR++jddYM&CEilwdL*t6vyJAYSdZ-14T4|{@t5fX5X3bO!47Jix zt7WQmSIyd`78q)!r`EFYaZa0cS1mBq%HS-_v2Xtx<<@+diUI zYJs6vCTDrAajum~Eilx|>?~=?d6Zct)dEAUEY6ZvhTiqRjCHO0YJs7aeBYRz+sNx} z%o?Z`7;0sMLZfuU9oSh0L#lG%u{DrQKt9;*e0 zS~;op-@7jn&5C?UX2|#IPhqH)3zoMpPw3b_vsqcx0z<9b)JmSW;~=wYs0D^vd0=^S z*uH0tf6VHw78q*frPi+l_g*k-j#^--m5;_1ZF`niX6;oA47Ku8E6=P|Kg@cd78q(3 za4nf*Igk3)t;6t_P$oth3}6%6XJo>C^&4t#Yt}o=5%eS_Rbt zL#^`ElJh9D8mk3{S`}b<+e^-)%o?l~7;06dmYheKwOB1M)T#t4=y{Y`ht&c@t;*CY zTler2v!190hFVo%dHa`~N0}A*DmGUD7;06eR*Z>>r<#>nEilxo2Ftrosq*yuO|z=0 z1%_JHsdf3>_Vs4|B^o-gC=o)B;1Ty3~^Q1(;P(Eilxo2g_TB zkC)7UVpdhPz)-6`wJv5zHrlM#YJs6v12--?0vuWTs;OB6)B;1ThScg?Wo34=rl&V}~611A1EsAS3R0|BXT2o7o^JWcF3k^v5X-CsYJs6vJ6M6fjvCS>x0KL#^I!T(UOgIB(WswZKrT54AdsKQqRxztjRlt-h`$ zb13KYvD_S9PzwyT`cX@c^JYC$3kaQ40*U22tzImpT{Cs-_kgY7KTR8G)Q{Om%bki&|i)HH2ES z4$T^>78q&`h2`B>hB_Rkp;^DH1%_I~sC6_&@^ogcQwt2WhP!cj>(H!2YJs8F2x?7O zmV2C8f2#$CS|eRc=1|Tzrn@k)jiQ#UL$e~?lHcU}d_!TVH5!&TheN`K8){ZE zwZKqo47Fx&uJpmI{Az)r)>v3U*P&T8)B;1Tany<)A@oSII;aJPTH{?y#x3jclzXf< zQY|plnm{dChi1)J3kVIy5VvT41O(6_z)L z?e6yY)2te5fuYtkYPCz3?=Q1Ds|AKy)7`ja4&``g)_AqRQ0sSUrFv4auURY90z<7C zt|fC=?c4f)hq^gDs1_J%&7_vBL$hwG1%_I)V5RYOWL)=$9KC7Qd$qt&Yc{o}Ke{=> ztY~+9zsPq1L#;V(T;4h~EA1Uf0br;#ms*`GMPFf7akaouYo2S#?~SqOL*(IZ4jZZk zhFbHfCF{_v-fDrN)&f}G92UKIJe^s;sRf2w3#qj$#r7U%ty2pOwHCQ?dF#-u<7$DS z)?#YKt1|P3S&!5LL#-vw3h-Uz@z+{6havCEb-wSB6^2?%oh7&M@PvG?%}TBo7-}tp z<-K+;>!8uOH@H@DwZKqoIkf`Eb-7|zSGB-UYlX991V?KWPP4<^S1wQs47FA|OU6|_ z(Yp6$?NAF0wN}x%&gDH6ZLe!xPzwyTR#Qvf^Jvy*NS>i#_IcoWnrkb zmRgf0S6O3LF}1)@YhAF`R@dsG78q*%L9K54b3Zg|m0Dn^wLVyDn`_-t3k-wPV5s#M zwSF&Ga=Tf*)B;1Tov^%djh?xzhgq}K0z<7`)H-*kXld}aQ0oA-E*z*=)LN6&0z<8Xu)MzoeDAkBhFP1{0z<7s)LK?=YHYKvss)Bx zhhfR~l6|>BuFz=`xc%#^T41Pkgj(%Rym@I>hDWlse9vD9L#?B*ym5`X5$~;8_0J3ieMv&O3hhFZsAdE2Y}n8tsbwM#89)H*?}4iQGpFzba{V5oHxmbd1kv>K4k ztR(;VX9EniPEjk=-fDZzs-hMcYMrLm$fQeanKeW$Fw{Cjtx0twKQn8iT41Pk)>$%! z5-F~}8s^rzuRX$Tqv?$i-&;^w>WeV5oH-mTWJ%gt*i8-cZ*nq!t)zU7*&8 zP{>D#Rf~LVZq{M7 zz)-mGhCfuYtTYW=ji@t{%eyf?;E|4jfxt$(N$V^g$+W~EmP47DD^^7gMtx%MwG ztGHTVsP%+eF_T`HVpc=7z)vwEoohFVXlwPoz}?`BO_3k@IL6sBM@vks~ShFULNOOA&-ibm{b*57J@q1H=k-TqRjwpstF z1%_I$V0m-6=w-XvW<`JIUmIYk^_p5Q+b29>Rywu7Q0omWZ_P&u`R!I+H-{zE0z<90 z)QYpHZhx~HsRf2w@7%a#4Ex^QzTerkdZ`75TJNb<=k55JW=&EH47L7)<*oUYidoyg7^?{(e5Q?x_WaTA`>F5NhuLv%aYXhFYOvd2{&w zSgW&U#e3mj8(^pvhFYV_O#jua>}r9bR#-PK`Mu|oj;=Jo&0!_Az)&k3wFadQvC^#8 zYJs6vcsDL-$#J8nYYkEh47DOqt7*!!!_1ng78q(pbmNkJIbn}a3C!B478q(pqSlUj zMWdN@N-Z$ditNTEtqEsFt=QC>wxdaFv(Bjn zhFWo81^QaDHg-Nt-Px>v)dEAUxYR0~qER=q!o2d|a4^)02g{qoK2>txGAmFmFw}}q zt;j`=tS~FTT41P^0G96uF2|Zp?wG~RVJ)@5Q0r%Ejq25{nOU9H0z<8Yu)KBnId#1+ zW{pt`47CzbtLV^)ZOvMu78q(Jh85j6D%oD`=cc$})*iLMP%8)$YY1>ZVun81%_HlsdYbNzvpH}d+q;SV5pT0mYc&BTc4SgMlCSZN=~gSCD+_C ztGHTVsFebiH;2)VWT;_QBelR#D$}Q#0Yj~v z)Y@`yO-!@0sRf2wxnOx~qvOdQDb1>-78q*frdG1X;~$yTS1mBq%0sQq*)tb6Yo1zQ zsFjym`C6t7Fl)bBV5pT3mbW%)ryG`gmixQ;BelR#D?hb5&AT<&tZ?uAGY^JZ1z>sG zEBWT4gUm{;78q(3q}Ggd`?s1^RxL2pDg?{hUc_VEjwby6)b)G7um&}WEMuEo$qW<6F547G|= ztK+U8JIo6E-uH`q7ckT+L9Ii(JI*mHg<4>!RgzkZlT>VARx!1}P^%Oy@9z#Zx1HOc z!p&h5wZKrTG_{HjubJDd$!dY2RvB3GI#@X#KFj@}UMJVurxqA$m8Dj^ihKSv>xNoj zs8!C5OIih6J!;e0wce=(hFayR^(bulRA&A3pYIp>E?}rt0haFvF7jF2>)bg&Mzz3D zt0J`)t;}@Ytm0~cp;jeWv3w<2hufo6nPgTSwZKrTGPNQloL$YVPHKUnRuyW+ZaD0s zStHc~L#?XRNRt;F*F{)DWKF!U# zrxqA$)udLJdc|j$^+_!-)T#x`_X8JsebidFHllywW*c9W%a+zO0E_dYSp2Z z{M})bYvoi647KV~YfYYuJIpGl78q*PgXOKm*2xRsFsqSTV5n7}T9Jmosbp4nwZKrT z0kuwadp6&!v1);#Rzqr)O}~1fSqszxL#;;tr?pirFw|;Ht(^5sC$`o}wZKrT2`q0N z7CApGlv(%G0z<8))asUHVvw2ts1_J%HG}2*fy?VRF-k9XYa{AM|FvMK)tp+dHxJHi zR$8^dP^$&CWF0Pdt>S8dp;k+3oh$tMqgf5r0z<7xf!lsMQXZ?*}e&+*sn~@Sa*=sMVfY zf$uwXGwZurV5s#AwPbs(aIN^C{I>uMwK`BswwGBs)B;1TjAN0Fx2W#txm=3{9E3&{!$AJwFXeD#E8lB&AO%*7-|iKu(A3mUXSvYJs8F7;0Vr<4hK_%BTf~T4RH? z%DGk>wZKqoT(Fi|W7Psft?{tDeL3mg15c~C)@rrDP-_CU$vH3r)^-(P_)cT!T@>(pjB7XPZZZOoE5v)nYu$<0cy78q*H z3f4O9KHE8;T41O(n_BW%&#W41fuYtMSl&6?wmGX_nbkopFw~k$t)5p3pD=5*T41O( z4_45}L}o2k3kY9p;}<5wVYbrw(g2zRyVc4P-_J&Z*7dJKeUutW7Gmet(DX| zzIJvov*xP>hFYtr)&AJYgl26~3kKrS`W+j0~gu9a=JC& zP%SXj+CVK?^Jeu|3ktLm{*7sRf2wTVcsLn>^ne;YY_vW_?i$47IjV>v`yQ3(blZ zLS`r+01UPMgyrpDVSaxUWHvIY1%_JNsWoO`>Auz~r4|@!?Vwi5ldpr!Mq{UUHG|Ldxq}|EUFrTKlLa?_DzM=aBxj0ft)pVR>u5 zOQ-Qm%_^)G7-}7$*7lm!+M3l;EilwNNUfWN8{ai+oLXS0b%z)oZ0AbuYz!tT@Q0tPjWH#hI;AUM=3ku+lH-h3goSp(DpL#>+IBOMD3kk)J)u_IlULT7wM{KB)cO~ew=cJU zd@a9OXVn5jt*6wgFmTjqv!1F2hFZ_4wWm|6K4ygt=U*FOsP&v$U;mj{#H^%hfuYt5 zSl;>kKfMZ0Gpm4FV5s$yT5;mN%wkq;wZKs86)bQ6iXP?KC$qY$1%_I$skP$O#ynygYQ3da+=M?JGwXm_V5s$uT3=EPj%C&@wZKs8J++dC-}l+9 zPildo)_<@9efM~BuXiKQ^kQbk3h!SVV5s$hS_zg9Ibc?1wZKs8BP?%i#Ozz|7qiN# z1%_Ims5R1%_JRsMWdGm_cTpPzwyTzQgj?{H>2S*O>KCEilyjL9M+9&!jQyhgx8$ z6%fI#RfuUAdSl(mvqW#xL zH*1YrV5k+2Te}a>H0zLBV5k)yR?zL0#%-@#YJs6v1Zv6lGV8rsV5k)lR?zKbR-}mj zwE>1&k*Fox%dF&TfuUApYRUF8E5BM`s1=1;BW6?_YgTo&z)&kHtf1S=toCYwp;k0% zUD^L>hgrka0z<9n&XOH$QSvmUle+CSTP-lu`pH>%oHG4(GPCxo1%_HNUJBlhfm&dw6^F(p z?@{gMT4U7$L#?>f3P|^^xml~!0z<8Mu)O1ZK!{XX%sQqP7;43*R@H$yN164nT41P^ zfLd#+zVB{Uq{#l62Scr&sg=9pqylDTPzwyT62kKCQ=aWzeBG>yYJs6vB5Jh`Q9XrO z9n}Iut;Dc`uEP&*d;O{w7-}VwHwe+85rUcjseYJs6v zMrw5p+_}W8fT;eh42D{ns3q@hH!Go9V5pUuTCEFq2yIp#wZKp-3oLJK$a@3NyVq~j zPzwyTvQn#Z(bAL5>Z%qPYGrdRSsS6F<<4i;uWEszR(5J#Yx`)4S?kmSL#-UtT2=a3 z7PC&N1%_HVskNq2*|BClQwt2Wa>4S}M$Tay5}6e#ntv;Up;m5c&3@2twOQ%Z0z<7l z)LOhcdRnu}ss)Bxd8sw{!TZ-{wNVQUweq=^j6we98^^7UQEGvqR(@*TUKeSGSu4~6 zL#+bATCrX0s9IpCRWMk~te0wmp;jSS-u;)n&Y{0M9>$LD-(Fy-RhU|GzF}4owZKrT z2rTb>BmN(Go0-*4Eilw7O0D9j@})9sx>{hURScH54&@xcto>?%p;mEfjhsAUqggN1 z0z<75u!7EEA2){ye)7*D7;2TImdv49rPKmLtx~Xp&Y@Xd)B;1T($rdTe9H>6=BWjS zT4i7bokO!us0D^vWvTVJ_=X5(eN+n!waUTr=1@K#ps$<5lrj8s2!>kasU`1iH>;{z zV5n6AmN$p<22|^AR)4j?P^%)fE~ifx&8(GbfuU9 z8qg>2BeSxo1%_I6oaMVq!Qb^}xb0OzEilxo>nu5Q$h)G*ZnN5`1%_JnV9EKRj3N21 z*$Zd6)-bieP^&(*@cw0Itx^jNwHmmV+`^(C=S;HJS+&4Wt0A?1`#$odSs&E`L#;;C zYQ8ztIkN&|`?nVuYBi?T?b^lam{mqCFw|-S%iEU+#yZ!-tj=nIp;l9BO)gimhFLSz z0z<84)WZ9+-OTS*3kKrY5~hTZpgko+qI&{@y{U`YPF=+fQ;vo znw48EFw|=0EZ@=ySe~oiE~>P^&$)p6{QV)~vX3{WA}STED>Z z?!Rt)h*Q?AVrqe*RtIYJ9NzAZS)J4ZL#>Xmyfq&p&GAWQ%~1;swK`EN-0;a)%{rzQ z7;1HPEgAW^=OZROb94BgT41Qvg<6lQExv13oOu2@1VgQ^u)H-d_bInrE2mmusMU>H z@;!8B)l~}&wYtNS?IpM7Qef=bf4f$HwZKrT2ep3GZ}rry#cF|}R!`TGJ>~tp)_2T0 zrWP1#^`chWvRJud0z<7a)SCR`)&R4*s|AKyV`0f>&Pc0codt6byVf|hz)))(wZ4?glFO`B zYJs8Fcv#-K=)3O^UY>HTqiTVn)&y#;`K7=BvmU4ghFTM0d4K=P^dMhZvwo-rhFZT; zYv|p#o6Jg>(7%zh=z)mDSfuYtMSV7l@S@YBaL#?^glC@#hF15f=YaWeD)`nSss|AKy^QpC` zdxtS*eNhVxwHCng?knZ>8~5GXNRZgSmBCPJA+>G~|MA7F9BP4~)}mmoEv{8jEilwt zOf7l5Y*rt&z)))mEbn-DZ``@Hw_R(AT41QPlv)M8{c_H%BWi)6)-qV$V~6(Juf{g( ziCSQ&wVYZzI%K|KR+J?EnFm9y6|lVh>$eBZrkIsgEilwtNv)^$yO~*i)B;1T)zrEYHC<1$=BfpTT5G6vHg5hlX6;i847Ju$>-(z?N6dPt78q)+ zbC&OL7%(_-m=|~5+K3S7pLsCU`omdrwCVXITqd(JsRf2w>zySnd7b$t*Q%x#7;0^B zmb4ZPyT0A5zG{J?)<#&~`NrP!RmUxGt%YiVq1Gm9bv?gyl36>|0z<9Mu)O1jJijsD zwJxg#hFV*wC4ciZ>$zHBsI?VVpl>E*+l*!@w|`|X(IBZ=ZPWrot-q+1w`tR_ zW(`#f47GN`3VPmq&CTH)wZKqo7qvo^=)2LZKh*+5t=+*|2VCodT41QPCs@m@S89Qw z*4|*P6Rs6GnSX77q1L`&Ewj?71%_JtgSD=>R&lk!Q0qXjmRZfz0z<8Xu)KZw>65(` zj=R=iwZKs85Vf+Wc^1m7#cF|}*5P2SBd&EwEilwN60Bv`6Scrl>u9jnQP+x`+`qlR zQ0rK*mRXtA0z<9i!CJ>$tEyUHsC6P(%dB2%fuYt(Sb@G{hK!+5j?ND+xz-%Dz)q4-WSp(GqL#>O!T9;jGfm&dwbtzcOto>?%q1NSKtuwB5Uo9}y zx)Q8qR@jvOnFm9ytHE05Tq})QV5oI1Sj(((YJs8F^{-Eo%JD(_ke)dEAUyUy}jX608447KjT^3K`hdC`ilRaY%A)Vfct zQ4L3hFsqwdV5s%LS>Cu3gbgGA({~xK78q(hbe4?kN6NmH&04A!7-~JDami!YpIvL0 zT41R454Gfc-mJT7fuYu8XURxj4T|P_knN2tbZY-r21BhU&XRG-ckG&#KrJxT`WKdW zE_(XUkhjdrtQHt*J*8Imkr}(0RZ1-|)OrTXI~QGB;=ku+HB<`>wVqS!=Gx1?uWR#W zqq|yQsP)2)OXe$d<$hyBJ8PU;V5s$yT8H1J^1Te!YpqcW47Fat%HZqB%y&7x+V=(Q zo^?_!Fw}ZYt-DRrOg8Is9k81%j#^--^?_RF24^{K z)*iLMQ0pTs?-(V2z!I)sP#EmYnGeCFlqhU3kU|Sa;XJ|THmQ9uUUHP##LG^Fx2`%E%`n~vl^%c zhFSp;eXHHQ|4UkrT&uHMV5k)WmiPXzX$SisFl&TbV5k)mmUj*y?-?27&NpVN1%_Io zs8v1Dy7y+SR|^caLc)B;1T2*FxrrBe$GwIaguwpXfC8)FS{bC_Q(Fw}}f zE%{7cvudgZhFXzfdH0ovYK9JBR!6nKP%8?xdNr>%+N?2ZfuUAZH!eBO7reBrs98(Y z0z<86)Ve=)Yb&$%s0D^v(VgW>1+R)B;1TSg^eNuOc6NH8HEWT41OZn_AnWcZg(G zBelR#D-JAg|B~~=qwe(pebfR&t+>?M((+R;v!<#AhFbBQCEH6LI~;edb!vg3R(xm4 z_KG_Ba}%?Us|AKy34)F5kZV0u3krk0G$tnX@pp;kgz-tlly$Z&~HxK^AD{C^&4t(4S~$3$k;PzwyTQaQ_8^UK`**8sJ^P%E{wWai~FKh2t~78q)!p>fH3 zEAqM461BikD=oF!ZFy1NtQ~5Bp;kIr-rx1QWl3JntTSqXp;mfoWiDSot67iK0z<6~ zu)O2p$i~~>nDtF9Fx1LOt+gKm7n&6-lYec1p;jhXa-0`p;l6g2V!8X}^lE{jR%U9+ zX9b(pP%SXj$^y%q!&hy8A7s`UPGgeQJTBRyJ7P9G+~Ns-s!&)B;1T z?9|#^>--(FQfKzhAsA}qa4lK$C4R0yi9J8#x&wZKp-U$9mc*NT$G zKl5Oym7iMaD=)ulRywu7P^$p7z)-6cEbnoOJg$7GR(WdO zYL|C~S&_2&w-*>{RiM_D-En%Dl~OG*)T&6Wyi*6xGpn##V5n6ImUoiE6wVr78q((f#n^0GW!4h4z)-6iwPasD?piz4 z0z<9p)RNaZm~~MtFx09+E!mgPy4G{Gz)-6uwdAu1%nFy?zc#>7t5&eqN!JQg3k)wK10&5Us1_J%)q&+bPLbCw&v31}YJs6vU23(PpCFA{J=6k2t$M*)E!}z4B(=a$ zt3I_-j@>fItaWOEp;iM}-a3@m+x+gvbwVvL)M`jAd7Zggchv$ztwz+6b@7t4Xld8`nyz78q(ZrIy@(nN>d>XPB6EOf4|fYU9QwkJ{?JOS{D^-{;=@uJb)hB@DINQtNKzkr~bU zp%xfwwS(o|e}(NCp|M#%=k&M0P^&$)-o9y8)vVlVfuYtfu)N19le&HXY*ux(z)-6L zwI;2a(!;DyYJs6vM_AtdSCV)+ADcB!EilyTM6G2*?w&PkxmsYT)tOpRmY$nx)&aG^ zP^$~IG8D@kWJTRp3kndzPD>rRW@WWD{e0TRt7_@?y$Vau>VA= zxjcm1zp|?ZhFU$SCEx#LRwK2*P^+hF$(kP?s(3fEMymyeTD_mQjFIk$ff!BDF&EN>ltT{Y{yS$Wg~L#=+)`YWdIbNk)Q zw@?cVwfa-*Qh`W|&6=bZ7-|im){5T)5}CDAEilv?2+La=uit;q7t-Cr$7+G0)*xyv zzx>~2vwq6spF=Rz8VoDYw=QIDTps!RTC?)11%_HfsFgX=@Y`lJR|^cahQji;SNQ@9 zJDD{>Eilv?My;F^9=$San_6I~HQbF$Mt){g`MjUpeac<6z)))hwbH$b`NFK2dHr(; zhFT+GdGGUmRV&G+&#qNMEilv?MXlZ$VvjMams((`H5!(8obNbtS}wCzss)BxW2kla zTIgqH-Bb$9wW1GO`X8n}UKO11EHI7<)?|iswR!OzMP-{FaZ*4@$UcIJSebfR& ztqIink*Rq?v(~BwhFTM;HT7_@EN0zR3krB?IS-&&XzJHLN6z)))vEN^=)37xuv zS!LA%L#@fwN>ZfdDzgTt1%_I`{hx7dPzwyTrckR|!4Und^-wJ^)S3z_jc?zQkq;dk zBT|4nM#V4SpA9h7nntZ9O@C`+RsprZP-{9Y?|AsNcE-n{U8|8=V5s#wwH6;)5Xr2` zYJs8F3|N7_G0E|8cjzV$%sQYJ7;4R=R?RGz?wIvKEilxY1$N8aZfuYu7Y85;Z@rYS#)dEAUC9q^|$VHyhE9Y8Q)B;1TrPMmvZR}&S z0t)+Q0}Qp6IZIlyy|TGEOrsVUYAtt`%wg`*%levCS}ictT0!G#a&LLPxUSVwEilwt zNv)I%iY7E`s9IpCwF;K^Ub6@%N*6S1o?2k2wVGPRU*s8R)=ss+P-~4Fm(0eoa&eZL zbzLnm)LKie2nkBvH0z^UV5qguS>EEOL#;oYCAYA^l^Gk&%Apn*YOROm zJ#Qn=rKEGMs%n9u)&^?HYkSPZr?Do{!R_j1Srw&~Kztnq4rq1Hia-8!H4j9IJH0z<7s)OvZM z!vV97ss)BxhhYUhMzwSIm5#wm%Hkmb1EilwN8LZXD?O%VX1%_Ius5LVFw@qf< zRtpTZPQ#LYSuR^vHOdv}S|LmLXC4f-&QL4xeTQylrBDkDwa(JGsr>!7iaA_siCSQ&b%9z_SG|d0)^)YOQ0pQr@BDB| zv93P~xK^~1{y79gtxME;)Vuajvr4N4hFX_ldG}u%iPxdS;Y)}GYTc#Q>B<}9n>9}@Fx0x|ESbag zcOFh{=H~E-T41Pk-&t}C4~+j_*Q}RnfuYs|Sl*gnTD{*jv*MKT&mkCUJ)~CUx`#uX zRah-B)Otj%2%%QYHLHzUV5s#EweGF!+}EthYJs8FV`}Z~-u#JKJJbS0ttZrqR4Z*` zv+k<}hFbr^^3FG+mPmcTtjJ~ka|ni7PpQ@NV6xa|ZIMcDZB$eX47EN` zD_-mJH_RHV78q)MgeB(yankj8ZQwl0t&QDkfuYtnYJIM^sCXu4-BSw;wZ1z` z*2dY*SLft$+bc{(|7?Jv)(>aN%;)Yd#wD+}F)N2!V5k)umUoUF zf9imP#a*j~T41OZhFV4TW*%YIc(uS#D=aK;4&~gYlxuBL3k#chFWo`^;?GYugbet#A^Q807I>~)Ve+*e|58Rss)Bx@nCt!d3nA!yE|exRtpTZ z;!|s7>Bw8n8mtx=Y9)Z>t&Ojjt{(c?wHBxahFU*UYub(`t<5^B78q(Jgyo&j&s`Ed zi&-z#0z<7t)LNTsWiGSgRrk+47-}Vk=1#g#PEW zS^ud8hFU3Ld2=YAr)O5Y8vdCFL#>q5y8iLb1GDm}1%_IwXk7KH?R;rg1GT_VD>b#I zx1CYUtbuBQp;j7L-nr<5QPtbTbK7fyT41P^mRi$Zj9y^Y9<{(wD;CSl%&AO=; z7;2@bR^ZS{bPoFI$$IW))Nm47D=3mT$=i z{2C$Nm5=Ut*ibDn)XGe)vtfRJVb%n-z)&lTv!pdPQ|_v%-1ge378q(}b(Wl^$hnPK zf2#$CTG?QEj~zzG&NtDlFKU6IR(5LTOdq|2SqW?TXC4f-a=`Momz-~yRZuN3)XGV% z9%px^FsqSTV5pVLwPX$>RlK-3y_>^9YJs6vZfa$(^=i3U^V9-Etvs;2W7OV^B|e(9 zQ!Oym%1f>9G0S~1>u#JH|sFj~urMG@PX;#A8{_O>ZS_NRG z@pXg%)}wSKPS zpLsCUDo!nVU8Pz1)dEAU60p2=nCwl#w`SE-3k4I5i@-+rJ8{1%_JHsa5ybzrUK*Q7tgkszI%5>GD_49?8Zlt;zh(_r3kP zdl<9ssRf2wO<;NZmpoq1;`Xn|4gIqLhFVRj^?F|S3T9n-T41Qvg2pAEixu0o7N`Y=S}m!yGH>)4X5Ci{47FOp^7gN9 zKVRG#+s$FhM*cYjL#@`-lF!vQtAtu$sMQ9RcbwnQd+AZLnyCebT5YK{;po&2W(`#f z47J+9^6o3;``XM}q!t)zwWrpp`_bl^wO=hT)cOTh(DTD^ZVvCM1%_H3sMVnT+LUI6 zZS0?UFx2V@E9jbUE>{?T41Qvjau^BRI|>g1%_JPT}#F#$HTU+^+qi) z)apU418?qqGb>pW|Mmhyt)8&F=ZGq;&QQ3Do5QMVfuU9}YE^E(>8)8q)dEAU-mWEQ z=GWGZsbbbfwZKrT54F}@OZdX92Wo+#R$o}&dDNu+orjwhr>TE7z)-6nwTfiO(9x_i zYJs6ve`>86eJQh9eboX(tpU{f^lWcmv(~5uhFSw*dB=@4hx=VI>y}zzs5OXMLxzr< zV^;KL{@DOSt-;hPlD&Lwvx=z&hFU|YRlZ8`dS-Q33kRS2L z0z<8F!CGc@QVR^V#>4WyFW{$QsiGEgtwm~qq1FUy4XT?cidm=C0z<8du)On)Dre*M zsNhtfYE7nA)A}bqRaPx9)cT!TSz49KYgQYzz))+3v!pdSV9${Zt~F9EFw~mq zEIHc9V3M{F5P&sS#jF{EraDfChERYU|%#V5qeYR?xL!R#vsZQ0otB z$=WchidtZ(wH{W`wP98#wZKqo1GRn`aA}uW6V(Dkt&OmPt_`!+ss)Bxo2WH@@__1Q zom2}9wKh{r)`nS6)dEAUE!3*GtY%8HBDV8yFEG^F3M=S2z%TB8Ijve?sI`q+@_5;- za%zF0)}L-%a{ncdD;v00JGH=2Ydf_r|8u*rS!2`!L#-XKyz{8|b?T;S?pn*$0z<98 zsI|6Mz4m6ER0|BXc2Y~;dz;_2Ua19!TDzzv@4Yqa=l1^X1%_I?VadKM7kO^EtZS82 z3ko6?u z{BYudF$=!A)*!XOQ0oY_O5Ip_)~pq3fuYt>8rQr8(N@KA+v}`aV5oJBTBn-Fn`_o{ zwZKs8xNFH)?iYJ&D6=AT@XsL_YMr1~pAplio0VEEFw{B;%RBZa9aA}lStZp1L#DYKfZ1%_Iuoh562d9HeoQ@A-Cq81oxopF}ThI|IHS@YEbL#?y00)2*9&oB0y zWY$i#z)(@a?!+pVb0GtqatOP~mM~v*LI3Z)Gslx(LhL zm*q3Y)4Dm#qZSxyU82_K6ubX1tEO6DsC5~Z_t;_1m;9~G>Y^4HYF(k$>_(SsoAs+& zV5oH!mbVV$oPN^CthH)^q1H8O<;oEwj#($v0z<9q&hjk{9DCck zet%?-SrIz{{SC`IMlI+tuS{LnN~0DSYTcyPps}g{HLH|bV5oHqmbW(Kd4MDC zy%o*X0z<9a)RNb4m^EB2Fx0vOE9iY?7We%QOVk2Gt-I9995McWvv#QkhFbS%T=KWJ zj&2SwsRf2w_o*eHwP;qT&i?HMhFT9`$vTvaoJTcstt@JRq1Hoct-t^Bhgl8O0z<7w z!N%3WwMMB0hFbqnOU7l^I<>%1>v6DF6W6+^78q(hp_aU!&8#14fuYvFu)H;2bKAN7 zHC!ug7yrzIq1IDsEf^Cqt68z8lJ9CU>!ey>sP)Q?OIq?>EoMDb3k zYnWPKsP!K#?>^;w-8%8iTA>ygYJH&Ama*5rn{`SpFx2`8E9e}Kc60bfEilyjL@k*^ zv*L8~&pa4veTEfu4$aD|78q)Mp_a^{S&h^JL#?l{g3h5?!_)#pt#8zlIW%j9T41R4 z-Hl6*z4G|0l$*m-YJs8F4{8O}czndH_iBNmR)FtKT%kgEbNF(8w^3##?Czg=Fw_bG z%X|OV<5+pOn^jURFw_bO%bUYzyY~zk)g`t+rp;0B#rPyft=p;okDEwgf|1%_JDVR`GYbBm4DTDn#ZwZKs8Cu&s+ zQ!trXz10Fktr)H)>u^WWi2cl(tri$+#iZ8lFNJEGwO1`L)QSbmTZfBYwwrC%L$$zA zD>k)WwoiD%tcbn*GY^JZaoo6M9m*WGaC4YhEilxIOD&m0v#P5FhFbAl%bP>9da4D6 zTJfnRb7+crx~+{SZM!?oblSF&Hqy4Ow{6?DZQHhO+qRL$m;KbLz4DCnjhi1CcZ@sdJA1F% zr%u($$qBV`+I5+8)RuU+{nVNy78q*fqE_ILH8a%OE*2PS<+d&JST-~4XlHmwEHKo{ zLoG8ywY>T`lLtesys(1LP_1NQfuUADYMB|T6(ANEYUQ`oZty0u7GgPaJ zSYW7C+P2IL%{5yaJHwu0fuU9zYME;`wI+)NhFWD|1;1ufYmHc7s8xL#>Li+-tV*?<4xQurrL?-#N-)s8xwtW`=6{ ziv@;Sm0`L2FkZOFdDUtp78q((p_W(31AWyRE*2PSRfXl=JD3@&wN@-J)T&0U;Q`ae zt94l{Fx09JEBFkX+Zp~83kBIso$GSy6}R-{4BX8AMDH!47FNQ%gj(Mf3d(&s|~E+GgPakSYW8tmRe?pYE2aj47J)>%bj6z zJHvxwfuUA=Yq>L2>!Da+sMP^h@ENM*HN=@A7;1H-mYJbiNyGv}txm9l&rq!*Vu7Jn zXKI-ls?|g+Fx2V-%be%U*Tp0w%J;W393mDNYIUVn|5V;9)mkAI7;1I%X!WzL(_(?4 zR(Fq{e49&emA3MV-XR%N$Z@5BN_tzod-dxsEN>ReST z>~LrDV5l{mT9H3I*{@bovA|Gkgk6`J;qmdILa60078q)cq}KA6D+a1nQ!Fsl8f9B% zhURtAVs?g|#R5aE(bO_O|59s?SYW6%#-ml#wvLDehFW7iT57!&3k6;aSYW6%ky<{RPKQ^kw^(4PHOZru+P0R81%_IaJz8pA z5DN^org*ec+14+yz))+dM@y~vBb~{Eq1H55<{H3!MTl9ULvGv3BNiBHO{dnr(YF(* zRZlE1)S3ayJs);#_2IZ$1H=MDt(nx?5TP-`}| z+Jy42tk!$6z)))rtl%@uWoH;`lrwoS)S62zGefmrA@ENMLR4g#mT1YK3L$ywc1%_ISU}bi;q1S;C(f?(#Gkh-=7-}u1mifF& zwPKBSCJ%;MOJMm0waj^b&(l;L)XFUu7-}u0R>9=;JF8V+EHKns2FsnH`MgTChKL1* zTFa>wsnGEiYON9r47FCka$ie1*?3~RtagSM!~#RDmDC#Ey>nx=zKR8gTB~5W`|ww) z+JS1t8{F&OP_1iXfuYt0Sixtg)-SQZP-`Q#%na4?8|zFS47E1F3O+-% zN{9u9TAQh5W~f#hvA|Gk3oLhr=Dm(N>24At5r78q*nrIwkYT93p6L#=(Vg3nN`aO0iH zgQ3=bYMB|Tl~F7()H+~W=4r*;r)01*tSS~5Y8|AOxld86omgO~bqH4Q`xLc?iv@;S zhpA=mQ`A}{78q(BvFmd0Q`Fik78q(BrIxu*QR{|SV5oJ>w#*DK?5pXQ&(83(SYW7i zoLc60Vbn@E!8yucsC5FCyAOwVnch#WVq$@z)=6p=zWp|oTJ6LFL#$-khFVu_%dG2WtH;IF>LL~xYF(vP@rnIJ$Fx0vR z%RL`%$(E_8TED~sL#^x7x*6(pf3^H4JL>{Nts8b-?hFI%3hFUkNWoD?>3bDXY z>y~Y~GgRxmSYW7in_6auYW)xk47KjS3O+-%l1y=?0ft(4sbyxUR%x-oQ0pEn^Y}7f z$>Q$%`Pa^{vshrLb)Q;~t28gA)>g5=Q0oCK_c>*F%gm$H`X&|_YCWV@qMiK@sg-A{ zGYv4*dIZazVbq|3^C357lNVIQ)-zR zs+CqOFw}YmEBFl6sw5T|YCWfxnW0*}!~#RD7qEiQP_4ycfuYt*YMB|Tbw(^O)OrQW zy*@PedYA3*sD2d-47FZU>tgG81=UJ0-I+WXYQ2HwKBuh7mwB05g~S3wt+&*=TI%;& zwVI0shFb4nxij=1SbmsVbh;E5(^BqK2vM9ce|!)l@<#OwZ6a#{`k6MTW!Pw zL#?mWGLJ8{CW!@xTHoxt%z56Nqtx0i78q)MrkYNuhy{jP|EOi2E7giQ%b7eFYI#LAzyD?SydiRjZBzQ0 zonc78q(pqII2ZIcb4fN5uj|t;p1xvE_`PTF=D-L#-(PV_o6rIFkoMt*F$x zmUI6#ZKV?n47H+BYiHPAOVlbS78q(pr&hW}DL$yxUMw)wib1UxXU^|ZYob_Ss1=i1 zU6K@Tq}FD!z)&j|wVKt;*+;FbVu7JnY-)Ya*kzzv-^Bt$tvImEdBYr=KBo`)|$m!u8+v8P2EHKncOs)CRa_>~DwOC-NEHKncMy*UA(yvy_d%iP6Fw{y8%f0S3_YNcM z3{!~(hFU486|eivb!wFp3k5fuU9!YQ=0)DUn*w#R5aEw6NS6ntO+lc7{x@`ns8xVk=H5ZAw_<^zRzYf+dk3|mEOsUjhFXPSne&F( z8zDj`&Y@N&vA|HPFtySpcpqD>ieiDGRuNdKrL}kJfe~tT6blTsic-rr{H%6rO%e+X zwTi)V_u=u6JJzVRSu8NrDo!nP@1WLIvA|HP1g*>8w?=cdzKaEhS|z!)KFw#f;w^EG z7Z_><{Ev0z6AKKrN>M9yq0JYxRZlE1)GAFabMK&5f3d(&s|>Zwy@Of{#R5aEveYv7 z4r(113k&d=V5n6YR`BQLu(mZpEHKonLM`*WtkyQMz)-8IU6=d3tk!L@ zz)-6iwaoLfS|OG>lLtes>ag6$vUy%sD~(uSs8xen=6PAIieiDGR!zIEpwkqdm&4c@ zb{7i_wQ5nzJTI#?S1d5ps%=~D^Rilp!~#RDI@B`H%WAz83kx%`3S`Dame_g~GYV{Kf47D2CmYLzX zC(A~uHCHS!)M`YnWk(LRQEQ)AV5rp?mit^8I>fCpYTXwL47Hk2tAf|kmTGyea3&9i zT1{cO$E$S4saMrXA{H2GHKW$!m_IhDRYWW>)cTKF*^1RoqE-{Jz)-6>wf+ov8(*y< zVu7Jn3s~m0O7pcZb;1r&?fV>-iUo#REvaSBhiaV?3kz!C& zsMVTU<}<6+im}o;USO!zhFUGl_MUOdUW?`s3kQd zKYjb#)*!LKP^&$)D%ZMFQmvI@fuU9hSnfS+vdwQ|@3gJ+Vu7JnM{4!$ndg~Wf5ZYq ztxmAqYwW~z``lJ5?J8&TV5rrZTIZS!o1#`NvA|HP3oQ4syfEvuoNA2_3kAKamI#U zq1FJ~GBY%vbGy#YaFmJ{{c$;k{TI);$47CPR zYj(9^!K^xBfuYtASngxFR{nSYW6%23GJHsx?$BFw`1Lt)wymaOfuYt!YVEt9?T%WD!~#RD zNw#Iq8*P@p>Y&zrvA|GkGPNoVUDiY`-;K_?z)))nEcbX-&e61)TJ^*NL#?UQYPcw% zgj#dN0z<87c3tLQ)3;p91Y7J3Z;J(nTGOdzW~i3WCTCq>s5Qg3%nWPYdvQ#y%3^_` z)=X-ZpZ+wzTI0n6L#jFcqIk3!Q*?gHjzsb(9 zgjisxHJ4gu&#To_EHKoX=h50@uX|UE1%_Jlsa3kr;M{866blTs7I?Jw+g6w@&NRSK zYaz8d?@3o!t^8tvq1Gag);`9uMEvDATEdw&CHD4?+)LH_|TpyY>M5{OOegb$OD$#>M6C>9uMt%2ny z$7{~{1Kktb)&;S^P-`u<%-``*EBtn6U0|rS&aTUxqiUA?a8#|rVu7L7dTQN`IJ~b~ zy~P4Utqri;b5w*$UisA8Di#=OZKPJ(&*z@0^!@d%QY(`-N6(gjisxwUb&Q_D2h))?u;0P-_<~ z_xiBA&*PA4{S^xgwRThMcizL})XKBVnFbhY?V)v<_iw1xMJzDX+DolUIev{$YrR-t zsI||o%lvCb`d*wn#_q#cVu7L7erlP0s8;gb&bq)*>i{fwA9h$7Kc8Cl!~#RDgVfs9 z=+I%cW{3rbT8Heq%$}d{ z&NRSK>m;=rwGOpjtqx*=q1Gu_?lr)eo>gOyxBGClSYW7inp$4{5-w5er&wU9bq1EZ z51&sh{YkA7`+=2ly@pzT2b_N)7;0Un zR@R8gr>NClEHKo%LhE`nrA#8V_K5|CT34ynKGcuDYDGTi{0qTQ>zZ9x&}jqr4&&@T ztSc56YF($+l|pI0s5L_@Fx0vM%j`q*ulY1H>GsjKby+Mh)VfKnXX*DBS1alvXI)^Z zb<3{HoDUn6D;}U$X|cdi>o&DQXNZI#Uq1GK(?mmog?8R@jj)(<@T6d{+E!^;I zYIz@a)&+)I_h7j*oO5%D*91Gm0%C!o)_rQdNq6vuT7AU=L#+qYN*`;%f1_+`w^(4P z^^jVF){w7ZKFzBo-KIJ%Q!^+`;^< zv4!?tZ-ZE1sP&XuYf7B(RqKpcV5s%XqqWGko{I&BTF*UNYK1!LOalzHUcfT@(0rNK zd*|7fpIBh1^^#hhr`=DgRuQqlQ0tX#nSV{~I{yO8*;W&=z))Q4et)JN64g4+^ z7;3$zmU-WoT0X~|;{}FVA8gC~3(H;~vr?^`Vu7L7M{4DY(#1=y8e)N=)+bo*Im)~* zMXerUfuYuCYURHbZiQMi#R5aEFV+fLmRFyL^X7fEGu$N>7;1gBmYK$}v3WnLbw?~P z)cOX?953_LEphbrfp#DM5ep2pzEi8#+z5y7;627z-I( zsP%_hC+j7;qE@IA&J4j&>n|+#+&gi7t9ife@k%Qe7;62amic@ewaSYHhFV@xf?fge zHowVbzUB?^PWr|^e{~cK47I$iW%l8inU$ibHAO5i)CyrOxAo4pwuuFXS|P3Fw$!>U z78q)Ug5}QeVxFT>pWD_yvA|F(G_}mn&DBbF(m7sWs1?RqW?ffvC%OB&nO3k!+`hFVdm z_4V__vL#^o6a`%Q>=fwg; ztr)P}y|MB4fQxE<5(^BqVp7ZO4YhnuJCg@Ptyr+!Ytb`DKGjw$zgS?X6`NWe@}``k zRwJ>%P%93s;Cn-@VPb)ymJhX7L<(%J)@rf9P%AFA%-&Gzf>>av6^~lGpB> zP%A#H;OD4Mc5lQ#<4hh5wGvS4{so`>YWa%=hFS@!Wv=JH*j59vz)&j@wNl)xw?nN# zVu7KSFD!Gs%o@@R=+Nk;Z7mTC47Czd%ls`QwT_DghFX5KE_0rLW?L`C0z<7N)cRF> zQBk$RoOLD-hFVFjWgg1`FOOaRXj@6e0z<82)-sRfMJqGjQmcSiV5pUx)@A;_`Dfdz zB^DTJrJz>d3>TBA)m1Do)Jh4%AzQT5H7uL#@=*+P-M` zQ?*Ws1%_H_s5Rm1=~`+%7Yhuv(*BQDsB_Ly21BiM)GGY`@p5e?5ep2p(!&bA=U>?4 zRX{8-)XG4uT&n{N>d47IXY%k24Lfn)Qjby+Mh)XGZh8r&qxo^bY_=%ZL*sFjUcO>2i6uU4q@ z&QS(Kt?bq^>+0HkNR0@#6-O*E)XHHkv##A=Li(tcUMw)w%IUGLq_$O9EHKo{MXe}D zV=Pyzu~=ZJmD^foUFLc|nQaXc3khZMH8 zSu8Nr%1148o>%L-SYW7?AC`L$+cU<28!2t;msnt^ShP^+M|%nV1)n7T}@eqw>4Rv}pKW7#|}H?gfHVu7JnVQS^dv+JH(r^Et7 zts>Sk>x!LiXM^Up^Y_74Fw`mr%e{9fQZPgdwc?5ehFZm` z)u~#=ziMR^3ksFmxWKx0T2-iZ?B=DM zYV{Kf47IAlaVu7JnZQBZZc;ROOdF}CP zB^DTJ)uC3)iyLC7HCik%)T#^1J#Q>4nqyTX+gdFa7;4p{mia6KwN8r#hFbMuxsT;W z1-CR+>y=nwsMUa4zEA$;QY+#W=XimkRzq0s@v2dJPfNAZiv@;Sji_}i&GYJNl@kjL zwHnj9N{)^BO|5offuU9tYK8uHVYXW1#R5aErm)<{vUy%^XOGtgvA|HP8MVyMztlP* z78q*%XDzc29~B>#zpZWE7Yhuvnp?{}JN)WU-A^s=tIqKPL#-CD+`W;g(~=r$B^3({ zwOUeZ!;Z)?)haF)7;3eGtD9|^$Cvq;Z&|xH!e4hL4~AOZsdb@J z|1@f45DN^odcbne8|HKMo7q-HvA|HPC$(a1j=E5-7Gi;+RxeoYH9*9ihZd;SUo0@x z>P@YfNiI)TYlc{0sMQCSyEp#Usu@?UjbeeJR$ppu9d+xkTBpPUL#=++GRLcVthk8+ zz1^Q>KNbrNwfb8N_bEYt!&a>Wq1Fgk?hFGXb?L6wL$Sb6Yb3Rb zRp}lB)7cwfs5P2eXLEh1tyUhfz)))pEcd)&KC7yZ zZPgVE47J8mE6MD~i`42W78q)cqjj0{VKv(tD;5}Pji*-H207NMwNWfE)S5u+%F=&C zu86jEMJzDXnny21os5Ob!^*Y!07?Eu&_Dzu2^8GHP53J+qQa&1%_Jlsa3skx1VY)5(^Bq7I?Jc*w!hrz)));wajbgYW)=p z47C<{wBp%TmOIYm!BA^4wag6Fsw5T|YAx|-#kH*tVu7L7QfiqQsx@0IFw|P+(ekma zqhf)f)^ci@8LAa178q)+fMuS)%vZ4lbp|G|t;~0w8G@nKN@|(++o)AqEHKns1uy~-?kQNRTB#gwKjRQ zlGs*%vA|GkGqpM&%Jo#OtzvFx1-N(aK<3Q^W#8t(_h%wf2hzhFZH|`N<43U(Fhr z*|uJa1%_I?srB+_!Rcznd*I9v47K)nv@+UOfLLItwb!GiRu8ejP-~w@E30iS7Yhuv z_ItF{x-J$NY8~)sWwEU=51na%q1Hi|ZQfszYV5oJ( zqm|9J&WHtuT1P!vYW)=p47HBIazA4sZ-s-4bJ$jFhL#+!QEid~zz&5eKQ0t;c zORXDXfuYtVk5&lV`Y9F|YF(yQh1Q!ttCj4DbG*P%>k74!6{~aVnw?=;vA|I4Dz&o4 z7!_NsMq+`X)-_n}>ump}nU+AUu3~|q)^%!~pLA!dTBF4RL#-RsT6BGFW3?8F1%_HT zskJ`+upDY_7YhuvZozV2OG(yabR@OTiUo#Rx2YBGN4Jz}Jr)ZLweC>s-jBO$)cPqF z7;4?6R-9^eTB{ZHsk1l0Q0pEn^Lmsa=KI$yoyhLP6k>s))_rQ3_rRzXAQl*EJ%Huz zjqkG9b`^-6BV5s$sT75z%*r-+!vA|I4Iki^K zc$Gx0|HJ}AtrxJ&@iPCKr01UIj%N49D6zm$>m{`c|0*?Et+ir-q1G!{?(3q93eNtf z)_JkOQ0q0da)xS@T&>SyfuYtLSbjlkGJ7Lg^^RU@`8;oNV_-Qiv@;SpQ&Ze8*0UP;Y=P3wZ7PvIbQdC(rs2NyI5eT^_5yT zLZ92ER!yL#=<*DmbT86t#AW1%_H) zQO)mvxvdcE^ZBcFTP!ft@`mO9{jUn`&ox%-k62)+6#|xfKJ2`()ONKJzjBTj7;1&2 zR*!4>3#e6CEHKmx1uhR$5DN^oB6zfZ+E$#`&hY|6 zt%x2iwF-&_hFXzexyLK%^tESy*;aG0z)&kPwYu$n|5B|%Vu7Jn6pz+l+nOU57-~hO z){DKxQ>b-REHKoH2FpEO<~`D%Z0oI9V5k+HTHU567^POcH_qh2P%DN<>!WQI6AKKr zVtTaH>L3;vYQ^$seXy$>&$Hf9etvJ*&Kd<~|Tc5-NLoFX_O_*45jatdx zIx_@At+*boueMc1EHKoH=h0GYh*)5#72l)v#kRJH1%_G)JX&f!6$=ct5_+`$*jDU! z&NRSKD-pHK=N_mPAQl*E`FgZ|+g2~Jz)&l(M@y}>Vu7KSpGPauw(g4shFVEHT5833 z?@R*>wUWYe&r#<6y-#ebm{?$_m5f?dN|nf}R&%kyP%Akszo2ux`PW?8|LgKpd%ZDI zEHKncL9ML&*Hl+)xmaMRm6FzF-g_|3wvLDehFYnp)%xR(T0NTYh4Jp;kI-O%3{4wpw|`0z<9zu-x-} z$pvj%b+N4~Vu7Jn25Ln-axJP_t;GUEt&AS6uC_HuEHKo{d>T%|UTE)ZyL#>?D`dVbuAhnu{1%_I=sFmel_^oP< z5(^Bqa>H`(ze-G+T}iFAVu7Jn9%{Xv8hfT%7sLWXt-RCk62)+RghZd zX8~%>6AKKr3R%mX4|ngn->HRd?H3CSwF+Cy+*da3@cWHgFU0~wts=18J>O{mou_KW z`0Pv`47G|(z6Fp1TgEEX7Qm9XnF zYbbWIdEo|jhWo?k3dV6SY8nqsY1%_Gywq+)t>C>~-YK8vd%n%HM9q)|yS! zN-Gu^YL$kSIjCb=zcS|Qp;iU4z)-6UwUX~SdQYt`Vu7JnSz6bGPq&V$HB&4w)G9}< z!h_*gEYGo1& z47Dmzt3{i%H`J;o78q((rj~c=QxnwcEfyGRRiW05g{kkVwNNZD)T#$q58s8x+xQ?};suGU+zz)-9D|5#VdZ_ebwP^$*Dmdu`-Oj~)x0z<8uu>6A7W&XQ` zlb`(D(>|6Phy{jPwWt;2Y|PMVjS>qCwQ75`dfC<%vA|HPjz>$a`(lBiR$W-``)w+D z&->cfw!(jRW(bB_^{ADwTcR*(+^u48c&VrM1j6k!h)wL@Y4WY6Z)^W;4G-x6!r=hy{jPt*JF(_mcB! zH5LmDwc5Zk$IGl?`}Jw@me|%%vA|HPEw%FeUeQynwPJyxRy*4=)0p3($1Sz4hy{jP z?WuL<@#XGn{SgZcwK`BM^3eYtsFm`UbG*P%t0T1v7QAsLC^wYIUYo&l+QQsI^cmFx2Wot*deV9Z>6(SYW8tm0Gj1&pfQwXR*Lgs~fD~kLBBT zZzK$KW(bB_-KkY`dDHr81&9TPT0QK#g0=>J*X)jMbruT@wR%#^XGXzRY6bm5lKD@0 zfuU9}YnlJwd^XEn+d3r{7;5#l79Pt%Ew#Rh1%_IEXk9G|d{}kVwvzmI{)J$u)t6e& z!jws=R&lYwP^+J{%(`-Yzi@VkZM6^!47K`O%dE>BFSRC$1%_G!V41yPtO7kA-cxI* zSYW6%kXpWzI>%S*u~=ZJHHcc1QfHl|R^&g<48c%qFtu8)98*%QTw;Nt){y_vY9tmI zY7M1U^TT2J7R&M)<|mYnl<*AT3^KiL#=UUQO$(Rz0!6P-`5l;LppkY%A#3>2MUmP-{H3BJMi1TCHhf zfuYs}YMIwq8#R5aE$<#8h&#M*d zpEC_G)SBY4u2lAC0a?WYL#?UQGV4;SlvrS>H4T=#=gsdSMzHH@AQl*EO{bRm>Z{%M&B#v5B!~#RDWw6}Gm%0BcWLvw% z0z<9k)H0uArq&y=z)))iEO&+luDy@Z!2TV&gdv<6f}z$*YPG)IaF$wG!~#RDRj}NB zn0?u~77cByxL9DQwVGPy@6oH(KrArST4P&g@=2F9=%7{)vA|GkEw%2ai1|*f$zp+_ z);d`3eTw;e^lGgW3kdkn8LHJuEHKpCX4hqA zSSw@pUQO%_$BPAqTHC3WwM64fYONLv47GOHmYHGkA2VXAbxbTU)Y?g{SVR7_QR}f- zV5qeVmOI0HYjU(!%PW*~l)+GIH?Y$Jz{~O)yXE~0_=G{P%JRiI!rCIF12EYc8)R_Y8`>)KBt&#w%T@GX~hCVt)tX3*KBH) z6$=ctj=^%z^X8hZj%~FS3kE%R75*KCb#YlB!|sCCj>=22;` z+0;5G78q)sg5~ZFbIlgU9O{GS_Ts#SQDs z5Dc|0STYHh@H%Dv1S#TDPgSCSdSMwOWe>hFW**x=d@ttku=j z8Y&hTYTc#Q_X3SSsWo3LFx0wdTR|x=GsBN|hC9UqL#_MNGBZ@`idbN%^#E4z8LIV8 zEHKo1NG&r%wIYOf_68VgJ+kX^XQ)<6vA|I4F}2JL)hZ$u7-|JQFy!|F%nW}v%NOUf zond{kz)_Ur4Qp8W|XML!(Nh~nbdSTaPW?1f6 zxXo%^5DN^oUQ#Q~tUJZj`XCkov6=#JuaRR%WrlQ0omW zcZTMg?W>((MX|t8E9j&tfBnZy!@Op$R!6bGQ0pBm_k3us+1}dLM6tk7>piv1-$PVu zgIHjw^?}x9euntYw$6zKhFTw~l{I(2ZfboK3kj$;W@k(Y}@5BN_t)J8~$4jk0!H<_(sl)<9tw3s-w};)lDog)QSPiea~%) z7GEE$HC`+*)QU;1#1&_CQEQc0V5k+#uFFh5ZMm80)H*5_7;43))}%3Q4yg4&EHKoH zL+gtC^==Zi0>uJDEgx!CUevpuT5+N|#|sR#;{K0yWf2Puwc=5$F4Ho5{-JFx5ep2p5>e}HsW*Ss zIw}?zYWZ5rw7&JtxbvxPJrxTKwGvy)tm{P1?4Q)~j_w>UFx2vcY2=S_#Dh zL#-s#+J1Uy8@2L?1%_HlVFi7|{c`dV5sG9Epuiw_e5%S5ep2p3cw2bhA;D6 z8OgR5iUo#R1*!FRTGw}K-4F{5wF+6w#LV9sTWsI!7$uG~4KUOyY%Q~{ddn7kQ!Bq% zV5n6DR`ByiG`p^rVu7JnQEJ8Oesi5#6U72UtzsUn*tWGpEHKn6PA&60bZR{l3k{L#;B@s$AVFi7|m)Y}6ZR?m=V5n7& zS`jA{IHA@{vA|HPytPcs%y6Y`MU3klFEG@qU@bF4^Lmt88N~uat%|VR8Gc;UrsZ1O zswfs1YE`0El|<{ls?}L6Fx09H%YA&A*I?t?=ai{pfuU9vYMH-9tJYSrz)-8IM=PFf zT@ecmwW@iv)cPhC7;06A74!{Xk2+^wxXjMbC!TY>z)-6OwQ|KQzgMkXVu7JnO=_8a zxWcxoiv@;SwWt+kca)H7brTB=wQ5_-EX?e~Rkk%%EHKonV=edGtJYSrz)-6$EO#G{ z3H%*$oo!ta3k4*o#O?DS`DaGXv*;-YUL0M47D1< z@(Y@uxyJ76z2nCs+o~=W7-}`5*7S30%BVF^EHKn+3@hjxzRcbzY+pZIEfyGRHKEp` zKgSZObyX}d)N1O{Dr8%K#R5aEX4HE7qGf5dQYCOE4~AO*!E*0Y^47?^yNGR75DN^o znp3OT`ewh?YA+TTYPEpn7c@b$d*f8~Z>ZKdvA|HPCAA)0`94ss^S!%@MRuf#ck`RSYW8tnOf#O6>5b}y%hvsMX7(71v&4zZMG&wR%&_T+gc&%hx$xV5rr{TIP5a`BrCMD*Imj z{9=KjR$ptG<7L*RRxPo>P^+J{+*WGa>M9l(YW264X>F|#IhI)*x7BADVw*aW&qvA|Gk1hpot3|C66uzt=A!BA@?wF=EydQGitVu7L7C|KrrnZ5Bop!qys zyEht$1%_IqsrBYk)VgYo77Glu#@LqG8xNj-->%j+vA|GkEVX7OU0+zO$6|q@);L&Y z<#@gPygr>;(ULeb1VgRy)T%rETN1Sjhy{jP6JP~>!`|q2;>QoQ+K2^)S`(@D$@_X- zwPuM0hFX)T<(0eUQ?*Wr1%_IasrBET^HbIOCKecKO@Za^jd>B4XH9JPM)IW248c%q zDz$b!nb=sZ%3^_`)->BPdt=+>mLt{bFBTYTO{doSY`x9g zU9rGWYbLcC?|;}vt;oroX@H^DELcI`us4d{T>DThf3d(&Yc{n8hikM@t+rx;q1GH~ zRgZG)wpw$=0z<92)ao}UaJX7$#R5aEd9d8QVa^)~?cVq!78q*Hr`Gd0H>;?XF1a&9 zFw|NAtD?*>(~Fyn)v75L7-}t~)~cyjYpXRvEHKns1S{wpj#tFr<6fz?Lo6`VT1>60 z(Ym!&>xEcgsI>%E@aw32_Sz%TsC(YFwEfyGRt$^kJtgWnn{R?Vs5(^BqR#I!$pXx=_x-AwMYOR8mS&rAm zt3S`F6)L4OLon1@O|898s-09TqgY_5wFXwuH|IR>;~l70O|igGYb~`h%sg~JtwCae zq1HNT4PL(ao?2_f0z<9!)Eabger&a_i3NsQ8({ebt;<{k931xbYZ$vXyiz$c1VgQj z)EZf4ePOjyi3NsQn_#)`-v|uXJ%w83!~#RD&D6Sdquo!nx{3vcT3cXcmg99LSB-jV z%@qp_wYE}g^~>*j)H)^>7;0^U74!{zqd?X?h17a478q)6r`A8e5JA7%?*0|vxT&4V zgQ3#R5aEozyx$&y@gwT{4YpTErC8(nBWtE#+MV5oJJTH|(heX3S# zvA|I47%X$WVZQo@2%G4ZZ4DO-47H9^Yx(aGTh&@C78q)spmmv_as0BaOJaec)=6ra zpWUbxCY>`wFw{B)%l*4%58}5kP|E)OuRLObq1I_?HNAUly;@Dh0z<7c)EZsj&(Hwd z8YdPQYMrH4jD|T%sI^rrFw{B+%ROG*x0IQZ+_r9u1%_JZskQq{NFTNSiUo#R7i`O% zH}>UA=Bt)pdS~)rsCAKA_m(DGtyVFyz)rlID@74Mt78q(hq*lic-`}YfJ)^TX zz)HK>LnH!YCW@-i4E`#{ceYC%@GR>wVqqc>?pGj)!HQ%7;3$M$+HA zsP&Rsfq%RCsP#=OFw}YlE9jfuhib*nx%V*SrM~1GXz7eAJiIsr2k`WWfuz!wSH3Tbdw_!)v6~J7;62374!|qE9|cDm(?03 z78q&;Qp-1glznQg7Yhuvep72>+3yw9x*--AYW<;B%S+RJ)$-2j%n%H<{=#yPSK{_R zqp6ivEHKpiN3HhLr?gkAidbN%dfq`QX2|R6BNiBHdBch%R@u`DMrv!RSYW6X z0+zeyFE*Yv<&xd==fna-t&r6EcxujQwZ4l5hFYPh)wOq_S7&W2aW-f2V5k+ET7~vy zOQKeQSYW6X29}wj`ARst((j$N)j=#U)CxF^>eZ^oAGK171%_IYV7dD+-;^5* z)hZ(v7-~hPR*bk^f2h?#EHKoHLM{K*yPm2wRV*;nib|~yKBeZWwM#58)QSeneXbl| z^Ua!bc5mDl3kx%+U?!F3O>*w$OIz)&j@wa!GIR#vUFxttk-p_Z?;%=vIi`yD6u+17tz zfuUAnYndxO^Ij3PrilfHT7IzHJ>NE8+s}|wUSb6c*a5_ z)Jm1xnFbhYC8O4nRX?hzRZ}c5)JjgR)!BdCP-~=EV5pUXTAQ04ZK~ETvA|F(B`o)` zoVw8ZS8BZ$3ku-+z$XZ*(0z<9B)H0tBpw>CDz)-6Qwanl0du?0K z#R5aEqSVSWXvIzJ>#c3I z6blTsN>a>v=C8yo`{=&90iv@;S<*bEkwzOZGsMTC7 zFw`m!%Y9ys7OP)BwdRTihFTS<^(4WW4{BW%3kY7;06b*6Uso zLaJ328mg7Furot2 z)T#^1-5Z^2KV7a?X|cdis~)xLydRNWtxjTrp;moroy;D=Tdi4QfuU9dYGvN|V3k^j z!~#RDhOpe{FLRE%WB0}@vA|HP5w+sg%Wzh$C`FtZf}vJpkJfG5$|4pRYBiyj`AiJ8 zs)+@LT1{cO*N3qxwC1MXf1ffuYuawq^F=^S`SzskL4#Fw|;J zt+g5Iy;19oSYW8t0+zcEJMD|TNv)S+fuUAQY8{<<`G{I!iaN&&47FO(y2`BU(ORu! zVu7JnYidn9Qmcbng~S3wtv3H-UG>BQL#?*ddOJMcM{V^I3kV zdh=(sLKSoN1{i8}f#tsTWj;G1l3kadSYW8tm0IRKOKO!A3kZvV5rs0qZQw_Vi$KN z4~AO3Jz8oN6blTs`cTWfAKsV5l_!mV2JxkmGmb6Sj3vEHKm>NUgPf)`e5+k62)+HOOOK$80M>3Fml$ zq1Iq(nV)~DRZuK2)EYwT3K@{RSYo?38jA&nT0^O|=z7+EYK;*K47G;YmU;eKIpO|28n4qjGkj96f(HRgY;Yr9xrs5O>a>F<{OsjWw1fuYtoSnl(e zInOt=dn0myGea=c8c(ffl@~u$E1Otgs5QY_=6u*|T8~qw?VhhG78q(xv=;6wgMJpE zRwuE*P-_w__uir6{sTU0jTQ?GwI)+*=*vE3)LJGM7-~(S*6;T*tEhEQEHKoXO0B5V zL)2C4j#yx*HSK@2zKaEhTGOeOfAyft+KN%iIm%$DHRFG@GKd9+S~IB?rOd`3+6oX0 z47Fzck5&`0z))*8wL(-0D6Or2Vu7L799Vuqd(iBtPeq<)RBNVKV5l{hTGd0OOQqIU zvA|Gk9xV49^=@b4&uU#13kq+=~5Z{SPoy>Im%$D zwUAo(FZkqFE3;T&sI>@|`}i6-GxRsLs*44NT8pW5`rY$oYV{Kf47HX}>*3tdYt>pN z78q(RrPlm%DT}LhPAo9gS_aF^(Cm!^p~`hq>zi0$sI{D0)ryR|ua<8aXYydEwE~vA zH##rx_*<39bwWf&$hFYtsb*OXI*lO()3kW6{V~*Lon1@2g}{_5#~gjR?_bIoMM5Y)_Q8aJv29s zTJ^;OL#++4+&#Z}^!UeW4HXLvwKh^~aKwO)YONCs47D~D0O|78q)6rq-%( zvuCU2RnD0q7;0^Sr zL#^%9dR*nsXSJ4y1%_HXsMY>q;uC6}6$=ctc2cY7gEa%x`X&|_YVD$ycj{9U)Jk05 znLHS3?WR^K|64WH3J?nnwf4Yr_x#1^qZ*X3d%mMsV5qg1S}7J3PN>#QvA|GkA1rsz zPkj4gzFG&w0z<9+)Oxq0acs3-iUo#R2Vj}^rI>T?um2VuQ!7RVXNF*?b&y&&0%y%p zE1y_ksC5XIyAMND&ap7PH%i;R5w4;$Lon1jPA#)H)XE|j7;2q>6?|`~RZA=|)H+Emvp3Wl zEEX7Qoq`p7Z>Y6aEHKnMO)axG)VeMf7;2q?6?|`~k=&YciZ0|>hn&mJ7R&M)@5ovy`8L%THnP2L#-=zUFN*eGt~WfYQ?DR94|1`x=O8w z?f-33D}z{IsC5mN`}kUSef+$__VE=U78q(>r&j(yZ7!Ax)Vfct*LxdIQ){hQV5s!~ zmb*8+v$X47(C&?^Vu7L7LuyqI7&J>Qud2=r!BFcFEO&1t`jEGnT4}`sL#@Zun$kE* zO|`0v1%_HrV7bR@*P^S*)EXof7-~JG*4OCiTB@~9EHKo11}pds3)mUn5(^Bqo>R-r zP%ZCj&J4j&>jkXfGgK>;SYW92l3HelYE=*m47Fat3O+-%x{C#dTCb^PW~kPDvA|I4 z4J>zt7xMZf^|v!TE*2PSy`|Q%o0oE`^m#+kKCjwGt%+iRq1Go@W`^c`7*Kk9Ikk3)1%_Im zsa2vzQO0BeFfuYuKSni%*alGw7wJM1PhFX89)h1ivA!_v!3k@-V5sE{%l-YY zZ?V=DRm-=QGkGx73PG)tzJD95RZ=W4)Cx(hLO;3(n_&mBz)&j`tl)d2klhl`mI)QSVkeSDeg4Yg8=1%_Ha)H2r_YLyoY47K7?D|d^YL)7Xf z78q*9qn5eeP-~u8V5k)zmV3RiYF)uHY8?{`47Czat9XtyCDnQ-78q(JgylY#&Gm*_ zaq2mf2Scqy)G|MJP^*AgV5sFwEpxr0)_-Dwp;lsQnV&nTHBKxr)bgX2x!zD~n^<6| zm4sU6=MHM!6AKKrlEQL-hb}^rf>A5mJs+mNGea=cN=B{LAE*3OD~niQsFmEKRmryM zhy{jPDLh(g4H63swNk=zAIq6vmX1@=wpNG*hFYnpWnSM<>w;KdsFfO)`&c%wZ>aTM zEHKncLoM_AhFX3NoXLZsR$99*b3Q!vU&_8}l@bdKwbD_mZpD)M)aoP_7;2@5l3~1%_HVs8wz8qk(FLZ{*An47GB?a`%Ss%{?F0$|@EZYUSeAs`XxK z)e#E}wQ^I-Tt}%jL@Y4W%0sQ`UabqMwN@-J)XEDh_}-{u_r^7`z)&k6wang7>z`O) zsFfd9@V%i{s>aUb!BESeT4rykRY@!`)G7cg_});fw^(4PRghX{Z>Y6YEHKn61S|O7 zQ0u%{V5n7?TS0q6t)F6np;i%UnZ2P_vL?<9!BDFxwang7tDIP1s8tM>*&F6->zoJ4 zuGwqs?qY$VR&i?mA7A$XWmnd2eY|2D9jD@SY^P$|wry8z+eXJp$41AtZJQnEJ!|e~ zt*7SbG2S!A&G^21=db@~@3Rl8Qc2E+n*LhV5>ePttN4Ffmt5W2J z3L9!wpjMR21^-qRrkQuR}?nXs_B$Dhvx5s+v{52MPWm&T27fq`H#oRPOD1R z+`Bfgp;m1udmR?JRp1|0rA1*wtvb}&|E*GNRb513L#?{hdNcOr5LI(TVMDEY)Y`Rr z`$koVL}5d%`v0f(S`;?aYCx^#ZI@=z)*mgrbBGPK8bX=Z4Rf1ZxbyEl?(r%p3L9!Q zqSlGfgW9U9Ckh*CHKya5pMPFsRlP)EL#-y%ikvoGTvgLWVMDE^PMPC6J?h~6ZSJ@> zi^7Il&73mV;hs-N_NqE33L9!Qr{k*fDE(qpFGXQPtrpaZ*WqwhRpDBCj~6!7Y6)dO z+vKfuyNs%oqOhS>D{8eoS-G*QBBHRNR%fEts>h_omACV z6gJdq>sr2)U!ivwGp~1#*DO)kP^%raMtqLnL)B(c*ifrIlzrX!el^);MpM_Md6on172Dp|vhiR@CO|Ze8!^5Jmq1HfZ znLi7o>aHkks5J=6erC)1EYzU=uJu(EHq;tSt>N{C2U8WJjdyKeL#-iD_BCpHlSm0v zr4xk>wT4nFM7Q&`RFx2g4Yh_*D{t1@HB~hhg$=caQ|oK1j8Rne6@?A8MnKtfXg-UM zbLVh|C~T-Tl3Is9q^zdus3>fxHHwa_Uho4KRsAap8)}WF)~pfoBP-_ge z-c^n|K~*hL*idUMwJOfN+EvvkQP@yxoNJkDeoU0&PY$_rxKk81)EZB%dhbhSR&`$# zHq@HnlxdlN=kb_pg>C1Z4Q!}2(JAw4vnk2oL#k4U!iHLtpzQaf8kK7Jc&BR>5`_)5 zCR3|Qsp45wwG@R7wWdJX=hugXdvmB7Ckh*CO{G?wt}QC7+9C=YYE6T(pV_{?`t(cH zZBf`zYdW>gj?0!*Rp|EKna74&Gob8i@9=qL&^tYR#tBj6betR<%?VHq@E}*4HPK&~ZT63v&ElYu`sy>Ut zhFbHW?6uLLT-(m75_Ry-JT}ytPpyLS_w-R!Tog9cS^#Cg&u0Ek_@3^XZ!ZcPYAvMJ z(7ubGtC}VX8)_|b$K^YPe&*j%?d4j#MPWm&#nc)Q*rKqiN20Ky))FZDS#<9HhIux* zR>Y3pImCuqe^KjvweWXUWfX-CwU$z=)P_SV4!c$*QP@yx8MXd=S}BIAPNJ}()^cin zojT&*5w0~s6gJdaL9J-Zo+eavNfb8JS_x%8V_)oAGtF?zy@KF;(M4VMDDo)Y=f`c0*OiMPWm&wNUmoDxv?0EUH3x_Kpi1YW+>E z5}CedS5;UPHq=@NmC0Q2zFVxV?YoY0=dhnBY^b%KS_MvBub^tDC~T;;0m|RkF|SeA zo0L1O>R(aVP-`Q#%AXsaSXK5e-r2y0TAQHq`8wv7DUE-Q(eAjqh{A?io2m8Bv|US7 ztrLX}wYEUn*TY4TM)p(nQWQ4S+DffVrAJ&)m8PqAT-Z=+8|1#KsgdruT8hGk zTHC2LJ6QXssuqdDhFUwI>}S!5f481D%(ZTa!iHKqskQU=zg<;D?&cjAHq_b$WnT|# zM?PMDoof{og$=cKQ)@xwtI<@o6NL@6_CWdL%JB2c-=oigF|IXJ6gJe_ORd(;FRoT~ zP82rO`UlE9m(A_c@9T+&x>nfk-r2y0TKlM#dwIb~$D-Mbb{H8i~S& zS_i1reQm%4YiI?t8D*5-Bpzkg$=ciQmb3R7co_J6NL@6j!`R3;WtrKEf$3hwT?sC*ZBog zW1mrVP82rOIzg@Idve`T^;;A+)H+G6z%U8Bs!HF}JBQd%>lC#@wd>-is*WgZsCC*Y zbIq4cnEdzO?wTJd3L9#jamu_qyxKKztg3aQu%XsjD0|I6?Xqx)s>`CVq1HKS-OT!A zt*T$5u%Xs@DEoEF>|8Z#sY=<)JBQd%>jJfY@7@?hl^2B#wJthk&SAF}Luw3k=dimd zY^Zg~DRU0Z-+Q2Hz9?*{b=e)4X?<;7bI}mjIwA@iYF(jLktLmOs(LF58){vJvhQE- zia%>J$hG41_Rb+T)VfBkb>)xkQWYQy8){v5$7O!cw@|0oAqKlv6H(Yu>jt&_M|ZlS zYPcwDsC5&{UWeIIWSFmNr6_Eub&Fbywih^}>WnCCsC664zHXdsl(N05kD{=l)*Wi? zE*^KEsOW5)*VsUQ0tLXc#ZP?9Sf>L272cZ z8)`j6RCI75b zHA@sW)Ot?G^=fX?sjB`Fg$=b{Q0r&6_dQiT7KIJ9UjCm}#J=8{$A((3sFmdM%Ocv! zA_^O7y@oQ+WplfFsYuVU?%Jp+3L9#@p;qVfe@#%;QxrDTdP}W$i`uq2;#$*1VMDEV z)VeWsMM_nhMPWm&_fY2AFwd{eUCIPZb*=NFu%XrmYK`2`=#Z+2{k$`e4YfW}>)ZF5 z!TY;bF;Uo1>l3xi&(EuBAqpF6eTK5nueRl;L{&9H6gJfQms*SZr>>}Kl_+ee^@Unx z{yxw})oD@KQ0ptTniU9NM%6n}*ih>mlzlFjpW6SKs+j$~Gmj0mzEkT_w({{+%T~E~8biC3L9!gqE@vrYfh;0 zALN}wY^W6(%D#VHsBkgEX?G6Gio%9kQK*G~lgp_-qOhS>R4986+cs{oNn0yKVMDEG z)CwDVPL}5d%=ur0c5dS8ZyNBThduIb1YQ><|)KME7Xe+lUY^W8Jj%)PzkX==^ z5`_)5Vo__-sSH_F%@l+9D!rpj-KcQ&x0Rvf6H z&*cHGl|vLZ)QU?j^ZZiPLlidDiU(!>z7%u2*Wyy0Q?9jD6gJd~Ppy4lvUF4RP82rO zN&sbFH_YGPd(ySi4E4?iHq=T;twt%%4pvo16gJdKM6II}<77DFTBAi_L#@QrGJl>( z)pk+XP|F|6e$S!Ax1zVMDEyQ1*4h{COf(e#5=9 zfep1%QR}|nmZqvQio%9ksa?xl^X58S?XHdbqOhUXpVTtnb5J!}6gJdK17*&k`8
    +&|6U2Cf-Y^ar%T7j)rO;&Y96gJdK=UV2t`Uek_aJOrH7KIJ9(o@U)edekXj_}Sr zHq^=hW&fS58I^0US>swoL}5d%jMVD*BY7TGZAD>2txQnJq3tc@^3)pk+XP%8_Rz2+BO@!PBFmMCnfm6cl68=lRfD#S?d9AZPQY*6-^&swx@ z5>ZtrB0?mebY~QP@x`50rhcG=DzjvAZ@Rjq=VsHq^>Xt(qUk%v6<46gJe#2W4L8 z&2{+U`;D&8U8}YzY^ar=S_j_W|EX%KC~T+|0A;Vk`O``zR&_=cHqXj{ps==bLp;lpcT)tE2w{lySQP12t+$#zj zY89bYhD`l0s(L628)_AWve$if{yt%@!^$NJnI@`=J=S}?u%T8t zYOR|#c_@3$moL(*iK>dCu%T83YHjPh_Nc0MqOhS>MLMphT^?LgHA)mV z)T%_S@F|83R<%qNHq@&8e~#;*C~T-zg<2(hHm|I$d!n$RR#hnTb)~tPpZi+ru8m)! zu%T8pY8`p7$zN5xao(eh4YjI6+3Rrqyk6a3xK?&i*ifqmwalN%QdLJ3Hq@%=j>}w! zxAs&mt7?EKY^YU>TED7X@>8`;6gJeV4P~#x?-9H9P<2`qHq@#^E%W!!tNJ7g8*0_1 zS`;?aYCtXj zg+n)~8Y2oDYBhwi@0Ix)-VLd0jVNrW)reXl3xBDl>Z~YisMQ$CK3*rwoR6gHgD7mM z)r4Bp>b={cD)t2L%wt2XrgU7N?^o`pDz_+XsMU;G{oXu^rmC(eY^c>7%6_&fw13{L zneOrGFA5uKwV+m)rw4|qnj;DuYPE#2-;e6Id2w=8+eBeQtya{^bUMriRhLC!L#@_O z_VJn@d`baTA4Oq9tv1veHow~)RnaGUj~6!7YD>q}^lt1KsxpbfhFa~Ym2g$+D5}bf z!iHMy|Icx?6@?A8I#6rDj$fg)HA)mV)avMz@2QN>HZ$C{v0M~3)avAvc@@nX81kU1 zBciaOR%a-C9d1hWabhs{XWJi%!iHL1sP#DA-eRhvO!6KtY^c>0%3g=N_a)DwDwim1 zsMU>H%>yG&RnCHqOhUXU}~A4`%+a?6gJcv z0%fj4b2Hy(Tk2ZfL}5d%q0}n+ce5X=rij9ZTEqU+TH#t7L}5d%;nX^CHTFDJ=R{#c ztr65(dh&3^r0(&0BMKX8jigqW{W%}0N;lPel(C`KC@6c)|BQ9AkE)iUu%XsyYJGdO zX_~5~qOhUX7Q}y1W>w2YVMDEX?zqfzIZl!&vs671g$=dlQ!90YtbwXh&hm~68)_|p3i@3B)1AX+ zqOhUXLTUx(FH%+2LQ&XIYmqxH^LPcDKQ>e<*SaYR8)_}4mU%9#iay&rE^Mf^1j^sn zG3T)M;JO`El@Nsuwf>@3>ERo~s_G{S8)_|e$7NdPnpd@16gJdaMy)>|-V9LnQWQ4S zTJBoDl;6eNE$gIk=P=nE?`&X0trgVjTjkVHRSiU8L#>ri{=SYmu1wR?l~XlK6gJda zMXgAyk5pB4MHDvFTJ4U@v?gw!l}}a7x!!SML#;K`ns|2XGgXyDVMDF8Q1)|F$pfc` zrgZ0UoG5Il^*6VCfA4{+qoS~();iZR$F=^~t_`Y!&GU{68)~hmR{Wpe5~<233L9!| zfU>Xi=I=dF)k73E)Y?d`s|BV~sgeiv^JY@6Jj!&joPq1I+<-5Qs% zi>f5^y|aN0wYIpHIfpqH7H_4hswixzwUt_{ZiZ~EYNRM^sI`q+&n~<>plXjOY^b%J zT4e$P_o@0I3L9$efU=KQi5yjKs7k%SI~&+gYbUjmeA*RJRXtJIP-_>pGB@pcT-78| z*idUXwdxOCK3mlhQP@yxk87E0V``+3M-sbh*rmFBl?`&X0t$(2W zeI0Xc#JagHi>l$Gu%XsIYJKmMVvDNNqOhUXes^4^bw6XVM56gJd43}wHUvUth0SgO)2 z_Kpi1Y8|20odpFesOlgJ8)_Yeve*2GS*xn4+9V1aY8|82x^QpftNJPm8)_YQEprad z*A9u?ISg3h9Tzs#Izg?{G28rB6(|ZDYMq3#pAVyL&C*lVc2U?+>lC$8O&U2s)fZ9N zQ0p|5{n}wuz8kMp<^0P#E^MfEhFY0RB)OofyC`g^br#A#UMG6q&aG;*C~T;8j#|ZP z?N6@iqbO{sb)H&Ff8{H#D(h13xUiwt1!{FUP;R8E&Z4lP)dwaoX3RJ|634Ye*q`TIKNS=nLr$a$*LEc1>F8){vl*5zX3cd2SA3L9!&b;o5| z-%}2VscNYxY^ZgOTJ<-SI-u&IC~T;89V+P84zb-iOuF1VE^MfEgIaOQ?cJuTo+xan zb<-V}@38zXG}x6krfW?Xg$=cCQ7c&capzQ>6on17ZbRAU^0xdB|5W9-!aFW(sC9>0 zFSEq+QfSws;ww&sCAE8ZQJ#ar)rTXY^Ze~%08FZ&Mg zsP%waGs^thq$=`C?`&X0t%uZlHRM`LRYgT%L#;>D+S=jtI90txVMDFQu4S$b^IVSa zu8nn~u%XryYMJMaahFZ_4_2EpO1FBk!!iHMU z-ErCHvZ@uLu%XrqYGum)A(E=6qOhUXOQ@jFCepTVtc*lhewcb&y=GS1& zR23A34Yl4w+2`_uq*Z&W>LCgnYJH$q>Dmvwt6D1x8)|)ovd`sBF{npV$r0?@e)lX5_Q0p6%zprDSU-`=K8>}kV-`?54hFagLm9apY?y9=hVMDFo)M~K0V?R~R zMPWlNKi}mZBAB`6&CPrt;1AcDFA5uK84x0v{qtXc-Aq|u)df-5P%Ai;{W>M_?Y*N^ zgLBia@P^1dFPw%CpfsE^Me3(J5aFUoXdS=Ww7XY^W8< zDRU1WRB2I4)ge*XP%AQ&y$+KPFT74w*iGI&#D-c?sMTw3n`f%ZiNc0jQK9U07-f5= zx2h(I!iHMWsCE0r)=8?ah{A?i(Ot`&L-QFsnmdOHHhaf~4YguWD{JbPAym~Cg$=c0 zLfQA_>c^7|P&Hi?Hq?qmt(0}A6<2jx6gJd~4dwd<*ZjA3OFO8FwZ%IwY^e1IwF<>q z_?N1xqOhS>94PyE9pAF=x2nmau%T95YL#ku;JB*uqOhS>JZjz9zjKGGXj{GG!iHM$ zskJ)v+kvVoio%9k37~wx;8rl@=bT~PwJ}~4Hq=T;tqF&=wNZ6a6gJdK(;$dHA@sW)Jo%8<~m#*&@Z>D)1t7UR$6NPNH_9{s*pRq7eX6 z>{I(mbyaypVMDF-)M}bH<`-2RMPWm&4DPthNi^p$vO9-MMPWm&jMOsEWmOMFVMDD< zu4T?)=<#vts!FoUI~&+gD>Jp;t@Y2Os-Y-ssFelEoWtyy!+j8t`7 z6gJe#=8nspL-SmY;?7~h-QICwL#^!8GS6jIwM1bH%I8|Nf0C zVO1YRVMDFrQ1vWcq$q5tRfSsS zXH!*0Kj00I_PMkS(X=ry2yNJSuTD7PZ;o#*cs^bbx z_SAJ%-$Y?Utvb}|yms$9RRs=v$At~G>bm1H?_Wh$w8RRgYS8UyRzX>X;~O zs8t`z_X}=mT8CN{(w)P|N4$H84Ye9jYr*1Ql~t7$g$=bDx|TVvJr6n;Ry9%-Hq>fF zt>lwd)l+p;6gJdqOszkI=i8<#%u(;Su%T8HYE3RQ;)SZ>qOhS>Qz(1QAMN?$p{k*x zu%T8nYF+)(ytJx=qOhS>b83|>wIawp3~|gmE^MgPf?9pbPU@ho!lJODR!gYVzQ@Y^ z*}$wTcUPI>epY{=C~TGr-+5O|q%_ zC<+^D4W!oS<#m3m`s0*$=CPsHASipymz#fOsj57pu%XsqYK>32_k*f>qOhUX5IU}K zB_7UDH9!JW}(zIEso{7SSS|i+X z`7RB=g-uIr&E&4bh^M_Xj}5g(QY+wA$vmnui^7IlqugYaF#&O{$oqsB2vig$=dF zQ)_wO)(cd97KIJ9CP10jL-Tnf?(S(na=BKVGv4Ec4Yejx%dhIwBdYR?!iHLt+;N%L zjnhqTr&HBP6gJeFOs%A;ZyiuITog9cngV5?%P;rr?WbyuC~T-Tm0EjW$GxlSf+%dL zHO(ED@38zbbw0f>w>yVlMPWm&>D2NYe%@bI^t0ZX$A(%npzP~>v`r2A7j~^QqOhUX zOlp0LTzZJA(xR}T)+{LBFL<3FUcX5~Rjou}L#^4=+PCgj995%4VMDDsQ1*2`#E2AO zRIL()4YlS{%RgtBZmLd-!iHM&pzO7gzV@hvs$Pl0hFbHf)iqVh7pfwk^Bym3sI`Dv zu^%SPuPUP`Y^b%6T8FpJpQWmzC~T;;2+Cd?=5udpcWrbMg$=b9Q|rK(U$sKLjRZ-YbYbBJw?+lvP-h8J{Ju2YN zVK-6OP-_*nrd)izMb&gs*idV=Q|19XvAcY};;yw#6gJdavg{(Z2QqMUz{!=1xQqOhUXMrvK^UE#i}R-&+>)+Q+PdT6eVO6}t{%;#DI zL}5d%&D5ILZ%a#6Geu!Ttu0X5d>!+69cvR~j;i&du%XsgYDH?8r>UwFqOhUXHYode zb)ItXoT^8nu%Xs=YCZV*F@vh#qOhUX4ybg#V=}irB^u|*>&{`^i{2H54YhVsE8>~` z8C7Kwg$=cKIb~XzUe#Y6;98|cVMDFmPT~1g;N2HhEkt2Mtvyh=d>x~D6?_v$)nHNB zP-`!>e%>2qDEoNjzqGWFs=cDHq1HZX1y=poLDg+h*idUfl)2{3&HSBd z`Q17EDGD2E9iY~jC*@YE`s0%KC}TsdgHD;2`8x?qx>hDp*ih?`Q|8PcUUqtts*0kp zq1It2^ZsRS?QRT@P{Or3h{A?iN2pc0b&oo#CW*p^T1TPmIjq|Au76I~+9V1aY8|6i zV37uIRh<-t4YiI#`F_E5*eKT3+NvIi!iHKWsP#DQ{Vl3~h{A?iC!y?hIAKNDQmSHI z_8w(ysC9~3+5TSGQ&k30*ih>PhY#o)?7;wJuR>wd9CWHC~T;8hgxxt^ggUA^i}Wi!iHLRp@P2lPH@*oa#7e&>mIe{=Q(*@RRK}h zQ0qRmI`40sX1r_F5`_)59#HGnk{eM~brFRPwH`wGe!Vd%Uor)>CSkzn8eOYXykHhFZ_4 zwYk~X9;&K|!iHMUq0BXJZsz-k)m*EMC~Tq$w6gJd)>6B@i&l}ZUYlbLn zsP)Pz^9oQtRQ{x@Hi*K8TCbsezuEltKN2ZtsSDUq1GpAeY$bHx~j{fu%XsxsG!$j71w$v3L9$uORekQ zQ~j$d$_?+#V?(Vk|7q25t#qQWq1IPwnSXO!RcTS!Q0p6%eZ0);MswF{AqpF6eW#ZB zbEB&Ih{A?iKmOAi>ssSPVMDE-|7odOED9TH{i2q+4r{vBR#Dhc>o>K`=R;K&MPWlN zzgWI^|6ukUn(yfiajmzau%T8kDEsHXVlS!{s4Cn|@7lnITEU@wcN4dP8)By$;95yU zVMDDD)H44jm#QM7u%T8+*D|jFqZ3~rs;a3dY^W8ATA`z-J)vs2C~T+|8p?jQ39R&? zyQ-CSSb5=nQLQ^JBM#YVMDEO)H46(f~t_WyvGY0YK8w# zYou%aAqpF6MWEJ!rQ!3a$}b8VYDIL)TpZ^8Yp82A7KIJ9A~|IqW%KX(s+u7R8)`*{ zvag4=x^Egb+_g@L!iHK=s5Pi=krk@GiNc0jQK@A<12l83l()Szj}5h=Q7iYLO}A8) z6@?A8qC?rQ%>!EpTpZzAokU?ntr*m*kuqW#RdYpQL#>#uWzKwtvIBFfIw}eqYQ>_~ zh>xLztNJ7g8*0Udvd^!bC+oadmGq8x4zZ!uAJjT?eE)S-6+~e}tvFEjHEMjMN!81^ za~LQJ8*0U+mbvCttrdk0wc3=dNAR{zpAQ=!iHLjpzPPMNhXxdrz%hsHq=T?twJAz7ge=H z6gJfIr{fxw_UJcNCq-dHtt8YsnR$6zRUbuRL#?Dx_BvdXsM=3e3GR7k9vf;Uqt=Gu zpXRG7DheBFC8t)D-gC;UYAXsGYNeo7?N}ijsG1@Q8)~JbR>5Iy4yxKE3L9#rqSm}I zF-E9*C<+^DrG~QC{JM?5;#Y9je8l_SImCuqe^Sd_^Qy9n!iHLDpv-gGT=RKrb-bsl zmMCnfm6lrOnpZVY6gJdK2jwrVa97v&Qnf-9Hq=T_t^9LWTv2sS6gJe#0A;U3b8V>l zDheBFWu#Vwr}qb`O7g%v^Vm=;6Sd5>p{kT9Y^ar)TEku^-l?jSC~T;e1Vtq#`%f2)f5(0jbFp;j&^du{ZpnDe%(jH0li zR&HuV9{BHKRi#B?L#;e?T(9cSy`!p`C~T;ems&TgEM2Q=fGBLJl@H2Z8>hy%Sli4! zUb97EL#_POij#G50#$oOVMDC|YMJYBpt}z5i^7Il1*m1du2l6+6gJc<2xY&2xVP%K zhOOLjMSJ8u%Ggk=5Vg8}D0V?rCQ;Z>t1y)PeAsk&K*3?|xXO#dhFV3aW&S=rRn0_U zL#?7v{=Vzo+^&9Z6|Rjtu0Eo$p;j?!oh$UJuBzFhu%T9QDEm4;ds+Dqs&VMDF5)XKkV$0Jn(L}5d%a@0!O@Iz8n3q@f=t@5sAu8qLn z2RgKM*T#NP*ifqiwfy=eSfc8hC~T-z5z787@ywpzL#uit3L9!wqE@-l3;L-F^Td0+ zu%T9EDD(U>*T(DD!E>ofED9THRiRe0+l^MK$|(vPYE^}@*T%v|{~l3QK@>LBsz$9) zowA-&)j||D)T&Ocms83lRMlS;Hq@#?tvvJEwNW))6gJeV31wgB&G$E&yKCcbQP@zc z7PabK-BnrDaZ%V%t2UH_p9!pX@ zduaRFCfZZ)io%9k^{Dl9`uZR$nJ8?iRUazoIqd3=E1M{6sMUa4HLvyjrmB!AY^c@H zDf3)5-?!=PTIEDxL#;+mnPS zL}5d%mQeO}WAUYkV^wVzg$=b@Q7guqszKBdQP@zcwNv)mDD1BJOQNu$RvV|xwbA-s z=rOA9i^7IlZJ~l*^Z8xtwJ2<;)s9;JcVGT+?vWvooS{qhRFSvQn$$5mDoHq`1wt)YDvKUdXB6gJfA{Ga10?pjktVMDDh z)T&UZ!~|8#MPWm&uK#HjbFCesu%T8rYUN&DaF41pqOhS>_y4rAxz+uikQ*uAIB7ljSA#!}1t`{t_li^7Il zA zq9|;rH3`aow%Oh=NjgJ?J8OB6QLno6zd zr_z>FbypNN)SBjw%Um1g_Yj-7Ya`?<@62OEt?ASvX`7EvmMQ!iHM&pzJxU*t^x^rtTb`7ljSA=2Of39=)nJqOhUX z0w{Y9|NQx2ys8MVy=wy-YAvKzw@t%usQObBHq=@KWzXTJxHtS&l@NsuwH8xrd$e^S zR5cTY4YiiImbvC!Prs z)-q}>k6CZMsxWW7Gmj0mmQyR@zD-+IWfO%BwN_AT$;U@CR5cQX4YgK6+3Rpfi2H$E z-8md53L9#zqL%r28&wNLVMDFeQ1u+ksim;%Ts^_Axq1HMm`#qw^U3L%7>plbg6on17)>CUmyDyhi#eC~s z8`w~515|3?^=^Josz$3)b2_`nD~%{@sI`$=(Uv_;sH%`CY^b#f%A7-UGw&$_+-K1m zqOhUXW@=^hf3;9mcTw0-Yl}NB(~6RB$dZ1pHANIQ)Y?j|gKHASQ?*$XHq_eYlxcOo zT`~Po*SaJM8)|KL%6!H)-#=9KNE9~I+ToOGt-5;bOMln;C<+^D?R3ht%%4$J75|-g zZD2#KT~OJ4!l>lW%WPFuNE9~I+D)zEKi92N)k+jL)Y=1OpI_$BsH&PM3L9$erB<=3 zYk#ZSE(#lJ{R5THcTDD*FVZB+h{5h0-V=olwf0f#eWMLqRDBkO4Yl?=oAnR@7|ev`156)`Kl_2!iHK$sP*sUT(wm-5`_)5jzZaMW8?CfRaA8mg$=ciQR~|L zp&e8W6@?A8jzgLEFLPXe8wV6oHC+@o)H*?}9yh9AQnf-9Hq<)lj?1JH?thoEnR}hz zDGD2EoubzLKN5adbxjmD)H)4iKeI(HeW-=1&!VuQ)){Ku8q;dAs#qVqs}~z;orSXJ z@O19ssZ?bXg$=dNQR~m9lh3QFA_^O7o&P_r&Z4lP)&*+iTvl?VwkC?ghFTY)%x5<9 zx-ov#!nrNn{E4K6gJel?2gM^8^0bmY|`AdK8V7GT34vmeR}*+ zs-k}M9xrUDb(LBj0#1c$?ON$XVMDEJ)Ec>=(IHhOMPWm&>#k*n61V(_hG{YOW}3sCA24O%B$Np=yUHY^Ze`%DzU``*}OOsw<+f zq1GL09WUDSyQ+_(u%XsnYBj5wBT!YePu`=94Ylr3>wC?-nN(#Eg$=dtyOy~Q6TBSx zvaP!|%80^-S`Vnz{lJHEs@jOchFTAy?AH#zZzilb#Jw+%5`_)59#Lz=%{MVstrUd~ zwH`y6_e%3zzR<7K=c4Yoj)}sCT2H9e^;oh)s_uxwhFVYEahYrWk8}a&RDBeM4Yi(8 z>-Lt->r_Sf>^;iZQ0qCh;z!C7T~$(1*ih>QwNhqDl~z@5QP@!HC6s+n8C7k~3{@3H zVMDD~)Vh5!OKDXtL}5d%*K}ML-+!*Es-GxqsP%?gxi9y>u4<|%Y^e1X%08E~1T_1g zYPBeAsP&Fo2mVbSYXTTsP&OrS?b;o zrz-5f-W7!nwLVcRYQnV(RV5aM4YfW~YeurJfvR$d!iHM^QtRV@cVktR6NL@6zCf9; zVa@X^T*AFaR5cZa4Yj^fEA7$8{Z$2u!iHMkpzQZ;G97u6P}LMs*ih>`wF>=CQA^co zQP@!H2bBFBb!+XIRjLk(!iHKusdXUH<>#tyio%9kzo6_j&yUwfQP@!HH?`(1oR~*j z5x;m>6gJfIi|u=)+@Jp%+$8d@mhQDTxhQO?6%5M$`LE5HqpeewM-(>H3JzsoqyC*a zXoso_qOhS>2x^6h7q_OW=Ay8nR!AuOc;)=~psA|9qOhS>C~7shv9GAADWb5UR%mKf zE>nG>s#T(}p;j1bjoEPEj;j5lu%T91YAwy#Vu7k_qOhS>IBKO0$Pq);TT$3hD?F6F z4ja~-(p*)Tuih1f4YeXrD_zUL>#7oo!iHKAskJflw4bW7i^7Ilk*Jj;)A$*x%8J5< zT9K*s=56_Vs+x$xhFVdmm9KNGr>c63!iHK=q3rhox{UAIUDZTU*ib7PwN@run?cob zQP@x`IvrQ78^yz^+A9hhYQ>;d)YHd$sJbEw8*0UL%J(vlpZjX#UN_!|!iHM0oWiHC z4JX2>3h~XmqOhS>Y$$&d^4%&Y`y*~U*NQC)8*2SQt!WFA&QcX13L9$0aV_&%^h%%F zaay@nGf~)3D=xLdryuo8RXd}>_`$X-#^dQsR= zD*=>!J$!hzZdO$%L}5d%gw(1sZQ*<7cWueD@w@Y^ar(S_ijJ z8mTI=C~TCh?45au|Dn`<`snvwUSV4%&F}`R5el9P%9~vdH*uEIUmY(&gZU; z_M)(%Rx)Z8{kz!@Rbxb9L#^ac_H$IlAvc1nS|JJ>YNeo7o4tW)RUH+D4Yg82*~e>n zu`I<@JrRWswNg>5Lz57JszU$p9%XE(mD(wD4!gA&QX{83hbcs1L#;oZGOruv&mgEO zBnlg9rE$k)TF2|Zo!P;CzqhU^Y^ar%T1nRbu}@VeQP@x`9h7}8M{XBkOH0=pDheBF zrKgtp-mqOhS>1}OWvcX|4VGgWO8g$=bbQfu0S9pzM=5`_)5GC|pEV^g`TPgFe? zg$=bbQ)^P+9~o5r7KIJ9vOxL!9xLR%*3A@&1jfoT9Ly zRyHX6S#;&iqgPc`6NL@6vQw*K+P$|`brXdRwQ@k&b2u!?U)5Dj6@?A8a#HI+_Y@yg zZ5D+MwQ{-R@|{AzU~yt>Ztu?FB~jQ=D>t={Y_0o5)dx}7P%96V{T@+|?gtLFbFHYq zyvGY0YUQO?hvPX)sLCq}8*1fqE%OTSA!NmWR5cTY4Yl%9>uHKB(^O3qg$=a=pzPx{ z*uT*)Rl7xDL#+bTdXXzzEmhA%VPhT`zgWM6``Mo?3+|VpbJIp$8{z-pR}lXl_kY{9 z^_!occP{<>%KDVKnGLH#P@%p5gkRe{BkrndE6QwG6^62Z4q@EZ+v!z}5M?&3ia^R;SNDuif{F3&qs&v83b?4`2HmpiQg%MSue(S8N%8D`@R;8fKSJ3A6 ztLc_(s#=LM8&;*E>^Yn<=ui_?V?>z^t1?g#yp-SLNSk~Yk-egpi!vKlWvO+x(&Qbg zPKYuaR^_0=No(%N){j*^5oI>4%0t;RAM0}be5xV__s+c8u&MxMk84h`W2aQ56lFH7 zDni+7{#?&vK_0J?qRfU>B~nkW@2IG)#-hxIRb?o9ZKTfF&iBySGv8N~*|4et6<*F^ z?CHxQshTCqY*8~mtlun<9mL} zf5&XNUJJ^8dQU!PKq*yyM41h%+EDgA?%UDRSk;H}z3AXpcU8{~sgONI<#h=FKf?yEm3B}su@%!QOR15 z7_BNnIIm?kteTTLy60^hRR=|x4XYMV_L-7#!o^#v+J^U9X2Yr_l)dI_zF*#3)of8_ z!>ScjSvjuJvu62T!0g#LCdzDBwT80SM*a-X15^!*;N3&BVbuo8UK=+9@AXktBBH0v zhE-cA-$xwW?!HZ1S=D7xX2Yr-lzo&dWH<|*RK^Iw7OC1E#cP=jtFBP?+9=<8kncYbT>cwhMVSq&Zcx6D ziMS;_w)eZLTv5H2*|6#kW$)pXj~5!K>LJQ(SoMJNy)fZ6WK>t*+l#%2TSS=+tDaEy zI{dJ*YZp}mqIvhwY*_VzviC5s^4$}v_KGqaR=uI@D_f$DEvu*+6Wwc>4XZv-8RfXD z+$gYDRX_|+nGLHzs8pi9^_&!_s;?-sVbvEZi>L+X!c0)LQPPBR`-nqSwT$WA zL$hJkAId&n_bZHwt14D3Pniv?0Z=LA9)?{!`-7^gqRfWXKq&iO*)aZwpQ@&aG8I{3b@uxDexD6?TT0?NKdC8~1c zfU00|yyG$(RwJQm%RPJ?wZ{!r1x1++t5HzBMAhmyIjO2ZQD(zxG*nGdTkAcHplXLG zvtcy`D!Zs2rFw2v^+}Z3uo_Eh>4O!2s>&AEI~!)hY8;e(lm~q%a#vLsQD(zxJe0lW z^WIEbSJehlX2WU%lzlxsxBas3Lxg>l--|LERuf6RYUH<1RhD?(ahVOPNl^AP_K`~m zgS;Mg7G*Z9CPU?rGrw@$!B*PZAj)i5O@Z>g#NhV4$LgM{TE+M7q1mvS3YAw>)p6^5 zC&r$Qb)w9M)ifykD*ANY9iO-AwJ5V;H61FmwCW~(bxc+I1l~O~8&)%@^>bE=gsR$# zG8hO8Skv38>WMNNRx6=ON-KQYVAoa66lFH7Rzca%QH6&0UZtvGQtuv` z4Xf2qzKw+t6C(= zY*_sb<-1$B9chy}iK>gD%!buEs6wLR#T>OsRjB0NJv19u>!GTMdX%DB5LHN&*|6F` z>hi6~UA5I$l-aP_2-QqlW5U!5a$Gw_nGLH=P` znGLI5Q1M)e=!xL_!rXQN1t=FQ=hSd?M=%PLaYaHbH6*Z05G8TtWW{$@T^)kK*Mt20pczy4x=ao=0C{r`0kWj3tNLY0%&$v(q_yr+y3Wj3tNLD{bz zvZw3sdtYYtnM@5+ptIJUKxTei+kycgM4Bl~>4XZ0qzTXbP zZNaAmL0&gXh%y^iSE1}Z{8G5J@BeAf#&A()!|EE8eY~3Ij`NqQBcjZP)paO)^|l`Q zt*xri8NK5&8&)@EXr(HJ%O^H z=WiBBxl7f2QD(#HDU`j3Ne@@_y|LTp*J)8^!|EBSzY85asOr5avtjidDw>?bn*U5& zq$+kc@64MGs~1rAQEoB%{3%rhM41h%mr(XIz}3PDeW%kNS1VCw!|D~3eU!g$2%THi zXi;Xv>NQkMIj-fo(**gh<62Q>!|Dx`?-$%!->n(sliqbvX2a?&lN`|eQJb%xXrU^0F0W-atbRcGzO=@zY4Q6(em^CfD6?Vp z6DpjjREfR^`3_81QD(#H7nD7&N*fA))_XWvl-aQQ4duHaaGRPoeUQ%p7etv2D?i^0 zXoz6`9`ZZVy~ZkSMbGV>4YOet49dP&zB?LjxTtI$yP z6+6_q_)k?G6J<86!a(^R5ZpFw+kRiw2T^9jDlAkyQKe>IPoOGEUhiy}4Xbca_H`q0 zM(`lld=*h-_0*xI^nPPaJ?wAVHJ^7zG;c~sk$x7 zY*U(qTUGr;nGLIGQ1&xhxbGpBs9GS(Y*6 zA+>_tnbA~L5m9EtDiM@@rpzo+F~~h^E6QwGC5DP1kJs$BgM)k(Fh!Kvu=0nppG7xp z8_-kl;Z{**!zu}sJ%@)A#O|c(fheyxT!BfArRb7kbBs+uy;1hhE-~)M)D|kuC(9xwrO8Qmy0qRR)0dZ6!k6I>m;h~i832j zX`qsd^7BjeLRGvX-aRxMR%xN^t4;LI8G?KUs3FR1SfwNNepSr2+L|iLY*?j->L>Sb zQKb$+zRz|+l-aP#098{|qf;-}Yb$zD@3_o{RYs_Cq7LqDpjXNnGLHfP`(p~Tk;(}gS_iSEan}T*|5qAWxu+4G;rt+ zZIu>fHmtHirI%LTmZ27^>L+Upc?2+Ahj$SmlNCeF=(No#3rTs0u9M9hcd#$_Euz)Po(n=c!sG%4}HW zhw?p0xb3QSKghMQSCrYX3V@0)s(aQo%e3`Ql-aNsinGLJLQ1;!SUyHnlRV66p-9xisRRk)eoQ)~L_E%C> zMwHpGDhlQOH+}TOBj4Mmy`q|lG8Q&BDX2Ys7ls&Fsmp?twR*~|aG8ZE@As{}qa0Y#Q)a`eI+VXR^Q*UPQxk2KuH-4R zVO0Yvo2YdSlTA@|Sd`hYstJ`vRFTbn8>{MB*=v~%t6ETbL{)9NFQcjyRXk-jtZGBq z$E#WD!HZQr7G*Z9>Ok4&*VrjVeGis>yjEBBT4uwlE|fhR-%o65uBt{gPniv?dQkRk zl)gE0xvFs0J!Lkm>O(b^vyt!Wp`og_h%y^i4WM#~$`rom6IDHGcrCMG)sWQfzfOHp zm8zzv%!XAXDEoLVtFoZDsw<+*hE-#z%J#UXf9|hpOf9cvHmsUJ+1HJ#aW`F4RjjtB z%!XA{sFKo(JE_r3Rl)0c%4}FQgPJC)N$nLuj%%+dvtiX7YLTeW`zrCVfK2SG8yn(08hE*FV`>fm+zUqBdi5q&#Y*@903XoQ#-t$Wj3tZL)owBpRe8USzBjBnGLHBQ1;VT)im9GC&r$QPom6*RYxe_7sF@GduTSSIziccxaQIOAny*PMVSq&&QQJ&YPgl}7uy-VX%!XArQmbE_JfW>mqRfU>cc_?hTrt;X4f1`P zR872dXf~{RK-se~@^05F+Nv(fY*_V#vfn=}STjbDuLAmrG81P>KjSyuvtOh{Y z>u}nbQGcu2B+6`94W!oKD@n(zdLqhfSPg=TDEDw#>q^&E#cbxCL$hHu7|Qpd5Vt~^ zN(Om%$SKNfSPg-)$MtmSu65dKCdzDB4TZAzFvRF~L9UG%qRfWXFev*>X^|^s2W{;V zWj3saQ!8+Nv#hG_i832jBcSXn_Mx(;tE&pt+&hP6!)hdyy?U3l2z6dna#3c(Y7~@x zrc66?VXmsOqRfWXXej&LgJd;NS5wtZl-aNvL#=*MCu~u*T9nza8VhA#d-s1@ALQ%G zOQOt%)i@~ocpYC|E0MN>weZfN*{~W9<$H<2?eBY+E2>H<%4}FofU>Uu@k;C&qN=DU zvtcz6%6{Kw;ft!BRCN+%HmoK=C6;@*t--CTs-}oC8&;E{?DtXy%HmsIF#g(&BYj0}b zLuaq~pQ6l$)n8Edbt6-saY0^1Gq>^1q1mun3S~dDRbIJmuePd+G8jwG8+>(c$b6wR*QD(zxC6v8-o1IO0Sk+Ha zX2WU~lzj!LbNF&5RcYFK=g@3et%kC%HlO>P?Wn4;D6?U;2Fku-UyAr5$UU4R%4}Gz zrPiLJ+g@wyiYT*T^*5C77u-7RsMkVOw07QcnGLITQ1Ewf>@8_FKn|5*DHc*%~c?k6B1 zL0niA5CjsHMI^H%CZJ9xlL?HONkS$Ii`w+-?)P42`gOnbGD|>KA@U(X0oervWM7m` z7TFRI*^MA5K|vN#)(=sTO}?{L)j74@+s|))Kf>!e|Nl9sPVIH;)_woa{F)lS?lfZ- zVl3XEbCfg{iv{h;qZMQf(ZV1 z+oS9uVl3<3#@5^K@^MuUcMA(Kmh~QDxmJ1lTZi`uw$2w8Vl3;giRH$x>-InHF9Peh zun=Qe?=`kQ|MiPr5Lhn}7Gf;xZ-{lepEc}#4>qc4-gBW^zR!t&^O4PCM?8Q)(44o6Jecpx8fnV_6?2mODl8x#|7YeB+OWg&52F2(g|o9{$K# zw>}YU?K;8HK#XPmEwMI)b@nTt0@H2h;SH{27Gf;xI%2_Q4gLGuPrv_rfpx905Mx8sqQ$rFZcSk^xf%hjkyU4QyJgNN@C7Gf;xABpuKvGvyRpZ#}WeMVS_v8+!TTlfCXRbL9M z7d(uth9jAebwuzv0Vm#UrHe-IX8EbE^P>p@#zeqgZmO<^I% zvi{kyZv5i6{!d{2#G^Q0h_S3s8`ilm->E#jyRZ;rS)Vbit3UZ-H6z+DEW}vWzZlj> zcI^A@;Ne4rg&52FtYQ7k6{p=IupTNb#8}qn4C_zs`YSIBtfvVJF_!gt!@BgF&;G^0 z`U_zp#t7A)@z=iOcEQ#cg@qW)`l4ZdZT&^>4XhhHnoAim zmi2Fjb=UJgab;lLL0E{ftbaGG-EW(~)ZX=?X9x>1mh~mWdj5M}_NRe$SXhX$tS=kZ z{{7dgou#p`5MxxE~-Zvhy9#{_(7Gf;x{~Ff2-t!`G){Cg3o(}UJ!0KOSa)9e(R&8gcZG!*%lbaCZZ52E-fF1Y z*XZ$V3o(}U17f-P{3$QL^{a!e7Yhq9mi0fx`dP6xyy{Z*Jms&2g&52FA+hGdy3H+4 zRsF_Y{ttVI7|U7#GdKK^bA)x>qn-c{NnGvyp|B8RSwBK7EG7K+jkkX4eu4GDC$KHV zSk?`Q@Fcc{7|Z%GV*Q+W_@YZr+&8dZCoIHR*3FEqU0?Z^ z^8@QPf5^5FV_7E|TRV4rNUh^zSpfuX<7N@NL3EjAi{Kv5pJt zmtXa#7X;RApTf2fV_82%EVs&j&UK$WJFu=77Gf;xr-=psp?_cg;|u;hu%7%>wuKnW zx+SsP`1PchUVYoZ`kJs1V_CN%maB(P{@bzg@OgjCwh&`kww~*3aJM5%&+Qz0Y7AWIuG|hlWif!vVM+OZmfLNHShm;V0}thh_S3Y5X(jWv(NkS-w&+kJ&SE2#tB6OV0}SYh_S4@5NoHf2JikkH7>vQPuLb>EbC-q!GGxA7au-UGopjfWfo#A z>l9)^X6WB7K6CF!1P@;-EW}vWFA&T1htL1=4UPrY;CXBdF_!g<#B%xi+Un6S2i8rV z&n(1P)-MsuMgG&bKIKqgJzrRev8=li>nzFF$M<|i_48-`DceGfW!=rN79YBm>alO} z0%jq`vhGf-GsMt_3&1y)^4`H-*>V_Eki)=k92 zb8dPjJTh{u<1c1gh_S3wiFJmszBhZ4+C6x>un=QeJBa1-^|*iik<)^$%U;5^5Mx<8 ziRH%S-}>r9RPFugmof`6mbHsm&{@#GTb=n~0J?m=SXhX$tlh-ATv(sJ?@B+g7B6F4 zh_S5Gh~-N887KX#>U;0=a%LgMvQ8(~8Di@Jk2ZbKVl3-di3JmD`giTsFZe|8 z@b#}?TZpl&Gl&HS=-ytg&4~^lUS}lyyb6VEpahC>s8D`jAh-MSgzl= z_pQI6`re;5Mx<;iFJyw&Uo0}ZWC;MSXhX$ zth0%AM`7LkkG`$y*!izz4-sQo`-tVDvGK`Yx>>OGW?>=5vd$rvtC?4S<70OTtP5Yq zwh&`k`-ydT@$idpyycAo>(;Ml7Gf;xTw=M^#D8CLAGJz)fv^x`S@$KD+mrd&u1CKz z*!rb6ur0(`*8PYD;ii9od)r@qOkllSSctK#1H^JOtE+$G@r%G(c_Z6GjAi{Mv0R^U z&)Yxr^1!-USctK#^N8hI+_gV(|L+IZga49kA;z)}63exe>+ZOBUtqmgSctK#Lxy$A z_rIu4f<5X@Yzr}#bw06N|MR3r-+L5n-S^GRLX2fyU|8?D)gN3IST}tOvk+rh7ZS^j z7f=4?rPIKAx3CanS@$QFi{VGU_W92T)+67_wh&`k7ZJNmYA*t+}Mn1vY2x`bFS7uKDJ$KMcG9~Bm2 zEbCHYxjKKllTT7l6`%2TwuKn(jlV7_XoOR~XHtG;bq0ML|GSJdLnBxJn6t8S(mPl) zVyr(8FsxUe`j60v9qVLaA;z*EXjpIf&)2K-8@q&s7|VK)VLkUvH-K)&+1e*8#8}pY z4eMop_s+Wo)?r~G#}&uMieuEURm5ed=Q`_*}4ct*{Vd zS*wQi#UFXh$$|AzVIjt{dWJQA(V1#5<#WP9jAiwSYN4mYR5Mx>EhV|?BTzg}%bq`@7#sdE`;ExB^ zeT0P=%NiQi)(6(E4y^Npg&51a+^|0S#GmX3)`NwG7|S|hSYLU{C9epqBf>(AWsMB$ zy9Y0MUtm2{SctK#O~X3$k$+RW2Tu?dVk~QHSpWR7C;erx^=x4w# z%AS+dTYF|O zZvyLNVIjt{jv3Z<|NOJ6E#F62h_S5WhIPl6oC;34G3BtZ5Mx;<4C|2}{NxJ)>xi%r zV_8=k))U|Ty-Nb?F~UNOWj)lePI~5Z_XXCog@qW)dYEDT*W0dnbYQ(sSctK#-!-g1 z-217cf%O4lA;z*EZdkX!)ia(RSf3LXVl3+shV_M0-+gIdeNR}3v8+cL)^FbULH`t3 zx4edH6k;svQHFK;^LJkrSoaVXVl3;?hPD3MZ+$4R_6Z9ymh~9J`lAoL@3VpRU|}J~ zvVM-P=o3s?O>)u?NQg&50vJh5CfzW$+4y(ZYYURa2+tp8(d{l~t` zRUh?bVIjt{o?uvCdi0-lf~^}~%QXrymh}h3avpy6rVmqf{`SH`jAcF1u+IDFf1ey| z-9uQ2v8<~N>xEzVl6p>bA7LTJvYupEAO5Frsi!dK2@5fn^@oP_orm06#4@p z4R8MM_YAgPC@jQS)*l)D2NaDGeJdT}1!Qdo$wtmhckRbTq7URMeWF_!fwhIQm~w|i}{wM$rtv8?AB z*2UksO4X=+!a|H?JSWlgqrux zgoPN(dVyiBJ>aIQw|R`P5Mx;{G_2b^ql;@(YE97|Z%I z!x|j?m^$tJI$QfrmzrWSuZ!NKfk80b`MT^54SJGSk@~H>+;8b7PjAA zzD^bvVl3;GhINx4yzut}>psFljAgybu--5}`M(0|u&@wgS+6FR8!K=3>bI&9_K2_$ z!(KmBQm|yKp4X6`pX4H2`O&vruWIHKg@qW)`g6nj{^w8ofU~r+@_Jz*#I{-w3SV7ZzeH>urYhw0k`CP++}ASctK#w;R^8?sQDm`Hu?= zF_!fX!#eNt_jqxz^#frc#!JVfHW)gbhqrhi#}F}=^f7Z#_@h z`YmB0#55595#UxKYug@qW)`g_BA+dFRZ*}%F?SctK# zj~mwPwtw`Xz)~2h(ShwfV8`bij_Rci7pj$+6wLR`vjCCJf2K#$s)4vpW{ILB4Be z4KSLl?-Zj$_*>C-)o7r1IPMRQ*D&jy(Qv#voYx%O>~hS9L;N4=}CX4HXd8fD09ghd2 z&SrP3m1*ZCnT9HxiSALZXZ7$p4~tnyoNKmdbPcARPQN?vLhW8mdxOqo+<_L;_l22} z&jy1dD|^O^(P(`!gr*411oAhWb?|2g)4B4xOlMS}*JO2VGTrRXu~lzDQ{fgT?PoS0 zOb3(B)^ySv%%t@=Bzzu@1;)ZSobK! zytCEY?5s_@n}b?=X4HSGCne% z92+BneiLEe2vp5;X*+X?yKLe`;KpE@)d9t@m<}S*p+o0S=EJpNk4h*A_Z>V89v(Wx z`P)BUY!0Sf7>_y!#0$;utI*>^<(LlE@@>lHu0a{r|NhK3L#Q4DY$kb~ zZH!Zc1)wPA_DiFNR0$gBiq&wq*_A2?O>%2F3Ro@r@7!t(9(1}GWN|<4JK98GF-9HG z%gm1r`)AtvJlyQ}=DSY!eL>ORjA7-H^gV67$tbEC4XTwr-7QJ7^h9l45Vh2?dHb23 zt*t)oQBtOPyiCl@C>K^V`Juwvu~QcoGUABh z;=mZ@1h5>SJ~yw-O}wfZ!ji}A=1uMG_b(c(mE{*fQFLc{AKZMcnwJa4JeVAY*}z~Q z%q-VoX;cr7^Ek;gRbD+gMayp0vVLH8@Im{|zxeQCYYS=!SW%M0hxhL+33l%Y66zlk zyW9|5nI&SHSG$76Xzv-$_FZ_%zV6oS0IVu-0&(Sl=Z?-LqV%>FogRREea#njqV6$t}xXNQ}~Vkv;&Jy zOzj+5bwygOO;l0VI~!L=u)}srj zlP%~nvsxB8LZcbr5RGoxus*J%t$=Za=nrgREDh-5Y zAC#fXPT$?R=)k$>qUTgi-BjN~F57$QerWB`B0THdLl?&>d-ugj7*4I)O|qS-OnkH` zghr?8iI7WoEq}Dt+lMRDVGkS0ENO*q+3n^kowea{==t4d9_#=@O&zc6=
    4k7R% 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%0D?1x*9i0s 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
    4))&wrjQG5Jow*awOE`V%i3n12n)Afou*3y%t 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 NFrxq?-}v``{eK)$#P$FH diff --git a/vendor/miniaudio/logging.odin b/vendor/miniaudio/logging.odin index 0c14a10c2..b03778079 100644 --- a/vendor/miniaudio/logging.odin +++ b/vendor/miniaudio/logging.odin @@ -12,6 +12,36 @@ when ODIN_OS == .Windows { MAX_LOG_CALLBACKS :: 4 + +/* +The callback for handling log messages. + + +Parameters +---------- +pUserData (in) + The user data pointer that was passed into ma_log_register_callback(). + +logLevel (in) + The log level. This can be one of the following: + + +----------------------+ + | Log Level | + +----------------------+ + | MA_LOG_LEVEL_DEBUG | + | MA_LOG_LEVEL_INFO | + | MA_LOG_LEVEL_WARNING | + | MA_LOG_LEVEL_ERROR | + +----------------------+ + +pMessage (in) + The log message. + + +Remarks +------- +Do not modify the state of the device from inside the callback. +*/ log_callback_proc :: proc "c" (pUserData: rawptr, level: u32, pMessage: cstring) log_callback :: struct { diff --git a/vendor/miniaudio/node_graph.odin b/vendor/miniaudio/node_graph.odin new file mode 100644 index 000000000..ac47d43d8 --- /dev/null +++ b/vendor/miniaudio/node_graph.odin @@ -0,0 +1,469 @@ +package miniaudio + +import "core:c" + +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} + +/************************************************************************************************************************************************************ + +Node Graph + +************************************************************************************************************************************************************/ + +/* Must never exceed 254. */ +MAX_NODE_BUS_COUNT :: 254 + +/* Used internally by miniaudio for memory management. Must never exceed MA_MAX_NODE_BUS_COUNT. */ +MAX_NODE_LOCAL_BUS_COUNT :: 2 + +/* Use this when the bus count is determined by the node instance rather than the vtable. */ +NODE_BUS_COUNT_UNKNOWN :: 255 + +node :: struct {} + +/* Node flags. */ +node_flags :: enum c.int { + PASSTHROUGH = 0x00000001, + CONTINUOUS_PROCESSING = 0x00000002, + ALLOW_NULL_INPUT = 0x00000004, + DIFFERENT_PROCESSING_RATES = 0x00000008, + SILENT_OUTPUT = 0x00000010, +} + +/* The playback state of a node. Either started or stopped. */ +node_state :: enum c.int { + started = 0, + stopped = 1, +} + +node_vtable :: struct { + /* + Extended processing callback. This callback is used for effects that process input and output + at different rates (i.e. they perform resampling). This is similar to the simple version, only + they take two seperate frame counts: one for input, and one for output. + + On input, `pFrameCountOut` is equal to the capacity of the output buffer for each bus, whereas + `pFrameCountIn` will be equal to the number of PCM frames in each of the buffers in `ppFramesIn`. + + On output, set `pFrameCountOut` to the number of PCM frames that were actually output and set + `pFrameCountIn` to the number of input frames that were consumed. + */ + onProcess: proc "c" (pNode: ^node, ppFramesIn: ^[^]f32, pFrameCountIn: ^u32, ppFramesOut: ^[^]f32, pFrameCountOut: ^u32), + + /* + A callback for retrieving the number of a input frames that are required to output the + specified number of output frames. You would only want to implement this when the node performs + resampling. This is optional, even for nodes that perform resampling, but it does offer a + small reduction in latency as it allows miniaudio to calculate the exact number of input frames + to read at a time instead of having to estimate. + */ + onGetRequiredInputFrameCount: proc "c" (pNode: ^node, outputFrameCount: u32, pInputFrameCount: ^u32) -> result, + + /* + The number of input buses. This is how many sub-buffers will be contained in the `ppFramesIn` + parameters of the callbacks above. + */ + inputBusCount: u8, + + /* + The number of output buses. This is how many sub-buffers will be contained in the `ppFramesOut` + parameters of the callbacks above. + */ + outputBusCount: u8, + + /* + Flags describing characteristics of the node. This is currently just a placeholder for some + ideas for later on. + */ + flags: u32, +} + +node_config :: struct { + vtable: ^node_vtable, /* Should never be null. Initialization of the node will fail if so. */ + initialState: node_state, /* Defaults to ma_node_state_started. */ + inputBusCount: u32, /* Only used if the vtable specifies an input bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise must be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */ + outputBusCount: u32, /* Only used if the vtable specifies an output bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */ + pInputChannels: ^u32, /* The number of elements are determined by the input bus count as determined by the vtable, or `inputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */ + pOutputChannels: ^u32, /* The number of elements are determined by the output bus count as determined by the vtable, or `outputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */ +} + +/* +A node has multiple output buses. An output bus is attached to an input bus as an item in a linked +list. Think of the input bus as a linked list, with the output bus being an item in that list. +*/ +node_output_bus :: struct { + /* Immutable. */ + pNode: ^node, /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */ + outputBusIndex: u8, /* The index of the output bus on pNode that this output bus represents. */ + channels: u8, /* The number of channels in the audio stream for this bus. */ + + /* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */ + inputNodeInputBusIndex: u8, /*atomic*/ /* The index of the input bus on the input. Required for detaching. */ + flags: u32, /*atomic*/ /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */ + refCount: u32, /*atomic*/ /* Reference count for some thread-safety when detaching. */ + isAttached: b32, /*atomic*/ /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */ + lock: spinlock, /*atomic*/ /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ + volume: f32, /*atomic*/ /* Linear. */ + pNext: ^node_output_bus, /*atomic*/ /* If null, it's the tail node or detached. */ + pPrev: ^node_output_bus, /*atomic*/ /* If null, it's the head node or detached. */ + pInputNode: ^node, /*atomic*/ /* The node that this output bus is attached to. Required for detaching. */ +} + +/* +A node has multiple input buses. The output buses of a node are connecting to the input busses of +another. An input bus is essentially just a linked list of output buses. +*/ +node_input_bus :: struct { + /* Mutable via multiple threads. */ + head: node_output_bus, /* Dummy head node for simplifying some lock-free thread-safety stuff. */ + nextCounter: u32, /*atomic*/ /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */ + lock: spinlock, /*atomic*/ /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ + + /* Set once at startup. */ + channels: u8, /* The number of channels in the audio stream for this bus. */ +} + + +node_base :: struct { + /* These variables are set once at startup. */ + pNodeGraph: ^node_graph, /* The graph this node belongs to. */ + vtable: ^node_vtable, + pCachedData: [^]f32, /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */ + cachedDataCapInFramesPerBus: u16, /* The capacity of the input data cache in frames, per bus. */ + + /* These variables are read and written only from the audio thread. */ + cachedFrameCountOut: u16, + cachedFrameCountIn: u16, + consumedFrameCountIn: u16, + + /* These variables are read and written between different threads. */ + state: node_state, /*atomic*/ /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */ + stateTimes: [2]u64, /*atomic*/ /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */ + localTime: u64, /*atomic*/ /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */ + inputBusCount: u32, + outputBusCount: u32, + pInputBuses: [^]node_input_bus, + pOutputBuses: [^]node_output_bus, + + /* Memory management. */ + _inputBuses: [MAX_NODE_LOCAL_BUS_COUNT]node_input_bus, + _outputBuses: [MAX_NODE_LOCAL_BUS_COUNT]node_output_bus, + _pHeap: rawptr, /* A heap allocation for internal use only. pInputBuses and/or pOutputBuses will point to this if the bus count exceeds MA_MAX_NODE_LOCAL_BUS_COUNT. */ + _ownsHeap: b32, /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */ +}; + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + node_config_init :: proc() -> node_config --- + + node_get_heap_size :: proc(pNodeGraph: ^node_graph, pConfig: ^node_config, pHeapSizeInBytes: ^c.size_t) -> result --- + node_init_preallocated :: proc(pNodeGraph: ^node_graph, pConfig: ^node_config, pHeap: rawptr, pNode: ^node) -> result --- + node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^node) -> result --- + node_uninit :: proc(pNode: ^node, pAllocationCallbacks: ^allocation_callbacks) --- + node_get_node_graph :: proc(pNode: ^node) -> ^node_graph --- + node_get_input_bus_count :: proc(pNode: ^node) -> u32 --- + node_get_output_bus_count :: proc(pNode: ^node) -> u32 --- + node_get_input_channels :: proc(pNode: ^node, inputBusIndex: u32) -> u32 --- + node_get_output_channels :: proc(pNode: ^node, outputBusIndex: u32) -> u32 --- + node_attach_output_bus :: proc(pNode: ^node, outputBusIndex: u32, pOtherNode: ^node, otherNodeInputBusIndex: u32) -> result --- + node_detach_output_bus :: proc(pNode: ^node, outputBusIndex: u32) -> result --- + node_detach_all_output_buses :: proc(pNode: ^node) -> result --- + node_set_output_bus_volume :: proc(pNode: ^node, outputBusIndex: u32, volume: f32) -> result --- + node_get_output_bus_volume :: proc(pNode: ^node, outputBusIndex: u32) -> f32 --- + node_set_state :: proc(pNode: ^node, state: node_state) -> result --- + node_get_state :: proc(pNode: ^node) -> node_state --- + node_set_state_time :: proc(pNode: ^node, state: node_state, globalTime: u64) -> result --- + node_get_state_time :: proc(pNode: ^node, state: node_state) -> u64 --- + node_get_state_by_time :: proc(pNode: ^node, globalTime: u64) -> node_state --- + node_get_state_by_time_range :: proc(pNode: ^node, globalTimeBeg: u64, globalTimeEnd: u64) -> node_state --- + node_get_time :: proc(pNode: ^node) -> u64 --- + node_set_time :: proc(pNode: ^node, localTime: u64) -> result --- +} + +node_graph_config :: struct { + channels: u32, + nodeCacheCapInFrames: u16, +} + +node_graph :: struct { + /* Immutable. */ + base: node_base, /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */ + endpoint: node_base, /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */ + nodeCacheCapInFrames: u16, + + /* Read and written by multiple threads. */ + isReading: b32, /*atomic*/ +}; + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + node_graph_config_init :: proc(channels: u32) -> node_graph_config --- + + node_graph_init :: proc(pConfig: ^node_graph_config, pAllocationCallbacks: ^allocation_callbacks, pNodeGraph: ^node_graph) -> result --- + node_graph_uninit :: proc(pNodeGraph: ^node_graph, pAllocationCallbacks: ^allocation_callbacks) --- + node_graph_get_endpoint :: proc(pNodeGraph: ^node_graph) -> ^node --- + node_graph_read_pcm_frames :: proc(pNodeGraph: ^node_graph, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + node_graph_get_channels :: proc(pNodeGraph: ^node_graph) -> u32 --- + node_graph_get_time :: proc(pNodeGraph: ^node_graph) -> u64 --- + node_graph_set_time :: proc(pNodeGraph: ^node_graph, globalTime: u64) -> result --- +} + + + +/* Data source node. 0 input buses, 1 output bus. Used for reading from a data source. */ +data_source_node_config :: struct { + nodeConfig: node_config, + pDataSource: ^data_source, +} + +data_source_node :: struct { + base: node_base, + pDataSource: ^data_source, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + data_source_node_config_init :: proc(pDataSource: ^data_source) -> data_source_node_config --- + + data_source_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^data_source_node_config, pAllocationCallbacks: ^allocation_callbacks, pDataSourceNode: ^data_source_node) -> result --- + data_source_node_uninit :: proc(pDataSourceNode: ^data_source_node, pAllocationCallbacks: ^allocation_callbacks) --- + data_source_node_set_looping :: proc(pDataSourceNode: ^data_source_node, isLooping: b32) -> result --- + data_source_node_is_looping :: proc(pDataSourceNode: ^data_source_node) -> b32 --- +} + + +/* Splitter Node. 1 input, 2 outputs. Used for splitting/copying a stream so it can be as input into two separate output nodes. */ +splitter_node_config :: struct { + nodeConfig: node_config, + channels: u32, +} + +splitter_node :: struct { + base: node_base, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + splitter_node_config_init :: proc(channels: u32) -> splitter_node_config --- + + splitter_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^splitter_node_config, pAllocationCallbacks: ^allocation_callbacks, pSplitterNode: ^splitter_node) -> result --- + splitter_node_uninit :: proc(pSplitterNode: ^splitter_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +Biquad Node +*/ +biquad_node_config :: struct { + nodeConfig: node_config, + biquad: biquad_config, +} + +biquad_node :: struct { + baseNode: node_base, + biquad: biquad, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + biquad_node_config_init :: proc(channels: u32, b0, b1, b2, a0, a1, a2: f32) -> biquad_node_config --- + + biquad_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^biquad_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^biquad_node) -> result --- + biquad_node_reinit :: proc(pConfig: ^biquad_config, pNode: ^biquad_node) -> result --- + biquad_node_uninit :: proc(pNode: ^biquad_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +Low Pass Filter Node +*/ +lpf_node_config :: struct { + nodeConfig: node_config, + lpf: lpf_config, +} + +lpf_node :: struct { + baseNode: node_base, + lpf: lpf, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + lpf_node_config_init :: proc(channels, sampleRate: u32, cutoffFrequency: f64, order: u32) -> lpf_node_config --- + + lpf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^lpf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^lpf_node) -> result --- + lpf_node_reinit :: proc(pConfig: ^lpf_config, pNode: ^lpf_node) -> result --- + lpf_node_uninit :: proc(pNode: ^lpf_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +High Pass Filter Node +*/ +hpf_node_config :: struct { + nodeConfig: node_config, + hpf: hpf_config, +} + +hpf_node :: struct { + baseNode: node_base, + hpf: hpf, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + hpf_node_config_init :: proc(channels, sampleRate: u32, cutoffFrequency: f64, order: u32) -> hpf_node_config --- + + hpf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^hpf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^hpf_node) -> result --- + hpf_node_reinit :: proc(pConfig: ^hpf_config, pNode: ^hpf_node) -> result --- + hpf_node_uninit :: proc(pNode: ^hpf_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +Band Pass Filter Node +*/ +bpf_node_config :: struct { + nodeConfig: node_config, + bpf: bpf_config, +} + +bpf_node :: struct { + baseNode: node_base, + bpf: bpf, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + bpf_node_config_init :: proc(channels, sampleRate: u32, cutoffFrequency: f64, order: u32) -> bpf_node_config --- + + bpf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^bpf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^bpf_node) -> result --- + bpf_node_reinit :: proc(pConfig: ^bpf_config, pNode: ^bpf_node) -> result --- + bpf_node_uninit :: proc(pNode: ^bpf_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +Notching Filter Node +*/ +notch_node_config :: struct { + nodeConfig: node_config, + notch: notch_config, +} + +notch_node :: struct { + baseNode: node_base, + notch: notch2, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + notch_node_config_init :: proc(channels, sampleRate: u32, q, frequency: f64) -> notch_node_config --- + + notch_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^notch_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^notch_node) -> result --- + notch_node_reinit :: proc(pConfig: ^notch_config, pNode: ^notch_node) -> result --- + notch_node_uninit :: proc(pNode: ^notch_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +Peaking Filter Node +*/ +peak_node_config :: struct { + nodeConfig: node_config, + peak: peak_config, +} + +peak_node :: struct { + baseNode: node_base, + peak: peak2, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + peak_node_config_init :: proc(channels, sampleRate: u32, gainDB, q, frequency: f64) -> peak_node_config --- + + peak_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^peak_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^peak_node) -> result --- + peak_node_reinit :: proc(pConfig: ^peak_config, pNode: ^peak_node) -> result --- + peak_node_uninit :: proc(pNode: ^peak_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +Low Shelf Filter Node +*/ +loshelf_node_config :: struct { + nodeConfig: node_config, + loshelf: loshelf_config, +} + +loshelf_node :: struct { + baseNode: node_base, + loshelf: loshelf2, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + loshelf_node_config_init :: proc(channels, sampleRate: u32, gainDB, q, frequency: f64) -> loshelf_node_config --- + + loshelf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^loshelf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^loshelf_node) -> result --- + loshelf_node_reinit :: proc(pConfig: ^loshelf_config, pNode: ^loshelf_node) -> result --- + loshelf_node_uninit :: proc(pNode: ^loshelf_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +High Shelf Filter Node +*/ +hishelf_node_config :: struct { + nodeConfig: node_config, + hishelf: hishelf_config, +} + +hishelf_node :: struct { + baseNode: node_base, + hishelf: hishelf2, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + hishelf_node_config_init :: proc(channels, sampleRate: u32, gainDB, q, frequency: f64) -> hishelf_node_config --- + + hishelf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^hishelf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^hishelf_node) -> result --- + hishelf_node_reinit :: proc(pConfig: ^hishelf_config, pNode: ^hishelf_node) -> result --- + hishelf_node_uninit :: proc(pNode: ^hishelf_node, pAllocationCallbacks: ^allocation_callbacks) --- +} + + +/* +Delay Filter Node +*/ +delay_node_config :: struct { + nodeConfig: node_config, + delay: delay_config, +} + +delay_node :: struct { + baseNode: node_base, + delay: delay, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + delay_node_config_init :: proc(channels, sampleRate, delayInFrames: u32, decay: f32) -> delay_node_config --- + + delay_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^delay_node_config, pAllocationCallbacks: ^allocation_callbacks, pDelayNode: ^delay_node) -> result --- + delay_node_uninit :: proc(pDelayNode: ^delay_node, pAllocationCallbacks: ^allocation_callbacks) --- + delay_node_set_wet :: proc(pDelayNode: ^delay_node, value: f32) --- + delay_node_get_wet :: proc(pDelayNode: ^delay_node) -> f32 --- + delay_node_set_dry :: proc(pDelayNode: ^delay_node, value: f32) --- + delay_node_get_dry :: proc(pDelayNode: ^delay_node) -> f32 --- + delay_node_set_decay :: proc(pDelayNode: ^delay_node, value: f32) --- + delay_node_get_decay :: proc(pDelayNode: ^delay_node) -> f32 --- +} diff --git a/vendor/miniaudio/resource_manager.odin b/vendor/miniaudio/resource_manager.odin new file mode 100644 index 000000000..c4d722342 --- /dev/null +++ b/vendor/miniaudio/resource_manager.odin @@ -0,0 +1,288 @@ +package miniaudio + +import "core:c" + +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} + +/************************************************************************************************************************************************************ + +Resource Manager + +************************************************************************************************************************************************************/ + +resource_manager_data_source_flags :: enum c.int { + STREAM = 0x00000001, /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */ + DECODE = 0x00000002, /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */ + ASYNC = 0x00000004, /* When set, the resource manager will load the data source asynchronously. */ + WAIT_INIT = 0x00000008, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */ + UNKNOWN_LENGTH = 0x00000010, /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */ +} + +/* +Pipeline notifications used by the resource manager. Made up of both an async notification and a fence, both of which are optional. +*/ +resource_manager_pipeline_stage_notification :: struct { + pNotification: ^async_notification, + pFence: ^fence, +} + +resource_manager_pipeline_notifications :: struct { + init: resource_manager_pipeline_stage_notification, /* Initialization of the decoder. */ + done: resource_manager_pipeline_stage_notification, /* Decoding fully completed. */ +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + resource_manager_pipeline_notifications_init :: proc() -> resource_manager_pipeline_notifications --- +} + + +/* BEGIN BACKWARDS COMPATIBILITY */ +/* TODO: Remove this block in version 0.12. */ +resource_manager_job :: job +resource_manager_job_init :: job_init +JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING :: job_queue_flags.NON_BLOCKING +resource_manager_job_queue_config :: job_queue_config +resource_manager_job_queue_config_init :: job_queue_config_init +resource_manager_job_queue :: job_queue +resource_manager_job_queue_get_heap_size :: job_queue_get_heap_size +resource_manager_job_queue_init_preallocated :: job_queue_init_preallocated +resource_manager_job_queue_init :: job_queue_init +resource_manager_job_queue_uninit :: job_queue_uninit +resource_manager_job_queue_post :: job_queue_post +resource_manager_job_queue_next :: job_queue_next +/* END BACKWARDS COMPATIBILITY */ + + + +/* Maximum job thread count will be restricted to this, but this may be removed later and replaced with a heap allocation thereby removing any limitation. */ +RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT :: 64 + +resource_manager_flags :: enum c.int { + /* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */ + NON_BLOCKING = 0x00000001, + + /* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */ + NO_THREADING = 0x00000002, +} + +resource_manager_data_source_config :: struct { + pFilePath: cstring, + pFilePathW: [^]c.wchar_t, + pNotifications: ^resource_manager_pipeline_notifications, + initialSeekPointInPCMFrames: u64, + rangeBegInPCMFrames: u64, + rangeEndInPCMFrames: u64, + loopPointBegInPCMFrames: u64, + loopPointEndInPCMFrames: u64, + isLooping: b32, + flags: u32, +} + +resource_manager_data_supply_type :: enum c.int { + unknown = 0, /* Used for determining whether or the data supply has been initialized. */ + encoded, /* Data supply is an encoded buffer. Connector is ma_decoder. */ + decoded, /* Data supply is a decoded buffer. Connector is ma_audio_buffer. */ + decoded_paged, /* Data supply is a linked list of decoded buffers. Connector is ma_paged_audio_buffer. */ +} + +resource_manager_data_supply :: struct { + type: resource_manager_data_supply_type, /*atomic*/ /* Read and written from different threads so needs to be accessed atomically. */ + backend: struct #raw_union { + encoded: struct { + pData: rawptr, + sizeInBytes: c.size_t, + }, + decoded: struct { + pData: rawptr, + totalFrameCount: u64, + decodedFrameCount: u64, + format: format, + channels: u32, + sampleRate: u32, + }, + decodedPaged: struct { + data: paged_audio_buffer_data, + decodedFrameCount: u64, + sampleRate: u32, + }, + }, +} + +resource_manager_data_buffer_node :: struct { + hashedName32: u32, /* The hashed name. This is the key. */ + refCount: u32, + result: result, /*atomic*/ /* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */ + executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */ + executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ + isDataOwnedByResourceManager: b32, /* Set to true when the underlying data buffer was allocated the resource manager. Set to false if it is owned by the application (via ma_resource_manager_register_*()). */ + data: resource_manager_data_supply, + pParent: ^resource_manager_data_buffer_node, + pChildLo: ^resource_manager_data_buffer_node, + pChildHi: ^resource_manager_data_buffer_node, +} + +resource_manager_data_buffer :: struct { + ds: data_source_base, /* Base data source. A data buffer is a data source. */ + pResourceManager: ^resource_manager, /* A pointer to the resource manager that owns this buffer. */ + pNode: ^resource_manager_data_buffer_node, /* The data node. This is reference counted and is what supplies the data. */ + flags: u32, /* The flags that were passed used to initialize the buffer. */ + executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */ + executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ + seekTargetInPCMFrames: u64, /* Only updated by the public API. Never written nor read from the job thread. */ + seekToCursorOnNextRead: b32, /* On the next read we need to seek to the frame cursor. */ + result: result, /*atomic*/ /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */ + isLooping: b32, /*atomic*/ /* Can be read and written by different threads at the same time. Must be used atomically. */ + isConnectorInitialized: b32, /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */ + connector: struct #raw_union { + decoder: decoder, /* Supply type is ma_resource_manager_data_supply_type_encoded */ + buffer: audio_buffer, /* Supply type is ma_resource_manager_data_supply_type_decoded */ + pagedBuffer: paged_audio_buffer, /* Supply type is ma_resource_manager_data_supply_type_decoded_paged */ + }, /* Connects this object to the node's data supply. */ +} + +resource_manager_data_stream :: struct { + ds: data_source_base, /* Base data source. A data stream is a data source. */ + pResourceManager: ^resource_manager, /* A pointer to the resource manager that owns this data stream. */ + flags: u32, /* The flags that were passed used to initialize the stream. */ + decoder: decoder, /* Used for filling pages with data. This is only ever accessed by the job thread. The public API should never touch this. */ + isDecoderInitialized: b32, /* Required for determining whether or not the decoder should be uninitialized in MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM. */ + totalLengthInPCMFrames: u64, /* This is calculated when first loaded by the MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM. */ + relativeCursor: u32, /* The playback cursor, relative to the current page. Only ever accessed by the public API. Never accessed by the job thread. */ + absoluteCursor: u64, /*atomic*/ /* The playback cursor, in absolute position starting from the start of the file. */ + currentPageIndex: u32, /* Toggles between 0 and 1. Index 0 is the first half of pPageData. Index 1 is the second half. Only ever accessed by the public API. Never accessed by the job thread. */ + executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */ + executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ + + /* Written by the public API, read by the job thread. */ + isLooping: b32, /*atomic*/ /* Whether or not the stream is looping. It's important to set the looping flag at the data stream level for smooth loop transitions. */ + + /* Written by the job thread, read by the public API. */ + pPageData: rawptr, /* Buffer containing the decoded data of each page. Allocated once at initialization time. */ + pageFrameCount: [2]u32, /*atomic*/ /* The number of valid PCM frames in each page. Used to determine the last valid frame. */ + + /* Written and read by both the public API and the job thread. These must be atomic. */ + result: result, /*atomic*/ /* Result from asynchronous loading. When loading set to MA_BUSY. When initialized set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. If an error occurs when loading, set to an error code. */ + isDecoderAtEnd: b32, /*atomic*/ /* Whether or not the decoder has reached the end. */ + isPageValid: [2]b32, /*atomic*/ /* Booleans to indicate whether or not a page is valid. Set to false by the public API, set to true by the job thread. Set to false as the pages are consumed, true when they are filled. */ + seekCounter: b32, /*atomic*/ /* When 0, no seeking is being performed. When > 0, a seek is being performed and reading should be delayed with MA_BUSY. */ +} + +resource_manager_data_source :: struct { + backend: struct #raw_union { + buffer: resource_manager_data_buffer, + stream: resource_manager_data_stream, + }, /* Must be the first item because we need the first item to be the data source callbacks for the buffer or stream. */ + + flags: u32, /* The flags that were passed in to ma_resource_manager_data_source_init(). */ + executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */ + executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ +} + +resource_manager_config :: struct { + allocationCallbacks: allocation_callbacks, + pLog: ^log, + decodedFormat: format, /* The decoded format to use. Set to ma_format_unknown (default) to use the file's native format. */ + decodedChannels: u32, /* The decoded channel count to use. Set to 0 (default) to use the file's native channel count. */ + decodedSampleRate: u32, /* the decoded sample rate to use. Set to 0 (default) to use the file's native sample rate. */ + jobThreadCount: u32, /* Set to 0 if you want to self-manage your job threads. Defaults to 1. */ + jobQueueCapacity: u32, /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY. Cannot be zero. */ + flags: u32, + pVFS: ^vfs, /* Can be NULL in which case defaults will be used. */ + ppCustomDecodingBackendVTables: ^[^]decoding_backend_vtable, + customDecodingBackendCount: u32, + pCustomDecodingBackendUserData: rawptr, +} + +resource_manager :: struct { + config: resource_manager_config, + pRootDataBufferNode: ^resource_manager_data_buffer_node, /* The root buffer in the binary tree. */ + dataBufferBSTLock: (struct {} when NO_THREADING else mutex), /* For synchronizing access to the data buffer binary tree. */ + jobThreads: (struct {} when NO_THREADING else [RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT]thread), /* The threads for executing jobs. */ + jobQueue: job_queue, /* Multi-consumer, multi-producer job queue for managing jobs for asynchronous decoding and streaming. */ + defaultVFS: default_vfs, /* Only used if a custom VFS is not specified. */ + log: log, /* Only used if no log was specified in the config. */ +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + resource_manager_data_source_config_init :: proc() -> resource_manager_data_source_config --- + resource_manager_config_init :: proc() -> resource_manager_config --- + + /* Init. */ + resource_manager_init :: proc(pConfig: ^resource_manager_config, pResourceManager: ^resource_manager) -> result --- + resource_manager_uninit :: proc(pResourceManager: ^resource_manager) --- + resource_manager_get_log :: proc(pResourceManager: ^resource_manager) -> ^log ---; + + /* Registration. */ + resource_manager_register_file :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32) -> result --- + resource_manager_register_file_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32) -> result --- + resource_manager_register_decoded_data :: proc(pResourceManager: ^resource_manager, pName: cstring, pData: rawptr, frameCount: u64, format: format, channels: u32, sampleRate: u32) -> result --- /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */ + resource_manager_register_decoded_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, pData: rawptr, frameCount: u64, format: format, channels: u32, sampleRate: u32) -> result --- + resource_manager_register_encoded_data :: proc(pResourceManager: ^resource_manager, pName: cstring, pData: rawptr, sizeInBytes: c.size_t) -> result --- /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */ + resource_manager_register_encoded_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, pData: rawptr, sizeInBytes: c.size_t) -> result --- + resource_manager_unregister_file :: proc(pResourceManager: ^resource_manager, pFilePath: cstring) -> result --- + resource_manager_unregister_file_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t) -> result --- + resource_manager_unregister_data :: proc(pResourceManager: ^resource_manager, pName: cstring) -> result --- + resource_manager_unregister_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t) -> result --- + + /* Data Buffers. */ + resource_manager_data_buffer_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataBuffer: ^resource_manager_data_buffer) -> result --- + resource_manager_data_buffer_init :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataBuffer: ^resource_manager_data_buffer) -> result --- + resource_manager_data_buffer_init_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataBuffer: ^resource_manager_data_buffer) -> result --- + resource_manager_data_buffer_init_copy :: proc(pResourceManager: ^resource_manager, pExistingDataBuffer, pDataBuffer: ^resource_manager_data_buffer) -> result --- + resource_manager_data_buffer_uninit :: proc(pDataBuffer: ^resource_manager_data_buffer) -> result --- + resource_manager_data_buffer_read_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + resource_manager_data_buffer_seek_to_pcm_frame :: proc(pDataBuffer: ^resource_manager_data_buffer, frameIndex: u64) -> result --- + resource_manager_data_buffer_get_data_format :: proc(pDataBuffer: ^resource_manager_data_buffer, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- + resource_manager_data_buffer_get_cursor_in_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pCursor: ^u64) -> result --- + resource_manager_data_buffer_get_length_in_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pLength: ^u64) -> result --- + resource_manager_data_buffer_result :: proc(pDataBuffer: ^resource_manager_data_buffer) -> result --- + resource_manager_data_buffer_set_looping :: proc(pDataBuffer: ^resource_manager_data_buffer, isLooping: b32) -> result --- + resource_manager_data_buffer_is_looping :: proc(pDataBuffer: ^resource_manager_data_buffer) -> b32 --- + resource_manager_data_buffer_get_available_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pAvailableFrames: ^u64) -> result --- + + /* Data Streams. */ + resource_manager_data_stream_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataStream: ^resource_manager_data_stream) -> result --- + resource_manager_data_stream_init :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataStream: ^resource_manager_data_stream) -> result --- + resource_manager_data_stream_init_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataStream: ^resource_manager_data_stream) -> result --- + resource_manager_data_stream_uninit :: proc(pDataStream: ^resource_manager_data_stream) -> result --- + resource_manager_data_stream_read_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + resource_manager_data_stream_seek_to_pcm_frame :: proc(pDataStream: ^resource_manager_data_stream, frameIndex: u64) -> result --- + resource_manager_data_stream_get_data_format :: proc(pDataStream: ^resource_manager_data_stream, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- + resource_manager_data_stream_get_cursor_in_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pCursor: ^u64) -> result --- + resource_manager_data_stream_get_length_in_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pLength: ^u64) -> result --- + resource_manager_data_stream_result :: proc(pDataStream: ^resource_manager_data_stream) -> result --- + resource_manager_data_stream_set_looping :: proc(pDataStream: ^resource_manager_data_stream, isLooping: b32) -> result --- + resource_manager_data_stream_is_looping :: proc(pDataStream: ^resource_manager_data_stream) -> b32 --- + resource_manager_data_stream_get_available_frames :: proc(pDataStream: ^resource_manager_data_stream, pAvailableFrames: ^u64) -> result --- + + /* Data Sources. */ + resource_manager_data_source_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataSource: ^resource_manager_data_source) -> result --- + resource_manager_data_source_init :: proc(pResourceManager: ^resource_manager, pName: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataSource: ^resource_manager_data_source) -> result --- + resource_manager_data_source_init_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataSource: ^resource_manager_data_source) -> result --- + resource_manager_data_source_init_copy :: proc(pResourceManager: ^resource_manager, pExistingDataSource, pDataSource: ^resource_manager_data_source) -> result --- + resource_manager_data_source_uninit :: proc(pDataSource: ^resource_manager_data_source) -> result --- + resource_manager_data_source_read_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + resource_manager_data_source_seek_to_pcm_frame :: proc(pDataSource: ^resource_manager_data_source, frameIndex: u64) -> result --- + resource_manager_data_source_get_data_format :: proc(pDataSource: ^resource_manager_data_source, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- + resource_manager_data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pCursor: ^u64) -> result --- + resource_manager_data_source_get_length_in_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pLength: ^u64) -> result --- + resource_manager_data_source_result :: proc(pDataSource: ^resource_manager_data_source) -> result --- + resource_manager_data_source_set_looping :: proc(pDataSource: ^resource_manager_data_source, isLooping: b32) -> result --- + resource_manager_data_source_is_looping :: proc(pDataSource: ^resource_manager_data_source) -> b32 --- + resource_manager_data_source_get_available_frames :: proc(pDataSource: ^resource_manager_data_source, pAvailableFrames: ^u64) -> result --- + + /* Job management. */ + resource_manager_post_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result --- + resource_manager_post_job_quit :: proc(pResourceManager: ^resource_manager) -> result --- /* Helper for posting a quit job. */ + resource_manager_next_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result --- + resource_manager_process_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result --- /* DEPRECATED. Use ma_job_process(). Will be removed in version 0.12. */ + resource_manager_process_next_job :: proc(pResourceManager: ^resource_manager) -> result --- /* Returns MA_CANCELLED if a MA_JOB_TYPE_QUIT job is found. In non-blocking mode, returns MA_NO_DATA_AVAILABLE if no jobs are available. */ +} diff --git a/vendor/miniaudio/src/miniaudio.h b/vendor/miniaudio/src/miniaudio.h index 5793f20d6..f774f0d5f 100644 --- a/vendor/miniaudio/src/miniaudio.h +++ b/vendor/miniaudio/src/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.10.42 - 2021-08-22 +miniaudio - v0.11.9 - 2022-04-20 David Reid - mackron@gmail.com @@ -12,7 +12,8 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -miniaudio is a single file library for audio playback and capture. To use it, do the following in one .c file: +miniaudio is a single file library for audio playback and capture. To use it, do the following in +one .c file: ```c #define MINIAUDIO_IMPLEMENTATION @@ -21,16 +22,44 @@ miniaudio is a single file library for audio playback and capture. To use it, do You can do `#include "miniaudio.h"` in other parts of the program just like any other header. -miniaudio uses the concept of a "device" as the abstraction for physical devices. The idea is that you choose a physical device to emit or capture audio from, -and then move data to/from the device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a callback which you specify when -initializing the device. +miniaudio includes both low level and high level APIs. The low level API is good for those who want +to do all of their mixing themselves and only require a light weight interface to the underlying +audio device. The high level API is good for those who have complex mixing and effect requirements. -When initializing the device you first need to configure it. The device configuration allows you to specify things like the format of the data delivered via -the callback, the size of the internal buffer and the ID of the device you want to emit or capture audio from. +In miniaudio, objects are transparent structures. Unlike many other libraries, there are no handles +to opaque objects which means you need to allocate memory for objects yourself. In the examples +presented in this documentation you will often see objects declared on the stack. You need to be +careful when translating these examples to your own code so that you don't accidentally declare +your objects on the stack and then cause them to become invalid once the function returns. In +addition, you must ensure the memory address of your objects remain the same throughout their +lifetime. You therefore cannot be making copies of your objects. -Once you have the device configuration set up you can initialize the device. When initializing a device you need to allocate memory for the device object -beforehand. This gives the application complete control over how the memory is allocated. In the example below we initialize a playback device on the stack, -but you could allocate it on the heap if that suits your situation better. +A config/init pattern is used throughout the entire library. The idea is that you set up a config +object and pass that into the initialization routine. The advantage to this system is that the +config object can be initialized with logical defaults and new properties added to it without +breaking the API. The config object can be allocated on the stack and does not need to be +maintained after initialization of the corresponding object. + + +1.1. Low Level API +------------------ +The low level API gives you access to the raw audio data of an audio device. It supports playback, +capture, full-duplex and loopback (WASAPI only). You can enumerate over devices to determine which +physical device(s) you want to connect to. + +The low level API uses the concept of a "device" as the abstraction for physical devices. The idea +is that you choose a physical device to emit or capture audio from, and then move data to/from the +device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a +callback which you specify when initializing the device. + +When initializing the device you first need to configure it. The device configuration allows you to +specify things like the format of the data delivered via the callback, the size of the internal +buffer and the ID of the device you want to emit or capture audio from. + +Once you have the device configuration set up you can initialize the device. When initializing a +device you need to allocate memory for the device object beforehand. This gives the application +complete control over how the memory is allocated. In the example below we initialize a playback +device on the stack, but you could allocate it on the heap if that suits your situation better. ```c void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) @@ -63,20 +92,27 @@ but you could allocate it on the heap if that suits your situation better. } ``` -In the example above, `data_callback()` is where audio data is written and read from the device. The idea is in playback mode you cause sound to be emitted -from the speakers by writing audio data to the output buffer (`pOutput` in the example). In capture mode you read data from the input buffer (`pInput`) to -extract sound captured by the microphone. The `frameCount` parameter tells you how many frames can be written to the output buffer and read from the input -buffer. A "frame" is one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 samples: one for the left, one for the right. -The channel count is defined by the device config. The size in bytes of an individual sample is defined by the sample format which is also specified in the -device config. Multi-channel audio data is always interleaved, which means the samples for each frame are stored next to each other in memory. For example, in -a stereo stream the first pair of samples will be the left and right samples for the first frame, the second pair of samples will be the left and right samples -for the second frame, etc. +In the example above, `data_callback()` is where audio data is written and read from the device. +The idea is in playback mode you cause sound to be emitted from the speakers by writing audio data +to the output buffer (`pOutput` in the example). In capture mode you read data from the input +buffer (`pInput`) to extract sound captured by the microphone. The `frameCount` parameter tells you +how many frames can be written to the output buffer and read from the input buffer. A "frame" is +one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 +samples: one for the left, one for the right. The channel count is defined by the device config. +The size in bytes of an individual sample is defined by the sample format which is also specified +in the device config. Multi-channel audio data is always interleaved, which means the samples for +each frame are stored next to each other in memory. For example, in a stereo stream the first pair +of samples will be the left and right samples for the first frame, the second pair of samples will +be the left and right samples for the second frame, etc. -The configuration of the device is defined by the `ma_device_config` structure. The config object is always initialized with `ma_device_config_init()`. It's -important to always initialize the config with this function as it initializes it with logical defaults and ensures your program doesn't break when new members -are added to the `ma_device_config` structure. The example above uses a fairly simple and standard device configuration. The call to `ma_device_config_init()` -takes a single parameter, which is whether or not the device is a playback, capture, duplex or loopback device (loopback devices are not supported on all -backends). The `config.playback.format` member sets the sample format which can be one of the following (all formats are native-endian): +The configuration of the device is defined by the `ma_device_config` structure. The config object +is always initialized with `ma_device_config_init()`. It's important to always initialize the +config with this function as it initializes it with logical defaults and ensures your program +doesn't break when new members are added to the `ma_device_config` structure. The example above +uses a fairly simple and standard device configuration. The call to `ma_device_config_init()` takes +a single parameter, which is whether or not the device is a playback, capture, duplex or loopback +device (loopback devices are not supported on all backends). The `config.playback.format` member +sets the sample format which can be one of the following (all formats are native-endian): +---------------+----------------------------------------+---------------------------+ | Symbol | Description | Range | @@ -88,22 +124,30 @@ backends). The `config.playback.format` member sets the sample format which can | ma_format_u8 | 8-bit unsigned integer | [0, 255] | +---------------+----------------------------------------+---------------------------+ -The `config.playback.channels` member sets the number of channels to use with the device. The channel count cannot exceed MA_MAX_CHANNELS. The -`config.sampleRate` member sets the sample rate (which must be the same for both playback and capture in full-duplex configurations). This is usually set to -44100 or 48000, but can be set to anything. It's recommended to keep this between 8000 and 384000, however. +The `config.playback.channels` member sets the number of channels to use with the device. The +channel count cannot exceed MA_MAX_CHANNELS. The `config.sampleRate` member sets the sample rate +(which must be the same for both playback and capture in full-duplex configurations). This is +usually set to 44100 or 48000, but can be set to anything. It's recommended to keep this between +8000 and 384000, however. -Note that leaving the format, channel count and/or sample rate at their default values will result in the internal device's native configuration being used -which is useful if you want to avoid the overhead of miniaudio's automatic data conversion. +Note that leaving the format, channel count and/or sample rate at their default values will result +in the internal device's native configuration being used which is useful if you want to avoid the +overhead of miniaudio's automatic data conversion. -In addition to the sample format, channel count and sample rate, the data callback and user data pointer are also set via the config. The user data pointer is -not passed into the callback as a parameter, but is instead set to the `pUserData` member of `ma_device` which you can access directly since all miniaudio -structures are transparent. +In addition to the sample format, channel count and sample rate, the data callback and user data +pointer are also set via the config. The user data pointer is not passed into the callback as a +parameter, but is instead set to the `pUserData` member of `ma_device` which you can access +directly since all miniaudio structures are transparent. -Initializing the device is done with `ma_device_init()`. This will return a result code telling you what went wrong, if anything. On success it will return -`MA_SUCCESS`. After initialization is complete the device will be in a stopped state. To start it, use `ma_device_start()`. Uninitializing the device will stop -it, which is what the example above does, but you can also stop the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again. -Note that it's important to never stop or start the device from inside the callback. This will result in a deadlock. Instead you set a variable or signal an -event indicating that the device needs to stop and handle it in a different thread. The following APIs must never be called inside the callback: +Initializing the device is done with `ma_device_init()`. This will return a result code telling you +what went wrong, if anything. On success it will return `MA_SUCCESS`. After initialization is +complete the device will be in a stopped state. To start it, use `ma_device_start()`. +Uninitializing the device will stop it, which is what the example above does, but you can also stop +the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again. +Note that it's important to never stop or start the device from inside the callback. This will +result in a deadlock. Instead you set a variable or signal an event indicating that the device +needs to stop and handle it in a different thread. The following APIs must never be called inside +the callback: ```c ma_device_init() @@ -113,12 +157,14 @@ event indicating that the device needs to stop and handle it in a different thre ma_device_stop() ``` -You must never try uninitializing and reinitializing a device inside the callback. You must also never try to stop and start it from inside the callback. There -are a few other things you shouldn't do in the callback depending on your requirements, however this isn't so much a thread-safety thing, but rather a -real-time processing thing which is beyond the scope of this introduction. +You must never try uninitializing and reinitializing a device inside the callback. You must also +never try to stop and start it from inside the callback. There are a few other things you shouldn't +do in the callback depending on your requirements, however this isn't so much a thread-safety +thing, but rather a real-time processing thing which is beyond the scope of this introduction. -The example above demonstrates the initialization of a playback device, but it works exactly the same for capture. All you need to do is change the device type -from `ma_device_type_playback` to `ma_device_type_capture` when setting up the config, like so: +The example above demonstrates the initialization of a playback device, but it works exactly the +same for capture. All you need to do is change the device type from `ma_device_type_playback` to +`ma_device_type_capture` when setting up the config, like so: ```c ma_device_config config = ma_device_config_init(ma_device_type_capture); @@ -126,8 +172,9 @@ from `ma_device_type_playback` to `ma_device_type_capture` when setting up the c config.capture.channels = MY_CHANNEL_COUNT; ``` -In the data callback you just read from the input buffer (`pInput` in the example above) and leave the output buffer alone (it will be set to NULL when the -device type is set to `ma_device_type_capture`). +In the data callback you just read from the input buffer (`pInput` in the example above) and leave +the output buffer alone (it will be set to NULL when the device type is set to +`ma_device_type_capture`). These are the available device types and how you should handle the buffers in the callback: @@ -140,23 +187,29 @@ These are the available device types and how you should handle the buffers in th | ma_device_type_loopback | Read from input buffer, leave output buffer untouched. | +-------------------------+--------------------------------------------------------+ -You will notice in the example above that the sample format and channel count is specified separately for playback and capture. This is to support different -data formats between the playback and capture devices in a full-duplex system. An example may be that you want to capture audio data as a monaural stream (one -channel), but output sound to a stereo speaker system. Note that if you use different formats between playback and capture in a full-duplex configuration you -will need to convert the data yourself. There are functions available to help you do this which will be explained later. +You will notice in the example above that the sample format and channel count is specified +separately for playback and capture. This is to support different data formats between the playback +and capture devices in a full-duplex system. An example may be that you want to capture audio data +as a monaural stream (one channel), but output sound to a stereo speaker system. Note that if you +use different formats between playback and capture in a full-duplex configuration you will need to +convert the data yourself. There are functions available to help you do this which will be +explained later. -The example above did not specify a physical device to connect to which means it will use the operating system's default device. If you have multiple physical -devices connected and you want to use a specific one you will need to specify the device ID in the configuration, like so: +The example above did not specify a physical device to connect to which means it will use the +operating system's default device. If you have multiple physical devices connected and you want to +use a specific one you will need to specify the device ID in the configuration, like so: ```c config.playback.pDeviceID = pMyPlaybackDeviceID; // Only if requesting a playback or duplex device. config.capture.pDeviceID = pMyCaptureDeviceID; // Only if requesting a capture, duplex or loopback device. ``` -To retrieve the device ID you will need to perform device enumeration, however this requires the use of a new concept called the "context". Conceptually -speaking the context sits above the device. There is one context to many devices. The purpose of the context is to represent the backend at a more global level -and to perform operations outside the scope of an individual device. Mainly it is used for performing run-time linking against backend libraries, initializing -backends and enumerating devices. The example below shows how to enumerate devices. +To retrieve the device ID you will need to perform device enumeration, however this requires the +use of a new concept called the "context". Conceptually speaking the context sits above the device. +There is one context to many devices. The purpose of the context is to represent the backend at a +more global level and to perform operations outside the scope of an individual device. Mainly it is +used for performing run-time linking against backend libraries, initializing backends and +enumerating devices. The example below shows how to enumerate devices. ```c ma_context context; @@ -197,44 +250,236 @@ backends and enumerating devices. The example below shows how to enumerate devic ma_context_uninit(&context); ``` -The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. The first parameter is a pointer to a list of `ma_backend` -values which are used to override the default backend priorities. When this is NULL, as in this example, miniaudio's default priorities are used. The second -parameter is the number of backends listed in the array pointed to by the first parameter. The third parameter is a pointer to a `ma_context_config` object -which can be NULL, in which case defaults are used. The context configuration is used for setting the logging callback, custom memory allocation callbacks, -user-defined data and some backend-specific configurations. +The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. +The first parameter is a pointer to a list of `ma_backend` values which are used to override the +default backend priorities. When this is NULL, as in this example, miniaudio's default priorities +are used. The second parameter is the number of backends listed in the array pointed to by the +first parameter. The third parameter is a pointer to a `ma_context_config` object which can be +NULL, in which case defaults are used. The context configuration is used for setting the logging +callback, custom memory allocation callbacks, user-defined data and some backend-specific +configurations. -Once the context has been initialized you can enumerate devices. In the example above we use the simpler `ma_context_get_devices()`, however you can also use a -callback for handling devices by using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer to a pointer that will, -upon output, be set to a pointer to a buffer containing a list of `ma_device_info` structures. You also provide a pointer to an unsigned integer that will -receive the number of items in the returned buffer. Do not free the returned buffers as their memory is managed internally by miniaudio. +Once the context has been initialized you can enumerate devices. In the example above we use the +simpler `ma_context_get_devices()`, however you can also use a callback for handling devices by +using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer +to a pointer that will, upon output, be set to a pointer to a buffer containing a list of +`ma_device_info` structures. You also provide a pointer to an unsigned integer that will receive +the number of items in the returned buffer. Do not free the returned buffers as their memory is +managed internally by miniaudio. -The `ma_device_info` structure contains an `id` member which is the ID you pass to the device config. It also contains the name of the device which is useful -for presenting a list of devices to the user via the UI. +The `ma_device_info` structure contains an `id` member which is the ID you pass to the device +config. It also contains the name of the device which is useful for presenting a list of devices +to the user via the UI. -When creating your own context you will want to pass it to `ma_device_init()` when initializing the device. Passing in NULL, like we do in the first example, -will result in miniaudio creating the context for you, which you don't want to do since you've already created a context. Note that internally the context is -only tracked by it's pointer which means you must not change the location of the `ma_context` object. If this is an issue, consider using `malloc()` to -allocate memory for the context. +When creating your own context you will want to pass it to `ma_device_init()` when initializing the +device. Passing in NULL, like we do in the first example, will result in miniaudio creating the +context for you, which you don't want to do since you've already created a context. Note that +internally the context is only tracked by it's pointer which means you must not change the location +of the `ma_context` object. If this is an issue, consider using `malloc()` to allocate memory for +the context. + + +1.2. High Level API +------------------- +The high level API consists of three main parts: + + * Resource management for loading and streaming sounds. + * A node graph for advanced mixing and effect processing. + * A high level "engine" that wraps around the resource manager and node graph. + +The resource manager (`ma_resource_manager`) is used for loading sounds. It supports loading sounds +fully into memory and also streaming. It will also deal with reference counting for you which +avoids the same sound being loaded multiple times. + +The node graph is used for mixing and effect processing. The idea is that you connect a number of +nodes into the graph by connecting each node's outputs to another node's inputs. Each node can +implement it's own effect. By chaining nodes together, advanced mixing and effect processing can +be achieved. + +The engine encapsulates both the resource manager and the node graph to create a simple, easy to +use high level API. The resource manager and node graph APIs are covered in more later sections of +this manual. + +The code below shows how you can initialize an engine using it's default configuration. + + ```c + ma_result result; + ma_engine engine; + + result = ma_engine_init(NULL, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +This creates an engine instance which will initialize a device internally which you can access with +`ma_engine_get_device()`. It will also initialize a resource manager for you which can be accessed +with `ma_engine_get_resource_manager()`. The engine itself is a node graph (`ma_node_graph`) which +means you can pass a pointer to the engine object into any of the `ma_node_graph` APIs (with a +cast). Alternatively, you can use `ma_engine_get_node_graph()` instead of a cast. + +Note that all objects in miniaudio, including the `ma_engine` object in the example above, are +transparent structures. There are no handles to opaque structures in miniaudio which means you need +to be mindful of how you declare them. In the example above we are declaring it on the stack, but +this will result in the struct being invalidated once the function encapsulating it returns. If +allocating the engine on the heap is more appropriate, you can easily do so with a standard call +to `malloc()` or whatever heap allocation routine you like: + + ```c + ma_engine* pEngine = malloc(sizeof(*pEngine)); + ``` + +The `ma_engine` API uses the same config/init pattern used all throughout miniaudio. To configure +an engine, you can fill out a `ma_engine_config` object and pass it into the first parameter of +`ma_engine_init()`: + + ```c + ma_result result; + ma_engine engine; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.pResourceManager = &myCustomResourceManager; // <-- Initialized as some earlier stage. + + result = ma_engine_init(&engineConfig, &engine); + if (result != MA_SUCCESS) { + return result; + } + ``` + +This creates an engine instance using a custom config. In this particular example it's showing how +you can specify a custom resource manager rather than having the engine initialize one internally. +This is particularly useful if you want to have multiple engine's share the same resource manager. + +The engine must be uninitialized with `ma_engine_uninit()` when it's no longer needed. + +By default the engine will be started, but nothing will be playing because no sounds have been +initialized. The easiest but least flexible way of playing a sound is like so: + + ```c + ma_engine_play_sound(&engine, "my_sound.wav", NULL); + ``` + +This plays what miniaudio calls an "inline" sound. It plays the sound once, and then puts the +internal sound up for recycling. The last parameter is used to specify which sound group the sound +should be associated with which will be explained later. This particular way of playing a sound is +simple, but lacks flexibility and features. A more flexible way of playing a sound is to first +initialize a sound: + + ```c + ma_result result; + ma_sound sound; + + result = ma_sound_init_from_file(&engine, "my_sound.wav", 0, NULL, NULL, &sound); + if (result != MA_SUCCESS) { + return result; + } + + ma_sound_start(&sound); + ``` + +This returns a `ma_sound` object which represents a single instance of the specified sound file. If +you want to play the same file multiple times simultaneously, you need to create one sound for each +instance. + +Sounds should be uninitialized with `ma_sound_uninit()`. + +Sounds are not started by default. Start a sound with `ma_sound_start()` and stop it with +`ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use +`ma_sound_seek_to_pcm_frames(&sound, 0)` to seek back to the start of a sound. By default, starting +and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound +the be started and/or stopped at a specific time. This can be done with the following functions: + + ```c + ma_sound_set_start_time_in_pcm_frames() + ma_sound_set_start_time_in_milliseconds() + ma_sound_set_stop_time_in_pcm_frames() + ma_sound_set_stop_time_in_milliseconds() + ``` + +The start/stop time needs to be specified based on the absolute timer which is controlled by the +engine. The current global time time in PCM frames can be retrieved with `ma_engine_get_time()`. +The engine's global time can be changed with `ma_engine_set_time()` for synchronization purposes if +required. Note that scheduling a start time still requires an explicit call to `ma_sound_start()` +before anything will play: + + ```c + ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 2); + ma_sound_start(&sound); + ``` + +The third parameter of `ma_sound_init_from_file()` is a set of flags that control how the sound be +loaded and a few options on which features should be enabled for that sound. By default, the sound +is synchronously loaded fully into memory straight from the file system without any kind of +decoding. If you want to decode the sound before storing it in memory, you need to specify the +`MA_SOUND_FLAG_DECODE` flag. This is useful if you want to incur the cost of decoding at an earlier +stage, such as a loading stage. Without this option, decoding will happen dynamically at mixing +time which might be too expensive on the audio thread. + +If you want to load the sound asynchronously, you can specify the `MA_SOUND_FLAG_ASYNC` flag. This +will result in `ma_sound_init_from_file()` returning quickly, but the sound will not start playing +until the sound has had some audio decoded. + +The fourth parameter is a pointer to sound group. A sound group is used as a mechanism to organise +sounds into groups which have their own effect processing and volume control. An example is a game +which might have separate groups for sfx, voice and music. Each of these groups have their own +independent volume control. Use `ma_sound_group_init()` or `ma_sound_group_init_ex()` to initialize +a sound group. + +Sounds and sound groups are nodes in the engine's node graph and can be plugged into any `ma_node` +API. This makes it possible to connect sounds and sound groups to effect nodes to produce complex +effect chains. + +A sound can have it's volume changed with `ma_sound_set_volume()`. If you prefer decibel volume +control you can use `ma_volume_db_to_linear()` to convert from decibel representation to linear. + +Panning and pitching is supported with `ma_sound_set_pan()` and `ma_sound_set_pitch()`. If you know +a sound will never have it's pitch changed with `ma_sound_set_pitch()` or via the doppler effect, +you can specify the `MA_SOUND_FLAG_NO_PITCH` flag when initializing the sound for an optimization. + +By default, sounds and sound groups have spatialization enabled. If you don't ever want to +spatialize your sounds, initialize the sound with the `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. The +spatialization model is fairly simple and is roughly on feature parity with OpenAL. HRTF and +environmental occlusion are not currently supported, but planned for the future. The supported +features include: + + * Sound and listener positioning and orientation with cones + * Attenuation models: none, inverse, linear and exponential + * Doppler effect + +Sounds can be faded in and out with `ma_sound_set_fade_in_pcm_frames()`. + +To check if a sound is currently playing, you can use `ma_sound_is_playing()`. To check if a sound +is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled with +`ma_sound_set_looping()`. Use `ma_sound_is_looping()` to check whether or not the sound is looping. 2. Building =========== -miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. +miniaudio should work cleanly out of the box without the need to download or install any +dependencies. See below for platform-specific details. 2.1. Windows ------------ -The Windows build should compile cleanly on all popular compilers without the need to configure any include paths nor link to any libraries. +The Windows build should compile cleanly on all popular compilers without the need to configure any +include paths nor link to any libraries. + +The UWP build may require linking to mmdevapi.lib if you get errors about an unresolved external +symbol for `ActivateAudioInterfaceAsync()`. + 2.2. macOS and iOS ------------------ -The macOS build should compile cleanly without the need to download any dependencies nor link to any libraries or frameworks. The iOS build needs to be -compiled as Objective-C and will need to link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling through the command line -requires linking to `-lpthread` and `-lm`. +The macOS build should compile cleanly without the need to download any dependencies nor link to +any libraries or frameworks. The iOS build needs to be compiled as Objective-C and will need to +link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling +through the command line requires linking to `-lpthread` and `-lm`. -Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's notarization process. To fix this there are two options. The -first is to use the `MA_NO_RUNTIME_LINKING` option, like so: +Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's +notarization process. To fix this there are two options. The first is to use the +`MA_NO_RUNTIME_LINKING` option, like so: ```c #ifdef __APPLE__ @@ -244,8 +489,9 @@ first is to use the `MA_NO_RUNTIME_LINKING` option, like so: #include "miniaudio.h" ``` -This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. Alternatively, if you would rather keep using runtime -linking you can add the following to your entitlements.xcent file: +This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. +Alternatively, if you would rather keep using runtime linking you can add the following to your +entitlements.xcent file: ``` com.apple.security.cs.allow-dyld-environment-variables @@ -254,26 +500,37 @@ linking you can add the following to your entitlements.xcent file: ``` +See this discussion for more info: https://github.com/mackron/miniaudio/issues/203. + 2.3. Linux ---------- -The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any development packages. +The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any +development packages. You may need to link with `-latomic` if you're compiling for 32-bit ARM. + 2.4. BSD -------- -The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS. +The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses +sndio and FreeBSD uses OSS. You may need to link with `-latomic` if you're compiling for 32-bit +ARM. + 2.5. Android ------------ -AAudio is the highest priority backend on Android. This should work out of the box without needing any kind of compiler configuration. Support for AAudio -starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+. +AAudio is the highest priority backend on Android. This should work out of the box without needing +any kind of compiler configuration. Support for AAudio starts with Android 8 which means older +versions will fall back to OpenSL|ES which requires API level 16+. + +There have been reports that the OpenSL|ES backend fails to initialize on some Android based +devices due to `dlopen()` failing to open "libOpenSLES.so". If this happens on your platform +you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES. -There have been reports that the OpenSL|ES backend fails to initialize on some Android based devices due to `dlopen()` failing to open "libOpenSLES.so". If -this happens on your platform you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES. 2.6. Emscripten --------------- -The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use -std=c* compiler flags, nor -ansi. +The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. +You cannot use `-std=c*` compiler flags, nor `-ansi`. 2.7. Build Options @@ -366,28 +623,26 @@ The Emscripten build emits Web Audio JavaScript directly and should compile clea +----------------------------------+--------------------------------------------------------------------+ | MA_NO_MP3 | Disables the built-in MP3 decoder. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_DEVICE_IO | Disables playback and recording. This will disable ma_context and | - | | ma_device APIs. This is useful if you only want to use miniaudio's | - | | data conversion and/or decoding APIs. | + | MA_NO_DEVICE_IO | Disables playback and recording. This will disable `ma_context` | + | | and `ma_device` APIs. This is useful if you only want to use | + | | miniaudio's data conversion and/or decoding APIs. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_THREADING | Disables the ma_thread, ma_mutex, ma_semaphore and ma_event APIs. | - | | This option is useful if you only need to use miniaudio for data | - | | conversion, decoding and/or encoding. Some families of APIs | - | | require threading which means the following options must also be | - | | set: | + | MA_NO_THREADING | Disables the `ma_thread`, `ma_mutex`, `ma_semaphore` and | + | | `ma_event` APIs. This option is useful if you only need to use | + | | miniaudio for data conversion, decoding and/or encoding. Some | + | | families of APIsrequire threading which means the following | + | | options must also be set: | | | | | | ``` | | | MA_NO_DEVICE_IO | | | ``` | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_GENERATION | Disables generation APIs such a ma_waveform and ma_noise. | + | MA_NO_GENERATION | Disables generation APIs such a `ma_waveform` and `ma_noise`. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_SSE2 | Disables SSE2 optimizations. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_AVX2 | Disables AVX2 optimizations. | +----------------------------------+--------------------------------------------------------------------+ - | MA_NO_AVX512 | Disables AVX-512 optimizations. | - +----------------------------------+--------------------------------------------------------------------+ | MA_NO_NEON | Disables NEON optimizations. | +----------------------------------+--------------------------------------------------------------------+ | MA_NO_RUNTIME_LINKING | Disables runtime linking. This is useful for passing Apple's | @@ -399,47 +654,47 @@ The Emscripten build emits Web Audio JavaScript directly and should compile clea | | You may need to enable this if your target platform does not allow | | | runtime linking via `dlopen()`. | +----------------------------------+--------------------------------------------------------------------+ - | MA_DEBUG_OUTPUT | Enable processing of MA_LOG_LEVEL_DEBUG messages and `printf()` | - | | output. | + | MA_DEBUG_OUTPUT | Enable `printf()` output of debug logs (`MA_LOG_LEVEL_DEBUG`). | +----------------------------------+--------------------------------------------------------------------+ | MA_COINIT_VALUE | Windows only. The value to pass to internal calls to | | | `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`. | +----------------------------------+--------------------------------------------------------------------+ | MA_API | Controls how public APIs should be decorated. Default is `extern`. | +----------------------------------+--------------------------------------------------------------------+ - | MA_DLL | If set, configures MA_API to either import or export APIs | - | | depending on whether or not the implementation is being defined. | - | | If defining the implementation, MA_API will be configured to | - | | export. Otherwise it will be configured to import. This has no | - | | effect if MA_API is defined externally. | - +----------------------------------+--------------------------------------------------------------------+ 3. Definitions ============== -This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this -section is intended to clarify how miniaudio uses each term. +This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity +in the use of terms throughout the audio space, so this section is intended to clarify how miniaudio +uses each term. 3.1. Sample ----------- -A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit floating point number. +A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit +floating point number. 3.2. Frame / PCM Frame ---------------------- -A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 samples, a mono frame is 1 sample, a 5.1 surround sound frame -is 6 samples, etc. The terms "frame" and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio -needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it's referring to with something like "FLAC frame". +A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 +samples, a mono frame is 1 sample, a 5.1 surround sound frame is 6 samples, etc. The terms "frame" +and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. +If ever miniaudio needs to refer to a compressed frame, such as a FLAC frame, it will always +clarify what it's referring to with something like "FLAC frame". 3.3. Channel ------------ -A stream of monaural audio that is emitted from an individual speaker in a speaker system, or received from an individual microphone in a microphone system. A -stereo stream has two channels (a left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio systems refer to a channel as -a complex audio stream that's mixed with other channels to produce the final mix - this is completely different to miniaudio's use of the term "channel" and -should not be confused. +A stream of monaural audio that is emitted from an individual speaker in a speaker system, or +received from an individual microphone in a microphone system. A stereo stream has two channels (a +left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio +systems refer to a channel as a complex audio stream that's mixed with other channels to produce +the final mix - this is completely different to miniaudio's use of the term "channel" and should +not be confused. 3.4. Sample Rate ---------------- -The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number of PCM frames that are processed per second. +The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number +of PCM frames that are processed per second. 3.5. Formats ------------ @@ -459,10 +714,1685 @@ All formats are native-endian. -4. Decoding +4. Data Sources +=============== +The data source abstraction in miniaudio is used for retrieving audio data from some source. A few +examples include `ma_decoder`, `ma_noise` and `ma_waveform`. You will need to be familiar with data +sources in order to make sense of some of the higher level concepts in miniaudio. + +The `ma_data_source` API is a generic interface for reading from a data source. Any object that +implements the data source interface can be plugged into any `ma_data_source` function. + +To read data from a data source: + + ```c + ma_result result; + ma_uint64 framesRead; + + result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, &framesRead, loop); + if (result != MA_SUCCESS) { + return result; // Failed to read data from the data source. + } + ``` + +If you don't need the number of frames that were successfully read you can pass in `NULL` to the +`pFramesRead` parameter. If this returns a value less than the number of frames requested it means +the end of the file has been reached. `MA_AT_END` will be returned only when the number of frames +read is 0. + +When calling any data source function, with the exception of `ma_data_source_init()` and +`ma_data_source_uninit()`, you can pass in any object that implements a data source. For example, +you could plug in a decoder like so: + + ```c + ma_result result; + ma_uint64 framesRead; + ma_decoder decoder; // <-- This would be initialized with `ma_decoder_init_*()`. + + result = ma_data_source_read_pcm_frames(&decoder, pFramesOut, frameCount, &framesRead, loop); + if (result != MA_SUCCESS) { + return result; // Failed to read data from the decoder. + } + ``` + +If you want to seek forward you can pass in `NULL` to the `pFramesOut` parameter. Alternatively you +can use `ma_data_source_seek_pcm_frames()`. + +To seek to a specific PCM frame: + + ```c + result = ma_data_source_seek_to_pcm_frame(pDataSource, frameIndex); + if (result != MA_SUCCESS) { + return result; // Failed to seek to PCM frame. + } + ``` + +You can retrieve the total length of a data source in PCM frames, but note that some data sources +may not have the notion of a length, such as noise and waveforms, and others may just not have a +way of determining the length such as some decoders. To retrieve the length: + + ```c + ma_uint64 length; + + result = ma_data_source_get_length_in_pcm_frames(pDataSource, &length); + if (result != MA_SUCCESS) { + return result; // Failed to retrieve the length. + } + ``` + +Care should be taken when retrieving the length of a data source where the underlying decoder is +pulling data from a data stream with an undefined length, such as internet radio or some kind of +broadcast. If you do this, `ma_data_source_get_length_in_pcm_frames()` may never return. + +The current position of the cursor in PCM frames can also be retrieved: + + ```c + ma_uint64 cursor; + + result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursor); + if (result != MA_SUCCESS) { + return result; // Failed to retrieve the cursor. + } + ``` + +You will often need to know the data format that will be returned after reading. This can be +retrieved like so: + + ```c + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_channel channelMap[MA_MAX_CHANNELS]; + + result = ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS); + if (result != MA_SUCCESS) { + return result; // Failed to retrieve data format. + } + ``` + +If you do not need a specific data format property, just pass in NULL to the respective parameter. + +There may be cases where you want to implement something like a sound bank where you only want to +read data within a certain range of the underlying data. To do this you can use a range: + + ```c + result = ma_data_source_set_range_in_pcm_frames(pDataSource, rangeBegInFrames, rangeEndInFrames); + if (result != MA_SUCCESS) { + return result; // Failed to set the range. + } + ``` + +This is useful if you have a sound bank where many sounds are stored in the same file and you want +the data source to only play one of those sub-sounds. + +Custom loop points can also be used with data sources. By default, data sources will loop after +they reach the end of the data source, but if you need to loop at a specific location, you can do +the following: + + ```c + result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); + if (result != MA_SUCCESS) { + return result; // Failed to set the loop point. + } + ``` + +The loop point is relative to the current range. + +It's sometimes useful to chain data sources together so that a seamless transition can be achieved. +To do this, you can use chaining: + + ```c + ma_decoder decoder1; + ma_decoder decoder2; + + // ... initialize decoders with ma_decoder_init_*() ... + + result = ma_data_source_set_next(&decoder1, &decoder2); + if (result != MA_SUCCESS) { + return result; // Failed to set the next data source. + } + + result = ma_data_source_read_pcm_frames(&decoder1, pFramesOut, frameCount, pFramesRead, MA_FALSE); + if (result != MA_SUCCESS) { + return result; // Failed to read from the decoder. + } + ``` + +In the example above we're using decoders. When reading from a chain, you always want to read from +the top level data source in the chain. In the example above, `decoder1` is the top level data +source in the chain. When `decoder1` reaches the end, `decoder2` will start seamlessly without any +gaps. + +Note that the `loop` parameter is set to false in the example above. When this is set to true, only +the current data source will be looped. You can loop the entire chain by linking in a loop like so: + + ```c + ma_data_source_set_next(&decoder1, &decoder2); // decoder1 -> decoder2 + ma_data_source_set_next(&decoder2, &decoder1); // decoder2 -> decoder1 (loop back to the start). + ``` + +Note that setting up chaining is not thread safe, so care needs to be taken if you're dynamically +changing links while the audio thread is in the middle of reading. + +Do not use `ma_decoder_seek_to_pcm_frame()` as a means to reuse a data source to play multiple +instances of the same sound simultaneously. Instead, initialize multiple data sources for each +instance. This can be extremely inefficient depending on the data source and can result in +glitching due to subtle changes to the state of internal filters. + + +4.1. Custom Data Sources +------------------------ +You can implement a custom data source by implementing the functions in `ma_data_source_vtable`. +Your custom object must have `ma_data_source_base` as it's first member: + + ```c + struct my_data_source + { + ma_data_source_base base; + ... + }; + ``` + +In your initialization routine, you need to call `ma_data_source_init()` in order to set up the +base object (`ma_data_source_base`): + + ```c + static ma_result my_data_source_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) + { + // Read data here. Output in the same format returned by my_data_source_get_data_format(). + } + + static ma_result my_data_source_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) + { + // Seek to a specific PCM frame here. Return MA_NOT_IMPLEMENTED if seeking is not supported. + } + + static ma_result my_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) + { + // Return the format of the data here. + } + + static ma_result my_data_source_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) + { + // Retrieve the current position of the cursor here. Return MA_NOT_IMPLEMENTED and set *pCursor to 0 if there is no notion of a cursor. + } + + static ma_result my_data_source_get_length(ma_data_source* pDataSource, ma_uint64* pLength) + { + // Retrieve the length in PCM frames here. Return MA_NOT_IMPLEMENTED and set *pLength to 0 if there is no notion of a length or if the length is unknown. + } + + static g_my_data_source_vtable = + { + my_data_source_read, + my_data_source_seek, + my_data_source_get_data_format, + my_data_source_get_cursor, + my_data_source_get_length + }; + + ma_result my_data_source_init(my_data_source* pMyDataSource) + { + ma_result result; + ma_data_source_config baseConfig; + + baseConfig = ma_data_source_config_init(); + baseConfig.vtable = &g_my_data_source_vtable; + + result = ma_data_source_init(&baseConfig, &pMyDataSource->base); + if (result != MA_SUCCESS) { + return result; + } + + // ... do the initialization of your custom data source here ... + + return MA_SUCCESS; + } + + void my_data_source_uninit(my_data_source* pMyDataSource) + { + // ... do the uninitialization of your custom data source here ... + + // You must uninitialize the base data source. + ma_data_source_uninit(&pMyDataSource->base); + } + ``` + +Note that `ma_data_source_init()` and `ma_data_source_uninit()` are never called directly outside +of the custom data source. It's up to the custom data source itself to call these within their own +init/uninit functions. + + + +5. Engine +========= +The `ma_engine` API is a high level API for managing and mixing sounds and effect processing. The +`ma_engine` object encapsulates a resource manager and a node graph, both of which will be +explained in more detail later. + +Sounds are called `ma_sound` and are created from an engine. Sounds can be associated with a mixing +group called `ma_sound_group` which are also created from the engine. Both `ma_sound` and +`ma_sound_group` objects are nodes within the engine's node graph. + +When the engine is initialized, it will normally create a device internally. If you would rather +manage the device yourself, you can do so and just pass a pointer to it via the engine config when +you initialize the engine. You can also just use the engine without a device, which again can be +configured via the engine config. + +The most basic way to initialize the engine is with a default config, like so: + + ```c + ma_result result; + ma_engine engine; + + result = ma_engine_init(NULL, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +This will result in the engine initializing a playback device using the operating system's default +device. This will be sufficient for many use cases, but if you need more flexibility you'll want to +configure the engine with an engine config: + + ```c + ma_result result; + ma_engine engine; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.pPlaybackDevice = &myDevice; + + result = ma_engine_init(&engineConfig, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +In the example above we're passing in a pre-initialized device. Since the caller is the one in +control of the device's data callback, it's their responsibility to manually call +`ma_engine_read_pcm_frames()` from inside their data callback: + + ```c + void playback_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) + { + ma_engine_read_pcm_frames(&g_Engine, pOutput, frameCount, NULL); + } + ``` + +You can also use the engine independent of a device entirely: + + ```c + ma_result result; + ma_engine engine; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.noDevice = MA_TRUE; + engineConfig.channels = 2; // Must be set when not using a device. + engineConfig.sampleRate = 48000; // Must be set when not using a device. + + result = ma_engine_init(&engineConfig, &engine); + if (result != MA_SUCCESS) { + return result; // Failed to initialize the engine. + } + ``` + +Note that when you're not using a device, you must set the channel count and sample rate in the +config or else miniaudio won't know what to use (miniaudio will use the device to determine this +normally). When not using a device, you need to use `ma_engine_read_pcm_frames()` to process audio +data from the engine. This kind of setup is useful if you want to do something like offline +processing. + +When a sound is loaded it goes through a resource manager. By default the engine will initialize a +resource manager internally, but you can also specify a pre-initialized resource manager: + + ```c + ma_result result; + ma_engine engine1; + ma_engine engine2; + ma_engine_config engineConfig; + + engineConfig = ma_engine_config_init(); + engineConfig.pResourceManager = &myResourceManager; + + ma_engine_init(&engineConfig, &engine1); + ma_engine_init(&engineConfig, &engine2); + ``` + +In this example we are initializing two engines, both of which are sharing the same resource +manager. This is especially useful for saving memory when loading the same file across multiple +engines. If you were not to use a shared resource manager, each engine instance would use their own +which would result in any sounds that are used between both engine's being loaded twice. By using +a shared resource manager, it would only be loaded once. Using multiple engine's is useful when you +need to output to multiple playback devices, such as in a local multiplayer game where each player +is using their own set of headphones. + +By default an engine will be in a started state. To make it so the engine is not automatically +started you can configure it as such: + + ```c + engineConfig.noAutoStart = MA_TRUE; + + // The engine will need to be started manually. + ma_engine_start(&engine); + + // Later on the engine can be stopped with ma_engine_stop(). + ma_engine_stop(&engine); + ``` + +The concept of starting or stopping an engine is only relevant when using the engine with a +device. Attempting to start or stop an engine that is not associated with a device will result in +`MA_INVALID_OPERATION`. + +The master volume of the engine can be controlled with `ma_engine_set_volume()` which takes a +linear scale, with 0 resulting in silence and anything above 1 resulting in amplification. If you +prefer decibel based volume control, use `ma_volume_db_to_linear()` to convert from dB to linear. + +When a sound is spatialized, it is done so relative to a listener. An engine can be configured to +have multiple listeners which can be configured via the config: + + ```c + engineConfig.listenerCount = 2; + ``` + +The maximum number of listeners is restricted to `MA_ENGINE_MAX_LISTENERS`. By default, when a +sound is spatialized, it will be done so relative to the closest listener. You can also pin a sound +to a specific listener which will be explained later. Listener's have a position, direction, cone, +and velocity (for doppler effect). A listener is referenced by an index, the meaning of which is up +to the caller (the index is 0 based and cannot go beyond the listener count, minus 1). The +position, direction and velocity are all specified in absolute terms: + + ```c + ma_engine_listener_set_position(&engine, listenerIndex, worldPosX, worldPosY, worldPosZ); + ``` + +The direction of the listener represents it's forward vector. The listener's up vector can also be +specified and defaults to +1 on the Y axis. + + ```c + ma_engine_listener_set_direction(&engine, listenerIndex, forwardX, forwardY, forwardZ); + ma_engine_listener_set_world_up(&engine, listenerIndex, 0, 1, 0); + ``` + +The engine supports directional attenuation. The listener can have a cone the controls how sound is +attenuated based on the listener's direction. When a sound is between the inner and outer cones, it +will be attenuated between 1 and the cone's outer gain: + + ```c + ma_engine_listener_set_cone(&engine, listenerIndex, innerAngleInRadians, outerAngleInRadians, outerGain); + ``` + +When a sound is inside the inner code, no directional attenuation is applied. When the sound is +outside of the outer cone, the attenuation will be set to `outerGain` in the example above. When +the sound is in between the inner and outer cones, the attenuation will be interpolated between 1 +and the outer gain. + +The engine's coordinate system follows the OpenGL coordinate system where positive X points right, +positive Y points up and negative Z points forward. + +The simplest and least flexible way to play a sound is like so: + + ```c + ma_engine_play_sound(&engine, "my_sound.wav", pGroup); + ``` + +This is a "fire and forget" style of function. The engine will manage the `ma_sound` object +internally. When the sound finishes playing, it'll be put up for recycling. For more flexibility +you'll want to initialize a sound object: + + ```c + ma_sound sound; + + result = ma_sound_init_from_file(&engine, "my_sound.wav", flags, pGroup, NULL, &sound); + if (result != MA_SUCCESS) { + return result; // Failed to load sound. + } + ``` + +Sounds need to be uninitialized with `ma_sound_uninit()`. + +The example above loads a sound from a file. If the resource manager has been disabled you will not +be able to use this function and instead you'll need to initialize a sound directly from a data +source: + + ```c + ma_sound sound; + + result = ma_sound_init_from_data_source(&engine, &dataSource, flags, pGroup, &sound); + if (result != MA_SUCCESS) { + return result; + } + ``` + +Each `ma_sound` object represents a single instance of the sound. If you want to play the same +sound multiple times at the same time, you need to initialize a separate `ma_sound` object. + +For the most flexibility when initializing sounds, use `ma_sound_init_ex()`. This uses miniaudio's +standard config/init pattern: + + ```c + ma_sound sound; + ma_sound_config soundConfig; + + soundConfig = ma_sound_config_init(); + soundConfig.pFilePath = NULL; // Set this to load from a file path. + soundConfig.pDataSource = NULL; // Set this to initialize from an existing data source. + soundConfig.pInitialAttachment = &someNodeInTheNodeGraph; + soundConfig.initialAttachmentInputBusIndex = 0; + soundConfig.channelsIn = 1; + soundConfig.channelsOut = 0; // Set to 0 to use the engine's native channel count. + + result = ma_sound_init_ex(&soundConfig, &sound); + if (result != MA_SUCCESS) { + return result; + } + ``` + +In the example above, the sound is being initialized without a file nor a data source. This is +valid, in which case the sound acts as a node in the middle of the node graph. This means you can +connect other sounds to this sound and allow it to act like a sound group. Indeed, this is exactly +what a `ma_sound_group` is. + +When loading a sound, you specify a set of flags that control how the sound is loaded and what +features are enabled for that sound. When no flags are set, the sound will be fully loaded into +memory in exactly the same format as how it's stored on the file system. The resource manager will +allocate a block of memory and then load the file directly into it. When reading audio data, it +will be decoded dynamically on the fly. In order to save processing time on the audio thread, it +might be beneficial to pre-decode the sound. You can do this with the `MA_SOUND_FLAG_DECODE` flag: + + ```c + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE, pGroup, NULL, &sound); + ``` + +By default, sounds will be loaded synchronously, meaning `ma_sound_init_*()` will not return until +the sound has been fully loaded. If this is prohibitive you can instead load sounds asynchronously +by specificying the `MA_SOUND_FLAG_ASYNC` flag: + + ```c + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, NULL, &sound); + ``` + +This will result in `ma_sound_init_*()` returning quickly, but the sound won't yet have been fully +loaded. When you start the sound, it won't output anything until some sound is available. The sound +will start outputting audio before the sound has been fully decoded when the `MA_SOUND_FLAG_DECODE` +is specified. + +If you need to wait for an asynchronously loaded sound to be fully loaded, you can use a fence. A +fence in miniaudio is a simple synchronization mechanism which simply blocks until it's internal +counter hit's zero. You can specify a fence like so: + + ```c + ma_result result; + ma_fence fence; + ma_sound sounds[4]; + + result = ma_fence_init(&fence); + if (result != MA_SUCCES) { + return result; + } + + // Load some sounds asynchronously. + for (int iSound = 0; iSound < 4; iSound += 1) { + ma_sound_init_from_file(&engine, mySoundFilesPaths[iSound], MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, &fence, &sounds[iSound]); + } + + // ... do some other stuff here in the mean time ... + + // Wait for all sounds to finish loading. + ma_fence_wait(&fence); + ``` + +If loading the entire sound into memory is prohibitive, you can also configure the engine to stream +the audio data: + + ```c + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_STREAM, pGroup, NULL, &sound); + ``` + +When streaming sounds, 2 seconds worth of audio data is stored in memory. Although it should work +fine, it's inefficient to use streaming for short sounds. Streaming is useful for things like music +tracks in games. + +When you initialize a sound, if you specify a sound group the sound will be attached to that group +automatically. If you set it to NULL, it will be automatically attached to the engine's endpoint. +If you would instead rather leave the sound unattached by default, you can can specify the +`MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT` flag. This is useful if you want to set up a complex node +graph. + +Sounds are not started by default. To start a sound, use `ma_sound_start()`. Stop a sound with +`ma_sound_stop()`. + +Sounds can have their volume controlled with `ma_sound_set_volume()` in the same way as the +engine's master volume. + +Sounds support stereo panning and pitching. Set the pan with `ma_sound_set_pan()`. Setting the pan +to 0 will result in an unpanned sound. Setting it to -1 will shift everything to the left, whereas ++1 will shift it to the right. The pitch can be controlled with `ma_sound_set_pitch()`. A larger +value will result in a higher pitch. The pitch must be greater than 0. + +The engine supports 3D spatialization of sounds. By default sounds will have spatialization +enabled, but if a sound does not need to be spatialized it's best to disable it. There are two ways +to disable spatialization of a sound: + + ```c + // Disable spatialization at initialization time via a flag: + ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, NULL, &sound); + + // Dynamically disable or enable spatialization post-initialization: + ma_sound_set_spatialization_enabled(&sound, isSpatializationEnabled); + ``` + +By default sounds will be spatialized based on the closest listener. If a sound should always be +spatialized relative to a specific listener it can be pinned to one: + + ```c + ma_sound_set_pinned_listener_index(&sound, listenerIndex); + ``` + +Like listeners, sounds have a position. By default, the position of a sound is in absolute space, +but it can be changed to be relative to a listener: + + ```c + ma_sound_set_positioning(&sound, ma_positioning_relative); + ``` + +Note that relative positioning of a sound only makes sense if there is either only one listener, or +the sound is pinned to a specific listener. To set the position of a sound: + + ```c + ma_sound_set_position(&sound, posX, posY, posZ); + ``` + +The direction works the same way as a listener and represents the sound's forward direction: + + ```c + ma_sound_set_direction(&sound, forwardX, forwardY, forwardZ); + ``` + +Sound's also have a cone for controlling directional attenuation. This works exactly the same as +listeners: + + ```c + ma_sound_set_cone(&sound, innerAngleInRadians, outerAngleInRadians, outerGain); + ``` + +The velocity of a sound is used for doppler effect and can be set as such: + + ```c + ma_sound_set_velocity(&sound, velocityX, velocityY, velocityZ); + ``` + +The engine supports different attenuation models which can be configured on a per-sound basis. By +default the attenuation model is set to `ma_attenuation_model_inverse` which is the equivalent to +OpenAL's `AL_INVERSE_DISTANCE_CLAMPED`. Configure the attenuation model like so: + + ```c + ma_sound_set_attenuation_model(&sound, ma_attenuation_model_inverse); + ``` + +The supported attenuation models include the following: + + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_none | No distance attenuation. | + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_inverse | Equivalent to `AL_INVERSE_DISTANCE_CLAMPED`. | + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_linear | Linear attenuation. | + +----------------------------------+----------------------------------------------+ + | ma_attenuation_model_exponential | Exponential attenuation. | + +----------------------------------+----------------------------------------------+ + +To control how quickly a sound rolls off as it moves away from the listener, you need to configure +the rolloff: + + ```c + ma_sound_set_rolloff(&sound, rolloff); + ``` + +You can control the minimum and maximum gain to apply from spatialization: + + ```c + ma_sound_set_min_gain(&sound, minGain); + ma_sound_set_max_gain(&sound, maxGain); + ``` + +Likewise, in the calculation of attenuation, you can control the minimum and maximum distances for +the attenuation calculation. This is useful if you want to ensure sounds don't drop below a certain +volume after the listener moves further away and to have sounds play a maximum volume when the +listener is within a certain distance: + + ```c + ma_sound_set_min_distance(&sound, minDistance); + ma_sound_set_max_distance(&sound, maxDistance); + ``` + +The engine's spatialization system supports doppler effect. The doppler factor can be configure on +a per-sound basis like so: + + ```c + ma_sound_set_doppler_factor(&sound, dopplerFactor); + ``` + +You can fade sounds in and out with `ma_sound_set_fade_in_pcm_frames()` and +`ma_sound_set_fade_in_milliseconds()`. Set the volume to -1 to use the current volume as the +starting volume: + + ```c + // Fade in over 1 second. + ma_sound_set_fade_in_milliseconds(&sound, 0, 1, 1000); + + // ... sometime later ... + + // Fade out over 1 second, starting from the current volume. + ma_sound_set_fade_in_milliseconds(&sound, -1, 0, 1000); + ``` + +By default sounds will start immediately, but sometimes for timing and synchronization purposes it +can be useful to schedule a sound to start or stop: + + ```c + // Start the sound in 1 second from now. + ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 1)); + + // Stop the sound in 2 seconds from now. + ma_sound_set_stop_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 2)); + ``` + +Note that scheduling a start time still requires an explicit call to `ma_sound_start()` before +anything will play. + +The time is specified in global time which is controlled by the engine. You can get the engine's +current time with `ma_engine_get_time()`. The engine's global time is incremented automatically as +audio data is read, but it can be reset with `ma_engine_set_time()` in case it needs to be +resynchronized for some reason. + +To determine whether or not a sound is currently playing, use `ma_sound_is_playing()`. This will +take the scheduled start and stop times into account. + +Whether or not a sound should loop can be controlled with `ma_sound_set_looping()`. Sounds will not +be looping by default. Use `ma_sound_is_looping()` to determine whether or not a sound is looping. + +Use `ma_sound_at_end()` to determine whether or not a sound is currently at the end. For a looping +sound this should never return true. + +Internally a sound wraps around a data source. Some APIs exist to control the underlying data +source, mainly for convenience: + + ```c + ma_sound_seek_to_pcm_frame(&sound, frameIndex); + ma_sound_get_data_format(&sound, &format, &channels, &sampleRate, pChannelMap, channelMapCapacity); + ma_sound_get_cursor_in_pcm_frames(&sound, &cursor); + ma_sound_get_length_in_pcm_frames(&sound, &length); + ``` + +Sound groups have the same API as sounds, only they are called `ma_sound_group`, and since they do +not have any notion of a data source, anything relating to a data source is unavailable. + +Internally, sound data is loaded via the `ma_decoder` API which means by default in only supports +file formats that have built-in support in miniaudio. You can extend this to support any kind of +file format through the use of custom decoders. To do this you'll need to use a self-managed +resource manager and configure it appropriately. See the "Resource Management" section below for +details on how to set this up. + + +6. Resource Management +====================== +Many programs will want to manage sound resources for things such as reference counting and +streaming. This is supported by miniaudio via the `ma_resource_manager` API. + +The resource manager is mainly responsible for the following: + + * Loading of sound files into memory with reference counting. + * Streaming of sound data + +When loading a sound file, the resource manager will give you back a `ma_data_source` compatible +object called `ma_resource_manager_data_source`. This object can be passed into any +`ma_data_source` API which is how you can read and seek audio data. When loading a sound file, you +specify whether or not you want the sound to be fully loaded into memory (and optionally +pre-decoded) or streamed. When loading into memory, you can also specify whether or not you want +the data to be loaded asynchronously. + +The example below is how you can initialize a resource manager using it's default configuration: + + ```c + ma_resource_manager_config config; + ma_resource_manager resourceManager; + + config = ma_resource_manager_config_init(); + result = ma_resource_manager_init(&config, &resourceManager); + if (result != MA_SUCCESS) { + ma_device_uninit(&device); + printf("Failed to initialize the resource manager."); + return -1; + } + ``` + +You can configure the format, channels and sample rate of the decoded audio data. By default it +will use the file's native data format, but you can configure it to use a consistent format. This +is useful for offloading the cost of data conversion to load time rather than dynamically +converting at mixing time. To do this, you configure the decoded format, channels and sample rate +like the code below: + + ```c + config = ma_resource_manager_config_init(); + config.decodedFormat = device.playback.format; + config.decodedChannels = device.playback.channels; + config.decodedSampleRate = device.sampleRate; + ``` + +In the code above, the resource manager will be configured so that any decoded audio data will be +pre-converted at load time to the device's native data format. If instead you used defaults and +the data format of the file did not match the device's data format, you would need to convert the +data at mixing time which may be prohibitive in high-performance and large scale scenarios like +games. + +Internally the resource manager uses the `ma_decoder` API to load sounds. This means by default it +only supports decoders that are built into miniaudio. It's possible to support additional encoding +formats through the use of custom decoders. To do so, pass in your `ma_decoding_backend_vtable` +vtables into the resource manager config: + + ```c + ma_decoding_backend_vtable* pCustomBackendVTables[] = + { + &g_ma_decoding_backend_vtable_libvorbis, + &g_ma_decoding_backend_vtable_libopus + }; + + ... + + resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables; + resourceManagerConfig.customDecodingBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]); + resourceManagerConfig.pCustomDecodingBackendUserData = NULL; + ``` + +This system can allow you to support any kind of file format. See the "Decoding" section for +details on how to implement custom decoders. The miniaudio repository includes examples for Opus +via libopus and libopusfile and Vorbis via libvorbis and libvorbisfile. + +Asynchronicity is achieved via a job system. When an operation needs to be performed, such as the +decoding of a page, a job will be posted to a queue which will then be processed by a job thread. +By default there will be only one job thread running, but this can be configured, like so: + + ```c + config = ma_resource_manager_config_init(); + config.jobThreadCount = MY_JOB_THREAD_COUNT; + ``` + +By default job threads are managed internally by the resource manager, however you can also self +manage your job threads if, for example, you want to integrate the job processing into your +existing job infrastructure, or if you simply don't like the way the resource manager does it. To +do this, just set the job thread count to 0 and process jobs manually. To process jobs, you first +need to retrieve a job using `ma_resource_manager_next_job()` and then process it using +`ma_job_process()`: + + ```c + config = ma_resource_manager_config_init(); + config.jobThreadCount = 0; // Don't manage any job threads internally. + config.flags = MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; // Optional. Makes `ma_resource_manager_next_job()` non-blocking. + + // ... Initialize your custom job threads ... + + void my_custom_job_thread(...) + { + for (;;) { + ma_job job; + ma_result result = ma_resource_manager_next_job(pMyResourceManager, &job); + if (result != MA_SUCCESS) { + if (result == MA_NOT_DATA_AVAILABLE) { + // No jobs are available. Keep going. Will only get this if the resource manager was initialized + // with MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. + continue; + } else if (result == MA_CANCELLED) { + // MA_JOB_TYPE_QUIT was posted. Exit. + break; + } else { + // Some other error occurred. + break; + } + } + + ma_job_process(&job); + } + } + ``` + +In the example above, the `MA_JOB_TYPE_QUIT` event is the used as the termination +indicator, but you can use whatever you would like to terminate the thread. The call to +`ma_resource_manager_next_job()` is blocking by default, but can be configured to be non-blocking +by initializing the resource manager with the `MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING` configuration +flag. Note that the `MA_JOB_TYPE_QUIT` will never be removed from the job queue. This +is to give every thread the opportunity to catch the event and terminate naturally. + +When loading a file, it's sometimes convenient to be able to customize how files are opened and +read instead of using standard `fopen()`, `fclose()`, etc. which is what miniaudio will use by +default. This can be done by setting `pVFS` member of the resource manager's config: + + ```c + // Initialize your custom VFS object. See documentation for VFS for information on how to do this. + my_custom_vfs vfs = my_custom_vfs_init(); + + config = ma_resource_manager_config_init(); + config.pVFS = &vfs; + ``` + +This is particularly useful in programs like games where you want to read straight from an archive +rather than the normal file system. If you do not specify a custom VFS, the resource manager will +use the operating system's normal file operations. This is default. + +To load a sound file and create a data source, call `ma_resource_manager_data_source_init()`. When +loading a sound you need to specify the file path and options for how the sounds should be loaded. +By default a sound will be loaded synchronously. The returned data source is owned by the caller +which means the caller is responsible for the allocation and freeing of the data source. Below is +an example for initializing a data source: + + ```c + ma_resource_manager_data_source dataSource; + ma_result result = ma_resource_manager_data_source_init(pResourceManager, pFilePath, flags, &dataSource); + if (result != MA_SUCCESS) { + // Error. + } + + // ... + + // A ma_resource_manager_data_source object is compatible with the `ma_data_source` API. To read data, just call + // the `ma_data_source_read_pcm_frames()` like you would with any normal data source. + result = ma_data_source_read_pcm_frames(&dataSource, pDecodedData, frameCount, &framesRead); + if (result != MA_SUCCESS) { + // Failed to read PCM frames. + } + + // ... + + ma_resource_manager_data_source_uninit(pResourceManager, &dataSource); + ``` + +The `flags` parameter specifies how you want to perform loading of the sound file. It can be a +combination of the following flags: + + ``` + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT + ``` + +When no flags are specified (set to 0), the sound will be fully loaded into memory, but not +decoded, meaning the raw file data will be stored in memory, and then dynamically decoded when +`ma_data_source_read_pcm_frames()` is called. To instead decode the audio data before storing it in +memory, use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` flag. By default, the sound file will +be loaded synchronously, meaning `ma_resource_manager_data_source_init()` will only return after +the entire file has been loaded. This is good for simplicity, but can be prohibitively slow. You +can instead load the sound asynchronously using the `MA_RESOURCE_MANAGER_DATA_SOURCE_ASYNC` flag. +This will result in `ma_resource_manager_data_source_init()` returning quickly, but no data will be +returned by `ma_data_source_read_pcm_frames()` until some data is available. When no data is +available because the asynchronous decoding hasn't caught up, `MA_BUSY` will be returned by +`ma_data_source_read_pcm_frames()`. + +For large sounds, it's often prohibitive to store the entire file in memory. To mitigate this, you +can instead stream audio data which you can do by specifying the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. When streaming, data will be decoded in 1 +second pages. When a new page needs to be decoded, a job will be posted to the job queue and then +subsequently processed in a job thread. + +For in-memory sounds, reference counting is used to ensure the data is loaded only once. This means +multiple calls to `ma_resource_manager_data_source_init()` with the same file path will result in +the file data only being loaded once. Each call to `ma_resource_manager_data_source_init()` must be +matched up with a call to `ma_resource_manager_data_source_uninit()`. Sometimes it can be useful +for a program to register self-managed raw audio data and associate it with a file path. Use the +`ma_resource_manager_register_*()` and `ma_resource_manager_unregister_*()` APIs to do this. +`ma_resource_manager_register_decoded_data()` is used to associate a pointer to raw, self-managed +decoded audio data in the specified data format with the specified name. Likewise, +`ma_resource_manager_register_encoded_data()` is used to associate a pointer to raw self-managed +encoded audio data (the raw file data) with the specified name. Note that these names need not be +actual file paths. When `ma_resource_manager_data_source_init()` is called (without the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag), the resource manager will look for these +explicitly registered data buffers and, if found, will use it as the backing data for the data +source. Note that the resource manager does *not* make a copy of this data so it is up to the +caller to ensure the pointer stays valid for it's lifetime. Use +`ma_resource_manager_unregister_data()` to unregister the self-managed data. You can also use +`ma_resource_manager_register_file()` and `ma_resource_manager_unregister_file()` to register and +unregister a file. It does not make sense to use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` +flag with a self-managed data pointer. + + +6.1. Asynchronous Loading and Synchronization +--------------------------------------------- +When loading asynchronously, it can be useful to poll whether or not loading has finished. Use +`ma_resource_manager_data_source_result()` to determine this. For in-memory sounds, this will +return `MA_SUCCESS` when the file has been *entirely* decoded. If the sound is still being decoded, +`MA_BUSY` will be returned. Otherwise, some other error code will be returned if the sound failed +to load. For streaming data sources, `MA_SUCCESS` will be returned when the first page has been +decoded and the sound is ready to be played. If the first page is still being decoded, `MA_BUSY` +will be returned. Otherwise, some other error code will be returned if the sound failed to load. + +In addition to polling, you can also use a simple synchronization object called a "fence" to wait +for asynchronously loaded sounds to finish. This is called `ma_fence`. The advantage to using a +fence is that it can be used to wait for a group of sounds to finish loading rather than waiting +for sounds on an individual basis. There are two stages to loading a sound: + + * Initialization of the internal decoder; and + * Completion of decoding of the file (the file is fully decoded) + +You can specify separate fences for each of the different stages. Waiting for the initialization +of the internal decoder is important for when you need to know the sample format, channels and +sample rate of the file. + +The example below shows how you could use a fence when loading a number of sounds: + + ```c + // This fence will be released when all sounds are finished loading entirely. + ma_fence fence; + ma_fence_init(&fence); + + // This will be passed into the initialization routine for each sound. + ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init(); + notifications.done.pFence = &fence; + + // Now load a bunch of sounds: + for (iSound = 0; iSound < soundCount; iSound += 1) { + ma_resource_manager_data_source_init(pResourceManager, pSoundFilePaths[iSound], flags, ¬ifications, &pSoundSources[iSound]); + } + + // ... DO SOMETHING ELSE WHILE SOUNDS ARE LOADING ... + + // Wait for loading of sounds to finish. + ma_fence_wait(&fence); + ``` + +In the example above we used a fence for waiting until the entire file has been fully decoded. If +you only need to wait for the initialization of the internal decoder to complete, you can use the +`init` member of the `ma_resource_manager_pipeline_notifications` object: + + ```c + notifications.init.pFence = &fence; + ``` + +If a fence is not appropriate for your situation, you can instead use a callback that is fired on +an individual sound basis. This is done in a very similar way to fences: + + ```c + typedef struct + { + ma_async_notification_callbacks cb; + void* pMyData; + } my_notification; + + void my_notification_callback(ma_async_notification* pNotification) + { + my_notification* pMyNotification = (my_notification*)pNotification; + + // Do something in response to the sound finishing loading. + } + + ... + + my_notification myCallback; + myCallback.cb.onSignal = my_notification_callback; + myCallback.pMyData = pMyData; + + ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init(); + notifications.done.pNotification = &myCallback; + + ma_resource_manager_data_source_init(pResourceManager, "my_sound.wav", flags, ¬ifications, &mySound); + ``` + +In the example above we just extend the `ma_async_notification_callbacks` object and pass an +instantiation into the `ma_resource_manager_pipeline_notifications` in the same way as we did with +the fence, only we set `pNotification` instead of `pFence`. You can set both of these at the same +time and they should both work as expected. If using the `pNotification` system, you need to ensure +your `ma_async_notification_callbacks` object stays valid. + + + +6.2. Resource Manager Implementation Details +-------------------------------------------- +Resources are managed in two main ways: + + * By storing the entire sound inside an in-memory buffer (referred to as a data buffer) + * By streaming audio data on the fly (referred to as a data stream) + +A resource managed data source (`ma_resource_manager_data_source`) encapsulates a data buffer or +data stream, depending on whether or not the data source was initialized with the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. If so, it will make use of a +`ma_resource_manager_data_stream` object. Otherwise it will use a `ma_resource_manager_data_buffer` +object. Both of these objects are data sources which means they can be used with any +`ma_data_source_*()` API. + +Another major feature of the resource manager is the ability to asynchronously decode audio files. +This relieves the audio thread of time-consuming decoding which can negatively affect scalability +due to the audio thread needing to complete it's work extremely quickly to avoid glitching. +Asynchronous decoding is achieved through a job system. There is a central multi-producer, +multi-consumer, fixed-capacity job queue. When some asynchronous work needs to be done, a job is +posted to the queue which is then read by a job thread. The number of job threads can be +configured for improved scalability, and job threads can all run in parallel without needing to +worry about the order of execution (how this is achieved is explained below). + +When a sound is being loaded asynchronously, playback can begin before the sound has been fully +decoded. This enables the application to start playback of the sound quickly, while at the same +time allowing to resource manager to keep loading in the background. Since there may be less +threads than the number of sounds being loaded at a given time, a simple scheduling system is used +to keep decoding time balanced and fair. The resource manager solves this by splitting decoding +into chunks called pages. By default, each page is 1 second long. When a page has been decoded, a +new job will be posted to start decoding the next page. By dividing up decoding into pages, an +individual sound shouldn't ever delay every other sound from having their first page decoded. Of +course, when loading many sounds at the same time, there will always be an amount of time required +to process jobs in the queue so in heavy load situations there will still be some delay. To +determine if a data source is ready to have some frames read, use +`ma_resource_manager_data_source_get_available_frames()`. This will return the number of frames +available starting from the current position. + + +6.2.1. Job Queue +---------------- +The resource manager uses a job queue which is multi-producer, multi-consumer, and fixed-capacity. +This job queue is not currently lock-free, and instead uses a spinlock to achieve thread-safety. +Only a fixed number of jobs can be allocated and inserted into the queue which is done through a +lock-free data structure for allocating an index into a fixed sized array, with reference counting +for mitigation of the ABA problem. The reference count is 32-bit. + +For many types of jobs it's important that they execute in a specific order. In these cases, jobs +are executed serially. For the resource manager, serial execution of jobs is only required on a +per-object basis (per data buffer or per data stream). Each of these objects stores an execution +counter. When a job is posted it is associated with an execution counter. When the job is +processed, it checks if the execution counter of the job equals the execution counter of the +owning object and if so, processes the job. If the counters are not equal, the job will be posted +back onto the job queue for later processing. When the job finishes processing the execution order +of the main object is incremented. This system means the no matter how many job threads are +executing, decoding of an individual sound will always get processed serially. The advantage to +having multiple threads comes into play when loading multiple sounds at the same time. + +The resource manager's job queue is not 100% lock-free and will use a spinlock to achieve +thread-safety for a very small section of code. This is only relevant when the resource manager +uses more than one job thread. If only using a single job thread, which is the default, the +lock should never actually wait in practice. The amount of time spent locking should be quite +short, but it's something to be aware of for those who have pedantic lock-free requirements and +need to use more than one job thread. There are plans to remove this lock in a future version. + +In addition, posting a job will release a semaphore, which on Win32 is implemented with +`ReleaseSemaphore` and on POSIX platforms via a condition variable: + + ```c + pthread_mutex_lock(&pSemaphore->lock); + { + pSemaphore->value += 1; + pthread_cond_signal(&pSemaphore->cond); + } + pthread_mutex_unlock(&pSemaphore->lock); + ``` + +Again, this is relevant for those with strict lock-free requirements in the audio thread. To avoid +this, you can use non-blocking mode (via the `MA_JOB_QUEUE_FLAG_NON_BLOCKING` +flag) and implement your own job processing routine (see the "Resource Manager" section above for +details on how to do this). + + + +6.2.2. Data Buffers +------------------- +When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag is excluded at initialization time, the +resource manager will try to load the data into an in-memory data buffer. Before doing so, however, +it will first check if the specified file is already loaded. If so, it will increment a reference +counter and just use the already loaded data. This saves both time and memory. When the data buffer +is uninitialized, the reference counter will be decremented. If the counter hits zero, the file +will be unloaded. This is a detail to keep in mind because it could result in excessive loading and +unloading of a sound. For example, the following sequence will result in a file be loaded twice, +once after the other: + + ```c + ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer0); // Refcount = 1. Initial load. + ma_resource_manager_data_source_uninit(pResourceManager, &myDataBuffer0); // Refcount = 0. Unloaded. + + ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer1); // Refcount = 1. Reloaded because previous uninit() unloaded it. + ma_resource_manager_data_source_uninit(pResourceManager, &myDataBuffer1); // Refcount = 0. Unloaded. + ``` + +A binary search tree (BST) is used for storing data buffers as it has good balance between +efficiency and simplicity. The key of the BST is a 64-bit hash of the file path that was passed +into `ma_resource_manager_data_source_init()`. The advantage of using a hash is that it saves +memory over storing the entire path, has faster comparisons, and results in a mostly balanced BST +due to the random nature of the hash. The disadvantage is that file names are case-sensitive. If +this is an issue, you should normalize your file names to upper- or lower-case before initializing +your data sources. + +When a sound file has not already been loaded and the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` +flag is excluded, the file will be decoded synchronously by the calling thread. There are two +options for controlling how the audio is stored in the data buffer - encoded or decoded. When the +`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` option is excluded, the raw file data will be stored +in memory. Otherwise the sound will be decoded before storing it in memory. Synchronous loading is +a very simple and standard process of simply adding an item to the BST, allocating a block of +memory and then decoding (if `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` is specified). + +When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag is specified, loading of the data buffer +is done asynchronously. In this case, a job is posted to the queue to start loading and then the +function immediately returns, setting an internal result code to `MA_BUSY`. This result code is +returned when the program calls `ma_resource_manager_data_source_result()`. When decoding has fully +completed `MA_SUCCESS` will be returned. This can be used to know if loading has fully completed. + +When loading asynchronously, a single job is posted to the queue of the type +`MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE`. This involves making a copy of the file path and +associating it with job. When the job is processed by the job thread, it will first load the file +using the VFS associated with the resource manager. When using a custom VFS, it's important that it +be completely thread-safe because it will be used from one or more job threads at the same time. +Individual files should only ever be accessed by one thread at a time, however. After opening the +file via the VFS, the job will determine whether or not the file is being decoded. If not, it +simply allocates a block of memory and loads the raw file contents into it and returns. On the +other hand, when the file is being decoded, it will first allocate a decoder on the heap and +initialize it. Then it will check if the length of the file is known. If so it will allocate a +block of memory to store the decoded output and initialize it to silence. If the size is unknown, +it will allocate room for one page. After memory has been allocated, the first page will be +decoded. If the sound is shorter than a page, the result code will be set to `MA_SUCCESS` and the +completion event will be signalled and loading is now complete. If, however, there is more to +decode, a job with the code `MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE` is posted. This job +will decode the next page and perform the same process if it reaches the end. If there is more to +decode, the job will post another `MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE` job which will +keep on happening until the sound has been fully decoded. For sounds of an unknown length, each +page will be linked together as a linked list. Internally this is implemented via the +`ma_paged_audio_buffer` object. + + +6.2.3. Data Streams +------------------- +Data streams only ever store two pages worth of data for each instance. They are most useful for +large sounds like music tracks in games that would consume too much memory if fully decoded in +memory. After every frame from a page has been read, a job will be posted to load the next page +which is done from the VFS. + +For data streams, the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag will determine whether or +not initialization of the data source waits until the two pages have been decoded. When unset, +`ma_resource_manager_data_source_init()` will wait until the two pages have been loaded, otherwise +it will return immediately. + +When frames are read from a data stream using `ma_resource_manager_data_source_read_pcm_frames()`, +`MA_BUSY` will be returned if there are no frames available. If there are some frames available, +but less than the number requested, `MA_SUCCESS` will be returned, but the actual number of frames +read will be less than the number requested. Due to the asynchronous nature of data streams, +seeking is also asynchronous. If the data stream is in the middle of a seek, `MA_BUSY` will be +returned when trying to read frames. + +When `ma_resource_manager_data_source_read_pcm_frames()` results in a page getting fully consumed +a job is posted to load the next page. This will be posted from the same thread that called +`ma_resource_manager_data_source_read_pcm_frames()`. + +Data streams are uninitialized by posting a job to the queue, but the function won't return until +that job has been processed. The reason for this is that the caller owns the data stream object and +therefore miniaudio needs to ensure everything completes before handing back control to the caller. +Also, if the data stream is uninitialized while pages are in the middle of decoding, they must +complete before destroying any underlying object and the job system handles this cleanly. + +Note that when a new page needs to be loaded, a job will be posted to the resource manager's job +thread from the audio thread. You must keep in mind the details mentioned in the "Job Queue" +section above regarding locking when posting an event if you require a strictly lock-free audio +thread. + + + +7. Node Graph +============= +miniaudio's routing infrastructure follows a node graph paradigm. The idea is that you create a +node whose outputs are attached to inputs of another node, thereby creating a graph. There are +different types of nodes, with each node in the graph processing input data to produce output, +which is then fed through the chain. Each node in the graph can apply their own custom effects. At +the start of the graph will usually be one or more data source nodes which have no inputs, but +instead pull their data from a data source. At the end of the graph is an endpoint which represents +the end of the chain and is where the final output is ultimately extracted from. + +Each node has a number of input buses and a number of output buses. An output bus from a node is +attached to an input bus of another. Multiple nodes can connect their output buses to another +node's input bus, in which case their outputs will be mixed before processing by the node. Below is +a diagram that illustrates a hypothetical node graph setup: + + ``` + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Data flows left to right >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + +---------------+ +-----------------+ + | Data Source 1 =----+ +----------+ +----= Low Pass Filter =----+ + +---------------+ | | =----+ +-----------------+ | +----------+ + +----= Splitter | +----= ENDPOINT | + +---------------+ | | =----+ +-----------------+ | +----------+ + | Data Source 2 =----+ +----------+ +----= Echo / Delay =----+ + +---------------+ +-----------------+ + ``` + +In the above graph, it starts with two data sources whose outputs are attached to the input of a +splitter node. It's at this point that the two data sources are mixed. After mixing, the splitter +performs it's processing routine and produces two outputs which is simply a duplication of the +input stream. One output is attached to a low pass filter, whereas the other output is attached to +a echo/delay. The outputs of the the low pass filter and the echo are attached to the endpoint, and +since they're both connected to the same input but, they'll be mixed. + +Each input bus must be configured to accept the same number of channels, but the number of channels +used by input buses can be different to the number of channels for output buses in which case +miniaudio will automatically convert the input data to the output channel count before processing. +The number of channels of an output bus of one node must match the channel count of the input bus +it's attached to. The channel counts cannot be changed after the node has been initialized. If you +attempt to attach an output bus to an input bus with a different channel count, attachment will +fail. + +To use a node graph, you first need to initialize a `ma_node_graph` object. This is essentially a +container around the entire graph. The `ma_node_graph` object is required for some thread-safety +issues which will be explained later. A `ma_node_graph` object is initialized using miniaudio's +standard config/init system: + + ```c + ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(myChannelCount); + + result = ma_node_graph_init(&nodeGraphConfig, NULL, &nodeGraph); // Second parameter is a pointer to allocation callbacks. + if (result != MA_SUCCESS) { + // Failed to initialize node graph. + } + ``` + +When you initialize the node graph, you're specifying the channel count of the endpoint. The +endpoint is a special node which has one input bus and one output bus, both of which have the +same channel count, which is specified in the config. Any nodes that connect directly to the +endpoint must be configured such that their output buses have the same channel count. When you read +audio data from the node graph, it'll have the channel count you specified in the config. To read +data from the graph: + + ```c + ma_uint32 framesRead; + result = ma_node_graph_read_pcm_frames(&nodeGraph, pFramesOut, frameCount, &framesRead); + if (result != MA_SUCCESS) { + // Failed to read data from the node graph. + } + ``` + +When you read audio data, miniaudio starts at the node graph's endpoint node which then pulls in +data from it's input attachments, which in turn recusively pull in data from their inputs, and so +on. At the start of the graph there will be some kind of data source node which will have zero +inputs and will instead read directly from a data source. The base nodes don't literally need to +read from a `ma_data_source` object, but they will always have some kind of underlying object that +sources some kind of audio. The `ma_data_source_node` node can be used to read from a +`ma_data_source`. Data is always in floating-point format and in the number of channels you +specified when the graph was initialized. The sample rate is defined by the underlying data sources. +It's up to you to ensure they use a consistent and appropraite sample rate. + +The `ma_node` API is designed to allow custom nodes to be implemented with relative ease, but +miniaudio includes a few stock nodes for common functionality. This is how you would initialize a +node which reads directly from a data source (`ma_data_source_node`) which is an example of one +of the stock nodes that comes with miniaudio: + + ```c + ma_data_source_node_config config = ma_data_source_node_config_init(pMyDataSource); + + ma_data_source_node dataSourceNode; + result = ma_data_source_node_init(&nodeGraph, &config, NULL, &dataSourceNode); + if (result != MA_SUCCESS) { + // Failed to create data source node. + } + ``` + +The data source node will use the output channel count to determine the channel count of the output +bus. There will be 1 output bus and 0 input buses (data will be drawn directly from the data +source). The data source must output to floating-point (`ma_format_f32`) or else an error will be +returned from `ma_data_source_node_init()`. + +By default the node will not be attached to the graph. To do so, use `ma_node_attach_output_bus()`: + + ```c + result = ma_node_attach_output_bus(&dataSourceNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0); + if (result != MA_SUCCESS) { + // Failed to attach node. + } + ``` + +The code above connects the data source node directly to the endpoint. Since the data source node +has only a single output bus, the index will always be 0. Likewise, the endpoint only has a single +input bus which means the input bus index will also always be 0. + +To detach a specific output bus, use `ma_node_detach_output_bus()`. To detach all output buses, use +`ma_node_detach_all_output_buses()`. If you want to just move the output bus from one attachment to +another, you do not need to detach first. You can just call `ma_node_attach_output_bus()` and it'll +deal with it for you. + +Less frequently you may want to create a specialized node. This will be a node where you implement +your own processing callback to apply a custom effect of some kind. This is similar to initalizing +one of the stock node types, only this time you need to specify a pointer to a vtable containing a +pointer to the processing function and the number of input and output buses. Example: + + ```c + static void my_custom_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) + { + // Do some processing of ppFramesIn (one stream of audio data per input bus) + const float* pFramesIn_0 = ppFramesIn[0]; // Input bus @ index 0. + const float* pFramesIn_1 = ppFramesIn[1]; // Input bus @ index 1. + float* pFramesOut_0 = ppFramesOut[0]; // Output bus @ index 0. + + // Do some processing. On input, `pFrameCountIn` will be the number of input frames in each + // buffer in `ppFramesIn` and `pFrameCountOut` will be the capacity of each of the buffers + // in `ppFramesOut`. On output, `pFrameCountIn` should be set to the number of input frames + // your node consumed and `pFrameCountOut` should be set the number of output frames that + // were produced. + // + // You should process as many frames as you can. If your effect consumes input frames at the + // same rate as output frames (always the case, unless you're doing resampling), you need + // only look at `ppFramesOut` and process that exact number of frames. If you're doing + // resampling, you'll need to be sure to set both `pFrameCountIn` and `pFrameCountOut` + // properly. + } + + static ma_node_vtable my_custom_node_vtable = + { + my_custom_node_process_pcm_frames, // The function that will be called process your custom node. This is where you'd implement your effect processing. + NULL, // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames. + 2, // 2 input buses. + 1, // 1 output bus. + 0 // Default flags. + }; + + ... + + // Each bus needs to have a channel count specified. To do this you need to specify the channel + // counts in an array and then pass that into the node config. + ma_uint32 inputChannels[2]; // Equal in size to the number of input channels specified in the vtable. + ma_uint32 outputChannels[1]; // Equal in size to the number of output channels specicied in the vtable. + + inputChannels[0] = channelsIn; + inputChannels[1] = channelsIn; + outputChannels[0] = channelsOut; + + ma_node_config nodeConfig = ma_node_config_init(); + nodeConfig.vtable = &my_custom_node_vtable; + nodeConfig.pInputChannels = inputChannels; + nodeConfig.pOutputChannels = outputChannels; + + ma_node_base node; + result = ma_node_init(&nodeGraph, &nodeConfig, NULL, &node); + if (result != MA_SUCCESS) { + // Failed to initialize node. + } + ``` + +When initializing a custom node, as in the code above, you'll normally just place your vtable in +static space. The number of input and output buses are specified as part of the vtable. If you need +a variable number of buses on a per-node bases, the vtable should have the relevant bus count set +to `MA_NODE_BUS_COUNT_UNKNOWN`. In this case, the bus count should be set in the node config: + + ```c + static ma_node_vtable my_custom_node_vtable = + { + my_custom_node_process_pcm_frames, // The function that will be called process your custom node. This is where you'd implement your effect processing. + NULL, // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames. + MA_NODE_BUS_COUNT_UNKNOWN, // The number of input buses is determined on a per-node basis. + 1, // 1 output bus. + 0 // Default flags. + }; + + ... + + ma_node_config nodeConfig = ma_node_config_init(); + nodeConfig.vtable = &my_custom_node_vtable; + nodeConfig.inputBusCount = myBusCount; // <-- Since the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN, the input bus count should be set here. + nodeConfig.pInputChannels = inputChannels; // <-- Make sure there are nodeConfig.inputBusCount elements in this array. + nodeConfig.pOutputChannels = outputChannels; // <-- The vtable specifies 1 output bus, so there must be 1 element in this array. + ``` + +In the above example it's important to never set the `inputBusCount` and `outputBusCount` members +to anything other than their defaults if the vtable specifies an explicit count. They can only be +set if the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN in the relevant bus count. + +Most often you'll want to create a structure to encapsulate your node with some extra data. You +need to make sure the `ma_node_base` object is your first member of the structure: + + ```c + typedef struct + { + ma_node_base base; // <-- Make sure this is always the first member. + float someCustomData; + } my_custom_node; + ``` + +By doing this, your object will be compatible with all `ma_node` APIs and you can attach it to the +graph just like any other node. + +In the custom processing callback (`my_custom_node_process_pcm_frames()` in the example above), the +number of channels for each bus is what was specified by the config when the node was initialized +with `ma_node_init()`. In addition, all attachments to each of the input buses will have been +pre-mixed by miniaudio. The config allows you to specify different channel counts for each +individual input and output bus. It's up to the effect to handle it appropriate, and if it can't, +return an error in it's initialization routine. + +Custom nodes can be assigned some flags to describe their behaviour. These are set via the vtable +and include the following: + + +-----------------------------------------+---------------------------------------------------+ + | Flag Name | Description | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_PASSTHROUGH | Useful for nodes that do not do any kind of audio | + | | processing, but are instead used for tracking | + | | time, handling events, etc. Also used by the | + | | internal endpoint node. It reads directly from | + | | the input bus to the output bus. Nodes with this | + | | flag must have exactly 1 input bus and 1 output | + | | bus, and both buses must have the same channel | + | | counts. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_CONTINUOUS_PROCESSING | Causes the processing callback to be called even | + | | when no data is available to be read from input | + | | attachments. This is useful for effects like | + | | echos where there will be a tail of audio data | + | | that still needs to be processed even when the | + | | original data sources have reached their ends. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_ALLOW_NULL_INPUT | Used in conjunction with | + | | `MA_NODE_FLAG_CONTINUOUS_PROCESSING`. When this | + | | is set, the `ppFramesIn` parameter of the | + | | processing callback will be set to NULL when | + | | there are no input frames are available. When | + | | this is unset, silence will be posted to the | + | | processing callback. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES | Used to tell miniaudio that input and output | + | | frames are processed at different rates. You | + | | should set this for any nodes that perform | + | | resampling. | + +-----------------------------------------+---------------------------------------------------+ + | MA_NODE_FLAG_SILENT_OUTPUT | Used to tell miniaudio that a node produces only | + | | silent output. This is useful for nodes where you | + | | don't want the output to contribute to the final | + | | mix. An example might be if you want split your | + | | stream and have one branch be output to a file. | + | | When using this flag, you should avoid writing to | + | | the output buffer of the node's processing | + | | callback because miniaudio will ignore it anyway. | + +-----------------------------------------+---------------------------------------------------+ + + +If you need to make a copy of an audio stream for effect processing you can use a splitter node +called `ma_splitter_node`. This takes has 1 input bus and splits the stream into 2 output buses. +You can use it like this: + + ```c + ma_splitter_node_config splitterNodeConfig = ma_splitter_node_config_init(channelsIn, channelsOut); + + ma_splitter_node splitterNode; + result = ma_splitter_node_init(&nodeGraph, &splitterNodeConfig, NULL, &splitterNode); + if (result != MA_SUCCESS) { + // Failed to create node. + } + + // Attach your output buses to two different input buses (can be on two different nodes). + ma_node_attach_output_bus(&splitterNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0); // Attach directly to the endpoint. + ma_node_attach_output_bus(&splitterNode, 1, &myEffectNode, 0); // Attach to input bus 0 of some effect node. + ``` + +The volume of an output bus can be configured on a per-bus basis: + + ```c + ma_node_set_output_bus_volume(&splitterNode, 0, 0.5f); + ma_node_set_output_bus_volume(&splitterNode, 1, 0.5f); + ``` + +In the code above we're using the splitter node from before and changing the volume of each of the +copied streams. + +You can start and stop a node with the following: + + ```c + ma_node_set_state(&splitterNode, ma_node_state_started); // The default state. + ma_node_set_state(&splitterNode, ma_node_state_stopped); + ``` + +By default the node is in a started state, but since it won't be connected to anything won't +actually be invoked by the node graph until it's connected. When you stop a node, data will not be +read from any of it's input connections. You can use this property to stop a group of sounds +atomically. + +You can configure the initial state of a node in it's config: + + ```c + nodeConfig.initialState = ma_node_state_stopped; + ``` + +Note that for the stock specialized nodes, all of their configs will have a `nodeConfig` member +which is the config to use with the base node. This is where the initial state can be configured +for specialized nodes: + + ```c + dataSourceNodeConfig.nodeConfig.initialState = ma_node_state_stopped; + ``` + +When using a specialized node like `ma_data_source_node` or `ma_splitter_node`, be sure to not +modify the `vtable` member of the `nodeConfig` object. + + +7.1. Timing +----------- +The node graph supports starting and stopping nodes at scheduled times. This is especially useful +for data source nodes where you want to get the node set up, but only start playback at a specific +time. There are two clocks: local and global. + +A local clock is per-node, whereas the global clock is per graph. Scheduling starts and stops can +only be done based on the global clock because the local clock will not be running while the node +is stopped. The global clocks advances whenever `ma_node_graph_read_pcm_frames()` is called. On the +other hand, the local clock only advances when the node's processing callback is fired, and is +advanced based on the output frame count. + +To retrieve the global time, use `ma_node_graph_get_time()`. The global time can be set with +`ma_node_graph_set_time()` which might be useful if you want to do seeking on a global timeline. +Getting and setting the local time is similar. Use `ma_node_get_time()` to retrieve the local time, +and `ma_node_set_time()` to set the local time. The global and local times will be advanced by the +audio thread, so care should be taken to avoid data races. Ideally you should avoid calling these +outside of the node processing callbacks which are always run on the audio thread. + +There is basic support for scheduling the starting and stopping of nodes. You can only schedule one +start and one stop at a time. This is mainly intended for putting nodes into a started or stopped +state in a frame-exact manner. Without this mechanism, starting and stopping of a node is limited +to the resolution of a call to `ma_node_graph_read_pcm_frames()` which would typically be in blocks +of several milliseconds. The following APIs can be used for scheduling node states: + + ```c + ma_node_set_state_time() + ma_node_get_state_time() + ``` + +The time is absolute and must be based on the global clock. An example is below: + + ```c + ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1); // Delay starting to 1 second. + ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5); // Delay stopping to 5 seconds. + ``` + +An example for changing the state using a relative time. + + ```c + ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1 + ma_node_graph_get_time(&myNodeGraph)); + ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5 + ma_node_graph_get_time(&myNodeGraph)); + ``` + +Note that due to the nature of multi-threading the times may not be 100% exact. If this is an +issue, consider scheduling state changes from within a processing callback. An idea might be to +have some kind of passthrough trigger node that is used specifically for tracking time and handling +events. + + + +7.2. Thread Safety and Locking +------------------------------ +When processing audio, it's ideal not to have any kind of locking in the audio thread. Since it's +expected that `ma_node_graph_read_pcm_frames()` would be run on the audio thread, it does so +without the use of any locks. This section discusses the implementation used by miniaudio and goes +over some of the compromises employed by miniaudio to achieve this goal. Note that the current +implementation may not be ideal - feedback and critiques are most welcome. + +The node graph API is not *entirely* lock-free. Only `ma_node_graph_read_pcm_frames()` is expected +to be lock-free. Attachment, detachment and uninitialization of nodes use locks to simplify the +implementation, but are crafted in a way such that such locking is not required when reading audio +data from the graph. Locking in these areas are achieved by means of spinlocks. + +The main complication with keeping `ma_node_graph_read_pcm_frames()` lock-free stems from the fact +that a node can be uninitialized, and it's memory potentially freed, while in the middle of being +processed on the audio thread. There are times when the audio thread will be referencing a node, +which means the uninitialization process of a node needs to make sure it delays returning until the +audio thread is finished so that control is not handed back to the caller thereby giving them a +chance to free the node's memory. + +When the audio thread is processing a node, it does so by reading from each of the output buses of +the node. In order for a node to process data for one of it's output buses, it needs to read from +each of it's input buses, and so on an so forth. It follows that once all output buses of a node +are detached, the node as a whole will be disconnected and no further processing will occur unless +it's output buses are reattached, which won't be happening when the node is being uninitialized. +By having `ma_node_detach_output_bus()` wait until the audio thread is finished with it, we can +simplify a few things, at the expense of making `ma_node_detach_output_bus()` a bit slower. By +doing this, the implementation of `ma_node_uninit()` becomes trivial - just detach all output +nodes, followed by each of the attachments to each of it's input nodes, and then do any final clean +up. + +With the above design, the worst-case scenario is `ma_node_detach_output_bus()` taking as long as +it takes to process the output bus being detached. This will happen if it's called at just the +wrong moment where the audio thread has just iterated it and has just started processing. The +caller of `ma_node_detach_output_bus()` will stall until the audio thread is finished, which +includes the cost of recursively processing it's inputs. This is the biggest compromise made with +the approach taken by miniaudio for it's lock-free processing system. The cost of detaching nodes +earlier in the pipeline (data sources, for example) will be cheaper than the cost of detaching +higher level nodes, such as some kind of final post-processing endpoint. If you need to do mass +detachments, detach starting from the lowest level nodes and work your way towards the final +endpoint node (but don't try detaching the node graph's endpoint). If the audio thread is not +running, detachment will be fast and detachment in any order will be the same. The reason nodes +need to wait for their input attachments to complete is due to the potential for desyncs between +data sources. If the node was to terminate processing mid way through processing it's inputs, +there's a chance that some of the underlying data sources will have been read, but then others not. +That will then result in a potential desynchronization when detaching and reattaching higher-level +nodes. A possible solution to this is to have an option when detaching to terminate processing +before processing all input attachments which should be fairly simple. + +Another compromise, albeit less significant, is locking when attaching and detaching nodes. This +locking is achieved by means of a spinlock in order to reduce memory overhead. A lock is present +for each input bus and output bus. When an output bus is connected to an input bus, both the output +bus and input bus is locked. This locking is specifically for attaching and detaching across +different threads and does not affect `ma_node_graph_read_pcm_frames()` in any way. The locking and +unlocking is mostly self-explanatory, but a slightly less intuitive aspect comes into it when +considering that iterating over attachments must not break as a result of attaching or detaching a +node while iteration is occuring. + +Attaching and detaching are both quite simple. When an output bus of a node is attached to an input +bus of another node, it's added to a linked list. Basically, an input bus is a linked list, where +each item in the list is and output bus. We have some intentional (and convenient) restrictions on +what can done with the linked list in order to simplify the implementation. First of all, whenever +something needs to iterate over the list, it must do so in a forward direction. Backwards iteration +is not supported. Also, items can only be added to the start of the list. + +The linked list is a doubly-linked list where each item in the list (an output bus) holds a pointer +to the next item in the list, and another to the previous item. A pointer to the previous item is +only required for fast detachment of the node - it is never used in iteration. This is an +important property because it means from the perspective of iteration, attaching and detaching of +an item can be done with a single atomic assignment. This is exploited by both the attachment and +detachment process. When attaching the node, the first thing that is done is the setting of the +local "next" and "previous" pointers of the node. After that, the item is "attached" to the list +by simply performing an atomic exchange with the head pointer. After that, the node is "attached" +to the list from the perspective of iteration. Even though the "previous" pointer of the next item +hasn't yet been set, from the perspective of iteration it's been attached because iteration will +only be happening in a forward direction which means the "previous" pointer won't actually ever get +used. The same general process applies to detachment. See `ma_node_attach_output_bus()` and +`ma_node_detach_output_bus()` for the implementation of this mechanism. + + + +8. Decoding =========== -The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from devices and can be used independently. The following formats are -supported: +The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from +devices and can be used independently. The following formats are supported: +---------+------------------+----------+ | Format | Decoding Backend | Built-In | @@ -473,7 +2403,8 @@ supported: | Vorbis | stb_vorbis | No | +---------+------------------+----------+ -Vorbis is supported via stb_vorbis which can be enabled by including the header section before the implementation of miniaudio, like the following: +Vorbis is supported via stb_vorbis which can be enabled by including the header section before the +implementation of miniaudio, like the following: ```c #define STB_VORBIS_HEADER_ONLY @@ -489,8 +2420,9 @@ Vorbis is supported via stb_vorbis which can be enabled by including the header A copy of stb_vorbis is included in the "extras" folder in the miniaudio repository (https://github.com/mackron/miniaudio). -Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the built-in decoders by specifying one or more of the -following options before the miniaudio implementation: +Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the +built-in decoders by specifying one or more of the following options before the miniaudio +implementation: ```c #define MA_NO_WAV @@ -498,10 +2430,12 @@ following options before the miniaudio implementation: #define MA_NO_FLAC ``` -Disabling built-in decoding libraries is useful if you use these libraries independantly of the `ma_decoder` API. +Disabling built-in decoding libraries is useful if you use these libraries independantly of the +`ma_decoder` API. -A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with `ma_decoder_init_memory()`, or from data delivered via callbacks -with `ma_decoder_init()`. Here is an example for loading a decoder from a file: +A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with +`ma_decoder_init_memory()`, or from data delivered via callbacks with `ma_decoder_init()`. Here is +an example for loading a decoder from a file: ```c ma_decoder decoder; @@ -515,20 +2449,23 @@ with `ma_decoder_init()`. Here is an example for loading a decoder from a file: ma_decoder_uninit(&decoder); ``` -When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object (the `NULL` argument in the example above) which allows you -to configure the output format, channel count, sample rate and channel map: +When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object +(the `NULL` argument in the example above) which allows you to configure the output format, channel +count, sample rate and channel map: ```c ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, 48000); ``` -When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the same as that defined by the decoding backend. +When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the +same as that defined by the decoding backend. -Data is read from the decoder as PCM frames. This will return the number of PCM frames actually read. If the return value is less than the requested number of -PCM frames it means you've reached the end: +Data is read from the decoder as PCM frames. This will output the number of PCM frames actually +read. If this is less than the requested number of PCM frames it means you've reached the end. The +return value will be `MA_AT_END` if no samples have been read and the end has been reached. ```c - ma_uint64 framesRead = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead); + ma_result result = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead, &framesRead); if (framesRead < framesToRead) { // Reached the end. } @@ -549,8 +2486,10 @@ If you want to loop back to the start, you can simply seek back to the first PCM ma_decoder_seek_to_pcm_frame(pDecoder, 0); ``` -When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding backend. This can be unnecessarily inefficient if the type -is already known. In this case you can use `encodingFormat` variable in the device config to specify a specific encoding format you want to decode: +When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding +backend. This can be unnecessarily inefficient if the type is already known. In this case you can +use `encodingFormat` variable in the device config to specify a specific encoding format you want +to decode: ```c decoderConfig.encodingFormat = ma_encoding_format_wav; @@ -558,24 +2497,95 @@ is already known. In this case you can use `encodingFormat` variable in the devi See the `ma_encoding_format` enum for possible encoding formats. -The `ma_decoder_init_file()` API will try using the file extension to determine which decoding backend to prefer. +The `ma_decoder_init_file()` API will try using the file extension to determine which decoding +backend to prefer. + + +8.1. Custom Decoders +-------------------- +It's possible to implement a custom decoder and plug it into miniaudio. This is extremely useful +when you want to use the `ma_decoder` API, but need to support an encoding format that's not one of +the stock formats supported by miniaudio. This can be put to particularly good use when using the +`ma_engine` and/or `ma_resource_manager` APIs because they use `ma_decoder` internally. If, for +example, you wanted to support Opus, you can do so with a custom decoder (there if a reference +Opus decoder in the "extras" folder of the miniaudio repository which uses libopus + libopusfile). + +A custom decoder must implement a data source. A vtable called `ma_decoding_backend_vtable` needs +to be implemented which is then passed into the decoder config: + + ```c + ma_decoding_backend_vtable* pCustomBackendVTables[] = + { + &g_ma_decoding_backend_vtable_libvorbis, + &g_ma_decoding_backend_vtable_libopus + }; + + ... + + decoderConfig = ma_decoder_config_init_default(); + decoderConfig.pCustomBackendUserData = NULL; + decoderConfig.ppCustomBackendVTables = pCustomBackendVTables; + decoderConfig.customBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]); + ``` + +The `ma_decoding_backend_vtable` vtable has the following functions: + + ``` + onInit + onInitFile + onInitFileW + onInitMemory + onUninit + ``` + +There are only two functions that must be implemented - `onInit` and `onUninit`. The other +functions can be implemented for a small optimization for loading from a file path or memory. If +these are not specified, miniaudio will deal with it for you via a generic implementation. + +When you initialize a custom data source (by implementing the `onInit` function in the vtable) you +will need to output a pointer to a `ma_data_source` which implements your custom decoder. See the +section about data sources for details on how to implemen this. Alternatively, see the +"custom_decoders" example in the miniaudio repository. + +The `onInit` function takes a pointer to some callbacks for the purpose of reading raw audio data +from some abitrary source. You'll use these functions to read from the raw data and perform the +decoding. When you call them, you will pass in the `pReadSeekTellUserData` pointer to the relevant +parameter. + +The `pConfig` parameter in `onInit` can be used to configure the backend if appropriate. It's only +used as a hint and can be ignored. However, if any of the properties are relevant to your decoder, +an optimal implementation will handle the relevant properties appropriately. + +If memory allocation is required, it should be done so via the specified allocation callbacks if +possible (the `pAllocationCallbacks` parameter). + +If an error occurs when initializing the decoder, you should leave `ppBackend` unset, or set to +NULL, and make sure everything is cleaned up appropriately and an appropriate result code returned. +When multiple custom backends are specified, miniaudio will cycle through the vtables in the order +they're listed in the array that's passed into the decoder config so it's important that your +initialization routine is clean. + +When a decoder is uninitialized, the `onUninit` callback will be fired which will give you an +opportunity to clean up and internal data. -5. Encoding +9. Encoding =========== -The `ma_encoding` API is used for writing audio files. The only supported output format is WAV which is achieved via dr_wav which is amalgamated into the -implementation section of miniaudio. This can be disabled by specifying the following option before the implementation of miniaudio: +The `ma_encoding` API is used for writing audio files. The only supported output format is WAV +which is achieved via dr_wav which is amalgamated into the implementation section of miniaudio. +This can be disabled by specifying the following option before the implementation of miniaudio: ```c #define MA_NO_WAV ``` -An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data delivered via callbacks with `ma_encoder_init()`. Below is an -example for initializing an encoder to output to a file. +An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data +delivered via callbacks with `ma_encoder_init()`. Below is an example for initializing an encoder +to output to a file. ```c - ma_encoder_config config = ma_encoder_config_init(ma_resource_format_wav, FORMAT, CHANNELS, SAMPLE_RATE); + ma_encoder_config config = ma_encoder_config_init(ma_encoding_format_wav, FORMAT, CHANNELS, SAMPLE_RATE); ma_encoder encoder; ma_result result = ma_encoder_init_file("my_file.wav", &config, &encoder); if (result != MA_SUCCESS) { @@ -587,17 +2597,20 @@ example for initializing an encoder to output to a file. ma_encoder_uninit(&encoder); ``` -When initializing an encoder you must specify a config which is initialized with `ma_encoder_config_init()`. Here you must specify the file type, the output -sample format, output channel count and output sample rate. The following file types are supported: +When initializing an encoder you must specify a config which is initialized with +`ma_encoder_config_init()`. Here you must specify the file type, the output sample format, output +channel count and output sample rate. The following file types are supported: +------------------------+-------------+ | Enum | Description | +------------------------+-------------+ - | ma_resource_format_wav | WAV | + | ma_encoding_format_wav | WAV | +------------------------+-------------+ -If the format, channel count or sample rate is not supported by the output file type an error will be returned. The encoder will not perform data conversion so -you will need to convert it before outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the example below: +If the format, channel count or sample rate is not supported by the output file type an error will +be returned. The encoder will not perform data conversion so you will need to convert it before +outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the +example below: ```c framesWritten = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite); @@ -606,21 +2619,25 @@ you will need to convert it before outputting any audio data. To output audio da Encoders must be uninitialized with `ma_encoder_uninit()`. -6. Data Conversion -================== -A data conversion API is included with miniaudio which supports the majority of data conversion requirements. This supports conversion between sample formats, -channel counts (with channel mapping) and sample rates. + +10. Data Conversion +=================== +A data conversion API is included with miniaudio which supports the majority of data conversion +requirements. This supports conversion between sample formats, channel counts (with channel +mapping) and sample rates. -6.1. Sample Format Conversion ------------------------------ -Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and `ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()` -to convert between two specific formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use `ma_convert_pcm_frames_format()` to convert -PCM frames where you want to specify the frame count and channel count as a variable instead of the total sample count. +10.1. Sample Format Conversion +------------------------------ +Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and +`ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()` to convert between two specific +formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use +`ma_convert_pcm_frames_format()` to convert PCM frames where you want to specify the frame count +and channel count as a variable instead of the total sample count. -6.1.1. Dithering ----------------- +10.1.1. Dithering +----------------- Dithering can be set using the ditherMode parameter. The different dithering modes include the following, in order of efficiency: @@ -633,8 +2650,9 @@ The different dithering modes include the following, in order of efficiency: | Triangle | ma_dither_mode_triangle | +-----------+--------------------------+ -Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be ignored for conversions where dithering is not needed. -Dithering is available for the following conversions: +Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be +ignored for conversions where dithering is not needed. Dithering is available for the following +conversions: ``` s16 -> u8 @@ -646,14 +2664,16 @@ Dithering is available for the following conversions: f32 -> s16 ``` -Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored. +Note that it is not an error to pass something other than ma_dither_mode_none for conversions where +dither is not used. It will just be ignored. -6.2. Channel Conversion ------------------------ -Channel conversion is used for channel rearrangement and conversion from one channel count to another. The `ma_channel_converter` API is used for channel -conversion. Below is an example of initializing a simple channel converter which converts from mono to stereo. +10.2. Channel Conversion +------------------------ +Channel conversion is used for channel rearrangement and conversion from one channel count to +another. The `ma_channel_converter` API is used for channel conversion. Below is an example of +initializing a simple channel converter which converts from mono to stereo. ```c ma_channel_converter_config config = ma_channel_converter_config_init( @@ -664,7 +2684,7 @@ conversion. Below is an example of initializing a simple channel converter which NULL, // Output channel map ma_channel_mix_mode_default); // The mixing algorithm to use when combining channels. - result = ma_channel_converter_init(&config, &converter); + result = ma_channel_converter_init(&config, NULL, &converter); if (result != MA_SUCCESS) { // Error. } @@ -679,34 +2699,43 @@ To perform the conversion simply call `ma_channel_converter_process_pcm_frames() } ``` -It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM frames. +It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM +frames. Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported. -6.2.1. Channel Mapping ----------------------- -In addition to converting from one channel count to another, like the example above, the channel converter can also be used to rearrange channels. When -initializing the channel converter, you can optionally pass in channel maps for both the input and output frames. If the channel counts are the same, and each -channel map contains the same channel positions with the exception that they're in a different order, a simple shuffling of the channels will be performed. If, -however, there is not a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed based on a mixing mode which is -specified when initializing the `ma_channel_converter_config` object. +10.2.1. Channel Mapping +----------------------- +In addition to converting from one channel count to another, like the example above, the channel +converter can also be used to rearrange channels. When initializing the channel converter, you can +optionally pass in channel maps for both the input and output frames. If the channel counts are the +same, and each channel map contains the same channel positions with the exception that they're in +a different order, a simple shuffling of the channels will be performed. If, however, there is not +a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed +based on a mixing mode which is specified when initializing the `ma_channel_converter_config` +object. -When converting from mono to multi-channel, the mono channel is simply copied to each output channel. When going the other way around, the audio of each output -channel is simply averaged and copied to the mono channel. +When converting from mono to multi-channel, the mono channel is simply copied to each output +channel. When going the other way around, the audio of each output channel is simply averaged and +copied to the mono channel. -In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess channels and silence extra channels. For example, converting -from 4 to 2 channels, the 3rd and 4th channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and 4th channels. +In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess +channels and silence extra channels. For example, converting from 4 to 2 channels, the 3rd and 4th +channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and +4th channels. -The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a simple distribution between input and output. Imagine sitting -in the middle of a room, with speakers on the walls representing channel positions. The MA_CHANNEL_FRONT_LEFT position can be thought of as being in the corner -of the front and left walls. +The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a +simple distribution between input and output. Imagine sitting in the middle of a room, with +speakers on the walls representing channel positions. The `MA_CHANNEL_FRONT_LEFT` position can be +thought of as being in the corner of the front and left walls. -Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined weights. Custom weights can be passed in as the last parameter of +Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined +weights. Custom weights can be passed in as the last parameter of `ma_channel_converter_config_init()`. -Predefined channel maps can be retrieved with `ma_get_standard_channel_map()`. This takes a `ma_standard_channel_map` enum as it's first parameter, which can -be one of the following: +Predefined channel maps can be retrieved with `ma_channel_map_init_standard()`. This takes a +`ma_standard_channel_map` enum as it's first parameter, which can be one of the following: +-----------------------------------+-----------------------------------------------------------+ | Name | Description | @@ -778,9 +2807,10 @@ Below are the channel maps used by default in miniaudio (`ma_standard_channel_ma -6.3. Resampling ---------------- -Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something like the following: +10.3. Resampling +---------------- +Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something +like the following: ```c ma_resampler_config config = ma_resampler_config_init( @@ -817,104 +2847,128 @@ The following example shows how data can be processed // number of output frames written. ``` -To initialize the resampler you first need to set up a config (`ma_resampler_config`) with `ma_resampler_config_init()`. You need to specify the sample format -you want to use, the number of channels, the input and output sample rate, and the algorithm. +To initialize the resampler you first need to set up a config (`ma_resampler_config`) with +`ma_resampler_config_init()`. You need to specify the sample format you want to use, the number of +channels, the input and output sample rate, and the algorithm. -The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format you will need to perform pre- and post-conversions yourself -where necessary. Note that the format is the same for both input and output. The format cannot be changed after initialization. +The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format +you will need to perform pre- and post-conversions yourself where necessary. Note that the format +is the same for both input and output. The format cannot be changed after initialization. -The resampler supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization. +The resampler supports multiple channels and is always interleaved (both input and output). The +channel count cannot be changed after initialization. -The sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the -only configuration property that can be changed after initialization. +The sample rates can be anything other than zero, and are always specified in hertz. They should be +set to something like 44100, etc. The sample rate is the only configuration property that can be +changed after initialization. -The miniaudio resampler supports multiple algorithms: +The miniaudio resampler has built-in support for the following algorithms: +-----------+------------------------------+ | Algorithm | Enum Token | +-----------+------------------------------+ | Linear | ma_resample_algorithm_linear | - | Speex | ma_resample_algorithm_speex | + | Custom | ma_resample_algorithm_custom | +-----------+------------------------------+ -Because Speex is not public domain it is strictly opt-in and the code is stored in separate files. if you opt-in to the Speex backend you will need to consider -it's license, the text of which can be found in it's source files in "extras/speex_resampler". Details on how to opt-in to the Speex resampler is explained in -the Speex Resampler section below. - The algorithm cannot be changed after initialization. -Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process -frames, use `ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number of -input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the -number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large -buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek. +Processing always happens on a per PCM frame basis and always assumes interleaved input and output. +De-interleaved processing is not supported. To process frames, use +`ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you +can fit in the output buffer and the number of input frames contained in the input buffer. On +output these variables contain the number of output frames that were written to the output buffer +and the number of input frames that were consumed in the process. You can pass in NULL for the +input buffer in which case it will be treated as an infinitely large buffer of zeros. The output +buffer can also be NULL, in which case the processing will be treated as seek. -The sample rate can be changed dynamically on the fly. You can change this with explicit sample rates with `ma_resampler_set_rate()` and also with a decimal -ratio with `ma_resampler_set_rate_ratio()`. The ratio is in/out. +The sample rate can be changed dynamically on the fly. You can change this with explicit sample +rates with `ma_resampler_set_rate()` and also with a decimal ratio with +`ma_resampler_set_rate_ratio()`. The ratio is in/out. -Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with -`ma_resampler_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of -input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`. +Sometimes it's useful to know exactly how many input frames will be required to output a specific +number of frames. You can calculate this with `ma_resampler_get_required_input_frame_count()`. +Likewise, it's sometimes useful to know exactly how many frames would be output given a certain +number of input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`. -Due to the nature of how resampling works, the resampler introduces some latency. This can be retrieved in terms of both the input rate and the output rate -with `ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`. +Due to the nature of how resampling works, the resampler introduces some latency. This can be +retrieved in terms of both the input rate and the output rate with +`ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`. -6.3.1. Resampling Algorithms ----------------------------- -The choice of resampling algorithm depends on your situation and requirements. The linear resampler is the most efficient and has the least amount of latency, -but at the expense of poorer quality. The Speex resampler is higher quality, but slower with more latency. It also performs several heap allocations internally -for memory management. +10.3.1. Resampling Algorithms +----------------------------- +The choice of resampling algorithm depends on your situation and requirements. -6.3.1.1. Linear Resampling --------------------------- -The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, some control over the quality of the linear resampler which -may make it a suitable option depending on your requirements. +10.3.1.1. Linear Resampling +--------------------------- +The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, +some control over the quality of the linear resampler which may make it a suitable option depending +on your requirements. -The linear resampler performs low-pass filtering before or after downsampling or upsampling, depending on the sample rates you're converting between. When -decreasing the sample rate, the low-pass filter will be applied before downsampling. When increasing the rate it will be performed after upsampling. By default -a fourth order low-pass filter will be applied. This can be configured via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. +The linear resampler performs low-pass filtering before or after downsampling or upsampling, +depending on the sample rates you're converting between. When decreasing the sample rate, the +low-pass filter will be applied before downsampling. When increasing the rate it will be performed +after upsampling. By default a fourth order low-pass filter will be applied. This can be configured +via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. -The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of the input and output sample rates (Nyquist Frequency). This -can be controlled with the `lpfNyquistFactor` config variable. This defaults to 1, and should be in the range of 0..1, although a value of 0 does not make -sense and should be avoided. A value of 1 will use the Nyquist Frequency as the cutoff. A value of 0.5 will use half the Nyquist Frequency as the cutoff, etc. -Values less than 1 will result in more washed out sound due to more of the higher frequencies being removed. This config variable has no impact on performance -and is a purely perceptual configuration. +The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of +the input and output sample rates (Nyquist Frequency). -The API for the linear resampler is the same as the main resampler API, only it's called `ma_linear_resampler`. +The API for the linear resampler is the same as the main resampler API, only it's called +`ma_linear_resampler`. -6.3.1.2. Speex Resampling +10.3.2. Custom Resamplers ------------------------- -The Speex resampler is made up of third party code which is released under the BSD license. Because it is licensed differently to miniaudio, which is public -domain, it is strictly opt-in and all of it's code is stored in separate files. If you opt-in to the Speex resampler you must consider the license text in it's -source files. To opt-in, you must first `#include` the following file before the implementation of miniaudio.h: +You can implement a custom resampler by using the `ma_resample_algorithm_custom` resampling +algorithm and setting a vtable in the resampler config: ```c - #include "extras/speex_resampler/ma_speex_resampler.h" + ma_resampler_config config = ma_resampler_config_init(..., ma_resample_algorithm_custom); + config.pBackendVTable = &g_customResamplerVTable; ``` -Both the header and implementation is contained within the same file. The implementation can be included in your program like so: +Custom resamplers are useful if the stock algorithms are not appropriate for your use case. You +need to implement the required functions in `ma_resampling_backend_vtable`. Note that not all +functions in the vtable need to be implemented, but if it's possible to implement, they should be. - ```c - #define MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION - #include "extras/speex_resampler/ma_speex_resampler.h" - ``` +You can use the `ma_linear_resampler` object for an example on how to implement the vtable. The +`onGetHeapSize` callback is used to calculate the size of any internal heap allocation the custom +resampler will need to make given the supplied config. When you initialize the resampler via the +`onInit` callback, you'll be given a pointer to a heap allocation which is where you should store +the heap allocated data. You should not free this data in `onUninit` because miniaudio will manage +it for you. -Note that even if you opt-in to the Speex backend, miniaudio won't use it unless you explicitly ask for it in the respective config of the object you are -initializing. If you try to use the Speex resampler without opting in, initialization of the `ma_resampler` object will fail with `MA_NO_BACKEND`. +The `onProcess` callback is where the actual resampling takes place. On input, `pFrameCountIn` +points to a variable containing the number of frames in the `pFramesIn` buffer and +`pFrameCountOut` points to a variable containing the capacity in frames of the `pFramesOut` buffer. +On output, `pFrameCountIn` should be set to the number of input frames that were fully consumed, +whereas `pFrameCountOut` should be set to the number of frames that were written to `pFramesOut`. -The only configuration option to consider with the Speex resampler is the `speex.quality` config variable. This is a value between 0 and 10, with 0 being -the fastest with the poorest quality and 10 being the slowest with the highest quality. The default value is 3. +The `onSetRate` callback is optional and is used for dynamically changing the sample rate. If +dynamic rate changes are not supported, you can set this callback to NULL. + +The `onGetInputLatency` and `onGetOutputLatency` functions are used for retrieving the latency in +input and output rates respectively. These can be NULL in which case latency calculations will be +assumed to be NULL. + +The `onGetRequiredInputFrameCount` callback is used to give miniaudio a hint as to how many input +frames are required to be available to produce the given number of output frames. Likewise, the +`onGetExpectedOutputFrameCount` callback is used to determine how many output frames will be +produced given the specified number of input frames. miniaudio will use these as a hint, but they +are optional and can be set to NULL if you're unable to implement them. -6.4. General Data Conversion ----------------------------- -The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and resampling into one operation. This is what miniaudio uses -internally to convert between the format requested when the device was initialized and the format of the backend's native device. The API for general data -conversion is very similar to the resampling API. Create a `ma_data_converter` object like this: +10.4. General Data Conversion +----------------------------- +The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and +resampling into one operation. This is what miniaudio uses internally to convert between the format +requested when the device was initialized and the format of the backend's native device. The API +for general data conversion is very similar to the resampling API. Create a `ma_data_converter` +object like this: ```c ma_data_converter_config config = ma_data_converter_config_init( @@ -927,14 +2981,15 @@ conversion is very similar to the resampling API. Create a `ma_data_converter` o ); ma_data_converter converter; - ma_result result = ma_data_converter_init(&config, &converter); + ma_result result = ma_data_converter_init(&config, NULL, &converter); if (result != MA_SUCCESS) { // An error occurred... } ``` -In the example above we use `ma_data_converter_config_init()` to initialize the config, however there's many more properties that can be configured, such as -channel maps and resampling quality. Something like the following may be more suitable depending on your requirements: +In the example above we use `ma_data_converter_config_init()` to initialize the config, however +there's many more properties that can be configured, such as channel maps and resampling quality. +Something like the following may be more suitable depending on your requirements: ```c ma_data_converter_config config = ma_data_converter_config_init_default(); @@ -944,14 +2999,14 @@ channel maps and resampling quality. Something like the following may be more su config.channelsOut = outputChannels; config.sampleRateIn = inputSampleRate; config.sampleRateOut = outputSampleRate; - ma_get_standard_channel_map(ma_standard_channel_map_flac, config.channelCountIn, config.channelMapIn); + ma_channel_map_init_standard(ma_standard_channel_map_flac, config.channelMapIn, sizeof(config.channelMapIn)/sizeof(config.channelMapIn[0]), config.channelCountIn); config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER; ``` Do the following to uninitialize the data converter: ```c - ma_data_converter_uninit(&converter); + ma_data_converter_uninit(&converter, NULL); ``` The following example shows how data can be processed @@ -968,33 +3023,42 @@ The following example shows how data can be processed // of output frames written. ``` -The data converter supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization. +The data converter supports multiple channels and is always interleaved (both input and output). +The channel count cannot be changed after initialization. -Sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the only -configuration property that can be changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of `ma_data_converter_config` is -set to `MA_TRUE`. To change the sample rate, use `ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. The -resampling algorithm cannot be changed after initialization. +Sample rates can be anything other than zero, and are always specified in hertz. They should be set +to something like 44100, etc. The sample rate is the only configuration property that can be +changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of +`ma_data_converter_config` is set to `MA_TRUE`. To change the sample rate, use +`ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. +The resampling algorithm cannot be changed after initialization. -Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process -frames, use `ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number -of input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the -number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large -buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek. +Processing always happens on a per PCM frame basis and always assumes interleaved input and output. +De-interleaved processing is not supported. To process frames, use +`ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames +you can fit in the output buffer and the number of input frames contained in the input buffer. On +output these variables contain the number of output frames that were written to the output buffer +and the number of input frames that were consumed in the process. You can pass in NULL for the +input buffer in which case it will be treated as an infinitely large +buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated +as seek. -Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with -`ma_data_converter_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of -input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`. +Sometimes it's useful to know exactly how many input frames will be required to output a specific +number of frames. You can calculate this with `ma_data_converter_get_required_input_frame_count()`. +Likewise, it's sometimes useful to know exactly how many frames would be output given a certain +number of input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`. -Due to the nature of how resampling works, the data converter introduces some latency if resampling is required. This can be retrieved in terms of both the -input rate and the output rate with `ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`. +Due to the nature of how resampling works, the data converter introduces some latency if resampling +is required. This can be retrieved in terms of both the input rate and the output rate with +`ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`. -7. Filtering -============ +11. Filtering +============= -7.1. Biquad Filtering ---------------------- +11.1. Biquad Filtering +---------------------- Biquad filtering is achieved with the `ma_biquad` API. Example: ```c @@ -1009,28 +3073,33 @@ Biquad filtering is achieved with the `ma_biquad` API. Example: ma_biquad_process_pcm_frames(&biquad, pFramesOut, pFramesIn, frameCount); ``` -Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, b1 and b2, and the denominator coefficients are a0, a1 and -a2. The a0 coefficient is required and coefficients must not be pre-normalized. +Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, +b1 and b2, and the denominator coefficients are a0, a1 and a2. The a0 coefficient is required and +coefficients must not be pre-normalized. -Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. When using -`ma_format_s16` the biquad filter will use fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used. +Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format +you need to convert it yourself beforehand. When using `ma_format_s16` the biquad filter will use +fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used. Input and output frames are always interleaved. -Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so: +Filtering can be applied in-place by passing in the same pointer for both the input and output +buffers, like so: ```c ma_biquad_process_pcm_frames(&biquad, pMyData, pMyData, frameCount); ``` -If you need to change the values of the coefficients, but maintain the values in the registers you can do so with `ma_biquad_reinit()`. This is useful if you -need to change the properties of the filter while keeping the values of registers valid to avoid glitching. Do not use `ma_biquad_init()` for this as it will -do a full initialization which involves clearing the registers to 0. Note that changing the format or channel count after initialization is invalid and will -result in an error. +If you need to change the values of the coefficients, but maintain the values in the registers you +can do so with `ma_biquad_reinit()`. This is useful if you need to change the properties of the +filter while keeping the values of registers valid to avoid glitching. Do not use +`ma_biquad_init()` for this as it will do a full initialization which involves clearing the +registers to 0. Note that changing the format or channel count after initialization is invalid and +will result in an error. -7.2. Low-Pass Filtering ------------------------ +11.2. Low-Pass Filtering +------------------------ Low-pass filtering is achieved with the following APIs: +---------+------------------------------------------+ @@ -1055,16 +3124,18 @@ Low-pass filter example: ma_lpf_process_pcm_frames(&lpf, pFramesOut, pFramesIn, frameCount); ``` -Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. Input and output -frames are always interleaved. +Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format +you need to convert it yourself beforehand. Input and output frames are always interleaved. -Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so: +Filtering can be applied in-place by passing in the same pointer for both the input and output +buffers, like so: ```c ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount); ``` -The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more, you can chain first and second order filters together. +The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more, +you can chain first and second order filters together. ```c for (iFilter = 0; iFilter < filterCount; iFilter += 1) { @@ -1072,19 +3143,22 @@ The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. } ``` -If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with `ma_lpf_reinit()`. This may be -useful if you need to change the sample rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the format or channel -count after initialization is invalid and will result in an error. +If you need to change the configuration of the filter, but need to maintain the state of internal +registers you can do so with `ma_lpf_reinit()`. This may be useful if you need to change the sample +rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the +format or channel count after initialization is invalid and will result in an error. -The `ma_lpf` object supports a configurable order, but if you only need a first order filter you may want to consider using `ma_lpf1`. Likewise, if you only -need a second order filter you can use `ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient. +The `ma_lpf` object supports a configurable order, but if you only need a first order filter you +may want to consider using `ma_lpf1`. Likewise, if you only need a second order filter you can use +`ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient. -If an even filter order is specified, a series of second order filters will be processed in a chain. If an odd filter order is specified, a first order filter -will be applied, followed by a series of second order filters in a chain. +If an even filter order is specified, a series of second order filters will be processed in a +chain. If an odd filter order is specified, a first order filter will be applied, followed by a +series of second order filters in a chain. -7.3. High-Pass Filtering ------------------------- +11.3. High-Pass Filtering +------------------------- High-pass filtering is achieved with the following APIs: +---------+-------------------------------------------+ @@ -1095,12 +3169,12 @@ High-pass filtering is achieved with the following APIs: | ma_hpf | High order high-pass filter (Butterworth) | +---------+-------------------------------------------+ -High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, `ma_hpf2` and `ma_hpf`. See example code for low-pass filters -for example usage. +High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, +`ma_hpf2` and `ma_hpf`. See example code for low-pass filters for example usage. -7.4. Band-Pass Filtering ------------------------- +11.4. Band-Pass Filtering +------------------------- Band-pass filtering is achieved with the following APIs: +---------+-------------------------------+ @@ -1110,13 +3184,14 @@ Band-pass filtering is achieved with the following APIs: | ma_bpf | High order band-pass filter | +---------+-------------------------------+ -Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and `ma_hpf`. See example code for low-pass filters for example -usage. Note that the order for band-pass filters must be an even number which means there is no first order band-pass filter, unlike low-pass and high-pass -filters. +Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and +`ma_hpf`. See example code for low-pass filters for example usage. Note that the order for +band-pass filters must be an even number which means there is no first order band-pass filter, +unlike low-pass and high-pass filters. -7.5. Notch Filtering --------------------- +11.5. Notch Filtering +--------------------- Notch filtering is achieved with the following APIs: +-----------+------------------------------------------+ @@ -1126,7 +3201,7 @@ Notch filtering is achieved with the following APIs: +-----------+------------------------------------------+ -7.6. Peaking EQ Filtering +11.6. Peaking EQ Filtering ------------------------- Peaking filtering is achieved with the following APIs: @@ -1137,8 +3212,8 @@ Peaking filtering is achieved with the following APIs: +----------+------------------------------------------+ -7.7. Low Shelf Filtering ------------------------- +11.7. Low Shelf Filtering +------------------------- Low shelf filtering is achieved with the following APIs: +-------------+------------------------------------------+ @@ -1147,11 +3222,12 @@ Low shelf filtering is achieved with the following APIs: | ma_loshelf2 | Second order low shelf filter | +-------------+------------------------------------------+ -Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to just turn them down rather than eliminate them entirely. +Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to +just turn them down rather than eliminate them entirely. -7.8. High Shelf Filtering -------------------------- +11.8. High Shelf Filtering +-------------------------- High shelf filtering is achieved with the following APIs: +-------------+------------------------------------------+ @@ -1160,18 +3236,20 @@ High shelf filtering is achieved with the following APIs: | ma_hishelf2 | Second order high shelf filter | +-------------+------------------------------------------+ -The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` instead of `ma_loshelf`. Where a low shelf filter is used to -adjust the volume of low frequencies, the high shelf filter does the same thing for high frequencies. +The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` +instead of `ma_loshelf`. Where a low shelf filter is used to adjust the volume of low frequencies, +the high shelf filter does the same thing for high frequencies. -8. Waveform and Noise Generation -================================ +12. Waveform and Noise Generation +================================= -8.1. Waveforms --------------- -miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved with the `ma_waveform` API. Example: +12.1. Waveforms +--------------- +miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved +with the `ma_waveform` API. Example: ```c ma_waveform_config config = ma_waveform_config_init( @@ -1193,11 +3271,12 @@ miniaudio supports generation of sine, square, triangle and sawtooth waveforms. ma_waveform_read_pcm_frames(&waveform, pOutput, frameCount); ``` -The amplitude, frequency, type, and sample rate can be changed dynamically with `ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`, -`ma_waveform_set_type()`, and `ma_waveform_set_sample_rate()` respectively. +The amplitude, frequency, type, and sample rate can be changed dynamically with +`ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`, `ma_waveform_set_type()`, and +`ma_waveform_set_sample_rate()` respectively. -You can invert the waveform by setting the amplitude to a negative value. You can use this to control whether or not a sawtooth has a positive or negative -ramp, for example. +You can invert the waveform by setting the amplitude to a negative value. You can use this to +control whether or not a sawtooth has a positive or negative ramp, for example. Below are the supported waveform types: @@ -1212,8 +3291,8 @@ Below are the supported waveform types: -8.2. Noise ----------- +12.2. Noise +----------- miniaudio supports generation of white, pink and Brownian noise via the `ma_noise` API. Example: ```c @@ -1235,13 +3314,16 @@ miniaudio supports generation of white, pink and Brownian noise via the `ma_nois ma_noise_read_pcm_frames(&noise, pOutput, frameCount); ``` -The noise API uses simple LCG random number generation. It supports a custom seed which is useful for things like automated testing requiring reproducibility. -Setting the seed to zero will default to `MA_DEFAULT_LCG_SEED`. +The noise API uses simple LCG random number generation. It supports a custom seed which is useful +for things like automated testing requiring reproducibility. Setting the seed to zero will default +to `MA_DEFAULT_LCG_SEED`. -The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`, `ma_noise_set_seed()`, and `ma_noise_set_type()` respectively. +The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`, +`ma_noise_set_seed()`, and `ma_noise_set_type()` respectively. -By default, the noise API will use different values for different channels. So, for example, the left side in a stereo stream will be different to the right -side. To instead have each channel use the same random value, set the `duplicateChannels` member of the noise config to true, like so: +By default, the noise API will use different values for different channels. So, for example, the +left side in a stereo stream will be different to the right side. To instead have each channel use +the same random value, set the `duplicateChannels` member of the noise config to true, like so: ```c config.duplicateChannels = MA_TRUE; @@ -1259,10 +3341,11 @@ Below are the supported noise types. -9. Audio Buffers -================ -miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can read from memory that's managed by the application, but -can also handle the memory management for you internally. Memory management is flexible and should support most use cases. +13. Audio Buffers +================= +miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can +read from memory that's managed by the application, but can also handle the memory management for +you internally. Memory management is flexible and should support most use cases. Audio buffers are initialised using the standard configuration system used everywhere in miniaudio: @@ -1285,11 +3368,14 @@ Audio buffers are initialised using the standard configuration system used every ma_audio_buffer_uninit(&buffer); ``` -In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an application can do self-managed memory allocation. If you -would rather make a copy of the data, use `ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`. +In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an +application can do self-managed memory allocation. If you would rather make a copy of the data, use +`ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`. -Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the raw audio data in a contiguous block of memory. That is, -the raw audio data will be located immediately after the `ma_audio_buffer` structure. To do this, use `ma_audio_buffer_alloc_and_init()`: +Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the +raw audio data in a contiguous block of memory. That is, the raw audio data will be located +immediately after the `ma_audio_buffer` structure. To do this, use +`ma_audio_buffer_alloc_and_init()`: ```c ma_audio_buffer_config config = ma_audio_buffer_config_init( @@ -1310,13 +3396,18 @@ the raw audio data will be located immediately after the `ma_audio_buffer` struc ma_audio_buffer_uninit_and_free(&buffer); ``` -If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it with `ma_audio_buffer_uninit_and_free()`. In the example above, -the memory pointed to by `pExistingData` will be copied into the buffer, which is contrary to the behavior of `ma_audio_buffer_init()`. +If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it +with `ma_audio_buffer_uninit_and_free()`. In the example above, the memory pointed to by +`pExistingData` will be copied into the buffer, which is contrary to the behavior of +`ma_audio_buffer_init()`. -An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the cursor moves forward. The last parameter (`loop`) can be -used to determine if the buffer should loop. The return value is the number of frames actually read. If this is less than the number of frames requested it -means the end has been reached. This should never happen if the `loop` parameter is set to true. If you want to manually loop back to the start, you can do so -with with `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an audio buffer. +An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the +cursor moves forward. The last parameter (`loop`) can be used to determine if the buffer should +loop. The return value is the number of frames actually read. If this is less than the number of +frames requested it means the end has been reached. This should never happen if the `loop` +parameter is set to true. If you want to manually loop back to the start, you can do so with with +`ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an +audio buffer. ```c ma_uint64 framesRead = ma_audio_buffer_read_pcm_frames(pAudioBuffer, pFramesOut, desiredFrameCount, isLooping); @@ -1325,8 +3416,8 @@ with with `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an exam } ``` -Sometimes you may want to avoid the cost of data movement between the internal buffer and the output buffer. Instead you can use memory mapping to retrieve a -pointer to a segment of data: +Sometimes you may want to avoid the cost of data movement between the internal buffer and the +output buffer. Instead you can use memory mapping to retrieve a pointer to a segment of data: ```c void* pMappedFrames; @@ -1342,23 +3433,30 @@ pointer to a segment of data: } ``` -When you use memory mapping, the read cursor is increment by the frame count passed in to `ma_audio_buffer_unmap()`. If you decide not to process every frame -you can pass in a value smaller than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is that it does not handle looping -for you. You can determine if the buffer is at the end for the purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of -`ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` as an error when returned by `ma_audio_buffer_unmap()`. +When you use memory mapping, the read cursor is increment by the frame count passed in to +`ma_audio_buffer_unmap()`. If you decide not to process every frame you can pass in a value smaller +than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is +that it does not handle looping for you. You can determine if the buffer is at the end for the +purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of +`ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` +as an error when returned by `ma_audio_buffer_unmap()`. -10. Ring Buffers +14. Ring Buffers ================ -miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates -on bytes, whereas the `ma_pcm_rb` operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around `ma_rb`. +miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via +the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates on bytes, whereas the `ma_pcm_rb` +operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around +`ma_rb`. -Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved streams. The caller can also allocate their own backing memory for -the ring buffer to use internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for you. +Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved +streams. The caller can also allocate their own backing memory for the ring buffer to use +internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for +you. -The examples below use the PCM frame variant of the ring buffer since that's most likely the one you will want to use. To initialize a ring buffer, do -something like the following: +The examples below use the PCM frame variant of the ring buffer since that's most likely the one +you will want to use. To initialize a ring buffer, do something like the following: ```c ma_pcm_rb rb; @@ -1368,39 +3466,53 @@ something like the following: } ``` -The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because it's the PCM varient of the ring buffer API. For the regular -ring buffer that operates on bytes you would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes instead of frames. The -fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation -routines. Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used. +The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because +it's the PCM varient of the ring buffer API. For the regular ring buffer that operates on bytes you +would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes +instead of frames. The fourth parameter is an optional pre-allocated buffer and the fifth parameter +is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation routines. +Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used. -Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. To manage your -sub-buffers you can use `ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and `ma_pcm_rb_get_subbuffer_ptr()`. +Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is +offset from each other based on the stride. To manage your sub-buffers you can use +`ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and +`ma_pcm_rb_get_subbuffer_ptr()`. -Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section of the ring buffer. You specify the number of frames you -need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of frames requested will require -a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you're given may be less than the number you requested. +Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section +of the ring buffer. You specify the number of frames you need, and on output it will set to what +was actually acquired. If the read or write pointer is positioned such that the number of frames +requested will require a loop, it will be clamped to the end of the buffer. Therefore, the number +of frames you're given may be less than the number you requested. -After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the buffer and then "commit" it with `ma_pcm_rb_commit_read()` or -`ma_pcm_rb_commit_write()`. This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier -call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and -`ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was originally requested. +After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the +buffer and then "commit" it with `ma_pcm_rb_commit_read()` or `ma_pcm_rb_commit_write()`. This is +where the read/write pointers are updated. When you commit you need to pass in the buffer that was +returned by the earlier call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is +only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and +`ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was +originally requested. -If you want to correct for drift between the write pointer and the read pointer you can use a combination of `ma_pcm_rb_pointer_distance()`, -`ma_pcm_rb_seek_read()` and `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only move the read pointer forward via -the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If +If you want to correct for drift between the write pointer and the read pointer you can use a +combination of `ma_pcm_rb_pointer_distance()`, `ma_pcm_rb_seek_read()` and +`ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only +move the read pointer forward via the consumer thread, and the write pointer forward by the +producer thread. If there is too much space between the pointers, move the read pointer forward. If there is too little space between the pointers, move the write pointer forward. -You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` API. This is exactly the same, only you will use the `ma_rb` -functions instead of `ma_pcm_rb` and instead of frame counts you will pass around byte counts. +You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` +API. This is exactly the same, only you will use the `ma_rb` functions instead of `ma_pcm_rb` and +instead of frame counts you will pass around byte counts. -The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most significant bit being used to encode a loop flag and the internally -managed buffers always being aligned to MA_SIMD_ALIGNMENT. +The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most +significant bit being used to encode a loop flag and the internally managed buffers always being +aligned to `MA_SIMD_ALIGNMENT`. -Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread. +Note that the ring buffer is only thread safe when used by a single consumer thread and single +producer thread. -11. Backends +15. Backends ============ The following backends are supported by miniaudio. @@ -1426,28 +3538,36 @@ The following backends are supported by miniaudio. Some backends have some nuance details you may want to be aware of. -11.1. WASAPI +15.1. WASAPI ------------ -- Low-latency shared mode will be disabled when using an application-defined sample rate which is different to the device's native sample rate. To work around - this, set `wasapi.noAutoConvertSRC` to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing when the - `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC will result in miniaudio's internal resampler being used instead - which will in turn enable the use of low-latency shared mode. +- Low-latency shared mode will be disabled when using an application-defined sample rate which is + different to the device's native sample rate. To work around this, set `wasapi.noAutoConvertSRC` + to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing + when the `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC + will result in miniaudio's internal resampler being used instead which will in turn enable the + use of low-latency shared mode. -11.2. PulseAudio +15.2. PulseAudio ---------------- - If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki: - https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. Alternatively, consider using a different backend such as ALSA. + https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. + Alternatively, consider using a different backend such as ALSA. -11.3. Android +15.3. Android ------------- -- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: `` -- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES. -- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however - perform your own device enumeration through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it to ma_device_init(). -- The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio's built-in resampler is to take advantage of any - potential device-specific optimizations the driver may implement. +- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: + `` +- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a + limitation with OpenSL|ES. +- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration + API (devices are enumerated through Java). You can however perform your own device enumeration + through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it + to ma_device_init(). +- The backend API will perform resampling where possible. The reason for this as opposed to using + miniaudio's built-in resampler is to take advantage of any potential device-specific + optimizations the driver may implement. -11.4. UWP +15.4. UWP --------- - UWP only supports default playback and capture devices. - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest): @@ -1461,29 +3581,51 @@ Some backends have some nuance details you may want to be aware of. ``` -11.5. Web Audio / Emscripten +15.5. Web Audio / Emscripten ---------------------------- - You cannot use `-std=c*` compiler flags, nor `-ansi`. This only applies to the Emscripten build. -- The first time a context is initialized it will create a global object called "miniaudio" whose primary purpose is to act as a factory for device objects. -- Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated. -- Google has implemented a policy in their browsers that prevent automatic media output without first receiving some kind of user input. The following web page - has additional details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device may fail if you try to start playback - without first handling some kind of user input. +- The first time a context is initialized it will create a global object called "miniaudio" whose + primary purpose is to act as a factory for device objects. +- Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as + they've been deprecated. +- Google has implemented a policy in their browsers that prevent automatic media output without + first receiving some kind of user input. The following web page has additional details: + https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device + may fail if you try to start playback without first handling some kind of user input. -12. Miscellaneous Notes +16. Optimization Tips +===================== + +16.1. High Level API +-------------------- +- If a sound does not require doppler or pitch shifting, consider disabling pitching by + initializing the sound with the `MA_SOUND_FLAG_NO_PITCH` flag. +- If a sound does not require spatialization, disable it by initialzing the sound with the + `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. It can be renabled again post-initialization with + `ma_sound_set_spatialization_enabled()`. + + + +17. Miscellaneous Notes ======================= -- Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as - PulseAudio may naturally support it, though not all have been tested. -- The contents of the output buffer passed into the data callback will always be pre-initialized to silence unless the `noPreZeroedOutputBuffer` config variable - in `ma_device_config` is set to true, in which case it'll be undefined which will require you to write something to the entire buffer. -- By default miniaudio will automatically clip samples. This only applies when the playback sample format is configured as `ma_format_f32`. If you are doing - clipping yourself, you can disable this overhead by setting `noClip` to true in the device config. -- The sndio backend is currently only enabled on OpenBSD builds. -- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it. +- Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for + WASAPI and Core Audio, however other backends such as PulseAudio may naturally support it, though + not all have been tested. +- The contents of the output buffer passed into the data callback will always be pre-initialized to + silence unless the `noPreSilencedOutputBuffer` config variable in `ma_device_config` is set to + true, in which case it'll be undefined which will require you to write something to the entire + buffer. +- By default miniaudio will automatically clip samples. This only applies when the playback sample + format is configured as `ma_format_f32`. If you are doing clipping yourself, you can disable this + overhead by setting `noClip` to true in the device config. - Note that GCC and Clang requires `-msse2`, `-mavx2`, etc. for SIMD optimizations. -- When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This is due to 64-bit file APIs not being available. +- The sndio backend is currently only enabled on OpenBSD builds. +- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can + use it. +- When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This + is due to 64-bit file APIs not being available. */ #ifndef miniaudio_h @@ -1497,8 +3639,8 @@ extern "C" { #define MA_XSTRINGIFY(x) MA_STRINGIFY(x) #define MA_VERSION_MAJOR 0 -#define MA_VERSION_MINOR 10 -#define MA_VERSION_REVISION 42 +#define MA_VERSION_MINOR 11 +#define MA_VERSION_REVISION 9 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -1513,66 +3655,55 @@ extern "C" { #pragma GCC diagnostic ignored "-Wc11-extensions" /* anonymous unions are a C11 extension */ #endif #endif + -/* Platform/backend detection. */ -#ifdef _WIN32 - #define MA_WIN32 - #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - #define MA_WIN32_UWP - #else - #define MA_WIN32_DESKTOP - #endif + +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) + #define MA_SIZEOF_PTR 8 #else - #define MA_POSIX - #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ - - #ifdef __unix__ - #define MA_UNIX - #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - #define MA_BSD - #endif - #endif - #ifdef __linux__ - #define MA_LINUX - #endif - #ifdef __APPLE__ - #define MA_APPLE - #endif - #ifdef __ANDROID__ - #define MA_ANDROID - #endif - #ifdef __EMSCRIPTEN__ - #define MA_EMSCRIPTEN - #endif + #define MA_SIZEOF_PTR 4 #endif #include /* For size_t. */ /* Sized types. */ -typedef signed char ma_int8; -typedef unsigned char ma_uint8; -typedef signed short ma_int16; -typedef unsigned short ma_uint16; -typedef signed int ma_int32; -typedef unsigned int ma_uint32; -#if defined(_MSC_VER) - typedef signed __int64 ma_int64; - typedef unsigned __int64 ma_uint64; +#if defined(MA_USE_STDINT) + #include + typedef int8_t ma_int8; + typedef uint8_t ma_uint8; + typedef int16_t ma_int16; + typedef uint16_t ma_uint16; + typedef int32_t ma_int32; + typedef uint32_t ma_uint32; + typedef int64_t ma_int64; + typedef uint64_t ma_uint64; #else - #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wlong-long" - #if defined(__clang__) - #pragma GCC diagnostic ignored "-Wc++11-long-long" + typedef signed char ma_int8; + typedef unsigned char ma_uint8; + typedef signed short ma_int16; + typedef unsigned short ma_uint16; + typedef signed int ma_int32; + typedef unsigned int ma_uint32; + #if defined(_MSC_VER) && !defined(__clang__) + typedef signed __int64 ma_int64; + typedef unsigned __int64 ma_uint64; + #else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long ma_int64; + typedef unsigned long long ma_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop #endif #endif - typedef signed long long ma_int64; - typedef unsigned long long ma_uint64; - #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) - #pragma GCC diagnostic pop - #endif -#endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +#endif /* MA_USE_STDINT */ + +#if MA_SIZEOF_PTR == 8 typedef ma_uint64 ma_uintptr; #else typedef ma_uint32 ma_uintptr; @@ -1603,6 +3734,58 @@ typedef ma_uint16 wchar_t; #endif +/* Platform/backend detection. */ +#ifdef _WIN32 + #define MA_WIN32 + #if defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PC_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) || (defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)) + #define MA_WIN32_UWP + #elif defined(WINAPI_FAMILY) && (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES) + #define MA_WIN32_GDK + #else + #define MA_WIN32_DESKTOP + #endif +#else + #define MA_POSIX + + /* + Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. + You can use this to avoid including pthread.h in the header section. The downside is that it + results in some fixed sized structures being declared for the various types that are used in + miniaudio. The risk here is that these types might be too small for a given platform. This + risk is yours to take and no support will be offered if you enable this option. + */ + #ifndef MA_NO_PTHREAD_IN_HEADER + #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ + typedef pthread_t ma_pthread_t; + typedef pthread_mutex_t ma_pthread_mutex_t; + typedef pthread_cond_t ma_pthread_cond_t; + #else + typedef ma_uintptr ma_pthread_t; + typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; + typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; + #endif + + #ifdef __unix__ + #define MA_UNIX + #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define MA_BSD + #endif + #endif + #ifdef __linux__ + #define MA_LINUX + #endif + #ifdef __APPLE__ + #define MA_APPLE + #endif + #ifdef __ANDROID__ + #define MA_ANDROID + #endif + #ifdef __EMSCRIPTEN__ + #define MA_EMSCRIPTEN + #endif +#endif + + #ifdef _MSC_VER #define MA_INLINE __forceinline #elif defined(__GNUC__) @@ -1614,9 +3797,15 @@ typedef ma_uint16 wchar_t; I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define MA_INLINE __inline__ __attribute__((always_inline)) + #define MA_GNUC_INLINE_HINT __inline__ #else - #define MA_INLINE inline __attribute__((always_inline)) + #define MA_GNUC_INLINE_HINT inline + #endif + + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define MA_INLINE MA_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define MA_INLINE MA_GNUC_INLINE_HINT #endif #elif defined(__WATCOMC__) #define MA_INLINE __inline @@ -1654,201 +3843,219 @@ typedef ma_uint16 wchar_t; #endif #endif -/* SIMD alignment in bytes. Currently set to 64 bytes in preparation for future AVX-512 optimizations. */ -#define MA_SIMD_ALIGNMENT 64 +/* SIMD alignment in bytes. Currently set to 32 bytes in preparation for future AVX optimizations. */ +#define MA_SIMD_ALIGNMENT 32 /* Logging Levels ============== Log levels are only used to give logging callbacks some context as to the severity of a log message -so they can do filtering. All log levels will be posted to registered logging callbacks, except for -MA_LOG_LEVEL_DEBUG which will only get processed if MA_DEBUG_OUTPUT is enabled. +so they can do filtering. All log levels will be posted to registered logging callbacks. If you +don't want to output a certain log level you can discriminate against the log level in the callback. MA_LOG_LEVEL_DEBUG - Used for debugging. These log messages are only posted when `MA_DEBUG_OUTPUT` is enabled. + Used for debugging. Useful for debug and test builds, but should be disabled in release builds. MA_LOG_LEVEL_INFO - Informational logging. Useful for debugging. This will also enable warning and error logs. This - will never be called from within the data callback. + Informational logging. Useful for debugging. This will never be called from within the data + callback. MA_LOG_LEVEL_WARNING - Warnings. You should enable this in you development builds and action them when encounted. This - will also enable error logs. These logs usually indicate a potential problem or - misconfiguration, but still allow you to keep running. This will never be called from within - the data callback. + Warnings. You should enable this in you development builds and action them when encounted. These + logs usually indicate a potential problem or misconfiguration, but still allow you to keep + running. This will never be called from within the data callback. MA_LOG_LEVEL_ERROR Error logging. This will be fired when an operation fails and is subsequently aborted. This can be fired from within the data callback, in which case the device will be stopped. You should always have this log level enabled. */ -#define MA_LOG_LEVEL_DEBUG 4 -#define MA_LOG_LEVEL_INFO 3 -#define MA_LOG_LEVEL_WARNING 2 -#define MA_LOG_LEVEL_ERROR 1 - -/* Deprecated. */ -#define MA_LOG_LEVEL_VERBOSE MA_LOG_LEVEL_DEBUG - -/* Deprecated. */ -#ifndef MA_LOG_LEVEL -#define MA_LOG_LEVEL MA_LOG_LEVEL_ERROR -#endif +typedef enum +{ + MA_LOG_LEVEL_DEBUG = 4, + MA_LOG_LEVEL_INFO = 3, + MA_LOG_LEVEL_WARNING = 2, + MA_LOG_LEVEL_ERROR = 1 +} ma_log_level; /* -An annotation for variables which must be used atomically. This doesn't actually do anything - it's -just used as a way for humans to identify variables that should be used atomically. +Variables needing to be accessed atomically should be declared with this macro for two reasons: + + 1) It allows people who read the code to identify a variable as such; and + 2) It forces alignment on platforms where it's required or optimal. + +Note that for x86/64, alignment is not strictly necessary, but does have some performance +implications. Where supported by the compiler, alignment will be used, but otherwise if the CPU +architecture does not require it, it will simply leave it unaligned. This is the case with old +versions of Visual Studio, which I've confirmed with at least VC6. */ -#define MA_ATOMIC +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) + #include + #define MA_ATOMIC(alignment, type) alignas(alignment) type +#else + #if defined(__GNUC__) + /* GCC-style compilers. */ + #define MA_ATOMIC(alignment, type) type __attribute__((aligned(alignment))) + #elif defined(_MSC_VER) && _MSC_VER > 1200 /* 1200 = VC6. Alignment not supported, but not necessary because x86 is the only supported target. */ + /* MSVC. */ + #define MA_ATOMIC(alignment, type) __declspec(align(alignment)) type + #else + /* Other compilers. */ + #define MA_ATOMIC(alignment, type) type + #endif +#endif typedef struct ma_context ma_context; typedef struct ma_device ma_device; typedef ma_uint8 ma_channel; -#define MA_CHANNEL_NONE 0 -#define MA_CHANNEL_MONO 1 -#define MA_CHANNEL_FRONT_LEFT 2 -#define MA_CHANNEL_FRONT_RIGHT 3 -#define MA_CHANNEL_FRONT_CENTER 4 -#define MA_CHANNEL_LFE 5 -#define MA_CHANNEL_BACK_LEFT 6 -#define MA_CHANNEL_BACK_RIGHT 7 -#define MA_CHANNEL_FRONT_LEFT_CENTER 8 -#define MA_CHANNEL_FRONT_RIGHT_CENTER 9 -#define MA_CHANNEL_BACK_CENTER 10 -#define MA_CHANNEL_SIDE_LEFT 11 -#define MA_CHANNEL_SIDE_RIGHT 12 -#define MA_CHANNEL_TOP_CENTER 13 -#define MA_CHANNEL_TOP_FRONT_LEFT 14 -#define MA_CHANNEL_TOP_FRONT_CENTER 15 -#define MA_CHANNEL_TOP_FRONT_RIGHT 16 -#define MA_CHANNEL_TOP_BACK_LEFT 17 -#define MA_CHANNEL_TOP_BACK_CENTER 18 -#define MA_CHANNEL_TOP_BACK_RIGHT 19 -#define MA_CHANNEL_AUX_0 20 -#define MA_CHANNEL_AUX_1 21 -#define MA_CHANNEL_AUX_2 22 -#define MA_CHANNEL_AUX_3 23 -#define MA_CHANNEL_AUX_4 24 -#define MA_CHANNEL_AUX_5 25 -#define MA_CHANNEL_AUX_6 26 -#define MA_CHANNEL_AUX_7 27 -#define MA_CHANNEL_AUX_8 28 -#define MA_CHANNEL_AUX_9 29 -#define MA_CHANNEL_AUX_10 30 -#define MA_CHANNEL_AUX_11 31 -#define MA_CHANNEL_AUX_12 32 -#define MA_CHANNEL_AUX_13 33 -#define MA_CHANNEL_AUX_14 34 -#define MA_CHANNEL_AUX_15 35 -#define MA_CHANNEL_AUX_16 36 -#define MA_CHANNEL_AUX_17 37 -#define MA_CHANNEL_AUX_18 38 -#define MA_CHANNEL_AUX_19 39 -#define MA_CHANNEL_AUX_20 40 -#define MA_CHANNEL_AUX_21 41 -#define MA_CHANNEL_AUX_22 42 -#define MA_CHANNEL_AUX_23 43 -#define MA_CHANNEL_AUX_24 44 -#define MA_CHANNEL_AUX_25 45 -#define MA_CHANNEL_AUX_26 46 -#define MA_CHANNEL_AUX_27 47 -#define MA_CHANNEL_AUX_28 48 -#define MA_CHANNEL_AUX_29 49 -#define MA_CHANNEL_AUX_30 50 -#define MA_CHANNEL_AUX_31 51 -#define MA_CHANNEL_LEFT MA_CHANNEL_FRONT_LEFT -#define MA_CHANNEL_RIGHT MA_CHANNEL_FRONT_RIGHT -#define MA_CHANNEL_POSITION_COUNT (MA_CHANNEL_AUX_31 + 1) +typedef enum +{ + MA_CHANNEL_NONE = 0, + MA_CHANNEL_MONO = 1, + MA_CHANNEL_FRONT_LEFT = 2, + MA_CHANNEL_FRONT_RIGHT = 3, + MA_CHANNEL_FRONT_CENTER = 4, + MA_CHANNEL_LFE = 5, + MA_CHANNEL_BACK_LEFT = 6, + MA_CHANNEL_BACK_RIGHT = 7, + MA_CHANNEL_FRONT_LEFT_CENTER = 8, + MA_CHANNEL_FRONT_RIGHT_CENTER = 9, + MA_CHANNEL_BACK_CENTER = 10, + MA_CHANNEL_SIDE_LEFT = 11, + MA_CHANNEL_SIDE_RIGHT = 12, + MA_CHANNEL_TOP_CENTER = 13, + MA_CHANNEL_TOP_FRONT_LEFT = 14, + MA_CHANNEL_TOP_FRONT_CENTER = 15, + MA_CHANNEL_TOP_FRONT_RIGHT = 16, + MA_CHANNEL_TOP_BACK_LEFT = 17, + MA_CHANNEL_TOP_BACK_CENTER = 18, + MA_CHANNEL_TOP_BACK_RIGHT = 19, + MA_CHANNEL_AUX_0 = 20, + MA_CHANNEL_AUX_1 = 21, + MA_CHANNEL_AUX_2 = 22, + MA_CHANNEL_AUX_3 = 23, + MA_CHANNEL_AUX_4 = 24, + MA_CHANNEL_AUX_5 = 25, + MA_CHANNEL_AUX_6 = 26, + MA_CHANNEL_AUX_7 = 27, + MA_CHANNEL_AUX_8 = 28, + MA_CHANNEL_AUX_9 = 29, + MA_CHANNEL_AUX_10 = 30, + MA_CHANNEL_AUX_11 = 31, + MA_CHANNEL_AUX_12 = 32, + MA_CHANNEL_AUX_13 = 33, + MA_CHANNEL_AUX_14 = 34, + MA_CHANNEL_AUX_15 = 35, + MA_CHANNEL_AUX_16 = 36, + MA_CHANNEL_AUX_17 = 37, + MA_CHANNEL_AUX_18 = 38, + MA_CHANNEL_AUX_19 = 39, + MA_CHANNEL_AUX_20 = 40, + MA_CHANNEL_AUX_21 = 41, + MA_CHANNEL_AUX_22 = 42, + MA_CHANNEL_AUX_23 = 43, + MA_CHANNEL_AUX_24 = 44, + MA_CHANNEL_AUX_25 = 45, + MA_CHANNEL_AUX_26 = 46, + MA_CHANNEL_AUX_27 = 47, + MA_CHANNEL_AUX_28 = 48, + MA_CHANNEL_AUX_29 = 49, + MA_CHANNEL_AUX_30 = 50, + MA_CHANNEL_AUX_31 = 51, + MA_CHANNEL_LEFT = MA_CHANNEL_FRONT_LEFT, + MA_CHANNEL_RIGHT = MA_CHANNEL_FRONT_RIGHT, + MA_CHANNEL_POSITION_COUNT = (MA_CHANNEL_AUX_31 + 1) +} _ma_channel_position; /* Do not use `_ma_channel_position` directly. Use `ma_channel` instead. */ + +typedef enum +{ + MA_SUCCESS = 0, + MA_ERROR = -1, /* A generic error. */ + MA_INVALID_ARGS = -2, + MA_INVALID_OPERATION = -3, + MA_OUT_OF_MEMORY = -4, + MA_OUT_OF_RANGE = -5, + MA_ACCESS_DENIED = -6, + MA_DOES_NOT_EXIST = -7, + MA_ALREADY_EXISTS = -8, + MA_TOO_MANY_OPEN_FILES = -9, + MA_INVALID_FILE = -10, + MA_TOO_BIG = -11, + MA_PATH_TOO_LONG = -12, + MA_NAME_TOO_LONG = -13, + MA_NOT_DIRECTORY = -14, + MA_IS_DIRECTORY = -15, + MA_DIRECTORY_NOT_EMPTY = -16, + MA_AT_END = -17, + MA_NO_SPACE = -18, + MA_BUSY = -19, + MA_IO_ERROR = -20, + MA_INTERRUPT = -21, + MA_UNAVAILABLE = -22, + MA_ALREADY_IN_USE = -23, + MA_BAD_ADDRESS = -24, + MA_BAD_SEEK = -25, + MA_BAD_PIPE = -26, + MA_DEADLOCK = -27, + MA_TOO_MANY_LINKS = -28, + MA_NOT_IMPLEMENTED = -29, + MA_NO_MESSAGE = -30, + MA_BAD_MESSAGE = -31, + MA_NO_DATA_AVAILABLE = -32, + MA_INVALID_DATA = -33, + MA_TIMEOUT = -34, + MA_NO_NETWORK = -35, + MA_NOT_UNIQUE = -36, + MA_NOT_SOCKET = -37, + MA_NO_ADDRESS = -38, + MA_BAD_PROTOCOL = -39, + MA_PROTOCOL_UNAVAILABLE = -40, + MA_PROTOCOL_NOT_SUPPORTED = -41, + MA_PROTOCOL_FAMILY_NOT_SUPPORTED = -42, + MA_ADDRESS_FAMILY_NOT_SUPPORTED = -43, + MA_SOCKET_NOT_SUPPORTED = -44, + MA_CONNECTION_RESET = -45, + MA_ALREADY_CONNECTED = -46, + MA_NOT_CONNECTED = -47, + MA_CONNECTION_REFUSED = -48, + MA_NO_HOST = -49, + MA_IN_PROGRESS = -50, + MA_CANCELLED = -51, + MA_MEMORY_ALREADY_MAPPED = -52, + + /* General miniaudio-specific errors. */ + MA_FORMAT_NOT_SUPPORTED = -100, + MA_DEVICE_TYPE_NOT_SUPPORTED = -101, + MA_SHARE_MODE_NOT_SUPPORTED = -102, + MA_NO_BACKEND = -103, + MA_NO_DEVICE = -104, + MA_API_NOT_FOUND = -105, + MA_INVALID_DEVICE_CONFIG = -106, + MA_LOOP = -107, + + /* State errors. */ + MA_DEVICE_NOT_INITIALIZED = -200, + MA_DEVICE_ALREADY_INITIALIZED = -201, + MA_DEVICE_NOT_STARTED = -202, + MA_DEVICE_NOT_STOPPED = -203, + + /* Operation errors. */ + MA_FAILED_TO_INIT_BACKEND = -300, + MA_FAILED_TO_OPEN_BACKEND_DEVICE = -301, + MA_FAILED_TO_START_BACKEND_DEVICE = -302, + MA_FAILED_TO_STOP_BACKEND_DEVICE = -303 +} ma_result; -typedef int ma_result; -#define MA_SUCCESS 0 -#define MA_ERROR -1 /* A generic error. */ -#define MA_INVALID_ARGS -2 -#define MA_INVALID_OPERATION -3 -#define MA_OUT_OF_MEMORY -4 -#define MA_OUT_OF_RANGE -5 -#define MA_ACCESS_DENIED -6 -#define MA_DOES_NOT_EXIST -7 -#define MA_ALREADY_EXISTS -8 -#define MA_TOO_MANY_OPEN_FILES -9 -#define MA_INVALID_FILE -10 -#define MA_TOO_BIG -11 -#define MA_PATH_TOO_LONG -12 -#define MA_NAME_TOO_LONG -13 -#define MA_NOT_DIRECTORY -14 -#define MA_IS_DIRECTORY -15 -#define MA_DIRECTORY_NOT_EMPTY -16 -#define MA_AT_END -17 -#define MA_NO_SPACE -18 -#define MA_BUSY -19 -#define MA_IO_ERROR -20 -#define MA_INTERRUPT -21 -#define MA_UNAVAILABLE -22 -#define MA_ALREADY_IN_USE -23 -#define MA_BAD_ADDRESS -24 -#define MA_BAD_SEEK -25 -#define MA_BAD_PIPE -26 -#define MA_DEADLOCK -27 -#define MA_TOO_MANY_LINKS -28 -#define MA_NOT_IMPLEMENTED -29 -#define MA_NO_MESSAGE -30 -#define MA_BAD_MESSAGE -31 -#define MA_NO_DATA_AVAILABLE -32 -#define MA_INVALID_DATA -33 -#define MA_TIMEOUT -34 -#define MA_NO_NETWORK -35 -#define MA_NOT_UNIQUE -36 -#define MA_NOT_SOCKET -37 -#define MA_NO_ADDRESS -38 -#define MA_BAD_PROTOCOL -39 -#define MA_PROTOCOL_UNAVAILABLE -40 -#define MA_PROTOCOL_NOT_SUPPORTED -41 -#define MA_PROTOCOL_FAMILY_NOT_SUPPORTED -42 -#define MA_ADDRESS_FAMILY_NOT_SUPPORTED -43 -#define MA_SOCKET_NOT_SUPPORTED -44 -#define MA_CONNECTION_RESET -45 -#define MA_ALREADY_CONNECTED -46 -#define MA_NOT_CONNECTED -47 -#define MA_CONNECTION_REFUSED -48 -#define MA_NO_HOST -49 -#define MA_IN_PROGRESS -50 -#define MA_CANCELLED -51 -#define MA_MEMORY_ALREADY_MAPPED -52 - -/* General miniaudio-specific errors. */ -#define MA_FORMAT_NOT_SUPPORTED -100 -#define MA_DEVICE_TYPE_NOT_SUPPORTED -101 -#define MA_SHARE_MODE_NOT_SUPPORTED -102 -#define MA_NO_BACKEND -103 -#define MA_NO_DEVICE -104 -#define MA_API_NOT_FOUND -105 -#define MA_INVALID_DEVICE_CONFIG -106 -#define MA_LOOP -107 - -/* State errors. */ -#define MA_DEVICE_NOT_INITIALIZED -200 -#define MA_DEVICE_ALREADY_INITIALIZED -201 -#define MA_DEVICE_NOT_STARTED -202 -#define MA_DEVICE_NOT_STOPPED -203 - -/* Operation errors. */ -#define MA_FAILED_TO_INIT_BACKEND -300 -#define MA_FAILED_TO_OPEN_BACKEND_DEVICE -301 -#define MA_FAILED_TO_START_BACKEND_DEVICE -302 -#define MA_FAILED_TO_STOP_BACKEND_DEVICE -303 - - -#define MA_MIN_CHANNELS 1 -#ifndef MA_MAX_CHANNELS -#define MA_MAX_CHANNELS 32 +#define MA_MIN_CHANNELS 1 +#ifndef MA_MAX_CHANNELS +#define MA_MAX_CHANNELS 254 #endif - #ifndef MA_MAX_FILTER_ORDER -#define MA_MAX_FILTER_ORDER 8 +#define MA_MAX_FILTER_ORDER 8 #endif typedef enum @@ -1911,17 +4118,12 @@ typedef enum ma_standard_sample_rate_count = 14 /* Need to maintain the count manually. Make sure this is updated if items are added to enum. */ } ma_standard_sample_rate; -/* These are deprecated. Use ma_standard_sample_rate_min and ma_standard_sample_rate_max. */ -#define MA_MIN_SAMPLE_RATE (ma_uint32)ma_standard_sample_rate_min -#define MA_MAX_SAMPLE_RATE (ma_uint32)ma_standard_sample_rate_max - typedef enum { ma_channel_mix_mode_rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */ ma_channel_mix_mode_simple, /* Drop excess channels; zeroed out extra channels. */ ma_channel_mix_mode_custom_weights, /* Use custom weights specified in ma_channel_router_config. */ - ma_channel_mix_mode_planar_blend = ma_channel_mix_mode_rectangular, ma_channel_mix_mode_default = ma_channel_mix_mode_rectangular } ma_channel_mix_mode; @@ -1959,6 +4161,9 @@ typedef struct } ma_lcg; +/* Spinlocks are 32-bit for compatibility reasons. */ +typedef ma_uint32 ma_spinlock; + #ifndef MA_NO_THREADING /* Thread priorities should be ordered such that the default priority of the worker thread is 0. */ typedef enum @@ -1973,21 +4178,18 @@ typedef enum ma_thread_priority_default = 0 } ma_thread_priority; -/* Spinlocks are 32-bit for compatibility reasons. */ -typedef ma_uint32 ma_spinlock; - #if defined(MA_WIN32) typedef ma_handle ma_thread; #endif #if defined(MA_POSIX) -typedef pthread_t ma_thread; +typedef ma_pthread_t ma_thread; #endif #if defined(MA_WIN32) typedef ma_handle ma_mutex; #endif #if defined(MA_POSIX) -typedef pthread_mutex_t ma_mutex; +typedef ma_pthread_mutex_t ma_mutex; #endif #if defined(MA_WIN32) @@ -1997,8 +4199,8 @@ typedef ma_handle ma_event; typedef struct { ma_uint32 value; - pthread_mutex_t lock; - pthread_cond_t cond; + ma_pthread_mutex_t lock; + ma_pthread_cond_t cond; } ma_event; #endif /* MA_POSIX */ @@ -2009,8 +4211,8 @@ typedef ma_handle ma_semaphore; typedef struct { int value; - pthread_mutex_t lock; - pthread_cond_t cond; + ma_pthread_mutex_t lock; + ma_pthread_cond_t cond; } ma_semaphore; #endif /* MA_POSIX */ #else @@ -2052,6 +4254,36 @@ Logging #define MA_MAX_LOG_CALLBACKS 4 #endif + +/* +The callback for handling log messages. + + +Parameters +---------- +pUserData (in) + The user data pointer that was passed into ma_log_register_callback(). + +logLevel (in) + The log level. This can be one of the following: + + +----------------------+ + | Log Level | + +----------------------+ + | MA_LOG_LEVEL_DEBUG | + | MA_LOG_LEVEL_INFO | + | MA_LOG_LEVEL_WARNING | + | MA_LOG_LEVEL_ERROR | + +----------------------+ + +pMessage (in) + The log message. + + +Remarks +------- +Do not modify the state of the device from inside the callback. +*/ typedef void (* ma_log_callback_proc)(void* pUserData, ma_uint32 level, const char* pMessage); typedef struct @@ -2116,12 +4348,20 @@ typedef struct ma_biquad_coefficient b2; ma_biquad_coefficient a1; ma_biquad_coefficient a2; - ma_biquad_coefficient r1[MA_MAX_CHANNELS]; - ma_biquad_coefficient r2[MA_MAX_CHANNELS]; + ma_biquad_coefficient* pR1; + ma_biquad_coefficient* pR2; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_biquad; -MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ); +MA_API ma_result ma_biquad_get_heap_size(const ma_biquad_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_biquad_init_preallocated(const ma_biquad_config* pConfig, void* pHeap, ma_biquad* pBQ); +MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad* pBQ); +MA_API void ma_biquad_uninit(ma_biquad* pBQ, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ); +MA_API ma_result ma_biquad_clear_cache(ma_biquad* pBQ); MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_biquad_get_latency(const ma_biquad* pBQ); @@ -2148,11 +4388,19 @@ typedef struct ma_format format; ma_uint32 channels; ma_biquad_coefficient a; - ma_biquad_coefficient r1[MA_MAX_CHANNELS]; + ma_biquad_coefficient* pR1; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_lpf1; -MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF); +MA_API ma_result ma_lpf1_get_heap_size(const ma_lpf1_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_lpf1_init_preallocated(const ma_lpf1_config* pConfig, void* pHeap, ma_lpf1* pLPF); +MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf1* pLPF); +MA_API void ma_lpf1_uninit(ma_lpf1* pLPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF); +MA_API ma_result ma_lpf1_clear_cache(ma_lpf1* pLPF); MA_API ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_lpf1_get_latency(const ma_lpf1* pLPF); @@ -2161,8 +4409,12 @@ typedef struct ma_biquad bq; /* The second order low-pass filter is implemented as a biquad filter. */ } ma_lpf2; -MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF); +MA_API ma_result ma_lpf2_get_heap_size(const ma_lpf2_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* pHeap, ma_lpf2* pHPF); +MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf2* pLPF); +MA_API void ma_lpf2_uninit(ma_lpf2* pLPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF); +MA_API ma_result ma_lpf2_clear_cache(ma_lpf2* pLPF); MA_API ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_lpf2_get_latency(const ma_lpf2* pLPF); @@ -2185,12 +4437,20 @@ typedef struct ma_uint32 sampleRate; ma_uint32 lpf1Count; ma_uint32 lpf2Count; - ma_lpf1 lpf1[1]; - ma_lpf2 lpf2[MA_MAX_FILTER_ORDER/2]; + ma_lpf1* pLPF1; + ma_lpf2* pLPF2; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_lpf; -MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF); +MA_API ma_result ma_lpf_get_heap_size(const ma_lpf_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_lpf_init_preallocated(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF); +MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf* pLPF); +MA_API void ma_lpf_uninit(ma_lpf* pLPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF); +MA_API ma_result ma_lpf_clear_cache(ma_lpf* pLPF); MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_lpf_get_latency(const ma_lpf* pLPF); @@ -2217,10 +4477,17 @@ typedef struct ma_format format; ma_uint32 channels; ma_biquad_coefficient a; - ma_biquad_coefficient r1[MA_MAX_CHANNELS]; + ma_biquad_coefficient* pR1; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_hpf1; -MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF); +MA_API ma_result ma_hpf1_get_heap_size(const ma_hpf1_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_hpf1_init_preallocated(const ma_hpf1_config* pConfig, void* pHeap, ma_hpf1* pLPF); +MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf1* pHPF); +MA_API void ma_hpf1_uninit(ma_hpf1* pHPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF); MA_API ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hpf1_get_latency(const ma_hpf1* pHPF); @@ -2230,7 +4497,10 @@ typedef struct ma_biquad bq; /* The second order high-pass filter is implemented as a biquad filter. */ } ma_hpf2; -MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF); +MA_API ma_result ma_hpf2_get_heap_size(const ma_hpf2_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* pHeap, ma_hpf2* pHPF); +MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf2* pHPF); +MA_API void ma_hpf2_uninit(ma_hpf2* pHPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF); MA_API ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hpf2_get_latency(const ma_hpf2* pHPF); @@ -2254,11 +4524,18 @@ typedef struct ma_uint32 sampleRate; ma_uint32 hpf1Count; ma_uint32 hpf2Count; - ma_hpf1 hpf1[1]; - ma_hpf2 hpf2[MA_MAX_FILTER_ORDER/2]; + ma_hpf1* pHPF1; + ma_hpf2* pHPF2; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_hpf; -MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF); +MA_API ma_result ma_hpf_get_heap_size(const ma_hpf_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_hpf_init_preallocated(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pLPF); +MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf* pHPF); +MA_API void ma_hpf_uninit(ma_hpf* pHPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF); MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hpf_get_latency(const ma_hpf* pHPF); @@ -2285,7 +4562,10 @@ typedef struct ma_biquad bq; /* The second order band-pass filter is implemented as a biquad filter. */ } ma_bpf2; -MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF); +MA_API ma_result ma_bpf2_get_heap_size(const ma_bpf2_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* pHeap, ma_bpf2* pBPF); +MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf2* pBPF); +MA_API void ma_bpf2_uninit(ma_bpf2* pBPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF); MA_API ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_bpf2_get_latency(const ma_bpf2* pBPF); @@ -2307,10 +4587,17 @@ typedef struct ma_format format; ma_uint32 channels; ma_uint32 bpf2Count; - ma_bpf2 bpf2[MA_MAX_FILTER_ORDER/2]; + ma_bpf2* pBPF2; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_bpf; -MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF); +MA_API ma_result ma_bpf_get_heap_size(const ma_bpf_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_bpf_init_preallocated(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF); +MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf* pBPF); +MA_API void ma_bpf_uninit(ma_bpf* pBPF, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF); MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_bpf_get_latency(const ma_bpf* pBPF); @@ -2337,7 +4624,10 @@ typedef struct ma_biquad bq; } ma_notch2; -MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter); +MA_API ma_result ma_notch2_get_heap_size(const ma_notch2_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, void* pHeap, ma_notch2* pFilter); +MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch2* pFilter); +MA_API void ma_notch2_uninit(ma_notch2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter); MA_API ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_notch2_get_latency(const ma_notch2* pFilter); @@ -2365,7 +4655,10 @@ typedef struct ma_biquad bq; } ma_peak2; -MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter); +MA_API ma_result ma_peak2_get_heap_size(const ma_peak2_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void* pHeap, ma_peak2* pFilter); +MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak2* pFilter); +MA_API void ma_peak2_uninit(ma_peak2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter); MA_API ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_peak2_get_latency(const ma_peak2* pFilter); @@ -2393,7 +4686,10 @@ typedef struct ma_biquad bq; } ma_loshelf2; -MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter); +MA_API ma_result ma_loshelf2_get_heap_size(const ma_loshelf2_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig, void* pHeap, ma_loshelf2* pFilter); +MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf2* pFilter); +MA_API void ma_loshelf2_uninit(ma_loshelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter); MA_API ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_loshelf2_get_latency(const ma_loshelf2* pFilter); @@ -2421,13 +4717,316 @@ typedef struct ma_biquad bq; } ma_hishelf2; -MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter); +MA_API ma_result ma_hishelf2_get_heap_size(const ma_hishelf2_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig, void* pHeap, ma_hishelf2* pFilter); +MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf2* pFilter); +MA_API void ma_hishelf2_uninit(ma_hishelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter); MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter); +/* +Delay +*/ +typedef struct +{ + ma_uint32 channels; + ma_uint32 sampleRate; + ma_uint32 delayInFrames; + ma_bool32 delayStart; /* Set to true to delay the start of the output; false otherwise. */ + float wet; /* 0..1. Default = 1. */ + float dry; /* 0..1. Default = 1. */ + float decay; /* 0..1. Default = 0 (no feedback). Feedback decay. Use this for echo. */ +} ma_delay_config; + +MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay); + + +typedef struct +{ + ma_delay_config config; + ma_uint32 cursor; /* Feedback is written to this cursor. Always equal or in front of the read cursor. */ + ma_uint32 bufferSizeInFrames; /* The maximum of config.startDelayInFrames and config.feedbackDelayInFrames. */ + float* pBuffer; +} ma_delay; + +MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay); +MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount); +MA_API void ma_delay_set_wet(ma_delay* pDelay, float value); +MA_API float ma_delay_get_wet(const ma_delay* pDelay); +MA_API void ma_delay_set_dry(ma_delay* pDelay, float value); +MA_API float ma_delay_get_dry(const ma_delay* pDelay); +MA_API void ma_delay_set_decay(ma_delay* pDelay, float value); +MA_API float ma_delay_get_decay(const ma_delay* pDelay); + + +/* Gainer for smooth volume changes. */ +typedef struct +{ + ma_uint32 channels; + ma_uint32 smoothTimeInFrames; +} ma_gainer_config; + +MA_API ma_gainer_config ma_gainer_config_init(ma_uint32 channels, ma_uint32 smoothTimeInFrames); + + +typedef struct +{ + ma_gainer_config config; + ma_uint32 t; + float* pOldGains; + float* pNewGains; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} ma_gainer; + +MA_API ma_result ma_gainer_get_heap_size(const ma_gainer_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_gainer_init_preallocated(const ma_gainer_config* pConfig, void* pHeap, ma_gainer* pGainer); +MA_API ma_result ma_gainer_init(const ma_gainer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_gainer* pGainer); +MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); +MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain); +MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains); + + + +/* Stereo panner. */ +typedef enum +{ + ma_pan_mode_balance = 0, /* Does not blend one side with the other. Technically just a balance. Compatible with other popular audio engines and therefore the default. */ + ma_pan_mode_pan /* A true pan. The sound from one side will "move" to the other side and blend with it. */ +} ma_pan_mode; + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_pan_mode mode; + float pan; +} ma_panner_config; + +MA_API ma_panner_config ma_panner_config_init(ma_format format, ma_uint32 channels); + + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_pan_mode mode; + float pan; /* -1..1 where 0 is no pan, -1 is left side, +1 is right side. Defaults to 0. */ +} ma_panner; + +MA_API ma_result ma_panner_init(const ma_panner_config* pConfig, ma_panner* pPanner); +MA_API ma_result ma_panner_process_pcm_frames(ma_panner* pPanner, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); +MA_API void ma_panner_set_mode(ma_panner* pPanner, ma_pan_mode mode); +MA_API ma_pan_mode ma_panner_get_mode(const ma_panner* pPanner); +MA_API void ma_panner_set_pan(ma_panner* pPanner, float pan); +MA_API float ma_panner_get_pan(const ma_panner* pPanner); + + + +/* Fader. */ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; +} ma_fader_config; + +MA_API ma_fader_config ma_fader_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate); + +typedef struct +{ + ma_fader_config config; + float volumeBeg; /* If volumeBeg and volumeEnd is equal to 1, no fading happens (ma_fader_process_pcm_frames() will run as a passthrough). */ + float volumeEnd; + ma_uint64 lengthInFrames; /* The total length of the fade. */ + ma_uint64 cursorInFrames; /* The current time in frames. Incremented by ma_fader_process_pcm_frames(). */ +} ma_fader; + +MA_API ma_result ma_fader_init(const ma_fader_config* pConfig, ma_fader* pFader); +MA_API ma_result ma_fader_process_pcm_frames(ma_fader* pFader, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); +MA_API void ma_fader_get_data_format(const ma_fader* pFader, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); +MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames); +MA_API float ma_fader_get_current_volume(ma_fader* pFader); + + + +/* Spatializer. */ +typedef struct +{ + float x; + float y; + float z; +} ma_vec3f; + +typedef enum +{ + ma_attenuation_model_none, /* No distance attenuation and no spatialization. */ + ma_attenuation_model_inverse, /* Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED. */ + ma_attenuation_model_linear, /* Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED. */ + ma_attenuation_model_exponential /* Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED. */ +} ma_attenuation_model; + +typedef enum +{ + ma_positioning_absolute, + ma_positioning_relative +} ma_positioning; + +typedef enum +{ + ma_handedness_right, + ma_handedness_left +} ma_handedness; + + +typedef struct +{ + ma_uint32 channelsOut; + ma_channel* pChannelMapOut; + ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ + float coneInnerAngleInRadians; + float coneOuterAngleInRadians; + float coneOuterGain; + float speedOfSound; + ma_vec3f worldUp; +} ma_spatializer_listener_config; + +MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(ma_uint32 channelsOut); + + +typedef struct +{ + ma_spatializer_listener_config config; + ma_vec3f position; /* The absolute position of the listener. */ + ma_vec3f direction; /* The direction the listener is facing. The world up vector is config.worldUp. */ + ma_vec3f velocity; + ma_bool32 isEnabled; + + /* Memory management. */ + ma_bool32 _ownsHeap; + void* _pHeap; +} ma_spatializer_listener; + +MA_API ma_result ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config* pConfig, void* pHeap, ma_spatializer_listener* pListener); +MA_API ma_result ma_spatializer_listener_init(const ma_spatializer_listener_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer_listener* pListener); +MA_API void ma_spatializer_listener_uninit(ma_spatializer_listener* pListener, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_channel* ma_spatializer_listener_get_channel_map(ma_spatializer_listener* pListener); +MA_API void ma_spatializer_listener_set_cone(ma_spatializer_listener* pListener, float innerAngleInRadians, float outerAngleInRadians, float outerGain); +MA_API void ma_spatializer_listener_get_cone(const ma_spatializer_listener* pListener, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); +MA_API void ma_spatializer_listener_set_position(ma_spatializer_listener* pListener, float x, float y, float z); +MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener* pListener); +MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pListener, float x, float y, float z); +MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener* pListener); +MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListener, float x, float y, float z); +MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener* pListener); +MA_API void ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener* pListener, float speedOfSound); +MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener* pListener); +MA_API void ma_spatializer_listener_set_world_up(ma_spatializer_listener* pListener, float x, float y, float z); +MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener* pListener); +MA_API void ma_spatializer_listener_set_enabled(ma_spatializer_listener* pListener, ma_bool32 isEnabled); +MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener* pListener); + + +typedef struct +{ + ma_uint32 channelsIn; + ma_uint32 channelsOut; + ma_channel* pChannelMapIn; + ma_attenuation_model attenuationModel; + ma_positioning positioning; + ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ + float minGain; + float maxGain; + float minDistance; + float maxDistance; + float rolloff; + float coneInnerAngleInRadians; + float coneOuterAngleInRadians; + float coneOuterGain; + float dopplerFactor; /* Set to 0 to disable doppler effect. */ + float directionalAttenuationFactor; /* Set to 0 to disable directional attenuation. */ + ma_uint32 gainSmoothTimeInFrames; /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ +} ma_spatializer_config; + +MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma_uint32 channelsOut); + + +typedef struct +{ + ma_uint32 channelsIn; + ma_uint32 channelsOut; + ma_channel* pChannelMapIn; + ma_attenuation_model attenuationModel; + ma_positioning positioning; + ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */ + float minGain; + float maxGain; + float minDistance; + float maxDistance; + float rolloff; + float coneInnerAngleInRadians; + float coneOuterAngleInRadians; + float coneOuterGain; + float dopplerFactor; /* Set to 0 to disable doppler effect. */ + float directionalAttenuationFactor; /* Set to 0 to disable directional attenuation. */ + ma_uint32 gainSmoothTimeInFrames; /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ + ma_vec3f position; + ma_vec3f direction; + ma_vec3f velocity; /* For doppler effect. */ + float dopplerPitch; /* Will be updated by ma_spatializer_process_pcm_frames() and can be used by higher level functions to apply a pitch shift for doppler effect. */ + ma_gainer gainer; /* For smooth gain transitions. */ + float* pNewChannelGainsOut; /* An offset of _pHeap. Used by ma_spatializer_process_pcm_frames() to store new channel gains. The number of elements in this array is equal to config.channelsOut. */ + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} ma_spatializer; + +MA_API ma_result ma_spatializer_get_heap_size(const ma_spatializer_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* pConfig, void* pHeap, ma_spatializer* pSpatializer); +MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer* pSpatializer); +MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); +MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer); +MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel); +MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning); +MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff); +MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain); +MA_API float ma_spatializer_get_min_gain(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_max_gain(ma_spatializer* pSpatializer, float maxGain); +MA_API float ma_spatializer_get_max_gain(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_min_distance(ma_spatializer* pSpatializer, float minDistance); +MA_API float ma_spatializer_get_min_distance(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_max_distance(ma_spatializer* pSpatializer, float maxDistance); +MA_API float ma_spatializer_get_max_distance(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAngleInRadians, float outerAngleInRadians, float outerGain); +MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); +MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor); +MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor); +MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z); +MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z); +MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z); +MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir); + + + /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -2465,75 +5064,106 @@ typedef struct ma_uint32 inTimeFrac; union { - float f32[MA_MAX_CHANNELS]; - ma_int16 s16[MA_MAX_CHANNELS]; + float* f32; + ma_int16* s16; } x0; /* The previous input frame. */ union { - float f32[MA_MAX_CHANNELS]; - ma_int16 s16[MA_MAX_CHANNELS]; + float* f32; + ma_int16* s16; } x1; /* The next input frame. */ ma_lpf lpf; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_linear_resampler; -MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler); -MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler); +MA_API ma_result ma_linear_resampler_get_heap_size(const ma_linear_resampler_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler_config* pConfig, void* pHeap, ma_linear_resampler* pResampler); +MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler); +MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut); -MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount); -MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount); MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler); MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler); +MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); +MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); +MA_API ma_result ma_linear_resampler_reset(ma_linear_resampler* pResampler); + + +typedef struct ma_resampler_config ma_resampler_config; + +typedef void ma_resampling_backend; +typedef struct +{ + ma_result (* onGetHeapSize )(void* pUserData, const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes); + ma_result (* onInit )(void* pUserData, const ma_resampler_config* pConfig, void* pHeap, ma_resampling_backend** ppBackend); + void (* onUninit )(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks); + ma_result (* onProcess )(void* pUserData, ma_resampling_backend* pBackend, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); + ma_result (* onSetRate )(void* pUserData, ma_resampling_backend* pBackend, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); /* Optional. Rate changes will be disabled. */ + ma_uint64 (* onGetInputLatency )(void* pUserData, const ma_resampling_backend* pBackend); /* Optional. Latency will be reported as 0. */ + ma_uint64 (* onGetOutputLatency )(void* pUserData, const ma_resampling_backend* pBackend); /* Optional. Latency will be reported as 0. */ + ma_result (* onGetRequiredInputFrameCount )(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); /* Optional. Latency mitigation will be disabled. */ + ma_result (* onGetExpectedOutputFrameCount)(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); /* Optional. Latency mitigation will be disabled. */ + ma_result (* onReset )(void* pUserData, ma_resampling_backend* pBackend); +} ma_resampling_backend_vtable; typedef enum { - ma_resample_algorithm_linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */ - ma_resample_algorithm_speex + ma_resample_algorithm_linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */ + ma_resample_algorithm_custom, } ma_resample_algorithm; -typedef struct +struct ma_resampler_config { ma_format format; /* Must be either ma_format_f32 or ma_format_s16. */ ma_uint32 channels; ma_uint32 sampleRateIn; ma_uint32 sampleRateOut; - ma_resample_algorithm algorithm; + ma_resample_algorithm algorithm; /* When set to ma_resample_algorithm_custom, pBackendVTable will be used. */ + ma_resampling_backend_vtable* pBackendVTable; + void* pBackendUserData; struct { ma_uint32 lpfOrder; - double lpfNyquistFactor; } linear; - struct - { - int quality; /* 0 to 10. Defaults to 3. */ - } speex; -} ma_resampler_config; +}; MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm); typedef struct { - ma_resampler_config config; + ma_resampling_backend* pBackend; + ma_resampling_backend_vtable* pBackendVTable; + void* pBackendUserData; + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRateIn; + ma_uint32 sampleRateOut; union { ma_linear_resampler linear; - struct - { - void* pSpeexResamplerState; /* SpeexResamplerState* */ - } speex; - } state; + } state; /* State for stock resamplers so we can avoid a malloc. For stock resamplers, pBackend will point here. */ + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_resampler; +MA_API ma_result ma_resampler_get_heap_size(const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_resampler_init_preallocated(const ma_resampler_config* pConfig, void* pHeap, ma_resampler* pResampler); + /* Initializes a new resampler object from a config. */ -MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler); +MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resampler* pResampler); /* Uninitializes a resampler. */ -MA_API void ma_resampler_uninit(ma_resampler* pResampler); +MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks); /* Converts the given input data. @@ -2572,23 +5202,6 @@ The ration is in/out. */ MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio); - -/* -Calculates the number of whole input frames that would need to be read from the client in order to output the specified -number of output frames. - -The returned value does not include cached input frames. It only returns the number of extra frames that would need to be -read from the input buffer in order to output the specified number of output frames. -*/ -MA_API ma_uint64 ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount); - -/* -Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of -input frames. -*/ -MA_API ma_uint64 ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount); - - /* Retrieves the latency introduced by the resampler in input frames. */ @@ -2599,6 +5212,25 @@ Retrieves the latency introduced by the resampler in output frames. */ MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler); +/* +Calculates the number of whole input frames that would need to be read from the client in order to output the specified +number of output frames. + +The returned value does not include cached input frames. It only returns the number of extra frames that would need to be +read from the input buffer in order to output the specified number of output frames. +*/ +MA_API ma_result ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); + +/* +Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of +input frames. +*/ +MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); + +/* +Resets the resampler's timer and clears it's internal cache. +*/ +MA_API ma_result ma_resampler_reset(ma_resampler* pResampler); /************************************************************************************************************************************************************** @@ -2606,15 +5238,33 @@ MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler) Channel Conversion **************************************************************************************************************************************************************/ +typedef enum +{ + ma_channel_conversion_path_unknown, + ma_channel_conversion_path_passthrough, + ma_channel_conversion_path_mono_out, /* Converting to mono. */ + ma_channel_conversion_path_mono_in, /* Converting from mono. */ + ma_channel_conversion_path_shuffle, /* Simple shuffle. Will use this when all channels are present in both input and output channel maps, but just in a different order. */ + ma_channel_conversion_path_weights /* Blended based on weights. */ +} ma_channel_conversion_path; + +typedef enum +{ + ma_mono_expansion_mode_duplicate = 0, /* The default. */ + ma_mono_expansion_mode_average, /* Average the mono channel across all channels. */ + ma_mono_expansion_mode_stereo_only, /* Duplicate to the left and right channels only and ignore the others. */ + ma_mono_expansion_mode_default = ma_mono_expansion_mode_duplicate +} ma_mono_expansion_mode; + typedef struct { ma_format format; ma_uint32 channelsIn; ma_uint32 channelsOut; - ma_channel channelMapIn[MA_MAX_CHANNELS]; - ma_channel channelMapOut[MA_MAX_CHANNELS]; + const ma_channel* pChannelMapIn; + const ma_channel* pChannelMapOut; ma_channel_mix_mode mixingMode; - float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ + float** ppWeights; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ } ma_channel_converter_config; MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel* pChannelMapIn, ma_uint32 channelsOut, const ma_channel* pChannelMapOut, ma_channel_mix_mode mixingMode); @@ -2624,24 +5274,29 @@ typedef struct ma_format format; ma_uint32 channelsIn; ma_uint32 channelsOut; - ma_channel channelMapIn[MA_MAX_CHANNELS]; - ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_channel_mix_mode mixingMode; + ma_channel_conversion_path conversionPath; + ma_channel* pChannelMapIn; + ma_channel* pChannelMapOut; + ma_uint8* pShuffleTable; /* Indexed by output channel index. */ union { - float f32[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; - ma_int32 s16[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; - } weights; - ma_bool8 isPassthrough; - ma_bool8 isSimpleShuffle; - ma_bool8 isSimpleMonoExpansion; - ma_bool8 isStereoToMono; - ma_uint8 shuffleTable[MA_MAX_CHANNELS]; + float** f32; + ma_int32** s16; + } weights; /* [in][out] */ + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_channel_converter; -MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, ma_channel_converter* pConverter); -MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter); +MA_API ma_result ma_channel_converter_get_heap_size(const ma_channel_converter_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_converter_config* pConfig, void* pHeap, ma_channel_converter* pConverter); +MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_channel_converter* pConverter); +MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); +MA_API ma_result ma_channel_converter_get_input_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_channel_converter_get_output_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); /************************************************************************************************************************************************************** @@ -2657,33 +5312,39 @@ typedef struct ma_uint32 channelsOut; ma_uint32 sampleRateIn; ma_uint32 sampleRateOut; - ma_channel channelMapIn[MA_MAX_CHANNELS]; - ma_channel channelMapOut[MA_MAX_CHANNELS]; + ma_channel* pChannelMapIn; + ma_channel* pChannelMapOut; ma_dither_mode ditherMode; ma_channel_mix_mode channelMixMode; - float channelWeights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */ - struct - { - ma_resample_algorithm algorithm; - ma_bool32 allowDynamicSampleRate; - struct - { - ma_uint32 lpfOrder; - double lpfNyquistFactor; - } linear; - struct - { - int quality; - } speex; - } resampling; + float** ppChannelWeights; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ + ma_bool32 allowDynamicSampleRate; + ma_resampler_config resampling; } ma_data_converter_config; MA_API ma_data_converter_config ma_data_converter_config_init_default(void); MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channelsIn, ma_uint32 channelsOut, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); + +typedef enum +{ + ma_data_converter_execution_path_passthrough, /* No conversion. */ + ma_data_converter_execution_path_format_only, /* Only format conversion. */ + ma_data_converter_execution_path_channels_only, /* Only channel conversion. */ + ma_data_converter_execution_path_resample_only, /* Only resampling. */ + ma_data_converter_execution_path_resample_first, /* All conversions, but resample as the first step. */ + ma_data_converter_execution_path_channels_first /* All conversions, but channels as the first step. */ +} ma_data_converter_execution_path; + typedef struct { - ma_data_converter_config config; + ma_format formatIn; + ma_format formatOut; + ma_uint32 channelsIn; + ma_uint32 channelsOut; + ma_uint32 sampleRateIn; + ma_uint32 sampleRateOut; + ma_dither_mode ditherMode; + ma_data_converter_execution_path executionPath; /* The execution path the data converter will follow when processing. */ ma_channel_converter channelConverter; ma_resampler resampler; ma_bool8 hasPreFormatConversion; @@ -2691,17 +5352,26 @@ typedef struct ma_bool8 hasChannelConverter; ma_bool8 hasResampler; ma_bool8 isPassthrough; + + /* Memory management. */ + ma_bool8 _ownsHeap; + void* _pHeap; } ma_data_converter; -MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, ma_data_converter* pConverter); -MA_API void ma_data_converter_uninit(ma_data_converter* pConverter); +MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter); +MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter); +MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); MA_API ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut); -MA_API ma_uint64 ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount); -MA_API ma_uint64 ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount); MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter); MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* pConverter); +MA_API ma_result ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount); +MA_API ma_result ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); +MA_API ma_result ma_data_converter_get_input_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_data_converter_get_output_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_data_converter_reset(ma_data_converter* pConverter); /************************************************************************************************************************************************************ @@ -2753,9 +5423,6 @@ This is used in the shuffle table to indicate that the channel index is undefine */ #define MA_CHANNEL_INDEX_NULL 255 -/* Retrieves the channel position of the specified channel based on miniaudio's default channel map. */ -MA_API ma_channel ma_channel_map_get_default_channel(ma_uint32 channelCount, ma_uint32 channelIndex); - /* Retrieves the channel position of the specified channel in the given channel map. @@ -2768,14 +5435,14 @@ Initializes a blank channel map. When a blank channel map is specified anywhere it indicates that the native channel map should be used. */ -MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap); +MA_API void ma_channel_map_init_blank(ma_channel* pChannelMap, ma_uint32 channels); /* Helper for retrieving a standard channel map. -The output channel map buffer must have a capacity of at least `channels`. +The output channel map buffer must have a capacity of at least `channelMapCap`. */ -MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap); +MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap, ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channels); /* Copies a channel map. @@ -2789,7 +5456,7 @@ Copies a channel map if one is specified, otherwise copies the default channel m The output buffer must have a capacity of at least `channels`. If not NULL, the input channel map must also have a capacity of at least `channels`. */ -MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels); +MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCapOut, const ma_channel* pIn, ma_uint32 channels); /* @@ -2804,7 +5471,7 @@ Invalid channel maps: The channel map buffer must have a capacity of at least `channels`. */ -MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap); +MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint32 channels); /* Helper for comparing two channel maps for equality. @@ -2813,14 +5480,14 @@ This assumes the channel count is the same between the two. Both channels map buffers must have a capacity of at least `channels`. */ -MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB); +MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const ma_channel* pChannelMapB, ma_uint32 channels); /* Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE). The channel map buffer must have a capacity of at least `channels`. */ -MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap); +MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint32 channels); /* Helper for determining whether or not a channel is present in the given channel map. @@ -2860,10 +5527,10 @@ typedef struct ma_uint32 subbufferSizeInBytes; ma_uint32 subbufferCount; ma_uint32 subbufferStrideInBytes; - MA_ATOMIC ma_uint32 encodedReadOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ - MA_ATOMIC ma_uint32 encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ - ma_bool8 ownsBuffer; /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */ - ma_bool8 clearOnWriteAcquire; /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */ + MA_ATOMIC(4, ma_uint32) encodedReadOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ + MA_ATOMIC(4, ma_uint32) encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */ + ma_bool8 ownsBuffer; /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */ + ma_bool8 clearOnWriteAcquire; /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */ ma_allocation_callbacks allocationCallbacks; } ma_rb; @@ -2872,9 +5539,9 @@ MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocate MA_API void ma_rb_uninit(ma_rb* pRB); MA_API void ma_rb_reset(ma_rb* pRB); MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut); -MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut); +MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes); MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut); -MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut); +MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes); MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes); MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes); MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB); /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. Will return the number of bytes that can be read before the read pointer hits the write pointer. */ @@ -2898,9 +5565,9 @@ MA_API ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB); MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB); MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut); -MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut); +MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames); MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut); -MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut); +MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames); MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames); MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames); MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB); /* Return value is in frames. */ @@ -2942,17 +5609,22 @@ Retrieves a human readable description of the given result code. MA_API const char* ma_result_description(ma_result result); /* -malloc(). Calls MA_MALLOC(). +malloc() */ MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); /* -realloc(). Calls MA_REALLOC(). +calloc() +*/ +MA_API void* ma_calloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); + +/* +realloc() */ MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); /* -free(). Calls MA_FREE(). +free() */ MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2994,6 +5666,413 @@ MA_API const char* ma_log_level_to_string(ma_uint32 logLevel); + +/************************************************************************************************************************************************************ + +Synchronization + +************************************************************************************************************************************************************/ +/* +Locks a spinlock. +*/ +MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock); + +/* +Locks a spinlock, but does not yield() when looping. +*/ +MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock); + +/* +Unlocks a spinlock. +*/ +MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock); + + +#ifndef MA_NO_THREADING + +/* +Creates a mutex. + +A mutex must be created from a valid context. A mutex is initially unlocked. +*/ +MA_API ma_result ma_mutex_init(ma_mutex* pMutex); + +/* +Deletes a mutex. +*/ +MA_API void ma_mutex_uninit(ma_mutex* pMutex); + +/* +Locks a mutex with an infinite timeout. +*/ +MA_API void ma_mutex_lock(ma_mutex* pMutex); + +/* +Unlocks a mutex. +*/ +MA_API void ma_mutex_unlock(ma_mutex* pMutex); + + +/* +Initializes an auto-reset event. +*/ +MA_API ma_result ma_event_init(ma_event* pEvent); + +/* +Uninitializes an auto-reset event. +*/ +MA_API void ma_event_uninit(ma_event* pEvent); + +/* +Waits for the specified auto-reset event to become signalled. +*/ +MA_API ma_result ma_event_wait(ma_event* pEvent); + +/* +Signals the specified auto-reset event. +*/ +MA_API ma_result ma_event_signal(ma_event* pEvent); +#endif /* MA_NO_THREADING */ + + +/* +Fence +===== +This locks while the counter is larger than 0. Counter can be incremented and decremented by any +thread, but care needs to be taken when waiting. It is possible for one thread to acquire the +fence just as another thread returns from ma_fence_wait(). + +The idea behind a fence is to allow you to wait for a group of operations to complete. When an +operation starts, the counter is incremented which locks the fence. When the operation completes, +the fence will be released which decrements the counter. ma_fence_wait() will block until the +counter hits zero. + +If threading is disabled, ma_fence_wait() will spin on the counter. +*/ +typedef struct +{ +#ifndef MA_NO_THREADING + ma_event e; +#endif + ma_uint32 counter; +} ma_fence; + +MA_API ma_result ma_fence_init(ma_fence* pFence); +MA_API void ma_fence_uninit(ma_fence* pFence); +MA_API ma_result ma_fence_acquire(ma_fence* pFence); /* Increment counter. */ +MA_API ma_result ma_fence_release(ma_fence* pFence); /* Decrement counter. */ +MA_API ma_result ma_fence_wait(ma_fence* pFence); /* Wait for counter to reach 0. */ + + + +/* +Notification callback for asynchronous operations. +*/ +typedef void ma_async_notification; + +typedef struct +{ + void (* onSignal)(ma_async_notification* pNotification); +} ma_async_notification_callbacks; + +MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification); + + +/* +Simple polling notification. + +This just sets a variable when the notification has been signalled which is then polled with ma_async_notification_poll_is_signalled() +*/ +typedef struct +{ + ma_async_notification_callbacks cb; + ma_bool32 signalled; +} ma_async_notification_poll; + +MA_API ma_result ma_async_notification_poll_init(ma_async_notification_poll* pNotificationPoll); +MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll* pNotificationPoll); + + +/* +Event Notification + +This uses an ma_event. If threading is disabled (MA_NO_THREADING), initialization will fail. +*/ +typedef struct +{ + ma_async_notification_callbacks cb; +#ifndef MA_NO_THREADING + ma_event e; +#endif +} ma_async_notification_event; + +MA_API ma_result ma_async_notification_event_init(ma_async_notification_event* pNotificationEvent); +MA_API ma_result ma_async_notification_event_uninit(ma_async_notification_event* pNotificationEvent); +MA_API ma_result ma_async_notification_event_wait(ma_async_notification_event* pNotificationEvent); +MA_API ma_result ma_async_notification_event_signal(ma_async_notification_event* pNotificationEvent); + + + + +/************************************************************************************************************************************************************ + +Job Queue + +************************************************************************************************************************************************************/ + +/* +Slot Allocator +-------------- +The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocator an index that can be used +as the insertion point for an object. + +Slots are reference counted to help mitigate the ABA problem in the lock-free queue we use for tracking jobs. + +The slot index is stored in the low 32 bits. The reference counter is stored in the high 32 bits: + + +-----------------+-----------------+ + | 32 Bits | 32 Bits | + +-----------------+-----------------+ + | Reference Count | Slot Index | + +-----------------+-----------------+ +*/ +typedef struct +{ + ma_uint32 capacity; /* The number of slots to make available. */ +} ma_slot_allocator_config; + +MA_API ma_slot_allocator_config ma_slot_allocator_config_init(ma_uint32 capacity); + + +typedef struct +{ + MA_ATOMIC(4, ma_uint32) bitfield; /* Must be used atomically because the allocation and freeing routines need to make copies of this which must never be optimized away by the compiler. */ +} ma_slot_allocator_group; + +typedef struct +{ + ma_slot_allocator_group* pGroups; /* Slots are grouped in chunks of 32. */ + ma_uint32* pSlots; /* 32 bits for reference counting for ABA mitigation. */ + ma_uint32 count; /* Allocation count. */ + ma_uint32 capacity; + + /* Memory management. */ + ma_bool32 _ownsHeap; + void* _pHeap; +} ma_slot_allocator; + +MA_API ma_result ma_slot_allocator_get_heap_size(const ma_slot_allocator_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_slot_allocator_init_preallocated(const ma_slot_allocator_config* pConfig, void* pHeap, ma_slot_allocator* pAllocator); +MA_API ma_result ma_slot_allocator_init(const ma_slot_allocator_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_slot_allocator* pAllocator); +MA_API void ma_slot_allocator_uninit(ma_slot_allocator* pAllocator, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint64* pSlot); +MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot); + + +typedef struct ma_job ma_job; + +/* +Callback for processing a job. Each job type will have their own processing callback which will be +called by ma_job_process(). +*/ +typedef ma_result (* ma_job_proc)(ma_job* pJob); + +/* When a job type is added here an callback needs to be added go "g_jobVTable" in the implementation section. */ +typedef enum +{ + /* Miscellaneous. */ + MA_JOB_TYPE_QUIT = 0, + MA_JOB_TYPE_CUSTOM, + + /* Resource Manager. */ + MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE, + MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE, + MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE, + MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER, + MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER, + MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM, + MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM, + MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM, + MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM, + + /* Device. */ + MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE, + + /* Count. Must always be last. */ + MA_JOB_TYPE_COUNT +} ma_job_type; + +struct ma_job +{ + union + { + struct + { + ma_uint16 code; /* Job type. */ + ma_uint16 slot; /* Index into a ma_slot_allocator. */ + ma_uint32 refcount; + } breakup; + ma_uint64 allocation; + } toc; /* 8 bytes. We encode the job code into the slot allocation data to save space. */ + MA_ATOMIC(8, ma_uint64) next; /* refcount + slot for the next item. Does not include the job code. */ + ma_uint32 order; /* Execution order. Used to create a data dependency and ensure a job is executed in order. Usage is contextual depending on the job type. */ + + union + { + /* Miscellaneous. */ + struct + { + ma_job_proc proc; + ma_uintptr data0; + ma_uintptr data1; + } custom; + + /* Resource Manager */ + union + { + struct + { + /*ma_resource_manager**/ void* pResourceManager; + /*ma_resource_manager_data_buffer_node**/ void* pDataBufferNode; + char* pFilePath; + wchar_t* pFilePathW; + ma_uint32 flags; /* Resource manager data source flags that were used when initializing the data buffer. */ + ma_async_notification* pInitNotification; /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */ + ma_async_notification* pDoneNotification; /* Signalled when the data buffer has been fully decoded. Will be passed through to MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE when decoding. */ + ma_fence* pInitFence; /* Released when initialization of the decoder is complete. */ + ma_fence* pDoneFence; /* Released if initialization of the decoder fails. Passed through to PAGE_DATA_BUFFER_NODE untouched if init is successful. */ + } loadDataBufferNode; + struct + { + /*ma_resource_manager**/ void* pResourceManager; + /*ma_resource_manager_data_buffer_node**/ void* pDataBufferNode; + ma_async_notification* pDoneNotification; + ma_fence* pDoneFence; + } freeDataBufferNode; + struct + { + /*ma_resource_manager**/ void* pResourceManager; + /*ma_resource_manager_data_buffer_node**/ void* pDataBufferNode; + /*ma_decoder**/ void* pDecoder; + ma_async_notification* pDoneNotification; /* Signalled when the data buffer has been fully decoded. */ + ma_fence* pDoneFence; /* Passed through from LOAD_DATA_BUFFER_NODE and released when the data buffer completes decoding or an error occurs. */ + } pageDataBufferNode; + + struct + { + /*ma_resource_manager_data_buffer**/ void* pDataBuffer; + ma_async_notification* pInitNotification; /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */ + ma_async_notification* pDoneNotification; /* Signalled when the data buffer has been fully decoded. */ + ma_fence* pInitFence; /* Released when the data buffer has been initialized and the format/channels/rate can be retrieved. */ + ma_fence* pDoneFence; /* Released when the data buffer has been fully decoded. */ + ma_uint64 rangeBegInPCMFrames; + ma_uint64 rangeEndInPCMFrames; + ma_uint64 loopPointBegInPCMFrames; + ma_uint64 loopPointEndInPCMFrames; + ma_uint32 isLooping; + } loadDataBuffer; + struct + { + /*ma_resource_manager_data_buffer**/ void* pDataBuffer; + ma_async_notification* pDoneNotification; + ma_fence* pDoneFence; + } freeDataBuffer; + + struct + { + /*ma_resource_manager_data_stream**/ void* pDataStream; + char* pFilePath; /* Allocated when the job is posted, freed by the job thread after loading. */ + wchar_t* pFilePathW; /* ^ As above ^. Only used if pFilePath is NULL. */ + ma_uint64 initialSeekPoint; + ma_async_notification* pInitNotification; /* Signalled after the first two pages have been decoded and frames can be read from the stream. */ + ma_fence* pInitFence; + } loadDataStream; + struct + { + /*ma_resource_manager_data_stream**/ void* pDataStream; + ma_async_notification* pDoneNotification; + ma_fence* pDoneFence; + } freeDataStream; + struct + { + /*ma_resource_manager_data_stream**/ void* pDataStream; + ma_uint32 pageIndex; /* The index of the page to decode into. */ + } pageDataStream; + struct + { + /*ma_resource_manager_data_stream**/ void* pDataStream; + ma_uint64 frameIndex; + } seekDataStream; + } resourceManager; + + /* Device. */ + union + { + union + { + struct + { + /*ma_device**/ void* pDevice; + /*ma_device_type*/ ma_uint32 deviceType; + } reroute; + } aaudio; + } device; + } data; +}; + +MA_API ma_job ma_job_init(ma_uint16 code); +MA_API ma_result ma_job_process(ma_job* pJob); + + +/* +When set, ma_job_queue_next() will not wait and no semaphore will be signaled in +ma_job_queue_post(). ma_job_queue_next() will return MA_NO_DATA_AVAILABLE if nothing is available. + +This flag should always be used for platforms that do not support multithreading. +*/ +typedef enum +{ + MA_JOB_QUEUE_FLAG_NON_BLOCKING = 0x00000001 +} ma_job_queue_flags; + +typedef struct +{ + ma_uint32 flags; + ma_uint32 capacity; /* The maximum number of jobs that can fit in the queue at a time. */ +} ma_job_queue_config; + +MA_API ma_job_queue_config ma_job_queue_config_init(ma_uint32 flags, ma_uint32 capacity); + + +typedef struct +{ + ma_uint32 flags; /* Flags passed in at initialization time. */ + ma_uint32 capacity; /* The maximum number of jobs that can fit in the queue at a time. Set by the config. */ + MA_ATOMIC(8, ma_uint64) head; /* The first item in the list. Required for removing from the top of the list. */ + MA_ATOMIC(8, ma_uint64) tail; /* The last item in the list. Required for appending to the end of the list. */ +#ifndef MA_NO_THREADING + ma_semaphore sem; /* Only used when MA_JOB_QUEUE_FLAG_NON_BLOCKING is unset. */ +#endif + ma_slot_allocator allocator; + ma_job* pJobs; +#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE + ma_spinlock lock; +#endif + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} ma_job_queue; + +MA_API ma_result ma_job_queue_get_heap_size(const ma_job_queue_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_job_queue_init_preallocated(const ma_job_queue_config* pConfig, void* pHeap, ma_job_queue* pQueue); +MA_API ma_result ma_job_queue_init(const ma_job_queue_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_job_queue* pQueue); +MA_API void ma_job_queue_uninit(ma_job_queue* pQueue, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_job_queue_post(ma_job_queue* pQueue, const ma_job* pJob); +MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob); /* Returns MA_CANCELLED if the next job is a quit job. */ + + + /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -3100,11 +6179,14 @@ This section contains the APIs for device playback and capture. Here is where yo #define MA_HAS_NULL #endif -#define MA_STATE_UNINITIALIZED 0 -#define MA_STATE_STOPPED 1 /* The device's default state after initialization. */ -#define MA_STATE_STARTED 2 /* The device is started and is requesting and/or delivering audio data. */ -#define MA_STATE_STARTING 3 /* Transitioning from a stopped state to started. */ -#define MA_STATE_STOPPING 4 /* Transitioning from a started state to stopped. */ +typedef enum +{ + ma_device_state_uninitialized = 0, + ma_device_state_stopped = 1, /* The device's default state after initialization. */ + ma_device_state_started = 2, /* The device is started and is requesting and/or delivering audio data. */ + ma_device_state_starting = 3, /* Transitioning from a stopped state to started. */ + ma_device_state_stopping = 4 /* Transitioning from a started state to stopped. */ +} ma_device_state; #ifdef MA_SUPPORT_WASAPI /* We need a IMMNotificationClient object for WASAPI. */ @@ -3139,6 +6221,114 @@ typedef enum #define MA_BACKEND_COUNT (ma_backend_null+1) +/* +Device job thread. This is used by backends that require asynchronous processing of certain +operations. It is not used by all backends. + +The device job thread is made up of a thread and a job queue. You can post a job to the thread with +ma_device_job_thread_post(). The thread will do the processing of the job. +*/ +typedef struct +{ + ma_bool32 noThread; /* Set this to true if you want to process jobs yourself. */ + ma_uint32 jobQueueCapacity; + ma_uint32 jobQueueFlags; +} ma_device_job_thread_config; + +MA_API ma_device_job_thread_config ma_device_job_thread_config_init(void); + +typedef struct +{ + ma_thread thread; + ma_job_queue jobQueue; + ma_bool32 _hasThread; +} ma_device_job_thread; + +MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_job_thread* pJobThread); +MA_API void ma_device_job_thread_uninit(ma_device_job_thread* pJobThread, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_device_job_thread_post(ma_device_job_thread* pJobThread, const ma_job* pJob); +MA_API ma_result ma_device_job_thread_next(ma_device_job_thread* pJobThread, ma_job* pJob); + + + +/* Device notification types. */ +typedef enum +{ + ma_device_notification_type_started, + ma_device_notification_type_stopped, + ma_device_notification_type_rerouted, + ma_device_notification_type_interruption_began, + ma_device_notification_type_interruption_ended +} ma_device_notification_type; + +typedef struct +{ + ma_device* pDevice; + ma_device_notification_type type; + union + { + struct + { + int _unused; + } started; + struct + { + int _unused; + } stopped; + struct + { + int _unused; + } rerouted; + struct + { + int _unused; + } interruption; + } data; +} ma_device_notification; + +/* +The notification callback for when the application should be notified of a change to the device. + +This callback is used for notifying the application of changes such as when the device has started, +stopped, rerouted or an interruption has occurred. Note that not all backends will post all +notification types. For example, some backends will perform automatic stream routing without any +kind of notification to the host program which means miniaudio will never know about it and will +never be able to fire the rerouted notification. You should keep this in mind when designing your +program. + +The stopped notification will *not* get fired when a device is rerouted. + + +Parameters +---------- +pNotification (in) + A pointer to a structure containing information about the event. Use the `pDevice` member of + this object to retrieve the relevant device. The `type` member can be used to discriminate + against each of the notification types. + + +Remarks +------- +Do not restart or uninitialize the device from the callback. + +Not all notifications will be triggered by all backends, however the started and stopped events +should be reliable for all backends. Some backends do not have a good way to detect device +stoppages due to unplugging the device which may result in the stopped callback not getting +fired. This has been observed with at least one BSD variant. + +The rerouted notification is fired *after* the reroute has occurred. The stopped notification will +*not* get fired when a device is rerouted. The following backends are known to do automatic stream +rerouting, but do not have a way to be notified of the change: + + * DirectSound + +The interruption notifications are used on mobile platforms for detecting when audio is interrupted +due to things like an incoming phone call. Currently this is only implemented on iOS. None of the +Android backends will report this notification. +*/ +typedef void (* ma_device_notification_proc)(const ma_device_notification* pNotification); + + /* The callback for processing audio data from the device. @@ -3179,9 +6369,14 @@ callback. The following APIs cannot be called from inside the callback: The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread. */ -typedef void (* ma_device_callback_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); +typedef void (* ma_device_data_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + + + /* +DEPRECATED. Use ma_device_notification_proc instead. + The callback for when the device has been stopped. This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces @@ -3198,41 +6393,7 @@ Remarks ------- Do not restart or uninitialize the device from the callback. */ -typedef void (* ma_stop_proc)(ma_device* pDevice); - -/* -The callback for handling log messages. - - -Parameters ----------- -pContext (in) - A pointer to the context the log message originated from. - -pDevice (in) - A pointer to the device the log message originate from, if any. This can be null, in which case the message came from the context. - -logLevel (in) - The log level. This can be one of the following: - - +----------------------+ - | Log Level | - +----------------------+ - | MA_LOG_LEVEL_DEBUG | - | MA_LOG_LEVEL_INFO | - | MA_LOG_LEVEL_WARNING | - | MA_LOG_LEVEL_ERROR | - +----------------------+ - -message (in) - The log message. - - -Remarks -------- -Do not modify the state of the device from inside the callback. -*/ -typedef void (* ma_log_proc)(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message); +typedef void (* ma_stop_proc)(ma_device* pDevice); /* DEPRECATED. Use ma_device_notification_proc instead. */ typedef enum { @@ -3378,30 +6539,17 @@ typedef struct ma_backend_callbacks ma_backend_callbacks; #define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1) /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */ +#ifndef MA_MAX_DEVICE_NAME_LENGTH +#define MA_MAX_DEVICE_NAME_LENGTH 255 +#endif + typedef struct { /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */ ma_device_id id; - char name[256]; + char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* +1 for null terminator. */ ma_bool32 isDefault; - /* - Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize - a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion - pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided - here mainly for informational purposes or in the rare case that someone might find it useful. - - These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices(). - */ - ma_uint32 formatCount; - ma_format formats[ma_format_count]; - ma_uint32 minChannels; - ma_uint32 maxChannels; - ma_uint32 minSampleRate; - ma_uint32 maxSampleRate; - - - /* Experimental. Don't use these right now. */ ma_uint32 nativeDataFormatCount; struct { @@ -3420,29 +6568,21 @@ struct ma_device_config ma_uint32 periodSizeInMilliseconds; ma_uint32 periods; ma_performance_profile performanceProfile; - ma_bool8 noPreZeroedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */ + ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */ ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ - ma_device_callback_proc dataCallback; + ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */ + ma_bool8 noFixedSizedCallback; /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */ + ma_device_data_proc dataCallback; + ma_device_notification_proc notificationCallback; ma_stop_proc stopCallback; void* pUserData; - struct - { - ma_resample_algorithm algorithm; - struct - { - ma_uint32 lpfOrder; - } linear; - struct - { - int quality; - } speex; - } resampling; + ma_resampler_config resampling; struct { const ma_device_id* pDeviceID; ma_format format; ma_uint32 channels; - ma_channel channelMap[MA_MAX_CHANNELS]; + ma_channel* pChannelMap; ma_channel_mix_mode channelMixMode; ma_share_mode shareMode; } playback; @@ -3451,7 +6591,7 @@ struct ma_device_config const ma_device_id* pDeviceID; ma_format format; ma_uint32 channels; - ma_channel channelMap[MA_MAX_CHANNELS]; + ma_channel* pChannelMap; ma_channel_mix_mode channelMixMode; ma_share_mode shareMode; } capture; @@ -3489,6 +6629,7 @@ struct ma_device_config ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; + ma_bool32 noAutoStartAfterReroute; } aaudio; }; @@ -3554,7 +6695,7 @@ callbacks defined in this structure. Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration -needs to stop and the `onContextEnumerateDevices()` function return with a success code. +needs to stop and the `onContextEnumerateDevices()` function returns with a success code. Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID, and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the @@ -3569,7 +6710,7 @@ internally by miniaudio. On input, if the sample format is set to `ma_format_unknown`, the backend is free to use whatever sample format it desires, so long as it's supported by miniaudio. When the channel count is set to 0, the backend should use the device's native channel count. The same applies for -sample rate. For the channel map, the default should be used when `ma_channel_map_blank()` returns true (all channels set to +sample rate. For the channel map, the default should be used when `ma_channel_map_is_blank()` returns true (all channels set to `MA_CHANNEL_NONE`). On input, the `periodSizeInFrames` or `periodSizeInMilliseconds` option should always be set. The backend should inspect both of these variables. If `periodSizeInFrames` is set, it should take priority, otherwise it needs to be derived from the period size in milliseconds (`periodSizeInMilliseconds`) and the sample rate, keeping in mind that the sample rate may be 0, in which case the @@ -3588,14 +6729,17 @@ This allows miniaudio to then process any necessary data conversion and then pas If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional. -The audio thread should run data delivery logic in a loop while `ma_device_get_state() == MA_STATE_STARTED` and no errors have been +The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback. The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this -callback. When the device is stopped, the `ma_device_get_state() == MA_STATE_STARTED` condition will fail and the loop will be terminated +callback. When the device is stopped, the `ma_device_get_state() == ma_device_state_started` condition will fail and the loop will be terminated which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback, look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to wake up the audio thread. + +If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the +`onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient. */ struct ma_backend_callbacks { @@ -3611,11 +6755,11 @@ struct ma_backend_callbacks ma_result (* onDeviceWrite)(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten); ma_result (* onDeviceDataLoop)(ma_device* pDevice); ma_result (* onDeviceDataLoopWakeup)(ma_device* pDevice); + ma_result (* onDeviceGetInfo)(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo); }; struct ma_context_config { - ma_log_proc logCallback; /* Legacy logging callback. Will be removed in version 0.11. */ ma_log* pLog; ma_thread_priority threadPriority; size_t threadStackSize; @@ -3678,7 +6822,6 @@ struct ma_context ma_backend backend; /* DirectSound, ALSA, etc. */ ma_log* pLog; ma_log log; /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */ - ma_log_proc logCallback; /* Legacy callback. Will be removed in version 0.11. */ ma_thread_priority threadPriority; size_t threadStackSize; void* pUserData; @@ -3863,6 +7006,7 @@ struct ma_context ma_proc pa_stream_set_write_callback; ma_proc pa_stream_set_read_callback; ma_proc pa_stream_set_suspended_callback; + ma_proc pa_stream_set_moved_callback; ma_proc pa_stream_is_suspended; ma_proc pa_stream_flush; ma_proc pa_stream_drain; @@ -3878,6 +7022,8 @@ struct ma_context /*pa_mainloop**/ ma_ptr pMainLoop; /*pa_context**/ ma_ptr pPulseContext; + char* pApplicationName; /* Set when the context is initialized. Used by devices for their local pa_context objects. */ + char* pServerName; /* Set when the context is initialized. Used by devices for their local pa_context objects. */ } pulse; #endif #ifdef MA_SUPPORT_JACK @@ -4004,6 +7150,7 @@ struct ma_context ma_proc AAudioStream_getFramesPerBurst; ma_proc AAudioStream_requestStart; ma_proc AAudioStream_requestStop; + ma_device_job_thread jobThread; /* For processing operations outside of the error callback, specifically device disconnections and rerouting. */ } aaudio; #endif #ifdef MA_SUPPORT_OPENSL @@ -4087,37 +7234,39 @@ struct ma_device ma_context* pContext; ma_device_type type; ma_uint32 sampleRate; - MA_ATOMIC ma_uint32 state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ - ma_device_callback_proc onData; /* Set once at initialization time and should not be changed after. */ - ma_stop_proc onStop; /* Set once at initialization time and should not be changed after. */ - void* pUserData; /* Application defined data. */ + MA_ATOMIC(4, ma_device_state) state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ + ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */ + ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */ + ma_stop_proc onStop; /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */ + void* pUserData; /* Application defined data. */ ma_mutex startStopLock; ma_event wakeupEvent; ma_event startEvent; ma_event stopEvent; ma_thread thread; - ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */ - ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ - ma_bool8 noPreZeroedOutputBuffer; + ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */ + ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ + ma_bool8 noPreSilencedOutputBuffer; ma_bool8 noClip; - MA_ATOMIC float masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ - ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ + ma_bool8 noDisableDenormals; + ma_bool8 noFixedSizedCallback; + MA_ATOMIC(4, float) masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ + ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ struct { ma_resample_algorithm algorithm; + ma_resampling_backend_vtable* pBackendVTable; + void* pBackendUserData; struct { ma_uint32 lpfOrder; } linear; - struct - { - int quality; - } speex; } resampling; struct { + ma_device_id* pID; /* Set to NULL if using default ID, otherwise set to the address of "id". */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ - char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ + char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_format format; ma_uint32 channels; @@ -4130,11 +7279,19 @@ struct ma_device ma_uint32 internalPeriods; ma_channel_mix_mode channelMixMode; ma_data_converter converter; + void* pIntermediaryBuffer; /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */ + ma_uint32 intermediaryBufferCap; + ma_uint32 intermediaryBufferLen; /* How many valid frames are sitting in the intermediary buffer. */ + void* pInputCache; /* In external format. Can be null. */ + ma_uint64 inputCacheCap; + ma_uint64 inputCacheConsumed; + ma_uint64 inputCacheRemaining; } playback; struct { + ma_device_id* pID; /* Set to NULL if using default ID, otherwise set to the address of "id". */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ - char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ + char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_format format; ma_uint32 channels; @@ -4147,6 +7304,9 @@ struct ma_device ma_uint32 internalPeriods; ma_channel_mix_mode channelMixMode; ma_data_converter converter; + void* pIntermediaryBuffer; /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */ + ma_uint32 intermediaryBufferCap; + ma_uint32 intermediaryBufferLen; /* How many valid frames are sitting in the intermediary buffer. */ } capture; union @@ -4162,16 +7322,22 @@ struct ma_device ma_IMMNotificationClient notificationClient; /*HANDLE*/ ma_handle hEventPlayback; /* Auto reset. Initialized to signaled. */ /*HANDLE*/ ma_handle hEventCapture; /* Auto reset. Initialized to unsignaled. */ - ma_uint32 actualPeriodSizeInFramesPlayback; /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */ - ma_uint32 actualPeriodSizeInFramesCapture; + ma_uint32 actualBufferSizeInFramesPlayback; /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */ + ma_uint32 actualBufferSizeInFramesCapture; ma_uint32 originalPeriodSizeInFrames; ma_uint32 originalPeriodSizeInMilliseconds; ma_uint32 originalPeriods; ma_performance_profile originalPerformanceProfile; ma_uint32 periodSizeInFramesPlayback; ma_uint32 periodSizeInFramesCapture; - MA_ATOMIC ma_bool32 isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ - MA_ATOMIC ma_bool32 isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ + void* pMappedBufferCapture; + ma_uint32 mappedBufferCaptureCap; + ma_uint32 mappedBufferCaptureLen; + void* pMappedBufferPlayback; + ma_uint32 mappedBufferPlaybackCap; + ma_uint32 mappedBufferPlaybackLen; + MA_ATOMIC(4, ma_bool32) isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ + MA_ATOMIC(4, ma_bool32) isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ ma_bool8 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */ ma_bool8 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */ ma_bool8 noHardwareOffloading; @@ -4228,6 +7394,8 @@ struct ma_device #ifdef MA_SUPPORT_PULSEAUDIO struct { + /*pa_mainloop**/ ma_ptr pMainLoop; + /*pa_context**/ ma_ptr pPulseContext; /*pa_stream**/ ma_ptr pStreamPlayback; /*pa_stream**/ ma_ptr pStreamCapture; } pulse; @@ -4236,8 +7404,8 @@ struct ma_device struct { /*jack_client_t**/ ma_ptr pClient; - /*jack_port_t**/ ma_ptr pPortsPlayback[MA_MAX_CHANNELS]; - /*jack_port_t**/ ma_ptr pPortsCapture[MA_MAX_CHANNELS]; + /*jack_port_t**/ ma_ptr* ppPortsPlayback; + /*jack_port_t**/ ma_ptr* ppPortsCapture; float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */ float* pIntermediaryBufferCapture; } jack; @@ -4260,7 +7428,7 @@ struct ma_device ma_bool32 isDefaultCaptureDevice; ma_bool32 isSwitchingPlaybackDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */ ma_bool32 isSwitchingCaptureDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */ - void* pRouteChangeHandler; /* Only used on mobile platforms. Obj-C object for handling route changes. */ + void* pNotificationHandler; /* Only used on mobile platforms. Obj-C object for handling route changes. */ } coreaudio; #endif #ifdef MA_SUPPORT_SNDIO @@ -4291,6 +7459,10 @@ struct ma_device { /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; + ma_aaudio_usage usage; + ma_aaudio_content_type contentType; + ma_aaudio_input_preset inputPreset; + ma_bool32 noAutoStartAfterReroute; } aaudio; #endif #ifdef MA_SUPPORT_OPENSL @@ -4334,7 +7506,7 @@ struct ma_device ma_uint32 currentPeriodFramesRemainingCapture; ma_uint64 lastProcessedFramePlayback; ma_uint64 lastProcessedFrameCapture; - MA_ATOMIC ma_bool32 isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */ + MA_ATOMIC(4, ma_bool32) isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */ } null_device; #endif }; @@ -4446,6 +7618,9 @@ can then be set directly on the structure. Below are the members of the `ma_cont | ma_thread_priority_default | |--------------------------------------| + threadStackSize + The desired size of the stack for the audio thread. Defaults to the operating system's default. + pUserData A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`. @@ -4500,6 +7675,12 @@ can then be set directly on the structure. Below are the members of the `ma_cont | ma_ios_session_category_option_allow_air_play | AVAudioSessionCategoryOptionAllowAirPlay | |---------------------------------------------------------------------------|------------------------------------------------------------------| + coreaudio.noAudioSessionActivate + iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. + + coreaudio.noAudioSessionDeactivate + iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. + jack.pClientName The name of the client to pass to `jack_client_open()`. @@ -4543,9 +7724,12 @@ ma_backend backends[] = { ma_backend_dsound }; +ma_log log; +ma_log_init(&log); +ma_log_register_callback(&log, ma_log_callback_init(my_log_callbac, pMyLogUserData)); + ma_context_config config = ma_context_config_init(); -config.logCallback = my_log_callback; -config.pUserData = pMyUserData; +config.pLog = &log; // Specify a custom log object in the config so any logs that are posted from ma_context_init() are captured. ma_context context; ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context); @@ -4555,6 +7739,9 @@ if (result != MA_SUCCESS) { // Couldn't find an appropriate backend. } } + +// You could also attach a log callback post-initialization: +ma_log_register_callback(ma_context_get_log(&context), ma_log_callback_init(my_log_callback, pMyLogUserData)); ``` @@ -4606,6 +7793,8 @@ Remarks Pass the returned pointer to `ma_log_post()`, `ma_log_postv()` or `ma_log_postf()` to post a log message. +You can attach your own logging callback to the log with `ma_log_register_callback()` + Return Value ------------ @@ -4747,10 +7936,6 @@ deviceType (in) pDeviceID (in) The ID of the device being queried. -shareMode (in) - The share mode to query for device capabilities. This should be set to whatever you're intending on using when initializing the device. If you're unsure, - set this to `ma_share_mode_shared`. - pDeviceInfo (out) A pointer to the `ma_device_info` structure that will receive the device information. @@ -4776,7 +7961,7 @@ the requested share mode is unsupported. This leaves pDeviceInfo unmodified in the result of an error. */ -MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo); +MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo); /* Determines if the given context supports loopback mode. @@ -4947,7 +8132,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value. - noPreZeroedOutputBuffer + noPreSilencedOutputBuffer When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of the output buffer will be cleared the zero. You can use this to avoid the overhead of zeroing out the buffer if you can guarantee that your data callback will write to every sample in the output buffer, or if you are doing your own clearing. @@ -4957,12 +8142,19 @@ then be set directly on the structure. Below are the members of the `ma_device_c contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only applies when the playback sample format is f32. + noDisableDenormals + By default, miniaudio will disable denormals when the data callback is called. Setting this to true will prevent the disabling of denormals. + + noFixedSizedCallback + Allows miniaudio to fire the data callback with any frame count. When this is set to true, the data callback will be fired with a consistent frame + count as specified by `periodSizeInFrames` or `periodSizeInMilliseconds`. When set to false, miniaudio will fire the callback with whatever the + backend requests, which could be anything. + dataCallback The callback to fire whenever data is ready to be delivered to or from the device. - stopCallback - The callback to fire whenever the device has stopped, either explicitly via `ma_device_stop()`, or implicitly due to things like the device being - disconnected. + notificationCallback + The callback to fire when something has changed with the device, such as whether or not it has been started or stopped. pUserData The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`. @@ -4971,6 +8163,12 @@ then be set directly on the structure. Below are the members of the `ma_device_c The resampling algorithm to use when miniaudio needs to perform resampling between the rate specified by `sampleRate` and the device's native rate. The default value is `ma_resample_algorithm_linear`, and the quality can be configured with `resampling.linear.lpfOrder`. + resampling.pBackendVTable + A pointer to an optional vtable that can be used for plugging in a custom resampler. + + resampling.pBackendUserData + A pointer that will passed to callbacks in pBackendVTable. + resampling.linear.lpfOrder The linear resampler applies a low-pass filter as part of it's procesing for anti-aliasing. This setting controls the order of the filter. The higher the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is @@ -4988,9 +8186,9 @@ then be set directly on the structure. Below are the members of the `ma_device_c The number of channels to use for playback. When set to 0 the device's native channel count will be used. This can be retrieved after initialization from the device object directly with `device.playback.channels`. - playback.channelMap + playback.pChannelMap The channel map to use for playback. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the - device object direct with `device.playback.channelMap`. + device object direct with `device.playback.pChannelMap`. When set, the buffer should contain `channels` items. playback.shareMode The preferred share mode to use for playback. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify @@ -5009,9 +8207,9 @@ then be set directly on the structure. Below are the members of the `ma_device_c The number of channels to use for capture. When set to 0 the device's native channel count will be used. This can be retrieved after initialization from the device object directly with `device.capture.channels`. - capture.channelMap + capture.pChannelMap The channel map to use for capture. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the - device object direct with `device.capture.channelMap`. + device object direct with `device.capture.pChannelMap`. When set, the buffer should contain `channels` items. capture.shareMode The preferred share mode to use for capture. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify @@ -5056,6 +8254,30 @@ then be set directly on the structure. Below are the members of the `ma_device_c find the closest match between the sample rate requested in the device config and the sample rates natively supported by the hardware. When set to false, the sample rate currently set by the operating system will always be used. + opensl.streamType + OpenSL only. Explicitly sets the stream type. If left unset (`ma_opensl_stream_type_default`), the + stream type will be left unset. Think of this as the type of audio you're playing. + + opensl.recordingPreset + OpenSL only. Explicitly sets the type of recording your program will be doing. When left + unset, the recording preset will be left unchanged. + + aaudio.usage + AAudio only. Explicitly sets the nature of the audio the program will be consuming. When + left unset, the usage will be left unchanged. + + aaudio.contentType + AAudio only. Sets the content type. When left unset, the content type will be left unchanged. + + aaudio.inputPreset + AAudio only. Explicitly sets the type of recording your program will be doing. When left + unset, the input preset will be left unchanged. + + aaudio.noAutoStartAfterReroute + AAudio only. Controls whether or not the device should be automatically restarted after a + stream reroute. When set to false (default) the device will be restarted automatically; + otherwise the device will be stopped. + Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device. @@ -5259,6 +8481,95 @@ Helper function for retrieving the log object associated with the context that o MA_API ma_log* ma_device_get_log(ma_device* pDevice); +/* +Retrieves information about the device. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose information is being retrieved. + +type (in) + The device type. This parameter is required for duplex devices. When retrieving device + information, you are doing so for an individual playback or capture device. + +pDeviceInfo (out) + A pointer to the `ma_device_info` that will receive the device information. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Unsafe. This should be considered unsafe because it may be calling into the backend which may or +may not be safe. + + +Callback Safety +--------------- +Unsafe. You should avoid calling this in the data callback because it may call into the backend +which may or may not be safe. +*/ +MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo); + + +/* +Retrieves the name of the device. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose information is being retrieved. + +type (in) + The device type. This parameter is required for duplex devices. When retrieving device + information, you are doing so for an individual playback or capture device. + +pName (out) + A pointer to the buffer that will receive the name. + +nameCap (in) + The capacity of the output buffer, including space for the null terminator. + +pLengthNotIncludingNullTerminator (out, optional) + A pointer to the variable that will receive the length of the name, not including the null + terminator. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Unsafe. This should be considered unsafe because it may be calling into the backend which may or +may not be safe. + + +Callback Safety +--------------- +Unsafe. You should avoid calling this in the data callback because it may call into the backend +which may or may not be safe. + + +Remarks +------- +If the name does not fully fit into the output buffer, it'll be truncated. You can pass in NULL to +`pName` if you want to first get the length of the name for the purpose of memory allocation of the +output buffer. Allocating a buffer of size `MA_MAX_DEVICE_NAME_LENGTH + 1` should be enough for +most cases and will avoid the need for the inefficiency of calling this function twice. + +This is implemented in terms of `ma_device_get_info()`. +*/ +MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator); + + /* Starts the device. For playback devices this begins playback. For capture devices it begins recording. @@ -5398,17 +8709,17 @@ Return Value ------------ The current state of the device. The return value will be one of the following: - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_UNINITIALIZED | Will only be returned if the device is in the middle of initialization. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STOPPED | The device is stopped. The initial state of the device after initialization. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STARTED | The device started and requesting and/or delivering audio data. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STARTING | The device is in the process of starting. | - +------------------------+------------------------------------------------------------------------------+ - | MA_STATE_STOPPING | The device is in the process of stopping. | - +------------------------+------------------------------------------------------------------------------+ + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_uninitialized | Will only be returned if the device is in the middle of initialization. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_stopped | The device is stopped. The initial state of the device after initialization. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_started | The device started and requesting and/or delivering audio data. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_starting | The device is in the process of starting. | + +-------------------------------+------------------------------------------------------------------------------+ + | ma_device_state_stopping | The device is in the process of stopping. | + +-------------------------------+------------------------------------------------------------------------------+ Thread Safety @@ -5427,22 +8738,71 @@ Remarks The general flow of a devices state goes like this: ``` - ma_device_init() -> MA_STATE_UNINITIALIZED -> MA_STATE_STOPPED - ma_device_start() -> MA_STATE_STARTING -> MA_STATE_STARTED - ma_device_stop() -> MA_STATE_STOPPING -> MA_STATE_STOPPED + ma_device_init() -> ma_device_state_uninitialized -> ma_device_state_stopped + ma_device_start() -> ma_device_state_starting -> ma_device_state_started + ma_device_stop() -> ma_device_state_stopping -> ma_device_state_stopped ``` When the state of the device is changed with `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, the value returned by this function could potentially be out of sync. If this is significant to your program you need to implement your own synchronization. */ -MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice); +MA_API ma_device_state ma_device_get_state(const ma_device* pDevice); + + +/* +Performs post backend initialization routines for setting up internal data conversion. + +This should be called whenever the backend is initialized. The only time this should be called from +outside of miniaudio is if you're implementing a custom backend, and you would only do it if you +are reinitializing the backend due to rerouting or reinitializing for some reason. + + +Parameters +---------- +pDevice [in] + A pointer to the device. + +deviceType [in] + The type of the device that was just reinitialized. + +pPlaybackDescriptor [in] + The descriptor of the playback device containing the internal data format and buffer sizes. + +pPlaybackDescriptor [in] + The descriptor of the capture device containing the internal data format and buffer sizes. + + +Return Value +------------ +MA_SUCCESS if successful; any other error otherwise. + + +Thread Safety +------------- +Unsafe. This will be reinitializing internal data converters which may be in use by another thread. + + +Callback Safety +--------------- +Unsafe. This will be reinitializing internal data converters which may be in use by the callback. + + +Remarks +------- +For a duplex device, you can call this for only one side of the system. This is why the deviceType +is specified as a parameter rather than deriving it from the device. + +You do not need to call this manually unless you are doing a custom backend, in which case you need +only do it if you're manually performing rerouting or reinitialization. +*/ +MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPlaybackDescriptor, const ma_device_descriptor* pCaptureDescriptor); /* Sets the master volume factor for the device. -The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_gain_db()` to use decibel notation, where 0 is full volume and +The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_volume_db()` to use decibel notation, where 0 is full volume and values less than 0 decreases the volume. @@ -5452,14 +8812,14 @@ pDevice (in) A pointer to the device whose volume is being set. volume (in) - The new volume factor. Must be within the range of [0, 1]. + The new volume factor. Must be >= 0. Return Value ------------ MA_SUCCESS if the volume was set successfully. MA_INVALID_ARGS if pDevice is NULL. -MA_INVALID_ARGS if the volume factor is not within the range of [0, 1]. +MA_INVALID_ARGS if volume is negative. Thread Safety @@ -5482,8 +8842,8 @@ This does not change the operating system's volume. It only affects the volume f See Also -------- ma_device_get_master_volume() -ma_device_set_master_volume_gain_db() -ma_device_get_master_volume_gain_db() +ma_device_set_master_volume_db() +ma_device_get_master_volume_db() */ MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume); @@ -5575,7 +8935,7 @@ ma_device_get_master_volume_gain_db() ma_device_set_master_volume() ma_device_get_master_volume() */ -MA_API ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB); +MA_API ma_result ma_device_set_master_volume_db(ma_device* pDevice, float gainDB); /* Retrieves the master gain in decibels. @@ -5614,11 +8974,11 @@ If an error occurs, `*pGainDB` will be set to 0. See Also -------- -ma_device_set_master_volume_gain_db() +ma_device_set_master_volume_db() ma_device_set_master_volume() ma_device_get_master_volume() */ -MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB); +MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGainDB); /* @@ -5814,68 +9174,6 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend); #endif /* MA_NO_DEVICE_IO */ -#ifndef MA_NO_THREADING - -/* -Locks a spinlock. -*/ -MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock); - -/* -Locks a spinlock, but does not yield() when looping. -*/ -MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock); - -/* -Unlocks a spinlock. -*/ -MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock); - - -/* -Creates a mutex. - -A mutex must be created from a valid context. A mutex is initially unlocked. -*/ -MA_API ma_result ma_mutex_init(ma_mutex* pMutex); - -/* -Deletes a mutex. -*/ -MA_API void ma_mutex_uninit(ma_mutex* pMutex); - -/* -Locks a mutex with an infinite timeout. -*/ -MA_API void ma_mutex_lock(ma_mutex* pMutex); - -/* -Unlocks a mutex. -*/ -MA_API void ma_mutex_unlock(ma_mutex* pMutex); - - -/* -Initializes an auto-reset event. -*/ -MA_API ma_result ma_event_init(ma_event* pEvent); - -/* -Uninitializes an auto-reset event. -*/ -MA_API void ma_event_uninit(ma_event* pEvent); - -/* -Waits for the specified auto-reset event to become signalled. -*/ -MA_API ma_result ma_event_wait(ma_event* pEvent); - -/* -Signals the specified auto-reset event. -*/ -MA_API ma_result ma_event_signal(ma_event* pEvent); -#endif /* MA_NO_THREADING */ - /************************************************************************************************************************************************************ @@ -5883,13 +9181,6 @@ Utiltities ************************************************************************************************************************************************************/ -/* -Adjust buffer size based on a scaling factor. - -This just multiplies the base size by the scaling factor, making sure it's a size of at least 1. -*/ -MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale); - /* Calculates a buffer size in milliseconds from the specified number of frames and sample rate. */ @@ -5914,7 +9205,6 @@ For all formats except `ma_format_u8`, the output buffer will be filled with 0. makes more sense for the purpose of mixing to initialize it to the center point. */ MA_API void ma_silence_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels); -static MA_INLINE void ma_zero_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels) { ma_silence_pcm_frames(p, frameCount, format, channels); } /* @@ -5927,10 +9217,14 @@ static MA_INLINE const float* ma_offset_pcm_frames_const_ptr_f32(const float* p, /* -Clips f32 samples. +Clips samples. */ -MA_API void ma_clip_samples_f32(float* p, ma_uint64 sampleCount); -static MA_INLINE void ma_clip_pcm_frames_f32(float* p, ma_uint64 frameCount, ma_uint32 channels) { ma_clip_samples_f32(p, frameCount*channels); } +MA_API void ma_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count); +MA_API void ma_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count); +MA_API void ma_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count); +MA_API void ma_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count); +MA_API void ma_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count); +MA_API void ma_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels); /* Helper for applying a volume factor to samples. @@ -5949,11 +9243,11 @@ MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, fl MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor); MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pFramesOut, const ma_uint8* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pFramesOut, const ma_int16* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pFramesOut, const ma_int32* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor); MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor); MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor); @@ -5963,36 +9257,55 @@ MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 f MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor); MA_API void ma_apply_volume_factor_pcm_frames(void* pFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor); +MA_API void ma_copy_and_apply_volume_factor_per_channel_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float* pChannelGains); + + +MA_API void ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count, float volume); +MA_API void ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count, float volume); +MA_API void ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count, float volume); +MA_API void ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count, float volume); +MA_API void ma_copy_and_apply_volume_and_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count, float volume); +MA_API void ma_copy_and_apply_volume_and_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float volume); + /* Helper for converting a linear factor to gain in decibels. */ -MA_API float ma_factor_to_gain_db(float factor); +MA_API float ma_volume_linear_to_db(float factor); /* Helper for converting gain in decibels to a linear factor. */ -MA_API float ma_gain_db_to_factor(float gain); +MA_API float ma_volume_db_to_linear(float gain); + + +/************************************************************************************************** + +Data Source + +**************************************************************************************************/ typedef void ma_data_source; +#define MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT 0x00000001 + typedef struct { ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); ma_result (* onSeek)(ma_data_source* pDataSource, ma_uint64 frameIndex); - ma_result (* onMap)(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ - ma_result (* onUnmap)(ma_data_source* pDataSource, ma_uint64 frameCount); - ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); + ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor); ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength); -} ma_data_source_vtable, ma_data_source_callbacks; /* TODO: Remove ma_data_source_callbacks in version 0.11. */ + ma_result (* onSetLooping)(ma_data_source* pDataSource, ma_bool32 isLooping); + ma_uint32 flags; +} ma_data_source_vtable; typedef ma_data_source* (* ma_data_source_get_next_proc)(ma_data_source* pDataSource); typedef struct { - const ma_data_source_vtable* vtable; /* Can be null, which is useful for proxies. */ + const ma_data_source_vtable* vtable; } ma_data_source_config; MA_API ma_data_source_config ma_data_source_config_init(void); @@ -6000,9 +9313,6 @@ MA_API ma_data_source_config ma_data_source_config_init(void); typedef struct { - ma_data_source_callbacks cb; /* TODO: Remove this. */ - - /* Variables below are placeholder and not yet used. */ const ma_data_source_vtable* vtable; ma_uint64 rangeBegInFrames; ma_uint64 rangeEndInFrames; /* Set to -1 for unranged (default). */ @@ -6011,30 +9321,31 @@ typedef struct ma_data_source* pCurrent; /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */ ma_data_source* pNext; /* When set to NULL, onGetNext will be used. */ ma_data_source_get_next_proc onGetNext; /* Will be used when pNext is NULL. If both are NULL, no next will be used. */ + MA_ATOMIC(4, ma_bool32) isLooping; } ma_data_source_base; MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource); MA_API void ma_data_source_uninit(ma_data_source* pDataSource); -MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ -MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */ +MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ +MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex); -MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount); /* Returns MA_NOT_IMPLEMENTED if mapping is not supported. */ -MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. */ -MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); +MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor); MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ -#if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) +MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor); +MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength); +MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping); +MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source* pDataSource); MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames); -MA_API void ma_data_source_get_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames); +MA_API void ma_data_source_get_range_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames); MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames); -MA_API void ma_data_source_get_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames); +MA_API void ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames); MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource); -MA_API ma_data_source* ma_data_source_get_current(ma_data_source* pDataSource); +MA_API ma_data_source* ma_data_source_get_current(const ma_data_source* pDataSource); MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource); -MA_API ma_data_source* ma_data_source_get_next(ma_data_source* pDataSource); +MA_API ma_data_source* ma_data_source_get_next(const ma_data_source* pDataSource); MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext); -MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(ma_data_source* pDataSource); -#endif +MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source* pDataSource); typedef struct @@ -6042,6 +9353,7 @@ typedef struct ma_data_source_base ds; ma_format format; ma_uint32 channels; + ma_uint32 sampleRate; ma_uint64 cursor; ma_uint64 sizeInFrames; const void* pData; @@ -6065,6 +9377,7 @@ typedef struct { ma_format format; ma_uint32 channels; + ma_uint32 sampleRate; ma_uint64 sizeInFrames; const void* pData; /* If set to NULL, will allocate a block of memory for you. */ ma_allocation_callbacks allocationCallbacks; @@ -6095,6 +9408,69 @@ MA_API ma_result ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer* MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames); +/* +Paged Audio Buffer +================== +A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It +can be used for cases where audio data is streamed in asynchronously while allowing data to be read +at the same time. + +This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across +simultaneously across different threads, however only one thread at a time can append, and only one +thread at a time can read and seek. +*/ +typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page; +struct ma_paged_audio_buffer_page +{ + MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pNext; + ma_uint64 sizeInFrames; + ma_uint8 pAudioData[1]; +}; + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_paged_audio_buffer_page head; /* Dummy head for the lock-free algorithm. Always has a size of 0. */ + MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pTail; /* Never null. Initially set to &head. */ +} ma_paged_audio_buffer_data; + +MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData); +MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData); +MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData); +MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength); +MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage); +MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage); +MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks); + + +typedef struct +{ + ma_paged_audio_buffer_data* pData; /* Must not be null. */ +} ma_paged_audio_buffer_config; + +MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData); + + +typedef struct +{ + ma_data_source_base ds; + ma_paged_audio_buffer_data* pData; /* Audio data is read from here. Cannot be null. */ + ma_paged_audio_buffer_page* pCurrent; + ma_uint64 relativeCursor; /* Relative to the current page. */ + ma_uint64 absoluteCursor; +} ma_paged_audio_buffer; + +MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer); +MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer); +MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Returns MA_AT_END if no more pages available. */ +MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex); +MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor); +MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength); + + /************************************************************************************************************************************************************ @@ -6108,8 +9484,11 @@ appropriate for a given situation. typedef void ma_vfs; typedef ma_handle ma_vfs_file; -#define MA_OPEN_MODE_READ 0x00000001 -#define MA_OPEN_MODE_WRITE 0x00000002 +typedef enum +{ + MA_OPEN_MODE_READ = 0x00000001, + MA_OPEN_MODE_WRITE = 0x00000002 +} ma_open_mode_flags; typedef enum { @@ -6162,11 +9541,6 @@ typedef ma_result (* ma_tell_proc)(void* pUserData, ma_int64* pCursor); #if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING) -typedef enum -{ - ma_resource_format_wav -} ma_resource_format; - typedef enum { ma_encoding_format_unknown = 0, @@ -6193,25 +9567,24 @@ typedef struct ma_decoder ma_decoder; typedef struct { ma_format preferredFormat; + ma_uint32 seekPointCount; /* Set to > 0 to generate a seektable if the decoding backend supports it. */ } ma_decoding_backend_config; -MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat); +MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat, ma_uint32 seekPointCount); typedef struct { - ma_result (* onInit )(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); - ma_result (* onInitFile )(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ - ma_result (* onInitFileW )(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ - ma_result (* onInitMemory )(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ - void (* onUninit )(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks); - ma_result (* onGetChannelMap)(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap); + ma_result (* onInit )(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); + ma_result (* onInitFile )(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ + ma_result (* onInitFileW )(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ + ma_result (* onInitMemory)(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend); /* Optional. */ + void (* onUninit )(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks); } ma_decoding_backend_vtable; -/* TODO: Convert read and seek to be consistent with the VFS API (ma_result return value, bytes read moved to an output parameter). */ -typedef size_t (* ma_decoder_read_proc)(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */ -typedef ma_bool32 (* ma_decoder_seek_proc)(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin); +typedef ma_result (* ma_decoder_read_proc)(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead); /* Returns the number of bytes read. */ +typedef ma_result (* ma_decoder_seek_proc)(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin); typedef ma_result (* ma_decoder_tell_proc)(ma_decoder* pDecoder, ma_int64* pCursor); typedef struct @@ -6219,23 +9592,13 @@ typedef struct ma_format format; /* Set to 0 or ma_format_unknown to use the stream's internal format. */ ma_uint32 channels; /* Set to 0 to use the stream's internal channels. */ ma_uint32 sampleRate; /* Set to 0 to use the stream's internal sample rate. */ - ma_channel channelMap[MA_MAX_CHANNELS]; + ma_channel* pChannelMap; ma_channel_mix_mode channelMixMode; ma_dither_mode ditherMode; - struct - { - ma_resample_algorithm algorithm; - struct - { - ma_uint32 lpfOrder; - } linear; - struct - { - int quality; - } speex; - } resampling; + ma_resampler_config resampling; ma_allocation_callbacks allocationCallbacks; ma_encoding_format encodingFormat; + ma_uint32 seekPointCount; /* When set to > 0, specifies the number of seek points to use for the generation of a seek table. Not all decoding backends support this. */ ma_decoding_backend_vtable** ppCustomBackendVTables; ma_uint32 customBackendCount; void* pCustomBackendUserData; @@ -6255,8 +9618,11 @@ struct ma_decoder ma_format outputFormat; ma_uint32 outputChannels; ma_uint32 outputSampleRate; - ma_channel outputChannelMap[MA_MAX_CHANNELS]; - ma_data_converter converter; /* <-- Data conversion is achieved by running frames through this. */ + ma_data_converter converter; /* Data conversion is achieved by running frames through this. */ + void* pInputCache; /* In input format. Can be null if it's not needed. */ + ma_uint64 inputCacheCap; /* The capacity of the input cache. */ + ma_uint64 inputCacheConsumed; /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */ + ma_uint64 inputCacheRemaining; /* The number of valid frames remaining in the cahce. */ ma_allocation_callbacks allocationCallbacks; union { @@ -6289,6 +9655,25 @@ Uninitializes a decoder. */ MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder); +/* +Reads PCM frames from the given decoder. + +This is not thread safe without your own synchronization. +*/ +MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); + +/* +Seeks to a PCM frame based on it's absolute index. + +This is not thread safe without your own synchronization. +*/ +MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex); + +/* +Retrieves the decoder's output data format. +*/ +MA_API ma_result ma_decoder_get_data_format(ma_decoder* pDecoder, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); + /* Retrieves the current position of the read cursor in PCM frames. */ @@ -6308,21 +9693,7 @@ For MP3's, this will decode the entire file. Do not call this in time critical s This function is not thread safe without your own synchronization. */ -MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder); - -/* -Reads PCM frames from the given decoder. - -This is not thread safe without your own synchronization. -*/ -MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); - -/* -Seeks to a PCM frame based on it's absolute index. - -This is not thread safe without your own synchronization. -*/ -MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex); +MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength); /* Retrieves the number of frames that can be read before reaching the end. @@ -6343,43 +9714,6 @@ MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_deco MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut); MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut); - - - -/* -DEPRECATED - -Set the "encodingFormat" variable in the decoder config instead: - - decoderConfig.encodingFormat = ma_encoding_format_wav; - -These functions will be removed in version 0.11. -*/ -MA_API ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_wav(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_flac(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_mp3(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_vorbis(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_wav_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_flac_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_mp3_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_vfs_vorbis_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); -MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); - #endif /* MA_NO_DECODING */ @@ -6394,22 +9728,22 @@ Encoders do not perform any format conversion for you. If your target format doe #ifndef MA_NO_ENCODING typedef struct ma_encoder ma_encoder; -typedef size_t (* ma_encoder_write_proc) (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite); /* Returns the number of bytes written. */ -typedef ma_bool32 (* ma_encoder_seek_proc) (ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin); +typedef ma_result (* ma_encoder_write_proc) (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite, size_t* pBytesWritten); +typedef ma_result (* ma_encoder_seek_proc) (ma_encoder* pEncoder, ma_int64 offset, ma_seek_origin origin); typedef ma_result (* ma_encoder_init_proc) (ma_encoder* pEncoder); typedef void (* ma_encoder_uninit_proc) (ma_encoder* pEncoder); -typedef ma_uint64 (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount); +typedef ma_result (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten); typedef struct { - ma_resource_format resourceFormat; + ma_encoding_format encodingFormat; ma_format format; ma_uint32 channels; ma_uint32 sampleRate; ma_allocation_callbacks allocationCallbacks; } ma_encoder_config; -MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); +MA_API ma_encoder_config ma_encoder_config_init(ma_encoding_format encodingFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); struct ma_encoder { @@ -6421,14 +9755,23 @@ struct ma_encoder ma_encoder_write_pcm_frames_proc onWritePCMFrames; void* pUserData; void* pInternalEncoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */ - void* pFile; /* FILE*. Only used when initialized with ma_encoder_init_file(). */ + union + { + struct + { + ma_vfs* pVFS; + ma_vfs_file file; + } vfs; + } data; }; MA_API ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, const ma_encoder_config* pConfig, ma_encoder* pEncoder); +MA_API ma_result ma_encoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); +MA_API ma_result ma_encoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder); MA_API void ma_encoder_uninit(ma_encoder* pEncoder); -MA_API ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount); +MA_API ma_result ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten); #endif /* MA_NO_ENCODING */ @@ -6469,7 +9812,7 @@ typedef struct MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform); MA_API void ma_waveform_uninit(ma_waveform* pWaveform); -MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount); +MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex); MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude); MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency); @@ -6483,6 +9826,7 @@ typedef enum ma_noise_type_brownian } ma_noise_type; + typedef struct { ma_format format; @@ -6504,32 +9848,1187 @@ typedef struct { struct { - double bin[MA_MAX_CHANNELS][16]; - double accumulation[MA_MAX_CHANNELS]; - ma_uint32 counter[MA_MAX_CHANNELS]; + double** bin; + double* accumulation; + ma_uint32* counter; } pink; struct { - double accumulation[MA_MAX_CHANNELS]; + double* accumulation; } brownian; } state; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_noise; -MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise); -MA_API void ma_noise_uninit(ma_noise* pNoise); -MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount); +MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise); +MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise); +MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude); MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed); MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type); #endif /* MA_NO_GENERATION */ + + +/************************************************************************************************************************************************************ + +Resource Manager + +************************************************************************************************************************************************************/ +/* The resource manager cannot be enabled if there is no decoder. */ +#if !defined(MA_NO_RESOURCE_MANAGER) && defined(MA_NO_DECODING) +#define MA_NO_RESOURCE_MANAGER +#endif + +#ifndef MA_NO_RESOURCE_MANAGER +typedef struct ma_resource_manager ma_resource_manager; +typedef struct ma_resource_manager_data_buffer_node ma_resource_manager_data_buffer_node; +typedef struct ma_resource_manager_data_buffer ma_resource_manager_data_buffer; +typedef struct ma_resource_manager_data_stream ma_resource_manager_data_stream; +typedef struct ma_resource_manager_data_source ma_resource_manager_data_source; + +typedef enum +{ + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM = 0x00000001, /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */ + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE = 0x00000002, /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */ + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC = 0x00000004, /* When set, the resource manager will load the data source asynchronously. */ + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT = 0x00000008, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */ + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH = 0x00000010 /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */ +} ma_resource_manager_data_source_flags; + + +/* +Pipeline notifications used by the resource manager. Made up of both an async notification and a fence, both of which are optional. +*/ +typedef struct +{ + ma_async_notification* pNotification; + ma_fence* pFence; +} ma_resource_manager_pipeline_stage_notification; + +typedef struct +{ + ma_resource_manager_pipeline_stage_notification init; /* Initialization of the decoder. */ + ma_resource_manager_pipeline_stage_notification done; /* Decoding fully completed. */ +} ma_resource_manager_pipeline_notifications; + +MA_API ma_resource_manager_pipeline_notifications ma_resource_manager_pipeline_notifications_init(void); + + + +/* BEGIN BACKWARDS COMPATIBILITY */ +/* TODO: Remove this block in version 0.12. */ +#if 1 +#define ma_resource_manager_job ma_job +#define ma_resource_manager_job_init ma_job_init +#define MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING MA_JOB_QUEUE_FLAG_NON_BLOCKING +#define ma_resource_manager_job_queue_config ma_job_queue_config +#define ma_resource_manager_job_queue_config_init ma_job_queue_config_init +#define ma_resource_manager_job_queue ma_job_queue +#define ma_resource_manager_job_queue_get_heap_size ma_job_queue_get_heap_size +#define ma_resource_manager_job_queue_init_preallocated ma_job_queue_init_preallocated +#define ma_resource_manager_job_queue_init ma_job_queue_init +#define ma_resource_manager_job_queue_uninit ma_job_queue_uninit +#define ma_resource_manager_job_queue_post ma_job_queue_post +#define ma_resource_manager_job_queue_next ma_job_queue_next +#endif +/* END BACKWARDS COMPATIBILITY */ + + + + +/* Maximum job thread count will be restricted to this, but this may be removed later and replaced with a heap allocation thereby removing any limitation. */ +#ifndef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT +#define MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT 64 +#endif + +typedef enum +{ + /* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */ + MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING = 0x00000001, + + /* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */ + MA_RESOURCE_MANAGER_FLAG_NO_THREADING = 0x00000002 +} ma_resource_manager_flags; + +typedef struct +{ + const char* pFilePath; + const wchar_t* pFilePathW; + const ma_resource_manager_pipeline_notifications* pNotifications; + ma_uint64 initialSeekPointInPCMFrames; + ma_uint64 rangeBegInPCMFrames; + ma_uint64 rangeEndInPCMFrames; + ma_uint64 loopPointBegInPCMFrames; + ma_uint64 loopPointEndInPCMFrames; + ma_bool32 isLooping; + ma_uint32 flags; +} ma_resource_manager_data_source_config; + +MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_config_init(void); + + +typedef enum +{ + ma_resource_manager_data_supply_type_unknown = 0, /* Used for determining whether or the data supply has been initialized. */ + ma_resource_manager_data_supply_type_encoded, /* Data supply is an encoded buffer. Connector is ma_decoder. */ + ma_resource_manager_data_supply_type_decoded, /* Data supply is a decoded buffer. Connector is ma_audio_buffer. */ + ma_resource_manager_data_supply_type_decoded_paged /* Data supply is a linked list of decoded buffers. Connector is ma_paged_audio_buffer. */ +} ma_resource_manager_data_supply_type; + +typedef struct +{ + MA_ATOMIC(4, ma_resource_manager_data_supply_type) type; /* Read and written from different threads so needs to be accessed atomically. */ + union + { + struct + { + const void* pData; + size_t sizeInBytes; + } encoded; + struct + { + const void* pData; + ma_uint64 totalFrameCount; + ma_uint64 decodedFrameCount; + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + } decoded; + struct + { + ma_paged_audio_buffer_data data; + ma_uint64 decodedFrameCount; + ma_uint32 sampleRate; + } decodedPaged; + } backend; +} ma_resource_manager_data_supply; + +struct ma_resource_manager_data_buffer_node +{ + ma_uint32 hashedName32; /* The hashed name. This is the key. */ + ma_uint32 refCount; + MA_ATOMIC(4, ma_result) result; /* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */ + MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ + MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ + ma_bool32 isDataOwnedByResourceManager; /* Set to true when the underlying data buffer was allocated the resource manager. Set to false if it is owned by the application (via ma_resource_manager_register_*()). */ + ma_resource_manager_data_supply data; + ma_resource_manager_data_buffer_node* pParent; + ma_resource_manager_data_buffer_node* pChildLo; + ma_resource_manager_data_buffer_node* pChildHi; +}; + +struct ma_resource_manager_data_buffer +{ + ma_data_source_base ds; /* Base data source. A data buffer is a data source. */ + ma_resource_manager* pResourceManager; /* A pointer to the resource manager that owns this buffer. */ + ma_resource_manager_data_buffer_node* pNode; /* The data node. This is reference counted and is what supplies the data. */ + ma_uint32 flags; /* The flags that were passed used to initialize the buffer. */ + MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ + MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ + ma_uint64 seekTargetInPCMFrames; /* Only updated by the public API. Never written nor read from the job thread. */ + ma_bool32 seekToCursorOnNextRead; /* On the next read we need to seek to the frame cursor. */ + MA_ATOMIC(4, ma_result) result; /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */ + MA_ATOMIC(4, ma_bool32) isLooping; /* Can be read and written by different threads at the same time. Must be used atomically. */ + ma_bool32 isConnectorInitialized; /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */ + union + { + ma_decoder decoder; /* Supply type is ma_resource_manager_data_supply_type_encoded */ + ma_audio_buffer buffer; /* Supply type is ma_resource_manager_data_supply_type_decoded */ + ma_paged_audio_buffer pagedBuffer; /* Supply type is ma_resource_manager_data_supply_type_decoded_paged */ + } connector; /* Connects this object to the node's data supply. */ +}; + +struct ma_resource_manager_data_stream +{ + ma_data_source_base ds; /* Base data source. A data stream is a data source. */ + ma_resource_manager* pResourceManager; /* A pointer to the resource manager that owns this data stream. */ + ma_uint32 flags; /* The flags that were passed used to initialize the stream. */ + ma_decoder decoder; /* Used for filling pages with data. This is only ever accessed by the job thread. The public API should never touch this. */ + ma_bool32 isDecoderInitialized; /* Required for determining whether or not the decoder should be uninitialized in MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM. */ + ma_uint64 totalLengthInPCMFrames; /* This is calculated when first loaded by the MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM. */ + ma_uint32 relativeCursor; /* The playback cursor, relative to the current page. Only ever accessed by the public API. Never accessed by the job thread. */ + MA_ATOMIC(8, ma_uint64) absoluteCursor; /* The playback cursor, in absolute position starting from the start of the file. */ + ma_uint32 currentPageIndex; /* Toggles between 0 and 1. Index 0 is the first half of pPageData. Index 1 is the second half. Only ever accessed by the public API. Never accessed by the job thread. */ + MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ + MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ + + /* Written by the public API, read by the job thread. */ + MA_ATOMIC(4, ma_bool32) isLooping; /* Whether or not the stream is looping. It's important to set the looping flag at the data stream level for smooth loop transitions. */ + + /* Written by the job thread, read by the public API. */ + void* pPageData; /* Buffer containing the decoded data of each page. Allocated once at initialization time. */ + MA_ATOMIC(4, ma_uint32) pageFrameCount[2]; /* The number of valid PCM frames in each page. Used to determine the last valid frame. */ + + /* Written and read by both the public API and the job thread. These must be atomic. */ + MA_ATOMIC(4, ma_result) result; /* Result from asynchronous loading. When loading set to MA_BUSY. When initialized set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. If an error occurs when loading, set to an error code. */ + MA_ATOMIC(4, ma_bool32) isDecoderAtEnd; /* Whether or not the decoder has reached the end. */ + MA_ATOMIC(4, ma_bool32) isPageValid[2]; /* Booleans to indicate whether or not a page is valid. Set to false by the public API, set to true by the job thread. Set to false as the pages are consumed, true when they are filled. */ + MA_ATOMIC(4, ma_bool32) seekCounter; /* When 0, no seeking is being performed. When > 0, a seek is being performed and reading should be delayed with MA_BUSY. */ +}; + +struct ma_resource_manager_data_source +{ + union + { + ma_resource_manager_data_buffer buffer; + ma_resource_manager_data_stream stream; + } backend; /* Must be the first item because we need the first item to be the data source callbacks for the buffer or stream. */ + + ma_uint32 flags; /* The flags that were passed in to ma_resource_manager_data_source_init(). */ + MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */ + MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */ +}; + +typedef struct +{ + ma_allocation_callbacks allocationCallbacks; + ma_log* pLog; + ma_format decodedFormat; /* The decoded format to use. Set to ma_format_unknown (default) to use the file's native format. */ + ma_uint32 decodedChannels; /* The decoded channel count to use. Set to 0 (default) to use the file's native channel count. */ + ma_uint32 decodedSampleRate; /* the decoded sample rate to use. Set to 0 (default) to use the file's native sample rate. */ + ma_uint32 jobThreadCount; /* Set to 0 if you want to self-manage your job threads. Defaults to 1. */ + ma_uint32 jobQueueCapacity; /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY. Cannot be zero. */ + ma_uint32 flags; + ma_vfs* pVFS; /* Can be NULL in which case defaults will be used. */ + ma_decoding_backend_vtable** ppCustomDecodingBackendVTables; + ma_uint32 customDecodingBackendCount; + void* pCustomDecodingBackendUserData; +} ma_resource_manager_config; + +MA_API ma_resource_manager_config ma_resource_manager_config_init(void); + +struct ma_resource_manager +{ + ma_resource_manager_config config; + ma_resource_manager_data_buffer_node* pRootDataBufferNode; /* The root buffer in the binary tree. */ +#ifndef MA_NO_THREADING + ma_mutex dataBufferBSTLock; /* For synchronizing access to the data buffer binary tree. */ + ma_thread jobThreads[MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT]; /* The threads for executing jobs. */ +#endif + ma_job_queue jobQueue; /* Multi-consumer, multi-producer job queue for managing jobs for asynchronous decoding and streaming. */ + ma_default_vfs defaultVFS; /* Only used if a custom VFS is not specified. */ + ma_log log; /* Only used if no log was specified in the config. */ +}; + +/* Init. */ +MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager); +MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager); +MA_API ma_log* ma_resource_manager_get_log(ma_resource_manager* pResourceManager); + +/* Registration. */ +MA_API ma_result ma_resource_manager_register_file(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags); +MA_API ma_result ma_resource_manager_register_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags); +MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */ +MA_API ma_result ma_resource_manager_register_decoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate); +MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes); /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */ +MA_API ma_result ma_resource_manager_register_encoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, size_t sizeInBytes); +MA_API ma_result ma_resource_manager_unregister_file(ma_resource_manager* pResourceManager, const char* pFilePath); +MA_API ma_result ma_resource_manager_unregister_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath); +MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName); +MA_API ma_result ma_resource_manager_unregister_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName); + +/* Data Buffers. */ +MA_API ma_result ma_resource_manager_data_buffer_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_buffer* pDataBuffer); +MA_API ma_result ma_resource_manager_data_buffer_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer); +MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer); +MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer); +MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data_buffer* pDataBuffer); +MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64 frameIndex); +MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_manager_data_buffer* pDataBuffer, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pCursor); +MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength); +MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manager_data_buffer* pDataBuffer); +MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping); +MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer); +MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames); + +/* Data Streams. */ +MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_stream* pDataStream); +MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream); +MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream); +MA_API ma_result ma_resource_manager_data_stream_uninit(ma_resource_manager_data_stream* pDataStream); +MA_API ma_result ma_resource_manager_data_stream_read_pcm_frames(ma_resource_manager_data_stream* pDataStream, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_result ma_resource_manager_data_stream_seek_to_pcm_frame(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameIndex); +MA_API ma_result ma_resource_manager_data_stream_get_data_format(ma_resource_manager_data_stream* pDataStream, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_resource_manager_data_stream_get_cursor_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pCursor); +MA_API ma_result ma_resource_manager_data_stream_get_length_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pLength); +MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream); +MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping); +MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream); +MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames); + +/* Data Sources. */ +MA_API ma_result ma_resource_manager_data_source_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource); +MA_API ma_result ma_resource_manager_data_source_init(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource); +MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pResourceManager, const wchar_t* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource); +MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource); +MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource); +MA_API ma_result ma_resource_manager_data_source_read_pcm_frames(ma_resource_manager_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_result ma_resource_manager_data_source_seek_to_pcm_frame(ma_resource_manager_data_source* pDataSource, ma_uint64 frameIndex); +MA_API ma_result ma_resource_manager_data_source_get_data_format(ma_resource_manager_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_resource_manager_data_source_get_cursor_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pCursor); +MA_API ma_result ma_resource_manager_data_source_get_length_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pLength); +MA_API ma_result ma_resource_manager_data_source_result(const ma_resource_manager_data_source* pDataSource); +MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager_data_source* pDataSource, ma_bool32 isLooping); +MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource); +MA_API ma_result ma_resource_manager_data_source_get_available_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pAvailableFrames); + +/* Job management. */ +MA_API ma_result ma_resource_manager_post_job(ma_resource_manager* pResourceManager, const ma_job* pJob); +MA_API ma_result ma_resource_manager_post_job_quit(ma_resource_manager* pResourceManager); /* Helper for posting a quit job. */ +MA_API ma_result ma_resource_manager_next_job(ma_resource_manager* pResourceManager, ma_job* pJob); +MA_API ma_result ma_resource_manager_process_job(ma_resource_manager* pResourceManager, ma_job* pJob); /* DEPRECATED. Use ma_job_process(). Will be removed in version 0.12. */ +MA_API ma_result ma_resource_manager_process_next_job(ma_resource_manager* pResourceManager); /* Returns MA_CANCELLED if a MA_JOB_TYPE_QUIT job is found. In non-blocking mode, returns MA_NO_DATA_AVAILABLE if no jobs are available. */ +#endif /* MA_NO_RESOURCE_MANAGER */ + + + +/************************************************************************************************************************************************************ + +Node Graph + +************************************************************************************************************************************************************/ +#ifndef MA_NO_NODE_GRAPH +/* Must never exceed 254. */ +#ifndef MA_MAX_NODE_BUS_COUNT +#define MA_MAX_NODE_BUS_COUNT 254 +#endif + +/* Used internally by miniaudio for memory management. Must never exceed MA_MAX_NODE_BUS_COUNT. */ +#ifndef MA_MAX_NODE_LOCAL_BUS_COUNT +#define MA_MAX_NODE_LOCAL_BUS_COUNT 2 +#endif + +/* Use this when the bus count is determined by the node instance rather than the vtable. */ +#define MA_NODE_BUS_COUNT_UNKNOWN 255 + +typedef struct ma_node_graph ma_node_graph; +typedef void ma_node; + + +/* Node flags. */ +typedef enum +{ + MA_NODE_FLAG_PASSTHROUGH = 0x00000001, + MA_NODE_FLAG_CONTINUOUS_PROCESSING = 0x00000002, + MA_NODE_FLAG_ALLOW_NULL_INPUT = 0x00000004, + MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES = 0x00000008, + MA_NODE_FLAG_SILENT_OUTPUT = 0x00000010 +} ma_node_flags; + + +/* The playback state of a node. Either started or stopped. */ +typedef enum +{ + ma_node_state_started = 0, + ma_node_state_stopped = 1 +} ma_node_state; + + +typedef struct +{ + /* + Extended processing callback. This callback is used for effects that process input and output + at different rates (i.e. they perform resampling). This is similar to the simple version, only + they take two seperate frame counts: one for input, and one for output. + + On input, `pFrameCountOut` is equal to the capacity of the output buffer for each bus, whereas + `pFrameCountIn` will be equal to the number of PCM frames in each of the buffers in `ppFramesIn`. + + On output, set `pFrameCountOut` to the number of PCM frames that were actually output and set + `pFrameCountIn` to the number of input frames that were consumed. + */ + void (* onProcess)(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut); + + /* + A callback for retrieving the number of a input frames that are required to output the + specified number of output frames. You would only want to implement this when the node performs + resampling. This is optional, even for nodes that perform resampling, but it does offer a + small reduction in latency as it allows miniaudio to calculate the exact number of input frames + to read at a time instead of having to estimate. + */ + ma_result (* onGetRequiredInputFrameCount)(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount); + + /* + The number of input buses. This is how many sub-buffers will be contained in the `ppFramesIn` + parameters of the callbacks above. + */ + ma_uint8 inputBusCount; + + /* + The number of output buses. This is how many sub-buffers will be contained in the `ppFramesOut` + parameters of the callbacks above. + */ + ma_uint8 outputBusCount; + + /* + Flags describing characteristics of the node. This is currently just a placeholder for some + ideas for later on. + */ + ma_uint32 flags; +} ma_node_vtable; + +typedef struct +{ + const ma_node_vtable* vtable; /* Should never be null. Initialization of the node will fail if so. */ + ma_node_state initialState; /* Defaults to ma_node_state_started. */ + ma_uint32 inputBusCount; /* Only used if the vtable specifies an input bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise must be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */ + ma_uint32 outputBusCount; /* Only used if the vtable specifies an output bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */ + const ma_uint32* pInputChannels; /* The number of elements are determined by the input bus count as determined by the vtable, or `inputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */ + const ma_uint32* pOutputChannels; /* The number of elements are determined by the output bus count as determined by the vtable, or `outputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */ +} ma_node_config; + +MA_API ma_node_config ma_node_config_init(void); + + +/* +A node has multiple output buses. An output bus is attached to an input bus as an item in a linked +list. Think of the input bus as a linked list, with the output bus being an item in that list. +*/ +typedef struct ma_node_output_bus ma_node_output_bus; +struct ma_node_output_bus +{ + /* Immutable. */ + ma_node* pNode; /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */ + ma_uint8 outputBusIndex; /* The index of the output bus on pNode that this output bus represents. */ + ma_uint8 channels; /* The number of channels in the audio stream for this bus. */ + + /* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */ + MA_ATOMIC(1, ma_uint8) inputNodeInputBusIndex; /* The index of the input bus on the input. Required for detaching. */ + MA_ATOMIC(4, ma_uint32) flags; /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */ + MA_ATOMIC(4, ma_uint32) refCount; /* Reference count for some thread-safety when detaching. */ + MA_ATOMIC(4, ma_bool32) isAttached; /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */ + MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ + MA_ATOMIC(4, float) volume; /* Linear. */ + MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pNext; /* If null, it's the tail node or detached. */ + MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pPrev; /* If null, it's the head node or detached. */ + MA_ATOMIC(MA_SIZEOF_PTR, ma_node*) pInputNode; /* The node that this output bus is attached to. Required for detaching. */ +}; + +/* +A node has multiple input buses. The output buses of a node are connecting to the input busses of +another. An input bus is essentially just a linked list of output buses. +*/ +typedef struct ma_node_input_bus ma_node_input_bus; +struct ma_node_input_bus +{ + /* Mutable via multiple threads. */ + ma_node_output_bus head; /* Dummy head node for simplifying some lock-free thread-safety stuff. */ + MA_ATOMIC(4, ma_uint32) nextCounter; /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */ + MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ + + /* Set once at startup. */ + ma_uint8 channels; /* The number of channels in the audio stream for this bus. */ +}; + + +typedef struct ma_node_base ma_node_base; +struct ma_node_base +{ + /* These variables are set once at startup. */ + ma_node_graph* pNodeGraph; /* The graph this node belongs to. */ + const ma_node_vtable* vtable; + float* pCachedData; /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */ + ma_uint16 cachedDataCapInFramesPerBus; /* The capacity of the input data cache in frames, per bus. */ + + /* These variables are read and written only from the audio thread. */ + ma_uint16 cachedFrameCountOut; + ma_uint16 cachedFrameCountIn; + ma_uint16 consumedFrameCountIn; + + /* These variables are read and written between different threads. */ + MA_ATOMIC(4, ma_node_state) state; /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */ + MA_ATOMIC(8, ma_uint64) stateTimes[2]; /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */ + MA_ATOMIC(8, ma_uint64) localTime; /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */ + ma_uint32 inputBusCount; + ma_uint32 outputBusCount; + ma_node_input_bus* pInputBuses; + ma_node_output_bus* pOutputBuses; + + /* Memory management. */ + ma_node_input_bus _inputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT]; + ma_node_output_bus _outputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT]; + void* _pHeap; /* A heap allocation for internal use only. pInputBuses and/or pOutputBuses will point to this if the bus count exceeds MA_MAX_NODE_LOCAL_BUS_COUNT. */ + ma_bool32 _ownsHeap; /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */ +}; + +MA_API ma_result ma_node_get_heap_size(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode); +MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode); +MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_node_graph* ma_node_get_node_graph(const ma_node* pNode); +MA_API ma_uint32 ma_node_get_input_bus_count(const ma_node* pNode); +MA_API ma_uint32 ma_node_get_output_bus_count(const ma_node* pNode); +MA_API ma_uint32 ma_node_get_input_channels(const ma_node* pNode, ma_uint32 inputBusIndex); +MA_API ma_uint32 ma_node_get_output_channels(const ma_node* pNode, ma_uint32 outputBusIndex); +MA_API ma_result ma_node_attach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex, ma_node* pOtherNode, ma_uint32 otherNodeInputBusIndex); +MA_API ma_result ma_node_detach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex); +MA_API ma_result ma_node_detach_all_output_buses(ma_node* pNode); +MA_API ma_result ma_node_set_output_bus_volume(ma_node* pNode, ma_uint32 outputBusIndex, float volume); +MA_API float ma_node_get_output_bus_volume(const ma_node* pNode, ma_uint32 outputBusIndex); +MA_API ma_result ma_node_set_state(ma_node* pNode, ma_node_state state); +MA_API ma_node_state ma_node_get_state(const ma_node* pNode); +MA_API ma_result ma_node_set_state_time(ma_node* pNode, ma_node_state state, ma_uint64 globalTime); +MA_API ma_uint64 ma_node_get_state_time(const ma_node* pNode, ma_node_state state); +MA_API ma_node_state ma_node_get_state_by_time(const ma_node* pNode, ma_uint64 globalTime); +MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_uint64 globalTimeBeg, ma_uint64 globalTimeEnd); +MA_API ma_uint64 ma_node_get_time(const ma_node* pNode); +MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime); + + +typedef struct +{ + ma_uint32 channels; + ma_uint16 nodeCacheCapInFrames; +} ma_node_graph_config; + +MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels); + + +struct ma_node_graph +{ + /* Immutable. */ + ma_node_base base; /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */ + ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */ + ma_uint16 nodeCacheCapInFrames; + + /* Read and written by multiple threads. */ + MA_ATOMIC(4, ma_bool32) isReading; +}; + +MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph); +MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph); +MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph); +MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph); +MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime); + + + +/* Data source node. 0 input buses, 1 output bus. Used for reading from a data source. */ +typedef struct +{ + ma_node_config nodeConfig; + ma_data_source* pDataSource; +} ma_data_source_node_config; + +MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource); + + +typedef struct +{ + ma_node_base base; + ma_data_source* pDataSource; +} ma_data_source_node; + +MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_data_source_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source_node* pDataSourceNode); +MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping); +MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode); + + +/* Splitter Node. 1 input, 2 outputs. Used for splitting/copying a stream so it can be as input into two separate output nodes. */ +typedef struct +{ + ma_node_config nodeConfig; + ma_uint32 channels; +} ma_splitter_node_config; + +MA_API ma_splitter_node_config ma_splitter_node_config_init(ma_uint32 channels); + + +typedef struct +{ + ma_node_base base; +} ma_splitter_node; + +MA_API ma_result ma_splitter_node_init(ma_node_graph* pNodeGraph, const ma_splitter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_splitter_node* pSplitterNode); +MA_API void ma_splitter_node_uninit(ma_splitter_node* pSplitterNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +Biquad Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_biquad_config biquad; +} ma_biquad_node_config; + +MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2); + + +typedef struct +{ + ma_node_base baseNode; + ma_biquad biquad; +} ma_biquad_node; + +MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode); +MA_API ma_result ma_biquad_node_reinit(const ma_biquad_config* pConfig, ma_biquad_node* pNode); +MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +Low Pass Filter Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_lpf_config lpf; +} ma_lpf_node_config; + +MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + + +typedef struct +{ + ma_node_base baseNode; + ma_lpf lpf; +} ma_lpf_node; + +MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode); +MA_API ma_result ma_lpf_node_reinit(const ma_lpf_config* pConfig, ma_lpf_node* pNode); +MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +High Pass Filter Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_hpf_config hpf; +} ma_hpf_node_config; + +MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + + +typedef struct +{ + ma_node_base baseNode; + ma_hpf hpf; +} ma_hpf_node; + +MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode); +MA_API ma_result ma_hpf_node_reinit(const ma_hpf_config* pConfig, ma_hpf_node* pNode); +MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +Band Pass Filter Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_bpf_config bpf; +} ma_bpf_node_config; + +MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + + +typedef struct +{ + ma_node_base baseNode; + ma_bpf bpf; +} ma_bpf_node; + +MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode); +MA_API ma_result ma_bpf_node_reinit(const ma_bpf_config* pConfig, ma_bpf_node* pNode); +MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +Notching Filter Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_notch_config notch; +} ma_notch_node_config; + +MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency); + + +typedef struct +{ + ma_node_base baseNode; + ma_notch2 notch; +} ma_notch_node; + +MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode); +MA_API ma_result ma_notch_node_reinit(const ma_notch_config* pConfig, ma_notch_node* pNode); +MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +Peaking Filter Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_peak_config peak; +} ma_peak_node_config; + +MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); + + +typedef struct +{ + ma_node_base baseNode; + ma_peak2 peak; +} ma_peak_node; + +MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode); +MA_API ma_result ma_peak_node_reinit(const ma_peak_config* pConfig, ma_peak_node* pNode); +MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +Low Shelf Filter Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_loshelf_config loshelf; +} ma_loshelf_node_config; + +MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); + + +typedef struct +{ + ma_node_base baseNode; + ma_loshelf2 loshelf; +} ma_loshelf_node; + +MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode); +MA_API ma_result ma_loshelf_node_reinit(const ma_loshelf_config* pConfig, ma_loshelf_node* pNode); +MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +High Shelf Filter Node +*/ +typedef struct +{ + ma_node_config nodeConfig; + ma_hishelf_config hishelf; +} ma_hishelf_node_config; + +MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); + + +typedef struct +{ + ma_node_base baseNode; + ma_hishelf2 hishelf; +} ma_hishelf_node; + +MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode); +MA_API ma_result ma_hishelf_node_reinit(const ma_hishelf_config* pConfig, ma_hishelf_node* pNode); +MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +typedef struct +{ + ma_node_config nodeConfig; + ma_delay_config delay; +} ma_delay_node_config; + +MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay); + + +typedef struct +{ + ma_node_base baseNode; + ma_delay delay; +} ma_delay_node; + +MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode); +MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value); +MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode); +MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value); +MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode); +MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value); +MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode); +#endif /* MA_NO_NODE_GRAPH */ + + +/************************************************************************************************************************************************************ + +Engine + +************************************************************************************************************************************************************/ +#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) +typedef struct ma_engine ma_engine; +typedef struct ma_sound ma_sound; + + +/* Sound flags. */ +typedef enum +{ + MA_SOUND_FLAG_STREAM = 0x00000001, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */ + MA_SOUND_FLAG_DECODE = 0x00000002, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */ + MA_SOUND_FLAG_ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */ + MA_SOUND_FLAG_WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */ + MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT = 0x00000010, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */ + MA_SOUND_FLAG_NO_PITCH = 0x00000020, /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */ + MA_SOUND_FLAG_NO_SPATIALIZATION = 0x00000040 /* Disable spatialization. */ +} ma_sound_flags; + +#ifndef MA_ENGINE_MAX_LISTENERS +#define MA_ENGINE_MAX_LISTENERS 4 +#endif + +#define MA_LISTENER_INDEX_CLOSEST ((ma_uint8)-1) + +typedef enum +{ + ma_engine_node_type_sound, + ma_engine_node_type_group +} ma_engine_node_type; + +typedef struct +{ + ma_engine* pEngine; + ma_engine_node_type type; + ma_uint32 channelsIn; + ma_uint32 channelsOut; + ma_uint32 sampleRate; /* Only used when the type is set to ma_engine_node_type_sound. */ + ma_bool8 isPitchDisabled; /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ + ma_bool8 isSpatializationDisabled; /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */ + ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ +} ma_engine_node_config; + +MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags); + + +/* Base node object for both ma_sound and ma_sound_group. */ +typedef struct +{ + ma_node_base baseNode; /* Must be the first member for compatiblity with the ma_node API. */ + ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */ + ma_uint32 sampleRate; /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */ + ma_fader fader; + ma_linear_resampler resampler; /* For pitch shift. */ + ma_spatializer spatializer; + ma_panner panner; + MA_ATOMIC(4, float) pitch; + float oldPitch; /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */ + float oldDopplerPitch; /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */ + MA_ATOMIC(4, ma_bool32) isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */ + MA_ATOMIC(4, ma_bool32) isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */ + MA_ATOMIC(4, ma_uint32) pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ + + /* Memory management. */ + ma_bool8 _ownsHeap; + void* _pHeap; +} ma_engine_node; + +MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode); +MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode); +MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +#define MA_SOUND_SOURCE_CHANNEL_COUNT 0xFFFFFFFF + +typedef struct +{ + const char* pFilePath; /* Set this to load from the resource manager. */ + const wchar_t* pFilePathW; /* Set this to load from the resource manager. */ + ma_data_source* pDataSource; /* Set this to load from an existing data source. */ + ma_node* pInitialAttachment; /* If set, the sound will be attached to an input of this node. This can be set to a ma_sound. If set to NULL, the sound will be attached directly to the endpoint unless MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT is set in `flags`. */ + ma_uint32 initialAttachmentInputBusIndex; /* The index of the input bus of pInitialAttachment to attach the sound to. */ + ma_uint32 channelsIn; /* Ignored if using a data source as input (the data source's channel count will be used always). Otherwise, setting to 0 will cause the engine's channel count to be used. */ + ma_uint32 channelsOut; /* Set this to 0 (default) to use the engine's channel count. Set to MA_SOUND_SOURCE_CHANNEL_COUNT to use the data source's channel count (only used if using a data source as input). */ + ma_uint32 flags; /* A combination of MA_SOUND_FLAG_* flags. */ + ma_uint64 initialSeekPointInPCMFrames; /* Initializes the sound such that it's seeked to this location by default. */ + ma_uint64 rangeBegInPCMFrames; + ma_uint64 rangeEndInPCMFrames; + ma_uint64 loopPointBegInPCMFrames; + ma_uint64 loopPointEndInPCMFrames; + ma_bool32 isLooping; + ma_fence* pDoneFence; /* Released when the resource manager has finished decoding the entire sound. Not used with streams. */ +} ma_sound_config; + +MA_API ma_sound_config ma_sound_config_init(void); + +struct ma_sound +{ + ma_engine_node engineNode; /* Must be the first member for compatibility with the ma_node API. */ + ma_data_source* pDataSource; + MA_ATOMIC(8, ma_uint64) seekTarget; /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */ + MA_ATOMIC(4, ma_bool32) atEnd; + ma_bool8 ownsDataSource; + + /* + We're declaring a resource manager data source object here to save us a malloc when loading a + sound via the resource manager, which I *think* will be the most common scenario. + */ +#ifndef MA_NO_RESOURCE_MANAGER + ma_resource_manager_data_source* pResourceManagerDataSource; +#endif +}; + +/* Structure specifically for sounds played with ma_engine_play_sound(). Making this a separate structure to reduce overhead. */ +typedef struct ma_sound_inlined ma_sound_inlined; +struct ma_sound_inlined +{ + ma_sound sound; + ma_sound_inlined* pNext; + ma_sound_inlined* pPrev; +}; + +/* A sound group is just a sound. */ +typedef ma_sound_config ma_sound_group_config; +typedef ma_sound ma_sound_group; + +MA_API ma_sound_group_config ma_sound_group_config_init(void); + + +typedef struct +{ +#if !defined(MA_NO_RESOURCE_MANAGER) + ma_resource_manager* pResourceManager; /* Can be null in which case a resource manager will be created for you. */ +#endif +#if !defined(MA_NO_DEVICE_IO) + ma_context* pContext; + ma_device* pDevice; /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */ + ma_device_id* pPlaybackDeviceID; /* The ID of the playback device to use with the default listener. */ +#endif + ma_log* pLog; /* When set to NULL, will use the context's log. */ + ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ + ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ + ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native channel count of the device. */ + ma_uint32 periodSizeInFrames; /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ + ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */ + ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ + ma_uint32 gainSmoothTimeInMilliseconds; /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */ + ma_allocation_callbacks allocationCallbacks; + ma_bool32 noAutoStart; /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */ + ma_bool32 noDevice; /* When set to true, don't create a default device. ma_engine_read_pcm_frames() can be called manually to read data. */ + ma_mono_expansion_mode monoExpansionMode; /* Controls how the mono channel should be expanded to other channels when spatialization is disabled on a sound. */ + ma_vfs* pResourceManagerVFS; /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */ +} ma_engine_config; + +MA_API ma_engine_config ma_engine_config_init(void); + + +struct ma_engine +{ + ma_node_graph nodeGraph; /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */ +#if !defined(MA_NO_RESOURCE_MANAGER) + ma_resource_manager* pResourceManager; +#endif +#if !defined(MA_NO_DEVICE_IO) + ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ +#endif + ma_log* pLog; + ma_uint32 sampleRate; + ma_uint32 listenerCount; + ma_spatializer_listener listeners[MA_ENGINE_MAX_LISTENERS]; + ma_allocation_callbacks allocationCallbacks; + ma_bool8 ownsResourceManager; + ma_bool8 ownsDevice; + ma_spinlock inlinedSoundLock; /* For synchronizing access so the inlined sound list. */ + ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */ + MA_ATOMIC(4, ma_uint32) inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */ + ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */ + ma_mono_expansion_mode monoExpansionMode; +}; + +MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine); +MA_API void ma_engine_uninit(ma_engine* pEngine); +MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_node_graph* ma_engine_get_node_graph(ma_engine* pEngine); +#if !defined(MA_NO_RESOURCE_MANAGER) +MA_API ma_resource_manager* ma_engine_get_resource_manager(ma_engine* pEngine); +#endif +MA_API ma_device* ma_engine_get_device(ma_engine* pEngine); +MA_API ma_log* ma_engine_get_log(ma_engine* pEngine); +MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine); +MA_API ma_uint64 ma_engine_get_time(const ma_engine* pEngine); +MA_API ma_result ma_engine_set_time(ma_engine* pEngine, ma_uint64 globalTime); +MA_API ma_uint32 ma_engine_get_channels(const ma_engine* pEngine); +MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine); + +MA_API ma_result ma_engine_start(ma_engine* pEngine); +MA_API ma_result ma_engine_stop(ma_engine* pEngine); +MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume); +MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB); + +MA_API ma_uint32 ma_engine_get_listener_count(const ma_engine* pEngine); +MA_API ma_uint32 ma_engine_find_closest_listener(const ma_engine* pEngine, float absolutePosX, float absolutePosY, float absolutePosZ); +MA_API void ma_engine_listener_set_position(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); +MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uint32 listenerIndex); +MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); +MA_API ma_vec3f ma_engine_listener_get_direction(const ma_engine* pEngine, ma_uint32 listenerIndex); +MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); +MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex); +MA_API void ma_engine_listener_set_cone(ma_engine* pEngine, ma_uint32 listenerIndex, float innerAngleInRadians, float outerAngleInRadians, float outerGain); +MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 listenerIndex, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); +MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); +MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex); +MA_API void ma_engine_listener_set_enabled(ma_engine* pEngine, ma_uint32 listenerIndex, ma_bool32 isEnabled); +MA_API ma_bool32 ma_engine_listener_is_enabled(const ma_engine* pEngine, ma_uint32 listenerIndex); + +#ifndef MA_NO_RESOURCE_MANAGER +MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePath, ma_node* pNode, ma_uint32 nodeInputBusIndex); +MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup); /* Fire and forget. */ +#endif + +#ifndef MA_NO_RESOURCE_MANAGER +MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound); +MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound); +MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound); +#endif +MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound); +MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound); +MA_API void ma_sound_uninit(ma_sound* pSound); +MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound); +MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound); +MA_API ma_result ma_sound_start(ma_sound* pSound); +MA_API ma_result ma_sound_stop(ma_sound* pSound); +MA_API void ma_sound_set_volume(ma_sound* pSound, float volume); +MA_API float ma_sound_get_volume(const ma_sound* pSound); +MA_API void ma_sound_set_pan(ma_sound* pSound, float pan); +MA_API float ma_sound_get_pan(const ma_sound* pSound); +MA_API void ma_sound_set_pan_mode(ma_sound* pSound, ma_pan_mode panMode); +MA_API ma_pan_mode ma_sound_get_pan_mode(const ma_sound* pSound); +MA_API void ma_sound_set_pitch(ma_sound* pSound, float pitch); +MA_API float ma_sound_get_pitch(const ma_sound* pSound); +MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enabled); +MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound); +MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex); +MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound); +MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound); +MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound); +MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z); +MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound); +MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z); +MA_API ma_vec3f ma_sound_get_direction(const ma_sound* pSound); +MA_API void ma_sound_set_velocity(ma_sound* pSound, float x, float y, float z); +MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound); +MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel); +MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound); +MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning); +MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound); +MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff); +MA_API float ma_sound_get_rolloff(const ma_sound* pSound); +MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain); +MA_API float ma_sound_get_min_gain(const ma_sound* pSound); +MA_API void ma_sound_set_max_gain(ma_sound* pSound, float maxGain); +MA_API float ma_sound_get_max_gain(const ma_sound* pSound); +MA_API void ma_sound_set_min_distance(ma_sound* pSound, float minDistance); +MA_API float ma_sound_get_min_distance(const ma_sound* pSound); +MA_API void ma_sound_set_max_distance(ma_sound* pSound, float maxDistance); +MA_API float ma_sound_get_max_distance(const ma_sound* pSound); +MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float outerAngleInRadians, float outerGain); +MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); +MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor); +MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound); +MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor); +MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound); +MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames); +MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds); +MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound); +MA_API void ma_sound_set_start_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames); +MA_API void ma_sound_set_start_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds); +MA_API void ma_sound_set_stop_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames); +MA_API void ma_sound_set_stop_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds); +MA_API ma_bool32 ma_sound_is_playing(const ma_sound* pSound); +MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound); +MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping); +MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound); +MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound); +MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ +MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); +MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); +MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor); +MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength); + +MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup); +MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup); +MA_API void ma_sound_group_uninit(ma_sound_group* pGroup); +MA_API ma_engine* ma_sound_group_get_engine(const ma_sound_group* pGroup); +MA_API ma_result ma_sound_group_start(ma_sound_group* pGroup); +MA_API ma_result ma_sound_group_stop(ma_sound_group* pGroup); +MA_API void ma_sound_group_set_volume(ma_sound_group* pGroup, float volume); +MA_API float ma_sound_group_get_volume(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_pan(ma_sound_group* pGroup, float pan); +MA_API float ma_sound_group_get_pan(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_pan_mode(ma_sound_group* pGroup, ma_pan_mode panMode); +MA_API ma_pan_mode ma_sound_group_get_pan_mode(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_pitch(ma_sound_group* pGroup, float pitch); +MA_API float ma_sound_group_get_pitch(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma_bool32 enabled); +MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex); +MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup); +MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup); +MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z); +MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z); +MA_API ma_vec3f ma_sound_group_get_direction(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_velocity(ma_sound_group* pGroup, float x, float y, float z); +MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel); +MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning); +MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff); +MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain); +MA_API float ma_sound_group_get_min_gain(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_max_gain(ma_sound_group* pGroup, float maxGain); +MA_API float ma_sound_group_get_max_gain(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_min_distance(ma_sound_group* pGroup, float minDistance); +MA_API float ma_sound_group_get_min_distance(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_max_distance(ma_sound_group* pGroup, float maxDistance); +MA_API float ma_sound_group_get_max_distance(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRadians, float outerAngleInRadians, float outerGain); +MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); +MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor); +MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor); +MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames); +MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds); +MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup); +MA_API void ma_sound_group_set_start_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames); +MA_API void ma_sound_group_set_start_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds); +MA_API void ma_sound_group_set_stop_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames); +MA_API void ma_sound_group_set_stop_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds); +MA_API ma_bool32 ma_sound_group_is_playing(const ma_sound_group* pGroup); +MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGroup); +#endif /* MA_NO_ENGINE */ + #ifdef __cplusplus } #endif #endif /* miniaudio_h */ +/* +This is for preventing greying out of the implementation section. +*/ +#if defined(Q_CREATOR_RUN) || defined(__INTELLISENSE__) || defined(__CDT_PARSER__) +#define MINIAUDIO_IMPLEMENTATION +#endif /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -6552,6 +11051,9 @@ IMPLEMENTATION #include /* For strcasecmp(). */ #include /* For wcslen(), wcsrtombs() */ #endif +#ifdef _MSC_VER + #include /* For _controlfp_s constants */ +#endif #ifdef MA_WIN32 #include @@ -6560,6 +11062,7 @@ IMPLEMENTATION #include /* For memset() */ #include #include /* select() (used for ma_sleep()). */ +#include #endif #include /* For fstat(), etc. */ @@ -6602,15 +11105,10 @@ IMPLEMENTATION #define MA_X64 #elif defined(__i386) || defined(_M_IX86) #define MA_X86 -#elif defined(__arm__) || defined(_M_ARM) +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) #define MA_ARM #endif -/* Cannot currently support AVX-512 if AVX is disabled. */ -#if !defined(MA_NO_AVX512) && defined(MA_NO_AVX2) -#define MA_NO_AVX512 -#endif - /* Intrinsics Support */ #if defined(MA_X64) || defined(MA_X86) #if defined(_MSC_VER) && !defined(__clang__) @@ -6624,9 +11122,6 @@ IMPLEMENTATION #if _MSC_VER >= 1700 && !defined(MA_NO_AVX2) /* 2012 */ #define MA_SUPPORT_AVX2 #endif - #if _MSC_VER >= 1910 && !defined(MA_NO_AVX512) /* 2017 */ - #define MA_SUPPORT_AVX512 - #endif #else /* Assume GNUC-style. */ #if defined(__SSE2__) && !defined(MA_NO_SSE2) @@ -6638,9 +11133,6 @@ IMPLEMENTATION #if defined(__AVX2__) && !defined(MA_NO_AVX2) #define MA_SUPPORT_AVX2 #endif - #if defined(__AVX512F__) && !defined(MA_NO_AVX512) - #define MA_SUPPORT_AVX512 - #endif #endif /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ @@ -6654,14 +11146,9 @@ IMPLEMENTATION #if !defined(MA_SUPPORT_AVX2) && !defined(MA_NO_AVX2) && __has_include() #define MA_SUPPORT_AVX2 #endif - #if !defined(MA_SUPPORT_AVX512) && !defined(MA_NO_AVX512) && __has_include() - #define MA_SUPPORT_AVX512 - #endif #endif - #if defined(MA_SUPPORT_AVX512) - #include /* Not a mistake. Intentionally including instead of because otherwise the compiler will complain. */ - #elif defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX) + #if defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX) #include #elif defined(MA_SUPPORT_SSE2) #include @@ -6671,16 +11158,6 @@ IMPLEMENTATION #if defined(MA_ARM) #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) #define MA_SUPPORT_NEON - #endif - - /* Fall back to looking for the #include file. */ - #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) - #if !defined(MA_SUPPORT_NEON) && !defined(MA_NO_NEON) && __has_include() - #define MA_SUPPORT_NEON - #endif - #endif - - #if defined(MA_SUPPORT_NEON) #include #endif #endif @@ -6689,6 +11166,7 @@ IMPLEMENTATION #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4752) /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */ + #pragma warning(disable:4049) /* compiler limit : terminating line number emission */ #endif #if defined(MA_X64) || defined(MA_X86) @@ -6850,41 +11328,6 @@ static MA_INLINE ma_bool32 ma_has_avx2(void) #endif } -static MA_INLINE ma_bool32 ma_has_avx512f(void) -{ -#if defined(MA_SUPPORT_AVX512) - #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX512) - #if defined(__AVX512F__) - return MA_TRUE; /* If the compiler is allowed to freely generate AVX-512F code we can assume support. */ - #else - /* AVX-512 requires both CPU and OS support. */ - #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV) - return MA_FALSE; - #else - int info1[4]; - int info7[4]; - ma_cpuid(info1, 1); - ma_cpuid(info7, 7); - if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 16)) != 0)) { - ma_uint64 xrc = ma_xgetbv(0); - if ((xrc & 0xE6) == 0xE6) { - return MA_TRUE; - } else { - return MA_FALSE; - } - } else { - return MA_FALSE; - } - #endif - #endif - #else - return MA_FALSE; /* AVX-512F is only supported on x86 and x64 architectures. */ - #endif -#else - return MA_FALSE; /* No compiler support. */ -#endif -} - static MA_INLINE ma_bool32 ma_has_neon(void) { #if defined(MA_SUPPORT_NEON) @@ -6934,7 +11377,7 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #elif defined(_MSC_VER) #define MA_ASSUME(x) __assume(x) #else - #define MA_ASSUME(x) while(0) + #define MA_ASSUME(x) (void)(x) #endif #endif @@ -7033,7 +11476,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) (void)milliseconds; MA_ASSERT(MA_FALSE); /* The Emscripten build should never sleep. */ #else - #if _POSIX_C_SOURCE >= 199309L + #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = milliseconds % 1000 * 1000000; @@ -7048,7 +11491,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) } #endif -static void ma_sleep(ma_uint32 milliseconds) +static MA_INLINE void ma_sleep(ma_uint32 milliseconds) { #ifdef MA_WIN32 ma_sleep__win32(milliseconds); @@ -7077,7 +11520,7 @@ static MA_INLINE void ma_yield() #else __asm__ __volatile__ ("pause"); #endif -#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) +#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) /* ARM */ #if defined(_MSC_VER) /* Apparently there is a __yield() intrinsic that's compatible with ARM, but I cannot find documentation for it nor can I find where it's declared. */ @@ -7091,6 +11534,96 @@ static MA_INLINE void ma_yield() } +#define MA_MM_DENORMALS_ZERO_MASK 0x0040 +#define MA_MM_FLUSH_ZERO_MASK 0x8000 + +static MA_INLINE unsigned int ma_disable_denormals() +{ + unsigned int prevState; + + #if defined(_MSC_VER) + { + /* + Older versions of Visual Studio don't support the "safe" versions of _controlfp_s(). I don't + know which version of Visual Studio first added support for _controlfp_s(), but I do know + that VC6 lacks support. _MSC_VER = 1200 is VC6, but if you get compilation errors on older + versions of Visual Studio, let me know and I'll make the necessary adjustment. + */ + #if _MSC_VER <= 1200 + { + prevState = _statusfp(); + _controlfp(prevState | _DN_FLUSH, _MCW_DN); + } + #else + { + unsigned int unused; + _controlfp_s(&prevState, 0, 0); + _controlfp_s(&unused, prevState | _DN_FLUSH, _MCW_DN); + } + #endif + } + #elif defined(MA_X86) || defined(MA_X64) + { + #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + { + prevState = _mm_getcsr(); + _mm_setcsr(prevState | MA_MM_DENORMALS_ZERO_MASK | MA_MM_FLUSH_ZERO_MASK); + } + #else + { + /* x88/64, but no support for _mm_getcsr()/_mm_setcsr(). May need to fall back to inlined assembly here. */ + prevState = 0; + } + #endif + } + #else + { + /* Unknown or unsupported architecture. No-op. */ + prevState = 0; + } + #endif + + return prevState; +} + +static MA_INLINE void ma_restore_denormals(unsigned int prevState) +{ + #if defined(_MSC_VER) + { + /* Older versions of Visual Studio do not support _controlfp_s(). See ma_disable_denormals(). */ + #if _MSC_VER <= 1200 + { + _controlfp(prevState, _MCW_DN); + } + #else + { + unsigned int unused; + _controlfp_s(&unused, prevState, _MCW_DN); + } + #endif + } + #elif defined(MA_X86) || defined(MA_X64) + { + #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + { + _mm_setcsr(prevState); + } + #else + { + /* x88/64, but no support for _mm_getcsr()/_mm_setcsr(). May need to fall back to inlined assembly here. */ + (void)prevState; + } + #endif + } + #else + { + /* Unknown or unsupported architecture. No-op. */ + (void)prevState; + } + #endif +} + + #ifndef MA_COINIT_VALUE #define MA_COINIT_VALUE 0 /* 0 = COINIT_MULTITHREADED */ @@ -7344,11 +11877,21 @@ static MA_INLINE double ma_sqrtd(double x) } +static MA_INLINE float ma_sinf(float x) +{ + return (float)ma_sind((float)x); +} + static MA_INLINE double ma_cosd(double x) { return ma_sind((MA_PI_D*0.5) - x); } +static MA_INLINE float ma_cosf(float x) +{ + return (float)ma_cosd((float)x); +} + static MA_INLINE double ma_log10d(double x) { return ma_logd(x) * 0.43429448190325182765; @@ -7684,6 +12227,10 @@ MA_API int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* MA_API char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks) { + if (src == NULL) { + return NULL; + } + size_t sz = strlen(src)+1; char* dst = (char*)ma_malloc(sz, pAllocationCallbacks); if (dst == NULL) { @@ -8367,76 +12914,6 @@ static void ma__free_default(void* p, void* pUserData) MA_FREE(p); } - -static void* ma__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks == NULL) { - return NULL; - } - - if (pAllocationCallbacks->onMalloc != NULL) { - return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); - } - - /* Try using realloc(). */ - if (pAllocationCallbacks->onRealloc != NULL) { - return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); - } - - return NULL; -} - -static void* ma__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks == NULL) { - return NULL; - } - - if (pAllocationCallbacks->onRealloc != NULL) { - return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); - } - - /* Try emulating realloc() in terms of malloc()/free(). */ - if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { - void* p2; - - p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); - if (p2 == NULL) { - return NULL; - } - - if (p != NULL) { - MA_COPY_MEMORY(p2, p, szOld); - pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); - } - - return p2; - } - - return NULL; -} - -static MA_INLINE void* ma__calloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) -{ - void* p = ma__malloc_from_callbacks(sz, pAllocationCallbacks); - if (p != NULL) { - MA_ZERO_MEMORY(p, sz); - } - - return p; -} - -static void ma__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (p == NULL || pAllocationCallbacks == NULL) { - return; - } - - if (pAllocationCallbacks->onFree != NULL) { - pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); - } -} - static ma_allocation_callbacks ma_allocation_callbacks_init_default(void) { ma_allocation_callbacks callbacks; @@ -8547,7 +13024,7 @@ MA_API ma_result ma_log_init(const ma_allocation_callbacks* pAllocationCallbacks } } #endif - + /* If we're using debug output, enable it. */ #if defined(MA_DEBUG_OUTPUT) { @@ -8644,15 +13121,6 @@ MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage return MA_INVALID_ARGS; } - /* If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. */ - #if !defined(MA_DEBUG_OUTPUT) - { - if (level == MA_LOG_LEVEL_DEBUG) { - return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */ - } - } - #endif - ma_log_lock(pLog); { ma_uint32 iLog; @@ -8719,18 +13187,6 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat return MA_INVALID_ARGS; } - /* - If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. Do this before generating the - formatted message string so that we don't waste time only to have ma_log_post() reject it. - */ - #if !defined(MA_DEBUG_OUTPUT) - { - if (level == MA_LOG_LEVEL_DEBUG) { - return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */ - } - } - #endif - #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || ((!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) { ma_result result; @@ -8840,18 +13296,6 @@ MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat return MA_INVALID_ARGS; } - /* - If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. Do this before generating the - formatted message string so that we don't waste time only to have ma_log_post() reject it. - */ - #if !defined(MA_DEBUG_OUTPUT) - { - if (level == MA_LOG_LEVEL_DEBUG) { - return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */ - } - } - #endif - va_start(args, pFormat); { result = ma_log_postv(pLog, level, pFormat, args); @@ -8863,8 +13307,32 @@ MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat +static MA_INLINE ma_uint8 ma_clip_u8(ma_int32 x) +{ + return (ma_uint8)(ma_clamp(x, -128, 127) + 128); +} + +static MA_INLINE ma_int16 ma_clip_s16(ma_int32 x) +{ + return (ma_int16)ma_clamp(x, -32768, 32767); +} + +static MA_INLINE ma_int64 ma_clip_s24(ma_int64 x) +{ + return (ma_int64)ma_clamp(x, -8388608, 8388607); +} + +static MA_INLINE ma_int32 ma_clip_s32(ma_int64 x) +{ + /* This dance is to silence warnings with -std=c89. A good compiler should be able to optimize this away. */ + ma_int64 clipMin; + ma_int64 clipMax; + clipMin = -((ma_int64)2147483647 + 1); + clipMax = (ma_int64)2147483647; + + return (ma_int32)ma_clamp(x, clipMin, clipMax); +} -/* Clamps an f32 sample to -1..1 */ static MA_INLINE float ma_clip_f32(float x) { if (x < -1) return -1; @@ -8872,6 +13340,7 @@ static MA_INLINE float ma_clip_f32(float x) return x; } + static MA_INLINE float ma_mix_f32(float x, float y, float a) { return x*(1-a) + y*a; @@ -8896,12 +13365,6 @@ static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x, __m256 y, __m256 a) return _mm256_add_ps(x, _mm256_mul_ps(_mm256_sub_ps(y, x), a)); } #endif -#if defined(MA_SUPPORT_AVX512) -static MA_INLINE __m512 ma_mix_f32_fast__avx512(__m512 x, __m512 y, __m512 a) -{ - return _mm512_add_ps(x, _mm512_mul_ps(_mm512_sub_ps(y, x), a)); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a) { @@ -8944,6 +13407,27 @@ static MA_INLINE ma_uint32 ma_gcf_u32(ma_uint32 a, ma_uint32 b) } +static ma_uint32 ma_ffs_32(ma_uint32 x) +{ + ma_uint32 i; + + /* Just a naive implementation just to get things working for now. Will optimize this later. */ + for (i = 0; i < 32; i += 1) { + if ((x & (1 << i)) != 0) { + return i; + } + } + + return i; +} + +static MA_INLINE ma_int16 ma_float_to_fixed_16(float x) +{ + return (ma_int16)(x * (1 << 8)); +} + + + /* Random Number Generation @@ -9104,7 +13588,7 @@ typedef signed short c89atomic_int16; typedef unsigned short c89atomic_uint16; typedef signed int c89atomic_int32; typedef unsigned int c89atomic_uint32; -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) typedef signed __int64 c89atomic_int64; typedef unsigned __int64 c89atomic_uint64; #else @@ -9153,7 +13637,7 @@ typedef unsigned char c89atomic_bool; #define C89ATOMIC_X64 #elif defined(__i386) || defined(_M_IX86) #define C89ATOMIC_X86 -#elif defined(__arm__) || defined(_M_ARM) +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) #define C89ATOMIC_ARM #endif #if defined(_MSC_VER) @@ -9262,7 +13746,7 @@ typedef unsigned char c89atomic_bool; #define c89atomic_compare_and_swap_32(dst, expected, desired) (c89atomic_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected) #endif #if defined(C89ATOMIC_HAS_64) - #define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile long long*)dst, (long long)desired, (long long)expected) + #define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile c89atomic_int64*)dst, (c89atomic_int64)desired, (c89atomic_int64)expected) #endif #endif #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY) @@ -10449,11 +14933,11 @@ typedef unsigned char c89atomic_bool; { return (void*)c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order); } - static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder); } - static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder); } @@ -10482,7 +14966,7 @@ typedef unsigned char c89atomic_bool; { return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder); } - static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) + static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder); } @@ -10498,8 +14982,8 @@ typedef unsigned char c89atomic_bool; #define c89atomic_store_ptr(dst, src) c89atomic_store_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst) #define c89atomic_load_ptr(ptr) c89atomic_load_explicit_ptr((volatile void**)ptr, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_ptr(dst, src) c89atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst) -#define c89atomic_compare_exchange_strong_ptr(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (volatile void**)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) -#define c89atomic_compare_exchange_weak_ptr(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (volatile void**)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_ptr(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_ptr(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_8( ptr) c89atomic_test_and_set_explicit_8( ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_16(ptr) c89atomic_test_and_set_explicit_16(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_32(ptr) c89atomic_test_and_set_explicit_32(ptr, c89atomic_memory_order_seq_cst) @@ -10672,16 +15156,16 @@ static C89ATOMIC_INLINE void c89atomic_store_explicit_f64(volatile double* dst, x.f = src; c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); } -static C89ATOMIC_INLINE float c89atomic_load_explicit_f32(volatile float* ptr, c89atomic_memory_order order) +static C89ATOMIC_INLINE float c89atomic_load_explicit_f32(volatile const float* ptr, c89atomic_memory_order order) { c89atomic_if32 r; - r.i = c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order); + r.i = c89atomic_load_explicit_32((volatile const c89atomic_uint32*)ptr, order); return r.f; } -static C89ATOMIC_INLINE double c89atomic_load_explicit_f64(volatile double* ptr, c89atomic_memory_order order) +static C89ATOMIC_INLINE double c89atomic_load_explicit_f64(volatile const double* ptr, c89atomic_memory_order order) { c89atomic_if64 r; - r.i = c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order); + r.i = c89atomic_load_explicit_64((volatile const c89atomic_uint64*)ptr, order); return r.f; } static C89ATOMIC_INLINE float c89atomic_exchange_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) @@ -10733,26 +15217,29 @@ static C89ATOMIC_INLINE void c89atomic_spinlock_unlock(volatile c89atomic_spinlo MA_API ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn) { - /* For robustness we're going to use a resampler object to calculate this since that already has a way of calculating this. */ - ma_result result; - ma_uint64 frameCountOut; - ma_resampler_config config; - ma_resampler resampler; + /* This is based on the calculation in ma_linear_resampler_get_expected_output_frame_count(). */ + ma_uint64 outputFrameCount; + ma_uint64 preliminaryInputFrameCountFromFrac; + ma_uint64 preliminaryInputFrameCount; + + if (sampleRateIn == 0 || sampleRateOut == 0 || frameCountIn == 0) { + return 0; + } if (sampleRateOut == sampleRateIn) { return frameCountIn; } - config = ma_resampler_config_init(ma_format_s16, 1, sampleRateIn, sampleRateOut, ma_resample_algorithm_linear); - result = ma_resampler_init(&config, &resampler); - if (result != MA_SUCCESS) { - return 0; + outputFrameCount = (frameCountIn * sampleRateOut) / sampleRateIn; + + preliminaryInputFrameCountFromFrac = (outputFrameCount * (sampleRateIn / sampleRateOut)) / sampleRateOut; + preliminaryInputFrameCount = (outputFrameCount * (sampleRateIn % sampleRateOut)) + preliminaryInputFrameCountFromFrac; + + if (preliminaryInputFrameCount <= frameCountIn) { + outputFrameCount += 1; } - frameCountOut = ma_resampler_get_expected_output_frame_count(&resampler, frameCountIn); - - ma_resampler_uninit(&resampler); - return frameCountOut; + return outputFrameCount; } #ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE @@ -10790,16 +15277,6 @@ static ma_result ma_result_from_GetLastError(DWORD error) Threading *******************************************************************************/ -#ifndef MA_NO_THREADING -#ifdef MA_WIN32 - #define MA_THREADCALL WINAPI - typedef unsigned long ma_thread_result; -#else - #define MA_THREADCALL - typedef void* ma_thread_result; -#endif -typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData); - static MA_INLINE ma_result ma_spinlock_lock_ex(volatile ma_spinlock* pSpinlock, ma_bool32 yield) { if (pSpinlock == NULL) { @@ -10841,6 +15318,17 @@ MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock) return MA_SUCCESS; } + +#ifndef MA_NO_THREADING +#ifdef MA_WIN32 + #define MA_THREADCALL WINAPI + typedef unsigned long ma_thread_result; +#else + #define MA_THREADCALL + typedef void* ma_thread_result; +#endif +typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData); + #ifdef MA_WIN32 static int ma_thread_priority_to_win32(ma_thread_priority priority) { @@ -11048,7 +15536,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority (void)stackSize; #endif - result = pthread_create(pThread, pAttr, entryProc, pData); + result = pthread_create((pthread_t*)pThread, pAttr, entryProc, pData); /* The thread attributes object is no longer required. */ if (pAttr != NULL) { @@ -11064,8 +15552,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority static void ma_thread_wait__posix(ma_thread* pThread) { - pthread_join(*pThread, NULL); - pthread_detach(*pThread); + pthread_join((pthread_t)*pThread, NULL); } @@ -11099,14 +15586,14 @@ static ma_result ma_event_init__posix(ma_event* pEvent) { int result; - result = pthread_mutex_init(&pEvent->lock, NULL); + result = pthread_mutex_init((pthread_mutex_t*)&pEvent->lock, NULL); if (result != 0) { return ma_result_from_errno(result); } - result = pthread_cond_init(&pEvent->cond, NULL); + result = pthread_cond_init((pthread_cond_t*)&pEvent->cond, NULL); if (result != 0) { - pthread_mutex_destroy(&pEvent->lock); + pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock); return ma_result_from_errno(result); } @@ -11116,32 +15603,32 @@ static ma_result ma_event_init__posix(ma_event* pEvent) static void ma_event_uninit__posix(ma_event* pEvent) { - pthread_cond_destroy(&pEvent->cond); - pthread_mutex_destroy(&pEvent->lock); + pthread_cond_destroy((pthread_cond_t*)&pEvent->cond); + pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock); } static ma_result ma_event_wait__posix(ma_event* pEvent) { - pthread_mutex_lock(&pEvent->lock); + pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock); { while (pEvent->value == 0) { - pthread_cond_wait(&pEvent->cond, &pEvent->lock); + pthread_cond_wait((pthread_cond_t*)&pEvent->cond, (pthread_mutex_t*)&pEvent->lock); } pEvent->value = 0; /* Auto-reset. */ } - pthread_mutex_unlock(&pEvent->lock); + pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock); return MA_SUCCESS; } static ma_result ma_event_signal__posix(ma_event* pEvent) { - pthread_mutex_lock(&pEvent->lock); + pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock); { pEvent->value = 1; - pthread_cond_signal(&pEvent->cond); + pthread_cond_signal((pthread_cond_t*)&pEvent->cond); } - pthread_mutex_unlock(&pEvent->lock); + pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock); return MA_SUCCESS; } @@ -11157,14 +15644,14 @@ static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemap pSemaphore->value = initialValue; - result = pthread_mutex_init(&pSemaphore->lock, NULL); + result = pthread_mutex_init((pthread_mutex_t*)&pSemaphore->lock, NULL); if (result != 0) { return ma_result_from_errno(result); /* Failed to create mutex. */ } - result = pthread_cond_init(&pSemaphore->cond, NULL); + result = pthread_cond_init((pthread_cond_t*)&pSemaphore->cond, NULL); if (result != 0) { - pthread_mutex_destroy(&pSemaphore->lock); + pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock); return ma_result_from_errno(result); /* Failed to create condition variable. */ } @@ -11177,8 +15664,8 @@ static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore) return; } - pthread_cond_destroy(&pSemaphore->cond); - pthread_mutex_destroy(&pSemaphore->lock); + pthread_cond_destroy((pthread_cond_t*)&pSemaphore->cond); + pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock); } static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore) @@ -11187,16 +15674,16 @@ static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore) return MA_INVALID_ARGS; } - pthread_mutex_lock(&pSemaphore->lock); + pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock); { /* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */ while (pSemaphore->value == 0) { - pthread_cond_wait(&pSemaphore->cond, &pSemaphore->lock); + pthread_cond_wait((pthread_cond_t*)&pSemaphore->cond, (pthread_mutex_t*)&pSemaphore->lock); } pSemaphore->value -= 1; } - pthread_mutex_unlock(&pSemaphore->lock); + pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock); return MA_SUCCESS; } @@ -11207,12 +15694,12 @@ static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore) return MA_INVALID_ARGS; } - pthread_mutex_lock(&pSemaphore->lock); + pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock); { pSemaphore->value += 1; - pthread_cond_signal(&pSemaphore->cond); + pthread_cond_signal((pthread_cond_t*)&pSemaphore->cond); } - pthread_mutex_unlock(&pSemaphore->lock); + pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock); return MA_SUCCESS; } @@ -11257,7 +15744,7 @@ static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priorit ma_thread_proxy_data* pProxyData; if (pThread == NULL || entryProc == NULL) { - return MA_FALSE; + return MA_INVALID_ARGS; } pProxyData = (ma_thread_proxy_data*)ma_malloc(sizeof(*pProxyData), pAllocationCallbacks); /* Will be freed by the proxy entry proc. */ @@ -11386,14 +15873,14 @@ static ma_result ma_event_alloc_and_init(ma_event** ppEvent, ma_allocation_callb *ppEvent = NULL; - pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/); + pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks); if (pEvent == NULL) { return MA_OUT_OF_MEMORY; } result = ma_event_init(pEvent); if (result != MA_SUCCESS) { - ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/); + ma_free(pEvent, pAllocationCallbacks); return result; } @@ -11424,7 +15911,7 @@ static void ma_event_uninit_and_free(ma_event* pEvent, ma_allocation_callbacks* } ma_event_uninit(pEvent); - ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/); + ma_free(pEvent, pAllocationCallbacks); } #endif @@ -11527,6 +16014,1025 @@ MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore) +#define MA_FENCE_COUNTER_MAX 0x7FFFFFFF + +MA_API ma_result ma_fence_init(ma_fence* pFence) +{ + if (pFence == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pFence); + pFence->counter = 0; + + #ifndef MA_NO_THREADING + { + ma_result result; + + result = ma_event_init(&pFence->e); + if (result != MA_SUCCESS) { + return result; + } + } + #endif + + return MA_SUCCESS; +} + +MA_API void ma_fence_uninit(ma_fence* pFence) +{ + if (pFence == NULL) { + return; + } + + #ifndef MA_NO_THREADING + { + ma_event_uninit(&pFence->e); + } + #endif + + MA_ZERO_OBJECT(pFence); +} + +MA_API ma_result ma_fence_acquire(ma_fence* pFence) +{ + if (pFence == NULL) { + return MA_INVALID_ARGS; + } + + for (;;) { + ma_uint32 oldCounter = c89atomic_load_32(&pFence->counter); + ma_uint32 newCounter = oldCounter + 1; + + /* Make sure we're not about to exceed our maximum value. */ + if (newCounter > MA_FENCE_COUNTER_MAX) { + MA_ASSERT(MA_FALSE); + return MA_OUT_OF_RANGE; + } + + if (c89atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) { + return MA_SUCCESS; + } else { + if (oldCounter == MA_FENCE_COUNTER_MAX) { + MA_ASSERT(MA_FALSE); + return MA_OUT_OF_RANGE; /* The other thread took the last available slot. Abort. */ + } + } + } + + /* Should never get here. */ + /*return MA_SUCCESS;*/ +} + +MA_API ma_result ma_fence_release(ma_fence* pFence) +{ + if (pFence == NULL) { + return MA_INVALID_ARGS; + } + + for (;;) { + ma_uint32 oldCounter = c89atomic_load_32(&pFence->counter); + ma_uint32 newCounter = oldCounter - 1; + + if (oldCounter == 0) { + MA_ASSERT(MA_FALSE); + return MA_INVALID_OPERATION; /* Acquire/release mismatch. */ + } + + if (c89atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) { + #ifndef MA_NO_THREADING + { + if (newCounter == 0) { + ma_event_signal(&pFence->e); /* <-- ma_fence_wait() will be waiting on this. */ + } + } + #endif + + return MA_SUCCESS; + } else { + if (oldCounter == 0) { + MA_ASSERT(MA_FALSE); + return MA_INVALID_OPERATION; /* Another thread has taken the 0 slot. Acquire/release mismatch. */ + } + } + } + + /* Should never get here. */ + /*return MA_SUCCESS;*/ +} + +MA_API ma_result ma_fence_wait(ma_fence* pFence) +{ + if (pFence == NULL) { + return MA_INVALID_ARGS; + } + + for (;;) { + ma_uint32 counter; + + counter = c89atomic_load_32(&pFence->counter); + if (counter == 0) { + /* + Counter has hit zero. By the time we get here some other thread may have acquired the + fence again, but that is where the caller needs to take care with how they se the fence. + */ + return MA_SUCCESS; + } + + /* Getting here means the counter is > 0. We'll need to wait for something to happen. */ + #ifndef MA_NO_THREADING + { + ma_result result; + + result = ma_event_wait(&pFence->e); + if (result != MA_SUCCESS) { + return result; + } + } + #endif + } + + /* Should never get here. */ + /*return MA_INVALID_OPERATION;*/ +} + + +MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification) +{ + ma_async_notification_callbacks* pNotificationCallbacks = (ma_async_notification_callbacks*)pNotification; + + if (pNotification == NULL) { + return MA_INVALID_ARGS; + } + + if (pNotificationCallbacks->onSignal == NULL) { + return MA_NOT_IMPLEMENTED; + } + + pNotificationCallbacks->onSignal(pNotification); + return MA_INVALID_ARGS; +} + + +static void ma_async_notification_poll__on_signal(ma_async_notification* pNotification) +{ + ((ma_async_notification_poll*)pNotification)->signalled = MA_TRUE; +} + +MA_API ma_result ma_async_notification_poll_init(ma_async_notification_poll* pNotificationPoll) +{ + if (pNotificationPoll == NULL) { + return MA_INVALID_ARGS; + } + + pNotificationPoll->cb.onSignal = ma_async_notification_poll__on_signal; + pNotificationPoll->signalled = MA_FALSE; + + return MA_SUCCESS; +} + +MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll* pNotificationPoll) +{ + if (pNotificationPoll == NULL) { + return MA_FALSE; + } + + return pNotificationPoll->signalled; +} + + +static void ma_async_notification_event__on_signal(ma_async_notification* pNotification) +{ + ma_async_notification_event_signal((ma_async_notification_event*)pNotification); +} + +MA_API ma_result ma_async_notification_event_init(ma_async_notification_event* pNotificationEvent) +{ + if (pNotificationEvent == NULL) { + return MA_INVALID_ARGS; + } + + pNotificationEvent->cb.onSignal = ma_async_notification_event__on_signal; + + #ifndef MA_NO_THREADING + { + ma_result result; + + result = ma_event_init(&pNotificationEvent->e); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; + } + #else + { + return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ + } + #endif +} + +MA_API ma_result ma_async_notification_event_uninit(ma_async_notification_event* pNotificationEvent) +{ + if (pNotificationEvent == NULL) { + return MA_INVALID_ARGS; + } + + #ifndef MA_NO_THREADING + { + ma_event_uninit(&pNotificationEvent->e); + return MA_SUCCESS; + } + #else + { + return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ + } + #endif +} + +MA_API ma_result ma_async_notification_event_wait(ma_async_notification_event* pNotificationEvent) +{ + if (pNotificationEvent == NULL) { + return MA_INVALID_ARGS; + } + + #ifndef MA_NO_THREADING + { + return ma_event_wait(&pNotificationEvent->e); + } + #else + { + return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ + } + #endif +} + +MA_API ma_result ma_async_notification_event_signal(ma_async_notification_event* pNotificationEvent) +{ + if (pNotificationEvent == NULL) { + return MA_INVALID_ARGS; + } + + #ifndef MA_NO_THREADING + { + return ma_event_signal(&pNotificationEvent->e); + } + #else + { + return MA_NOT_IMPLEMENTED; /* Threading is disabled. */ + } + #endif +} + + + +/************************************************************************************************************************************************************ + +Job Queue + +************************************************************************************************************************************************************/ +MA_API ma_slot_allocator_config ma_slot_allocator_config_init(ma_uint32 capacity) +{ + ma_slot_allocator_config config; + + MA_ZERO_OBJECT(&config); + config.capacity = capacity; + + return config; +} + + +static MA_INLINE ma_uint32 ma_slot_allocator_calculate_group_capacity(ma_uint32 slotCapacity) +{ + ma_uint32 cap = slotCapacity / 32; + if ((slotCapacity % 32) != 0) { + cap += 1; + } + + return cap; +} + +static MA_INLINE ma_uint32 ma_slot_allocator_group_capacity(const ma_slot_allocator* pAllocator) +{ + return ma_slot_allocator_calculate_group_capacity(pAllocator->capacity); +} + + +typedef struct +{ + size_t sizeInBytes; + size_t groupsOffset; + size_t slotsOffset; +} ma_slot_allocator_heap_layout; + +static ma_result ma_slot_allocator_get_heap_layout(const ma_slot_allocator_config* pConfig, ma_slot_allocator_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->capacity == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* Groups. */ + pHeapLayout->groupsOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(ma_slot_allocator_calculate_group_capacity(pConfig->capacity) * sizeof(ma_slot_allocator_group)); + + /* Slots. */ + pHeapLayout->slotsOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(pConfig->capacity * sizeof(ma_uint32)); + + return MA_SUCCESS; +} + +MA_API ma_result ma_slot_allocator_get_heap_size(const ma_slot_allocator_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_slot_allocator_heap_layout layout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_slot_allocator_get_heap_layout(pConfig, &layout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = layout.sizeInBytes; + + return result; +} + +MA_API ma_result ma_slot_allocator_init_preallocated(const ma_slot_allocator_config* pConfig, void* pHeap, ma_slot_allocator* pAllocator) +{ + ma_result result; + ma_slot_allocator_heap_layout heapLayout; + + if (pAllocator == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pAllocator); + + if (pHeap == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_slot_allocator_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pAllocator->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pAllocator->pGroups = (ma_slot_allocator_group*)ma_offset_ptr(pHeap, heapLayout.groupsOffset); + pAllocator->pSlots = (ma_uint32*)ma_offset_ptr(pHeap, heapLayout.slotsOffset); + pAllocator->capacity = pConfig->capacity; + + return MA_SUCCESS; +} + +MA_API ma_result ma_slot_allocator_init(const ma_slot_allocator_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_slot_allocator* pAllocator) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_slot_allocator_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the size of the heap allocation. */ + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_slot_allocator_init_preallocated(pConfig, pHeap, pAllocator); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pAllocator->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_slot_allocator_uninit(ma_slot_allocator* pAllocator, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocator == NULL) { + return; + } + + if (pAllocator->_ownsHeap) { + ma_free(pAllocator->_pHeap, pAllocationCallbacks); + } +} + +MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint64* pSlot) +{ + ma_uint32 iAttempt; + const ma_uint32 maxAttempts = 2; /* The number of iterations to perform until returning MA_OUT_OF_MEMORY if no slots can be found. */ + + if (pAllocator == NULL || pSlot == NULL) { + return MA_INVALID_ARGS; + } + + for (iAttempt = 0; iAttempt < maxAttempts; iAttempt += 1) { + /* We need to acquire a suitable bitfield first. This is a bitfield that's got an available slot within it. */ + ma_uint32 iGroup; + for (iGroup = 0; iGroup < ma_slot_allocator_group_capacity(pAllocator); iGroup += 1) { + /* CAS */ + for (;;) { + ma_uint32 oldBitfield; + ma_uint32 newBitfield; + ma_uint32 bitOffset; + + oldBitfield = c89atomic_load_32(&pAllocator->pGroups[iGroup].bitfield); /* <-- This copy must happen. The compiler must not optimize this away. */ + + /* Fast check to see if anything is available. */ + if (oldBitfield == 0xFFFFFFFF) { + break; /* No available bits in this bitfield. */ + } + + bitOffset = ma_ffs_32(~oldBitfield); + MA_ASSERT(bitOffset < 32); + + newBitfield = oldBitfield | (1 << bitOffset); + + if (c89atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield, oldBitfield, newBitfield) == oldBitfield) { + ma_uint32 slotIndex; + + /* Increment the counter as soon as possible to have other threads report out-of-memory sooner than later. */ + c89atomic_fetch_add_32(&pAllocator->count, 1); + + /* The slot index is required for constructing the output value. */ + slotIndex = (iGroup << 5) + bitOffset; /* iGroup << 5 = iGroup * 32 */ + if (slotIndex >= pAllocator->capacity) { + return MA_OUT_OF_MEMORY; + } + + /* Increment the reference count before constructing the output value. */ + pAllocator->pSlots[slotIndex] += 1; + + /* Construct the output value. */ + *pSlot = (((ma_uint64)pAllocator->pSlots[slotIndex] << 32) | slotIndex); + + return MA_SUCCESS; + } + } + } + + /* We weren't able to find a slot. If it's because we've reached our capacity we need to return MA_OUT_OF_MEMORY. Otherwise we need to do another iteration and try again. */ + if (pAllocator->count < pAllocator->capacity) { + ma_yield(); + } else { + return MA_OUT_OF_MEMORY; + } + } + + /* We couldn't find a slot within the maximum number of attempts. */ + return MA_OUT_OF_MEMORY; +} + +MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot) +{ + ma_uint32 iGroup; + ma_uint32 iBit; + + if (pAllocator == NULL) { + return MA_INVALID_ARGS; + } + + iGroup = (ma_uint32)((slot & 0xFFFFFFFF) >> 5); /* slot / 32 */ + iBit = (ma_uint32)((slot & 0xFFFFFFFF) & 31); /* slot % 32 */ + + if (iGroup >= ma_slot_allocator_group_capacity(pAllocator)) { + return MA_INVALID_ARGS; + } + + MA_ASSERT(iBit < 32); /* This must be true due to the logic we used to actually calculate it. */ + + while (c89atomic_load_32(&pAllocator->count) > 0) { + /* CAS */ + ma_uint32 oldBitfield; + ma_uint32 newBitfield; + + oldBitfield = c89atomic_load_32(&pAllocator->pGroups[iGroup].bitfield); /* <-- This copy must happen. The compiler must not optimize this away. */ + newBitfield = oldBitfield & ~(1 << iBit); + + /* Debugging for checking for double-frees. */ + #if defined(MA_DEBUG_OUTPUT) + { + if ((oldBitfield & (1 << iBit)) == 0) { + MA_ASSERT(MA_FALSE); /* Double free detected.*/ + } + } + #endif + + if (c89atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield, oldBitfield, newBitfield) == oldBitfield) { + c89atomic_fetch_sub_32(&pAllocator->count, 1); + return MA_SUCCESS; + } + } + + /* Getting here means there are no allocations available for freeing. */ + return MA_INVALID_OPERATION; +} + + +#define MA_JOB_ID_NONE ~((ma_uint64)0) +#define MA_JOB_SLOT_NONE (ma_uint16)(~0) + +static MA_INLINE ma_uint32 ma_job_extract_refcount(ma_uint64 toc) +{ + return (ma_uint32)(toc >> 32); +} + +static MA_INLINE ma_uint16 ma_job_extract_slot(ma_uint64 toc) +{ + return (ma_uint16)(toc & 0x0000FFFF); +} + +static MA_INLINE ma_uint16 ma_job_extract_code(ma_uint64 toc) +{ + return (ma_uint16)((toc & 0xFFFF0000) >> 16); +} + +static MA_INLINE ma_uint64 ma_job_toc_to_allocation(ma_uint64 toc) +{ + return ((ma_uint64)ma_job_extract_refcount(toc) << 32) | (ma_uint64)ma_job_extract_slot(toc); +} + +static MA_INLINE ma_uint64 ma_job_set_refcount(ma_uint64 toc, ma_uint32 refcount) +{ + /* Clear the reference count first. */ + toc = toc & ~((ma_uint64)0xFFFFFFFF << 32); + toc = toc | ((ma_uint64)refcount << 32); + + return toc; +} + + +MA_API ma_job ma_job_init(ma_uint16 code) +{ + ma_job job; + + MA_ZERO_OBJECT(&job); + job.toc.breakup.code = code; + job.toc.breakup.slot = MA_JOB_SLOT_NONE; /* Temp value. Will be allocated when posted to a queue. */ + job.next = MA_JOB_ID_NONE; + + return job; +} + + +static ma_result ma_job_process__noop(ma_job* pJob); +static ma_result ma_job_process__quit(ma_job* pJob); +static ma_result ma_job_process__custom(ma_job* pJob); +static ma_result ma_job_process__resource_manager__load_data_buffer_node(ma_job* pJob); +static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* pJob); +static ma_result ma_job_process__resource_manager__page_data_buffer_node(ma_job* pJob); +static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob); +static ma_result ma_job_process__resource_manager__free_data_buffer(ma_job* pJob); +static ma_result ma_job_process__resource_manager__load_data_stream(ma_job* pJob); +static ma_result ma_job_process__resource_manager__free_data_stream(ma_job* pJob); +static ma_result ma_job_process__resource_manager__page_data_stream(ma_job* pJob); +static ma_result ma_job_process__resource_manager__seek_data_stream(ma_job* pJob); + +#if !defined(MA_NO_DEVICE_IO) +static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob); +#endif + +static ma_job_proc g_jobVTable[MA_JOB_TYPE_COUNT] = +{ + /* Miscellaneous. */ + ma_job_process__quit, /* MA_JOB_TYPE_QUIT */ + ma_job_process__custom, /* MA_JOB_TYPE_CUSTOM */ + + /* Resource Manager. */ + ma_job_process__resource_manager__load_data_buffer_node, /* MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE */ + ma_job_process__resource_manager__free_data_buffer_node, /* MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE */ + ma_job_process__resource_manager__page_data_buffer_node, /* MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE */ + ma_job_process__resource_manager__load_data_buffer, /* MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER */ + ma_job_process__resource_manager__free_data_buffer, /* MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER */ + ma_job_process__resource_manager__load_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM */ + ma_job_process__resource_manager__free_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM */ + ma_job_process__resource_manager__page_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM */ + ma_job_process__resource_manager__seek_data_stream, /* MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM */ + + /* Device. */ +#if !defined(MA_NO_DEVICE_IO) + ma_job_process__device__aaudio_reroute /*MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE*/ +#endif +}; + +MA_API ma_result ma_job_process(ma_job* pJob) +{ + if (pJob == NULL) { + return MA_INVALID_ARGS; + } + + if (pJob->toc.breakup.code > MA_JOB_TYPE_COUNT) { + return MA_INVALID_OPERATION; + } + + return g_jobVTable[pJob->toc.breakup.code](pJob); +} + +static ma_result ma_job_process__noop(ma_job* pJob) +{ + MA_ASSERT(pJob != NULL); + + /* No-op. */ + (void)pJob; + + return MA_SUCCESS; +} + +static ma_result ma_job_process__quit(ma_job* pJob) +{ + return ma_job_process__noop(pJob); +} + +static ma_result ma_job_process__custom(ma_job* pJob) +{ + MA_ASSERT(pJob != NULL); + + /* No-op if there's no callback. */ + if (pJob->data.custom.proc == NULL) { + return MA_SUCCESS; + } + + return pJob->data.custom.proc(pJob); +} + + + +MA_API ma_job_queue_config ma_job_queue_config_init(ma_uint32 flags, ma_uint32 capacity) +{ + ma_job_queue_config config; + + config.flags = flags; + config.capacity = capacity; + + return config; +} + + +typedef struct +{ + size_t sizeInBytes; + size_t allocatorOffset; + size_t jobsOffset; +} ma_job_queue_heap_layout; + +static ma_result ma_job_queue_get_heap_layout(const ma_job_queue_config* pConfig, ma_job_queue_heap_layout* pHeapLayout) +{ + ma_result result; + + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->capacity == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* Allocator. */ + { + ma_slot_allocator_config allocatorConfig; + size_t allocatorHeapSizeInBytes; + + allocatorConfig = ma_slot_allocator_config_init(pConfig->capacity); + result = ma_slot_allocator_get_heap_size(&allocatorConfig, &allocatorHeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->allocatorOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += allocatorHeapSizeInBytes; + } + + /* Jobs. */ + pHeapLayout->jobsOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(pConfig->capacity * sizeof(ma_job)); + + return MA_SUCCESS; +} + +MA_API ma_result ma_job_queue_get_heap_size(const ma_job_queue_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_job_queue_heap_layout layout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_job_queue_get_heap_layout(pConfig, &layout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = layout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_job_queue_init_preallocated(const ma_job_queue_config* pConfig, void* pHeap, ma_job_queue* pQueue) +{ + ma_result result; + ma_job_queue_heap_layout heapLayout; + ma_slot_allocator_config allocatorConfig; + + if (pQueue == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pQueue); + + result = ma_job_queue_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pQueue->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pQueue->flags = pConfig->flags; + pQueue->capacity = pConfig->capacity; + pQueue->pJobs = (ma_job*)ma_offset_ptr(pHeap, heapLayout.jobsOffset); + + allocatorConfig = ma_slot_allocator_config_init(pConfig->capacity); + result = ma_slot_allocator_init_preallocated(&allocatorConfig, ma_offset_ptr(pHeap, heapLayout.allocatorOffset), &pQueue->allocator); + if (result != MA_SUCCESS) { + return result; + } + + /* We need a semaphore if we're running in non-blocking mode. If threading is disabled we need to return an error. */ + if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { + #ifndef MA_NO_THREADING + { + ma_semaphore_init(0, &pQueue->sem); + } + #else + { + /* Threading is disabled and we've requested non-blocking mode. */ + return MA_INVALID_OPERATION; + } + #endif + } + + /* + Our queue needs to be initialized with a free standing node. This should always be slot 0. Required for the lock free algorithm. The first job in the queue is + just a dummy item for giving us the first item in the list which is stored in the "next" member. + */ + ma_slot_allocator_alloc(&pQueue->allocator, &pQueue->head); /* Will never fail. */ + pQueue->pJobs[ma_job_extract_slot(pQueue->head)].next = MA_JOB_ID_NONE; + pQueue->tail = pQueue->head; + + return MA_SUCCESS; +} + +MA_API ma_result ma_job_queue_init(const ma_job_queue_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_job_queue* pQueue) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_job_queue_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_job_queue_init_preallocated(pConfig, pHeap, pQueue); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pQueue->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_job_queue_uninit(ma_job_queue* pQueue, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pQueue == NULL) { + return; + } + + /* All we need to do is uninitialize the semaphore. */ + if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { + #ifndef MA_NO_THREADING + { + ma_semaphore_uninit(&pQueue->sem); + } + #else + { + MA_ASSERT(MA_FALSE); /* Should never get here. Should have been checked at initialization time. */ + } + #endif + } + + ma_slot_allocator_uninit(&pQueue->allocator, pAllocationCallbacks); + + if (pQueue->_ownsHeap) { + ma_free(pQueue->_pHeap, pAllocationCallbacks); + } +} + +static ma_bool32 ma_job_queue_cas(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) +{ + /* The new counter is taken from the expected value. */ + return c89atomic_compare_and_swap_64(dst, expected, ma_job_set_refcount(desired, ma_job_extract_refcount(expected) + 1)) == expected; +} + +MA_API ma_result ma_job_queue_post(ma_job_queue* pQueue, const ma_job* pJob) +{ + /* + Lock free queue implementation based on the paper by Michael and Scott: Nonblocking Algorithms and Preemption-Safe Locking on Multiprogrammed Shared Memory Multiprocessors + */ + ma_result result; + ma_uint64 slot; + ma_uint64 tail; + ma_uint64 next; + + if (pQueue == NULL || pJob == NULL) { + return MA_INVALID_ARGS; + } + + /* We need a new slot. */ + result = ma_slot_allocator_alloc(&pQueue->allocator, &slot); + if (result != MA_SUCCESS) { + return result; /* Probably ran out of slots. If so, MA_OUT_OF_MEMORY will be returned. */ + } + + /* At this point we should have a slot to place the job. */ + MA_ASSERT(ma_job_extract_slot(slot) < pQueue->capacity); + + /* We need to put the job into memory before we do anything. */ + pQueue->pJobs[ma_job_extract_slot(slot)] = *pJob; + pQueue->pJobs[ma_job_extract_slot(slot)].toc.allocation = slot; /* This will overwrite the job code. */ + pQueue->pJobs[ma_job_extract_slot(slot)].toc.breakup.code = pJob->toc.breakup.code; /* The job code needs to be applied again because the line above overwrote it. */ + pQueue->pJobs[ma_job_extract_slot(slot)].next = MA_JOB_ID_NONE; /* Reset for safety. */ + + #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE + ma_spinlock_lock(&pQueue->lock); + #endif + { + /* The job is stored in memory so now we need to add it to our linked list. We only ever add items to the end of the list. */ + for (;;) { + tail = c89atomic_load_64(&pQueue->tail); + next = c89atomic_load_64(&pQueue->pJobs[ma_job_extract_slot(tail)].next); + + if (ma_job_toc_to_allocation(tail) == ma_job_toc_to_allocation(c89atomic_load_64(&pQueue->tail))) { + if (ma_job_extract_slot(next) == 0xFFFF) { + if (ma_job_queue_cas(&pQueue->pJobs[ma_job_extract_slot(tail)].next, next, slot)) { + break; + } + } else { + ma_job_queue_cas(&pQueue->tail, tail, ma_job_extract_slot(next)); + } + } + } + ma_job_queue_cas(&pQueue->tail, tail, slot); + } + #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE + ma_spinlock_unlock(&pQueue->lock); + #endif + + + /* Signal the semaphore as the last step if we're using synchronous mode. */ + if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { + #ifndef MA_NO_THREADING + { + ma_semaphore_release(&pQueue->sem); + } + #else + { + MA_ASSERT(MA_FALSE); /* Should never get here. Should have been checked at initialization time. */ + } + #endif + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob) +{ + ma_uint64 head; + ma_uint64 tail; + ma_uint64 next; + + if (pQueue == NULL || pJob == NULL) { + return MA_INVALID_ARGS; + } + + /* If we're running in synchronous mode we'll need to wait on a semaphore. */ + if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) { + #ifndef MA_NO_THREADING + { + ma_semaphore_wait(&pQueue->sem); + } + #else + { + MA_ASSERT(MA_FALSE); /* Should never get here. Should have been checked at initialization time. */ + } + #endif + } + + #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE + ma_spinlock_lock(&pQueue->lock); + #endif + { + /* + BUG: In lock-free mode, multiple threads can be in this section of code. The "head" variable in the loop below + is stored. One thread can fall through to the freeing of this item while another is still using "head" for the + retrieval of the "next" variable. + + The slot allocator might need to make use of some reference counting to ensure it's only truely freed when + there are no more references to the item. This must be fixed before removing these locks. + */ + + /* Now we need to remove the root item from the list. */ + for (;;) { + head = c89atomic_load_64(&pQueue->head); + tail = c89atomic_load_64(&pQueue->tail); + next = c89atomic_load_64(&pQueue->pJobs[ma_job_extract_slot(head)].next); + + if (ma_job_toc_to_allocation(head) == ma_job_toc_to_allocation(c89atomic_load_64(&pQueue->head))) { + if (ma_job_extract_slot(head) == ma_job_extract_slot(tail)) { + if (ma_job_extract_slot(next) == 0xFFFF) { + #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE + ma_spinlock_unlock(&pQueue->lock); + #endif + return MA_NO_DATA_AVAILABLE; + } + ma_job_queue_cas(&pQueue->tail, tail, ma_job_extract_slot(next)); + } else { + *pJob = pQueue->pJobs[ma_job_extract_slot(next)]; + if (ma_job_queue_cas(&pQueue->head, head, ma_job_extract_slot(next))) { + break; + } + } + } + } + } + #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE + ma_spinlock_unlock(&pQueue->lock); + #endif + + ma_slot_allocator_free(&pQueue->allocator, head); + + /* + If it's a quit job make sure it's put back on the queue to ensure other threads have an opportunity to detect it and terminate naturally. We + could instead just leave it on the queue, but that would involve fiddling with the lock-free code above and I want to keep that as simple as + possible. + */ + if (pJob->toc.breakup.code == MA_JOB_TYPE_QUIT) { + ma_job_queue_post(pQueue, pJob); + return MA_CANCELLED; /* Return a cancelled status just in case the thread is checking return codes and not properly checking for a quit job. */ + } + + return MA_SUCCESS; +} + + + + /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* @@ -11940,58 +17446,19 @@ typedef int (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLE typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(void); typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(void); +#if defined(MA_WIN32_DESKTOP) /* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */ typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); -#endif +#endif /* MA_WIN32_DESKTOP */ +#endif /* MA_WIN32 */ #define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device" #define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device" -/* Posts a log message. */ -static void ma_post_log_message(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) -{ - if (pContext == NULL) { - if (pDevice != NULL) { - pContext = pDevice->pContext; - } - } - - if (pContext == NULL) { - return; - } - - ma_log_post(ma_context_get_log(pContext), logLevel, message); /* <-- This will deal with MA_DEBUG_OUTPUT. */ - - /* Legacy. */ -#if defined(MA_LOG_LEVEL) - if (logLevel <= MA_LOG_LEVEL) { - ma_log_proc onLog; - - onLog = pContext->logCallback; - if (onLog) { - onLog(pContext, pDevice, logLevel, message); - } - } -#endif -} - -/* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */ -static ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) -{ - ma_post_log_message(pContext, pDevice, logLevel, message); - return resultCode; -} - -static ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) -{ - return ma_context_post_error(ma_device_get_context(pDevice), pDevice, logLevel, message, resultCode); -} - - /******************************************************************************* @@ -12001,7 +17468,7 @@ Timing *******************************************************************************/ #ifdef MA_WIN32 static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's static. */ - static void ma_timer_init(ma_timer* pTimer) + void ma_timer_init(ma_timer* pTimer) { LARGE_INTEGER counter; @@ -12013,7 +17480,7 @@ Timing pTimer->counter = counter.QuadPart; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + double ma_timer_get_time_in_seconds(ma_timer* pTimer) { LARGE_INTEGER counter; if (!QueryPerformanceCounter(&counter)) { @@ -12051,7 +17518,7 @@ Timing return (emscripten_get_now() - pTimer->counterD) / 1000; /* Emscripten is in milliseconds. */ } #else - #if _POSIX_C_SOURCE >= 199309L + #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L #if defined(CLOCK_MONOTONIC) #define MA_CLOCK_ID CLOCK_MONOTONIC #else @@ -12215,51 +17682,234 @@ static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn) #endif +static MA_INLINE unsigned int ma_device_disable_denormals(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (!pDevice->noDisableDenormals) { + return ma_disable_denormals(); + } else { + return 0; + } +} + +static MA_INLINE void ma_device_restore_denormals(ma_device* pDevice, unsigned int prevState) +{ + MA_ASSERT(pDevice != NULL); + + if (!pDevice->noDisableDenormals) { + ma_restore_denormals(prevState); + } else { + /* Do nothing. */ + (void)prevState; + } +} + +static ma_device_notification ma_device_notification_init(ma_device* pDevice, ma_device_notification_type type) +{ + ma_device_notification notification; + + MA_ZERO_OBJECT(¬ification); + notification.pDevice = pDevice; + notification.type = type; + + return notification; +} + +static void ma_device__on_notification(ma_device_notification notification) +{ + MA_ASSERT(notification.pDevice != NULL); + + if (notification.pDevice->onNotification != NULL) { + notification.pDevice->onNotification(¬ification); + } + + /* TEMP FOR COMPATIBILITY: If it's a stopped notification, fire the onStop callback as well. This is only for backwards compatibility and will be removed. */ + if (notification.pDevice->onStop != NULL && notification.type == ma_device_notification_type_stopped) { + notification.pDevice->onStop(notification.pDevice); + } +} + +void ma_device__on_notification_started(ma_device* pDevice) +{ + ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_started)); +} + +void ma_device__on_notification_stopped(ma_device* pDevice) +{ + ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_stopped)); +} + +void ma_device__on_notification_rerouted(ma_device* pDevice) +{ + ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_rerouted)); +} + +void ma_device__on_notification_interruption_began(ma_device* pDevice) +{ + ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_began)); +} + +void ma_device__on_notification_interruption_ended(ma_device* pDevice) +{ + ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_ended)); +} + + +static void ma_device__on_data_inner(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) +{ + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pDevice->onData != NULL); + + if (!pDevice->noPreSilencedOutputBuffer && pFramesOut != NULL) { + ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); + } + + pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount); +} + static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->noFixedSizedCallback) { + /* Fast path. Not using a fixed sized callback. Process directly from the specified buffers. */ + ma_device__on_data_inner(pDevice, pFramesOut, pFramesIn, frameCount); + } else { + /* Slow path. Using a fixed sized callback. Need to use the intermediary buffer. */ + ma_uint32 totalFramesProcessed = 0; + + while (totalFramesProcessed < frameCount) { + ma_uint32 totalFramesRemaining = frameCount - totalFramesProcessed; + ma_uint32 framesToProcessThisIteration = 0; + + if (pFramesIn != NULL) { + /* Capturing. Write to the intermediary buffer. If there's no room, fire the callback to empty it. */ + if (pDevice->capture.intermediaryBufferLen < pDevice->capture.intermediaryBufferCap) { + /* There's some room left in the intermediary buffer. Write to it without firing the callback. */ + framesToProcessThisIteration = totalFramesRemaining; + if (framesToProcessThisIteration > pDevice->capture.intermediaryBufferCap - pDevice->capture.intermediaryBufferLen) { + framesToProcessThisIteration = pDevice->capture.intermediaryBufferCap - pDevice->capture.intermediaryBufferLen; + } + + ma_copy_pcm_frames( + ma_offset_pcm_frames_ptr(pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferLen, pDevice->capture.format, pDevice->capture.channels), + ma_offset_pcm_frames_const_ptr(pFramesIn, totalFramesProcessed, pDevice->capture.format, pDevice->capture.channels), + framesToProcessThisIteration, + pDevice->capture.format, pDevice->capture.channels); + + pDevice->capture.intermediaryBufferLen += framesToProcessThisIteration; + } + + if (pDevice->capture.intermediaryBufferLen == pDevice->capture.intermediaryBufferCap) { + /* No room left in the intermediary buffer. Fire the data callback. */ + if (pDevice->type == ma_device_type_duplex) { + /* We'll do the duplex data callback later after we've processed the playback data. */ + } else { + ma_device__on_data_inner(pDevice, NULL, pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap); + + /* The intermediary buffer has just been drained. */ + pDevice->capture.intermediaryBufferLen = 0; + } + } + } + + if (pFramesOut != NULL) { + /* Playing back. Read from the intermediary buffer. If there's nothing in it, fire the callback to fill it. */ + if (pDevice->playback.intermediaryBufferLen > 0) { + /* There's some content in the intermediary buffer. Read from that without firing the callback. */ + if (pDevice->type == ma_device_type_duplex) { + /* The frames processed this iteration for a duplex device will always be based on the capture side. Leave it unmodified. */ + } else { + framesToProcessThisIteration = totalFramesRemaining; + if (framesToProcessThisIteration > pDevice->playback.intermediaryBufferLen) { + framesToProcessThisIteration = pDevice->playback.intermediaryBufferLen; + } + } + + ma_copy_pcm_frames( + ma_offset_pcm_frames_ptr(pFramesOut, totalFramesProcessed, pDevice->playback.format, pDevice->playback.channels), + ma_offset_pcm_frames_ptr(pDevice->playback.pIntermediaryBuffer, pDevice->playback.intermediaryBufferCap - pDevice->playback.intermediaryBufferLen, pDevice->playback.format, pDevice->playback.channels), + framesToProcessThisIteration, + pDevice->playback.format, pDevice->playback.channels); + + pDevice->playback.intermediaryBufferLen -= framesToProcessThisIteration; + } + + if (pDevice->playback.intermediaryBufferLen == 0) { + /* There's nothing in the intermediary buffer. Fire the data callback to fill it. */ + if (pDevice->type == ma_device_type_duplex) { + /* In duplex mode, the data callback will be fired later. Nothing to do here. */ + } else { + ma_device__on_data_inner(pDevice, pDevice->playback.pIntermediaryBuffer, NULL, pDevice->playback.intermediaryBufferCap); + + /* The intermediary buffer has just been filled. */ + pDevice->playback.intermediaryBufferLen = pDevice->playback.intermediaryBufferCap; + } + } + } + + /* If we're in duplex mode we might need to do a refill of the data. */ + if (pDevice->type == ma_device_type_duplex) { + if (pDevice->capture.intermediaryBufferLen == pDevice->capture.intermediaryBufferCap) { + ma_device__on_data_inner(pDevice, pDevice->playback.pIntermediaryBuffer, pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap); + + pDevice->playback.intermediaryBufferLen = pDevice->playback.intermediaryBufferCap; /* The playback buffer will have just been filled. */ + pDevice->capture.intermediaryBufferLen = 0; /* The intermediary buffer has just been drained. */ + } + } + + /* Make sure this is only incremented once in the duplex case. */ + totalFramesProcessed += framesToProcessThisIteration; + } + } +} + +static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) { float masterVolumeFactor; ma_device_get_master_volume(pDevice, &masterVolumeFactor); /* Use ma_device_get_master_volume() to ensure the volume is loaded atomically. */ if (pDevice->onData) { - if (!pDevice->noPreZeroedOutputBuffer && pFramesOut != NULL) { - ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); - } + unsigned int prevDenormalState = ma_device_disable_denormals(pDevice); + { + /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */ + if (pFramesIn != NULL && masterVolumeFactor < 1) { + ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + ma_uint32 totalFramesProcessed = 0; + while (totalFramesProcessed < frameCount) { + ma_uint32 framesToProcessThisIteration = frameCount - totalFramesProcessed; + if (framesToProcessThisIteration > sizeof(tempFramesIn)/bpfCapture) { + framesToProcessThisIteration = sizeof(tempFramesIn)/bpfCapture; + } - /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */ - if (pFramesIn != NULL && masterVolumeFactor < 1) { - ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - ma_uint32 totalFramesProcessed = 0; - while (totalFramesProcessed < frameCount) { - ma_uint32 framesToProcessThisIteration = frameCount - totalFramesProcessed; - if (framesToProcessThisIteration > sizeof(tempFramesIn)/bpfCapture) { - framesToProcessThisIteration = sizeof(tempFramesIn)/bpfCapture; + ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor); + + ma_device__on_data(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration); + + totalFramesProcessed += framesToProcessThisIteration; + } + } else { + ma_device__on_data(pDevice, pFramesOut, pFramesIn, frameCount); + } + + /* Volume control and clipping for playback devices. */ + if (pFramesOut != NULL) { + if (masterVolumeFactor < 1) { + if (pFramesIn == NULL) { /* <-- In full-duplex situations, the volume will have been applied to the input samples before the data callback. Applying it again post-callback will incorrectly compound it. */ + ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor); + } } - ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor); - - pDevice->onData(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration); - - totalFramesProcessed += framesToProcessThisIteration; - } - } else { - pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount); - } - - /* Volume control and clipping for playback devices. */ - if (pFramesOut != NULL) { - if (masterVolumeFactor < 1) { - if (pFramesIn == NULL) { /* <-- In full-duplex situations, the volume will have been applied to the input samples before the data callback. Applying it again post-callback will incorrectly compound it. */ - ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor); + if (!pDevice->noClip && pDevice->playback.format == ma_format_f32) { + ma_clip_samples_f32((float*)pFramesOut, (const float*)pFramesOut, frameCount * pDevice->playback.channels); /* Intentionally specifying the same pointer for both input and output for in-place processing. */ } } - - if (!pDevice->noClip && pDevice->playback.format == ma_format_f32) { - ma_clip_pcm_frames_f32((float*)pFramesOut, frameCount, pDevice->playback.channels); - } } + ma_device_restore_denormals(pDevice, prevDenormalState); } } @@ -12273,58 +17923,99 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra MA_ASSERT(pFramesOut != NULL); if (pDevice->playback.converter.isPassthrough) { - ma_device__on_data(pDevice, pFramesOut, NULL, frameCount); + ma_device__handle_data_callback(pDevice, pFramesOut, NULL, frameCount); } else { ma_result result; ma_uint64 totalFramesReadOut; - ma_uint64 totalFramesReadIn; void* pRunningFramesOut; totalFramesReadOut = 0; - totalFramesReadIn = 0; pRunningFramesOut = pFramesOut; - while (totalFramesReadOut < frameCount) { - ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In client format. */ - ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - ma_uint64 framesToReadThisIterationIn; - ma_uint64 framesReadThisIterationIn; - ma_uint64 framesToReadThisIterationOut; - ma_uint64 framesReadThisIterationOut; - ma_uint64 requiredInputFrameCount; + /* + We run slightly different logic depending on whether or not we're using a heap-allocated + buffer for caching input data. This will be the case if the data converter does not have + the ability to retrieve the required input frame count for a given output frame count. + */ + if (pDevice->playback.pInputCache != NULL) { + while (totalFramesReadOut < frameCount) { + ma_uint64 framesToReadThisIterationIn; + ma_uint64 framesToReadThisIterationOut; - framesToReadThisIterationOut = (frameCount - totalFramesReadOut); - framesToReadThisIterationIn = framesToReadThisIterationOut; - if (framesToReadThisIterationIn > intermediaryBufferCap) { - framesToReadThisIterationIn = intermediaryBufferCap; + /* If there's any data available in the cache, that needs to get processed first. */ + if (pDevice->playback.inputCacheRemaining > 0) { + framesToReadThisIterationOut = (frameCount - totalFramesReadOut); + framesToReadThisIterationIn = framesToReadThisIterationOut; + if (framesToReadThisIterationIn > pDevice->playback.inputCacheRemaining) { + framesToReadThisIterationIn = pDevice->playback.inputCacheRemaining; + } + + result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, ma_offset_pcm_frames_ptr(pDevice->playback.pInputCache, pDevice->playback.inputCacheConsumed, pDevice->playback.format, pDevice->playback.channels), &framesToReadThisIterationIn, pRunningFramesOut, &framesToReadThisIterationOut); + if (result != MA_SUCCESS) { + break; + } + + pDevice->playback.inputCacheConsumed += framesToReadThisIterationIn; + pDevice->playback.inputCacheRemaining -= framesToReadThisIterationIn; + + totalFramesReadOut += framesToReadThisIterationOut; + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesToReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); + + if (framesToReadThisIterationIn == 0 && framesToReadThisIterationOut == 0) { + break; /* We're done. */ + } + } + + /* Getting here means there's no data in the cache and we need to fill it up with data from the client. */ + if (pDevice->playback.inputCacheRemaining == 0) { + ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, NULL, (ma_uint32)pDevice->playback.inputCacheCap); + + pDevice->playback.inputCacheConsumed = 0; + pDevice->playback.inputCacheRemaining = pDevice->playback.inputCacheCap; + } } + } else { + while (totalFramesReadOut < frameCount) { + ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In client format. */ + ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + ma_uint64 framesToReadThisIterationIn; + ma_uint64 framesReadThisIterationIn; + ma_uint64 framesToReadThisIterationOut; + ma_uint64 framesReadThisIterationOut; + ma_uint64 requiredInputFrameCount; - requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, framesToReadThisIterationOut); - if (framesToReadThisIterationIn > requiredInputFrameCount) { - framesToReadThisIterationIn = requiredInputFrameCount; - } + framesToReadThisIterationOut = (frameCount - totalFramesReadOut); + framesToReadThisIterationIn = framesToReadThisIterationOut; + if (framesToReadThisIterationIn > intermediaryBufferCap) { + framesToReadThisIterationIn = intermediaryBufferCap; + } - if (framesToReadThisIterationIn > 0) { - ma_device__on_data(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); - totalFramesReadIn += framesToReadThisIterationIn; - } + ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, framesToReadThisIterationOut, &requiredInputFrameCount); + if (framesToReadThisIterationIn > requiredInputFrameCount) { + framesToReadThisIterationIn = requiredInputFrameCount; + } - /* - At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any - input frames, we still want to try processing frames because there may some output frames generated from cached input data. - */ - framesReadThisIterationIn = framesToReadThisIterationIn; - framesReadThisIterationOut = framesToReadThisIterationOut; - result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); - if (result != MA_SUCCESS) { - break; - } + if (framesToReadThisIterationIn > 0) { + ma_device__handle_data_callback(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); + } - totalFramesReadOut += framesReadThisIterationOut; - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); + /* + At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any + input frames, we still want to try processing frames because there may some output frames generated from cached input data. + */ + framesReadThisIterationIn = framesToReadThisIterationIn; + framesReadThisIterationOut = framesToReadThisIterationOut; + result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); + if (result != MA_SUCCESS) { + break; + } - if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { - break; /* We're done. */ + totalFramesReadOut += framesReadThisIterationOut; + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); + + if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { + break; /* We're done. */ + } } } } @@ -12338,7 +18029,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame MA_ASSERT(pFramesInDeviceFormat != NULL); if (pDevice->capture.converter.isPassthrough) { - ma_device__on_data(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat); + ma_device__handle_data_callback(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat); } else { ma_result result; ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; @@ -12361,7 +18052,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame } if (clientFramesProcessedThisIteration > 0) { - ma_device__on_data(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */ + ma_device__handle_data_callback(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */ } pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); @@ -12396,7 +18087,7 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m result = ma_pcm_rb_acquire_write(pRB, &framesToProcessInClientFormat, &pFramesInClientFormat); if (result != MA_SUCCESS) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer."); break; } @@ -12414,9 +18105,9 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m break; } - result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat, pFramesInClientFormat); /* Safe cast. */ + result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat); /* Safe cast. */ if (result != MA_SUCCESS) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer."); break; } @@ -12435,16 +18126,14 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_pcm_rb* pRB) { ma_result result; - ma_uint8 playbackFramesInExternalFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint8 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - ma_uint32 totalFramesToReadFromClient; - ma_uint32 totalFramesReadFromClient; ma_uint32 totalFramesReadOut = 0; MA_ASSERT(pDevice != NULL); MA_ASSERT(frameCount > 0); MA_ASSERT(pFramesInInternalFormat != NULL); MA_ASSERT(pRB != NULL); + MA_ASSERT(pDevice->playback.pInputCache != NULL); /* Sitting in the ring buffer should be captured data from the capture callback in external format. If there's not enough data in there for @@ -12452,68 +18141,61 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, */ MA_ZERO_MEMORY(silentInputFrames, sizeof(silentInputFrames)); - /* We need to calculate how many output frames are required to be read from the client to completely fill frameCount internal frames. */ - totalFramesToReadFromClient = (ma_uint32)ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, frameCount); - totalFramesReadFromClient = 0; - while (totalFramesReadFromClient < totalFramesToReadFromClient && ma_device_is_started(pDevice)) { - ma_uint32 framesRemainingFromClient; - ma_uint32 framesToProcessFromClient; - ma_uint32 inputFrameCount; - void* pInputFrames; - - framesRemainingFromClient = (totalFramesToReadFromClient - totalFramesReadFromClient); - framesToProcessFromClient = sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - if (framesToProcessFromClient > framesRemainingFromClient) { - framesToProcessFromClient = framesRemainingFromClient; - } - - /* We need to grab captured samples before firing the callback. If there's not enough input samples we just pass silence. */ - inputFrameCount = framesToProcessFromClient; - result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames); - if (result == MA_SUCCESS) { - if (inputFrameCount > 0) { - /* Use actual input frames. */ - ma_device__on_data(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount); - } else { - if (ma_pcm_rb_pointer_distance(pRB) == 0) { - break; /* Underrun. */ - } - } - - /* We're done with the captured samples. */ - result = ma_pcm_rb_commit_read(pRB, inputFrameCount, pInputFrames); - if (result != MA_SUCCESS) { - break; /* Don't know what to do here... Just abandon ship. */ - } - } else { - /* Use silent input frames. */ - inputFrameCount = ma_min( - sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels), - sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels) - ); - - ma_device__on_data(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount); - } - - /* We have samples in external format so now we need to convert to internal format and output to the device. */ - { - ma_uint64 framesConvertedIn = inputFrameCount; + while (totalFramesReadOut < frameCount && ma_device_is_started(pDevice)) { + /* + We should have a buffer allocated on the heap. Any playback frames still sitting in there + need to be sent to the internal device before we process any more data from the client. + */ + if (pDevice->playback.inputCacheRemaining > 0) { + ma_uint64 framesConvertedIn = pDevice->playback.inputCacheRemaining; ma_uint64 framesConvertedOut = (frameCount - totalFramesReadOut); - ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackFramesInExternalFormat, &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut); + ma_data_converter_process_pcm_frames(&pDevice->playback.converter, ma_offset_pcm_frames_ptr(pDevice->playback.pInputCache, pDevice->playback.inputCacheConsumed, pDevice->playback.format, pDevice->playback.channels), &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut); + + pDevice->playback.inputCacheConsumed += framesConvertedIn; + pDevice->playback.inputCacheRemaining -= framesConvertedIn; - totalFramesReadFromClient += (ma_uint32)framesConvertedIn; /* Safe cast. */ totalFramesReadOut += (ma_uint32)framesConvertedOut; /* Safe cast. */ pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } + + /* If there's no more data in the cache we'll need to fill it with some. */ + if (totalFramesReadOut < frameCount && pDevice->playback.inputCacheRemaining == 0) { + ma_uint32 inputFrameCount; + void* pInputFrames; + + inputFrameCount = (ma_uint32)pDevice->playback.inputCacheCap; + result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames); + if (result == MA_SUCCESS) { + if (inputFrameCount > 0) { + ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, pInputFrames, inputFrameCount); + } else { + if (ma_pcm_rb_pointer_distance(pRB) == 0) { + break; /* Underrun. */ + } + } + } else { + /* No capture data available. Feed in silence. */ + inputFrameCount = (ma_uint32)ma_min(pDevice->playback.inputCacheCap, sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels)); + ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, silentInputFrames, inputFrameCount); + } + + pDevice->playback.inputCacheConsumed = 0; + pDevice->playback.inputCacheRemaining = inputFrameCount; + + result = ma_pcm_rb_commit_read(pRB, inputFrameCount); + if (result != MA_SUCCESS) { + return result; /* Should never happen. */ + } + } } return MA_SUCCESS; } /* A helper for changing the state of the device. */ -static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_uint32 newState) +static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state newState) { - c89atomic_exchange_32(&pDevice->state, newState); + c89atomic_exchange_i32((ma_int32*)&pDevice->state, (ma_int32)newState); } @@ -12541,7 +18223,6 @@ MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = bette static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType); - static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDeviceDescriptor) { if (pDeviceDescriptor == NULL) { @@ -12552,7 +18233,7 @@ static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDevi return MA_FALSE; } - if (pDeviceDescriptor->channels < MA_MIN_CHANNELS || pDeviceDescriptor->channels > MA_MAX_CHANNELS) { + if (pDeviceDescriptor->channels == 0 || pDeviceDescriptor->channels > MA_MAX_CHANNELS) { return MA_FALSE; } @@ -12594,7 +18275,7 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) /* NOTE: The device was started outside of this function, in the worker thread. */ - while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) { + while (ma_device_get_state(pDevice) == ma_device_state_started && !exitLoop) { switch (pDevice->type) { case ma_device_type_duplex: { @@ -12644,7 +18325,7 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) break; } - ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/ + ma_device__handle_data_callback(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/ capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ @@ -12974,7 +18655,7 @@ static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config pDescriptorCapture->sampleRate = (pDescriptorCapture->sampleRate != 0) ? pDescriptorCapture->sampleRate : MA_DEFAULT_SAMPLE_RATE; if (pDescriptorCapture->channelMap[0] == MA_CHANNEL_NONE) { - ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptorCapture->channels, pDescriptorCapture->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels); } pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile); @@ -12986,7 +18667,7 @@ static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config pDescriptorPlayback->sampleRate = (pDescriptorPlayback->sampleRate != 0) ? pDescriptorPlayback->sampleRate : MA_DEFAULT_SAMPLE_RATE; if (pDescriptorPlayback->channelMap[0] == MA_CHANNEL_NONE) { - ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorPlayback->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorPlayback->channels); } pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); @@ -13555,7 +19236,7 @@ static const PROPERTYKEY MA_PKEY_Device_FriendlyName = {{0xA45C254E, static const PROPERTYKEY MA_PKEY_AudioEngine_DeviceFormat = {{0xF19F064D, 0x82C, 0x4E27, {0xBC, 0x73, 0x68, 0x82, 0xA1, 0xBB, 0x8E, 0x4C}}, 0}; static const IID MA_IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; /* 00000000-0000-0000-C000-000000000046 */ -#ifndef MA_WIN32_DESKTOP +#if !defined(MA_WIN32_DESKTOP) && !defined(MA_WIN32_GDK) static const IID MA_IID_IAgileObject = {0x94EA2B94, 0xE9CC, 0x49E0, {0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90}}; /* 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90 */ #endif @@ -13565,7 +19246,7 @@ static const IID MA_IID_IAudioClient3 = {0x7ED4EE07, static const IID MA_IID_IAudioRenderClient = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; /* F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) */ static const IID MA_IID_IAudioCaptureClient = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; /* C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) */ static const IID MA_IID_IMMNotificationClient = {0x7991EEC9, 0x7E89, 0x4D85, {0x83, 0x90, 0x6C, 0x70, 0x3C, 0xEC, 0x60, 0xC0}}; /* 7991EEC9-7E89-4D85-8390-6C703CEC60C0 = __uuidof(IMMNotificationClient) */ -#ifndef MA_WIN32_DESKTOP +#if !defined(MA_WIN32_DESKTOP) && !defined(MA_WIN32_GDK) static const IID MA_IID_DEVINTERFACE_AUDIO_RENDER = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; /* E6327CAD-DCEC-4949-AE8A-991E976A79D2 */ static const IID MA_IID_DEVINTERFACE_AUDIO_CAPTURE = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; /* 2EEF81BE-33FA-4800-9670-1CD474972C3F */ static const IID MA_IID_IActivateAudioInterfaceCompletionHandler = {0x41D949AB, 0x9862, 0x444A, {0x80, 0xF6, 0xC2, 0x61, 0x33, 0x4D, 0xA5, 0xEB}}; /* 41D949AB-9862-444A-80F6-C261334DA5EB */ @@ -13582,7 +19263,7 @@ static const IID MA_IID_IMMDeviceEnumerator_Instance = {0xA95664D2, #endif typedef struct ma_IUnknown ma_IUnknown; -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) #define MA_MM_DEVICE_STATE_ACTIVE 1 #define MA_MM_DEVICE_STATE_DISABLED 2 #define MA_MM_DEVICE_STATE_NOTPRESENT 4 @@ -13668,7 +19349,7 @@ static MA_INLINE HRESULT ma_IUnknown_QueryInterface(ma_IUnknown* pThis, const II static MA_INLINE ULONG ma_IUnknown_AddRef(ma_IUnknown* pThis) { return pThis->lpVtbl->AddRef(pThis); } static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) { return pThis->lpVtbl->Release(pThis); } -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) /* IMMNotificationClient */ typedef struct { @@ -14012,7 +19693,7 @@ static MA_INLINE HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); } static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket) { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); } -#ifndef MA_WIN32_DESKTOP +#if !defined(MA_WIN32_DESKTOP) && !defined(MA_WIN32_GDK) #include typedef struct ma_completion_handler_uwp ma_completion_handler_uwp; @@ -14029,7 +19710,7 @@ typedef struct struct ma_completion_handler_uwp { ma_completion_handler_uwp_vtbl* lpVtbl; - MA_ATOMIC ma_uint32 counter; + MA_ATOMIC(4, ma_uint32) counter; HANDLE hEvent; }; @@ -14109,7 +19790,7 @@ static void ma_completion_handler_uwp_wait(ma_completion_handler_uwp* pHandler) #endif /* !MA_WIN32_DESKTOP */ /* We need a virtual table for our notification client object that's used for detecting changes to the default device. */ -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject) { /* @@ -14183,7 +19864,7 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(m use this to determine whether or not we need to automatically start the device when it's plugged back in again. */ - if (ma_device_get_state(pThis->pDevice) == MA_STATE_STARTED) { + if (ma_device_get_state(pThis->pDevice) == ma_device_state_started) { if (isPlayback) { pThis->pDevice->wasapi.isDetachedPlayback = MA_TRUE; } @@ -14293,13 +19974,13 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged /* Second attempt at device rerouting. We're going to retrieve the device's state at the time of the route change. We're then going to stop the device, reinitialize the device, and then start - it again if the state before stopping was MA_STATE_STARTED. + it again if the state before stopping was ma_device_state_started. */ { ma_uint32 previousState = ma_device_get_state(pThis->pDevice); ma_bool8 restartDevice = MA_FALSE; - if (previousState == MA_STATE_STARTED) { + if (previousState == ma_device_state_started) { ma_device_stop(pThis->pDevice); restartDevice = MA_TRUE; } @@ -14364,7 +20045,7 @@ static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl = { }; #endif /* MA_WIN32_DESKTOP */ -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) typedef ma_IMMDevice ma_WASAPIDeviceInterface; #else typedef ma_IUnknown ma_WASAPIDeviceInterface; @@ -14584,7 +20265,8 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context if (SUCCEEDED(hr)) { ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_shared, pInfo); } else { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval."); + return ma_result_from_HRESULT(hr); } /* @@ -14592,7 +20274,7 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context UWP. Failure to retrieve the exclusive mode format is not considered an error, so from here on out, MA_SUCCESS is guaranteed to be returned. */ - #ifdef MA_WIN32_DESKTOP + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) { ma_IPropertyStore *pProperties; @@ -14622,7 +20304,7 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context The format returned by PKEY_AudioEngine_DeviceFormat is not supported, so fall back to a search. We assume the channel count returned by MA_PKEY_AudioEngine_DeviceFormat is valid and correct. For simplicity we're only returning one format. */ - ma_uint32 channels = pInfo->minChannels; + ma_uint32 channels = pWF->nChannels; ma_channel defaultChannelMap[MA_MAX_CHANNELS]; WAVEFORMATEXTENSIBLE wf; ma_bool32 found; @@ -14633,7 +20315,7 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context channels = MA_MAX_CHANNELS; } - ma_get_standard_channel_map(ma_standard_channel_map_microsoft, channels, defaultChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_microsoft, defaultChannelMap, ma_countof(defaultChannelMap), channels); MA_ZERO_OBJECT(&wf); wf.Format.cbSize = sizeof(wf); @@ -14675,16 +20357,16 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context ma_PropVariantClear(pContext, &var); if (!found) { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to find suitable device format for device info retrieval.", MA_FORMAT_NOT_SUPPORTED); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to find suitable device format for device info retrieval."); } } } else { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval."); } ma_IPropertyStore_Release(pProperties); } else { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to open property store for device info retrieval.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to open property store for device info retrieval."); } } #endif @@ -14692,7 +20374,7 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context return MA_SUCCESS; } -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) static ma_EDataFlow ma_device_type_to_EDataFlow(ma_device_type deviceType) { if (deviceType == ma_device_type_playback) { @@ -14717,7 +20399,8 @@ static ma_result ma_context_create_IMMDeviceEnumerator__wasapi(ma_context* pCont hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator."); + return ma_result_from_HRESULT(hr); } *ppDeviceEnumerator = pDeviceEnumerator; @@ -14790,7 +20473,8 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator."); + return ma_result_from_HRESULT(hr); } if (pDeviceID == NULL) { @@ -14801,7 +20485,8 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice."); + return ma_result_from_HRESULT(hr); } return MA_SUCCESS; @@ -14881,7 +20566,8 @@ static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pC ma_IAudioClient_Release(pAudioClient); return result; } else { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval."); + return ma_result_from_HRESULT(hr); } } @@ -14908,7 +20594,8 @@ static ma_result ma_context_enumerate_devices_by_type__wasapi(ma_context* pConte if (SUCCEEDED(hr)) { hr = ma_IMMDeviceCollection_GetCount(pDeviceCollection, &deviceCount); if (FAILED(hr)) { - result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count."); + result = ma_result_from_HRESULT(hr); goto done; } @@ -14999,13 +20686,15 @@ static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, m hr = StringFromIID(&iid, &iidStr); #endif if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory."); + return ma_result_from_HRESULT(hr); } result = ma_completion_handler_uwp_init(&completionHandler); if (result != MA_SUCCESS) { ma_CoTaskMemFree(pContext, iidStr); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", result); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync()."); + return result; } #if defined(__cplusplus) @@ -15016,7 +20705,8 @@ static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, m if (FAILED(hr)) { ma_completion_handler_uwp_uninit(&completionHandler); ma_CoTaskMemFree(pContext, iidStr); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed."); + return ma_result_from_HRESULT(hr); } ma_CoTaskMemFree(pContext, iidStr); @@ -15029,13 +20719,15 @@ static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, m ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp); if (FAILED(hr) || FAILED(activateResult)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.", FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device."); + return FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult); } /* Here is where we grab the IAudioClient interface. */ hr = ma_IUnknown_QueryInterface(pActivatedInterface, &MA_IID_IAudioClient, (void**)ppAudioClient); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface."); + return ma_result_from_HRESULT(hr); } if (ppActivatedInterface) { @@ -15050,7 +20742,7 @@ static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, m static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_WASAPIDeviceInterface** ppDeviceInterface) { -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) return ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface); #else return ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface); @@ -15061,14 +20753,15 @@ static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_de static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { /* Different enumeration for desktop and UWP. */ -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) /* Desktop */ HRESULT hr; ma_IMMDeviceEnumerator* pDeviceEnumerator; hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator."); + return ma_result_from_HRESULT(hr); } ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_playback, callback, pUserData); @@ -15112,7 +20805,7 @@ static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_e static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) { -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) ma_result result; ma_IMMDevice* pMMDevice = NULL; LPWSTR pDefaultDeviceID = NULL; @@ -15164,7 +20857,7 @@ static ma_result ma_device_uninit__wasapi(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) if (pDevice->wasapi.pDeviceEnumerator) { ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient); ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator); @@ -15172,9 +20865,23 @@ static ma_result ma_device_uninit__wasapi(ma_device* pDevice) #endif if (pDevice->wasapi.pRenderClient) { + if (pDevice->wasapi.pMappedBufferPlayback != NULL) { + ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); + pDevice->wasapi.pMappedBufferPlayback = NULL; + pDevice->wasapi.mappedBufferPlaybackCap = 0; + pDevice->wasapi.mappedBufferPlaybackLen = 0; + } + ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); } if (pDevice->wasapi.pCaptureClient) { + if (pDevice->wasapi.pMappedBufferCapture != NULL) { + ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); + pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.mappedBufferCaptureCap = 0; + pDevice->wasapi.mappedBufferCaptureLen = 0; + } + ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); } @@ -15293,7 +21000,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device /* Here is where we try to determine the best format to use with the device. If the client if wanting exclusive mode, first try finding the best format for that. If this fails, fall back to shared mode. */ result = MA_FORMAT_NOT_SUPPORTED; if (pData->shareMode == ma_share_mode_exclusive) { - #ifdef MA_WIN32_DESKTOP + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) /* In exclusive mode on desktop we always use the backend's native format. */ ma_IPropertyStore* pStore = NULL; hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore); @@ -15405,7 +21112,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device /* Slightly different initialization for shared and exclusive modes. We try exclusive mode first, and if it fails, fall back to shared mode. */ if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) { - MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * 10; + MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * pData->periodsOut * 10; /* If the periodicy is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing @@ -15439,7 +21146,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device /* Unfortunately we need to release and re-acquire the audio client according to MSDN. Seems silly - why not just call IAudioClient_Initialize() again?! */ ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient); - #ifdef MA_WIN32_DESKTOP + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) hr = ma_IMMDevice_Activate(pDeviceInterface, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient); #else hr = ma_IUnknown_QueryInterface(pDeviceInterface, &MA_IID_IAudioClient, (void**)&pData->pAudioClient); @@ -15497,15 +21204,11 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */ actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames); - #if defined(MA_DEBUG_OUTPUT) - { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " defaultPeriodInFrames=%d\n", defaultPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " minPeriodInFrames=%d\n", minPeriodInFrames); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " maxPeriodInFrames=%d\n", maxPeriodInFrames); - } - #endif + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " defaultPeriodInFrames=%d\n", defaultPeriodInFrames); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " minPeriodInFrames=%d\n", minPeriodInFrames); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " maxPeriodInFrames=%d\n", maxPeriodInFrames); /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */ if (actualPeriodInFrames >= desiredPeriodInFrames) { @@ -15517,12 +21220,9 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device if (SUCCEEDED(hr)) { wasInitializedUsingIAudioClient3 = MA_TRUE; pData->periodSizeInFramesOut = actualPeriodInFrames; - #if defined(MA_DEBUG_OUTPUT) - { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Using IAudioClient3\n"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut); - } - #endif + + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Using IAudioClient3\n"); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut); } else { ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n"); } @@ -15590,7 +21290,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device /* Grab the name of the device. */ - #ifdef MA_WIN32_DESKTOP + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) { ma_IPropertyStore *pProperties; hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties); @@ -15613,7 +21313,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device stream routing so that IDs can be compared and we can determine which device has been detached and whether or not it matches with our ma_device. */ - #ifdef MA_WIN32_DESKTOP + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) { /* Desktop */ ma_context_get_device_id_from_MMDevice__wasapi(pContext, pDeviceInterface, &pData->id); @@ -15627,7 +21327,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device done: /* Clean up. */ -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) if (pDeviceInterface != NULL) { ma_IMMDevice_Release(pDeviceInterface); } @@ -15652,7 +21352,7 @@ done: } if (errorMsg != NULL && errorMsg[0] != '\0') { - ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_ERROR, errorMsg); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "%s", errorMsg); } return result; @@ -15750,7 +21450,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); /* We must always have a valid ID. */ ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi); @@ -15771,9 +21471,9 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); - /* We must always have a valid ID. */ + /* We must always have a valid ID because rerouting will look at it. */ ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); } @@ -15784,7 +21484,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf { ma_result result = MA_SUCCESS; -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) HRESULT hr; ma_IMMDeviceEnumerator* pDeviceEnumerator; #endif @@ -15845,12 +21545,13 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf pDevice->wasapi.pAudioClientCapture = NULL; } - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture."); + return result; } ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); /* We must always have a valid ID. */ ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi); @@ -15938,14 +21639,15 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf pDevice->wasapi.pAudioClientPlayback = NULL; } - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback."); + return result; } ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; - ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback); + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); - /* We must always have a valid ID. */ + /* We must always have a valid ID because rerouting will look at it. */ ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); /* The descriptor needs to be updated with actual values. */ @@ -15962,7 +21664,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf we are connecting to the default device we want to do automatic stream routing when the device is disabled or unplugged. Otherwise we want to just stop the device outright and let the application handle it. */ -#ifdef MA_WIN32_DESKTOP +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) { if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) { pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE; @@ -15975,7 +21677,8 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf hr = ma_CoCreateInstance(pDevice->pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { ma_device_uninit__wasapi(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator."); + return ma_result_from_HRESULT(hr); } pDevice->wasapi.notificationClient.lpVtbl = (void*)&g_maNotificationCientVtbl; @@ -16036,16 +21739,16 @@ static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_ } if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { - *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback - paddingFramesCount; + *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback - paddingFramesCount; } else { *pFrameCount = paddingFramesCount; } } else { /* Exclusive mode. */ if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { - *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback; + *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback; } else { - *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesCapture; + *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesCapture; } } @@ -16065,12 +21768,14 @@ static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type de result = ma_device_reinit__wasapi(pDevice, deviceType); if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Reinitializing device after route change failed.\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WASAPI] Reinitializing device after route change failed.\n"); return result; } ma_device__post_init_setup(pDevice, deviceType); + ma_device__on_notification_rerouted(pDevice); + return MA_SUCCESS; } @@ -16083,14 +21788,21 @@ static ma_result ma_device_start__wasapi(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device."); + return ma_result_from_HRESULT(hr); } c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_TRUE); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* No need to do anything for playback as that'll be started automatically in the data loop. */ + hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + if (FAILED(hr)) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device."); + return ma_result_from_HRESULT(hr); + } + + c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); } return MA_SUCCESS; @@ -16106,13 +21818,23 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device."); + return ma_result_from_HRESULT(hr); } /* The audio client needs to be reset otherwise restarting will fail. */ hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device."); + return ma_result_from_HRESULT(hr); + } + + /* If we have a mapped buffer we need to release it. */ + if (pDevice->wasapi.pMappedBufferCapture != NULL) { + ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); + pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.mappedBufferCaptureCap = 0; + pDevice->wasapi.mappedBufferCaptureLen = 0; } c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE); @@ -16125,7 +21847,7 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) */ if (c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) { /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */ - DWORD waitTime = pDevice->wasapi.actualPeriodSizeInFramesPlayback / pDevice->playback.internalSampleRate; + DWORD waitTime = pDevice->wasapi.actualBufferSizeInFramesPlayback / pDevice->playback.internalSampleRate; if (pDevice->playback.shareMode == ma_share_mode_exclusive) { WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime); @@ -16138,7 +21860,7 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) break; } - if (framesAvailablePlayback >= pDevice->wasapi.actualPeriodSizeInFramesPlayback) { + if (framesAvailablePlayback >= pDevice->wasapi.actualBufferSizeInFramesPlayback) { break; } @@ -16159,13 +21881,22 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device."); + return ma_result_from_HRESULT(hr); } /* The audio client needs to be reset otherwise restarting will fail. */ hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device."); + return ma_result_from_HRESULT(hr); + } + + if (pDevice->wasapi.pMappedBufferPlayback != NULL) { + ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); + pDevice->wasapi.pMappedBufferPlayback = NULL; + pDevice->wasapi.mappedBufferPlaybackCap = 0; + pDevice->wasapi.mappedBufferPlaybackLen = 0; } c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE); @@ -16179,508 +21910,237 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) #define MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS 5000 #endif -static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) +static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) { - ma_result result; - HRESULT hr; - ma_bool32 exitLoop = MA_FALSE; - ma_uint32 framesWrittenToPlaybackDevice = 0; - ma_uint32 mappedDeviceBufferSizeInFramesCapture = 0; - ma_uint32 mappedDeviceBufferSizeInFramesPlayback = 0; - ma_uint32 mappedDeviceBufferFramesRemainingCapture = 0; - ma_uint32 mappedDeviceBufferFramesRemainingPlayback = 0; - BYTE* pMappedDeviceBufferCapture = NULL; - BYTE* pMappedDeviceBufferPlayback = NULL; - ma_uint32 bpfCaptureDevice = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); - ma_uint32 bpfPlaybackDevice = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); - ma_uint32 bpfCaptureClient = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 bpfPlaybackClient = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - ma_uint8 inputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - ma_uint32 inputDataInClientFormatCap = 0; - ma_uint8 outputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - ma_uint32 outputDataInClientFormatCap = 0; - ma_uint32 outputDataInClientFormatCount = 0; - ma_uint32 outputDataInClientFormatConsumed = 0; - ma_uint32 periodSizeInFramesCapture = 0; + ma_result result = MA_SUCCESS; + ma_uint32 totalFramesProcessed = 0; - MA_ASSERT(pDevice != NULL); + /* + When reading, we need to get a buffer and process all of it before releasing it. Because the + frame count (frameCount) can be different to the size of the buffer, we'll need to cache the + pointer to the buffer. + */ - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { - periodSizeInFramesCapture = pDevice->capture.internalPeriodSizeInFrames; - inputDataInClientFormatCap = sizeof(inputDataInClientFormat) / bpfCaptureClient; - } + /* Keep running until we've processed the requested number of frames. */ + while (ma_device_get_state(pDevice) == ma_device_state_started && totalFramesProcessed < frameCount) { + ma_uint32 framesRemaining = frameCount - totalFramesProcessed; - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - outputDataInClientFormatCap = sizeof(outputDataInClientFormat) / bpfPlaybackClient; - } + /* If we have a mapped data buffer, consume that first. */ + if (pDevice->wasapi.pMappedBufferCapture != NULL) { + /* We have a cached data pointer so consume that before grabbing another one from WASAPI. */ + ma_uint32 framesToProcessNow = framesRemaining; + if (framesToProcessNow > pDevice->wasapi.mappedBufferCaptureLen) { + framesToProcessNow = pDevice->wasapi.mappedBufferCaptureLen; + } - while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) { - switch (pDevice->type) - { - case ma_device_type_duplex: - { - ma_uint32 framesAvailableCapture; - ma_uint32 framesAvailablePlayback; - DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */ + /* Now just copy the data over to the output buffer. */ + ma_copy_pcm_frames( + ma_offset_pcm_frames_ptr(pFrames, totalFramesProcessed, pDevice->capture.internalFormat, pDevice->capture.internalChannels), + ma_offset_pcm_frames_const_ptr(pDevice->wasapi.pMappedBufferCapture, pDevice->wasapi.mappedBufferCaptureCap - pDevice->wasapi.mappedBufferCaptureLen, pDevice->capture.internalFormat, pDevice->capture.internalChannels), + framesToProcessNow, + pDevice->capture.internalFormat, pDevice->capture.internalChannels + ); - /* The process is to map the playback buffer and fill it as quickly as possible from input data. */ - if (pMappedDeviceBufferPlayback == NULL) { - result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); - if (result != MA_SUCCESS) { - return result; - } + totalFramesProcessed += framesToProcessNow; + pDevice->wasapi.mappedBufferCaptureLen -= framesToProcessNow; - /* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */ - if (pDevice->playback.shareMode != ma_share_mode_exclusive) { - if (framesAvailablePlayback > pDevice->wasapi.periodSizeInFramesPlayback) { - framesAvailablePlayback = pDevice->wasapi.periodSizeInFramesPlayback; - } - } + /* If the data buffer has been fully consumed we need to release it. */ + if (pDevice->wasapi.mappedBufferCaptureLen == 0) { + ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); + pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.mappedBufferCaptureCap = 0; + } + } else { + /* We don't have any cached data pointer, so grab another one. */ + HRESULT hr; + DWORD flags; - /* We're ready to map the playback device's buffer. We don't release this until it's been entirely filled. */ - hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - - mappedDeviceBufferSizeInFramesPlayback = framesAvailablePlayback; - mappedDeviceBufferFramesRemainingPlayback = framesAvailablePlayback; - } - - if (mappedDeviceBufferFramesRemainingPlayback > 0) { - /* At this point we should have a buffer available for output. We need to keep writing input samples to it. */ - for (;;) { - /* Try grabbing some captured data if we haven't already got a mapped buffer. */ - if (pMappedDeviceBufferCapture == NULL) { - if (pDevice->capture.shareMode == ma_share_mode_shared) { - if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { - return MA_ERROR; /* Wait failed. */ - } - } - - result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - /* Wait for more if nothing is available. */ - if (framesAvailableCapture == 0) { - /* In exclusive mode we waited at the top. */ - if (pDevice->capture.shareMode != ma_share_mode_shared) { - if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { - return MA_ERROR; /* Wait failed. */ - } - } - - continue; - } - - /* Getting here means there's data available for writing to the output device. */ - mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture); - hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - - - /* Overrun detection. */ - if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { - /* Glitched. Probably due to an overrun. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); - - /* - Exeriment: If we get an overrun it probably means we're straddling the end of the buffer. In order to prevent a never-ending sequence of glitches let's experiment - by dropping every frame until we're left with only a single period. To do this we just keep retrieving and immediately releasing buffers until we're down to the - last period. - */ - if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Synchronizing capture stream. "); - do - { - hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); - if (FAILED(hr)) { - break; - } - - framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture; - - if (framesAvailableCapture > 0) { - mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture); - hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - } else { - pMappedDeviceBufferCapture = NULL; - mappedDeviceBufferSizeInFramesCapture = 0; - } - } while (framesAvailableCapture > periodSizeInFramesCapture); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); - } - } else { - #ifdef MA_DEBUG_OUTPUT - if (flagsCapture != 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture); - } - #endif - } - - mappedDeviceBufferFramesRemainingCapture = mappedDeviceBufferSizeInFramesCapture; - } - - - /* At this point we should have both input and output data available. We now need to convert the data and post it to the client. */ - for (;;) { - BYTE* pRunningDeviceBufferCapture; - BYTE* pRunningDeviceBufferPlayback; - ma_uint32 framesToProcess; - ma_uint32 framesProcessed; - - pRunningDeviceBufferCapture = pMappedDeviceBufferCapture + ((mappedDeviceBufferSizeInFramesCapture - mappedDeviceBufferFramesRemainingCapture ) * bpfCaptureDevice); - pRunningDeviceBufferPlayback = pMappedDeviceBufferPlayback + ((mappedDeviceBufferSizeInFramesPlayback - mappedDeviceBufferFramesRemainingPlayback) * bpfPlaybackDevice); - - /* There may be some data sitting in the converter that needs to be processed first. Once this is exhaused, run the data callback again. */ - if (!pDevice->playback.converter.isPassthrough && outputDataInClientFormatConsumed < outputDataInClientFormatCount) { - ma_uint64 convertedFrameCountClient = (outputDataInClientFormatCount - outputDataInClientFormatConsumed); - ma_uint64 convertedFrameCountDevice = mappedDeviceBufferFramesRemainingPlayback; - void* pConvertedFramesClient = outputDataInClientFormat + (outputDataInClientFormatConsumed * bpfPlaybackClient); - void* pConvertedFramesDevice = pRunningDeviceBufferPlayback; - result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesClient, &convertedFrameCountClient, pConvertedFramesDevice, &convertedFrameCountDevice); - if (result != MA_SUCCESS) { - break; - } - - outputDataInClientFormatConsumed += (ma_uint32)convertedFrameCountClient; /* Safe cast. */ - mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)convertedFrameCountDevice; /* Safe cast. */ - - if (mappedDeviceBufferFramesRemainingPlayback == 0) { - break; - } - } - - /* - Getting here means we need to fire the callback. If format conversion is unnecessary, we can optimize this by passing the pointers to the internal - buffers directly to the callback. - */ - if (pDevice->capture.converter.isPassthrough && pDevice->playback.converter.isPassthrough) { - /* Optimal path. We can pass mapped pointers directly to the callback. */ - framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, mappedDeviceBufferFramesRemainingPlayback); - framesProcessed = framesToProcess; - - ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, pRunningDeviceBufferCapture, framesToProcess); - - mappedDeviceBufferFramesRemainingCapture -= framesProcessed; - mappedDeviceBufferFramesRemainingPlayback -= framesProcessed; - - if (mappedDeviceBufferFramesRemainingCapture == 0) { - break; /* Exhausted input data. */ - } - if (mappedDeviceBufferFramesRemainingPlayback == 0) { - break; /* Exhausted output data. */ - } - } else if (pDevice->capture.converter.isPassthrough) { - /* The input buffer is a passthrough, but the playback buffer requires a conversion. */ - framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, outputDataInClientFormatCap); - framesProcessed = framesToProcess; - - ma_device__on_data(pDevice, outputDataInClientFormat, pRunningDeviceBufferCapture, framesToProcess); - outputDataInClientFormatCount = framesProcessed; - outputDataInClientFormatConsumed = 0; - - mappedDeviceBufferFramesRemainingCapture -= framesProcessed; - if (mappedDeviceBufferFramesRemainingCapture == 0) { - break; /* Exhausted input data. */ - } - } else if (pDevice->playback.converter.isPassthrough) { - /* The input buffer requires conversion, the playback buffer is passthrough. */ - ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture; - ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, mappedDeviceBufferFramesRemainingPlayback); - - result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess); - if (result != MA_SUCCESS) { - break; - } - - if (capturedClientFramesToProcess == 0) { - break; - } - - ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); /* Safe cast. */ - - mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess; - mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)capturedClientFramesToProcess; - } else { - ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture; - ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, outputDataInClientFormatCap); - - result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess); - if (result != MA_SUCCESS) { - break; - } - - if (capturedClientFramesToProcess == 0) { - break; - } - - ma_device__on_data(pDevice, outputDataInClientFormat, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); - - mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess; - outputDataInClientFormatCount = (ma_uint32)capturedClientFramesToProcess; - outputDataInClientFormatConsumed = 0; - } - } - - - /* If at this point we've run out of capture data we need to release the buffer. */ - if (mappedDeviceBufferFramesRemainingCapture == 0 && pMappedDeviceBufferCapture != NULL) { - hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - - pMappedDeviceBufferCapture = NULL; - mappedDeviceBufferFramesRemainingCapture = 0; - mappedDeviceBufferSizeInFramesCapture = 0; - } - - /* Get out of this loop if we're run out of room in the playback buffer. */ - if (mappedDeviceBufferFramesRemainingPlayback == 0) { - break; - } - } - } - - - /* If at this point we've run out of data we need to release the buffer. */ - if (mappedDeviceBufferFramesRemainingPlayback == 0 && pMappedDeviceBufferPlayback != NULL) { - hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - - framesWrittenToPlaybackDevice += mappedDeviceBufferSizeInFramesPlayback; - - pMappedDeviceBufferPlayback = NULL; - mappedDeviceBufferFramesRemainingPlayback = 0; - mappedDeviceBufferSizeInFramesPlayback = 0; - } - - if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) { - ma_uint32 startThreshold = pDevice->playback.internalPeriodSizeInFrames * 1; - - /* Prevent a deadlock. If we don't clamp against the actual buffer size we'll never end up starting the playback device which will result in a deadlock. */ - if (startThreshold > pDevice->wasapi.actualPeriodSizeInFramesPlayback) { - startThreshold = pDevice->wasapi.actualPeriodSizeInFramesPlayback; - } - - if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= startThreshold) { - hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); - if (FAILED(hr)) { - ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); - ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr)); - } - - c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); - } - } - - /* Make sure the device has started before waiting. */ - if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { - return MA_ERROR; /* Wait failed. */ - } - } break; - - - - case ma_device_type_capture: - case ma_device_type_loopback: - { - ma_uint32 framesAvailableCapture; - DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */ - - /* Wait for data to become available first. */ - if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { - /* - For capture we can terminate here because it probably means the microphone just isn't delivering data for whatever reason, but - for loopback is most likely means nothing is actually playing. We want to keep trying in this situation. - */ - if (pDevice->type == ma_device_type_loopback) { - continue; /* Keep waiting in loopback mode. */ - } else { - exitLoop = MA_TRUE; - break; /* Wait failed. */ - } - } - - /* See how many frames are available. Since we waited at the top, I don't think this should ever return 0. I'm checking for this anyway. */ - result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (framesAvailableCapture < pDevice->wasapi.periodSizeInFramesCapture) { - continue; /* Nothing available. Keep waiting. */ - } - - /* Map the data buffer in preparation for sending to the client. */ - mappedDeviceBufferSizeInFramesCapture = framesAvailableCapture; - hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } + /* First just ask WASAPI for a data buffer. If it's not available, we'll wait for more. */ + hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL); + if (hr == S_OK) { + /* We got a data buffer. Continue to the next loop iteration which will then read from the mapped pointer. */ /* Overrun detection. */ - if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { + if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { /* Glitched. Probably due to an overrun. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=%d\n", pDevice->wasapi.mappedBufferCaptureCap); /* - Exeriment: If we get an overrun it probably means we're straddling the end of the buffer. In order to prevent a never-ending sequence of glitches let's experiment - by dropping every frame until we're left with only a single period. To do this we just keep retrieving and immediately releasing buffers until we're down to the - last period. + If we got an overrun it probably means we're straddling the end of the buffer. In order to prevent + a never-ending sequence of glitches we're going to recover by completely clearing out the capture + buffer. */ - if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Synchronizing capture stream. "); - do - { - hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); + { + ma_uint32 iterationCount = 4; /* Safety to prevent an infinite loop. */ + ma_uint32 i; + + for (i = 0; i < iterationCount; i += 1) { + hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); if (FAILED(hr)) { break; } - framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture; - - if (framesAvailableCapture > 0) { - mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture); - hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - } else { - pMappedDeviceBufferCapture = NULL; - mappedDeviceBufferSizeInFramesCapture = 0; + hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL); + if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || FAILED(hr)) { + break; } - } while (framesAvailableCapture > periodSizeInFramesCapture); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); + } } + + /* We should not have a valid buffer at this point so make sure everything is empty. */ + pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.mappedBufferCaptureCap = 0; + pDevice->wasapi.mappedBufferCaptureLen = 0; } else { - #ifdef MA_DEBUG_OUTPUT - if (flagsCapture != 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture); - } - #endif - } + /* The data is clean. */ + pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap; - /* We should have a buffer at this point, but let's just do a sanity check anyway. */ - if (mappedDeviceBufferSizeInFramesCapture > 0 && pMappedDeviceBufferCapture != NULL) { - ma_device__send_frames_to_client(pDevice, mappedDeviceBufferSizeInFramesCapture, pMappedDeviceBufferCapture); - - /* At this point we're done with the buffer. */ - hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); - pMappedDeviceBufferCapture = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */ - mappedDeviceBufferSizeInFramesCapture = 0; - if (FAILED(hr)) { - ma_post_log_message(ma_device_get_context(pDevice), pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device."); - exitLoop = MA_TRUE; - break; + if (flags != 0) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flags); } } - } break; + continue; + } else { + if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || hr == MA_AUDCLNT_E_BUFFER_ERROR) { + /* + No data is available. We need to wait for more. There's two situations to consider + here. The first is normal capture mode. If this times out it probably means the + microphone isn't delivering data for whatever reason. In this case we'll just + abort the read and return whatever we were able to get. The other situations is + loopback mode, in which case a timeout probably just means the nothing is playing + through the speakers. + */ + if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + if (pDevice->type == ma_device_type_loopback) { + continue; /* Keep waiting in loopback mode. */ + } else { + result = MA_ERROR; + break; /* Wait failed. */ + } + } - - case ma_device_type_playback: - { - ma_uint32 framesAvailablePlayback; - - /* Check how much space is available. If this returns 0 we just keep waiting. */ - result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; + /* At this point we should be able to loop back to the start of the loop and try retrieving a data buffer again. */ + } else { + /* An error occured and we need to abort. */ + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for reading from the device. HRESULT = %d. Stopping device.\n", (int)hr); + result = ma_result_from_HRESULT(hr); break; } - - if (framesAvailablePlayback >= pDevice->wasapi.periodSizeInFramesPlayback) { - /* Map a the data buffer in preparation for the callback. */ - hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - - /* We should have a buffer at this point. */ - ma_device__read_frames_from_client(pDevice, framesAvailablePlayback, pMappedDeviceBufferPlayback); - - /* At this point we're done writing to the device and we just need to release the buffer. */ - hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, 0); - pMappedDeviceBufferPlayback = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */ - mappedDeviceBufferSizeInFramesPlayback = 0; - - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - - framesWrittenToPlaybackDevice += framesAvailablePlayback; - } - - if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) { - hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); - if (FAILED(hr)) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr)); - exitLoop = MA_TRUE; - break; - } - - c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); - } - - /* Make sure we don't wait on the event before we've started the device or we may end up deadlocking. */ - if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { - exitLoop = MA_TRUE; - break; /* Wait failed. Probably timed out. */ - } - } break; - - default: return MA_INVALID_ARGS; + } } } - /* Here is where the device needs to be stopped. */ - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { - /* Any mapped buffers need to be released. */ - if (pMappedDeviceBufferCapture != NULL) { - hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture); + /* + If we were unable to process the entire requested frame count, but we still have a mapped buffer, + there's a good chance either an error occurred or the device was stopped mid-read. In this case + we'll need to make sure the buffer is released. + */ + if (totalFramesProcessed < frameCount && pDevice->wasapi.pMappedBufferCapture != NULL) { + ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); + pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.mappedBufferCaptureCap = 0; + pDevice->wasapi.mappedBufferCaptureLen = 0; + } + + if (pFramesRead != NULL) { + *pFramesRead = totalFramesProcessed; + } + + return result; +} + +static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) +{ + ma_result result = MA_SUCCESS; + ma_uint32 totalFramesProcessed = 0; + + /* Keep writing to the device until it's stopped or we've consumed all of our input. */ + while (ma_device_get_state(pDevice) == ma_device_state_started && totalFramesProcessed < frameCount) { + ma_uint32 framesRemaining = frameCount - totalFramesProcessed; + + /* + We're going to do this in a similar way to capture. We'll first check if the cached data pointer + is valid, and if so, read from that. Otherwise We will call IAudioRenderClient_GetBuffer() with + a requested buffer size equal to our actual period size. If it returns AUDCLNT_E_BUFFER_TOO_LARGE + it means we need to wait for some data to become available. + */ + if (pDevice->wasapi.pMappedBufferPlayback != NULL) { + /* We still have some space available in the mapped data buffer. Write to it. */ + ma_uint32 framesToProcessNow = framesRemaining; + if (framesToProcessNow > (pDevice->wasapi.mappedBufferPlaybackCap - pDevice->wasapi.mappedBufferPlaybackLen)) { + framesToProcessNow = (pDevice->wasapi.mappedBufferPlaybackCap - pDevice->wasapi.mappedBufferPlaybackLen); + } + + /* Now just copy the data over to the output buffer. */ + ma_copy_pcm_frames( + ma_offset_pcm_frames_ptr(pDevice->wasapi.pMappedBufferPlayback, pDevice->wasapi.mappedBufferPlaybackLen, pDevice->playback.internalFormat, pDevice->playback.internalChannels), + ma_offset_pcm_frames_const_ptr(pFrames, totalFramesProcessed, pDevice->playback.internalFormat, pDevice->playback.internalChannels), + framesToProcessNow, + pDevice->playback.internalFormat, pDevice->playback.internalChannels + ); + + totalFramesProcessed += framesToProcessNow; + pDevice->wasapi.mappedBufferPlaybackLen += framesToProcessNow; + + /* If the data buffer has been fully consumed we need to release it. */ + if (pDevice->wasapi.mappedBufferPlaybackLen == pDevice->wasapi.mappedBufferPlaybackCap) { + ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); + pDevice->wasapi.pMappedBufferPlayback = NULL; + pDevice->wasapi.mappedBufferPlaybackCap = 0; + pDevice->wasapi.mappedBufferPlaybackLen = 0; + + /* + In exclusive mode we need to wait here. Exclusive mode is weird because GetBuffer() never + seems to return AUDCLNT_E_BUFFER_TOO_LARGE, which is what we normally use to determine + whether or not we need to wait for more data. + */ + if (pDevice->playback.shareMode == ma_share_mode_exclusive) { + if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + result = MA_ERROR; + break; /* Wait failed. Probably timed out. */ + } + } + } + } else { + /* We don't have a mapped data buffer so we'll need to get one. */ + HRESULT hr; + ma_uint32 bufferSizeInFrames; + + /* Special rules for exclusive mode. */ + if (pDevice->playback.shareMode == ma_share_mode_exclusive) { + bufferSizeInFrames = pDevice->wasapi.actualBufferSizeInFramesPlayback; + } else { + bufferSizeInFrames = pDevice->wasapi.periodSizeInFramesPlayback; + } + + hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, bufferSizeInFrames, (BYTE**)&pDevice->wasapi.pMappedBufferPlayback); + if (hr == S_OK) { + /* We have data available. */ + pDevice->wasapi.mappedBufferPlaybackCap = bufferSizeInFrames; + pDevice->wasapi.mappedBufferPlaybackLen = 0; + } else { + if (hr == MA_AUDCLNT_E_BUFFER_TOO_LARGE || hr == MA_AUDCLNT_E_BUFFER_ERROR) { + /* Not enough data available. We need to wait for more. */ + if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { + result = MA_ERROR; + break; /* Wait failed. Probably timed out. */ + } + } else { + /* Some error occurred. We'll need to abort. */ + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device. HRESULT = %d. Stopping device.\n", (int)hr); + result = ma_result_from_HRESULT(hr); + break; + } + } } } - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* Any mapped buffers need to be released. */ - if (pMappedDeviceBufferPlayback != NULL) { - hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0); - } + if (pFramesWritten != NULL) { + *pFramesWritten = totalFramesProcessed; } - return MA_SUCCESS; + return result; } static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice) @@ -16825,9 +22285,9 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ pCallbacks->onDeviceUninit = ma_device_uninit__wasapi; pCallbacks->onDeviceStart = ma_device_start__wasapi; pCallbacks->onDeviceStop = ma_device_stop__wasapi; - pCallbacks->onDeviceRead = NULL; /* Not used. Reading is done manually in the audio thread. */ - pCallbacks->onDeviceWrite = NULL; /* Not used. Writing is done manually in the audio thread. */ - pCallbacks->onDeviceDataLoop = ma_device_data_loop__wasapi; + pCallbacks->onDeviceRead = ma_device_read__wasapi; + pCallbacks->onDeviceWrite = ma_device_write__wasapi; + pCallbacks->onDeviceDataLoop = NULL; pCallbacks->onDeviceDataLoopWakeup = ma_device_data_loop_wakeup__wasapi; return MA_SUCCESS; @@ -17089,9 +22549,9 @@ struct ma_IDirectSoundCapture { ma_IDirectSoundCaptureVtbl* lpVtbl; }; -static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } -static MA_INLINE ULONG ma_IDirectSoundCapture_AddRef(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->AddRef(pThis); } -static MA_INLINE ULONG ma_IDirectSoundCapture_Release(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->Release(pThis); } +static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface (ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IDirectSoundCapture_AddRef (ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->AddRef(pThis); } +static MA_INLINE ULONG ma_IDirectSoundCapture_Release (ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->Release(pThis); } static MA_INLINE HRESULT ma_IDirectSoundCapture_CreateCaptureBuffer(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter) { return pThis->lpVtbl->CreateCaptureBuffer(pThis, pDSCBufferDesc, ppDSCBuffer, pUnkOuter); } static MA_INLINE HRESULT ma_IDirectSoundCapture_GetCaps (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCCaps); } static MA_INLINE HRESULT ma_IDirectSoundCapture_Initialize (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice) { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); } @@ -17250,7 +22710,8 @@ static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma pDirectSound = NULL; if (FAILED(((ma_DirectSoundCreateProc)pContext->dsound.DirectSoundCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSound, NULL))) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } /* The cooperative level must be set before doing anything else. */ @@ -17261,7 +22722,8 @@ static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma hr = ma_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == ma_share_mode_exclusive) ? MA_DSSCL_EXCLUSIVE : MA_DSSCL_PRIORITY); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device."); + return ma_result_from_HRESULT(hr); } *ppDirectSound = pDirectSound; @@ -17286,7 +22748,8 @@ static ma_result ma_context_create_IDirectSoundCapture__dsound(ma_context* pCont hr = ((ma_DirectSoundCaptureCreateProc)pContext->dsound.DirectSoundCaptureCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSoundCapture, NULL); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device."); + return ma_result_from_HRESULT(hr); } *ppDirectSoundCapture = pDirectSoundCapture; @@ -17317,7 +22780,8 @@ static ma_result ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_c caps.dwSize = sizeof(caps); hr = ma_IDirectSoundCapture_GetCaps(pDirectSoundCapture, &caps); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device."); + return ma_result_from_HRESULT(hr); } if (pChannels) { @@ -17552,7 +23016,8 @@ static ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_dev caps.dwSize = sizeof(caps); hr = ma_IDirectSound_GetCaps(pDirectSound, &caps); if (FAILED(hr)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device."); + return ma_result_from_HRESULT(hr); } @@ -17628,13 +23093,13 @@ static ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_dev /* The format is always an integer format and is based on the bits per sample. */ if (bitsPerSample == 8) { - pDeviceInfo->formats[0] = ma_format_u8; + pDeviceInfo->nativeDataFormats[0].format = ma_format_u8; } else if (bitsPerSample == 16) { - pDeviceInfo->formats[0] = ma_format_s16; + pDeviceInfo->nativeDataFormats[0].format = ma_format_s16; } else if (bitsPerSample == 24) { - pDeviceInfo->formats[0] = ma_format_s24; + pDeviceInfo->nativeDataFormats[0].format = ma_format_s24; } else if (bitsPerSample == 32) { - pDeviceInfo->formats[0] = ma_format_s32; + pDeviceInfo->nativeDataFormats[0].format = ma_format_s32; } else { return MA_FORMAT_NOT_SUPPORTED; } @@ -17727,8 +23192,11 @@ static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 c static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__dsound(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) { - /* DirectSound has a minimum period size of 20ms. */ - ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(20, nativeSampleRate); + /* + DirectSound has a minimum period size of 20ms. In practice, this doesn't seem to be enough for + reliable glitch-free processing so going to use 30ms instead. + */ + ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(30, nativeSampleRate); ma_uint32 periodSizeInFrames; periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile); @@ -17799,7 +23267,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device."); + return ma_result_from_HRESULT(hr); } /* Get the _actual_ properties of the buffer. */ @@ -17807,7 +23276,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer."); + return ma_result_from_HRESULT(hr); } /* We can now start setting the output data formats. */ @@ -17833,7 +23303,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device."); + return ma_result_from_HRESULT(hr); } } @@ -17869,7 +23340,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDSPrimary, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer."); + return ma_result_from_HRESULT(hr); } @@ -17879,7 +23351,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSound_GetCaps((ma_IDirectSound*)pDevice->dsound.pPlayback, &caps); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device."); + return ma_result_from_HRESULT(hr); } if (pDescriptorPlayback->channels == 0) { @@ -17921,7 +23394,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer."); + return ma_result_from_HRESULT(hr); } /* Get the _actual_ properties of the buffer. */ @@ -17929,7 +23403,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer."); + return ma_result_from_HRESULT(hr); } /* We now have enough information to start setting some output properties. */ @@ -17971,7 +23446,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer."); + return ma_result_from_HRESULT(hr); } /* DirectSound should give us a buffer exactly the size we asked for. */ @@ -18011,12 +23487,14 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) /* The first thing to do is start the capture device. The playback device is only started after the first period is written. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - if (FAILED(ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING))) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MA_FAILED_TO_START_BACKEND_DEVICE); + hr = ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING); + if (FAILED(hr)) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed."); + return ma_result_from_HRESULT(hr); } } - while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { + while (ma_device_get_state(pDevice) == ma_device_state_started) { switch (pDevice->type) { case ma_device_type_duplex: @@ -18065,7 +23543,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device."); + return ma_result_from_HRESULT(hr); } @@ -18091,7 +23570,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) outputFramesInClientFormatCount = (ma_uint32)clientCapturedFramesToProcess; mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess; - ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess); + ma_device__handle_data_callback(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess); /* At this point we have input and output data in client format. All we need to do now is convert it to the output device format. This may take a few passes. */ for (;;) { @@ -18119,7 +23598,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Play cursor has moved in front of the write cursor (same loop iteration). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); availableBytesPlayback = 0; } } else { @@ -18128,7 +23607,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); availableBytesPlayback = 0; } } @@ -18140,7 +23619,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); + return ma_result_from_HRESULT(hr); } isPlaybackDeviceStarted = MA_TRUE; } else { @@ -18162,7 +23642,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0); if (FAILED(hr)) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device."); + result = ma_result_from_HRESULT(hr); break; } @@ -18178,7 +23659,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) silentPaddingInBytes = lockSizeInBytesPlayback; } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes); } } @@ -18204,7 +23685,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, framesWrittenThisIteration*bpfDevicePlayback, NULL, 0); if (FAILED(hr)) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device."); + result = ma_result_from_HRESULT(hr); break; } @@ -18223,7 +23705,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); + return ma_result_from_HRESULT(hr); } isPlaybackDeviceStarted = MA_TRUE; } @@ -18242,7 +23725,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) /* At this point we're done with the mapped portion of the capture buffer. */ hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device."); + return ma_result_from_HRESULT(hr); } prevReadCursorInBytesCapture = (lockOffsetInBytesCapture + mappedSizeInBytesCapture); } break; @@ -18292,20 +23776,20 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device."); + result = ma_result_from_HRESULT(hr); } - #ifdef MA_DEBUG_OUTPUT if (lockSizeInBytesCapture != mappedSizeInBytesCapture) { ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture); } - #endif ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture); hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device."); + return ma_result_from_HRESULT(hr); } prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture; @@ -18339,7 +23823,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); availableBytesPlayback = 0; } } else { @@ -18348,7 +23832,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } else { /* This is an error. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); availableBytesPlayback = 0; } } @@ -18359,7 +23843,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) { hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); + return ma_result_from_HRESULT(hr); } isPlaybackDeviceStarted = MA_TRUE; } else { @@ -18380,7 +23865,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0); if (FAILED(hr)) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device."); + result = ma_result_from_HRESULT(hr); break; } @@ -18389,7 +23875,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, mappedSizeInBytesPlayback, NULL, 0); if (FAILED(hr)) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device."); + result = ma_result_from_HRESULT(hr); break; } @@ -18407,7 +23894,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames) { hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed."); + return ma_result_from_HRESULT(hr); } isPlaybackDeviceStarted = MA_TRUE; } @@ -18426,7 +23914,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { hr = ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed."); + return ma_result_from_HRESULT(hr); } } @@ -18474,7 +23963,8 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) hr = ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer); if (FAILED(hr)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.", ma_result_from_HRESULT(hr)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed."); + return ma_result_from_HRESULT(hr); } ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0); @@ -18789,10 +24279,10 @@ static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, if (((MA_PFN_RegOpenKeyExA)pContext->win32.RegOpenKeyExA)(HKEY_LOCAL_MACHINE, keyStr, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { BYTE nameFromReg[512]; DWORD nameFromRegSize = sizeof(nameFromReg); - result = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (LPBYTE)nameFromReg, (LPDWORD)&nameFromRegSize); + LONG resultWin32 = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (LPBYTE)nameFromReg, (LPDWORD)&nameFromRegSize); ((MA_PFN_RegCloseKey)pContext->win32.RegCloseKey)(hKey); - if (result == ERROR_SUCCESS) { + if (resultWin32 == ERROR_SUCCESS) { /* We have the value from the registry, so now we need to construct the name string. */ char name[1024]; if (ma_strcpy_s(name, sizeof(name), pDeviceInfo->name) == 0) { @@ -19000,7 +24490,7 @@ static ma_result ma_device_uninit__winmm(ma_device* pDevice) CloseHandle((HANDLE)pDevice->winmm.hEventPlayback); } - ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); MA_ZERO_OBJECT(&pDevice->winmm); /* Safety. */ @@ -19085,7 +24575,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi pDescriptorCapture->format = ma_format_from_WAVEFORMATEX(&wf); pDescriptorCapture->channels = wf.nChannels; pDescriptorCapture->sampleRate = wf.nSamplesPerSec; - ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorCapture->channels, pDescriptorCapture->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels); pDescriptorCapture->periodCount = pDescriptorCapture->periodCount; pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile); } @@ -19096,7 +24586,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi MMRESULT resultMM; /* We use an event to know when a new fragment needs to be enqueued. */ - pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL); + pDevice->winmm.hEventPlayback = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventPlayback == NULL) { errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError()); goto on_error; @@ -19123,7 +24613,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi pDescriptorPlayback->format = ma_format_from_WAVEFORMATEX(&wf); pDescriptorPlayback->channels = wf.nChannels; pDescriptorPlayback->sampleRate = wf.nSamplesPerSec; - ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels); pDescriptorPlayback->periodCount = pDescriptorPlayback->periodCount; pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); } @@ -19141,7 +24631,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi heapSize += sizeof(WAVEHDR)*pDescriptorPlayback->periodCount + (pDescriptorPlayback->periodSizeInFrames * pDescriptorPlayback->periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels)); } - pDevice->winmm._pHeapData = (ma_uint8*)ma__calloc_from_callbacks(heapSize, &pDevice->pContext->allocationCallbacks); + pDevice->winmm._pHeapData = (ma_uint8*)ma_calloc(heapSize, &pDevice->pContext->allocationCallbacks); if (pDevice->winmm._pHeapData == NULL) { errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY; goto on_error; @@ -19232,8 +24722,13 @@ on_error: ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback); } - ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, errorMsg, errorCode); + ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); + + if (errorMsg != NULL && errorMsg[0] != '\0') { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "%s", errorMsg); + } + + return errorCode; } static ma_result ma_device_start__winmm(ma_device* pDevice) @@ -19254,7 +24749,8 @@ static ma_result ma_device_start__winmm(ma_device* pDevice) for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.", ma_result_from_MMRESULT(resultMM)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture."); + return ma_result_from_MMRESULT(resultMM); } /* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */ @@ -19264,7 +24760,8 @@ static ma_result ma_device_start__winmm(ma_device* pDevice) /* Capture devices need to be explicitly started, unlike playback devices. */ resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture); if (resultMM != MMSYSERR_NOERROR) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", ma_result_from_MMRESULT(resultMM)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device."); + return ma_result_from_MMRESULT(resultMM); } } @@ -19288,7 +24785,7 @@ static ma_result ma_device_stop__winmm(ma_device* pDevice) resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDeviceCapture); if (resultMM != MMSYSERR_NOERROR) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset capture device.", ma_result_from_MMRESULT(resultMM)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset capture device."); } } @@ -19314,7 +24811,7 @@ static ma_result ma_device_stop__winmm(ma_device* pDevice) resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback); if (resultMM != MMSYSERR_NOERROR) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset playback device.", ma_result_from_MMRESULT(resultMM)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset playback device."); } } @@ -19369,7 +24866,7 @@ static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFram resultMM = ((MA_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &pWAVEHDR[pDevice->winmm.iNextHeaderPlayback], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { result = ma_result_from_MMRESULT(resultMM); - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed."); break; } @@ -19401,7 +24898,7 @@ static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFram } /* If the device has been stopped we need to break. */ - if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { + if (ma_device_get_state(pDevice) != ma_device_state_started) { break; } } @@ -19458,7 +24955,7 @@ static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_ resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[pDevice->winmm.iNextHeaderCapture], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { result = ma_result_from_MMRESULT(resultMM); - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed."); break; } @@ -19490,7 +24987,7 @@ static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_ } /* If the device has been stopped we need to break. */ - if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { + if (ma_device_get_state(pDevice) != ma_device_state_started) { break; } } @@ -20206,7 +25703,8 @@ static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode s } if (!isDeviceOpen) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } } else { /* @@ -20254,7 +25752,8 @@ static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode s } if (resultALSA < 0) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.", ma_result_from_errno(-resultALSA)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed."); + return ma_result_from_errno(-resultALSA); } } @@ -20325,9 +25824,8 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu goto next_device; /* The device has already been enumerated. Move on to the next one. */ } else { /* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */ - size_t oldCapacity = sizeof(*pUniqueIDs) * uniqueIDCount; size_t newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1); - ma_device_id* pNewUniqueIDs = (ma_device_id*)ma__realloc_from_callbacks(pUniqueIDs, newCapacity, oldCapacity, &pContext->allocationCallbacks); + ma_device_id* pNewUniqueIDs = (ma_device_id*)ma_realloc(pUniqueIDs, newCapacity, &pContext->allocationCallbacks); if (pNewUniqueIDs == NULL) { goto next_device; /* Failed to allocate memory. */ } @@ -20392,10 +25890,11 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu /* Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback - again for the other device type in this case. We do this for known devices. + again for the other device type in this case. We do this for known devices and where the IOID hint is NULL, which + means both Input and Output. */ if (cbResult) { - if (ma_is_common_device_name__alsa(NAME)) { + if (ma_is_common_device_name__alsa(NAME) || IOID == NULL) { if (deviceType == ma_device_type_playback) { if (!ma_is_capture_device_blacklisted__alsa(NAME)) { cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); @@ -20424,7 +25923,7 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu } } - ma__free_from_callbacks(pUniqueIDs, &pContext->allocationCallbacks); + ma_free(pUniqueIDs, &pContext->allocationCallbacks); ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock); @@ -20548,7 +26047,7 @@ static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_devic } /* We need to initialize a HW parameters object in order to know what formats are supported. */ - pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks); + pHWParams = (ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks); if (pHWParams == NULL) { ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); return MA_OUT_OF_MEMORY; @@ -20556,9 +26055,10 @@ static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_devic resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks); + ma_free(pHWParams, &pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA)); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed."); + return ma_result_from_errno(-resultALSA); } /* @@ -20642,7 +26142,7 @@ static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_devic } } - ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks); + ma_free(pHWParams, &pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); return MA_SUCCESS; @@ -20712,16 +26212,19 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic /* Hardware parameters. */ - pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_hw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); + pHWParams = (ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_hw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); if (pHWParams == NULL) { + ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for hardware parameters."); return MA_OUT_OF_MEMORY; } resultALSA = ((ma_snd_pcm_hw_params_any_proc)pDevice->pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed."); + return ma_result_from_errno(-resultALSA); } /* MMAP Mode. Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. */ @@ -20739,9 +26242,10 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic if (!isUsingMMap) { resultALSA = ((ma_snd_pcm_hw_params_set_access_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_RW_INTERLEAVED); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed."); + return ma_result_from_errno(-resultALSA); } } @@ -20769,24 +26273,27 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic } if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats."); + return MA_FORMAT_NOT_SUPPORTED; } } resultALSA = ((ma_snd_pcm_hw_params_set_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed."); + return ma_result_from_errno(-resultALSA); } internalFormat = ma_format_from_alsa(formatALSA); if (internalFormat == ma_format_unknown) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio."); + return MA_FORMAT_NOT_SUPPORTED; } } @@ -20799,9 +26306,10 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_channels_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed."); + return ma_result_from_errno(-resultALSA); } internalChannels = (ma_uint32)channels; @@ -20837,9 +26345,10 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_rate_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed."); + return ma_result_from_errno(-resultALSA); } internalSampleRate = (ma_uint32)sampleRate; @@ -20851,9 +26360,10 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_periods_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed."); + return ma_result_from_errno(-resultALSA); } internalPeriods = periods; @@ -20865,9 +26375,10 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic resultALSA = ((ma_snd_pcm_hw_params_set_buffer_size_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM, pHWParams, &actualBufferSizeInFrames); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed."); + return ma_result_from_errno(-resultALSA); } internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods; @@ -20876,34 +26387,38 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic /* Apply hardware parameters. */ resultALSA = ((ma_snd_pcm_hw_params_proc)pDevice->pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams); if (resultALSA < 0) { - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed."); + return ma_result_from_errno(-resultALSA); } - ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pHWParams, &pDevice->pContext->allocationCallbacks); pHWParams = NULL; /* Software parameters. */ - pSWParams = (ma_snd_pcm_sw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_sw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_sw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); + pSWParams = (ma_snd_pcm_sw_params_t*)ma_calloc(((ma_snd_pcm_sw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_sw_params_sizeof)(), &pDevice->pContext->allocationCallbacks); if (pSWParams == NULL) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for software parameters."); return MA_OUT_OF_MEMORY; } resultALSA = ((ma_snd_pcm_sw_params_current_proc)pDevice->pContext->alsa.snd_pcm_sw_params_current)(pPCM, pSWParams); if (resultALSA < 0) { - ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed."); + return ma_result_from_errno(-resultALSA); } resultALSA = ((ma_snd_pcm_sw_params_set_avail_min_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_avail_min)(pPCM, pSWParams, ma_prev_power_of_2(internalPeriodSizeInFrames)); if (resultALSA < 0) { - ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed."); + return ma_result_from_errno(-resultALSA); } resultALSA = ((ma_snd_pcm_sw_params_get_boundary_proc)pDevice->pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary); @@ -20918,27 +26433,30 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic */ resultALSA = ((ma_snd_pcm_sw_params_set_start_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalPeriodSizeInFrames*2); if (resultALSA < 0) { - ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed."); + return ma_result_from_errno(-resultALSA); } resultALSA = ((ma_snd_pcm_sw_params_set_stop_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM, pSWParams, bufferBoundary); if (resultALSA < 0) { /* Set to boundary to loop instead of stop in the event of an xrun. */ - ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed."); + return ma_result_from_errno(-resultALSA); } } resultALSA = ((ma_snd_pcm_sw_params_proc)pDevice->pContext->alsa.snd_pcm_sw_params)(pPCM, pSWParams); if (resultALSA < 0) { - ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed."); + return ma_result_from_errno(-resultALSA); } - ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks); + ma_free(pSWParams, &pDevice->pContext->allocationCallbacks); pSWParams = NULL; @@ -20964,7 +26482,7 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic ma_bool32 isValid = MA_TRUE; /* Fill with defaults. */ - ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels); /* Overwrite first pChmap->channels channels. */ for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) { @@ -20984,7 +26502,7 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic /* If our channel map is invalid, fall back to defaults. */ if (!isValid) { - ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels); } } @@ -20992,7 +26510,7 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic pChmap = NULL; } else { /* Could not retrieve the channel map. Fall back to a hard-coded assumption. */ - ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels); } } @@ -21005,13 +26523,15 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic pollDescriptorCount = ((ma_snd_pcm_poll_descriptors_count_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_count)(pPCM); if (pollDescriptorCount <= 0) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors count.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors count."); + return MA_ERROR; } - pPollDescriptors = (struct pollfd*)ma_malloc(sizeof(*pPollDescriptors) * (pollDescriptorCount + 1), &pDevice->pContext->allocationCallbacks/*, MA_ALLOCATION_TYPE_GENERAL*/); /* +1 because we want room for the wakeup descriptor. */ + pPollDescriptors = (struct pollfd*)ma_malloc(sizeof(*pPollDescriptors) * (pollDescriptorCount + 1), &pDevice->pContext->allocationCallbacks); /* +1 because we want room for the wakeup descriptor. */ if (pPollDescriptors == NULL) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for poll descriptors.", MA_OUT_OF_MEMORY); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for poll descriptors."); + return MA_OUT_OF_MEMORY; } /* @@ -21022,7 +26542,8 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic if (wakeupfd < 0) { ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to create eventfd for poll wakeup.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to create eventfd for poll wakeup."); + return ma_result_from_errno(errno); } /* We'll place the wakeup fd at the start of the buffer. */ @@ -21036,7 +26557,8 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic close(wakeupfd); ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors."); + return MA_ERROR; } if (deviceType == ma_device_type_capture) { @@ -21056,7 +26578,8 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic close(wakeupfd); ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device."); + return ma_result_from_errno(-resultALSA); } @@ -21112,7 +26635,8 @@ static ma_result ma_device_start__alsa(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); if (resultALSA < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device."); + return ma_result_from_errno(-resultALSA); } } @@ -21126,30 +26650,30 @@ static ma_result ma_device_start__alsa(ma_device* pDevice) static ma_result ma_device_stop__alsa(ma_device* pDevice) { if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device... "); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...\n"); ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device successful.\n"); /* We need to prepare the device again, otherwise we won't be able to restart the device. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device... "); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device...\n"); if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device failed.\n"); } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device successful.\n"); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device... "); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device...\n"); ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device successful.\n"); /* We need to prepare the device again, otherwise we won't be able to restart the device. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device... "); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device...\n"); if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device failed.\n"); } else { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device successful.\n"); } } @@ -21163,7 +26687,8 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st int resultALSA; int resultPoll = poll(pPollDescriptors, pollDescriptorCount, -1); if (resultPoll < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] poll() failed.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] poll() failed."); + return ma_result_from_errno(errno); } /* @@ -21173,10 +26698,13 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st */ if ((pPollDescriptors[0].revents & POLLIN) != 0) { ma_uint64 t; - read(pPollDescriptors[0].fd, &t, sizeof(t)); /* <-- Important that we read here so that the next write() does not block. */ + int resultRead = read(pPollDescriptors[0].fd, &t, sizeof(t)); /* <-- Important that we read here so that the next write() does not block. */ + if (resultRead < 0) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] read() failed."); + return ma_result_from_errno(errno); + } ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] POLLIN set for wakeupfd\n"); - return MA_DEVICE_NOT_STARTED; } @@ -21186,11 +26714,13 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st */ resultALSA = ((ma_snd_pcm_poll_descriptors_revents_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_revents)(pPCM, pPollDescriptors + 1, pollDescriptorCount - 1, &revents); /* +1, -1 to ignore the wakeup descriptor. */ if (resultALSA < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_poll_descriptors_revents() failed.", ma_result_from_errno(-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_poll_descriptors_revents() failed."); + return ma_result_from_errno(-resultALSA); } if ((revents & POLLERR) != 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] POLLERR detected.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] POLLERR detected."); + return ma_result_from_errno(errno); } if ((revents & requiredEvent) == requiredEvent) { @@ -21213,7 +26743,7 @@ static ma_result ma_device_wait_write__alsa(ma_device* pDevice) static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead) { - ma_snd_pcm_sframes_t resultALSA; + ma_snd_pcm_sframes_t resultALSA = 0; MA_ASSERT(pDevice != NULL); MA_ASSERT(pFramesOut != NULL); @@ -21222,7 +26752,7 @@ static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_u *pFramesRead = 0; } - while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { + while (ma_device_get_state(pDevice) == ma_device_state_started) { ma_result result; /* The first thing to do is wait for data to become available for reading. This will return an error code if the device has been stopped. */ @@ -21237,20 +26767,22 @@ static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_u break; /* Success. */ } else { if (resultALSA == -EAGAIN) { - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "TRACE: EGAIN (read)\n");*/ + /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EGAIN (read)\n");*/ continue; /* Try again. */ } else if (resultALSA == -EPIPE) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "TRACE: EPIPE (read)\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (read)\n"); /* Overrun. Recover and try again. If this fails we need to return an error. */ resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, resultALSA, MA_TRUE); if (resultALSA < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.", ma_result_from_errno((int)-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun."); + return ma_result_from_errno((int)-resultALSA); } resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); if (resultALSA < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun."); + return ma_result_from_errno((int)-resultALSA); } continue; /* Try reading again. */ @@ -21267,7 +26799,7 @@ static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_u static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) { - ma_snd_pcm_sframes_t resultALSA; + ma_snd_pcm_sframes_t resultALSA = 0; MA_ASSERT(pDevice != NULL); MA_ASSERT(pFrames != NULL); @@ -21276,7 +26808,7 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, *pFramesWritten = 0; } - while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { + while (ma_device_get_state(pDevice) == ma_device_state_started) { ma_result result; /* The first thing to do is wait for space to become available for writing. This will return an error code if the device has been stopped. */ @@ -21290,15 +26822,16 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, break; /* Success. */ } else { if (resultALSA == -EAGAIN) { - /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "TRACE: EGAIN (write)\n");*/ + /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EGAIN (write)\n");*/ continue; /* Try again. */ } else if (resultALSA == -EPIPE) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "TRACE: EPIPE (write)\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (write)\n"); /* Underrun. Recover and try again. If this fails we need to return an error. */ resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE); /* MA_TRUE=silent (don't print anything on error). */ if (resultALSA < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.", ma_result_from_errno((int)-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun."); + return ma_result_from_errno((int)-resultALSA); } /* @@ -21310,7 +26843,8 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, */ resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); if (resultALSA < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun."); + return ma_result_from_errno((int)-resultALSA); } continue; /* Try writing again. */ @@ -21328,20 +26862,26 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, static ma_result ma_device_data_loop_wakeup__alsa(ma_device* pDevice) { ma_uint64 t = 1; + int resultWrite = 0; MA_ASSERT(pDevice != NULL); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up... "); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up...\n"); /* Write to an eventfd to trigger a wakeup from poll() and abort any reading or writing. */ if (pDevice->alsa.pPollDescriptorsCapture != NULL) { - write(pDevice->alsa.wakeupfdCapture, &t, sizeof(t)); + resultWrite = write(pDevice->alsa.wakeupfdCapture, &t, sizeof(t)); } if (pDevice->alsa.pPollDescriptorsPlayback != NULL) { - write(pDevice->alsa.wakeupfdPlayback, &t, sizeof(t)); + resultWrite = write(pDevice->alsa.wakeupfdPlayback, &t, sizeof(t)); } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); + if (resultWrite < 0) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] write() failed.\n"); + return ma_result_from_errno(errno); + } + + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up completed successfully.\n"); return MA_SUCCESS; } @@ -21365,6 +26905,7 @@ static ma_result ma_context_uninit__alsa(ma_context* pContext) static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) { + ma_result result; #ifndef MA_NO_RUNTIME_LINKING const char* libasoundNames[] = { "libasound.so.2", @@ -21589,8 +27130,10 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pContext->alsa.useVerboseDeviceEnumeration = pConfig->alsa.useVerboseDeviceEnumeration; - if (ma_mutex_init(&pContext->alsa.internalDeviceEnumLock) != MA_SUCCESS) { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.", MA_ERROR); + result = ma_mutex_init(&pContext->alsa.internalDeviceEnumLock); + if (result != MA_SUCCESS) { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration."); + return result; } pCallbacks->onContextInit = ma_context_init__alsa; @@ -21692,7 +27235,7 @@ that point (it may still need to load files or whatnot). Instead, this callback stream be started which is how it works with literally *every* other callback-based audio API. Since miniaudio forbids firing of the data callback until the device has been started (as it should be with *all* callback based APIs), logic needs to be added to ensure miniaudio doesn't just blindly fire the application-defined data callback from within the PulseAudio callback before the stream has actually been -started. The device state is used for this - if the state is anything other than `MA_STATE_STARTING` or `MA_STATE_STARTED`, the main data +started. The device state is used for this - if the state is anything other than `ma_device_state_starting` or `ma_device_state_started`, the main data callback is not fired. This, unfortunately, is not the end of the problems with the PulseAudio write callback. Any normal callback based audio API will @@ -22288,6 +27831,7 @@ typedef const char* (* ma_pa_stream_get_device_name_proc) ( typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); +typedef void (* ma_pa_stream_set_moved_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); @@ -22482,7 +28026,7 @@ static ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position } #endif -static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_operation* pOP) +static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP) { int resultPA; ma_pa_operation_state_t state; @@ -22496,7 +28040,7 @@ static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_operat break; /* Done. */ } - resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL); + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); if (resultPA < 0) { return ma_result_from_pulse(resultPA); } @@ -22505,7 +28049,7 @@ static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_operat return MA_SUCCESS; } -static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma_pa_operation* pOP) +static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP) { ma_result result; @@ -22513,28 +28057,29 @@ static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma return MA_INVALID_ARGS; } - result = ma_wait_for_operation__pulse(pContext, pOP); + result = ma_wait_for_operation__pulse(pContext, pMainLoop, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); return result; } -static ma_result ma_context_wait_for_pa_context_to_connect__pulse(ma_context* pContext) +static ma_result ma_wait_for_pa_context_to_connect__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_ptr pPulseContext) { int resultPA; ma_pa_context_state_t state; for (;;) { - state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pContext->pulse.pPulseContext); + state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pPulseContext); if (state == MA_PA_CONTEXT_READY) { break; /* Done. */ } if (state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context.", MA_ERROR); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context."); + return MA_ERROR; } - resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL); + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); if (resultPA < 0) { return ma_result_from_pulse(resultPA); } @@ -22544,22 +28089,23 @@ static ma_result ma_context_wait_for_pa_context_to_connect__pulse(ma_context* pC return MA_SUCCESS; } -static ma_result ma_context_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, ma_pa_stream* pStream) +static ma_result ma_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_ptr pStream) { int resultPA; ma_pa_stream_state_t state; for (;;) { - state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)(pStream); + state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)((ma_pa_stream*)pStream); if (state == MA_PA_STREAM_READY) { break; /* Done. */ } if (state == MA_PA_STREAM_FAILED || state == MA_PA_STREAM_TERMINATED) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio stream.", MA_ERROR); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio stream."); + return MA_ERROR; } - resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL); + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); if (resultPA < 0) { return ma_result_from_pulse(resultPA); } @@ -22569,6 +28115,52 @@ static ma_result ma_context_wait_for_pa_stream_to_connect__pulse(ma_context* pCo } +static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, const char* pApplicationName, const char* pServerName, ma_bool32 tryAutoSpawn, ma_ptr* ppMainLoop, ma_ptr* ppPulseContext) +{ + ma_result result; + ma_ptr pMainLoop; + ma_ptr pPulseContext; + + MA_ASSERT(ppMainLoop != NULL); + MA_ASSERT(ppPulseContext != NULL); + + /* The PulseAudio context maps well to miniaudio's notion of a context. The pa_context object will be initialized as part of the ma_context. */ + pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); + if (pMainLoop == NULL) { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create mainloop."); + return MA_FAILED_TO_INIT_BACKEND; + } + + pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pMainLoop), pApplicationName); + if (pPulseContext == NULL) { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context."); + ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); + return MA_FAILED_TO_INIT_BACKEND; + } + + /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ + result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); + if (result != MA_SUCCESS) { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context."); + ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); + return result; + } + + /* Since ma_context_init() runs synchronously we need to wait for the PulseAudio context to connect before we return. */ + result = ma_wait_for_pa_context_to_connect__pulse(pContext, pMainLoop, pPulseContext); + if (result != MA_SUCCESS) { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Waiting for connection failed."); + ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); + return result; + } + + *ppMainLoop = pMainLoop; + *ppPulseContext = pPulseContext; + + return MA_SUCCESS; +} + + static void ma_device_sink_info_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) { ma_pa_sink_info* pInfoOut; @@ -22601,6 +28193,7 @@ static void ma_device_source_info_callback(ma_pa_context* pPulseContext, const m (void)pPulseContext; /* Unused. */ } +#if 0 static void ma_device_sink_name_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) { ma_device* pDevice; @@ -22632,7 +28225,7 @@ static void ma_device_source_name_callback(ma_pa_context* pPulseContext, const m (void)pPulseContext; /* Unused. */ } - +#endif static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_sink_info* pSinkInfo) { @@ -22643,7 +28236,7 @@ static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const cha return MA_ERROR; } - return ma_wait_for_operation_and_unref__pulse(pContext, pOP); + return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); } static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_source_info* pSourceInfo) @@ -22655,7 +28248,7 @@ static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const c return MA_ERROR; } - return ma_wait_for_operation_and_unref__pulse(pContext, pOP);; + return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); } static ma_result ma_context_get_default_device_index__pulse(ma_context* pContext, ma_device_type deviceType, ma_uint32* pIndex) @@ -22799,7 +28392,7 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en goto done; } - result = ma_wait_for_operation__pulse(pContext, pOP); + result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); if (result != MA_SUCCESS) { @@ -22816,7 +28409,7 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en goto done; } - result = ma_wait_for_operation__pulse(pContext, pOP); + result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); if (result != MA_SUCCESS) { @@ -22937,7 +28530,7 @@ static ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_devi } if (pOP != NULL) { - ma_wait_for_operation_and_unref__pulse(pContext, pOP); + ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); } else { result = MA_ERROR; goto done; @@ -22975,6 +28568,10 @@ static ma_result ma_device_uninit__pulse(ma_device* pDevice) ma_duplex_rb_uninit(&pDevice->duplexRB); } + ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext); + ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext); + ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop); + return MA_SUCCESS; } @@ -22990,7 +28587,7 @@ static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFra return attr; } -static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap) +static ma_pa_stream* ma_device__pa_stream_new__pulse(ma_device* pDevice, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap) { static int g_StreamCounter = 0; char actualStreamName[256]; @@ -23003,7 +28600,7 @@ static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, cons } g_StreamCounter += 1; - return ((ma_pa_stream_new_proc)pContext->pulse.pa_stream_new)((ma_pa_context*)pContext->pulse.pPulseContext, actualStreamName, ss, cmap); + return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap); } @@ -23022,7 +28619,7 @@ static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, vo can fire this callback before the stream has even started. Ridiculous. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != MA_STATE_STARTING && deviceState != MA_STATE_STARTED) { + if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) { return; } @@ -23032,7 +28629,7 @@ static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, vo frameCount = byteCount / bpf; framesProcessed = 0; - while (ma_device_get_state(pDevice) == MA_STATE_STARTED && framesProcessed < frameCount) { + while (ma_device_get_state(pDevice) == ma_device_state_started && framesProcessed < frameCount) { const void* pMappedPCMFrames; size_t bytesMapped; ma_uint64 framesMapped; @@ -23094,7 +28691,7 @@ static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stre framesMapped = bytesMapped / bpf; - if (deviceState == MA_STATE_STARTED || deviceState == MA_STATE_STARTING) { /* Check for starting state just in case this is being used to do the initial fill. */ + if (deviceState == ma_device_state_started || deviceState == ma_device_state_starting) { /* Check for starting state just in case this is being used to do the initial fill. */ ma_device_handle_backend_data_callback(pDevice, pMappedPCMFrames, NULL, framesMapped); } else { /* Device is not started. Write silence. */ @@ -23109,7 +28706,7 @@ static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stre framesProcessed += framesMapped; } else { - result = MA_ERROR; /* No data available. Abort. */ + result = MA_SUCCESS; /* No data available for writing. */ goto done; } } else { @@ -23141,7 +28738,7 @@ static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, v can fire this callback before the stream has even started. Ridiculous. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != MA_STATE_STARTING && deviceState != MA_STATE_STARTED) { + if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) { return; } @@ -23156,7 +28753,7 @@ static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, v /* Don't keep trying to process frames if the device isn't started. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != MA_STATE_STARTING && deviceState != MA_STATE_STARTED) { + if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) { break; } @@ -23185,13 +28782,47 @@ static void ma_device_on_suspended__pulse(ma_pa_stream* pStream, void* pUserData if (suspended == 1) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n"); - - if (pDevice->onStop) { - pDevice->onStop(pDevice); - } + ma_device__on_notification_stopped(pDevice); } else { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n"); - } + ma_device__on_notification_started(pDevice); + } +} + +static void ma_device_on_rerouted__pulse(ma_pa_stream* pStream, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + + (void)pStream; + (void)pUserData; + + ma_device__on_notification_rerouted(pDevice); +} + +static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__pulse(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) +{ + /* + There have been reports from users where buffers of < ~20ms result glitches when running through + PipeWire. To work around this we're going to have to use a different default buffer size. + */ + const ma_uint32 defaultPeriodSizeInMilliseconds_LowLatency = 25; + const ma_uint32 defaultPeriodSizeInMilliseconds_Conservative = MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE; + + MA_ASSERT(nativeSampleRate != 0); + + if (pDescriptor->periodSizeInFrames == 0) { + if (pDescriptor->periodSizeInMilliseconds == 0) { + if (performanceProfile == ma_performance_profile_low_latency) { + return ma_calculate_buffer_size_in_frames_from_milliseconds(defaultPeriodSizeInMilliseconds_LowLatency, nativeSampleRate); + } else { + return ma_calculate_buffer_size_in_frames_from_milliseconds(defaultPeriodSizeInMilliseconds_Conservative, nativeSampleRate); + } + } else { + return ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate); + } + } else { + return pDescriptor->periodSizeInFrames; + } } static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) @@ -23263,10 +28894,18 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi sampleRate = pDescriptorCapture->sampleRate; } + + + result = ma_init_pa_mainloop_and_pa_context__pulse(pDevice->pContext, pDevice->pContext->pulse.pApplicationName, pDevice->pContext->pulse.pServerName, MA_FALSE, &pDevice->pulse.pMainLoop, &pDevice->pulse.pPulseContext); + if (result != MA_SUCCESS) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize PA mainloop and context for device.\n"); + return result; + } + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { result = ma_context_get_source_info__pulse(pDevice->pContext, devCapture, &sourceInfo); if (result != MA_SUCCESS) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device."); goto on_error0; } @@ -23279,26 +28918,27 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi } else { ss.format = MA_PA_SAMPLE_FLOAT32BE; } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_RATE_FLOAT32\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n"); } if (ss.rate == 0) { ss.rate = MA_DEFAULT_SAMPLE_RATE; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.rate = 0. Defaulting to %d\n", ss.rate); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate); } if (ss.channels == 0) { ss.channels = MA_DEFAULT_CHANNELS; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.channels = 0. Defaulting to %d\n", ss.channels); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels); } /* We now have enough information to calculate our actual period size in frames. */ - pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, ss.rate, pConfig->performanceProfile); + pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__pulse(pDescriptorCapture, ss.rate, pConfig->performanceProfile); attr = ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodCount, &ss); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); - pDevice->pulse.pStreamCapture = ma_context__pa_stream_new__pulse(pDevice->pContext, pConfig->pulse.pStreamNameCapture, &ss, &cmap); + pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap); if (pDevice->pulse.pStreamCapture == NULL) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.\n"); + result = MA_ERROR; goto on_error0; } @@ -23309,6 +28949,9 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi /* State callback for checking when the device has been corked. */ ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_suspended__pulse, pDevice); + /* Rerouting notification. */ + ((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_rerouted__pulse, pDevice); + /* Connect after we've got all of our internal state set up. */ streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; @@ -23318,33 +28961,64 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); if (error != MA_PA_OK) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.", ma_result_from_pulse(error)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream."); + result = ma_result_from_pulse(error); goto on_error1; } - result = ma_context_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, (ma_pa_stream*)pDevice->pulse.pStreamCapture); + result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamCapture); if (result != MA_SUCCESS) { goto on_error2; } + /* Internal format. */ pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (pActualSS != NULL) { ss = *pActualSS; + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate); + } else { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve capture sample spec.\n"); } pDescriptorCapture->format = ma_format_from_pulse(ss.format); pDescriptorCapture->channels = ss.channels; pDescriptorCapture->sampleRate = ss.rate; - /* Internal channel map. */ - pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture); - if (pActualCMap != NULL) { - cmap = *pActualCMap; + if (pDescriptorCapture->format == ma_format_unknown || pDescriptorCapture->channels == 0 || pDescriptorCapture->sampleRate == 0) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Capture sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorCapture->format), pDescriptorCapture->channels, pDescriptorCapture->sampleRate); + result = MA_ERROR; + goto on_error4; } - for (iChannel = 0; iChannel < pDescriptorCapture->channels; ++iChannel) { - pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); + /* Internal channel map. */ + + /* + Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting + the channel map. To somewhat workaround this, I'm hacking in a hard coded channel map for mono + and stereo. In this case it should be safe to assume mono = MONO and stereo = LEFT/RIGHT. For + all other channel counts we need to just put up with whatever PipeWire reports and hope it gets + fixed sooner than later. I might remove this hack later. + */ + if (pDescriptorCapture->channels > 2) { + pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + if (pActualCMap != NULL) { + cmap = *pActualCMap; + } + + for (iChannel = 0; iChannel < pDescriptorCapture->channels; ++iChannel) { + pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); + } + } else { + /* Hack for mono and stereo. */ + if (pDescriptorCapture->channels == 1) { + pDescriptorCapture->channelMap[0] = MA_CHANNEL_MONO; + } else if (pDescriptorCapture->channels == 2) { + pDescriptorCapture->channelMap[0] = MA_CHANNEL_FRONT_LEFT; + pDescriptorCapture->channelMap[1] = MA_CHANNEL_FRONT_RIGHT; + } else { + MA_ASSERT(MA_FALSE); /* Should never hit this. */ + } } @@ -23354,24 +29028,20 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi attr = *pActualAttr; } - pDescriptorCapture->periodCount = attr.maxlength / attr.fragsize; - pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount; - - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); - - - /* Name. */ - devCapture = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture); - if (devCapture != NULL) { - ma_pa_operation* pOP = ((ma_pa_context_get_source_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pContext->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice); - ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); + if (attr.fragsize > 0) { + pDescriptorCapture->periodCount = ma_max(attr.maxlength / attr.fragsize, 1); + } else { + pDescriptorCapture->periodCount = 1; } + + pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount; + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { result = ma_context_get_sink_info__pulse(pDevice->pContext, devPlayback, &sinkInfo); if (result != MA_SUCCESS) { - ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.\n"); goto on_error2; } @@ -23384,40 +29054,44 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi } else { ss.format = MA_PA_SAMPLE_FLOAT32BE; } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_RATE_FLOAT32\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n"); } if (ss.rate == 0) { ss.rate = MA_DEFAULT_SAMPLE_RATE; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.rate = 0. Defaulting to %d\n", ss.rate); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate); } if (ss.channels == 0) { ss.channels = MA_DEFAULT_CHANNELS; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.channels = 0. Defaulting to %d\n", ss.channels); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels); } /* We now have enough information to calculate the actual buffer size in frames. */ - pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, ss.rate, pConfig->performanceProfile); + pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__pulse(pDescriptorPlayback, ss.rate, pConfig->performanceProfile); attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); - pDevice->pulse.pStreamPlayback = ma_context__pa_stream_new__pulse(pDevice->pContext, pConfig->pulse.pStreamNamePlayback, &ss, &cmap); + pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap); if (pDevice->pulse.pStreamPlayback == NULL) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.\n"); + result = MA_ERROR; goto on_error2; } /* Note that this callback will be fired as soon as the stream is connected, even though it's started as corked. The callback needs to handle a - device state of MA_STATE_UNINITIALIZED. + device state of ma_device_state_uninitialized. */ ((ma_pa_stream_set_write_callback_proc)pDevice->pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice); /* State callback for checking when the device has been corked. */ ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_suspended__pulse, pDevice); + /* Rerouting notification. */ + ((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_rerouted__pulse, pDevice); + /* Connect after we've got all of our internal state set up. */ streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; @@ -23427,11 +29101,12 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); if (error != MA_PA_OK) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.", ma_result_from_pulse(error)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream."); + result = ma_result_from_pulse(error); goto on_error3; } - result = ma_context_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, (ma_pa_stream*)pDevice->pulse.pStreamPlayback); + result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (result != MA_SUCCESS) { goto on_error3; } @@ -23441,20 +29116,49 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (pActualSS != NULL) { ss = *pActualSS; + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate); + } else { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve playback sample spec.\n"); } pDescriptorPlayback->format = ma_format_from_pulse(ss.format); pDescriptorPlayback->channels = ss.channels; pDescriptorPlayback->sampleRate = ss.rate; - /* Internal channel map. */ - pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); - if (pActualCMap != NULL) { - cmap = *pActualCMap; + if (pDescriptorPlayback->format == ma_format_unknown || pDescriptorPlayback->channels == 0 || pDescriptorPlayback->sampleRate == 0) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Playback sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorPlayback->format), pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate); + result = MA_ERROR; + goto on_error4; } - for (iChannel = 0; iChannel < pDescriptorPlayback->channels; ++iChannel) { - pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); + /* Internal channel map. */ + + /* + Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting + the channel map. To somewhat workaround this, I'm hacking in a hard coded channel map for mono + and stereo. In this case it should be safe to assume mono = MONO and stereo = LEFT/RIGHT. For + all other channel counts we need to just put up with whatever PipeWire reports and hope it gets + fixed sooner than later. I might remove this hack later. + */ + if (pDescriptorPlayback->channels > 2) { + pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + if (pActualCMap != NULL) { + cmap = *pActualCMap; + } + + for (iChannel = 0; iChannel < pDescriptorPlayback->channels; ++iChannel) { + pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); + } + } else { + /* Hack for mono and stereo. */ + if (pDescriptorPlayback->channels == 1) { + pDescriptorPlayback->channelMap[0] = MA_CHANNEL_MONO; + } else if (pDescriptorPlayback->channels == 2) { + pDescriptorPlayback->channelMap[0] = MA_CHANNEL_FRONT_LEFT; + pDescriptorPlayback->channelMap[1] = MA_CHANNEL_FRONT_RIGHT; + } else { + MA_ASSERT(MA_FALSE); /* Should never hit this. */ + } } @@ -23464,17 +29168,14 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi attr = *pActualAttr; } - pDescriptorPlayback->periodCount = attr.maxlength / attr.tlength; - pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); - - - /* Name. */ - devPlayback = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); - if (devPlayback != NULL) { - ma_pa_operation* pOP = ((ma_pa_context_get_sink_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pContext->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice); - ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); + if (attr.tlength > 0) { + pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1); + } else { + pDescriptorPlayback->periodCount = 1; } + + pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount; + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); } @@ -23485,9 +29186,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi onDeviceDataLoop callback is NULL, which is not the case for PulseAudio. */ if (pConfig->deviceType == ma_device_type_duplex) { - result = ma_duplex_rb_init(format, channels, sampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB); + ma_format rbFormat = (format != ma_format_unknown) ? format : pDescriptorCapture->format; + ma_uint32 rbChannels = (channels > 0) ? channels : pDescriptorCapture->channels; + ma_uint32 rbSampleRate = (sampleRate > 0) ? sampleRate : pDescriptorCapture->sampleRate; + + result = ma_duplex_rb_init(rbFormat, rbChannels, rbSampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB); if (result != MA_SUCCESS) { - result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer.", result); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer. %s.\n", ma_result_description(result)); goto on_error4; } } @@ -23546,20 +29251,19 @@ static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_typ pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful); if (pOP == NULL) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.", (cork == 0) ? MA_FAILED_TO_START_BACKEND_DEVICE : MA_FAILED_TO_STOP_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream."); + return MA_ERROR; } - result = ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); + result = ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP); if (result != MA_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork."); + return result; } if (!wasSuccessful) { - if (cork) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to stop PulseAudio stream.", MA_FAILED_TO_STOP_BACKEND_DEVICE); - } else { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to start PulseAudio stream.", MA_FAILED_TO_START_BACKEND_DEVICE); - } + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to %s PulseAudio stream.", (cork) ? "stop" : "start"); + return MA_ERROR; } return MA_SUCCESS; @@ -23579,11 +29283,12 @@ static ma_result ma_device_start__pulse(ma_device* pDevice) } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* We need to fill some data before uncorking. Not doing this will result in the write callback never getting fired. */ - result = ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL); - if (result != MA_SUCCESS) { - return result; /* Failed to write data. Not sure what to do here... Just aborting. */ - } + /* + We need to fill some data before uncorking. Not doing this will result in the write callback + never getting fired. We're not going to abort if writing fails because I still want the device + to get uncorked. + */ + ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL); /* No need to check the result here. Always want to fall through an uncork.*/ result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0); if (result != MA_SUCCESS) { @@ -23597,7 +29302,6 @@ static ma_result ma_device_start__pulse(ma_device* pDevice) static ma_result ma_device_stop__pulse(ma_device* pDevice) { ma_result result; - ma_bool32 wasSuccessful; MA_ASSERT(pDevice != NULL); @@ -23609,9 +29313,16 @@ static ma_result ma_device_stop__pulse(ma_device* pDevice) } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* The stream needs to be drained if it's a playback device. */ + /* + Ideally we would drain the device here, but there's been cases where PulseAudio seems to be + broken on some systems to the point where no audio processing seems to happen. When this + happens, draining never completes and we get stuck here. For now I'm disabling draining of + the device so we don't just freeze the application. + */ + #if 0 ma_pa_operation* pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful); - ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP); + ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP); + #endif result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1); if (result != MA_SUCCESS) { @@ -23634,8 +29345,8 @@ static ma_result ma_device_data_loop__pulse(ma_device* pDevice) All data is handled through callbacks. All we need to do is iterate over the main loop and let the callbacks deal with it. */ - while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { - resultPA = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pContext->pulse.pMainLoop, 1, NULL); + while (ma_device_get_state(pDevice) == ma_device_state_started) { + resultPA = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL); if (resultPA < 0) { break; } @@ -23649,7 +29360,7 @@ static ma_result ma_device_data_loop_wakeup__pulse(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - ((ma_pa_mainloop_wakeup_proc)pDevice->pContext->pulse.pa_mainloop_wakeup)((ma_pa_mainloop*)pDevice->pContext->pulse.pMainLoop); + ((ma_pa_mainloop_wakeup_proc)pDevice->pContext->pulse.pa_mainloop_wakeup)((ma_pa_mainloop*)pDevice->pulse.pMainLoop); return MA_SUCCESS; } @@ -23663,6 +29374,9 @@ static ma_result ma_context_uninit__pulse(ma_context* pContext) ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pContext->pulse.pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pContext->pulse.pMainLoop); + ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks); + ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks); + #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->pulse.pulseSO); #endif @@ -23739,6 +29453,7 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback"); pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback"); pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_suspended_callback"); + pContext->pulse.pa_stream_set_moved_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_moved_callback"); pContext->pulse.pa_stream_is_suspended = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_suspended"); pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush"); pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain"); @@ -23801,6 +29516,7 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c ma_pa_stream_set_write_callback_proc _pa_stream_set_write_callback = pa_stream_set_write_callback; ma_pa_stream_set_read_callback_proc _pa_stream_set_read_callback = pa_stream_set_read_callback; ma_pa_stream_set_suspended_callback_proc _pa_stream_set_suspended_callback = pa_stream_set_suspended_callback; + ma_pa_stream_set_moved_callback_proc _pa_stream_set_moved_callback = pa_stream_set_moved_callback; ma_pa_stream_is_suspended_proc _pa_stream_is_suspended = pa_stream_is_suspended; ma_pa_stream_flush_proc _pa_stream_flush = pa_stream_flush; ma_pa_stream_drain_proc _pa_stream_drain = pa_stream_drain; @@ -23862,6 +29578,7 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_set_write_callback = (ma_proc)_pa_stream_set_write_callback; pContext->pulse.pa_stream_set_read_callback = (ma_proc)_pa_stream_set_read_callback; pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)_pa_stream_set_suspended_callback; + pContext->pulse.pa_stream_set_moved_callback = (ma_proc)_pa_stream_set_moved_callback; pContext->pulse.pa_stream_is_suspended = (ma_proc)_pa_stream_is_suspended; pContext->pulse.pa_stream_flush = (ma_proc)_pa_stream_flush; pContext->pulse.pa_stream_drain = (ma_proc)_pa_stream_drain; @@ -23876,48 +29593,28 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_readable_size = (ma_proc)_pa_stream_readable_size; #endif - /* The PulseAudio context maps well to miniaudio's notion of a context. The pa_context object will be initialized as part of the ma_context. */ - pContext->pulse.pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); - if (pContext->pulse.pMainLoop == NULL) { - result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create mainloop.", MA_FAILED_TO_INIT_BACKEND); - #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext, pContext->pulse.pulseSO); - #endif - return result; + /* We need to make a copy of the application and server names so we can pass them to the pa_context of each device. */ + pContext->pulse.pApplicationName = ma_copy_string(pConfig->pulse.pApplicationName, &pContext->allocationCallbacks); + if (pContext->pulse.pApplicationName == NULL && pConfig->pulse.pApplicationName != NULL) { + return MA_OUT_OF_MEMORY; } - pContext->pulse.pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pContext->pulse.pMainLoop), pConfig->pulse.pApplicationName); - if (pContext->pulse.pPulseContext == NULL) { - result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context.", MA_FAILED_TO_INIT_BACKEND); - ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop)); - #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext, pContext->pulse.pulseSO); - #endif - return result; + pContext->pulse.pServerName = ma_copy_string(pConfig->pulse.pServerName, &pContext->allocationCallbacks); + if (pContext->pulse.pServerName == NULL && pConfig->pulse.pServerName != NULL) { + ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks); + return MA_OUT_OF_MEMORY; } - /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ - result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pContext->pulse.pPulseContext, pConfig->pulse.pServerName, (pConfig->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); + result = ma_init_pa_mainloop_and_pa_context__pulse(pContext, pConfig->pulse.pApplicationName, pConfig->pulse.pServerName, pConfig->pulse.tryAutoSpawn, &pContext->pulse.pMainLoop, &pContext->pulse.pPulseContext); if (result != MA_SUCCESS) { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.", result); - ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop)); + ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks); + ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks); #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return result; } - /* Since ma_context_init() runs synchronously we need to wait for the PulseAudio context to connect before we return. */ - result = ma_context_wait_for_pa_context_to_connect__pulse(pContext); - if (result != MA_SUCCESS) { - ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop)); - #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext, pContext->pulse.pulseSO); - #endif - return result; - } - - /* With pa_mainloop we run a synchronous backend, but we implement our own main loop. */ pCallbacks->onContextInit = ma_context_init__pulse; pCallbacks->onContextUninit = ma_context_uninit__pulse; @@ -24082,7 +29779,8 @@ static ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_devic /* The channel count and sample rate can only be determined by opening the device. */ result = ma_context_open_client__jack(pContext, &pClient); if (result != MA_SUCCESS) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client."); + return result; } pDeviceInfo->nativeDataFormats[0].sampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient); @@ -24091,7 +29789,8 @@ static ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_devic ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ((deviceType == ma_device_type_playback) ? ma_JackPortIsInput : ma_JackPortIsOutput)); if (ppPorts == NULL) { ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } while (ppPorts[pDeviceInfo->nativeDataFormats[0].channels] != NULL) { @@ -24123,11 +29822,13 @@ static ma_result ma_device_uninit__jack(ma_device* pDevice) } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->jack.ppPortsCapture, &pDevice->pContext->allocationCallbacks); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->jack.ppPortsPlayback, &pDevice->pContext->allocationCallbacks); } return MA_SUCCESS; @@ -24149,12 +29850,12 @@ static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, vo if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { size_t newBufferSize = frameCount * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat)); - float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks); + float* pNewBuffer = (float*)ma_calloc(newBufferSize, &pDevice->pContext->allocationCallbacks); if (pNewBuffer == NULL) { return MA_OUT_OF_MEMORY; } - ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); pDevice->jack.pIntermediaryBufferCapture = pNewBuffer; pDevice->playback.internalPeriodSizeInFrames = frameCount; @@ -24162,12 +29863,12 @@ static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, vo if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { size_t newBufferSize = frameCount * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat)); - float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks); + float* pNewBuffer = (float*)ma_calloc(newBufferSize, &pDevice->pContext->allocationCallbacks); if (pNewBuffer == NULL) { return MA_OUT_OF_MEMORY; } - ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer; pDevice->playback.internalPeriodSizeInFrames = frameCount; @@ -24191,7 +29892,7 @@ static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { /* Channels need to be interleaved. */ for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) { - const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsCapture[iChannel], frameCount); + const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.ppPortsCapture[iChannel], frameCount); if (pSrc != NULL) { float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel; ma_jack_nframes_t iFrame; @@ -24212,7 +29913,7 @@ static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* /* Channels need to be deinterleaved. */ for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { - float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[iChannel], frameCount); + float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.ppPortsPlayback[iChannel], frameCount); if (pDst != NULL) { const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel; ma_jack_nframes_t iFrame; @@ -24238,33 +29939,39 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config MA_ASSERT(pDevice != NULL); if (pConfig->deviceType == ma_device_type_loopback) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Loopback mode not supported."); return MA_DEVICE_TYPE_NOT_SUPPORTED; } /* Only supporting default devices with JACK. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->pDeviceID != NULL && pDescriptorPlayback->pDeviceID->jack != 0) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->pDeviceID != NULL && pDescriptorCapture->pDeviceID->jack != 0)) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Only default devices are supported."); return MA_NO_DEVICE; } /* No exclusive mode with the JACK backend. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Exclusive mode not supported."); return MA_SHARE_MODE_NOT_SUPPORTED; } /* Open the client. */ result = ma_context_open_client__jack(pDevice->pContext, (ma_jack_client_t**)&pDevice->jack.pClient); if (result != MA_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client."); + return result; } /* Callbacks. */ if (((ma_jack_set_process_callback_proc)pDevice->pContext->jack.jack_set_process_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_process_callback, pDevice) != 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } if (((ma_jack_set_buffer_size_callback_proc)pDevice->pContext->jack.jack_set_buffer_size_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_buffer_size_callback, pDevice) != 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } ((ma_jack_on_shutdown_proc)pDevice->pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice); @@ -24274,31 +29981,42 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config periodSizeInFrames = ((ma_jack_get_buffer_size_proc)pDevice->pContext->jack.jack_get_buffer_size)((ma_jack_client_t*)pDevice->jack.pClient); if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ma_uint32 iPort; const char** ppPorts; pDescriptorCapture->format = ma_format_f32; pDescriptorCapture->channels = 0; pDescriptorCapture->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDescriptorCapture->channels, pDescriptorCapture->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels); ppPorts = ((ma_jack_get_ports_proc)pDevice->pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput); if (ppPorts == NULL) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } + /* Need to count the number of ports first so we can allocate some memory. */ while (ppPorts[pDescriptorCapture->channels] != NULL) { + pDescriptorCapture->channels += 1; + } + + pDevice->jack.ppPortsCapture = (ma_ptr*)ma_malloc(sizeof(*pDevice->jack.ppPortsCapture) * pDescriptorCapture->channels, &pDevice->pContext->allocationCallbacks); + if (pDevice->jack.ppPortsCapture == NULL) { + return MA_OUT_OF_MEMORY; + } + + for (iPort = 0; iPort < pDescriptorCapture->channels; iPort += 1) { char name[64]; ma_strcpy_s(name, sizeof(name), "capture"); - ma_itoa_s((int)pDescriptorCapture->channels, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */ + ma_itoa_s((int)iPort, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */ - pDevice->jack.pPortsCapture[pDescriptorCapture->channels] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0); - if (pDevice->jack.pPortsCapture[pDescriptorCapture->channels] == NULL) { + pDevice->jack.ppPortsCapture[iPort] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0); + if (pDevice->jack.ppPortsCapture[iPort] == NULL) { ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); ma_device_uninit__jack(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } - - pDescriptorCapture->channels += 1; } ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); @@ -24306,7 +30024,7 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config pDescriptorCapture->periodSizeInFrames = periodSizeInFrames; pDescriptorCapture->periodCount = 1; /* There's no notion of a period in JACK. Just set to 1. */ - pDevice->jack.pIntermediaryBufferCapture = (float*)ma__calloc_from_callbacks(pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels), &pDevice->pContext->allocationCallbacks); + pDevice->jack.pIntermediaryBufferCapture = (float*)ma_calloc(pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels), &pDevice->pContext->allocationCallbacks); if (pDevice->jack.pIntermediaryBufferCapture == NULL) { ma_device_uninit__jack(pDevice); return MA_OUT_OF_MEMORY; @@ -24314,31 +30032,43 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_uint32 iPort; const char** ppPorts; pDescriptorPlayback->format = ma_format_f32; pDescriptorPlayback->channels = 0; pDescriptorPlayback->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient); - ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels); ppPorts = ((ma_jack_get_ports_proc)pDevice->pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput); if (ppPorts == NULL) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } + /* Need to count the number of ports first so we can allocate some memory. */ while (ppPorts[pDescriptorPlayback->channels] != NULL) { + pDescriptorPlayback->channels += 1; + } + + pDevice->jack.ppPortsPlayback = (ma_ptr*)ma_malloc(sizeof(*pDevice->jack.ppPortsPlayback) * pDescriptorPlayback->channels, &pDevice->pContext->allocationCallbacks); + if (pDevice->jack.ppPortsPlayback == NULL) { + ma_free(pDevice->jack.ppPortsCapture, &pDevice->pContext->allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + + for (iPort = 0; iPort < pDescriptorPlayback->channels; iPort += 1) { char name[64]; ma_strcpy_s(name, sizeof(name), "playback"); - ma_itoa_s((int)pDescriptorPlayback->channels, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */ + ma_itoa_s((int)iPort, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */ - pDevice->jack.pPortsPlayback[pDescriptorPlayback->channels] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0); - if (pDevice->jack.pPortsPlayback[pDescriptorPlayback->channels] == NULL) { + pDevice->jack.ppPortsPlayback[iPort] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0); + if (pDevice->jack.ppPortsPlayback[iPort] == NULL) { ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); ma_device_uninit__jack(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } - - pDescriptorPlayback->channels += 1; } ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); @@ -24346,7 +30076,7 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames; pDescriptorPlayback->periodCount = 1; /* There's no notion of a period in JACK. Just set to 1. */ - pDevice->jack.pIntermediaryBufferPlayback = (float*)ma__calloc_from_callbacks(pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels), &pDevice->pContext->allocationCallbacks); + pDevice->jack.pIntermediaryBufferPlayback = (float*)ma_calloc(pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels), &pDevice->pContext->allocationCallbacks); if (pDevice->jack.pIntermediaryBufferPlayback == NULL) { ma_device_uninit__jack(pDevice); return MA_OUT_OF_MEMORY; @@ -24365,25 +30095,28 @@ static ma_result ma_device_start__jack(ma_device* pDevice) resultJACK = ((ma_jack_activate_proc)pContext->jack.jack_activate)((ma_jack_client_t*)pDevice->jack.pClient); if (resultJACK != 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.", MA_FAILED_TO_START_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client."); + return MA_FAILED_TO_START_BACKEND_DEVICE; } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput); if (ppServerPorts == NULL) { ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports."); + return MA_ERROR; } for (i = 0; ppServerPorts[i] != NULL; ++i) { const char* pServerPort = ppServerPorts[i]; - const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsCapture[i]); + const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.ppPortsCapture[i]); resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pServerPort, pClientPort); if (resultJACK != 0) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports."); + return MA_ERROR; } } @@ -24394,18 +30127,20 @@ static ma_result ma_device_start__jack(ma_device* pDevice) const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput); if (ppServerPorts == NULL) { ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports."); + return MA_ERROR; } for (i = 0; ppServerPorts[i] != NULL; ++i) { const char* pServerPort = ppServerPorts[i]; - const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[i]); + const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.ppPortsPlayback[i]); resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pClientPort, pServerPort); if (resultJACK != 0) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports."); + return MA_ERROR; } } @@ -24418,16 +30153,13 @@ static ma_result ma_device_start__jack(ma_device* pDevice) static ma_result ma_device_stop__jack(ma_device* pDevice) { ma_context* pContext = pDevice->pContext; - ma_stop_proc onStop; if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client."); + return MA_ERROR; } - onStop = pDevice->onStop; - if (onStop) { - onStop(pDevice); - } + ma_device__on_notification_stopped(pDevice); return MA_SUCCESS; } @@ -24592,6 +30324,13 @@ References #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 #define MA_APPLE_WATCH #endif + #if __has_feature(objc_arc) + #define MA_BRIDGE_TRANSFER __bridge_transfer + #define MA_BRIDGE_RETAINED __bridge_retained + #else + #define MA_BRIDGE_TRANSFER + #define MA_BRIDGE_RETAINED + #endif #else #define MA_APPLE_DESKTOP #endif @@ -24930,7 +30669,7 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* case kAudioChannelLayoutTag_Binaural: case kAudioChannelLayoutTag_Ambisonic_B_Format: { - ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); } break; case kAudioChannelLayoutTag_Octagonal: @@ -24958,7 +30697,7 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* default: { - ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); } break; } } @@ -25095,14 +30834,14 @@ static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioOb return MA_FALSE; } - pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(dataSize, &pContext->allocationCallbacks); + pBufferList = (AudioBufferList*)ma_malloc(dataSize, &pContext->allocationCallbacks); if (pBufferList == NULL) { return MA_FALSE; /* Out of memory. */ } status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pBufferList); if (status != noErr) { - ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks); + ma_free(pBufferList, &pContext->allocationCallbacks); return MA_FALSE; } @@ -25111,7 +30850,7 @@ static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioOb isSupported = MA_TRUE; } - ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks); + ma_free(pBufferList, &pContext->allocationCallbacks); return isSupported; } @@ -25740,24 +31479,24 @@ static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit au return ma_result_from_OSStatus(status); } - pChannelLayout = (AudioChannelLayout*)ma__malloc_from_callbacks(channelLayoutSize, &pContext->allocationCallbacks); + pChannelLayout = (AudioChannelLayout*)ma_malloc(channelLayoutSize, &pContext->allocationCallbacks); if (pChannelLayout == NULL) { return MA_OUT_OF_MEMORY; } status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, pChannelLayout, &channelLayoutSize); if (status != noErr) { - ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); + ma_free(pChannelLayout, &pContext->allocationCallbacks); return ma_result_from_OSStatus(status); } result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap); if (result != MA_SUCCESS) { - ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); + ma_free(pChannelLayout, &pContext->allocationCallbacks); return result; } - ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); + ma_free(pChannelLayout, &pContext->allocationCallbacks); return MA_SUCCESS; } #endif /* MA_APPLE_DESKTOP */ @@ -25993,7 +31732,7 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ UInt32 propSize; /* We want to ensure we use a consistent device name to device enumeration. */ - if (pDeviceID != NULL) { + if (pDeviceID != NULL && pDeviceID->coreaudio[0] != '\0') { ma_bool32 found = MA_FALSE; if (deviceType == ma_device_type_playback) { NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs]; @@ -26109,7 +31848,7 @@ static AudioBufferList* ma_allocate_AudioBufferList__coreaudio(ma_uint32 sizeInF allocationSize += sizeInFrames * ma_get_bytes_per_frame(format, channels); - pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(allocationSize, pAllocationCallbacks); + pBufferList = (AudioBufferList*)ma_malloc(allocationSize, pAllocationCallbacks); if (pBufferList == NULL) { return NULL; } @@ -26145,12 +31884,12 @@ static ma_result ma_device_realloc_AudioBufferList__coreaudio(ma_device* pDevice AudioBufferList* pNewAudioBufferList; pNewAudioBufferList = ma_allocate_AudioBufferList__coreaudio(sizeInFrames, format, channels, layout, &pDevice->pContext->allocationCallbacks); - if (pNewAudioBufferList != NULL) { + if (pNewAudioBufferList == NULL) { return MA_OUT_OF_MEMORY; } /* At this point we'll have a new AudioBufferList and we can free the old one. */ - ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); pDevice->coreaudio.pAudioBufferList = pNewAudioBufferList; pDevice->coreaudio.audioBufferCapInFrames = sizeInFrames; } @@ -26167,7 +31906,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl MA_ASSERT(pDevice != NULL); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pBufferList->mNumberBuffers); + /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pBufferList->mNumberBuffers);*/ /* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */ layout = ma_stream_layout_interleaved; @@ -26185,7 +31924,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl ma_device_handle_backend_data_callback(pDevice, pBufferList->mBuffers[iBuffer].mData, NULL, frameCountForThisBuffer); } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize); + /*a_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);*/ } else { /* This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's @@ -26193,7 +31932,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl output silence here. */ MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize); + /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);*/ } } } else { @@ -26262,7 +32001,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla layout = ma_stream_layout_deinterleaved; } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pRenderedBufferList->mNumberBuffers); + /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pRenderedBufferList->mNumberBuffers);*/ /* There has been a situation reported where frame count passed into this function is greater than the capacity of @@ -26272,9 +32011,12 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla */ result = ma_device_realloc_AudioBufferList__coreaudio(pDevice, frameCount, pDevice->capture.internalFormat, pDevice->capture.internalChannels, layout); if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture."); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture.\n"); return noErr; } + + pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList; + MA_ASSERT(pRenderedBufferList); /* When you call AudioUnitRender(), Core Audio tries to be helpful by setting the mDataByteSize to the number of bytes @@ -26290,7 +32032,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList); if (status != noErr) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " ERROR: AudioUnitRender() failed with %d\n", status); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " ERROR: AudioUnitRender() failed with %d.\n", (int)status); return status; } @@ -26298,7 +32040,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) { if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) { ma_device_handle_backend_data_callback(pDevice, NULL, pRenderedBufferList->mBuffers[iBuffer].mData, frameCount); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " mDataByteSize=%d\n", pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); + /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " mDataByteSize=%d.\n", (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/ } else { /* This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's @@ -26321,7 +32063,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla framesRemaining -= framesToSend; } - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); + /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/ } } } else { @@ -26383,24 +32125,17 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio can try waiting on the same lock. I'm going to try working around this by not calling any Core Audio APIs in the callback when the device has been stopped or uninitialized. */ - if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED || ma_device_get_state(pDevice) == MA_STATE_STOPPING || ma_device_get_state(pDevice) == MA_STATE_STOPPED) { - ma_stop_proc onStop = pDevice->onStop; - if (onStop) { - onStop(pDevice); - } - - ma_event_signal(&pDevice->coreaudio.stopEvent); + if (ma_device_get_state(pDevice) == ma_device_state_uninitialized || ma_device_get_state(pDevice) == ma_device_state_stopping || ma_device_get_state(pDevice) == ma_device_state_stopped) { + ma_device__on_notification_stopped(pDevice); } else { UInt32 isRunning; UInt32 isRunningSize = sizeof(isRunning); OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize); if (status != noErr) { - return; /* Don't really know what to do in this case... just ignore it, I suppose... */ + goto done; /* Don't really know what to do in this case... just ignore it, I suppose... */ } if (!isRunning) { - ma_stop_proc onStop; - /* The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider: @@ -26414,12 +32149,12 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio /* It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the - device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it + device to be seamless to the client (we don't want them receiving the stopped event and thinking that the device has stopped when it hasn't!). */ if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) || ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isSwitchingCaptureDevice)) { - return; + goto done; } /* @@ -26427,20 +32162,21 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most likely be successful in switching to the new device. - TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted. + TODO: Try to predict if Core Audio will switch devices. If not, the stopped callback needs to be posted. */ - return; + goto done; } /* Getting here means we need to stop the device. */ - onStop = pDevice->onStop; - if (onStop) { - onStop(pDevice); - } + ma_device__on_notification_stopped(pDevice); } } (void)propertyID; /* Unused. */ + +done: + /* Always signal the stop event. It's possible for the "else" case to get hit which can happen during an interruption. */ + ma_event_signal(&pDevice->coreaudio.stopEvent); } #if defined(MA_APPLE_DESKTOP) @@ -26491,7 +32227,7 @@ static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UIn ma_device__post_init_setup(pDevice, deviceType); /* Restart the device if required. If this fails we need to stop the device entirely. */ - if (ma_device_get_state(pDevice) == MA_STATE_STARTED) { + if (ma_device_get_state(pDevice) == ma_device_state_started) { OSStatus status; if (deviceType == ma_device_type_playback) { status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); @@ -26499,7 +32235,7 @@ static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UIn if (pDevice->type == ma_device_type_duplex) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } - ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_device__set_state(pDevice, ma_device_state_stopped); } } else if (deviceType == ma_device_type_capture) { status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture); @@ -26507,10 +32243,12 @@ static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UIn if (pDevice->type == ma_device_type_duplex) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); } - ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_device__set_state(pDevice, ma_device_state_stopped); } } } + + ma_device__on_notification_rerouted(pDevice); } } } @@ -26574,7 +32312,7 @@ static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pCont /* At this point there should be no tracked devices. If not there's an error somewhere. */ if (g_ppTrackedDevices_CoreAudio != NULL) { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active.", MA_INVALID_OPERATION); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active."); ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio); return MA_INVALID_OPERATION; } @@ -26595,17 +32333,15 @@ static ma_result ma_device__track__coreaudio(ma_device* pDevice) { /* Allocate memory if required. */ if (g_TrackedDeviceCap_CoreAudio <= g_TrackedDeviceCount_CoreAudio) { - ma_uint32 oldCap; ma_uint32 newCap; ma_device** ppNewDevices; - oldCap = g_TrackedDeviceCap_CoreAudio; newCap = g_TrackedDeviceCap_CoreAudio * 2; if (newCap == 0) { newCap = 1; } - ppNewDevices = (ma_device**)ma__realloc_from_callbacks(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, sizeof(*g_ppTrackedDevices_CoreAudio)*oldCap, &pDevice->pContext->allocationCallbacks); + ppNewDevices = (ma_device**)ma_realloc(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, &pDevice->pContext->allocationCallbacks); if (ppNewDevices == NULL) { ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio); return MA_OUT_OF_MEMORY; @@ -26642,7 +32378,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) /* If there's nothing else in the list we need to free memory. */ if (g_TrackedDeviceCount_CoreAudio == 0) { - ma__free_from_callbacks(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks); + ma_free(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks); g_ppTrackedDevices_CoreAudio = NULL; g_TrackedDeviceCap_CoreAudio = 0; } @@ -26658,30 +32394,71 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) #endif #if defined(MA_APPLE_MOBILE) -@interface ma_router_change_handler:NSObject { +@interface ma_ios_notification_handler:NSObject { ma_device* m_pDevice; } @end -@implementation ma_router_change_handler +@implementation ma_ios_notification_handler -(id)init:(ma_device*)pDevice { self = [super init]; m_pDevice = pDevice; + /* For route changes. */ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_route_change:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]]; + /* For interruptions. */ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_interruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; + return self; } -(void)dealloc { [self remove_handler]; + + #if defined(__has_feature) + #if !__has_feature(objc_arc) + [super dealloc]; + #endif + #endif } -(void)remove_handler { [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil]; +} + +-(void)handle_interruption:(NSNotification*)pNotification +{ + NSInteger type = [[[pNotification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue]; + switch (type) + { + case AVAudioSessionInterruptionTypeBegan: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeBegan\n"); + + /* + Core Audio will have stopped the internal device automatically, but we need explicitly + stop it at a higher level to ensure miniaudio-specific state is updated for consistency. + */ + ma_device_stop(m_pDevice); + + /* + Fire the notification after the device has been stopped to ensure it's in the correct + state when the notification handler is invoked. + */ + ma_device__on_notification_interruption_began(m_pDevice); + } break; + + case AVAudioSessionInterruptionTypeEnded: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n"); + ma_device__on_notification_interruption_ended(m_pDevice); + } break; + } } -(void)handle_route_change:(NSNotification*)pNotification @@ -26693,66 +32470,45 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) { case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n"); + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n"); } break; case AVAudioSessionRouteChangeReasonNewDeviceAvailable: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n"); + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n"); } break; case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n"); + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n"); } break; case AVAudioSessionRouteChangeReasonWakeFromSleep: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n"); + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n"); } break; case AVAudioSessionRouteChangeReasonOverride: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n"); + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n"); } break; case AVAudioSessionRouteChangeReasonCategoryChange: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n"); + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n"); } break; case AVAudioSessionRouteChangeReasonUnknown: default: { - ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n"); + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n"); } break; } ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels); - - /* Temporarily disabling this section of code because it appears to be causing errors. */ -#if 0 - ma_uint32 previousState = ma_device_get_state(m_pDevice); - - if (previousState == MA_STATE_STARTED) { - ma_device_stop(m_pDevice); - } - - if (m_pDevice->type == ma_device_type_capture || m_pDevice->type == ma_device_type_duplex) { - m_pDevice->capture.internalChannels = (ma_uint32)pSession.inputNumberOfChannels; - m_pDevice->capture.internalSampleRate = (ma_uint32)pSession.sampleRate; - ma_device__post_init_setup(m_pDevice, ma_device_type_capture); - } - if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) { - m_pDevice->playback.internalChannels = (ma_uint32)pSession.outputNumberOfChannels; - m_pDevice->playback.internalSampleRate = (ma_uint32)pSession.sampleRate; - ma_device__post_init_setup(m_pDevice, ma_device_type_playback); - } - - if (previousState == MA_STATE_STARTED) { - ma_device_start(m_pDevice); - } -#endif + + /* Let the application know about the route change. */ + ma_device__on_notification_rerouted(m_pDevice); } @end #endif @@ -26760,7 +32516,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) static ma_result ma_device_uninit__coreaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED); + MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_uninitialized); #if defined(MA_APPLE_DESKTOP) /* @@ -26770,9 +32526,9 @@ static ma_result ma_device_uninit__coreaudio(ma_device* pDevice) ma_device__untrack__coreaudio(pDevice); #endif #if defined(MA_APPLE_MOBILE) - if (pDevice->coreaudio.pRouteChangeHandler != NULL) { - ma_router_change_handler* pRouteChangeHandler = (__bridge_transfer ma_router_change_handler*)pDevice->coreaudio.pRouteChangeHandler; - [pRouteChangeHandler remove_handler]; + if (pDevice->coreaudio.pNotificationHandler != NULL) { + ma_ios_notification_handler* pNotificationHandler = (MA_BRIDGE_TRANSFER ma_ios_notification_handler*)pDevice->coreaudio.pNotificationHandler; + [pNotificationHandler remove_handler]; } #endif @@ -26784,7 +32540,7 @@ static ma_result ma_device_uninit__coreaudio(ma_device* pDevice) } if (pDevice->coreaudio.pAudioBufferList) { - ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); } return MA_SUCCESS; @@ -26832,8 +32588,6 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev AURenderCallbackStruct callbackInfo; #if defined(MA_APPLE_DESKTOP) AudioObjectID deviceObjectID; -#else - UInt32 actualPeriodSizeInFramesSize = sizeof(actualPeriodSizeInFrames); #endif /* This API should only be used for a single device type: playback or capture. No full-duplex mode. */ @@ -27087,12 +32841,12 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev } #else /* Fall back to default assumptions. */ - ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut); + ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut); #endif } #else /* TODO: Figure out how to get the channel map using AVAudioSession. */ - ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut); + ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut); #endif @@ -27118,13 +32872,16 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev } #else /* - I don't know how to configure buffer sizes on iOS so for now we're not allowing it to be configured. Instead we're - just going to set it to the value of kAudioUnitProperty_MaximumFramesPerSlice. + On iOS, the size of the IO buffer needs to be specified in seconds and is a floating point + number. I don't trust any potential truncation errors due to converting from float to integer + so I'm going to explicitly set the actual period size to the next power of 2. */ - status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, &actualPeriodSizeInFramesSize); - if (status != noErr) { - ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); - return ma_result_from_OSStatus(status); + @autoreleasepool { + AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; + MA_ASSERT(pAudioSession != NULL); + + [pAudioSession setPreferredIOBufferDuration:((float)actualPeriodSizeInFrames / pAudioSession.sampleRate) error:nil]; + actualPeriodSizeInFrames = ma_next_power_of_2((ma_uint32)(pAudioSession.IOBufferDuration * pAudioSession.sampleRate)); } #endif @@ -27189,7 +32946,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev /* Initialize the audio unit. */ status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit); if (status != noErr) { - ma__free_from_callbacks(pData->pAudioBufferList, &pContext->allocationCallbacks); + ma_free(pData->pAudioBufferList, &pContext->allocationCallbacks); pData->pAudioBufferList = NULL; ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); @@ -27236,7 +32993,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } if (pDevice->coreaudio.pAudioBufferList) { - ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); } } else if (deviceType == ma_device_type_playback) { data.formatIn = pDevice->playback.format; @@ -27269,6 +33026,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev if (deviceType == ma_device_type_capture) { #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID; + ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio); #endif pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit; pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList; @@ -27283,6 +33041,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev } else if (deviceType == ma_device_type_playback) { #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID; + ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio); #endif pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit; @@ -27360,6 +33119,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c pDescriptorCapture->periodCount = data.periodsOut; #if defined(MA_APPLE_DESKTOP) + ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio); + /* If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. @@ -27398,7 +33159,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c if (pConfig->deviceType == ma_device_type_duplex) { ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); if (pDevice->coreaudio.pAudioBufferList) { - ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); } } return result; @@ -27422,6 +33183,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c pDescriptorPlayback->periodCount = data.periodsOut; #if defined(MA_APPLE_DESKTOP) + ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio); + /* If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. @@ -27445,7 +33208,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c differently on non-Desktop Apple platforms. */ #if defined(MA_APPLE_MOBILE) - pDevice->coreaudio.pRouteChangeHandler = (__bridge_retained void*)[[ma_router_change_handler alloc] init:pDevice]; + pDevice->coreaudio.pNotificationHandler = (MA_BRIDGE_RETAINED void*)[[ma_ios_notification_handler alloc] init:pDevice]; #endif return MA_SUCCESS; @@ -27510,7 +33273,8 @@ static ma_result ma_context_uninit__coreaudio(ma_context* pContext) #if defined(MA_APPLE_MOBILE) if (!pContext->coreaudio.noAudioSessionDeactivate) { if (![[AVAudioSession sharedInstance] setActive:false error:nil]) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to deactivate audio session.", MA_FAILED_TO_INIT_BACKEND); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "Failed to deactivate audio session."); + return MA_FAILED_TO_INIT_BACKEND; } } #endif @@ -27529,7 +33293,7 @@ static ma_result ma_context_uninit__coreaudio(ma_context* pContext) return MA_SUCCESS; } -#if defined(MA_APPLE_MOBILE) +#if defined(MA_APPLE_MOBILE) && defined(__IPHONE_12_0) static AVAudioSessionCategory ma_to_AVAudioSessionCategory(ma_ios_session_category category) { /* The "default" and "none" categories are treated different and should not be used as an input into this function. */ @@ -27586,15 +33350,21 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte } } else { if (pConfig->coreaudio.sessionCategory != ma_ios_session_category_none) { + #if defined(__IPHONE_12_0) if (![pAudioSession setCategory: ma_to_AVAudioSessionCategory(pConfig->coreaudio.sessionCategory) withOptions:options error:nil]) { return MA_INVALID_OPERATION; /* Failed to set session category. */ } + #else + /* Ignore the session category on version 11 and older, but post a warning. */ + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Session category only supported in iOS 12 and newer."); + #endif } } if (!pConfig->coreaudio.noAudioSessionActivate) { if (![pAudioSession setActive:true error:nil]) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to activate audio session.", MA_FAILED_TO_INIT_BACKEND); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "Failed to activate audio session."); + return MA_FAILED_TO_INIT_BACKEND; } } } @@ -28255,7 +34025,7 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic MA_ASSERT(pDevice != NULL); if (deviceType == ma_device_type_capture) { - openFlags = MA_SIO_REC; + openFlags = MA_SIO_REC; } else { openFlags = MA_SIO_PLAY; } @@ -28272,13 +34042,15 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic handle = (ma_ptr)((ma_sio_open_proc)pDevice->pContext->sndio.sio_open)(pDeviceName, openFlags, 0); if (handle == NULL) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device."); + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } /* We need to retrieve the device caps to determine the most appropriate format to use. */ if (((ma_sio_getcap_proc)pDevice->pContext->sndio.sio_getcap)((struct ma_sio_hdl*)handle, &caps) == 0) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps.", MA_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps."); + return MA_ERROR; } /* @@ -28372,12 +34144,14 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic if (((ma_sio_setpar_proc)pDevice->pContext->sndio.sio_setpar)((struct ma_sio_hdl*)handle, &par) == 0) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size."); + return MA_ERROR; } if (((ma_sio_getpar_proc)pDevice->pContext->sndio.sio_getpar)((struct ma_sio_hdl*)handle, &par) == 0) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size."); + return MA_ERROR; } internalFormat = ma_format_from_sio_enc__sndio(par.bits, par.bps, par.sig, par.le, par.msb); @@ -28395,23 +34169,10 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic pDescriptor->format = internalFormat; pDescriptor->channels = internalChannels; pDescriptor->sampleRate = internalSampleRate; - ma_get_standard_channel_map(ma_standard_channel_map_sndio, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_sndio, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), internalChannels); pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; pDescriptor->periodCount = internalPeriods; - #ifdef MA_DEBUG_OUTPUT - { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "DEVICE INFO\n"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Format: %s\n", ma_get_format_name(internalFormat)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channels: %d\n", internalChannels); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Sample Rate: %d\n", internalSampleRate); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Period Size: %d\n", internalPeriodSizeInFrames); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Periods: %d\n", internalPeriods); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " appbufsz: %d\n", par.appbufsz); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " round: %d\n", par.round); - } - #endif - return MA_SUCCESS; } @@ -28492,7 +34253,8 @@ static ma_result ma_device_write__sndio(ma_device* pDevice, const void* pPCMFram result = ((ma_sio_write_proc)pDevice->pContext->sndio.sio_write)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (result == 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device.", MA_IO_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device."); + return MA_IO_ERROR; } if (pFramesWritten != NULL) { @@ -28512,7 +34274,8 @@ static ma_result ma_device_read__sndio(ma_device* pDevice, void* pPCMFrames, ma_ result = ((ma_sio_read_proc)pDevice->pContext->sndio.sio_read)((struct ma_sio_hdl*)pDevice->sndio.handleCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (result == 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device.", MA_IO_ERROR); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device."); + return MA_IO_ERROR; } if (pFramesRead != NULL) { @@ -29055,7 +34818,8 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c } if (fd == -1) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device."); + return ma_result_from_errno(errno); } #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */ @@ -29107,12 +34871,14 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed."); + return ma_result_from_errno(errno); } if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed."); + return ma_result_from_errno(errno); } if (deviceType == ma_device_type_capture) { @@ -29127,7 +34893,8 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (internalFormat == ma_format_unknown) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable."); + return MA_FORMAT_NOT_SUPPORTED; } /* Buffer. */ @@ -29153,7 +34920,8 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c fdInfo.blocksize = internalPeriodSizeInBytes; if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed."); + return ma_result_from_errno(errno); } internalPeriods = fdInfo.hiwat; @@ -29167,7 +34935,8 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c /* We need to retrieve the format of the device so we can know the channel count and sample rate. Then we can calculate the buffer size. */ if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters."); + return ma_result_from_errno(errno); } internalFormat = ma_format_from_swpar__audio4(&fdPar); @@ -29176,7 +34945,8 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (internalFormat == ma_format_unknown) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable."); + return MA_FORMAT_NOT_SUPPORTED; } /* Buffer. */ @@ -29196,12 +34966,14 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (ioctl(fd, AUDIO_SETPAR, &fdPar) < 0) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters."); + return ma_result_from_errno(errno); } if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters."); + return ma_result_from_errno(errno); } } @@ -29215,7 +34987,8 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c if (internalFormat == ma_format_unknown) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable."); + return MA_FORMAT_NOT_SUPPORTED; } if (deviceType == ma_device_type_capture) { @@ -29227,7 +35000,7 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c pDescriptor->format = internalFormat; pDescriptor->channels = internalChannels; pDescriptor->sampleRate = internalSampleRate; - ma_get_standard_channel_map(ma_standard_channel_map_sound4, internalChannels, pDescriptor->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_sound4, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), internalChannels); pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; pDescriptor->periodCount = internalPeriods; @@ -29309,11 +35082,13 @@ static ma_result ma_device_stop_fd__audio4(ma_device* pDevice, int fd) #if !defined(MA_AUDIO4_USE_NEW_API) if (ioctl(fd, AUDIO_FLUSH, 0) < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed."); + return ma_result_from_errno(errno); } #else if (ioctl(fd, AUDIO_STOP, 0) < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed."); + return ma_result_from_errno(errno); } #endif @@ -29361,7 +35136,8 @@ static ma_result ma_device_write__audio4(ma_device* pDevice, const void* pPCMFra result = write(pDevice->audio4.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (result < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device."); + return ma_result_from_errno(errno); } if (pFramesWritten != NULL) { @@ -29381,7 +35157,8 @@ static ma_result ma_device_read__audio4(ma_device* pDevice, void* pPCMFrames, ma result = read(pDevice->audio4.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (result < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device."); + return ma_result_from_errno(errno); } if (pFramesRead != NULL) { @@ -29496,7 +35273,8 @@ static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum fd = ma_open_temp_device__oss(); if (fd == -1) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration."); + return MA_NO_BACKEND; } result = ioctl(fd, SNDCTL_SYSINFO, &si); @@ -29543,7 +35321,8 @@ static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum } } else { close(fd); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration."); + return MA_NO_BACKEND; } close(fd); @@ -29626,7 +35405,8 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device fdTemp = ma_open_temp_device__oss(); if (fdTemp == -1) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration."); + return MA_NO_BACKEND; } result = ioctl(fdTemp, SNDCTL_SYSINFO, &si); @@ -29684,7 +35464,8 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device } } else { close(fdTemp); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration."); + return MA_NO_BACKEND; } @@ -29774,7 +35555,8 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf result = ma_context_open_device__oss(pDevice->pContext, deviceType, pDeviceID, shareMode, &fd); if (result != MA_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device."); + return result; } /* @@ -29788,21 +35570,24 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf ossResult = ioctl(fd, SNDCTL_DSP_SETFMT, &ossFormat); if (ossResult == -1) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format."); + return ma_result_from_errno(errno); } /* Channels. */ ossResult = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossChannels); if (ossResult == -1) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count."); + return ma_result_from_errno(errno); } /* Sample Rate. */ ossResult = ioctl(fd, SNDCTL_DSP_SPEED, &ossSampleRate); if (ossResult == -1) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate."); + return ma_result_from_errno(errno); } /* @@ -29836,7 +35621,8 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf ossResult = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment); if (ossResult == -1) { close(fd); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count."); + return ma_result_from_errno(errno); } } @@ -29850,12 +35636,13 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf pDescriptor->format = ma_format_from_oss(ossFormat); pDescriptor->channels = ossChannels; pDescriptor->sampleRate = ossSampleRate; - ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDescriptor->channels, pDescriptor->channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_sound4, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); pDescriptor->periodCount = (ma_uint32)(ossFragment >> 16); pDescriptor->periodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDescriptor->format, pDescriptor->channels); if (pDescriptor->format == ma_format_unknown) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio."); + return MA_FORMAT_NOT_SUPPORTED; } return MA_SUCCESS; @@ -29875,14 +35662,16 @@ static ma_result ma_device_init__oss(ma_device* pDevice, const ma_device_config* if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture); if (result != MA_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device."); + return result; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback); if (result != MA_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device."); + return result; } } @@ -29939,13 +35728,14 @@ static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames /* Don't do any processing if the device is stopped. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) { + if (deviceState != ma_device_state_started && deviceState != ma_device_state_starting) { return MA_SUCCESS; } resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (resultOSS < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device."); + return ma_result_from_errno(errno); } if (pFramesWritten != NULL) { @@ -29966,13 +35756,14 @@ static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_ui /* Don't do any processing if the device is stopped. */ deviceState = ma_device_get_state(pDevice); - if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) { + if (deviceState != ma_device_state_started && deviceState != ma_device_state_starting) { return MA_SUCCESS; } resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (resultOSS < 0) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", ma_result_from_errno(errno)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client."); + return ma_result_from_errno(errno); } if (pFramesRead != NULL) { @@ -30004,7 +35795,8 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con /* Try opening a temporary device first so we can get version information. This is closed at the end. */ fd = ma_open_temp_device__oss(); if (fd == -1) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.", MA_NO_BACKEND); /* Looks liks OSS isn't installed, or there are no available devices. */ + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties."); /* Looks liks OSS isn't installed, or there are no available devices. */ + return MA_NO_BACKEND; } /* Grab the OSS version. */ @@ -30012,7 +35804,8 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con result = ioctl(fd, OSS_GETVERSION, &ossVersion); if (result == -1) { close(fd); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.", MA_NO_BACKEND); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version."); + return MA_NO_BACKEND; } /* The file handle to temp device is no longer needed. Close ASAP. */ @@ -30238,14 +36031,29 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs (void)error; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); /* From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. */ if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[AAudio] Device Disconnected.\n"); + /* We need to post a job to the job thread for processing. This will reroute the device by reinitializing the stream. */ + ma_result result; + ma_job job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); + job.data.device.aaudio.reroute.pDevice = pDevice; + + if (pStream == pDevice->aaudio.pStreamCapture) { + job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; + } else { + job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; + } + + result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); + if (result != MA_SUCCESS) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); + return; + } } } @@ -30391,8 +36199,9 @@ static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_conf ma_result result; ma_AAudioStreamBuilder* pBuilder; - MA_ASSERT(pConfig != NULL); - MA_ASSERT(pConfig->deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */ + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pDescriptor != NULL); + MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */ *ppStream = NULL; @@ -30576,9 +36385,9 @@ static ma_result ma_device_init_by_type__aaudio(ma_device* pDevice, const ma_dev /* For the channel map we need to be sure we don't overflow any buffers. */ if (pDescriptor->channels <= MA_MAX_CHANNELS) { - ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptor->channels, pDescriptor->channelMap); /* <-- Cannot find info on channel order, so assuming a default. */ + ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); /* <-- Cannot find info on channel order, so assuming a default. */ } else { - ma_channel_map_init_blank(MA_MAX_CHANNELS, pDescriptor->channelMap); /* Too many channels. Use a blank channel map. */ + ma_channel_map_init_blank(pDescriptor->channelMap, MA_MAX_CHANNELS); /* Too many channels. Use a blank channel map. */ } bufferCapacityInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pDevice->pContext->aaudio.AAudioStream_getBufferCapacityInFrames)(pStream); @@ -30607,11 +36416,10 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf return MA_DEVICE_TYPE_NOT_SUPPORTED; } - /* No exclusive mode with AAudio. */ - if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || - ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) { - return MA_SHARE_MODE_NOT_SUPPORTED; - } + pDevice->aaudio.usage = pConfig->aaudio.usage; + pDevice->aaudio.contentType = pConfig->aaudio.contentType; + pDevice->aaudio.inputPreset = pConfig->aaudio.inputPreset; + pDevice->aaudio.noAutoStartAfterReroute = pConfig->aaudio.noAutoStartAfterReroute; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_capture, pDescriptorCapture, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture); @@ -30676,6 +36484,10 @@ static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStre This maps with miniaudio's requirement that device's be drained which means we don't need to implement any draining logic. */ + currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream); + if (currentState == MA_AAUDIO_STREAM_STATE_DISCONNECTED) { + return MA_SUCCESS; /* The device is disconnected. Don't try stopping it. */ + } resultAA = ((MA_PFN_AAudioStream_requestStop)pDevice->pContext->aaudio.AAudioStream_requestStop)(pStream); if (resultAA != MA_AAUDIO_OK) { @@ -30726,8 +36538,6 @@ static ma_result ma_device_start__aaudio(ma_device* pDevice) static ma_result ma_device_stop__aaudio(ma_device* pDevice) { - ma_stop_proc onStop; - MA_ASSERT(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { @@ -30744,11 +36554,131 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) } } - onStop = pDevice->onStop; - if (onStop) { - onStop(pDevice); + ma_device__on_notification_stopped(pDevice); + + return MA_SUCCESS; +} + +static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + /* The first thing to do is close the streams. */ + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); + pDevice->aaudio.pStreamCapture = NULL; } + if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); + pDevice->aaudio.pStreamPlayback = NULL; + } + + /* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */ + { + ma_device_config deviceConfig; + ma_device_descriptor descriptorPlayback; + ma_device_descriptor descriptorCapture; + + deviceConfig = ma_device_config_init(deviceType); + deviceConfig.playback.pDeviceID = NULL; /* Only doing rerouting with default devices. */ + deviceConfig.playback.shareMode = pDevice->playback.shareMode; + deviceConfig.playback.format = pDevice->playback.format; + deviceConfig.playback.channels = pDevice->playback.channels; + deviceConfig.capture.pDeviceID = NULL; /* Only doing rerouting with default devices. */ + deviceConfig.capture.shareMode = pDevice->capture.shareMode; + deviceConfig.capture.format = pDevice->capture.format; + deviceConfig.capture.channels = pDevice->capture.channels; + deviceConfig.sampleRate = pDevice->sampleRate; + deviceConfig.aaudio.usage = pDevice->aaudio.usage; + deviceConfig.aaudio.contentType = pDevice->aaudio.contentType; + deviceConfig.aaudio.inputPreset = pDevice->aaudio.inputPreset; + deviceConfig.aaudio.noAutoStartAfterReroute = pDevice->aaudio.noAutoStartAfterReroute; + deviceConfig.periods = 1; + + /* Try to get an accurate period size. */ + if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { + deviceConfig.periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames; + } else { + deviceConfig.periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames; + } + + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { + descriptorCapture.pDeviceID = deviceConfig.capture.pDeviceID; + descriptorCapture.shareMode = deviceConfig.capture.shareMode; + descriptorCapture.format = deviceConfig.capture.format; + descriptorCapture.channels = deviceConfig.capture.channels; + descriptorCapture.sampleRate = deviceConfig.sampleRate; + descriptorCapture.periodSizeInFrames = deviceConfig.periodSizeInFrames; + descriptorCapture.periodCount = deviceConfig.periods; + } + + if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { + descriptorPlayback.pDeviceID = deviceConfig.playback.pDeviceID; + descriptorPlayback.shareMode = deviceConfig.playback.shareMode; + descriptorPlayback.format = deviceConfig.playback.format; + descriptorPlayback.channels = deviceConfig.playback.channels; + descriptorPlayback.sampleRate = deviceConfig.sampleRate; + descriptorPlayback.periodSizeInFrames = deviceConfig.periodSizeInFrames; + descriptorPlayback.periodCount = deviceConfig.periods; + } + + result = ma_device_init__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); + if (result != MA_SUCCESS) { + ma_device_uninit__aaudio(pDevice); + return result; + } + + /* We'll only ever do this in response to a reroute. */ + ma_device__on_notification_rerouted(pDevice); + + /* If the device is started, start the streams. Maybe make this configurable? */ + if (ma_device_get_state(pDevice) == ma_device_state_started) { + if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) { + ma_device_start__aaudio(pDevice); + } else { + ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ + } + } + + return MA_SUCCESS; + } +} + +static ma_result ma_device_get_info__aaudio(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo) +{ + ma_AAudioStream* pStream = NULL; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(type != ma_device_type_duplex); + MA_ASSERT(pDeviceInfo != NULL); + + if (type == ma_device_type_playback) { + pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamCapture; + pDeviceInfo->id.aaudio = pDevice->capture.id.aaudio; + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */ + } + if (type == ma_device_type_capture) { + pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback; + pDeviceInfo->id.aaudio = pDevice->playback.id.aaudio; + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */ + } + + /* Safety. Should never happen. */ + if (pStream == NULL) { + return MA_INVALID_OPERATION; + } + + pDeviceInfo->nativeDataFormatCount = 0; + ma_context_add_native_data_format_from_AAudioStream__aaudio(pDevice->pContext, pStream, 0, pDeviceInfo); + return MA_SUCCESS; } @@ -30758,6 +36688,8 @@ static ma_result ma_context_uninit__aaudio(ma_context* pContext) MA_ASSERT(pContext != NULL); MA_ASSERT(pContext->backend == ma_backend_aaudio); + ma_device_job_thread_uninit(&pContext->aaudio.jobThread, &pContext->allocationCallbacks); + ma_dlclose(pContext, pContext->aaudio.hAAudio); pContext->aaudio.hAAudio = NULL; @@ -30823,10 +36755,47 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ pCallbacks->onDeviceRead = NULL; /* Not used because AAudio is asynchronous. */ pCallbacks->onDeviceWrite = NULL; /* Not used because AAudio is asynchronous. */ pCallbacks->onDeviceDataLoop = NULL; /* Not used because AAudio is asynchronous. */ + pCallbacks->onDeviceGetInfo = ma_device_get_info__aaudio; + + + /* We need a job thread so we can deal with rerouting. */ + { + ma_result result; + ma_device_job_thread_config jobThreadConfig; + + jobThreadConfig = ma_device_job_thread_config_init(); + + result = ma_device_job_thread_init(&jobThreadConfig, &pContext->allocationCallbacks, &pContext->aaudio.jobThread); + if (result != MA_SUCCESS) { + ma_dlclose(pContext, pContext->aaudio.hAAudio); + pContext->aaudio.hAAudio = NULL; + return result; + } + } + (void)pConfig; return MA_SUCCESS; } + +static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) +{ + ma_device* pDevice; + + MA_ASSERT(pJob != NULL); + + pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice; + MA_ASSERT(pDevice != NULL); + + /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ + return ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); +} +#else +/* Getting here means there is no AAudio backend so we need a no-op job implementation. */ +static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) +{ + return ma_job_process__noop(pJob); +} #endif /* AAudio */ @@ -31153,6 +37122,7 @@ return_default_device:; if (cbResult) { ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT; ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } @@ -31161,6 +37131,7 @@ return_default_device:; if (cbResult) { ma_device_info deviceInfo; MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT; ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } @@ -31259,10 +37230,12 @@ return_default_device: } } - /* Name / Description */ + /* ID and Name / Description */ if (deviceType == ma_device_type_playback) { + pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT; ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { + pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT; ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } @@ -31309,7 +37282,7 @@ static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBuff */ /* Don't do anything if the device is not started. */ - if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { + if (ma_device_get_state(pDevice) != ma_device_state_started) { return; } @@ -31343,7 +37316,7 @@ static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBuf (void)pBufferQueue; /* Don't do anything if the device is not started. */ - if (ma_device_get_state(pDevice) != MA_STATE_STARTED) { + if (ma_device_get_state(pDevice) != ma_device_state_started) { return; } @@ -31380,7 +37353,7 @@ static ma_result ma_device_uninit__opensl(ma_device* pDevice) MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj); } - ma__free_from_callbacks(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { @@ -31391,7 +37364,7 @@ static ma_result ma_device_uninit__opensl(ma_device* pDevice) MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj); } - ma__free_from_callbacks(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks); } return MA_SUCCESS; @@ -31428,8 +37401,8 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch #endif pDataFormat->numChannels = channels; - ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate) * 1000; /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */ - pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8; + ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate * 1000); /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */ + pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format) * 8; pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels); pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; @@ -31556,7 +37529,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE; locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT; - locatorDevice.deviceID = (pDescriptorCapture->pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pDescriptorCapture->pDeviceID->opensl; + locatorDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; /* Must always use the default device with Android. */ locatorDevice.device = NULL; source.pLocator = &locatorDevice; @@ -31568,20 +37541,21 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf sink.pFormat = (SLDataFormat_PCM*)&pcm; resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); - if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { + if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; pcm.numChannels = 1; ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */ pcm.bitsPerSample = 16; pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ - pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + pcm.channelMask = 0; resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); } if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder."); + return ma_result_from_OpenSL(resultSL); } @@ -31600,25 +37574,29 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_RECORD, &pDevice->opensl.pAudioRecorder); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, ma_buffer_queue_callback_capture__opensl_android, pDevice); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback."); + return ma_result_from_OpenSL(resultSL); } /* The internal format is determined by the "pcm" object. */ @@ -31629,10 +37607,11 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf pDevice->opensl.currentBufferIndexCapture = 0; bufferSizeInBytes = pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * pDescriptorCapture->periodCount; - pDevice->opensl.pBufferCapture = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); + pDevice->opensl.pBufferCapture = (ma_uint8*)ma_calloc(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); if (pDevice->opensl.pBufferCapture == NULL) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer."); + return MA_OUT_OF_MEMORY; } MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes); } @@ -31649,19 +37628,22 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf resultSL = (*g_maEngineSL)->CreateOutputMix(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface."); + return ma_result_from_OpenSL(resultSL); } /* Set the output device. */ @@ -31682,7 +37664,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf sink.pFormat = NULL; resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); - if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { + if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; pcm.numChannels = 2; @@ -31695,7 +37677,8 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player."); + return ma_result_from_OpenSL(resultSL); } @@ -31714,25 +37697,29 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_PLAY, &pDevice->opensl.pAudioPlayer); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface."); + return ma_result_from_OpenSL(resultSL); } resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, ma_buffer_queue_callback_playback__opensl_android, pDevice); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback."); + return ma_result_from_OpenSL(resultSL); } /* The internal format is determined by the "pcm" object. */ @@ -31743,10 +37730,11 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf pDevice->opensl.currentBufferIndexPlayback = 0; bufferSizeInBytes = pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) * pDescriptorPlayback->periodCount; - pDevice->opensl.pBufferPlayback = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); + pDevice->opensl.pBufferPlayback = (ma_uint8*)ma_calloc(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks); if (pDevice->opensl.pBufferPlayback == NULL) { ma_device_uninit__opensl(pDevice); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer."); + return MA_OUT_OF_MEMORY; } MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes); } @@ -31773,7 +37761,8 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING); if (resultSL != SL_RESULT_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device."); + return ma_result_from_OpenSL(resultSL); } periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); @@ -31781,7 +37770,8 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device."); + return ma_result_from_OpenSL(resultSL); } } } @@ -31789,7 +37779,8 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING); if (resultSL != SL_RESULT_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device."); + return ma_result_from_OpenSL(resultSL); } /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueu silent buffers. */ @@ -31804,7 +37795,8 @@ static ma_result ma_device_start__opensl(ma_device* pDevice) resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pDevice->opensl.pBufferPlayback + (periodSizeInBytes * iPeriod), periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device."); + return ma_result_from_OpenSL(resultSL); } } } @@ -31849,7 +37841,6 @@ static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type devi static ma_result ma_device_stop__opensl(ma_device* pDevice) { SLresult resultSL; - ma_stop_proc onStop; MA_ASSERT(pDevice != NULL); @@ -31863,7 +37854,8 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice) resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); if (resultSL != SL_RESULT_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device."); + return ma_result_from_OpenSL(resultSL); } MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture); @@ -31874,17 +37866,15 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice) resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); if (resultSL != SL_RESULT_SUCCESS) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.", ma_result_from_OpenSL(resultSL)); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device."); + return ma_result_from_OpenSL(resultSL); } MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback); } /* Make sure the client is aware that the device has stopped. There may be an OpenSL|ES callback for this, but I haven't found it. */ - onStop = pDevice->onStop; - if (onStop) { - onStop(pDevice); - } + ma_device__on_notification_stopped(pDevice); return MA_SUCCESS; } @@ -31916,7 +37906,7 @@ static ma_result ma_dlsym_SLInterfaceID__opensl(ma_context* pContext, const char /* We need to return an error if the symbol cannot be found. This is important because there have been reports that some symbols do not exist. */ ma_handle* p = (ma_handle*)ma_dlsym(pContext, pContext->opensl.libOpenSLES, pName); if (p == NULL) { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol %s", pName); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol %s", pName); return MA_NO_BACKEND; } @@ -31979,7 +37969,7 @@ static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_ } if (pContext->opensl.libOpenSLES == NULL) { - ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Could not find libOpenSLES.so"); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Could not find libOpenSLES.so"); return MA_NO_BACKEND; } @@ -32028,7 +38018,7 @@ static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_ pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(pContext, pContext->opensl.libOpenSLES, "slCreateEngine"); if (pContext->opensl.slCreateEngine == NULL) { ma_dlclose(pContext, pContext->opensl.libOpenSLES); - ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol slCreateEngine."); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol slCreateEngine."); return MA_NO_BACKEND; } #else @@ -32052,7 +38042,7 @@ static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_ if (result != MA_SUCCESS) { ma_dlclose(pContext, pContext->opensl.libOpenSLES); - ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Failed to initialize OpenSL engine."); + ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Failed to initialize OpenSL engine."); return result; } @@ -32290,6 +38280,7 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d sampleRate = (pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE; periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__webaudio(pDescriptor, sampleRate, pConfig->performanceProfile); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "periodSizeInFrames = %d\n", (int)periodSizeInFrames); /* We create the device on the JavaScript side and reference it using an index. We use this to make it possible to reference the device between JavaScript and C. */ deviceIndex = EM_ASM_INT({ @@ -32299,7 +38290,7 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d var isCapture = $3; var pDevice = $4; - if (typeof(miniaudio) === 'undefined') { + if (typeof(window.miniaudio) === 'undefined') { return -1; /* Context not initialized. */ } @@ -32308,7 +38299,7 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d /* The AudioContext must be created in a suspended state. */ device.webaudio = new (window.AudioContext || window.webkitAudioContext)({sampleRate:sampleRate}); device.webaudio.suspend(); - device.state = 1; /* MA_STATE_STOPPED */ + device.state = 1; /* ma_device_state_stopped */ /* We need an intermediary buffer which we use for JavaScript and C interop. This buffer stores interleaved f32 PCM data. Because it's passed between @@ -32334,7 +38325,7 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d how well this would work. Although ScriptProccessorNode is deprecated, in practice it seems to have pretty good browser support so I'm leaving it like this for now. If anyone knows how I could get raw PCM data using the MediaRecorder API please let me know! */ - device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, channels, channels); + device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, (isCapture) ? channels : 0, (isCapture) ? 0 : channels); if (isCapture) { device.scriptNode.onaudioprocess = function(e) { @@ -32342,7 +38333,7 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d return; /* This means the device has been uninitialized. */ } - if(device.intermediaryBufferView.length == 0) { + if (device.intermediaryBufferView.length == 0) { /* Recreate intermediaryBufferView when losing reference to the underlying buffer, probably due to emscripten resizing heap. */ device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes); } @@ -32440,8 +38431,10 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d } } else { for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { + var outputBuffer = e.outputBuffer.getChannelData(iChannel); + var intermediaryBuffer = device.intermediaryBufferView; for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) { - e.outputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame] = device.intermediaryBufferView[iFrame*channels + iChannel]; + outputBuffer[totalFramesProcessed + iFrame] = intermediaryBuffer[iFrame*channels + iChannel]; } } } @@ -32466,12 +38459,12 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d pDevice->webaudio.indexPlayback = deviceIndex; } - pDescriptor->format = ma_format_f32; - pDescriptor->channels = channels; - ma_get_standard_channel_map(ma_standard_channel_map_webaudio, pDescriptor->channels, pDescriptor->channelMap); - pDescriptor->sampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); - pDescriptor->periodSizeInFrames = periodSizeInFrames; - pDescriptor->periodCount = 1; + pDescriptor->format = ma_format_f32; + pDescriptor->channels = channels; + ma_channel_map_init_standard(ma_standard_channel_map_webaudio, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); + pDescriptor->sampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); + pDescriptor->periodSizeInFrames = periodSizeInFrames; + pDescriptor->periodCount = 1; return MA_SUCCESS; } @@ -32518,7 +38511,7 @@ static ma_result ma_device_start__webaudio(ma_device* pDevice) EM_ASM({ var device = miniaudio.get_device_by_index($0); device.webaudio.resume(); - device.state = 2; /* MA_STATE_STARTED */ + device.state = 2; /* ma_device_state_started */ }, pDevice->webaudio.indexCapture); } @@ -32526,7 +38519,7 @@ static ma_result ma_device_start__webaudio(ma_device* pDevice) EM_ASM({ var device = miniaudio.get_device_by_index($0); device.webaudio.resume(); - device.state = 2; /* MA_STATE_STARTED */ + device.state = 2; /* ma_device_state_started */ }, pDevice->webaudio.indexPlayback); } @@ -32551,7 +38544,7 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice) EM_ASM({ var device = miniaudio.get_device_by_index($0); device.webaudio.suspend(); - device.state = 1; /* MA_STATE_STOPPED */ + device.state = 1; /* ma_device_state_stopped */ }, pDevice->webaudio.indexCapture); } @@ -32559,14 +38552,11 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice) EM_ASM({ var device = miniaudio.get_device_by_index($0); device.webaudio.suspend(); - device.state = 1; /* MA_STATE_STOPPED */ + device.state = 1; /* ma_device_state_stopped */ }, pDevice->webaudio.indexPlayback); } - ma_stop_proc onStop = pDevice->onStop; - if (onStop) { - onStop(pDevice); - } + ma_device__on_notification_stopped(pDevice); return MA_SUCCESS; } @@ -32596,8 +38586,8 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex return 0; /* Web Audio not supported. */ } - if (typeof(miniaudio) === 'undefined') { - miniaudio = {}; + if (typeof(window.miniaudio) === 'undefined') { + window.miniaudio = {}; miniaudio.devices = []; /* Device cache for mapping devices to indexes for JavaScript/C interop. */ miniaudio.track_device = function(device) { @@ -32647,7 +38637,7 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex miniaudio.unlock = function() { for(var i = 0; i < miniaudio.devices.length; ++i) { var device = miniaudio.devices[i]; - if (device != null && device.webaudio != null && device.state === 2 /* MA_STATE_STARTED */) { + if (device != null && device.webaudio != null && device.state === 2 /* ma_device_state_started */) { device.webaudio.resume(); } } @@ -32686,10 +38676,10 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex -static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint32 channels) +static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, ma_uint32 channels) { /* A blank channel map should be allowed, in which case it should use an appropriate default which will depend on context. */ - if (channelMap[0] != MA_CHANNEL_NONE) { + if (pChannelMap != NULL && pChannelMap[0] != MA_CHANNEL_NONE) { ma_uint32 iChannel; if (channels == 0 || channels > MA_MAX_CHANNELS) { @@ -32700,7 +38690,7 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint3 for (iChannel = 0; iChannel < channels; ++iChannel) { ma_uint32 jChannel; for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) { - if (channelMap[iChannel] == channelMap[jChannel]) { + if (pChannelMap[iChannel] == pChannelMap[jChannel]) { return MA_FALSE; } } @@ -32730,9 +38720,9 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels); } else { if (pDevice->capture.channelMixMode == ma_channel_mix_mode_simple) { - ma_channel_map_init_blank(pDevice->capture.channels, pDevice->capture.channelMap); + ma_channel_map_init_blank(pDevice->capture.channelMap, pDevice->capture.channels); } else { - ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.channels, pDevice->capture.channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pDevice->capture.channels); } } } @@ -32751,9 +38741,9 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels); } else { if (pDevice->playback.channelMixMode == ma_channel_mix_mode_simple) { - ma_channel_map_init_blank(pDevice->playback.channels, pDevice->playback.channelMap); + ma_channel_map_init_blank(pDevice->playback.channelMap, pDevice->playback.channels); } else { - ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.channels, pDevice->playback.channelMap); + ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pDevice->playback.channels); } } } @@ -32771,21 +38761,27 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { /* Converting from internal device format to client format. */ ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); - converterConfig.formatIn = pDevice->capture.internalFormat; - converterConfig.channelsIn = pDevice->capture.internalChannels; - converterConfig.sampleRateIn = pDevice->capture.internalSampleRate; - ma_channel_map_copy(converterConfig.channelMapIn, pDevice->capture.internalChannelMap, ma_min(pDevice->capture.internalChannels, MA_MAX_CHANNELS)); - converterConfig.formatOut = pDevice->capture.format; - converterConfig.channelsOut = pDevice->capture.channels; - converterConfig.sampleRateOut = pDevice->sampleRate; - ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, ma_min(pDevice->capture.channels, MA_MAX_CHANNELS)); - converterConfig.channelMixMode = pDevice->capture.channelMixMode; - converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; - converterConfig.resampling.algorithm = pDevice->resampling.algorithm; - converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; - converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality; + converterConfig.formatIn = pDevice->capture.internalFormat; + converterConfig.channelsIn = pDevice->capture.internalChannels; + converterConfig.sampleRateIn = pDevice->capture.internalSampleRate; + converterConfig.pChannelMapIn = pDevice->capture.internalChannelMap; + converterConfig.formatOut = pDevice->capture.format; + converterConfig.channelsOut = pDevice->capture.channels; + converterConfig.sampleRateOut = pDevice->sampleRate; + converterConfig.pChannelMapOut = pDevice->capture.channelMap; + converterConfig.channelMixMode = pDevice->capture.channelMixMode; + converterConfig.allowDynamicSampleRate = MA_FALSE; + converterConfig.resampling.algorithm = pDevice->resampling.algorithm; + converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; + converterConfig.resampling.pBackendVTable = pDevice->resampling.pBackendVTable; + converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData; - result = ma_data_converter_init(&converterConfig, &pDevice->capture.converter); + /* Make sure the old converter is uninitialized first. */ + if (ma_device_get_state(pDevice) != ma_device_state_uninitialized) { + ma_data_converter_uninit(&pDevice->capture.converter, &pDevice->pContext->allocationCallbacks); + } + + result = ma_data_converter_init(&converterConfig, &pDevice->pContext->allocationCallbacks, &pDevice->capture.converter); if (result != MA_SUCCESS) { return result; } @@ -32794,29 +38790,164 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { /* Converting from client format to device format. */ ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); - converterConfig.formatIn = pDevice->playback.format; - converterConfig.channelsIn = pDevice->playback.channels; - converterConfig.sampleRateIn = pDevice->sampleRate; - ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, ma_min(pDevice->playback.channels, MA_MAX_CHANNELS)); - converterConfig.formatOut = pDevice->playback.internalFormat; - converterConfig.channelsOut = pDevice->playback.internalChannels; - converterConfig.sampleRateOut = pDevice->playback.internalSampleRate; - ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, ma_min(pDevice->playback.internalChannels, MA_MAX_CHANNELS)); - converterConfig.channelMixMode = pDevice->playback.channelMixMode; - converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; - converterConfig.resampling.algorithm = pDevice->resampling.algorithm; - converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; - converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality; + converterConfig.formatIn = pDevice->playback.format; + converterConfig.channelsIn = pDevice->playback.channels; + converterConfig.sampleRateIn = pDevice->sampleRate; + converterConfig.pChannelMapIn = pDevice->playback.channelMap; + converterConfig.formatOut = pDevice->playback.internalFormat; + converterConfig.channelsOut = pDevice->playback.internalChannels; + converterConfig.sampleRateOut = pDevice->playback.internalSampleRate; + converterConfig.pChannelMapOut = pDevice->playback.internalChannelMap; + converterConfig.channelMixMode = pDevice->playback.channelMixMode; + converterConfig.allowDynamicSampleRate = MA_FALSE; + converterConfig.resampling.algorithm = pDevice->resampling.algorithm; + converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; + converterConfig.resampling.pBackendVTable = pDevice->resampling.pBackendVTable; + converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData; - result = ma_data_converter_init(&converterConfig, &pDevice->playback.converter); + /* Make sure the old converter is uninitialized first. */ + if (ma_device_get_state(pDevice) != ma_device_state_uninitialized) { + ma_data_converter_uninit(&pDevice->playback.converter, &pDevice->pContext->allocationCallbacks); + } + + result = ma_data_converter_init(&converterConfig, &pDevice->pContext->allocationCallbacks, &pDevice->playback.converter); if (result != MA_SUCCESS) { return result; } } + + /* + In playback mode, if the data converter does not support retrieval of the required number of + input frames given a number of output frames, we need to fall back to a heap-allocated cache. + */ + if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { + ma_uint64 unused; + + pDevice->playback.inputCacheConsumed = 0; + pDevice->playback.inputCacheRemaining = 0; + + if (deviceType == ma_device_type_duplex || ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, 1, &unused) != MA_SUCCESS) { + /* We need a heap allocated cache. We want to size this based on the period size. */ + void* pNewInputCache; + ma_uint64 newInputCacheCap; + ma_uint64 newInputCacheSizeInBytes; + + newInputCacheCap = ma_calculate_frame_count_after_resampling(pDevice->playback.internalSampleRate, pDevice->sampleRate, pDevice->playback.internalPeriodSizeInFrames); + + newInputCacheSizeInBytes = newInputCacheCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + if (newInputCacheSizeInBytes > MA_SIZE_MAX) { + ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); + pDevice->playback.pInputCache = NULL; + pDevice->playback.inputCacheCap = 0; + return MA_OUT_OF_MEMORY; /* Allocation too big. Should never hit this, but makes the cast below safer for 32-bit builds. */ + } + + pNewInputCache = ma_realloc(pDevice->playback.pInputCache, (size_t)newInputCacheSizeInBytes, &pDevice->pContext->allocationCallbacks); + if (pNewInputCache == NULL) { + ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); + pDevice->playback.pInputCache = NULL; + pDevice->playback.inputCacheCap = 0; + return MA_OUT_OF_MEMORY; + } + + pDevice->playback.pInputCache = pNewInputCache; + pDevice->playback.inputCacheCap = newInputCacheCap; + } else { + /* Heap allocation not required. Make sure we clear out the old cache just in case this function was called in response to a route change. */ + ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); + pDevice->playback.pInputCache = NULL; + pDevice->playback.inputCacheCap = 0; + } + } + return MA_SUCCESS; } +MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pDescriptorPlayback, const ma_device_descriptor* pDescriptorCapture) +{ + ma_result result; + + if (pDevice == NULL) { + return MA_INVALID_ARGS; + } + + /* Capture. */ + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { + if (ma_device_descriptor_is_valid(pDescriptorCapture) == MA_FALSE) { + return MA_INVALID_ARGS; + } + + pDevice->capture.internalFormat = pDescriptorCapture->format; + pDevice->capture.internalChannels = pDescriptorCapture->channels; + pDevice->capture.internalSampleRate = pDescriptorCapture->sampleRate; + MA_COPY_MEMORY(pDevice->capture.internalChannelMap, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap)); + pDevice->capture.internalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames; + pDevice->capture.internalPeriods = pDescriptorCapture->periodCount; + + if (pDevice->capture.internalPeriodSizeInFrames == 0) { + pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptorCapture->periodSizeInMilliseconds, pDescriptorCapture->sampleRate); + } + } + + /* Playback. */ + if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { + if (ma_device_descriptor_is_valid(pDescriptorPlayback) == MA_FALSE) { + return MA_INVALID_ARGS; + } + + pDevice->playback.internalFormat = pDescriptorPlayback->format; + pDevice->playback.internalChannels = pDescriptorPlayback->channels; + pDevice->playback.internalSampleRate = pDescriptorPlayback->sampleRate; + MA_COPY_MEMORY(pDevice->playback.internalChannelMap, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap)); + pDevice->playback.internalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames; + pDevice->playback.internalPeriods = pDescriptorPlayback->periodCount; + + if (pDevice->playback.internalPeriodSizeInFrames == 0) { + pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptorPlayback->periodSizeInMilliseconds, pDescriptorPlayback->sampleRate); + } + } + + /* + The name of the device can be retrieved from device info. This may be temporary and replaced with a `ma_device_get_info(pDevice, deviceType)` instead. + For loopback devices, we need to retrieve the name of the playback device. + */ + { + ma_device_info deviceInfo; + + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { + result = ma_device_get_info(pDevice, (deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, &deviceInfo); + if (result == MA_SUCCESS) { + ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1); + } else { + /* We failed to retrieve the device info. Fall back to a default name. */ + if (pDescriptorCapture->pDeviceID == NULL) { + ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "Capture Device", (size_t)-1); + } + } + } + + if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { + result = ma_device_get_info(pDevice, ma_device_type_playback, &deviceInfo); + if (result == MA_SUCCESS) { + ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1); + } else { + /* We failed to retrieve the device info. Fall back to a default name. */ + if (pDescriptorPlayback->pDeviceID == NULL) { + ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "Playback Device", (size_t)-1); + } + } + } + } + + /* Update data conversion. */ + return ma_device__post_init_setup(pDevice, deviceType); /* TODO: Should probably rename ma_device__post_init_setup() to something better. */ +} + static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) { @@ -32828,17 +38959,17 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) #endif /* - When the device is being initialized it's initial state is set to MA_STATE_UNINITIALIZED. Before returning from + When the device is being initialized it's initial state is set to ma_device_state_uninitialized. Before returning from ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker thread to signal an event to know when the worker thread is ready for action. */ - ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_device__set_state(pDevice, ma_device_state_stopped); ma_event_signal(&pDevice->stopEvent); for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */ ma_result startResult; - ma_result stopResult; /* <-- This will store the result from onDeviceStop(). If it returns an error, we don't fire the onStop callback. */ + ma_result stopResult; /* <-- This will store the result from onDeviceStop(). If it returns an error, we don't fire the stopped notification callback. */ /* We wait on an event to know when something has requested that the device be started and the main loop entered. */ ma_event_wait(&pDevice->wakeupEvent); @@ -32847,7 +38978,7 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) pDevice->workResult = MA_SUCCESS; /* If the reason for the wake up is that we are terminating, just break from the loop. */ - if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) { + if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { break; } @@ -32856,7 +38987,7 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) be started will be waiting on an event (pDevice->startEvent) which means we need to make sure we signal the event in both the success and error case. It's important that the state of the device is set _before_ signaling the event. */ - MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STARTING); + MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_starting); /* If the device has a start callback, start it now. */ if (pDevice->pContext->callbacks.onDeviceStart != NULL) { @@ -32865,15 +38996,22 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) startResult = MA_SUCCESS; } + /* + If starting was not successful we'll need to loop back to the start and wait for something + to happen (pDevice->wakeupEvent). + */ if (startResult != MA_SUCCESS) { pDevice->workResult = startResult; - continue; /* Failed to start. Loop back to the start and wait for something to happen (pDevice->wakeupEvent). */ + ma_event_signal(&pDevice->startEvent); /* <-- Always signal the start event so ma_device_start() can return as it'll be waiting on it. */ + continue; } /* Make sure the state is set appropriately. */ - ma_device__set_state(pDevice, MA_STATE_STARTED); + ma_device__set_state(pDevice, ma_device_state_started); /* <-- Set this before signaling the event so that the state is always guaranteed to be good after ma_device_start() has returned. */ ma_event_signal(&pDevice->startEvent); + ma_device__on_notification_started(pDevice); + if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) { pDevice->pContext->callbacks.onDeviceDataLoop(pDevice); } else { @@ -32889,16 +39027,16 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) } /* - After the device has stopped, make sure an event is posted. Don't post an onStop event if + After the device has stopped, make sure an event is posted. Don't post a stopped event if stopping failed. This can happen on some backends when the underlying stream has been stopped due to the device being physically unplugged or disabled via an OS setting. */ - if (pDevice->onStop && stopResult != MA_SUCCESS) { - pDevice->onStop(pDevice); + if (stopResult == MA_SUCCESS) { + ma_device__on_notification_stopped(pDevice); } /* A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. */ - ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_device__set_state(pDevice, ma_device_state_stopped); ma_event_signal(&pDevice->stopEvent); } @@ -32917,17 +39055,22 @@ static ma_bool32 ma_device__is_initialized(ma_device* pDevice) return MA_FALSE; } - return ma_device_get_state(pDevice) != MA_STATE_UNINITIALIZED; + return ma_device_get_state(pDevice) != ma_device_state_uninitialized; } #ifdef MA_WIN32 static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { + /* For some reason UWP complains when CoUninitialize() is called. I'm just not going to call it on UWP. */ +#ifdef MA_WIN32_DESKTOP ma_CoUninitialize(pContext); ma_dlclose(pContext, pContext->win32.hUser32DLL); ma_dlclose(pContext, pContext->win32.hOle32DLL); ma_dlclose(pContext, pContext->win32.hAdvapi32DLL); +#else + (void)pContext; +#endif return MA_SUCCESS; } @@ -33087,7 +39230,138 @@ static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext) } -MA_API ma_context_config ma_context_config_init() +/* The default capacity doesn't need to be too big. */ +#ifndef MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY +#define MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY 32 +#endif + +MA_API ma_device_job_thread_config ma_device_job_thread_config_init(void) +{ + ma_device_job_thread_config config; + + MA_ZERO_OBJECT(&config); + config.noThread = MA_FALSE; + config.jobQueueCapacity = MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY; + config.jobQueueFlags = 0; + + return config; +} + + +static ma_thread_result MA_THREADCALL ma_device_job_thread_entry(void* pUserData) +{ + ma_device_job_thread* pJobThread = (ma_device_job_thread*)pUserData; + MA_ASSERT(pJobThread != NULL); + + for (;;) { + ma_result result; + ma_job job; + + result = ma_device_job_thread_next(pJobThread, &job); + if (result != MA_SUCCESS) { + break; + } + + if (job.toc.breakup.code == MA_JOB_TYPE_QUIT) { + break; + } + + ma_job_process(&job); + } + + return (ma_thread_result)0; +} + +MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_job_thread* pJobThread) +{ + ma_result result; + ma_job_queue_config jobQueueConfig; + + if (pJobThread == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pJobThread); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + + /* Initialize the job queue before the thread to ensure it's in a valid state. */ + jobQueueConfig = ma_job_queue_config_init(pConfig->jobQueueFlags, pConfig->jobQueueCapacity); + + result = ma_job_queue_init(&jobQueueConfig, pAllocationCallbacks, &pJobThread->jobQueue); + if (result != MA_SUCCESS) { + return result; /* Failed to initialize job queue. */ + } + + + /* The thread needs to be initialized after the job queue to ensure the thread doesn't try to access it prematurely. */ + if (pConfig->noThread == MA_FALSE) { + result = ma_thread_create(&pJobThread->thread, ma_thread_priority_normal, 0, ma_device_job_thread_entry, pJobThread, pAllocationCallbacks); + if (result != MA_SUCCESS) { + ma_job_queue_uninit(&pJobThread->jobQueue, pAllocationCallbacks); + return result; /* Failed to create the job thread. */ + } + + pJobThread->_hasThread = MA_TRUE; + } else { + pJobThread->_hasThread = MA_FALSE; + } + + + return MA_SUCCESS; +} + +MA_API void ma_device_job_thread_uninit(ma_device_job_thread* pJobThread, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pJobThread == NULL) { + return; + } + + /* The first thing to do is post a quit message to the job queue. If we're using a thread we'll need to wait for it. */ + { + ma_job job = ma_job_init(MA_JOB_TYPE_QUIT); + ma_device_job_thread_post(pJobThread, &job); + } + + /* Wait for the thread to terminate naturally. */ + if (pJobThread->_hasThread) { + ma_thread_wait(&pJobThread->thread); + } + + /* At this point the thread should be terminated so we can safely uninitialize the job queue. */ + ma_job_queue_uninit(&pJobThread->jobQueue, pAllocationCallbacks); +} + +MA_API ma_result ma_device_job_thread_post(ma_device_job_thread* pJobThread, const ma_job* pJob) +{ + if (pJobThread == NULL || pJob == NULL) { + return MA_INVALID_ARGS; + } + + return ma_job_queue_post(&pJobThread->jobQueue, pJob); +} + +MA_API ma_result ma_device_job_thread_next(ma_device_job_thread* pJobThread, ma_job* pJob) +{ + if (pJob == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pJob); + + if (pJobThread == NULL) { + return MA_INVALID_ARGS; + } + + return ma_job_queue_next(&pJobThread->jobQueue, pJob); +} + + + +MA_API ma_context_config ma_context_config_init(void) { ma_context_config config; MA_ZERO_OBJECT(&config); @@ -33134,7 +39408,6 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC } } - pContext->logCallback = pConfig->logCallback; pContext->threadPriority = pConfig->threadPriority; pContext->threadStackSize = pConfig->threadStackSize; pContext->pUserData = pConfig->pUserData; @@ -33272,23 +39545,19 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC if (result == MA_SUCCESS) { result = ma_mutex_init(&pContext->deviceEnumLock); if (result != MA_SUCCESS) { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.\n", result); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.\n"); } result = ma_mutex_init(&pContext->deviceInfoLock); if (result != MA_SUCCESS) { - ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n", result); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n"); } - #ifdef MA_DEBUG_OUTPUT - { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] Endian: %s\n", ma_is_little_endian() ? "LE" : "BE"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] SSE2: %s\n", ma_has_sse2() ? "YES" : "NO"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] AVX2: %s\n", ma_has_avx2() ? "YES" : "NO"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] AVX512F: %s\n", ma_has_avx512f() ? "YES" : "NO"); - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] NEON: %s\n", ma_has_neon() ? "YES" : "NO"); - } - #endif + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "System Architecture:\n"); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " Endian: %s\n", ma_is_little_endian() ? "LE" : "BE"); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " SSE2: %s\n", ma_has_sse2() ? "YES" : "NO"); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " AVX2: %s\n", ma_has_avx2() ? "YES" : "NO"); + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " NEON: %s\n", ma_has_neon() ? "YES" : "NO"); pContext->backend = backend; return result; @@ -33314,7 +39583,7 @@ MA_API ma_result ma_context_uninit(ma_context* pContext) ma_mutex_uninit(&pContext->deviceEnumLock); ma_mutex_uninit(&pContext->deviceInfoLock); - ma__free_from_callbacks(pContext->pDeviceInfos, &pContext->allocationCallbacks); + ma_free(pContext->pDeviceInfos, &pContext->allocationCallbacks); ma_context_uninit_backend_apis(pContext); if (pContext->pLog == &pContext->log) { @@ -33377,9 +39646,8 @@ static ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_ const ma_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount; if (totalDeviceInfoCount >= pContext->deviceInfoCapacity) { - ma_uint32 oldCapacity = pContext->deviceInfoCapacity; - ma_uint32 newCapacity = oldCapacity + bufferExpansionCount; - ma_device_info* pNewInfos = (ma_device_info*)ma__realloc_from_callbacks(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, sizeof(*pContext->pDeviceInfos)*oldCapacity, &pContext->allocationCallbacks); + ma_uint32 newCapacity = pContext->deviceInfoCapacity + bufferExpansionCount; + ma_device_info* pNewInfos = (ma_device_info*)ma_realloc(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, &pContext->allocationCallbacks); if (pNewInfos == NULL) { return MA_FALSE; /* Out of memory. */ } @@ -33461,13 +39729,11 @@ MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** p return result; } -MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) +MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) { ma_result result; ma_device_info deviceInfo; - (void)shareMode; /* Unused. This parameter will be removed in version 0.11. */ - /* NOTE: Do not clear pDeviceInfo on entry. The reason is the pDeviceID may actually point to pDeviceInfo->id which will break things. */ if (pContext == NULL || pDeviceInfo == NULL) { return MA_INVALID_ARGS; @@ -33490,81 +39756,6 @@ MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type } ma_mutex_unlock(&pContext->deviceInfoLock); - /* - If the backend is using the new device info system, do a pass to fill out the old settings for backwards compatibility. This will be removed in - the future when all backends have implemented the new device info system. - */ - if (deviceInfo.nativeDataFormatCount > 0) { - ma_uint32 iNativeFormat; - ma_uint32 iSampleFormat; - - deviceInfo.minChannels = 0xFFFFFFFF; - deviceInfo.maxChannels = 0; - deviceInfo.minSampleRate = 0xFFFFFFFF; - deviceInfo.maxSampleRate = 0; - - for (iNativeFormat = 0; iNativeFormat < deviceInfo.nativeDataFormatCount; iNativeFormat += 1) { - /* Formats. */ - if (deviceInfo.nativeDataFormats[iNativeFormat].format == ma_format_unknown) { - /* All formats are supported. */ - deviceInfo.formats[0] = ma_format_u8; - deviceInfo.formats[1] = ma_format_s16; - deviceInfo.formats[2] = ma_format_s24; - deviceInfo.formats[3] = ma_format_s32; - deviceInfo.formats[4] = ma_format_f32; - deviceInfo.formatCount = 5; - } else { - /* Make sure the format isn't already in the list. If so, skip. */ - ma_bool32 alreadyExists = MA_FALSE; - for (iSampleFormat = 0; iSampleFormat < deviceInfo.formatCount; iSampleFormat += 1) { - if (deviceInfo.formats[iSampleFormat] == deviceInfo.nativeDataFormats[iNativeFormat].format) { - alreadyExists = MA_TRUE; - break; - } - } - - if (!alreadyExists) { - deviceInfo.formats[deviceInfo.formatCount++] = deviceInfo.nativeDataFormats[iNativeFormat].format; - } - } - - /* Channels. */ - if (deviceInfo.nativeDataFormats[iNativeFormat].channels == 0) { - /* All channels supported. */ - deviceInfo.minChannels = MA_MIN_CHANNELS; - deviceInfo.maxChannels = MA_MAX_CHANNELS; - } else { - if (deviceInfo.minChannels > deviceInfo.nativeDataFormats[iNativeFormat].channels) { - deviceInfo.minChannels = deviceInfo.nativeDataFormats[iNativeFormat].channels; - } - if (deviceInfo.maxChannels < deviceInfo.nativeDataFormats[iNativeFormat].channels) { - deviceInfo.maxChannels = deviceInfo.nativeDataFormats[iNativeFormat].channels; - } - } - - /* Sample rate. */ - if (deviceInfo.nativeDataFormats[iNativeFormat].sampleRate == 0) { - /* All sample rates supported. */ - deviceInfo.minSampleRate = (ma_uint32)ma_standard_sample_rate_min; - deviceInfo.maxSampleRate = (ma_uint32)ma_standard_sample_rate_max; - } else { - if (deviceInfo.minSampleRate > deviceInfo.nativeDataFormats[iNativeFormat].sampleRate) { - deviceInfo.minSampleRate = deviceInfo.nativeDataFormats[iNativeFormat].sampleRate; - } - if (deviceInfo.maxSampleRate < deviceInfo.nativeDataFormats[iNativeFormat].sampleRate) { - deviceInfo.maxSampleRate = deviceInfo.nativeDataFormats[iNativeFormat].sampleRate; - } - } - } - } - - - /* Clamp ranges. */ - deviceInfo.minChannels = ma_max(deviceInfo.minChannels, MA_MIN_CHANNELS); - deviceInfo.maxChannels = ma_min(deviceInfo.maxChannels, MA_MAX_CHANNELS); - deviceInfo.minSampleRate = ma_max(deviceInfo.minSampleRate, (ma_uint32)ma_standard_sample_rate_min); - deviceInfo.maxSampleRate = ma_min(deviceInfo.maxSampleRate, (ma_uint32)ma_standard_sample_rate_max); - *pDeviceInfo = deviceInfo; return result; } @@ -33584,11 +39775,7 @@ MA_API ma_device_config ma_device_config_init(ma_device_type deviceType) ma_device_config config; MA_ZERO_OBJECT(&config); config.deviceType = deviceType; - - /* Resampling defaults. We must never use the Speex backend by default because it uses licensed third party code. */ - config.resampling.algorithm = ma_resample_algorithm_linear; - config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); - config.resampling.speex.quality = 3; + config.resampling = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); /* Format/channels/rate don't matter here. */ return config; } @@ -33605,92 +39792,92 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC } if (pDevice == NULL) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); + return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pDevice); if (pConfig == NULL) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pConfig == NULL).", MA_INVALID_ARGS); + return MA_INVALID_ARGS; } - /* Check that we have our callbacks defined. */ if (pContext->callbacks.onDeviceInit == NULL) { return MA_INVALID_OPERATION; } - /* Basic config validation. */ - if (pConfig->deviceType != ma_device_type_playback && pConfig->deviceType != ma_device_type_capture && pConfig->deviceType != ma_device_type_duplex && pConfig->deviceType != ma_device_type_loopback) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Device type is invalid. Make sure the device type has been set in the config.", MA_INVALID_DEVICE_CONFIG); - } - if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->capture.channels > MA_MAX_CHANNELS) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Capture channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG); + return MA_INVALID_ARGS; } - if (!ma__is_channel_map_valid(pConfig->capture.channelMap, pConfig->capture.channels)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Capture channel map is invalid.", MA_INVALID_DEVICE_CONFIG); + + if (!ma__is_channel_map_valid(pConfig->capture.pChannelMap, pConfig->capture.channels)) { + return MA_INVALID_ARGS; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { if (pConfig->playback.channels > MA_MAX_CHANNELS) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Playback channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG); + return MA_INVALID_ARGS; } - if (!ma__is_channel_map_valid(pConfig->playback.channelMap, pConfig->playback.channels)) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Playback channel map is invalid.", MA_INVALID_DEVICE_CONFIG); + + if (!ma__is_channel_map_valid(pConfig->playback.pChannelMap, pConfig->playback.channels)) { + return MA_INVALID_ARGS; } } pDevice->pContext = pContext; /* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */ - pDevice->pUserData = pConfig->pUserData; - pDevice->onData = pConfig->dataCallback; - pDevice->onStop = pConfig->stopCallback; - - if (((ma_uintptr)pDevice % sizeof(pDevice)) != 0) { - if (pContext->logCallback) { - pContext->logCallback(pContext, pDevice, MA_LOG_LEVEL_WARNING, "WARNING: ma_device_init() called for a device that is not properly aligned. Thread safety is not supported."); - } - } + pDevice->pUserData = pConfig->pUserData; + pDevice->onData = pConfig->dataCallback; + pDevice->onNotification = pConfig->notificationCallback; + pDevice->onStop = pConfig->stopCallback; if (pConfig->playback.pDeviceID != NULL) { MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id)); + pDevice->playback.pID = &pDevice->playback.id; + } else { + pDevice->playback.pID = NULL; } if (pConfig->capture.pDeviceID != NULL) { MA_COPY_MEMORY(&pDevice->capture.id, pConfig->capture.pDeviceID, sizeof(pDevice->capture.id)); + pDevice->capture.pID = &pDevice->capture.id; + } else { + pDevice->capture.pID = NULL; } - pDevice->noPreZeroedOutputBuffer = pConfig->noPreZeroedOutputBuffer; - pDevice->noClip = pConfig->noClip; - pDevice->masterVolumeFactor = 1; + pDevice->noPreSilencedOutputBuffer = pConfig->noPreSilencedOutputBuffer; + pDevice->noClip = pConfig->noClip; + pDevice->noDisableDenormals = pConfig->noDisableDenormals; + pDevice->noFixedSizedCallback = pConfig->noFixedSizedCallback; + pDevice->masterVolumeFactor = 1; - pDevice->type = pConfig->deviceType; - pDevice->sampleRate = pConfig->sampleRate; - pDevice->resampling.algorithm = pConfig->resampling.algorithm; - pDevice->resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder; - pDevice->resampling.speex.quality = pConfig->resampling.speex.quality; + pDevice->type = pConfig->deviceType; + pDevice->sampleRate = pConfig->sampleRate; + pDevice->resampling.algorithm = pConfig->resampling.algorithm; + pDevice->resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder; + pDevice->resampling.pBackendVTable = pConfig->resampling.pBackendVTable; + pDevice->resampling.pBackendUserData = pConfig->resampling.pBackendUserData; - pDevice->capture.shareMode = pConfig->capture.shareMode; - pDevice->capture.format = pConfig->capture.format; - pDevice->capture.channels = pConfig->capture.channels; - ma_channel_map_copy(pDevice->capture.channelMap, pConfig->capture.channelMap, pConfig->capture.channels); - pDevice->capture.channelMixMode = pConfig->capture.channelMixMode; + pDevice->capture.shareMode = pConfig->capture.shareMode; + pDevice->capture.format = pConfig->capture.format; + pDevice->capture.channels = pConfig->capture.channels; + ma_channel_map_copy_or_default(pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pConfig->capture.pChannelMap, pConfig->capture.channels); + pDevice->capture.channelMixMode = pConfig->capture.channelMixMode; - pDevice->playback.shareMode = pConfig->playback.shareMode; - pDevice->playback.format = pConfig->playback.format; - pDevice->playback.channels = pConfig->playback.channels; - ma_channel_map_copy(pDevice->playback.channelMap, pConfig->playback.channelMap, pConfig->playback.channels); - pDevice->playback.channelMixMode = pConfig->playback.channelMixMode; + pDevice->playback.shareMode = pConfig->playback.shareMode; + pDevice->playback.format = pConfig->playback.format; + pDevice->playback.channels = pConfig->playback.channels; + ma_channel_map_copy_or_default(pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pConfig->playback.pChannelMap, pConfig->playback.channels); + pDevice->playback.channelMixMode = pConfig->playback.channelMixMode; result = ma_mutex_init(&pDevice->startStopLock); if (result != MA_SUCCESS) { - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result); + return result; } /* @@ -33703,14 +39890,14 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC result = ma_event_init(&pDevice->wakeupEvent); if (result != MA_SUCCESS) { ma_mutex_uninit(&pDevice->startStopLock); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result); + return result; } result = ma_event_init(&pDevice->startEvent); if (result != MA_SUCCESS) { ma_event_uninit(&pDevice->wakeupEvent); ma_mutex_uninit(&pDevice->startStopLock); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result); + return result; } result = ma_event_init(&pDevice->stopEvent); @@ -33718,7 +39905,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ma_event_uninit(&pDevice->startEvent); ma_event_uninit(&pDevice->wakeupEvent); ma_mutex_uninit(&pDevice->startStopLock); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result); + return result; } @@ -33728,7 +39915,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC descriptorPlayback.format = pConfig->playback.format; descriptorPlayback.channels = pConfig->playback.channels; descriptorPlayback.sampleRate = pConfig->sampleRate; - ma_channel_map_copy(descriptorPlayback.channelMap, pConfig->playback.channelMap, pConfig->playback.channels); + ma_channel_map_copy_or_default(descriptorPlayback.channelMap, ma_countof(descriptorPlayback.channelMap), pConfig->playback.pChannelMap, pConfig->playback.channels); descriptorPlayback.periodSizeInFrames = pConfig->periodSizeInFrames; descriptorPlayback.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds; descriptorPlayback.periodCount = pConfig->periods; @@ -33744,7 +39931,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC descriptorCapture.format = pConfig->capture.format; descriptorCapture.channels = pConfig->capture.channels; descriptorCapture.sampleRate = pConfig->sampleRate; - ma_channel_map_copy(descriptorCapture.channelMap, pConfig->capture.channelMap, pConfig->capture.channels); + ma_channel_map_copy_or_default(descriptorCapture.channelMap, ma_countof(descriptorCapture.channelMap), pConfig->capture.pChannelMap, pConfig->capture.channels); descriptorCapture.periodSizeInFrames = pConfig->periodSizeInFrames; descriptorCapture.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds; descriptorCapture.periodCount = pConfig->periods; @@ -33762,7 +39949,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC return result; } - +#if 0 /* On output the descriptors will contain the *actual* data format of the device. We need this to know how to convert the data between the requested format and the internal format. @@ -33812,7 +39999,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ma_device_info deviceInfo; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { - result = ma_context_get_device_info(pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, descriptorCapture.pDeviceID, descriptorCapture.shareMode, &deviceInfo); + result = ma_device_get_info(pDevice, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, &deviceInfo); if (result == MA_SUCCESS) { ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1); } else { @@ -33826,7 +40013,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { - result = ma_context_get_device_info(pContext, ma_device_type_playback, descriptorPlayback.pDeviceID, descriptorPlayback.shareMode, &deviceInfo); + result = ma_device_get_info(pDevice, ma_device_type_playback, &deviceInfo); if (result == MA_SUCCESS) { ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1); } else { @@ -33842,6 +40029,77 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ma_device__post_init_setup(pDevice, pConfig->deviceType); +#endif + + result = ma_device_post_init(pDevice, pConfig->deviceType, &descriptorPlayback, &descriptorCapture); + if (result != MA_SUCCESS) { + ma_device_uninit(pDevice); + return result; + } + + + + /* + If we're using fixed sized callbacks we'll need to make use of an intermediary buffer. Needs to + be done after post_init_setup() because we'll need access to the sample rate. + */ + if (pConfig->noFixedSizedCallback == MA_FALSE) { + /* We're using a fixed sized data callback so we'll need an intermediary buffer. */ + ma_uint32 intermediaryBufferCap = pConfig->periodSizeInFrames; + if (intermediaryBufferCap == 0) { + intermediaryBufferCap = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pDevice->sampleRate); + } + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { + ma_uint32 intermediaryBufferSizeInBytes; + + pDevice->capture.intermediaryBufferLen = 0; + pDevice->capture.intermediaryBufferCap = intermediaryBufferCap; + if (pDevice->capture.intermediaryBufferCap == 0) { + pDevice->capture.intermediaryBufferCap = pDevice->capture.internalPeriodSizeInFrames; + } + + intermediaryBufferSizeInBytes = pDevice->capture.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + + pDevice->capture.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks); + if (pDevice->capture.pIntermediaryBuffer == NULL) { + ma_device_uninit(pDevice); + return MA_OUT_OF_MEMORY; + } + + /* Silence the buffer for safety. */ + ma_silence_pcm_frames(pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap, pDevice->capture.format, pDevice->capture.channels); + pDevice->capture.intermediaryBufferLen = pDevice->capture.intermediaryBufferCap; + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_uint64 intermediaryBufferSizeInBytes; + + pDevice->playback.intermediaryBufferLen = 0; + if (pConfig->deviceType == ma_device_type_duplex) { + pDevice->playback.intermediaryBufferCap = pDevice->capture.intermediaryBufferCap; /* In duplex mode, make sure the intermediary buffer is always the same size as the capture side. */ + } else { + pDevice->playback.intermediaryBufferCap = intermediaryBufferCap; + if (pDevice->playback.intermediaryBufferCap == 0) { + pDevice->playback.intermediaryBufferCap = pDevice->playback.internalPeriodSizeInFrames; + } + } + + intermediaryBufferSizeInBytes = pDevice->playback.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + pDevice->playback.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks); + if (pDevice->playback.pIntermediaryBuffer == NULL) { + ma_device_uninit(pDevice); + return MA_OUT_OF_MEMORY; + } + + /* Silence the buffer for safety. */ + ma_silence_pcm_frames(pDevice->playback.pIntermediaryBuffer, pDevice->playback.intermediaryBufferCap, pDevice->playback.format, pDevice->playback.channels); + pDevice->playback.intermediaryBufferLen = 0; + } + } else { + /* Not using a fixed sized data callback so no need for an intermediary buffer. */ + } /* Some backends don't require the worker thread. */ @@ -33850,12 +40108,12 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice, &pContext->allocationCallbacks); if (result != MA_SUCCESS) { ma_device_uninit(pDevice); - return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result); + return result; } /* Wait for the worker thread to put the device into it's stopped state for real. */ ma_event_wait(&pDevice->stopEvent); - MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED); + MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); } else { /* If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done @@ -33871,39 +40129,47 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC } } - ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_device__set_state(pDevice, ma_device_state_stopped); } + /* Log device information. */ + { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend)); + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; + ma_device_get_name(pDevice, ma_device_type_capture, name, sizeof(name), NULL); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend)); - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", pDevice->capture.name, "Capture"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); - } - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", pDevice->playback.name, "Playback"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods)); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO"); - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Capture"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format)); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods)); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); + } + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; + ma_device_get_name(pDevice, ma_device_type_playback, name, sizeof(name), NULL); + + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Playback"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat)); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods)); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO"); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); + } } - MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED); + MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); return MA_SUCCESS; } @@ -33931,7 +40197,7 @@ MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backen } - pContext = (ma_context*)ma__malloc_from_callbacks(sizeof(*pContext), &allocationCallbacks); + pContext = (ma_context*)ma_malloc(sizeof(*pContext), &allocationCallbacks); if (pContext == NULL) { return MA_OUT_OF_MEMORY; } @@ -33962,7 +40228,7 @@ MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backen } if (result != MA_SUCCESS) { - ma__free_from_callbacks(pContext, &allocationCallbacks); + ma_free(pContext, &allocationCallbacks); return result; } @@ -33982,7 +40248,7 @@ MA_API void ma_device_uninit(ma_device* pDevice) } /* Putting the device into an uninitialized state will make the worker thread return. */ - ma_device__set_state(pDevice, MA_STATE_UNINITIALIZED); + ma_device__set_state(pDevice, ma_device_state_uninitialized); /* Wake up the worker thread and wait for it to properly terminate. */ if (!ma_context_is_backend_asynchronous(pDevice->pContext)) { @@ -34006,11 +40272,29 @@ MA_API void ma_device_uninit(ma_device* pDevice) } } + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { + ma_data_converter_uninit(&pDevice->capture.converter, &pDevice->pContext->allocationCallbacks); + } + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_data_converter_uninit(&pDevice->playback.converter, &pDevice->pContext->allocationCallbacks); + } + + if (pDevice->playback.pInputCache != NULL) { + ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); + } + + if (pDevice->capture.pIntermediaryBuffer != NULL) { + ma_free(pDevice->capture.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks); + } + if (pDevice->playback.pIntermediaryBuffer != NULL) { + ma_free(pDevice->playback.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks); + } + if (pDevice->isOwnerOfContext) { ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks; ma_context_uninit(pDevice->pContext); - ma__free_from_callbacks(pDevice->pContext, &allocationCallbacks); + ma_free(pDevice->pContext, &allocationCallbacks); } MA_ZERO_OBJECT(pDevice); @@ -34030,28 +40314,92 @@ MA_API ma_log* ma_device_get_log(ma_device* pDevice) return ma_context_get_log(ma_device_get_context(pDevice)); } +MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo) +{ + if (pDeviceInfo == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDeviceInfo); + + if (pDevice == NULL) { + return MA_INVALID_ARGS; + } + + /* If the onDeviceGetInfo() callback is set, use that. Otherwise we'll fall back to ma_context_get_device_info(). */ + if (pDevice->pContext->callbacks.onDeviceGetInfo != NULL) { + return pDevice->pContext->callbacks.onDeviceGetInfo(pDevice, type, pDeviceInfo); + } + + /* Getting here means onDeviceGetInfo is not implemented so we need to fall back to an alternative. */ + if (type == ma_device_type_playback) { + return ma_context_get_device_info(pDevice->pContext, type, pDevice->playback.pID, pDeviceInfo); + } else { + return ma_context_get_device_info(pDevice->pContext, type, pDevice->capture.pID, pDeviceInfo); + } +} + +MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator) +{ + ma_result result; + ma_device_info deviceInfo; + + if (pLengthNotIncludingNullTerminator != NULL) { + *pLengthNotIncludingNullTerminator = 0; + } + + if (pName != NULL && nameCap > 0) { + pName[0] = '\0'; + } + + result = ma_device_get_info(pDevice, type, &deviceInfo); + if (result != MA_SUCCESS) { + return result; + } + + if (pName != NULL) { + ma_strncpy_s(pName, nameCap, deviceInfo.name, (size_t)-1); + + /* + For safety, make sure the length is based on the truncated output string rather than the + source. Otherwise the caller might assume the output buffer contains more content than it + actually does. + */ + if (pLengthNotIncludingNullTerminator != NULL) { + *pLengthNotIncludingNullTerminator = strlen(pName); + } + } else { + /* Name not specified. Just report the length of the source string. */ + if (pLengthNotIncludingNullTerminator != NULL) { + *pLengthNotIncludingNullTerminator = strlen(deviceInfo.name); + } + } + + return MA_SUCCESS; +} + MA_API ma_result ma_device_start(ma_device* pDevice) { ma_result result; if (pDevice == NULL) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); + return MA_INVALID_ARGS; } - if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); + if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { + return MA_INVALID_OPERATION; /* Not initialized. */ } - if (ma_device_get_state(pDevice) == MA_STATE_STARTED) { - return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_start() called when the device is already started.", MA_INVALID_OPERATION); /* Already started. Returning an error to let the application know because it probably means they're doing something wrong. */ + if (ma_device_get_state(pDevice) == ma_device_state_started) { + return MA_SUCCESS; /* Already started. */ } ma_mutex_lock(&pDevice->startStopLock); { /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */ - MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED); + MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); - ma_device__set_state(pDevice, MA_STATE_STARTING); + ma_device__set_state(pDevice, ma_device_state_starting); /* Asynchronous backends need to be handled differently. */ if (ma_context_is_backend_asynchronous(pDevice->pContext)) { @@ -34062,7 +40410,8 @@ MA_API ma_result ma_device_start(ma_device* pDevice) } if (result == MA_SUCCESS) { - ma_device__set_state(pDevice, MA_STATE_STARTED); + ma_device__set_state(pDevice, ma_device_state_started); + ma_device__on_notification_started(pDevice); } } else { /* @@ -34081,7 +40430,7 @@ MA_API ma_result ma_device_start(ma_device* pDevice) /* We changed the state from stopped to started, so if we failed, make sure we put the state back to stopped. */ if (result != MA_SUCCESS) { - ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_device__set_state(pDevice, ma_device_state_stopped); } } ma_mutex_unlock(&pDevice->startStopLock); @@ -34094,23 +40443,23 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) ma_result result; if (pDevice == NULL) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); + return MA_INVALID_ARGS; } - if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); + if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { + return MA_INVALID_OPERATION; /* Not initialized. */ } - if (ma_device_get_state(pDevice) == MA_STATE_STOPPED) { - return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_stop() called when the device is already stopped.", MA_INVALID_OPERATION); /* Already stopped. Returning an error to let the application know because it probably means they're doing something wrong. */ + if (ma_device_get_state(pDevice) == ma_device_state_stopped) { + return MA_SUCCESS; /* Already stopped. */ } ma_mutex_lock(&pDevice->startStopLock); { /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */ - MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STARTED); + MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_started); - ma_device__set_state(pDevice, MA_STATE_STOPPING); + ma_device__set_state(pDevice, ma_device_state_stopping); /* Asynchronous backends need to be handled differently. */ if (ma_context_is_backend_asynchronous(pDevice->pContext)) { @@ -34121,7 +40470,7 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) result = MA_INVALID_OPERATION; } - ma_device__set_state(pDevice, MA_STATE_STOPPED); + ma_device__set_state(pDevice, ma_device_state_stopped); } else { /* Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If @@ -34129,7 +40478,7 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super important though, so I'm asserting it here as well for extra safety in case we accidentally change something later. */ - MA_ASSERT(ma_device_get_state(pDevice) != MA_STATE_STARTED); + MA_ASSERT(ma_device_get_state(pDevice) != ma_device_state_started); if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) { pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice); @@ -34150,16 +40499,16 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice) { - return ma_device_get_state(pDevice) == MA_STATE_STARTED; + return ma_device_get_state(pDevice) == ma_device_state_started; } -MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice) +MA_API ma_device_state ma_device_get_state(const ma_device* pDevice) { if (pDevice == NULL) { - return MA_STATE_UNINITIALIZED; + return ma_device_state_uninitialized; } - return c89atomic_load_32((ma_uint32*)&pDevice->state); /* Naughty cast to get rid of a const warning. */ + return (ma_device_state)c89atomic_load_i32((ma_int32*)&pDevice->state); /* Naughty cast to get rid of a const warning. */ } MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume) @@ -34168,7 +40517,7 @@ MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume) return MA_INVALID_ARGS; } - if (volume < 0.0f || volume > 1.0f) { + if (volume < 0.0f) { return MA_INVALID_ARGS; } @@ -34193,16 +40542,16 @@ MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume) return MA_SUCCESS; } -MA_API ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB) +MA_API ma_result ma_device_set_master_volume_db(ma_device* pDevice, float gainDB) { if (gainDB > 0) { return MA_INVALID_ARGS; } - return ma_device_set_master_volume(pDevice, ma_gain_db_to_factor(gainDB)); + return ma_device_set_master_volume(pDevice, ma_volume_db_to_linear(gainDB)); } -MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB) +MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGainDB) { float factor; ma_result result; @@ -34217,7 +40566,7 @@ MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB return result; } - *pGainDB = ma_factor_to_gain_db(factor); + *pGainDB = ma_volume_linear_to_db(factor); return MA_SUCCESS; } @@ -34300,11 +40649,6 @@ MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_dev #endif /* MA_NO_DEVICE_IO */ -MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale) -{ - return ma_max(1, (ma_uint32)(baseBufferSize*scale)); -} - MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate) { /* Prevent a division by zero. */ @@ -34358,13 +40702,89 @@ MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offse } -MA_API void ma_clip_samples_f32(float* p, ma_uint64 sampleCount) +MA_API void ma_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count) { - ma_uint32 iSample; + ma_uint64 iSample; - /* TODO: Research a branchless SSE implementation. */ - for (iSample = 0; iSample < sampleCount; iSample += 1) { - p[iSample] = ma_clip_f32(p[iSample]); + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_u8(pSrc[iSample]); + } +} + +MA_API void ma_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count) +{ + ma_uint64 iSample; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_s16(pSrc[iSample]); + } +} + +MA_API void ma_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count) +{ + ma_uint64 iSample; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + for (iSample = 0; iSample < count; iSample += 1) { + ma_int64 s = ma_clip_s24(pSrc[iSample]); + pDst[iSample*3 + 0] = (ma_uint8)((s & 0x000000FF) >> 0); + pDst[iSample*3 + 1] = (ma_uint8)((s & 0x0000FF00) >> 8); + pDst[iSample*3 + 2] = (ma_uint8)((s & 0x00FF0000) >> 16); + } +} + +MA_API void ma_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count) +{ + ma_uint64 iSample; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_s32(pSrc[iSample]); + } +} + +MA_API void ma_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count) +{ + ma_uint64 iSample; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_f32(pSrc[iSample]); + } +} + +MA_API void ma_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels) +{ + ma_uint64 sampleCount; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + sampleCount = frameCount * channels; + + switch (format) { + case ma_format_u8: ma_clip_samples_u8( (ma_uint8*)pDst, (const ma_int16*)pSrc, sampleCount); break; + case ma_format_s16: ma_clip_samples_s16((ma_int16*)pDst, (const ma_int32*)pSrc, sampleCount); break; + case ma_format_s24: ma_clip_samples_s24((ma_uint8*)pDst, (const ma_int64*)pSrc, sampleCount); break; + case ma_format_s32: ma_clip_samples_s32((ma_int32*)pDst, (const ma_int64*)pSrc, sampleCount); break; + case ma_format_f32: ma_clip_samples_f32(( float*)pDst, (const float*)pSrc, sampleCount); break; + + /* Do nothing if we don't know the format. We're including these here to silence a compiler warning about enums not being handled by the switch. */ + case ma_format_unknown: + case ma_format_count: + break; } } @@ -34441,8 +40861,19 @@ MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* return; } - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pSamplesOut[iSample] = pSamplesIn[iSample] * factor; + if (factor == 1) { + if (pSamplesOut == pSamplesIn) { + /* In place. No-op. */ + } else { + /* Just a copy. */ + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamplesOut[iSample] = pSamplesIn[iSample]; + } + } + } else { + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamplesOut[iSample] = pSamplesIn[iSample] * factor; + } } } @@ -34471,85 +40902,236 @@ MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, f ma_copy_and_apply_volume_factor_f32(pSamples, pSamples, sampleCount, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pFramesOut, const ma_uint8* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_u8(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_u8(pFramesOut, pFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pFramesOut, const ma_int16* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_s16(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_s16(pFramesOut, pFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_s24(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_s24(pFramesOut, pFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pFramesOut, const ma_int32* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_s32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_s32(pFramesOut, pFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_f32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor); + ma_copy_and_apply_volume_factor_f32(pFramesOut, pFramesIn, frameCount*channels, factor); } -MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) +MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) { switch (format) { - case ma_format_u8: ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pPCMFramesOut, (const ma_uint8*)pPCMFramesIn, frameCount, channels, factor); return; - case ma_format_s16: ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pPCMFramesOut, (const ma_int16*)pPCMFramesIn, frameCount, channels, factor); return; - case ma_format_s24: ma_copy_and_apply_volume_factor_pcm_frames_s24( pPCMFramesOut, pPCMFramesIn, frameCount, channels, factor); return; - case ma_format_s32: ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pPCMFramesOut, (const ma_int32*)pPCMFramesIn, frameCount, channels, factor); return; - case ma_format_f32: ma_copy_and_apply_volume_factor_pcm_frames_f32( (float*)pPCMFramesOut, (const float*)pPCMFramesIn, frameCount, channels, factor); return; + case ma_format_u8: ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pFramesOut, (const ma_uint8*)pFramesIn, frameCount, channels, factor); return; + case ma_format_s16: ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pFramesOut, (const ma_int16*)pFramesIn, frameCount, channels, factor); return; + case ma_format_s24: ma_copy_and_apply_volume_factor_pcm_frames_s24( pFramesOut, pFramesIn, frameCount, channels, factor); return; + case ma_format_s32: ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pFramesOut, (const ma_int32*)pFramesIn, frameCount, channels, factor); return; + case ma_format_f32: ma_copy_and_apply_volume_factor_pcm_frames_f32( (float*)pFramesOut, (const float*)pFramesIn, frameCount, channels, factor); return; default: return; /* Do nothing. */ } } -MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_u8(pPCMFrames, pPCMFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_u8(pFrames, pFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_s16(pPCMFrames, pPCMFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_s16(pFrames, pFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_s24(pPCMFrames, pPCMFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_s24(pFrames, pFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_s32(pPCMFrames, pPCMFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_s32(pFrames, pFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames_f32(pPCMFrames, pPCMFrames, frameCount, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames_f32(pFrames, pFrames, frameCount, channels, factor); } -MA_API void ma_apply_volume_factor_pcm_frames(void* pPCMFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) +MA_API void ma_apply_volume_factor_pcm_frames(void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor) { - ma_copy_and_apply_volume_factor_pcm_frames(pPCMFrames, pPCMFrames, frameCount, format, channels, factor); + ma_copy_and_apply_volume_factor_pcm_frames(pFramesOut, pFramesOut, frameCount, format, channels, factor); } -MA_API float ma_factor_to_gain_db(float factor) +MA_API void ma_copy_and_apply_volume_factor_per_channel_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float* pChannelGains) { - return (float)(20*ma_log10f(factor)); + ma_uint64 iFrame; + + if (channels == 2) { + /* TODO: Do an optimized implementation for stereo and mono. Can do a SIMD optimized implementation as well. */ + } + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOut[iFrame * channels + iChannel] = pFramesIn[iFrame * channels + iChannel] * pChannelGains[iChannel]; + } + } } -MA_API float ma_gain_db_to_factor(float gain) + + +static MA_INLINE ma_int16 ma_apply_volume_unclipped_u8(ma_int16 x, ma_int16 volume) { - return (float)ma_powf(10, gain/20.0f); + return (ma_int16)(((ma_int32)x * (ma_int32)volume) >> 8); } +static MA_INLINE ma_int32 ma_apply_volume_unclipped_s16(ma_int32 x, ma_int16 volume) +{ + return (ma_int32)((x * volume) >> 8); +} + +static MA_INLINE ma_int64 ma_apply_volume_unclipped_s24(ma_int64 x, ma_int16 volume) +{ + return (ma_int64)((x * volume) >> 8); +} + +static MA_INLINE ma_int64 ma_apply_volume_unclipped_s32(ma_int64 x, ma_int16 volume) +{ + return (ma_int64)((x * volume) >> 8); +} + +static MA_INLINE float ma_apply_volume_unclipped_f32(float x, float volume) +{ + return x * volume; +} + + +MA_API void ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count, float volume) +{ + ma_uint64 iSample; + ma_int16 volumeFixed; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + volumeFixed = ma_float_to_fixed_16(volume); + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_u8(ma_apply_volume_unclipped_u8(pSrc[iSample], volumeFixed)); + } +} + +MA_API void ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count, float volume) +{ + ma_uint64 iSample; + ma_int16 volumeFixed; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + volumeFixed = ma_float_to_fixed_16(volume); + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_s16(ma_apply_volume_unclipped_s16(pSrc[iSample], volumeFixed)); + } +} + +MA_API void ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count, float volume) +{ + ma_uint64 iSample; + ma_int16 volumeFixed; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + volumeFixed = ma_float_to_fixed_16(volume); + + for (iSample = 0; iSample < count; iSample += 1) { + ma_int64 s = ma_clip_s24(ma_apply_volume_unclipped_s24(pSrc[iSample], volumeFixed)); + pDst[iSample*3 + 0] = (ma_uint8)((s & 0x000000FF) >> 0); + pDst[iSample*3 + 1] = (ma_uint8)((s & 0x0000FF00) >> 8); + pDst[iSample*3 + 2] = (ma_uint8)((s & 0x00FF0000) >> 16); + } +} + +MA_API void ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count, float volume) +{ + ma_uint64 iSample; + ma_int16 volumeFixed; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + volumeFixed = ma_float_to_fixed_16(volume); + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_s32(ma_apply_volume_unclipped_s32(pSrc[iSample], volumeFixed)); + } +} + +MA_API void ma_copy_and_apply_volume_and_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count, float volume) +{ + ma_uint64 iSample; + + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + /* For the f32 case we need to make sure this supports in-place processing where the input and output buffers are the same. */ + + for (iSample = 0; iSample < count; iSample += 1) { + pDst[iSample] = ma_clip_f32(ma_apply_volume_unclipped_f32(pSrc[iSample], volume)); + } +} + +MA_API void ma_copy_and_apply_volume_and_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float volume) +{ + MA_ASSERT(pDst != NULL); + MA_ASSERT(pSrc != NULL); + + if (volume == 1) { + ma_clip_pcm_frames(pDst, pSrc, frameCount, format, channels); /* Optimized case for volume = 1. */ + } else if (volume == 0) { + ma_silence_pcm_frames(pDst, frameCount, format, channels); /* Optimized case for volume = 0. */ + } else { + ma_uint64 sampleCount = frameCount * channels; + + switch (format) { + case ma_format_u8: ma_copy_and_apply_volume_and_clip_samples_u8( (ma_uint8*)pDst, (const ma_int16*)pSrc, sampleCount, volume); break; + case ma_format_s16: ma_copy_and_apply_volume_and_clip_samples_s16((ma_int16*)pDst, (const ma_int32*)pSrc, sampleCount, volume); break; + case ma_format_s24: ma_copy_and_apply_volume_and_clip_samples_s24((ma_uint8*)pDst, (const ma_int64*)pSrc, sampleCount, volume); break; + case ma_format_s32: ma_copy_and_apply_volume_and_clip_samples_s32((ma_int32*)pDst, (const ma_int64*)pSrc, sampleCount, volume); break; + case ma_format_f32: ma_copy_and_apply_volume_and_clip_samples_f32(( float*)pDst, (const float*)pSrc, sampleCount, volume); break; + + /* Do nothing if we don't know the format. We're including these here to silence a compiler warning about enums not being handled by the switch. */ + case ma_format_unknown: + case ma_format_count: + break; + } + } +} + + + +MA_API float ma_volume_linear_to_db(float factor) +{ + return 20*ma_log10f(factor); +} + +MA_API float ma_volume_db_to_linear(float gain) +{ + return ma_powf(10, gain/20.0f); +} + + /************************************************************************************************************************************************************** @@ -34580,33 +41162,6 @@ static MA_INLINE void ma_pcm_sample_s32_to_s24_no_scale(ma_int64 x, ma_uint8* s2 } -static MA_INLINE ma_uint8 ma_clip_u8(ma_int16 x) -{ - return (ma_uint8)(ma_clamp(x, -128, 127) + 128); -} - -static MA_INLINE ma_int16 ma_clip_s16(ma_int32 x) -{ - return (ma_int16)ma_clamp(x, -32768, 32767); -} - -static MA_INLINE ma_int64 ma_clip_s24(ma_int64 x) -{ - return (ma_int64)ma_clamp(x, -8388608, 8388607); -} - -static MA_INLINE ma_int32 ma_clip_s32(ma_int64 x) -{ - /* This dance is to silence warnings with -std=c89. A good compiler should be able to optimize this away. */ - ma_int64 clipMin; - ma_int64 clipMax; - clipMin = -((ma_int64)2147483647 + 1); - clipMax = (ma_int64)2147483647; - - return (ma_int32)ma_clamp(x, clipMin, clipMax); -} - - /* u8 */ MA_API void ma_pcm_u8_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -36985,25 +43540,131 @@ MA_API ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channe return config; } -MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ) + +typedef struct { + size_t sizeInBytes; + size_t r1Offset; + size_t r2Offset; +} ma_biquad_heap_layout; + +static ma_result ma_biquad_get_heap_layout(const ma_biquad_config* pConfig, ma_biquad_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* R0 */ + pHeapLayout->r1Offset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; + + /* R1 */ + pHeapLayout->r2Offset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_biquad_get_heap_size(const ma_biquad_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_biquad_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_biquad_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_biquad_init_preallocated(const ma_biquad_config* pConfig, void* pHeap, ma_biquad* pBQ) +{ + ma_result result; + ma_biquad_heap_layout heapLayout; + if (pBQ == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pBQ); - if (pConfig == NULL) { - return MA_INVALID_ARGS; + result = ma_biquad_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; } - if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; - } + pBQ->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pBQ->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset); + pBQ->pR2 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r2Offset); return ma_biquad_reinit(pConfig, pBQ); } +MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad* pBQ) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_biquad_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_biquad_init_preallocated(pConfig, pHeap, pBQ); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pBQ->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_biquad_uninit(ma_biquad* pBQ, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pBQ == NULL) { + return; + } + + if (pBQ->_ownsHeap) { + ma_free(pBQ->_pHeap, pAllocationCallbacks); + } +} + MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ) { if (pBQ == NULL || pConfig == NULL) { @@ -37051,6 +43712,23 @@ MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pB return MA_SUCCESS; } +MA_API ma_result ma_biquad_clear_cache(ma_biquad* pBQ) +{ + if (pBQ == NULL) { + return MA_INVALID_ARGS; + } + + if (pBQ->format == ma_format_f32) { + pBQ->pR1->f32 = 0; + pBQ->pR2->f32 = 0; + } else { + pBQ->pR1->s32 = 0; + pBQ->pR2->s32 = 0; + } + + return MA_SUCCESS; +} + static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX) { ma_uint32 c; @@ -37061,10 +43739,10 @@ static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed( const float a1 = pBQ->a1.f32; const float a2 = pBQ->a2.f32; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { - float r1 = pBQ->r1[c].f32; - float r2 = pBQ->r2[c].f32; + float r1 = pBQ->pR1[c].f32; + float r2 = pBQ->pR2[c].f32; float x = pX[c]; float y; @@ -37072,9 +43750,9 @@ static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed( r1 = b1*x - a1*y + r2; r2 = b2*x - a2*y; - pY[c] = y; - pBQ->r1[c].f32 = r1; - pBQ->r2[c].f32 = r2; + pY[c] = y; + pBQ->pR1[c].f32 = r1; + pBQ->pR2[c].f32 = r2; } } @@ -37093,10 +43771,10 @@ static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed( const ma_int32 a1 = pBQ->a1.s32; const ma_int32 a2 = pBQ->a2.s32; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { - ma_int32 r1 = pBQ->r1[c].s32; - ma_int32 r2 = pBQ->r2[c].s32; + ma_int32 r1 = pBQ->pR1[c].s32; + ma_int32 r2 = pBQ->pR2[c].s32; ma_int32 x = pX[c]; ma_int32 y; @@ -37104,9 +43782,9 @@ static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed( r1 = (b1*x - a1*y + r2); r2 = (b2*x - a2*y); - pY[c] = (ma_int16)ma_clamp(y, -32768, 32767); - pBQ->r1[c].s32 = r1; - pBQ->r2[c].s32 = r2; + pY[c] = (ma_int16)ma_clamp(y, -32768, 32767); + pBQ->pR1[c].s32 = r1; + pBQ->pR2[c].s32 = r2; } } @@ -37200,25 +43878,122 @@ MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, } -MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) +typedef struct { + size_t sizeInBytes; + size_t r1Offset; +} ma_lpf1_heap_layout; + +static ma_result ma_lpf1_get_heap_layout(const ma_lpf1_config* pConfig, ma_lpf1_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* R1 */ + pHeapLayout->r1Offset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_lpf1_get_heap_size(const ma_lpf1_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_lpf1_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_lpf1_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_lpf1_init_preallocated(const ma_lpf1_config* pConfig, void* pHeap, ma_lpf1* pLPF) +{ + ma_result result; + ma_lpf1_heap_layout heapLayout; + if (pLPF == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pLPF); - if (pConfig == NULL) { - return MA_INVALID_ARGS; + result = ma_lpf1_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; } - if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; - } + pLPF->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pLPF->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset); return ma_lpf1_reinit(pConfig, pLPF); } +MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf1* pLPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_lpf1_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_lpf1_init_preallocated(pConfig, pHeap, pLPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pLPF->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_lpf1_uninit(ma_lpf1* pLPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pLPF == NULL) { + return; + } + + if (pLPF->_ownsHeap) { + ma_free(pLPF->_pHeap, pAllocationCallbacks); + } +} + MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) { double a; @@ -37255,6 +44030,21 @@ MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) return MA_SUCCESS; } +MA_API ma_result ma_lpf1_clear_cache(ma_lpf1* pLPF) +{ + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + if (pLPF->format == ma_format_f32) { + pLPF->a.f32 = 0; + } else { + pLPF->a.s32 = 0; + } + + return MA_SUCCESS; +} + static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, const float* pX) { ma_uint32 c; @@ -37262,16 +44052,16 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, co const float a = pLPF->a.f32; const float b = 1 - a; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { - float r1 = pLPF->r1[c].f32; + float r1 = pLPF->pR1[c].f32; float x = pX[c]; float y; y = b*x + a*r1; pY[c] = y; - pLPF->r1[c].f32 = y; + pLPF->pR1[c].f32 = y; } } @@ -37282,16 +44072,16 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int32 a = pLPF->a.s32; const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { - ma_int32 r1 = pLPF->r1[c].s32; + ma_int32 r1 = pLPF->pR1[c].s32; ma_int32 x = pX[c]; ma_int32 y; y = (b*x + a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT; - pY[c] = (ma_int16)y; - pLPF->r1[c].s32 = (ma_int32)y; + pY[c] = (ma_int16)y; + pLPF->pR1[c].s32 = (ma_int32)y; } } @@ -37371,7 +44161,15 @@ static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_confi return bqConfig; } -MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) +MA_API ma_result ma_lpf2_get_heap_size(const ma_lpf2_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_biquad_config bqConfig; + bqConfig = ma_lpf2__get_biquad_config(pConfig); + + return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); +} + +MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* pHeap, ma_lpf2* pLPF) { ma_result result; ma_biquad_config bqConfig; @@ -37387,7 +44185,7 @@ MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) } bqConfig = ma_lpf2__get_biquad_config(pConfig); - result = ma_biquad_init(&bqConfig, &pLPF->bq); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pLPF->bq); if (result != MA_SUCCESS) { return result; } @@ -37395,6 +44193,45 @@ MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) return MA_SUCCESS; } +MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf2* pLPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_lpf2_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_lpf2_init_preallocated(pConfig, pHeap, pLPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pLPF->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ + return MA_SUCCESS; +} + +MA_API void ma_lpf2_uninit(ma_lpf2* pLPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pLPF == NULL) { + return; + } + + ma_biquad_uninit(&pLPF->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ +} + MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) { ma_result result; @@ -37413,6 +44250,17 @@ MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF) return MA_SUCCESS; } +MA_API ma_result ma_lpf2_clear_cache(ma_lpf2* pLPF) +{ + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + ma_biquad_clear_cache(&pLPF->bq); + + return MA_SUCCESS; +} + static MA_INLINE void ma_lpf2_process_pcm_frame_s16(ma_lpf2* pLPF, ma_int16* pFrameOut, const ma_int16* pFrameIn) { ma_biquad_process_pcm_frame_s16(&pLPF->bq, pFrameOut, pFrameIn); @@ -37456,7 +44304,24 @@ MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma return config; } -static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* pLPF, ma_bool32 isNew) + +typedef struct +{ + size_t sizeInBytes; + size_t lpf1Offset; + size_t lpf2Offset; /* Offset of the first second order filter. Subsequent filters will come straight after, and will each have the same heap size. */ +} ma_lpf_heap_layout; + +static void ma_lpf_calculate_sub_lpf_counts(ma_uint32 order, ma_uint32* pLPF1Count, ma_uint32* pLPF2Count) +{ + MA_ASSERT(pLPF1Count != NULL); + MA_ASSERT(pLPF2Count != NULL); + + *pLPF1Count = order % 2; + *pLPF2Count = order / 2; +} + +static ma_result ma_lpf_get_heap_layout(const ma_lpf_config* pConfig, ma_lpf_heap_layout* pHeapLayout) { ma_result result; ma_uint32 lpf1Count; @@ -37464,6 +44329,69 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* p ma_uint32 ilpf1; ma_uint32 ilpf2; + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels == 0) { + return MA_INVALID_ARGS; + } + + if (pConfig->order > MA_MAX_FILTER_ORDER) { + return MA_INVALID_ARGS; + } + + ma_lpf_calculate_sub_lpf_counts(pConfig->order, &lpf1Count, &lpf2Count); + + pHeapLayout->sizeInBytes = 0; + + /* LPF 1 */ + pHeapLayout->lpf1Offset = pHeapLayout->sizeInBytes; + for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) { + size_t lpf1HeapSizeInBytes; + ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); + + result = ma_lpf1_get_heap_size(&lpf1Config, &lpf1HeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += sizeof(ma_lpf1) + lpf1HeapSizeInBytes; + } + + /* LPF 2*/ + pHeapLayout->lpf2Offset = pHeapLayout->sizeInBytes; + for (ilpf2 = 0; ilpf2 < lpf2Count; ilpf2 += 1) { + size_t lpf2HeapSizeInBytes; + ma_lpf2_config lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107); /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */ + + result = ma_lpf2_get_heap_size(&lpf2Config, &lpf2HeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += sizeof(ma_lpf2) + lpf2HeapSizeInBytes; + } + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF, ma_bool32 isNew) +{ + ma_result result; + ma_uint32 lpf1Count; + ma_uint32 lpf2Count; + ma_uint32 ilpf1; + ma_uint32 ilpf2; + ma_lpf_heap_layout heapLayout; /* Only used if isNew is true. */ + if (pLPF == NULL || pConfig == NULL) { return MA_INVALID_ARGS; } @@ -37487,11 +44415,7 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* p return MA_INVALID_ARGS; } - lpf1Count = pConfig->order % 2; - lpf2Count = pConfig->order / 2; - - MA_ASSERT(lpf1Count <= ma_countof(pLPF->lpf1)); - MA_ASSERT(lpf2Count <= ma_countof(pLPF->lpf2)); + ma_lpf_calculate_sub_lpf_counts(pConfig->order, &lpf1Count, &lpf2Count); /* The filter order can't change between reinits. */ if (!isNew) { @@ -37500,16 +44424,42 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* p } } + if (isNew) { + result = ma_lpf_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pLPF->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pLPF->pLPF1 = (ma_lpf1*)ma_offset_ptr(pHeap, heapLayout.lpf1Offset); + pLPF->pLPF2 = (ma_lpf2*)ma_offset_ptr(pHeap, heapLayout.lpf2Offset); + } else { + MA_ZERO_OBJECT(&heapLayout); /* To silence a compiler warning. */ + } + for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) { ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); if (isNew) { - result = ma_lpf1_init(&lpf1Config, &pLPF->lpf1[ilpf1]); + size_t lpf1HeapSizeInBytes; + + result = ma_lpf1_get_heap_size(&lpf1Config, &lpf1HeapSizeInBytes); + if (result == MA_SUCCESS) { + result = ma_lpf1_init_preallocated(&lpf1Config, ma_offset_ptr(pHeap, heapLayout.lpf1Offset + (sizeof(ma_lpf1) * lpf1Count) + (ilpf1 * lpf1HeapSizeInBytes)), &pLPF->pLPF1[ilpf1]); + } } else { - result = ma_lpf1_reinit(&lpf1Config, &pLPF->lpf1[ilpf1]); + result = ma_lpf1_reinit(&lpf1Config, &pLPF->pLPF1[ilpf1]); } if (result != MA_SUCCESS) { + ma_uint32 jlpf1; + + for (jlpf1 = 0; jlpf1 < ilpf1; jlpf1 += 1) { + ma_lpf1_uninit(&pLPF->pLPF1[jlpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ + } + return result; } } @@ -37530,12 +44480,28 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* p lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q); if (isNew) { - result = ma_lpf2_init(&lpf2Config, &pLPF->lpf2[ilpf2]); + size_t lpf2HeapSizeInBytes; + + result = ma_lpf2_get_heap_size(&lpf2Config, &lpf2HeapSizeInBytes); + if (result == MA_SUCCESS) { + result = ma_lpf2_init_preallocated(&lpf2Config, ma_offset_ptr(pHeap, heapLayout.lpf2Offset + (sizeof(ma_lpf2) * lpf2Count) + (ilpf2 * lpf2HeapSizeInBytes)), &pLPF->pLPF2[ilpf2]); + } } else { - result = ma_lpf2_reinit(&lpf2Config, &pLPF->lpf2[ilpf2]); + result = ma_lpf2_reinit(&lpf2Config, &pLPF->pLPF2[ilpf2]); } if (result != MA_SUCCESS) { + ma_uint32 jlpf1; + ma_uint32 jlpf2; + + for (jlpf1 = 0; jlpf1 < lpf1Count; jlpf1 += 1) { + ma_lpf1_uninit(&pLPF->pLPF1[jlpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ + } + + for (jlpf2 = 0; jlpf2 < ilpf2; jlpf2 += 1) { + ma_lpf2_uninit(&pLPF->pLPF2[jlpf2], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ + } + return result; } } @@ -37549,7 +44515,28 @@ static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* p return MA_SUCCESS; } -MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF) +MA_API ma_result ma_lpf_get_heap_size(const ma_lpf_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_lpf_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_lpf_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return result; +} + +MA_API ma_result ma_lpf_init_preallocated(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF) { if (pLPF == NULL) { return MA_INVALID_ARGS; @@ -37557,16 +44544,84 @@ MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF) MA_ZERO_OBJECT(pLPF); - if (pConfig == NULL) { - return MA_INVALID_ARGS; + return ma_lpf_reinit__internal(pConfig, pHeap, pLPF, /*isNew*/MA_TRUE); +} + +MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf* pLPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_lpf_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; } - return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_TRUE); + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_lpf_init_preallocated(pConfig, pHeap, pLPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pLPF->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_lpf_uninit(ma_lpf* pLPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_uint32 ilpf1; + ma_uint32 ilpf2; + + if (pLPF == NULL) { + return; + } + + for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { + ma_lpf1_uninit(&pLPF->pLPF1[ilpf1], pAllocationCallbacks); + } + + for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { + ma_lpf2_uninit(&pLPF->pLPF2[ilpf2], pAllocationCallbacks); + } + + if (pLPF->_ownsHeap) { + ma_free(pLPF->_pHeap, pAllocationCallbacks); + } } MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF) { - return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_FALSE); + return ma_lpf_reinit__internal(pConfig, NULL, pLPF, /*isNew*/MA_FALSE); +} + +MA_API ma_result ma_lpf_clear_cache(ma_lpf* pLPF) +{ + ma_uint32 ilpf1; + ma_uint32 ilpf2; + + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { + ma_lpf1_clear_cache(&pLPF->pLPF1[ilpf1]); + } + + for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { + ma_lpf2_clear_cache(&pLPF->pLPF2[ilpf2]); + } + + return MA_SUCCESS; } static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, const void* pX) @@ -37579,11 +44634,11 @@ static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, cons MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - ma_lpf1_process_pcm_frame_f32(&pLPF->lpf1[ilpf1], pY, pY); + ma_lpf1_process_pcm_frame_f32(&pLPF->pLPF1[ilpf1], pY, pY); } for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - ma_lpf2_process_pcm_frame_f32(&pLPF->lpf2[ilpf2], pY, pY); + ma_lpf2_process_pcm_frame_f32(&pLPF->pLPF2[ilpf2], pY, pY); } } @@ -37597,11 +44652,11 @@ static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pY, c MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - ma_lpf1_process_pcm_frame_s16(&pLPF->lpf1[ilpf1], pY, pY); + ma_lpf1_process_pcm_frame_s16(&pLPF->pLPF1[ilpf1], pY, pY); } for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - ma_lpf2_process_pcm_frame_s16(&pLPF->lpf2[ilpf2], pY, pY); + ma_lpf2_process_pcm_frame_s16(&pLPF->pLPF2[ilpf2], pY, pY); } } @@ -37618,14 +44673,14 @@ MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const /* Faster path for in-place. */ if (pFramesOut == pFramesIn) { for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { - result = ma_lpf1_process_pcm_frames(&pLPF->lpf1[ilpf1], pFramesOut, pFramesOut, frameCount); + result = ma_lpf1_process_pcm_frames(&pLPF->pLPF1[ilpf1], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } } for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { - result = ma_lpf2_process_pcm_frames(&pLPF->lpf2[ilpf2], pFramesOut, pFramesOut, frameCount); + result = ma_lpf2_process_pcm_frames(&pLPF->pLPF2[ilpf2], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } @@ -37711,23 +44766,120 @@ MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, } -MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) +typedef struct { - if (pHPF == NULL) { - return MA_INVALID_ARGS; - } + size_t sizeInBytes; + size_t r1Offset; +} ma_hpf1_heap_layout; - MA_ZERO_OBJECT(pHPF); +static ma_result ma_hpf1_get_heap_layout(const ma_hpf1_config* pConfig, ma_hpf1_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); if (pConfig == NULL) { return MA_INVALID_ARGS; } - if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { + if (pConfig->channels == 0) { return MA_INVALID_ARGS; } - return ma_hpf1_reinit(pConfig, pHPF); + pHeapLayout->sizeInBytes = 0; + + /* R1 */ + pHeapLayout->r1Offset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels; + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_hpf1_get_heap_size(const ma_hpf1_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_hpf1_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_hpf1_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_hpf1_init_preallocated(const ma_hpf1_config* pConfig, void* pHeap, ma_hpf1* pLPF) +{ + ma_result result; + ma_hpf1_heap_layout heapLayout; + + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pLPF); + + result = ma_hpf1_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pLPF->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pLPF->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset); + + return ma_hpf1_reinit(pConfig, pLPF); +} + +MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf1* pLPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_hpf1_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_hpf1_init_preallocated(pConfig, pHeap, pLPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pLPF->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_hpf1_uninit(ma_hpf1* pHPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pHPF == NULL) { + return; + } + + if (pHPF->_ownsHeap) { + ma_free(pHPF->_pHeap, pAllocationCallbacks); + } } MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) @@ -37773,16 +44925,16 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, co const float a = 1 - pHPF->a.f32; const float b = 1 - a; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { - float r1 = pHPF->r1[c].f32; + float r1 = pHPF->pR1[c].f32; float x = pX[c]; float y; y = b*x - a*r1; - pY[c] = y; - pHPF->r1[c].f32 = y; + pY[c] = y; + pHPF->pR1[c].f32 = y; } } @@ -37793,16 +44945,16 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32); const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { - ma_int32 r1 = pHPF->r1[c].s32; + ma_int32 r1 = pHPF->pR1[c].s32; ma_int32 x = pX[c]; ma_int32 y; y = (b*x - a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT; - pY[c] = (ma_int16)y; - pHPF->r1[c].s32 = (ma_int32)y; + pY[c] = (ma_int16)y; + pHPF->pR1[c].s32 = (ma_int32)y; } } @@ -37882,7 +45034,15 @@ static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_confi return bqConfig; } -MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF) +MA_API ma_result ma_hpf2_get_heap_size(const ma_hpf2_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_biquad_config bqConfig; + bqConfig = ma_hpf2__get_biquad_config(pConfig); + + return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); +} + +MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* pHeap, ma_hpf2* pHPF) { ma_result result; ma_biquad_config bqConfig; @@ -37898,7 +45058,7 @@ MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF) } bqConfig = ma_hpf2__get_biquad_config(pConfig); - result = ma_biquad_init(&bqConfig, &pHPF->bq); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pHPF->bq); if (result != MA_SUCCESS) { return result; } @@ -37906,6 +45066,45 @@ MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF) return MA_SUCCESS; } +MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf2* pHPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_hpf2_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_hpf2_init_preallocated(pConfig, pHeap, pHPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pHPF->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ + return MA_SUCCESS; +} + +MA_API void ma_hpf2_uninit(ma_hpf2* pHPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pHPF == NULL) { + return; + } + + ma_biquad_uninit(&pHPF->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ +} + MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF) { ma_result result; @@ -37967,7 +45166,24 @@ MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma return config; } -static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* pHPF, ma_bool32 isNew) + +typedef struct +{ + size_t sizeInBytes; + size_t hpf1Offset; + size_t hpf2Offset; /* Offset of the first second order filter. Subsequent filters will come straight after, and will each have the same heap size. */ +} ma_hpf_heap_layout; + +static void ma_hpf_calculate_sub_hpf_counts(ma_uint32 order, ma_uint32* pHPF1Count, ma_uint32* pHPF2Count) +{ + MA_ASSERT(pHPF1Count != NULL); + MA_ASSERT(pHPF2Count != NULL); + + *pHPF1Count = order % 2; + *pHPF2Count = order / 2; +} + +static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_heap_layout* pHeapLayout) { ma_result result; ma_uint32 hpf1Count; @@ -37975,6 +45191,69 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* p ma_uint32 ihpf1; ma_uint32 ihpf2; + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels == 0) { + return MA_INVALID_ARGS; + } + + if (pConfig->order > MA_MAX_FILTER_ORDER) { + return MA_INVALID_ARGS; + } + + ma_hpf_calculate_sub_hpf_counts(pConfig->order, &hpf1Count, &hpf2Count); + + pHeapLayout->sizeInBytes = 0; + + /* HPF 1 */ + pHeapLayout->hpf1Offset = pHeapLayout->sizeInBytes; + for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) { + size_t hpf1HeapSizeInBytes; + ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); + + result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += sizeof(ma_hpf1) + hpf1HeapSizeInBytes; + } + + /* HPF 2*/ + pHeapLayout->hpf2Offset = pHeapLayout->sizeInBytes; + for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) { + size_t hpf2HeapSizeInBytes; + ma_hpf2_config hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107); /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */ + + result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += sizeof(ma_hpf2) + hpf2HeapSizeInBytes; + } + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pHPF, ma_bool32 isNew) +{ + ma_result result; + ma_uint32 hpf1Count; + ma_uint32 hpf2Count; + ma_uint32 ihpf1; + ma_uint32 ihpf2; + ma_hpf_heap_layout heapLayout; /* Only used if isNew is true. */ + if (pHPF == NULL || pConfig == NULL) { return MA_INVALID_ARGS; } @@ -37998,11 +45277,7 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* p return MA_INVALID_ARGS; } - hpf1Count = pConfig->order % 2; - hpf2Count = pConfig->order / 2; - - MA_ASSERT(hpf1Count <= ma_countof(pHPF->hpf1)); - MA_ASSERT(hpf2Count <= ma_countof(pHPF->hpf2)); + ma_hpf_calculate_sub_hpf_counts(pConfig->order, &hpf1Count, &hpf2Count); /* The filter order can't change between reinits. */ if (!isNew) { @@ -38011,16 +45286,42 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* p } } + if (isNew) { + result = ma_hpf_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pHPF->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pHPF->pHPF1 = (ma_hpf1*)ma_offset_ptr(pHeap, heapLayout.hpf1Offset); + pHPF->pHPF2 = (ma_hpf2*)ma_offset_ptr(pHeap, heapLayout.hpf2Offset); + } else { + MA_ZERO_OBJECT(&heapLayout); /* To silence a compiler warning. */ + } + for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) { ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency); if (isNew) { - result = ma_hpf1_init(&hpf1Config, &pHPF->hpf1[ihpf1]); + size_t hpf1HeapSizeInBytes; + + result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes); + if (result == MA_SUCCESS) { + result = ma_hpf1_init_preallocated(&hpf1Config, ma_offset_ptr(pHeap, heapLayout.hpf1Offset + (sizeof(ma_hpf1) * hpf1Count) + (ihpf1 * hpf1HeapSizeInBytes)), &pHPF->pHPF1[ihpf1]); + } } else { - result = ma_hpf1_reinit(&hpf1Config, &pHPF->hpf1[ihpf1]); + result = ma_hpf1_reinit(&hpf1Config, &pHPF->pHPF1[ihpf1]); } if (result != MA_SUCCESS) { + ma_uint32 jhpf1; + + for (jhpf1 = 0; jhpf1 < ihpf1; jhpf1 += 1) { + ma_hpf1_uninit(&pHPF->pHPF1[jhpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ + } + return result; } } @@ -38041,12 +45342,28 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* p hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q); if (isNew) { - result = ma_hpf2_init(&hpf2Config, &pHPF->hpf2[ihpf2]); + size_t hpf2HeapSizeInBytes; + + result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes); + if (result == MA_SUCCESS) { + result = ma_hpf2_init_preallocated(&hpf2Config, ma_offset_ptr(pHeap, heapLayout.hpf2Offset + (sizeof(ma_hpf2) * hpf2Count) + (ihpf2 * hpf2HeapSizeInBytes)), &pHPF->pHPF2[ihpf2]); + } } else { - result = ma_hpf2_reinit(&hpf2Config, &pHPF->hpf2[ihpf2]); + result = ma_hpf2_reinit(&hpf2Config, &pHPF->pHPF2[ihpf2]); } if (result != MA_SUCCESS) { + ma_uint32 jhpf1; + ma_uint32 jhpf2; + + for (jhpf1 = 0; jhpf1 < hpf1Count; jhpf1 += 1) { + ma_hpf1_uninit(&pHPF->pHPF1[jhpf1], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ + } + + for (jhpf2 = 0; jhpf2 < ihpf2; jhpf2 += 1) { + ma_hpf2_uninit(&pHPF->pHPF2[jhpf2], NULL); /* No need for allocation callbacks here since we used a preallocated heap allocation. */ + } + return result; } } @@ -38060,24 +45377,93 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* p return MA_SUCCESS; } -MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF) +MA_API ma_result ma_hpf_get_heap_size(const ma_hpf_config* pConfig, size_t* pHeapSizeInBytes) { + ma_result result; + ma_hpf_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_hpf_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return result; +} + +MA_API ma_result ma_hpf_init_preallocated(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pLPF) +{ + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pLPF); + + return ma_hpf_reinit__internal(pConfig, pHeap, pLPF, /*isNew*/MA_TRUE); +} + +MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf* pHPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_hpf_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_hpf_init_preallocated(pConfig, pHeap, pHPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pHPF->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_hpf_uninit(ma_hpf* pHPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_uint32 ihpf1; + ma_uint32 ihpf2; + if (pHPF == NULL) { - return MA_INVALID_ARGS; + return; } - MA_ZERO_OBJECT(pHPF); - - if (pConfig == NULL) { - return MA_INVALID_ARGS; + for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { + ma_hpf1_uninit(&pHPF->pHPF1[ihpf1], pAllocationCallbacks); } - return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_TRUE); + for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { + ma_hpf2_uninit(&pHPF->pHPF2[ihpf2], pAllocationCallbacks); + } + + if (pHPF->_ownsHeap) { + ma_free(pHPF->_pHeap, pAllocationCallbacks); + } } MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF) { - return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_FALSE); + return ma_hpf_reinit__internal(pConfig, NULL, pHPF, /*isNew*/MA_FALSE); } MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) @@ -38093,14 +45479,14 @@ MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const /* Faster path for in-place. */ if (pFramesOut == pFramesIn) { for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { - result = ma_hpf1_process_pcm_frames(&pHPF->hpf1[ihpf1], pFramesOut, pFramesOut, frameCount); + result = ma_hpf1_process_pcm_frames(&pHPF->pHPF1[ihpf1], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } } for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { - result = ma_hpf2_process_pcm_frames(&pHPF->hpf2[ihpf2], pFramesOut, pFramesOut, frameCount); + result = ma_hpf2_process_pcm_frames(&pHPF->pHPF2[ihpf2], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } @@ -38119,11 +45505,11 @@ MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pHPF->format, pHPF->channels)); for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { - ma_hpf1_process_pcm_frame_f32(&pHPF->hpf1[ihpf1], pFramesOutF32, pFramesOutF32); + ma_hpf1_process_pcm_frame_f32(&pHPF->pHPF1[ihpf1], pFramesOutF32, pFramesOutF32); } for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { - ma_hpf2_process_pcm_frame_f32(&pHPF->hpf2[ihpf2], pFramesOutF32, pFramesOutF32); + ma_hpf2_process_pcm_frame_f32(&pHPF->pHPF2[ihpf2], pFramesOutF32, pFramesOutF32); } pFramesOutF32 += pHPF->channels; @@ -38137,11 +45523,11 @@ MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pHPF->format, pHPF->channels)); for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { - ma_hpf1_process_pcm_frame_s16(&pHPF->hpf1[ihpf1], pFramesOutS16, pFramesOutS16); + ma_hpf1_process_pcm_frame_s16(&pHPF->pHPF1[ihpf1], pFramesOutS16, pFramesOutS16); } for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { - ma_hpf2_process_pcm_frame_s16(&pHPF->hpf2[ihpf2], pFramesOutS16, pFramesOutS16); + ma_hpf2_process_pcm_frame_s16(&pHPF->pHPF2[ihpf2], pFramesOutS16, pFramesOutS16); } pFramesOutS16 += pHPF->channels; @@ -38221,7 +45607,15 @@ static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_confi return bqConfig; } -MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF) +MA_API ma_result ma_bpf2_get_heap_size(const ma_bpf2_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_biquad_config bqConfig; + bqConfig = ma_bpf2__get_biquad_config(pConfig); + + return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); +} + +MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* pHeap, ma_bpf2* pBPF) { ma_result result; ma_biquad_config bqConfig; @@ -38237,7 +45631,7 @@ MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF) } bqConfig = ma_bpf2__get_biquad_config(pConfig); - result = ma_biquad_init(&bqConfig, &pBPF->bq); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pBPF->bq); if (result != MA_SUCCESS) { return result; } @@ -38245,6 +45639,45 @@ MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF) return MA_SUCCESS; } +MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf2* pBPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_bpf2_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_bpf2_init_preallocated(pConfig, pHeap, pBPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pBPF->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ + return MA_SUCCESS; +} + +MA_API void ma_bpf2_uninit(ma_bpf2* pBPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pBPF == NULL) { + return; + } + + ma_biquad_uninit(&pBPF->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ +} + MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF) { ma_result result; @@ -38306,12 +45739,67 @@ MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma return config; } -static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* pBPF, ma_bool32 isNew) + +typedef struct +{ + size_t sizeInBytes; + size_t bpf2Offset; +} ma_bpf_heap_layout; + +static ma_result ma_bpf_get_heap_layout(const ma_bpf_config* pConfig, ma_bpf_heap_layout* pHeapLayout) { ma_result result; ma_uint32 bpf2Count; ma_uint32 ibpf2; + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->order > MA_MAX_FILTER_ORDER) { + return MA_INVALID_ARGS; + } + + /* We must have an even number of order. */ + if ((pConfig->order & 0x1) != 0) { + return MA_INVALID_ARGS; + } + + bpf2Count = pConfig->channels / 2; + + pHeapLayout->sizeInBytes = 0; + + /* BPF 2 */ + pHeapLayout->bpf2Offset = pHeapLayout->sizeInBytes; + for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) { + size_t bpf2HeapSizeInBytes; + ma_bpf2_config bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107); /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */ + + result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += sizeof(ma_bpf2) + bpf2HeapSizeInBytes; + } + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF, ma_bool32 isNew) +{ + ma_result result; + ma_uint32 bpf2Count; + ma_uint32 ibpf2; + ma_bpf_heap_layout heapLayout; /* Only used if isNew is true. */ + if (pBPF == NULL || pConfig == NULL) { return MA_INVALID_ARGS; } @@ -38342,8 +45830,6 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* p bpf2Count = pConfig->order / 2; - MA_ASSERT(bpf2Count <= ma_countof(pBPF->bpf2)); - /* The filter order can't change between reinits. */ if (!isNew) { if (pBPF->bpf2Count != bpf2Count) { @@ -38351,6 +45837,20 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* p } } + if (isNew) { + result = ma_bpf_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pBPF->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pBPF->pBPF2 = (ma_bpf2*)ma_offset_ptr(pHeap, heapLayout.bpf2Offset); + } else { + MA_ZERO_OBJECT(&heapLayout); + } + for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) { ma_bpf2_config bpf2Config; double q; @@ -38361,9 +45861,14 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* p bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q); if (isNew) { - result = ma_bpf2_init(&bpf2Config, &pBPF->bpf2[ibpf2]); + size_t bpf2HeapSizeInBytes; + + result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes); + if (result == MA_SUCCESS) { + result = ma_bpf2_init_preallocated(&bpf2Config, ma_offset_ptr(pHeap, heapLayout.bpf2Offset + (sizeof(ma_bpf2) * bpf2Count) + (ibpf2 * bpf2HeapSizeInBytes)), &pBPF->pBPF2[ibpf2]); + } } else { - result = ma_bpf2_reinit(&bpf2Config, &pBPF->bpf2[ibpf2]); + result = ma_bpf2_reinit(&bpf2Config, &pBPF->pBPF2[ibpf2]); } if (result != MA_SUCCESS) { @@ -38378,7 +45883,29 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* p return MA_SUCCESS; } -MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF) + +MA_API ma_result ma_bpf_get_heap_size(const ma_bpf_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_bpf_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_bpf_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_bpf_init_preallocated(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF) { if (pBPF == NULL) { return MA_INVALID_ARGS; @@ -38386,16 +45913,59 @@ MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF) MA_ZERO_OBJECT(pBPF); - if (pConfig == NULL) { - return MA_INVALID_ARGS; + return ma_bpf_reinit__internal(pConfig, pHeap, pBPF, /*isNew*/MA_TRUE); +} + +MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf* pBPF) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_bpf_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; } - return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_TRUE); + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_bpf_init_preallocated(pConfig, pHeap, pBPF); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pBPF->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_bpf_uninit(ma_bpf* pBPF, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_uint32 ibpf2; + + if (pBPF == NULL) { + return; + } + + for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { + ma_bpf2_uninit(&pBPF->pBPF2[ibpf2], pAllocationCallbacks); + } + + if (pBPF->_ownsHeap) { + ma_free(pBPF->_pHeap, pAllocationCallbacks); + } } MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF) { - return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_FALSE); + return ma_bpf_reinit__internal(pConfig, NULL, pBPF, /*isNew*/MA_FALSE); } MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) @@ -38410,7 +45980,7 @@ MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const /* Faster path for in-place. */ if (pFramesOut == pFramesIn) { for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { - result = ma_bpf2_process_pcm_frames(&pBPF->bpf2[ibpf2], pFramesOut, pFramesOut, frameCount); + result = ma_bpf2_process_pcm_frames(&pBPF->pBPF2[ibpf2], pFramesOut, pFramesOut, frameCount); if (result != MA_SUCCESS) { return result; } @@ -38429,7 +45999,7 @@ MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pBPF->format, pBPF->channels)); for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { - ma_bpf2_process_pcm_frame_f32(&pBPF->bpf2[ibpf2], pFramesOutF32, pFramesOutF32); + ma_bpf2_process_pcm_frame_f32(&pBPF->pBPF2[ibpf2], pFramesOutF32, pFramesOutF32); } pFramesOutF32 += pBPF->channels; @@ -38443,7 +46013,7 @@ MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pBPF->format, pBPF->channels)); for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) { - ma_bpf2_process_pcm_frame_s16(&pBPF->bpf2[ibpf2], pFramesOutS16, pFramesOutS16); + ma_bpf2_process_pcm_frame_s16(&pBPF->pBPF2[ibpf2], pFramesOutS16, pFramesOutS16); } pFramesOutS16 += pBPF->channels; @@ -38522,7 +46092,15 @@ static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_c return bqConfig; } -MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter) +MA_API ma_result ma_notch2_get_heap_size(const ma_notch2_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_biquad_config bqConfig; + bqConfig = ma_notch2__get_biquad_config(pConfig); + + return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); +} + +MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, void* pHeap, ma_notch2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -38538,7 +46116,7 @@ MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFil } bqConfig = ma_notch2__get_biquad_config(pConfig); - result = ma_biquad_init(&bqConfig, &pFilter->bq); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -38546,6 +46124,45 @@ MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFil return MA_SUCCESS; } +MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch2* pFilter) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_notch2_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_notch2_init_preallocated(pConfig, pHeap, pFilter); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ + return MA_SUCCESS; +} + +MA_API void ma_notch2_uninit(ma_notch2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pFilter == NULL) { + return; + } + + ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ +} + MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter) { ma_result result; @@ -38651,7 +46268,15 @@ static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_con return bqConfig; } -MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter) +MA_API ma_result ma_peak2_get_heap_size(const ma_peak2_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_biquad_config bqConfig; + bqConfig = ma_peak2__get_biquad_config(pConfig); + + return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); +} + +MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void* pHeap, ma_peak2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -38667,7 +46292,7 @@ MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter } bqConfig = ma_peak2__get_biquad_config(pConfig); - result = ma_biquad_init(&bqConfig, &pFilter->bq); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -38675,6 +46300,45 @@ MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter return MA_SUCCESS; } +MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak2* pFilter) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_peak2_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_peak2_init_preallocated(pConfig, pHeap, pFilter); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ + return MA_SUCCESS; +} + +MA_API void ma_peak2_uninit(ma_peak2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pFilter == NULL) { + return; + } + + ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ +} + MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter) { ma_result result; @@ -38777,7 +46441,15 @@ static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshel return bqConfig; } -MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter) +MA_API ma_result ma_loshelf2_get_heap_size(const ma_loshelf2_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_biquad_config bqConfig; + bqConfig = ma_loshelf2__get_biquad_config(pConfig); + + return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); +} + +MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig, void* pHeap, ma_loshelf2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -38793,7 +46465,7 @@ MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2 } bqConfig = ma_loshelf2__get_biquad_config(pConfig); - result = ma_biquad_init(&bqConfig, &pFilter->bq); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -38801,6 +46473,45 @@ MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2 return MA_SUCCESS; } +MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf2* pFilter) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_loshelf2_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_loshelf2_init_preallocated(pConfig, pHeap, pFilter); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ + return MA_SUCCESS; +} + +MA_API void ma_loshelf2_uninit(ma_loshelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pFilter == NULL) { + return; + } + + ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ +} + MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter) { ma_result result; @@ -38903,7 +46614,15 @@ static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishel return bqConfig; } -MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter) +MA_API ma_result ma_hishelf2_get_heap_size(const ma_hishelf2_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_biquad_config bqConfig; + bqConfig = ma_hishelf2__get_biquad_config(pConfig); + + return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes); +} + +MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig, void* pHeap, ma_hishelf2* pFilter) { ma_result result; ma_biquad_config bqConfig; @@ -38919,7 +46638,7 @@ MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2 } bqConfig = ma_hishelf2__get_biquad_config(pConfig); - result = ma_biquad_init(&bqConfig, &pFilter->bq); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); if (result != MA_SUCCESS) { return result; } @@ -38927,6 +46646,45 @@ MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2 return MA_SUCCESS; } +MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf2* pFilter) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_hishelf2_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_hishelf2_init_preallocated(pConfig, pHeap, pFilter); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pFilter->bq._ownsHeap = MA_TRUE; /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */ + return MA_SUCCESS; +} + +MA_API void ma_hishelf2_uninit(ma_hishelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pFilter == NULL) { + return; + } + + ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks); /* <-- This will free the heap allocation. */ +} + MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter) { ma_result result; @@ -38975,6 +46733,2286 @@ MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter) +/* +Delay +*/ +MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay) +{ + ma_delay_config config; + + MA_ZERO_OBJECT(&config); + config.channels = channels; + config.sampleRate = sampleRate; + config.delayInFrames = delayInFrames; + config.delayStart = (decay == 0) ? MA_TRUE : MA_FALSE; /* Delay the start if it looks like we're not configuring an echo. */ + config.wet = 1; + config.dry = 1; + config.decay = decay; + + return config; +} + + +MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay) +{ + if (pDelay == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDelay); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->decay < 0 || pConfig->decay > 1) { + return MA_INVALID_ARGS; + } + + pDelay->config = *pConfig; + pDelay->bufferSizeInFrames = pConfig->delayInFrames; + pDelay->cursor = 0; + + pDelay->pBuffer = (float*)ma_malloc((size_t)(pDelay->bufferSizeInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->channels)), pAllocationCallbacks); + if (pDelay->pBuffer == NULL) { + return MA_OUT_OF_MEMORY; + } + + ma_silence_pcm_frames(pDelay->pBuffer, pDelay->bufferSizeInFrames, ma_format_f32, pConfig->channels); + + return MA_SUCCESS; +} + +MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pDelay == NULL) { + return; + } + + ma_free(pDelay->pBuffer, pAllocationCallbacks); +} + +MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) +{ + ma_uint32 iFrame; + ma_uint32 iChannel; + float* pFramesOutF32 = (float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + if (pDelay == NULL || pFramesOut == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pDelay->config.channels; iChannel += 1) { + ma_uint32 iBuffer = (pDelay->cursor * pDelay->config.channels) + iChannel; + + if (pDelay->config.delayStart) { + /* Delayed start. */ + + /* Read */ + pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet; + + /* Feedback */ + pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry); + } else { + /* Immediate start */ + + /* Feedback */ + pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry); + + /* Read */ + pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet; + } + } + + pDelay->cursor = (pDelay->cursor + 1) % pDelay->bufferSizeInFrames; + + pFramesOutF32 += pDelay->config.channels; + pFramesInF32 += pDelay->config.channels; + } + + return MA_SUCCESS; +} + +MA_API void ma_delay_set_wet(ma_delay* pDelay, float value) +{ + if (pDelay == NULL) { + return; + } + + pDelay->config.wet = value; +} + +MA_API float ma_delay_get_wet(const ma_delay* pDelay) +{ + if (pDelay == NULL) { + return 0; + } + + return pDelay->config.wet; +} + +MA_API void ma_delay_set_dry(ma_delay* pDelay, float value) +{ + if (pDelay == NULL) { + return; + } + + pDelay->config.dry = value; +} + +MA_API float ma_delay_get_dry(const ma_delay* pDelay) +{ + if (pDelay == NULL) { + return 0; + } + + return pDelay->config.dry; +} + +MA_API void ma_delay_set_decay(ma_delay* pDelay, float value) +{ + if (pDelay == NULL) { + return; + } + + pDelay->config.decay = value; +} + +MA_API float ma_delay_get_decay(const ma_delay* pDelay) +{ + if (pDelay == NULL) { + return 0; + } + + return pDelay->config.decay; +} + + +MA_API ma_gainer_config ma_gainer_config_init(ma_uint32 channels, ma_uint32 smoothTimeInFrames) +{ + ma_gainer_config config; + + MA_ZERO_OBJECT(&config); + config.channels = channels; + config.smoothTimeInFrames = smoothTimeInFrames; + + return config; +} + + +typedef struct +{ + size_t sizeInBytes; + size_t oldGainsOffset; + size_t newGainsOffset; +} ma_gainer_heap_layout; + +static ma_result ma_gainer_get_heap_layout(const ma_gainer_config* pConfig, ma_gainer_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* Old gains. */ + pHeapLayout->oldGainsOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; + + /* New gains. */ + pHeapLayout->newGainsOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; + + /* Alignment. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + + +MA_API ma_result ma_gainer_get_heap_size(const ma_gainer_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_gainer_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_gainer_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + + +MA_API ma_result ma_gainer_init_preallocated(const ma_gainer_config* pConfig, void* pHeap, ma_gainer* pGainer) +{ + ma_result result; + ma_gainer_heap_layout heapLayout; + ma_uint32 iChannel; + + if (pGainer == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pGainer); + + if (pConfig == NULL || pHeap == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_gainer_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pGainer->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pGainer->pOldGains = (float*)ma_offset_ptr(pHeap, heapLayout.oldGainsOffset); + pGainer->pNewGains = (float*)ma_offset_ptr(pHeap, heapLayout.newGainsOffset); + + pGainer->config = *pConfig; + pGainer->t = (ma_uint32)-1; /* No interpolation by default. */ + + for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { + pGainer->pOldGains[iChannel] = 1; + pGainer->pNewGains[iChannel] = 1; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_gainer_init(const ma_gainer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_gainer* pGainer) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_gainer_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the size of the heap allocation. */ + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_gainer_init_preallocated(pConfig, pHeap, pGainer); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pGainer->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pGainer == NULL) { + return; + } + + if (pGainer->_ownsHeap) { + ma_free(pGainer->_pHeap, pAllocationCallbacks); + } +} + +static float ma_gainer_calculate_current_gain(const ma_gainer* pGainer, ma_uint32 channel) +{ + float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames; + return ma_mix_f32_fast(pGainer->pOldGains[channel], pGainer->pNewGains[channel], a); +} + +MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint32 iChannel; + float* pFramesOutF32 = (float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + if (pGainer == NULL) { + return MA_INVALID_ARGS; + } + + if (pGainer->t >= pGainer->config.smoothTimeInFrames) { + /* Fast path. No gain calculation required. */ + ma_copy_and_apply_volume_factor_per_channel_f32(pFramesOutF32, pFramesInF32, frameCount, pGainer->config.channels, pGainer->pNewGains); + + /* Now that some frames have been processed we need to make sure future changes to the gain are interpolated. */ + if (pGainer->t == (ma_uint32)-1) { + pGainer->t = pGainer->config.smoothTimeInFrames; + } + } else { + /* Slow path. Need to interpolate the gain for each channel individually. */ + + /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */ + if (pFramesOut != NULL && pFramesIn != NULL) { + float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames; + float d = 1.0f / pGainer->config.smoothTimeInFrames; + ma_uint32 channelCount = pGainer->config.channels; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channelCount; iChannel += 1) { + pFramesOutF32[iChannel] = pFramesInF32[iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a); + } + + pFramesOutF32 += channelCount; + pFramesInF32 += channelCount; + + a += d; + if (a > 1) { + a = 1; + } + } + } + + pGainer->t = (ma_uint32)ma_min(pGainer->t + frameCount, pGainer->config.smoothTimeInFrames); + + #if 0 /* Reference implementation. */ + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */ + if (pFramesOut != NULL && pFramesIn != NULL) { + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * ma_gainer_calculate_current_gain(pGainer, iChannel); + } + } + + /* Move interpolation time forward, but don't go beyond our smoothing time. */ + pGainer->t = ma_min(pGainer->t + 1, pGainer->config.smoothTimeInFrames); + } + #endif + } + + return MA_SUCCESS; +} + +static void ma_gainer_set_gain_by_index(ma_gainer* pGainer, float newGain, ma_uint32 iChannel) +{ + pGainer->pOldGains[iChannel] = ma_gainer_calculate_current_gain(pGainer, iChannel); + pGainer->pNewGains[iChannel] = newGain; +} + +static void ma_gainer_reset_smoothing_time(ma_gainer* pGainer) +{ + if (pGainer->t == (ma_uint32)-1) { + pGainer->t = pGainer->config.smoothTimeInFrames; /* No smoothing required for initial gains setting. */ + } else { + pGainer->t = 0; + } +} + +MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain) +{ + ma_uint32 iChannel; + + if (pGainer == NULL) { + return MA_INVALID_ARGS; + } + + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + ma_gainer_set_gain_by_index(pGainer, newGain, iChannel); + } + + /* The smoothing time needs to be reset to ensure we always interpolate by the configured smoothing time, but only if it's not the first setting. */ + ma_gainer_reset_smoothing_time(pGainer); + + return MA_SUCCESS; +} + +MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains) +{ + ma_uint32 iChannel; + + if (pGainer == NULL || pNewGains == NULL) { + return MA_INVALID_ARGS; + } + + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + ma_gainer_set_gain_by_index(pGainer, pNewGains[iChannel], iChannel); + } + + /* The smoothing time needs to be reset to ensure we always interpolate by the configured smoothing time, but only if it's not the first setting. */ + ma_gainer_reset_smoothing_time(pGainer); + + return MA_SUCCESS; +} + + +MA_API ma_panner_config ma_panner_config_init(ma_format format, ma_uint32 channels) +{ + ma_panner_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.mode = ma_pan_mode_balance; /* Set to balancing mode by default because it's consistent with other audio engines and most likely what the caller is expecting. */ + config.pan = 0; + + return config; +} + + +MA_API ma_result ma_panner_init(const ma_panner_config* pConfig, ma_panner* pPanner) +{ + if (pPanner == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pPanner); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + pPanner->format = pConfig->format; + pPanner->channels = pConfig->channels; + pPanner->mode = pConfig->mode; + pPanner->pan = pConfig->pan; + + return MA_SUCCESS; +} + +static void ma_stereo_balance_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, float pan) +{ + ma_uint64 iFrame; + + if (pan > 0) { + float factor = 1.0f - pan; + if (pFramesOut == pFramesIn) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0] * factor; + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0] * factor; + pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1]; + } + } + } else { + float factor = 1.0f + pan; + if (pFramesOut == pFramesIn) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1] * factor; + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0]; + pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1] * factor; + } + } + } +} + +static void ma_stereo_balance_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, float pan) +{ + if (pan == 0) { + /* Fast path. No panning required. */ + if (pFramesOut == pFramesIn) { + /* No-op */ + } else { + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); + } + + return; + } + + switch (format) { + case ma_format_f32: ma_stereo_balance_pcm_frames_f32((float*)pFramesOut, (float*)pFramesIn, frameCount, pan); break; + + /* Unknown format. Just copy. */ + default: + { + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); + } break; + } +} + + +static void ma_stereo_pan_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, float pan) +{ + ma_uint64 iFrame; + + if (pan > 0) { + float factorL0 = 1.0f - pan; + float factorL1 = 0.0f + pan; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float sample0 = (pFramesIn[iFrame*2 + 0] * factorL0); + float sample1 = (pFramesIn[iFrame*2 + 0] * factorL1) + pFramesIn[iFrame*2 + 1]; + + pFramesOut[iFrame*2 + 0] = sample0; + pFramesOut[iFrame*2 + 1] = sample1; + } + } else { + float factorR0 = 0.0f - pan; + float factorR1 = 1.0f + pan; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float sample0 = pFramesIn[iFrame*2 + 0] + (pFramesIn[iFrame*2 + 1] * factorR0); + float sample1 = (pFramesIn[iFrame*2 + 1] * factorR1); + + pFramesOut[iFrame*2 + 0] = sample0; + pFramesOut[iFrame*2 + 1] = sample1; + } + } +} + +static void ma_stereo_pan_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, float pan) +{ + if (pan == 0) { + /* Fast path. No panning required. */ + if (pFramesOut == pFramesIn) { + /* No-op */ + } else { + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); + } + + return; + } + + switch (format) { + case ma_format_f32: ma_stereo_pan_pcm_frames_f32((float*)pFramesOut, (float*)pFramesIn, frameCount, pan); break; + + /* Unknown format. Just copy. */ + default: + { + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2); + } break; + } +} + +MA_API ma_result ma_panner_process_pcm_frames(ma_panner* pPanner, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pPanner == NULL || pFramesOut == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + if (pPanner->channels == 2) { + /* Stereo case. For now assume channel 0 is left and channel right is 1, but should probably add support for a channel map. */ + if (pPanner->mode == ma_pan_mode_balance) { + ma_stereo_balance_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->pan); + } else { + ma_stereo_pan_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->pan); + } + } else { + if (pPanner->channels == 1) { + /* Panning has no effect on mono streams. */ + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->channels); + } else { + /* For now we're not going to support non-stereo set ups. Not sure how I want to handle this case just yet. */ + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->channels); + } + } + + return MA_SUCCESS; +} + +MA_API void ma_panner_set_mode(ma_panner* pPanner, ma_pan_mode mode) +{ + if (pPanner == NULL) { + return; + } + + pPanner->mode = mode; +} + +MA_API ma_pan_mode ma_panner_get_mode(const ma_panner* pPanner) +{ + if (pPanner == NULL) { + return ma_pan_mode_balance; + } + + return pPanner->mode; +} + +MA_API void ma_panner_set_pan(ma_panner* pPanner, float pan) +{ + if (pPanner == NULL) { + return; + } + + pPanner->pan = ma_clamp(pan, -1.0f, 1.0f); +} + +MA_API float ma_panner_get_pan(const ma_panner* pPanner) +{ + if (pPanner == NULL) { + return 0; + } + + return pPanner->pan; +} + + + + +MA_API ma_fader_config ma_fader_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +{ + ma_fader_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + + return config; +} + + +MA_API ma_result ma_fader_init(const ma_fader_config* pConfig, ma_fader* pFader) +{ + if (pFader == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pFader); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + /* Only f32 is supported for now. */ + if (pConfig->format != ma_format_f32) { + return MA_INVALID_ARGS; + } + + pFader->config = *pConfig; + pFader->volumeBeg = 1; + pFader->volumeEnd = 1; + pFader->lengthInFrames = 0; + pFader->cursorInFrames = 0; + + return MA_SUCCESS; +} + +MA_API ma_result ma_fader_process_pcm_frames(ma_fader* pFader, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pFader == NULL) { + return MA_INVALID_ARGS; + } + + /* + For now we need to clamp frameCount so that the cursor never overflows 32-bits. This is required for + the conversion to a float which we use for the linear interpolation. This might be changed later. + */ + if (frameCount + pFader->cursorInFrames > UINT_MAX) { + frameCount = UINT_MAX - pFader->cursorInFrames; + } + + /* Optimized path if volumeBeg and volumeEnd are equal. */ + if (pFader->volumeBeg == pFader->volumeEnd) { + if (pFader->volumeBeg == 1) { + /* Straight copy. */ + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels); + } else { + /* Copy with volume. */ + ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels, pFader->volumeEnd); + } + } else { + /* Slower path. Volumes are different, so may need to do an interpolation. */ + if (pFader->cursorInFrames >= pFader->lengthInFrames) { + /* Fast path. We've gone past the end of the fade period so just apply the end volume to all samples. */ + ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels, pFader->volumeEnd); + } else { + /* Slow path. This is where we do the actual fading. */ + ma_uint64 iFrame; + ma_uint32 iChannel; + + /* For now we only support f32. Support for other formats will be added later. */ + if (pFader->config.format == ma_format_f32) { + const float* pFramesInF32 = (const float*)pFramesIn; + /* */ float* pFramesOutF32 = ( float*)pFramesOut; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float a = (ma_uint32)ma_min(pFader->cursorInFrames + iFrame, pFader->lengthInFrames) / (float)((ma_uint32)pFader->lengthInFrames); /* Safe cast due to the frameCount clamp at the top of this function. */ + float volume = ma_mix_f32_fast(pFader->volumeBeg, pFader->volumeEnd, a); + + for (iChannel = 0; iChannel < pFader->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pFader->config.channels + iChannel] = pFramesInF32[iFrame*pFader->config.channels + iChannel] * volume; + } + } + } else { + return MA_NOT_IMPLEMENTED; + } + } + } + + pFader->cursorInFrames += frameCount; + + return MA_SUCCESS; +} + +MA_API void ma_fader_get_data_format(const ma_fader* pFader, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +{ + if (pFader == NULL) { + return; + } + + if (pFormat != NULL) { + *pFormat = pFader->config.format; + } + + if (pChannels != NULL) { + *pChannels = pFader->config.channels; + } + + if (pSampleRate != NULL) { + *pSampleRate = pFader->config.sampleRate; + } +} + +MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames) +{ + if (pFader == NULL) { + return; + } + + /* If the volume is negative, use current volume. */ + if (volumeBeg < 0) { + volumeBeg = ma_fader_get_current_volume(pFader); + } + + /* + The length needs to be clamped to 32-bits due to how we convert it to a float for linear + interpolation reasons. I might change this requirement later, but for now it's not important. + */ + if (lengthInFrames > UINT_MAX) { + lengthInFrames = UINT_MAX; + } + + pFader->volumeBeg = volumeBeg; + pFader->volumeEnd = volumeEnd; + pFader->lengthInFrames = lengthInFrames; + pFader->cursorInFrames = 0; /* Reset cursor. */ +} + +MA_API float ma_fader_get_current_volume(ma_fader* pFader) +{ + if (pFader == NULL) { + return 0.0f; + } + + /* The current volume depends on the position of the cursor. */ + if (pFader->cursorInFrames == 0) { + return pFader->volumeBeg; + } else if (pFader->cursorInFrames >= pFader->lengthInFrames) { + return pFader->volumeEnd; + } else { + /* The cursor is somewhere inside the fading period. We can figure this out with a simple linear interpoluation between volumeBeg and volumeEnd based on our cursor position. */ + return ma_mix_f32_fast(pFader->volumeBeg, pFader->volumeEnd, (ma_uint32)pFader->cursorInFrames / (float)((ma_uint32)pFader->lengthInFrames)); /* Safe cast to uint32 because we clamp it in ma_fader_process_pcm_frames(). */ + } +} + + + + + +MA_API ma_vec3f ma_vec3f_init_3f(float x, float y, float z) +{ + ma_vec3f v; + + v.x = x; + v.y = y; + v.z = z; + + return v; +} + +MA_API ma_vec3f ma_vec3f_sub(ma_vec3f a, ma_vec3f b) +{ + return ma_vec3f_init_3f( + a.x - b.x, + a.y - b.y, + a.z - b.z + ); +} + +MA_API ma_vec3f ma_vec3f_neg(ma_vec3f a) +{ + return ma_vec3f_init_3f( + -a.x, + -a.y, + -a.z + ); +} + +MA_API float ma_vec3f_dot(ma_vec3f a, ma_vec3f b) +{ + return a.x*b.x + a.y*b.y + a.z*b.z; +} + +MA_API float ma_vec3f_len2(ma_vec3f v) +{ + return ma_vec3f_dot(v, v); +} + +MA_API float ma_vec3f_len(ma_vec3f v) +{ + return (float)ma_sqrtd(ma_vec3f_len2(v)); +} + +MA_API float ma_vec3f_dist(ma_vec3f a, ma_vec3f b) +{ + return ma_vec3f_len(ma_vec3f_sub(a, b)); +} + +MA_API ma_vec3f ma_vec3f_normalize(ma_vec3f v) +{ + float f; + float l = ma_vec3f_len(v); + if (l == 0) { + return ma_vec3f_init_3f(0, 0, 0); + } + + f = 1 / l; + v.x *= f; + v.y *= f; + v.z *= f; + + return v; +} + +MA_API ma_vec3f ma_vec3f_cross(ma_vec3f a, ma_vec3f b) +{ + return ma_vec3f_init_3f( + a.y*b.z - a.z*b.y, + a.z*b.x - a.x*b.z, + a.x*b.y - a.y*b.x + ); +} + + + +static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount, ma_channel_mix_mode mode, ma_mono_expansion_mode monoExpansionMode); +static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition); + + +#ifndef MA_DEFAULT_SPEED_OF_SOUND +#define MA_DEFAULT_SPEED_OF_SOUND 343.3f +#endif + +/* +These vectors represent the direction that speakers are facing from the center point. They're used +for panning in the spatializer. Must be normalized. +*/ +static ma_vec3f g_maChannelDirections[MA_CHANNEL_POSITION_COUNT] = { + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_NONE */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_MONO */ + {-0.7071f, 0.0f, -0.7071f }, /* MA_CHANNEL_FRONT_LEFT */ + {+0.7071f, 0.0f, -0.7071f }, /* MA_CHANNEL_FRONT_RIGHT */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_FRONT_CENTER */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_LFE */ + {-0.7071f, 0.0f, +0.7071f }, /* MA_CHANNEL_BACK_LEFT */ + {+0.7071f, 0.0f, +0.7071f }, /* MA_CHANNEL_BACK_RIGHT */ + {-0.3162f, 0.0f, -0.9487f }, /* MA_CHANNEL_FRONT_LEFT_CENTER */ + {+0.3162f, 0.0f, -0.9487f }, /* MA_CHANNEL_FRONT_RIGHT_CENTER */ + { 0.0f, 0.0f, +1.0f }, /* MA_CHANNEL_BACK_CENTER */ + {-1.0f, 0.0f, 0.0f }, /* MA_CHANNEL_SIDE_LEFT */ + {+1.0f, 0.0f, 0.0f }, /* MA_CHANNEL_SIDE_RIGHT */ + { 0.0f, +1.0f, 0.0f }, /* MA_CHANNEL_TOP_CENTER */ + {-0.5774f, +0.5774f, -0.5774f }, /* MA_CHANNEL_TOP_FRONT_LEFT */ + { 0.0f, +0.7071f, -0.7071f }, /* MA_CHANNEL_TOP_FRONT_CENTER */ + {+0.5774f, +0.5774f, -0.5774f }, /* MA_CHANNEL_TOP_FRONT_RIGHT */ + {-0.5774f, +0.5774f, +0.5774f }, /* MA_CHANNEL_TOP_BACK_LEFT */ + { 0.0f, +0.7071f, +0.7071f }, /* MA_CHANNEL_TOP_BACK_CENTER */ + {+0.5774f, +0.5774f, +0.5774f }, /* MA_CHANNEL_TOP_BACK_RIGHT */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_0 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_1 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_2 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_3 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_4 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_5 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_6 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_7 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_8 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_9 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_10 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_11 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_12 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_13 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_14 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_15 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_16 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_17 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_18 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_19 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_20 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_21 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_22 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_23 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_24 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_25 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_26 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_27 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_28 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_29 */ + { 0.0f, 0.0f, -1.0f }, /* MA_CHANNEL_AUX_30 */ + { 0.0f, 0.0f, -1.0f } /* MA_CHANNEL_AUX_31 */ +}; + +static ma_vec3f ma_get_channel_direction(ma_channel channel) +{ + if (channel >= MA_CHANNEL_POSITION_COUNT) { + return ma_vec3f_init_3f(0, 0, -1); + } else { + return g_maChannelDirections[channel]; + } +} + + + +static float ma_attenuation_inverse(float distance, float minDistance, float maxDistance, float rolloff) +{ + if (minDistance >= maxDistance) { + return 1; /* To avoid division by zero. Do not attenuate. */ + } + + return minDistance / (minDistance + rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance)); +} + +static float ma_attenuation_linear(float distance, float minDistance, float maxDistance, float rolloff) +{ + if (minDistance >= maxDistance) { + return 1; /* To avoid division by zero. Do not attenuate. */ + } + + return 1 - rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance) / (maxDistance - minDistance); +} + +static float ma_attenuation_exponential(float distance, float minDistance, float maxDistance, float rolloff) +{ + if (minDistance >= maxDistance) { + return 1; /* To avoid division by zero. Do not attenuate. */ + } + + return (float)ma_powd(ma_clamp(distance, minDistance, maxDistance) / minDistance, -rolloff); +} + + +/* +Dopper Effect calculation taken from the OpenAL spec, with two main differences: + + 1) The source to listener vector will have already been calcualted at an earlier step so we can + just use that directly. We need only the position of the source relative to the origin. + + 2) We don't scale by a frequency because we actually just want the ratio which we'll plug straight + into the resampler directly. +*/ +static float ma_doppler_pitch(ma_vec3f relativePosition, ma_vec3f sourceVelocity, ma_vec3f listenVelocity, float speedOfSound, float dopplerFactor) +{ + float len; + float vls; + float vss; + + len = ma_vec3f_len(relativePosition); + + /* + There's a case where the position of the source will be right on top of the listener in which + case the length will be 0 and we'll end up with a division by zero. We can just return a ratio + of 1.0 in this case. This is not considered in the OpenAL spec, but is necessary. + */ + if (len == 0) { + return 1.0; + } + + vls = ma_vec3f_dot(relativePosition, listenVelocity) / len; + vss = ma_vec3f_dot(relativePosition, sourceVelocity) / len; + + vls = ma_min(vls, speedOfSound / dopplerFactor); + vss = ma_min(vss, speedOfSound / dopplerFactor); + + return (speedOfSound - dopplerFactor*vls) / (speedOfSound - dopplerFactor*vss); +} + + +static void ma_get_default_channel_map_for_spatializer(ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channelCount) +{ + /* + Special case for stereo. Want to default the left and right speakers to side left and side + right so that they're facing directly down the X axis rather than slightly forward. Not + doing this will result in sounds being quieter when behind the listener. This might + actually be good for some scenerios, but I don't think it's an appropriate default because + it can be a bit unexpected. + */ + if (channelCount == 2) { + pChannelMap[0] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[1] = MA_CHANNEL_SIDE_RIGHT; + } else { + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); + } +} + + +MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(ma_uint32 channelsOut) +{ + ma_spatializer_listener_config config; + + MA_ZERO_OBJECT(&config); + config.channelsOut = channelsOut; + config.pChannelMapOut = NULL; + config.handedness = ma_handedness_right; + config.worldUp = ma_vec3f_init_3f(0, 1, 0); + config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */ + config.coneOuterAngleInRadians = 6.283185f; /* 360 degrees. */ + config.coneOuterGain = 0; + config.speedOfSound = 343.3f; /* Same as OpenAL. Used for doppler effect. */ + + return config; +} + + +typedef struct +{ + size_t sizeInBytes; + size_t channelMapOutOffset; +} ma_spatializer_listener_heap_layout; + +static ma_result ma_spatializer_listener_get_heap_layout(const ma_spatializer_listener_config* pConfig, ma_spatializer_listener_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channelsOut == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* Channel map. We always need this, even for passthroughs. */ + pHeapLayout->channelMapOutOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(sizeof(*pConfig->pChannelMapOut) * pConfig->channelsOut); + + return MA_SUCCESS; +} + + +MA_API ma_result ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_spatializer_listener_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_spatializer_listener_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config* pConfig, void* pHeap, ma_spatializer_listener* pListener) +{ + ma_result result; + ma_spatializer_listener_heap_layout heapLayout; + + if (pListener == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pListener); + + result = ma_spatializer_listener_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pListener->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pListener->config = *pConfig; + pListener->position = ma_vec3f_init_3f(0, 0, 0); + pListener->direction = ma_vec3f_init_3f(0, 0, -1); + pListener->velocity = ma_vec3f_init_3f(0, 0, 0); + pListener->isEnabled = MA_TRUE; + + /* Swap the forward direction if we're left handed (it was initialized based on right handed). */ + if (pListener->config.handedness == ma_handedness_left) { + pListener->direction = ma_vec3f_neg(pListener->direction); + } + + + /* We must always have a valid channel map. */ + pListener->config.pChannelMapOut = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapOutOffset); + + /* Use a slightly different default channel map for stereo. */ + if (pConfig->pChannelMapOut == NULL) { + ma_get_default_channel_map_for_spatializer(pListener->config.pChannelMapOut, pConfig->channelsOut, pConfig->channelsOut); + } else { + ma_channel_map_copy_or_default(pListener->config.pChannelMapOut, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelsOut); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_spatializer_listener_init(const ma_spatializer_listener_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer_listener* pListener) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_spatializer_listener_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_spatializer_listener_init_preallocated(pConfig, pHeap, pListener); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pListener->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_spatializer_listener_uninit(ma_spatializer_listener* pListener, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pListener == NULL) { + return; + } + + if (pListener->_ownsHeap) { + ma_free(pListener->_pHeap, pAllocationCallbacks); + } +} + +MA_API ma_channel* ma_spatializer_listener_get_channel_map(ma_spatializer_listener* pListener) +{ + if (pListener == NULL) { + return NULL; + } + + return pListener->config.pChannelMapOut; +} + +MA_API void ma_spatializer_listener_set_cone(ma_spatializer_listener* pListener, float innerAngleInRadians, float outerAngleInRadians, float outerGain) +{ + if (pListener == NULL) { + return; + } + + pListener->config.coneInnerAngleInRadians = innerAngleInRadians; + pListener->config.coneOuterAngleInRadians = outerAngleInRadians; + pListener->config.coneOuterGain = outerGain; +} + +MA_API void ma_spatializer_listener_get_cone(const ma_spatializer_listener* pListener, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) +{ + if (pListener == NULL) { + return; + } + + if (pInnerAngleInRadians != NULL) { + *pInnerAngleInRadians = pListener->config.coneInnerAngleInRadians; + } + + if (pOuterAngleInRadians != NULL) { + *pOuterAngleInRadians = pListener->config.coneOuterAngleInRadians; + } + + if (pOuterGain != NULL) { + *pOuterGain = pListener->config.coneOuterGain; + } +} + +MA_API void ma_spatializer_listener_set_position(ma_spatializer_listener* pListener, float x, float y, float z) +{ + if (pListener == NULL) { + return; + } + + pListener->position = ma_vec3f_init_3f(x, y, z); +} + +MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener* pListener) +{ + if (pListener == NULL) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return pListener->position; +} + +MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pListener, float x, float y, float z) +{ + if (pListener == NULL) { + return; + } + + pListener->direction = ma_vec3f_init_3f(x, y, z); +} + +MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener* pListener) +{ + if (pListener == NULL) { + return ma_vec3f_init_3f(0, 0, -1); + } + + return pListener->direction; +} + +MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListener, float x, float y, float z) +{ + if (pListener == NULL) { + return; + } + + pListener->velocity = ma_vec3f_init_3f(x, y, z); +} + +MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener* pListener) +{ + if (pListener == NULL) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return pListener->velocity; +} + +MA_API void ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener* pListener, float speedOfSound) +{ + if (pListener == NULL) { + return; + } + + pListener->config.speedOfSound = speedOfSound; +} + +MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener* pListener) +{ + if (pListener == NULL) { + return 0; + } + + return pListener->config.speedOfSound; +} + +MA_API void ma_spatializer_listener_set_world_up(ma_spatializer_listener* pListener, float x, float y, float z) +{ + if (pListener == NULL) { + return; + } + + pListener->config.worldUp = ma_vec3f_init_3f(x, y, z); +} + +MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener* pListener) +{ + if (pListener == NULL) { + return ma_vec3f_init_3f(0, 1, 0); + } + + return pListener->config.worldUp; +} + +MA_API void ma_spatializer_listener_set_enabled(ma_spatializer_listener* pListener, ma_bool32 isEnabled) +{ + if (pListener == NULL) { + return; + } + + pListener->isEnabled = isEnabled; +} + +MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener* pListener) +{ + if (pListener == NULL) { + return MA_FALSE; + } + + return pListener->isEnabled; +} + + + + +MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma_uint32 channelsOut) +{ + ma_spatializer_config config; + + MA_ZERO_OBJECT(&config); + config.channelsIn = channelsIn; + config.channelsOut = channelsOut; + config.pChannelMapIn = NULL; + config.attenuationModel = ma_attenuation_model_inverse; + config.positioning = ma_positioning_absolute; + config.handedness = ma_handedness_right; + config.minGain = 0; + config.maxGain = 1; + config.minDistance = 1; + config.maxDistance = MA_FLT_MAX; + config.rolloff = 1; + config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */ + config.coneOuterAngleInRadians = 6.283185f; /* 360 degress. */ + config.coneOuterGain = 0.0f; + config.dopplerFactor = 1; + config.directionalAttenuationFactor = 1; + config.gainSmoothTimeInFrames = 360; /* 7.5ms @ 48K. */ + + return config; +} + + +static ma_gainer_config ma_spatializer_gainer_config_init(const ma_spatializer_config* pConfig) +{ + MA_ASSERT(pConfig != NULL); + return ma_gainer_config_init(pConfig->channelsOut, pConfig->gainSmoothTimeInFrames); +} + +static ma_result ma_spatializer_validate_config(const ma_spatializer_config* pConfig) +{ + MA_ASSERT(pConfig != NULL); + + if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) { + return MA_INVALID_ARGS; + } + + return MA_SUCCESS; +} + +typedef struct +{ + size_t sizeInBytes; + size_t channelMapInOffset; + size_t newChannelGainsOffset; + size_t gainerOffset; +} ma_spatializer_heap_layout; + +static ma_result ma_spatializer_get_heap_layout(const ma_spatializer_config* pConfig, ma_spatializer_heap_layout* pHeapLayout) +{ + ma_result result; + + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_spatializer_validate_config(pConfig); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes = 0; + + /* Channel map. */ + pHeapLayout->channelMapInOffset = MA_SIZE_MAX; /* <-- MA_SIZE_MAX indicates no allocation necessary. */ + if (pConfig->pChannelMapIn != NULL) { + pHeapLayout->channelMapInOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(sizeof(*pConfig->pChannelMapIn) * pConfig->channelsIn); + } + + /* New channel gains for output. */ + pHeapLayout->newChannelGainsOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(sizeof(float) * pConfig->channelsOut); + + /* Gainer. */ + { + size_t gainerHeapSizeInBytes; + ma_gainer_config gainerConfig; + + gainerConfig = ma_spatializer_gainer_config_init(pConfig); + + result = ma_gainer_get_heap_size(&gainerConfig, &gainerHeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->gainerOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(gainerHeapSizeInBytes); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_spatializer_get_heap_size(const ma_spatializer_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_spatializer_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; /* Safety. */ + + result = ma_spatializer_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + + +MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* pConfig, void* pHeap, ma_spatializer* pSpatializer) +{ + ma_result result; + ma_spatializer_heap_layout heapLayout; + ma_gainer_config gainerConfig; + + if (pSpatializer == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pSpatializer); + + if (pConfig == NULL || pHeap == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_spatializer_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pSpatializer->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pSpatializer->channelsIn = pConfig->channelsIn; + pSpatializer->channelsOut = pConfig->channelsOut; + pSpatializer->attenuationModel = pConfig->attenuationModel; + pSpatializer->positioning = pConfig->positioning; + pSpatializer->handedness = pConfig->handedness; + pSpatializer->minGain = pConfig->minGain; + pSpatializer->maxGain = pConfig->maxGain; + pSpatializer->minDistance = pConfig->minDistance; + pSpatializer->maxDistance = pConfig->maxDistance; + pSpatializer->rolloff = pConfig->rolloff; + pSpatializer->coneInnerAngleInRadians = pConfig->coneInnerAngleInRadians; + pSpatializer->coneOuterAngleInRadians = pConfig->coneOuterAngleInRadians; + pSpatializer->coneOuterGain = pConfig->coneOuterGain; + pSpatializer->dopplerFactor = pConfig->dopplerFactor; + pSpatializer->directionalAttenuationFactor = pConfig->directionalAttenuationFactor; + pSpatializer->gainSmoothTimeInFrames = pConfig->gainSmoothTimeInFrames; + pSpatializer->position = ma_vec3f_init_3f(0, 0, 0); + pSpatializer->direction = ma_vec3f_init_3f(0, 0, -1); + pSpatializer->velocity = ma_vec3f_init_3f(0, 0, 0); + pSpatializer->dopplerPitch = 1; + + /* Swap the forward direction if we're left handed (it was initialized based on right handed). */ + if (pSpatializer->handedness == ma_handedness_left) { + pSpatializer->direction = ma_vec3f_neg(pSpatializer->direction); + } + + /* Channel map. This will be on the heap. */ + if (pConfig->pChannelMapIn != NULL) { + pSpatializer->pChannelMapIn = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapInOffset); + ma_channel_map_copy_or_default(pSpatializer->pChannelMapIn, pSpatializer->channelsIn, pConfig->pChannelMapIn, pSpatializer->channelsIn); + } + + /* New channel gains for output channels. */ + pSpatializer->pNewChannelGainsOut = (float*)ma_offset_ptr(pHeap, heapLayout.newChannelGainsOffset); + + /* Gainer. */ + gainerConfig = ma_spatializer_gainer_config_init(pConfig); + + result = ma_gainer_init_preallocated(&gainerConfig, ma_offset_ptr(pHeap, heapLayout.gainerOffset), &pSpatializer->gainer); + if (result != MA_SUCCESS) { + return result; /* Failed to initialize the gainer. */ + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer* pSpatializer) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + /* We'll need a heap allocation to retrieve the size. */ + result = ma_spatializer_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_spatializer_init_preallocated(pConfig, pHeap, pSpatializer); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pSpatializer->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pSpatializer == NULL) { + return; + } + + ma_gainer_uninit(&pSpatializer->gainer, pAllocationCallbacks); + + if (pSpatializer->_ownsHeap) { + ma_free(pSpatializer->_pHeap, pAllocationCallbacks); + } +} + +static float ma_calculate_angular_gain(ma_vec3f dirA, ma_vec3f dirB, float coneInnerAngleInRadians, float coneOuterAngleInRadians, float coneOuterGain) +{ + /* + Angular attenuation. + + Unlike distance gain, the math for this is not specified by the OpenAL spec so we'll just go ahead and figure + this out for ourselves at the expense of possibly being inconsistent with other implementations. + + To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We + just need to get the direction from the source to the listener and then do a dot product against that and the + direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer + angles. If the dot product is greater than the the outer angle, we just use coneOuterGain. If it's less than + the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain. + */ + if (coneInnerAngleInRadians < 6.283185f) { + float angularGain = 1; + float cutoffInner = (float)ma_cosd(coneInnerAngleInRadians*0.5f); + float cutoffOuter = (float)ma_cosd(coneOuterAngleInRadians*0.5f); + float d; + + d = ma_vec3f_dot(dirA, dirB); + + if (d > cutoffInner) { + /* It's inside the inner angle. */ + angularGain = 1; + } else { + /* It's outside the inner angle. */ + if (d > cutoffOuter) { + /* It's between the inner and outer angle. We need to linearly interpolate between 1 and coneOuterGain. */ + angularGain = ma_mix_f32(coneOuterGain, 1, (d - cutoffOuter) / (cutoffInner - cutoffOuter)); + } else { + /* It's outside the outer angle. */ + angularGain = coneOuterGain; + } + } + + /*printf("d = %f; cutoffInner = %f; cutoffOuter = %f; angularGain = %f\n", d, cutoffInner, cutoffOuter, angularGain);*/ + return angularGain; + } else { + /* Inner angle is 360 degrees so no need to do any attenuation. */ + return 1; + } +} + +MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_channel* pChannelMapIn = pSpatializer->pChannelMapIn; + ma_channel* pChannelMapOut = pListener->config.pChannelMapOut; + + if (pSpatializer == NULL) { + return MA_INVALID_ARGS; + } + + /* If we're not spatializing we need to run an optimized path. */ + if (c89atomic_load_i32(&pSpatializer->attenuationModel) == ma_attenuation_model_none) { + if (ma_spatializer_listener_is_enabled(pListener)) { + /* No attenuation is required, but we'll need to do some channel conversion. */ + if (pSpatializer->channelsIn == pSpatializer->channelsOut) { + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, ma_format_f32, pSpatializer->channelsIn); + } else { + ma_channel_map_apply_f32((float*)pFramesOut, pChannelMapOut, pSpatializer->channelsOut, (const float*)pFramesIn, pChannelMapIn, pSpatializer->channelsIn, frameCount, ma_channel_mix_mode_rectangular, ma_mono_expansion_mode_default); /* Safe casts to float* because f32 is the only supported format. */ + } + } else { + /* The listener is disabled. Output silence. */ + ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, pSpatializer->channelsOut); + } + + /* + We're not doing attenuation so don't bother with doppler for now. I'm not sure if this is + the correct thinking so might need to review this later. + */ + pSpatializer->dopplerPitch = 1; + } else { + /* + Let's first determine which listener the sound is closest to. Need to keep in mind that we + might not have a world or any listeners, in which case we just spatializer based on the + listener being positioned at the origin (0, 0, 0). + */ + ma_vec3f relativePosNormalized; + ma_vec3f relativePos; /* The position relative to the listener. */ + ma_vec3f relativeDir; /* The direction of the sound, relative to the listener. */ + ma_vec3f listenerVel; /* The volocity of the listener. For doppler pitch calculation. */ + float speedOfSound; + float distance = 0; + float gain = 1; + ma_uint32 iChannel; + const ma_uint32 channelsOut = pSpatializer->channelsOut; + const ma_uint32 channelsIn = pSpatializer->channelsIn; + float minDistance = ma_spatializer_get_min_distance(pSpatializer); + float maxDistance = ma_spatializer_get_max_distance(pSpatializer); + float rolloff = ma_spatializer_get_rolloff(pSpatializer); + float dopplerFactor = ma_spatializer_get_doppler_factor(pSpatializer); + + /* + We'll need the listener velocity for doppler pitch calculations. The speed of sound is + defined by the listener, so we'll grab that here too. + */ + if (pListener != NULL) { + listenerVel = pListener->velocity; + speedOfSound = pListener->config.speedOfSound; + } else { + listenerVel = ma_vec3f_init_3f(0, 0, 0); + speedOfSound = MA_DEFAULT_SPEED_OF_SOUND; + } + + if (pListener == NULL || ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { + /* There's no listener or we're using relative positioning. */ + relativePos = pSpatializer->position; + relativeDir = pSpatializer->direction; + } else { + /* + We've found a listener and we're using absolute positioning. We need to transform the + sound's position and direction so that it's relative to listener. Later on we'll use + this for determining the factors to apply to each channel to apply the panning effect. + */ + ma_spatializer_get_relative_position_and_direction(pSpatializer, pListener, &relativePos, &relativeDir); + } + + distance = ma_vec3f_len(relativePos); + + /* We've gathered the data, so now we can apply some spatialization. */ + switch (ma_spatializer_get_attenuation_model(pSpatializer)) { + case ma_attenuation_model_inverse: + { + gain = ma_attenuation_inverse(distance, minDistance, maxDistance, rolloff); + } break; + case ma_attenuation_model_linear: + { + gain = ma_attenuation_linear(distance, minDistance, maxDistance, rolloff); + } break; + case ma_attenuation_model_exponential: + { + gain = ma_attenuation_exponential(distance, minDistance, maxDistance, rolloff); + } break; + case ma_attenuation_model_none: + default: + { + gain = 1; + } break; + } + + /* Normalize the position. */ + if (distance > 0.001f) { + float distanceInv = 1/distance; + relativePosNormalized = relativePos; + relativePosNormalized.x *= distanceInv; + relativePosNormalized.y *= distanceInv; + relativePosNormalized.z *= distanceInv; + } else { + distance = 0; + relativePosNormalized = ma_vec3f_init_3f(0, 0, 0); + } + + /* + Angular attenuation. + + Unlike distance gain, the math for this is not specified by the OpenAL spec so we'll just go ahead and figure + this out for ourselves at the expense of possibly being inconsistent with other implementations. + + To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We + just need to get the direction from the source to the listener and then do a dot product against that and the + direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer + angles. If the dot product is greater than the the outer angle, we just use coneOuterGain. If it's less than + the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain. + */ + if (distance > 0) { + /* Source anglular gain. */ + float spatializerConeInnerAngle; + float spatializerConeOuterAngle; + float spatializerConeOuterGain; + ma_spatializer_get_cone(pSpatializer, &spatializerConeInnerAngle, &spatializerConeOuterAngle, &spatializerConeOuterGain); + + gain *= ma_calculate_angular_gain(relativeDir, ma_vec3f_neg(relativePosNormalized), spatializerConeInnerAngle, spatializerConeOuterAngle, spatializerConeOuterGain); + + /* + We're supporting angular gain on the listener as well for those who want to reduce the volume of sounds that + are positioned behind the listener. On default settings, this will have no effect. + */ + if (pListener != NULL && pListener->config.coneInnerAngleInRadians < 6.283185f) { + ma_vec3f listenerDirection; + float listenerInnerAngle; + float listenerOuterAngle; + float listenerOuterGain; + + if (pListener->config.handedness == ma_handedness_right) { + listenerDirection = ma_vec3f_init_3f(0, 0, -1); + } else { + listenerDirection = ma_vec3f_init_3f(0, 0, +1); + } + + listenerInnerAngle = pListener->config.coneInnerAngleInRadians; + listenerOuterAngle = pListener->config.coneOuterAngleInRadians; + listenerOuterGain = pListener->config.coneOuterGain; + + gain *= ma_calculate_angular_gain(listenerDirection, relativePosNormalized, listenerInnerAngle, listenerOuterAngle, listenerOuterGain); + } + } else { + /* The sound is right on top of the listener. Don't do any angular attenuation. */ + } + + + /* Clamp the gain. */ + gain = ma_clamp(gain, ma_spatializer_get_min_gain(pSpatializer), ma_spatializer_get_max_gain(pSpatializer)); + + /* + Panning. This is where we'll apply the gain and convert to the output channel count. We have an optimized path for + when we're converting to a mono stream. In that case we don't really need to do any panning - we just apply the + gain to the final output. + */ + /*printf("distance=%f; gain=%f\n", distance, gain);*/ + + /* We must have a valid channel map here to ensure we spatialize properly. */ + MA_ASSERT(pChannelMapOut != NULL); + + /* + We're not converting to mono so we'll want to apply some panning. This is where the feeling of something being + to the left, right, infront or behind the listener is calculated. I'm just using a basic model here. Note that + the code below is not based on any specific algorithm. I'm just implementing this off the top of my head and + seeing how it goes. There might be better ways to do this. + + To determine the direction of the sound relative to a speaker I'm using dot products. Each speaker is given a + direction. For example, the left channel in a stereo system will be -1 on the X axis and the right channel will + be +1 on the X axis. A dot product is performed against the direction vector of the channel and the normalized + position of the sound. + */ + for (iChannel = 0; iChannel < channelsOut; iChannel += 1) { + pSpatializer->pNewChannelGainsOut[iChannel] = gain; + } + + /* + Convert to our output channel count. If the listener is disabled we just output silence here. We cannot ignore + the whole section of code here because we need to update some internal spatialization state. + */ + if (ma_spatializer_listener_is_enabled(pListener)) { + ma_channel_map_apply_f32((float*)pFramesOut, pChannelMapOut, channelsOut, (const float*)pFramesIn, pChannelMapIn, channelsIn, frameCount, ma_channel_mix_mode_rectangular, ma_mono_expansion_mode_default); + } else { + ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, pSpatializer->channelsOut); + } + + /* + Calculate our per-channel gains. We do this based on the normalized relative position of the sound and it's + relation to the direction of the channel. + */ + if (distance > 0) { + ma_vec3f unitPos = relativePos; + float distanceInv = 1/distance; + unitPos.x *= distanceInv; + unitPos.y *= distanceInv; + unitPos.z *= distanceInv; + + for (iChannel = 0; iChannel < channelsOut; iChannel += 1) { + ma_channel channelOut; + float d; + float dMin; + + channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannel); + if (ma_is_spatial_channel_position(channelOut)) { + d = ma_mix_f32_fast(1, ma_vec3f_dot(unitPos, ma_get_channel_direction(channelOut)), ma_spatializer_get_directional_attenuation_factor(pSpatializer)); + } else { + d = 1; /* It's not a spatial channel so there's no real notion of direction. */ + } + + /* + In my testing, if the panning effect is too aggressive it makes spatialization feel uncomfortable. + The "dMin" variable below is used to control the aggressiveness of the panning effect. When set to + 0, panning will be most extreme and any sounds that are positioned on the opposite side of the + speaker will be completely silent from that speaker. Not only does this feel uncomfortable, it + doesn't even remotely represent the real world at all because sounds that come from your right side + are still clearly audible from your left side. Setting "dMin" to 1 will result in no panning at + all, which is also not ideal. By setting it to something greater than 0, the spatialization effect + becomes much less dramatic and a lot more bearable. + + Summary: 0 = more extreme panning; 1 = no panning. + */ + dMin = 0.2f; /* TODO: Consider making this configurable. */ + + /* + At this point, "d" will be positive if the sound is on the same side as the channel and negative if + it's on the opposite side. It will be in the range of -1..1. There's two ways I can think of to + calculate a panning value. The first is to simply convert it to 0..1, however this has a problem + which I'm not entirely happy with. Considering a stereo system, when a sound is positioned right + in front of the listener it'll result in each speaker getting a gain of 0.5. I don't know if I like + the idea of having a scaling factor of 0.5 being applied to a sound when it's sitting right in front + of the listener. I would intuitively expect that to be played at full volume, or close to it. + + The second idea I think of is to only apply a reduction in gain when the sound is on the opposite + side of the speaker. That is, reduce the gain only when the dot product is negative. The problem + with this is that there will not be any attenuation as the sound sweeps around the 180 degrees + where the dot product is positive. The idea with this option is that you leave the gain at 1 when + the sound is being played on the same side as the speaker and then you just reduce the volume when + the sound is on the other side. + + The summarize, I think the first option should give a better sense of spatialization, but the second + option is better for preserving the sound's power. + + UPDATE: In my testing, I find the first option to sound better. You can feel the sense of space a + bit better, but you can also hear the reduction in volume when it's right in front. + */ + #if 1 + { + /* + Scale the dot product from -1..1 to 0..1. Will result in a sound directly in front losing power + by being played at 0.5 gain. + */ + d = (d + 1) * 0.5f; /* -1..1 to 0..1 */ + d = ma_max(d, dMin); + pSpatializer->pNewChannelGainsOut[iChannel] *= d; + } + #else + { + /* + Only reduce the volume of the sound if it's on the opposite side. This path keeps the volume more + consistent, but comes at the expense of a worse sense of space and positioning. + */ + if (d < 0) { + d += 1; /* Move into the positive range. */ + d = ma_max(d, dMin); + channelGainsOut[iChannel] *= d; + } + } + #endif + } + } else { + /* Assume the sound is right on top of us. Don't do any panning. */ + } + + /* Now we need to apply the volume to each channel. This needs to run through the gainer to ensure we get a smooth volume transition. */ + ma_gainer_set_gains(&pSpatializer->gainer, pSpatializer->pNewChannelGainsOut); + ma_gainer_process_pcm_frames(&pSpatializer->gainer, pFramesOut, pFramesOut, frameCount); + + /* + Before leaving we'll want to update our doppler pitch so that the caller can apply some + pitch shifting if they desire. Note that we need to negate the relative position here + because the doppler calculation needs to be source-to-listener, but ours is listener-to- + source. + */ + if (dopplerFactor > 0) { + pSpatializer->dopplerPitch = ma_doppler_pitch(ma_vec3f_sub(pListener->position, pSpatializer->position), pSpatializer->velocity, listenerVel, speedOfSound, dopplerFactor); + } else { + pSpatializer->dopplerPitch = 1; + } + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return pSpatializer->channelsIn; +} + +MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return pSpatializer->channelsOut; +} + +MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_i32(&pSpatializer->attenuationModel, attenuationModel); +} + +MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return ma_attenuation_model_none; + } + + return (ma_attenuation_model)c89atomic_load_i32(&pSpatializer->attenuationModel); +} + +MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_i32(&pSpatializer->positioning, positioning); +} + +MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return ma_positioning_absolute; + } + + return (ma_positioning)c89atomic_load_i32(&pSpatializer->positioning); +} + +MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->rolloff, rolloff); +} + +MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return c89atomic_load_f32(&pSpatializer->rolloff); +} + +MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->minGain, minGain); +} + +MA_API float ma_spatializer_get_min_gain(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return c89atomic_load_f32(&pSpatializer->minGain); +} + +MA_API void ma_spatializer_set_max_gain(ma_spatializer* pSpatializer, float maxGain) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->maxGain, maxGain); +} + +MA_API float ma_spatializer_get_max_gain(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return c89atomic_load_f32(&pSpatializer->maxGain); +} + +MA_API void ma_spatializer_set_min_distance(ma_spatializer* pSpatializer, float minDistance) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->minDistance, minDistance); +} + +MA_API float ma_spatializer_get_min_distance(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return c89atomic_load_f32(&pSpatializer->minDistance); +} + +MA_API void ma_spatializer_set_max_distance(ma_spatializer* pSpatializer, float maxDistance) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->maxDistance, maxDistance); +} + +MA_API float ma_spatializer_get_max_distance(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return c89atomic_load_f32(&pSpatializer->maxDistance); +} + +MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAngleInRadians, float outerAngleInRadians, float outerGain) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->coneInnerAngleInRadians, innerAngleInRadians); + c89atomic_exchange_f32(&pSpatializer->coneOuterAngleInRadians, outerAngleInRadians); + c89atomic_exchange_f32(&pSpatializer->coneOuterGain, outerGain); +} + +MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) +{ + if (pSpatializer == NULL) { + return; + } + + if (pInnerAngleInRadians != NULL) { + *pInnerAngleInRadians = c89atomic_load_f32(&pSpatializer->coneInnerAngleInRadians); + } + + if (pOuterAngleInRadians != NULL) { + *pOuterAngleInRadians = c89atomic_load_f32(&pSpatializer->coneOuterAngleInRadians); + } + + if (pOuterGain != NULL) { + *pOuterGain = c89atomic_load_f32(&pSpatializer->coneOuterGain); + } +} + +MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->dopplerFactor, dopplerFactor); +} + +MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 1; + } + + return c89atomic_load_f32(&pSpatializer->dopplerFactor); +} + +MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor) +{ + if (pSpatializer == NULL) { + return; + } + + c89atomic_exchange_f32(&pSpatializer->directionalAttenuationFactor, directionalAttenuationFactor); +} + +MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 1; + } + + return c89atomic_load_f32(&pSpatializer->directionalAttenuationFactor); +} + +MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z) +{ + if (pSpatializer == NULL) { + return; + } + + pSpatializer->position = ma_vec3f_init_3f(x, y, z); +} + +MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return pSpatializer->position; +} + +MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z) +{ + if (pSpatializer == NULL) { + return; + } + + pSpatializer->direction = ma_vec3f_init_3f(x, y, z); +} + +MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return ma_vec3f_init_3f(0, 0, -1); + } + + return pSpatializer->direction; +} + +MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z) +{ + if (pSpatializer == NULL) { + return; + } + + pSpatializer->velocity = ma_vec3f_init_3f(x, y, z); +} + +MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return pSpatializer->velocity; +} + +MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir) +{ + if (pRelativePos != NULL) { + pRelativePos->x = 0; + pRelativePos->y = 0; + pRelativePos->z = 0; + } + + if (pRelativeDir != NULL) { + pRelativeDir->x = 0; + pRelativeDir->y = 0; + pRelativeDir->z = -1; + } + + if (pSpatializer == NULL) { + return; + } + + if (pListener == NULL || ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { + /* There's no listener or we're using relative positioning. */ + if (pRelativePos != NULL) { + *pRelativePos = pSpatializer->position; + } + if (pRelativeDir != NULL) { + *pRelativeDir = pSpatializer->direction; + } + } else { + ma_vec3f v; + ma_vec3f axisX; + ma_vec3f axisY; + ma_vec3f axisZ; + float m[4][4]; + + /* + We need to calcualte the right vector from our forward and up vectors. This is done with + a cross product. + */ + axisZ = ma_vec3f_normalize(pListener->direction); /* Normalization required here because we can't trust the caller. */ + axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */ + + /* + The calculation of axisX above can result in a zero-length vector if the listener is + looking straight up on the Y axis. We'll need to fall back to a +X in this case so that + the calculations below don't fall apart. This is where a quaternion based listener and + sound orientation would come in handy. + */ + if (ma_vec3f_len2(axisX) == 0) { + axisX = ma_vec3f_init_3f(1, 0, 0); + } + + axisY = ma_vec3f_cross(axisX, axisZ); /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */ + + /* + We need to swap the X axis if we're left handed because otherwise the cross product above + will have resulted in it pointing in the wrong direction (right handed was assumed in the + cross products above). + */ + if (pListener->config.handedness == ma_handedness_left) { + axisX = ma_vec3f_neg(axisX); + } + + /* Lookat. */ + m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); + m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); + m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), pListener->position); + m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; + + /* + Multiply the lookat matrix by the spatializer position to transform it to listener + space. This allows calculations to work based on the sound being relative to the + origin which makes things simpler. + */ + if (pRelativePos != NULL) { + v = pSpatializer->position; + pRelativePos->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1; + pRelativePos->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1; + pRelativePos->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1; + } + + /* + The direction of the sound needs to also be transformed so that it's relative to the + rotation of the listener. + */ + if (pRelativeDir != NULL) { + v = pSpatializer->direction; + pRelativeDir->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z; + pRelativeDir->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z; + pRelativeDir->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z; + } + } +} + + + + /************************************************************************************************************************************************************** Resampling @@ -38994,6 +49032,16 @@ MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format form return config; } + +typedef struct +{ + size_t sizeInBytes; + size_t x0Offset; + size_t x1Offset; + size_t lpfOffset; +} ma_linear_resampler_heap_layout; + + static void ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler* pResampler, ma_uint32 oldSampleRateOut, ma_uint32 newSampleRateOut) { /* @@ -39012,7 +49060,7 @@ static void ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler* p pResampler->inTimeFrac = pResampler->inTimeFrac % pResampler->config.sampleRateOut; } -static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized) +static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, void* pHeap, ma_linear_resampler_heap_layout* pHeapLayout, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized) { ma_result result; ma_uint32 gcf; @@ -39056,7 +49104,7 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes if (isResamplerAlreadyInitialized) { result = ma_lpf_reinit(&lpfConfig, &pResampler->lpf); } else { - result = ma_lpf_init(&lpfConfig, &pResampler->lpf); + result = ma_lpf_init_preallocated(&lpfConfig, ma_offset_ptr(pHeap, pHeapLayout->lpfOffset), &pResampler->lpf); } if (result != MA_SUCCESS) { @@ -39073,9 +49121,88 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes return MA_SUCCESS; } -MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler) +static ma_result ma_linear_resampler_get_heap_layout(const ma_linear_resampler_config* pConfig, ma_linear_resampler_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* x0 */ + pHeapLayout->x0Offset = pHeapLayout->sizeInBytes; + if (pConfig->format == ma_format_f32) { + pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; + } else { + pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels; + } + + /* x1 */ + pHeapLayout->x1Offset = pHeapLayout->sizeInBytes; + if (pConfig->format == ma_format_f32) { + pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels; + } else { + pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels; + } + + /* LPF */ + pHeapLayout->lpfOffset = pHeapLayout->sizeInBytes; + { + ma_result result; + size_t lpfHeapSizeInBytes; + ma_lpf_config lpfConfig = ma_lpf_config_init(pConfig->format, pConfig->channels, 1, 1, pConfig->lpfOrder); /* Sample rate and cutoff frequency do not matter. */ + + result = ma_lpf_get_heap_size(&lpfConfig, &lpfHeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += lpfHeapSizeInBytes; + } + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_linear_resampler_get_heap_size(const ma_linear_resampler_config* pConfig, size_t* pHeapSizeInBytes) { ma_result result; + ma_linear_resampler_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_linear_resampler_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler_config* pConfig, void* pHeap, ma_linear_resampler* pResampler) +{ + ma_result result; + ma_linear_resampler_heap_layout heapLayout; if (pResampler == NULL) { return MA_INVALID_ARGS; @@ -39083,18 +49210,26 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon MA_ZERO_OBJECT(pResampler); - if (pConfig == NULL) { - return MA_INVALID_ARGS; - } - - if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; + result = ma_linear_resampler_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; } pResampler->config = *pConfig; + pResampler->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + if (pConfig->format == ma_format_f32) { + pResampler->x0.f32 = (float*)ma_offset_ptr(pHeap, heapLayout.x0Offset); + pResampler->x1.f32 = (float*)ma_offset_ptr(pHeap, heapLayout.x1Offset); + } else { + pResampler->x0.s16 = (ma_int16*)ma_offset_ptr(pHeap, heapLayout.x0Offset); + pResampler->x1.s16 = (ma_int16*)ma_offset_ptr(pHeap, heapLayout.x1Offset); + } + /* Setting the rate will set up the filter and time advances for us. */ - result = ma_linear_resampler_set_rate_internal(pResampler, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE); + result = ma_linear_resampler_set_rate_internal(pResampler, pHeap, &heapLayout, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE); if (result != MA_SUCCESS) { return result; } @@ -39105,11 +49240,47 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon return MA_SUCCESS; } -MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler) +MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_linear_resampler_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_linear_resampler_init_preallocated(pConfig, pHeap, pResampler); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pResampler->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks) { if (pResampler == NULL) { return; } + + ma_lpf_uninit(&pResampler->lpf, pAllocationCallbacks); + + if (pResampler->_ownsHeap) { + ma_free(pResampler->_pHeap, pAllocationCallbacks); + } } static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift) @@ -39139,7 +49310,7 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift); pFrameOut[c] = s; @@ -39158,7 +49329,7 @@ static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResa a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); for (c = 0; c < channels; c += 1) { float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a); pFrameOut[c] = s; @@ -39505,7 +49676,7 @@ MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pRe MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) { - return ma_linear_resampler_set_rate_internal(pResampler, sampleRateIn, sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_TRUE); + return ma_linear_resampler_set_rate_internal(pResampler, NULL, NULL, sampleRateIn, sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_TRUE); } MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut) @@ -39513,6 +49684,14 @@ MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResamp ma_uint32 n; ma_uint32 d; + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + if (ratioInOut <= 0) { + return MA_INVALID_ARGS; + } + d = 1000; n = (ma_uint32)(ratioInOut * d); @@ -39525,19 +49704,42 @@ MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResamp return ma_linear_resampler_set_rate(pResampler, n, d); } - -MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount) +MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler) { - ma_uint64 inputFrameCount; - if (pResampler == NULL) { return 0; } - if (outputFrameCount == 0) { + return 1 + ma_lpf_get_latency(&pResampler->lpf); +} + +MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler) +{ + if (pResampler == NULL) { return 0; } + return ma_linear_resampler_get_input_latency(pResampler) * pResampler->config.sampleRateOut / pResampler->config.sampleRateIn; +} + +MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) +{ + ma_uint64 inputFrameCount; + + if (pInputFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + *pInputFrameCount = 0; + + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + if (outputFrameCount == 0) { + return MA_SUCCESS; + } + /* Any whole input frames are consumed before the first output frame is generated. */ inputFrameCount = pResampler->inTimeInt; outputFrameCount -= 1; @@ -39546,17 +49748,25 @@ MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(const ma_lin inputFrameCount += outputFrameCount * pResampler->inAdvanceInt; inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut; - return inputFrameCount; + *pInputFrameCount = inputFrameCount; + + return MA_SUCCESS; } -MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount) +MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) { ma_uint64 outputFrameCount; ma_uint64 preliminaryInputFrameCountFromFrac; ma_uint64 preliminaryInputFrameCount; + if (pOutputFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + *pOutputFrameCount = 0; + if (pResampler == NULL) { - return 0; + return MA_INVALID_ARGS; } /* @@ -39583,45 +49793,157 @@ MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(const ma_li outputFrameCount += 1; } - return outputFrameCount; + *pOutputFrameCount = outputFrameCount; + + return MA_SUCCESS; } -MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler) +MA_API ma_result ma_linear_resampler_reset(ma_linear_resampler* pResampler) { + ma_uint32 iChannel; + if (pResampler == NULL) { - return 0; + return MA_INVALID_ARGS; } - return 1 + ma_lpf_get_latency(&pResampler->lpf); + /* Timers need to be cleared back to zero. */ + pResampler->inTimeInt = 1; /* Set this to one to force an input sample to always be loaded for the first output frame. */ + pResampler->inTimeFrac = 0; + + /* Cached samples need to be cleared. */ + if (pResampler->config.format == ma_format_f32) { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.f32[iChannel] = 0; + pResampler->x1.f32[iChannel] = 0; + } + } else { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.s16[iChannel] = 0; + pResampler->x1.s16[iChannel] = 0; + } + } + + /* The low pass filter needs to have it's cache reset. */ + ma_lpf_clear_cache(&pResampler->lpf); + + return MA_SUCCESS; } -MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler) + + +/* Linear resampler backend vtable. */ +static ma_linear_resampler_config ma_resampling_backend_get_config__linear(const ma_resampler_config* pConfig) { - if (pResampler == NULL) { - return 0; - } + ma_linear_resampler_config linearConfig; - return ma_linear_resampler_get_input_latency(pResampler) * pResampler->config.sampleRateOut / pResampler->config.sampleRateIn; + linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut); + linearConfig.lpfOrder = pConfig->linear.lpfOrder; + + return linearConfig; } - -#if defined(ma_speex_resampler_h) -#define MA_HAS_SPEEX_RESAMPLER - -static ma_result ma_result_from_speex_err(int err) +static ma_result ma_resampling_backend_get_heap_size__linear(void* pUserData, const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes) { - switch (err) - { - case RESAMPLER_ERR_SUCCESS: return MA_SUCCESS; - case RESAMPLER_ERR_ALLOC_FAILED: return MA_OUT_OF_MEMORY; - case RESAMPLER_ERR_BAD_STATE: return MA_ERROR; - case RESAMPLER_ERR_INVALID_ARG: return MA_INVALID_ARGS; - case RESAMPLER_ERR_PTR_OVERLAP: return MA_INVALID_ARGS; - case RESAMPLER_ERR_OVERFLOW: return MA_ERROR; - default: return MA_ERROR; - } + ma_linear_resampler_config linearConfig; + + (void)pUserData; + + linearConfig = ma_resampling_backend_get_config__linear(pConfig); + + return ma_linear_resampler_get_heap_size(&linearConfig, pHeapSizeInBytes); } -#endif /* ma_speex_resampler_h */ + +static ma_result ma_resampling_backend_init__linear(void* pUserData, const ma_resampler_config* pConfig, void* pHeap, ma_resampling_backend** ppBackend) +{ + ma_resampler* pResampler = (ma_resampler*)pUserData; + ma_result result; + ma_linear_resampler_config linearConfig; + + (void)pUserData; + + linearConfig = ma_resampling_backend_get_config__linear(pConfig); + + result = ma_linear_resampler_init_preallocated(&linearConfig, pHeap, &pResampler->state.linear); + if (result != MA_SUCCESS) { + return result; + } + + *ppBackend = &pResampler->state.linear; + + return MA_SUCCESS; +} + +static void ma_resampling_backend_uninit__linear(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) +{ + (void)pUserData; + + ma_linear_resampler_uninit((ma_linear_resampler*)pBackend, pAllocationCallbacks); +} + +static ma_result ma_resampling_backend_process__linear(void* pUserData, ma_resampling_backend* pBackend, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + (void)pUserData; + + return ma_linear_resampler_process_pcm_frames((ma_linear_resampler*)pBackend, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); +} + +static ma_result ma_resampling_backend_set_rate__linear(void* pUserData, ma_resampling_backend* pBackend, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) +{ + (void)pUserData; + + return ma_linear_resampler_set_rate((ma_linear_resampler*)pBackend, sampleRateIn, sampleRateOut); +} + +static ma_uint64 ma_resampling_backend_get_input_latency__linear(void* pUserData, const ma_resampling_backend* pBackend) +{ + (void)pUserData; + + return ma_linear_resampler_get_input_latency((const ma_linear_resampler*)pBackend); +} + +static ma_uint64 ma_resampling_backend_get_output_latency__linear(void* pUserData, const ma_resampling_backend* pBackend) +{ + (void)pUserData; + + return ma_linear_resampler_get_output_latency((const ma_linear_resampler*)pBackend); +} + +static ma_result ma_resampling_backend_get_required_input_frame_count__linear(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) +{ + (void)pUserData; + + return ma_linear_resampler_get_required_input_frame_count((const ma_linear_resampler*)pBackend, outputFrameCount, pInputFrameCount); +} + +static ma_result ma_resampling_backend_get_expected_output_frame_count__linear(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) +{ + (void)pUserData; + + return ma_linear_resampler_get_expected_output_frame_count((const ma_linear_resampler*)pBackend, inputFrameCount, pOutputFrameCount); +} + +static ma_result ma_resampling_backend_reset__linear(void* pUserData, ma_resampling_backend* pBackend) +{ + (void)pUserData; + + return ma_linear_resampler_reset((ma_linear_resampler*)pBackend); +} + +static ma_resampling_backend_vtable g_ma_linear_resampler_vtable = +{ + ma_resampling_backend_get_heap_size__linear, + ma_resampling_backend_init__linear, + ma_resampling_backend_uninit__linear, + ma_resampling_backend_process__linear, + ma_resampling_backend_set_rate__linear, + ma_resampling_backend_get_input_latency__linear, + ma_resampling_backend_get_output_latency__linear, + ma_resampling_backend_get_required_input_frame_count__linear, + ma_resampling_backend_get_expected_output_frame_count__linear, + ma_resampling_backend_reset__linear +}; + + MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm) { @@ -39636,15 +49958,74 @@ MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 /* Linear. */ config.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); - config.linear.lpfNyquistFactor = 1; - - /* Speex. */ - config.speex.quality = 3; /* Cannot leave this as 0 as that is actually a valid value for Speex resampling quality. */ return config; } -MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler) +static ma_result ma_resampler_get_vtable(const ma_resampler_config* pConfig, ma_resampler* pResampler, ma_resampling_backend_vtable** ppVTable, void** ppUserData) +{ + MA_ASSERT(pConfig != NULL); + MA_ASSERT(ppVTable != NULL); + MA_ASSERT(ppUserData != NULL); + + /* Safety. */ + *ppVTable = NULL; + *ppUserData = NULL; + + switch (pConfig->algorithm) + { + case ma_resample_algorithm_linear: + { + *ppVTable = &g_ma_linear_resampler_vtable; + *ppUserData = pResampler; + } break; + + case ma_resample_algorithm_custom: + { + *ppVTable = pConfig->pBackendVTable; + *ppUserData = pConfig->pBackendUserData; + } break; + + default: return MA_INVALID_ARGS; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_resampler_get_heap_size(const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_resampling_backend_vtable* pVTable; + void* pVTableUserData; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_resampler_get_vtable(pConfig, NULL, &pVTable, &pVTableUserData); + if (result != MA_SUCCESS) { + return result; + } + + if (pVTable == NULL || pVTable->onGetHeapSize == NULL) { + return MA_NOT_IMPLEMENTED; + } + + result = pVTable->onGetHeapSize(pVTableUserData, pConfig, pHeapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_resampler_init_preallocated(const ma_resampler_config* pConfig, void* pHeap, ma_resampler* pResampler) { ma_result result; @@ -39658,291 +50039,75 @@ MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resamp return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { - return MA_INVALID_ARGS; + pResampler->_pHeap = pHeap; + pResampler->format = pConfig->format; + pResampler->channels = pConfig->channels; + pResampler->sampleRateIn = pConfig->sampleRateIn; + pResampler->sampleRateOut = pConfig->sampleRateOut; + + result = ma_resampler_get_vtable(pConfig, pResampler, &pResampler->pBackendVTable, &pResampler->pBackendUserData); + if (result != MA_SUCCESS) { + return result; } - pResampler->config = *pConfig; + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onInit == NULL) { + return MA_NOT_IMPLEMENTED; /* onInit not implemented. */ + } - switch (pConfig->algorithm) - { - case ma_resample_algorithm_linear: - { - ma_linear_resampler_config linearConfig; - linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut); - linearConfig.lpfOrder = pConfig->linear.lpfOrder; - linearConfig.lpfNyquistFactor = pConfig->linear.lpfNyquistFactor; - - result = ma_linear_resampler_init(&linearConfig, &pResampler->state.linear); - if (result != MA_SUCCESS) { - return result; - } - } break; - - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - int speexErr; - pResampler->state.speex.pSpeexResamplerState = speex_resampler_init(pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->speex.quality, &speexErr); - if (pResampler->state.speex.pSpeexResamplerState == NULL) { - return ma_result_from_speex_err(speexErr); - } - #else - /* Speex resampler not available. */ - return MA_NO_BACKEND; - #endif - } break; - - default: return MA_INVALID_ARGS; + result = pResampler->pBackendVTable->onInit(pResampler->pBackendUserData, pConfig, pHeap, &pResampler->pBackend); + if (result != MA_SUCCESS) { + return result; } return MA_SUCCESS; } -MA_API void ma_resampler_uninit(ma_resampler* pResampler) +MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resampler* pResampler) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_resampler_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_resampler_init_preallocated(pConfig, pHeap, pResampler); + if (result != MA_SUCCESS) { + return result; + } + + pResampler->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks) { if (pResampler == NULL) { return; } - if (pResampler->config.algorithm == ma_resample_algorithm_linear) { - ma_linear_resampler_uninit(&pResampler->state.linear); + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onUninit == NULL) { + return; } -#if defined(MA_HAS_SPEEX_RESAMPLER) - if (pResampler->config.algorithm == ma_resample_algorithm_speex) { - speex_resampler_destroy((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState); + pResampler->pBackendVTable->onUninit(pResampler->pBackendUserData, pResampler->pBackend, pAllocationCallbacks); + + if (pResampler->_ownsHeap) { + ma_free(pResampler->_pHeap, pAllocationCallbacks); } -#endif } -static ma_result ma_resampler_process_pcm_frames__read__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) -{ - return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); -} - -#if defined(MA_HAS_SPEEX_RESAMPLER) -static ma_result ma_resampler_process_pcm_frames__read__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) -{ - int speexErr; - ma_uint64 frameCountOut; - ma_uint64 frameCountIn; - ma_uint64 framesProcessedOut; - ma_uint64 framesProcessedIn; - unsigned int framesPerIteration = UINT_MAX; - - MA_ASSERT(pResampler != NULL); - MA_ASSERT(pFramesOut != NULL); - MA_ASSERT(pFrameCountOut != NULL); - MA_ASSERT(pFrameCountIn != NULL); - - /* - Reading from the Speex resampler requires a bit of dancing around for a few reasons. The first thing is that it's frame counts - are in unsigned int's whereas ours is in ma_uint64. We therefore need to run the conversion in a loop. The other, more complicated - problem, is that we need to keep track of the input time, similar to what we do with the linear resampler. The reason we need to - do this is for ma_resampler_get_required_input_frame_count() and ma_resampler_get_expected_output_frame_count(). - */ - frameCountOut = *pFrameCountOut; - frameCountIn = *pFrameCountIn; - framesProcessedOut = 0; - framesProcessedIn = 0; - - while (framesProcessedOut < frameCountOut && framesProcessedIn < frameCountIn) { - unsigned int frameCountInThisIteration; - unsigned int frameCountOutThisIteration; - const void* pFramesInThisIteration; - void* pFramesOutThisIteration; - - frameCountInThisIteration = framesPerIteration; - if ((ma_uint64)frameCountInThisIteration > (frameCountIn - framesProcessedIn)) { - frameCountInThisIteration = (unsigned int)(frameCountIn - framesProcessedIn); - } - - frameCountOutThisIteration = framesPerIteration; - if ((ma_uint64)frameCountOutThisIteration > (frameCountOut - framesProcessedOut)) { - frameCountOutThisIteration = (unsigned int)(frameCountOut - framesProcessedOut); - } - - pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels)); - pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels)); - - if (pResampler->config.format == ma_format_f32) { - speexErr = speex_resampler_process_interleaved_float((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const float*)pFramesInThisIteration, &frameCountInThisIteration, (float*)pFramesOutThisIteration, &frameCountOutThisIteration); - } else if (pResampler->config.format == ma_format_s16) { - speexErr = speex_resampler_process_interleaved_int((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const spx_int16_t*)pFramesInThisIteration, &frameCountInThisIteration, (spx_int16_t*)pFramesOutThisIteration, &frameCountOutThisIteration); - } else { - /* Format not supported. Should never get here. */ - MA_ASSERT(MA_FALSE); - return MA_INVALID_OPERATION; - } - - if (speexErr != RESAMPLER_ERR_SUCCESS) { - return ma_result_from_speex_err(speexErr); - } - - framesProcessedIn += frameCountInThisIteration; - framesProcessedOut += frameCountOutThisIteration; - } - - *pFrameCountOut = framesProcessedOut; - *pFrameCountIn = framesProcessedIn; - - return MA_SUCCESS; -} -#endif - -static ma_result ma_resampler_process_pcm_frames__read(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) -{ - MA_ASSERT(pResampler != NULL); - MA_ASSERT(pFramesOut != NULL); - - /* pFramesOut is not NULL, which means we must have a capacity. */ - if (pFrameCountOut == NULL) { - return MA_INVALID_ARGS; - } - - /* It doesn't make sense to not have any input frames to process. */ - if (pFrameCountIn == NULL || pFramesIn == NULL) { - return MA_INVALID_ARGS; - } - - switch (pResampler->config.algorithm) - { - case ma_resample_algorithm_linear: - { - return ma_resampler_process_pcm_frames__read__linear(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } - - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - return ma_resampler_process_pcm_frames__read__speex(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - #else - break; - #endif - } - - default: break; - } - - /* Should never get here. */ - MA_ASSERT(MA_FALSE); - return MA_INVALID_ARGS; -} - - -static ma_result ma_resampler_process_pcm_frames__seek__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) -{ - MA_ASSERT(pResampler != NULL); - - /* Seeking is supported natively by the linear resampler. */ - return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, NULL, pFrameCountOut); -} - -#if defined(MA_HAS_SPEEX_RESAMPLER) -static ma_result ma_resampler_process_pcm_frames__seek__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) -{ - /* The generic seek method is implemented in on top of ma_resampler_process_pcm_frames__read() by just processing into a dummy buffer. */ - float devnull[4096]; - ma_uint64 totalOutputFramesToProcess; - ma_uint64 totalOutputFramesProcessed; - ma_uint64 totalInputFramesProcessed; - ma_uint32 bpf; - ma_result result; - - MA_ASSERT(pResampler != NULL); - - totalOutputFramesProcessed = 0; - totalInputFramesProcessed = 0; - bpf = ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels); - - if (pFrameCountOut != NULL) { - /* Seek by output frames. */ - totalOutputFramesToProcess = *pFrameCountOut; - } else { - /* Seek by input frames. */ - MA_ASSERT(pFrameCountIn != NULL); - totalOutputFramesToProcess = ma_resampler_get_expected_output_frame_count(pResampler, *pFrameCountIn); - } - - if (pFramesIn != NULL) { - /* Process input data. */ - MA_ASSERT(pFrameCountIn != NULL); - while (totalOutputFramesProcessed < totalOutputFramesToProcess && totalInputFramesProcessed < *pFrameCountIn) { - ma_uint64 inputFramesToProcessThisIteration = (*pFrameCountIn - totalInputFramesProcessed); - ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed); - if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) { - outputFramesToProcessThisIteration = sizeof(devnull) / bpf; - } - - result = ma_resampler_process_pcm_frames__read(pResampler, ma_offset_ptr(pFramesIn, totalInputFramesProcessed*bpf), &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration); - if (result != MA_SUCCESS) { - return result; - } - - totalOutputFramesProcessed += outputFramesToProcessThisIteration; - totalInputFramesProcessed += inputFramesToProcessThisIteration; - } - } else { - /* Don't process input data - just update timing and filter state as if zeroes were passed in. */ - while (totalOutputFramesProcessed < totalOutputFramesToProcess) { - ma_uint64 inputFramesToProcessThisIteration = 16384; - ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed); - if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) { - outputFramesToProcessThisIteration = sizeof(devnull) / bpf; - } - - result = ma_resampler_process_pcm_frames__read(pResampler, NULL, &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration); - if (result != MA_SUCCESS) { - return result; - } - - totalOutputFramesProcessed += outputFramesToProcessThisIteration; - totalInputFramesProcessed += inputFramesToProcessThisIteration; - } - } - - - if (pFrameCountIn != NULL) { - *pFrameCountIn = totalInputFramesProcessed; - } - if (pFrameCountOut != NULL) { - *pFrameCountOut = totalOutputFramesProcessed; - } - - return MA_SUCCESS; -} -#endif - -static ma_result ma_resampler_process_pcm_frames__seek(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) -{ - MA_ASSERT(pResampler != NULL); - - switch (pResampler->config.algorithm) - { - case ma_resample_algorithm_linear: - { - return ma_resampler_process_pcm_frames__seek__linear(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut); - } break; - - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - return ma_resampler_process_pcm_frames__seek__speex(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut); - #else - break; - #endif - }; - - default: break; - } - - /* Should never hit this. */ - MA_ASSERT(MA_FALSE); - return MA_INVALID_ARGS; -} - - MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) { if (pResampler == NULL) { @@ -39953,17 +50118,17 @@ MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const return MA_INVALID_ARGS; } - if (pFramesOut != NULL) { - /* Reading. */ - return ma_resampler_process_pcm_frames__read(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } else { - /* Seeking. */ - return ma_resampler_process_pcm_frames__seek(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut); + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onProcess == NULL) { + return MA_NOT_IMPLEMENTED; } + + return pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData, pResampler->pBackend, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); } MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) { + ma_result result; + if (pResampler == NULL) { return MA_INVALID_ARGS; } @@ -39972,137 +50137,44 @@ MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampl return MA_INVALID_ARGS; } - pResampler->config.sampleRateIn = sampleRateIn; - pResampler->config.sampleRateOut = sampleRateOut; - - switch (pResampler->config.algorithm) - { - case ma_resample_algorithm_linear: - { - return ma_linear_resampler_set_rate(&pResampler->state.linear, sampleRateIn, sampleRateOut); - } break; - - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - return ma_result_from_speex_err(speex_resampler_set_rate((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, sampleRateIn, sampleRateOut)); - #else - break; - #endif - }; - - default: break; + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onSetRate == NULL) { + return MA_NOT_IMPLEMENTED; } - /* Should never get here. */ - MA_ASSERT(MA_FALSE); - return MA_INVALID_OPERATION; + result = pResampler->pBackendVTable->onSetRate(pResampler->pBackendUserData, pResampler->pBackend, sampleRateIn, sampleRateOut); + if (result != MA_SUCCESS) { + return result; + } + + pResampler->sampleRateIn = sampleRateIn; + pResampler->sampleRateOut = sampleRateOut; + + return MA_SUCCESS; } MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio) { + ma_uint32 n; + ma_uint32 d; + if (pResampler == NULL) { return MA_INVALID_ARGS; } - if (pResampler->config.algorithm == ma_resample_algorithm_linear) { - return ma_linear_resampler_set_rate_ratio(&pResampler->state.linear, ratio); - } else { - /* Getting here means the backend does not have native support for setting the rate as a ratio so we just do it generically. */ - ma_uint32 n; - ma_uint32 d; - - d = 1000; - n = (ma_uint32)(ratio * d); - - if (n == 0) { - return MA_INVALID_ARGS; /* Ratio too small. */ - } - - MA_ASSERT(n != 0); - - return ma_resampler_set_rate(pResampler, n, d); - } -} - -MA_API ma_uint64 ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount) -{ - if (pResampler == NULL) { - return 0; + if (ratio <= 0) { + return MA_INVALID_ARGS; } - if (outputFrameCount == 0) { - return 0; + d = 1000; + n = (ma_uint32)(ratio * d); + + if (n == 0) { + return MA_INVALID_ARGS; /* Ratio too small. */ } - switch (pResampler->config.algorithm) - { - case ma_resample_algorithm_linear: - { - return ma_linear_resampler_get_required_input_frame_count(&pResampler->state.linear, outputFrameCount); - } + MA_ASSERT(n != 0); - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - spx_uint64_t count; - int speexErr = ma_speex_resampler_get_required_input_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, outputFrameCount, &count); - if (speexErr != RESAMPLER_ERR_SUCCESS) { - return 0; - } - - return (ma_uint64)count; - #else - break; - #endif - } - - default: break; - } - - /* Should never get here. */ - MA_ASSERT(MA_FALSE); - return 0; -} - -MA_API ma_uint64 ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount) -{ - if (pResampler == NULL) { - return 0; /* Invalid args. */ - } - - if (inputFrameCount == 0) { - return 0; - } - - switch (pResampler->config.algorithm) - { - case ma_resample_algorithm_linear: - { - return ma_linear_resampler_get_expected_output_frame_count(&pResampler->state.linear, inputFrameCount); - } - - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - spx_uint64_t count; - int speexErr = ma_speex_resampler_get_expected_output_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, inputFrameCount, &count); - if (speexErr != RESAMPLER_ERR_SUCCESS) { - return 0; - } - - return (ma_uint64)count; - #else - break; - #endif - } - - default: break; - } - - /* Should never get here. */ - MA_ASSERT(MA_FALSE); - return 0; + return ma_resampler_set_rate(pResampler, n, d); } MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler) @@ -40111,28 +50183,11 @@ MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler) return 0; } - switch (pResampler->config.algorithm) - { - case ma_resample_algorithm_linear: - { - return ma_linear_resampler_get_input_latency(&pResampler->state.linear); - } - - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - return (ma_uint64)ma_speex_resampler_get_input_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState); - #else - break; - #endif - } - - default: break; + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetInputLatency == NULL) { + return 0; } - /* Should never get here. */ - MA_ASSERT(MA_FALSE); - return 0; + return pResampler->pBackendVTable->onGetInputLatency(pResampler->pBackendUserData, pResampler->pBackend); } MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler) @@ -40141,28 +50196,62 @@ MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler) return 0; } - switch (pResampler->config.algorithm) - { - case ma_resample_algorithm_linear: - { - return ma_linear_resampler_get_output_latency(&pResampler->state.linear); - } - - case ma_resample_algorithm_speex: - { - #if defined(MA_HAS_SPEEX_RESAMPLER) - return (ma_uint64)ma_speex_resampler_get_output_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState); - #else - break; - #endif - } - - default: break; + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetOutputLatency == NULL) { + return 0; } - /* Should never get here. */ - MA_ASSERT(MA_FALSE); - return 0; + return pResampler->pBackendVTable->onGetOutputLatency(pResampler->pBackendUserData, pResampler->pBackend); +} + +MA_API ma_result ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) +{ + if (pInputFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + *pInputFrameCount = 0; + + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetRequiredInputFrameCount == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pResampler->pBackendVTable->onGetRequiredInputFrameCount(pResampler->pBackendUserData, pResampler->pBackend, outputFrameCount, pInputFrameCount); +} + +MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) +{ + if (pOutputFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + *pOutputFrameCount = 0; + + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetExpectedOutputFrameCount == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pResampler->pBackendVTable->onGetExpectedOutputFrameCount(pResampler->pBackendUserData, pResampler->pBackend, inputFrameCount, pOutputFrameCount); +} + +MA_API ma_result ma_resampler_reset(ma_resampler* pResampler) +{ + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onReset == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pResampler->pBackendVTable->onReset(pResampler->pBackendUserData, pResampler->pBackend); } /************************************************************************************************************************************************************** @@ -40283,17 +50372,13 @@ MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format fo { ma_channel_converter_config config; - /* Channel counts need to be clamped. */ - channelsIn = ma_min(channelsIn, ma_countof(config.channelMapIn)); - channelsOut = ma_min(channelsOut, ma_countof(config.channelMapOut)); - MA_ZERO_OBJECT(&config); - config.format = format; - config.channelsIn = channelsIn; - config.channelsOut = channelsOut; - ma_channel_map_copy_or_default(config.channelMapIn, pChannelMapIn, channelsIn); - ma_channel_map_copy_or_default(config.channelMapOut, pChannelMapOut, channelsOut); - config.mixingMode = mixingMode; + config.format = format; + config.channelsIn = channelsIn; + config.channelsOut = channelsOut; + config.pChannelMapIn = pChannelMapIn; + config.pChannelMapOut = pChannelMapOut; + config.mixingMode = mixingMode; return config; } @@ -40324,320 +50409,862 @@ static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition) return MA_FALSE; } -MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, ma_channel_converter* pConverter) + +static ma_bool32 ma_channel_map_is_passthrough(const ma_channel* pChannelMapIn, ma_uint32 channelsIn, const ma_channel* pChannelMapOut, ma_uint32 channelsOut) +{ + if (channelsOut == channelsIn) { + return ma_channel_map_is_equal(pChannelMapOut, pChannelMapIn, channelsOut); + } else { + return MA_FALSE; /* Channel counts differ, so cannot be a passthrough. */ + } +} + +static ma_channel_conversion_path ma_channel_map_get_conversion_path(const ma_channel* pChannelMapIn, ma_uint32 channelsIn, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, ma_channel_mix_mode mode) +{ + if (ma_channel_map_is_passthrough(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut)) { + return ma_channel_conversion_path_passthrough; + } + + if (channelsOut == 1 && (pChannelMapOut == NULL || pChannelMapOut[0] == MA_CHANNEL_MONO)) { + return ma_channel_conversion_path_mono_out; + } + + if (channelsIn == 1 && (pChannelMapIn == NULL || pChannelMapIn[0] == MA_CHANNEL_MONO)) { + return ma_channel_conversion_path_mono_in; + } + + if (mode == ma_channel_mix_mode_custom_weights) { + return ma_channel_conversion_path_weights; + } + + /* + We can use a simple shuffle if both channel maps have the same channel count and all channel + positions are present in both. + */ + if (channelsIn == channelsOut) { + ma_uint32 iChannelIn; + ma_bool32 areAllChannelPositionsPresent = MA_TRUE; + for (iChannelIn = 0; iChannelIn < channelsIn; ++iChannelIn) { + ma_bool32 isInputChannelPositionInOutput = MA_FALSE; + if (ma_channel_map_contains_channel_position(channelsOut, pChannelMapOut, ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn))) { + isInputChannelPositionInOutput = MA_TRUE; + break; + } + + if (!isInputChannelPositionInOutput) { + areAllChannelPositionsPresent = MA_FALSE; + break; + } + } + + if (areAllChannelPositionsPresent) { + return ma_channel_conversion_path_shuffle; + } + } + + /* Getting here means we'll need to use weights. */ + return ma_channel_conversion_path_weights; +} + + +static ma_result ma_channel_map_build_shuffle_table(const ma_channel* pChannelMapIn, ma_uint32 channelCountIn, const ma_channel* pChannelMapOut, ma_uint32 channelCountOut, ma_uint8* pShuffleTable) { ma_uint32 iChannelIn; ma_uint32 iChannelOut; + if (pShuffleTable == NULL || channelCountIn == 0 || channelCountOut == 0) { + return MA_INVALID_ARGS; + } + + /* + When building the shuffle table we just do a 1:1 mapping based on the first occurance of a channel. If the + input channel has more than one occurance of a channel position, the second one will be ignored. + */ + for (iChannelOut = 0; iChannelOut < channelCountOut; iChannelOut += 1) { + ma_channel channelOut; + + /* Default to MA_CHANNEL_INDEX_NULL so that if a mapping is not found it'll be set appropriately. */ + pShuffleTable[iChannelOut] = MA_CHANNEL_INDEX_NULL; + + channelOut = ma_channel_map_get_channel(pChannelMapOut, channelCountOut, iChannelOut); + for (iChannelIn = 0; iChannelIn < channelCountIn; iChannelIn += 1) { + ma_channel channelIn; + + channelIn = ma_channel_map_get_channel(pChannelMapIn, channelCountIn, iChannelIn); + if (channelOut == channelIn) { + pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn; + break; + } + + /* + Getting here means the channels don't exactly match, but we are going to support some + relaxed matching for practicality. If, for example, there are two stereo channel maps, + but one uses front left/right and the other uses side left/right, it makes logical + sense to just map these. The way we'll do it is we'll check if there is a logical + corresponding mapping, and if so, apply it, but we will *not* break from the loop, + thereby giving the loop a chance to find an exact match later which will take priority. + */ + switch (channelOut) + { + /* Left channels. */ + case MA_CHANNEL_FRONT_LEFT: + case MA_CHANNEL_SIDE_LEFT: + { + switch (channelIn) { + case MA_CHANNEL_FRONT_LEFT: + case MA_CHANNEL_SIDE_LEFT: + { + pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn; + } break; + } + } break; + + /* Right channels. */ + case MA_CHANNEL_FRONT_RIGHT: + case MA_CHANNEL_SIDE_RIGHT: + { + switch (channelIn) { + case MA_CHANNEL_FRONT_RIGHT: + case MA_CHANNEL_SIDE_RIGHT: + { + pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn; + } break; + } + } break; + + default: break; + } + } + } + + return MA_SUCCESS; +} + + +static void ma_channel_map_apply_shuffle_table_u8(ma_uint8* pFramesOut, ma_uint32 channelsOut, const ma_uint8* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) +{ + ma_uint64 iFrame; + ma_uint32 iChannelOut; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; + if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ + pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; + } else { + pFramesOut[iChannelOut] = 0; + } + } + + pFramesOut += channelsOut; + pFramesIn += channelsIn; + } +} + +static void ma_channel_map_apply_shuffle_table_s16(ma_int16* pFramesOut, ma_uint32 channelsOut, const ma_int16* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) +{ + ma_uint64 iFrame; + ma_uint32 iChannelOut; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; + if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ + pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; + } else { + pFramesOut[iChannelOut] = 0; + } + } + + pFramesOut += channelsOut; + pFramesIn += channelsIn; + } +} + +static void ma_channel_map_apply_shuffle_table_s24(ma_uint8* pFramesOut, ma_uint32 channelsOut, const ma_uint8* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) +{ + ma_uint64 iFrame; + ma_uint32 iChannelOut; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; + if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ + pFramesOut[iChannelOut*3 + 0] = pFramesIn[iChannelIn*3 + 0]; + pFramesOut[iChannelOut*3 + 1] = pFramesIn[iChannelIn*3 + 1]; + pFramesOut[iChannelOut*3 + 2] = pFramesIn[iChannelIn*3 + 2]; + } else { + pFramesOut[iChannelOut*3 + 0] = 0; + } pFramesOut[iChannelOut*3 + 1] = 0; + } pFramesOut[iChannelOut*3 + 2] = 0; + + pFramesOut += channelsOut*3; + pFramesIn += channelsIn*3; + } +} + +static void ma_channel_map_apply_shuffle_table_s32(ma_int32* pFramesOut, ma_uint32 channelsOut, const ma_int32* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) +{ + ma_uint64 iFrame; + ma_uint32 iChannelOut; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; + if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ + pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; + } else { + pFramesOut[iChannelOut] = 0; + } + } + + pFramesOut += channelsOut; + pFramesIn += channelsIn; + } +} + +static void ma_channel_map_apply_shuffle_table_f32(float* pFramesOut, ma_uint32 channelsOut, const float* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable) +{ + ma_uint64 iFrame; + ma_uint32 iChannelOut; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_uint8 iChannelIn = pShuffleTable[iChannelOut]; + if (iChannelIn < channelsIn) { /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */ + pFramesOut[iChannelOut] = pFramesIn[iChannelIn]; + } else { + pFramesOut[iChannelOut] = 0; + } + } + + pFramesOut += channelsOut; + pFramesIn += channelsIn; + } +} + +static ma_result ma_channel_map_apply_shuffle_table(void* pFramesOut, ma_uint32 channelsOut, const void* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable, ma_format format) +{ + if (pFramesOut == NULL || pFramesIn == NULL || channelsOut == 0 || pShuffleTable == NULL) { + return MA_INVALID_ARGS; + } + + switch (format) + { + case ma_format_u8: + { + ma_channel_map_apply_shuffle_table_u8((ma_uint8*)pFramesOut, channelsOut, (const ma_uint8*)pFramesIn, channelsIn, frameCount, pShuffleTable); + } break; + + case ma_format_s16: + { + ma_channel_map_apply_shuffle_table_s16((ma_int16*)pFramesOut, channelsOut, (const ma_int16*)pFramesIn, channelsIn, frameCount, pShuffleTable); + } break; + + case ma_format_s24: + { + ma_channel_map_apply_shuffle_table_s24((ma_uint8*)pFramesOut, channelsOut, (const ma_uint8*)pFramesIn, channelsIn, frameCount, pShuffleTable); + } break; + + case ma_format_s32: + { + ma_channel_map_apply_shuffle_table_s32((ma_int32*)pFramesOut, channelsOut, (const ma_int32*)pFramesIn, channelsIn, frameCount, pShuffleTable); + } break; + + case ma_format_f32: + { + ma_channel_map_apply_shuffle_table_f32((float*)pFramesOut, channelsOut, (const float*)pFramesIn, channelsIn, frameCount, pShuffleTable); + } break; + + default: return MA_INVALID_ARGS; /* Unknown format. */ + } + + return MA_SUCCESS; +} + +static ma_result ma_channel_map_apply_mono_out_f32(float* pFramesOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint32 iChannelIn; + ma_uint32 accumulationCount; + + if (pFramesOut == NULL || pFramesIn == NULL || channelsIn == 0) { + return MA_INVALID_ARGS; + } + + /* In this case the output stream needs to be the average of all channels, ignoring NONE. */ + + /* A quick pre-processing step to get the accumulation counter since we're ignoring NONE channels. */ + accumulationCount = 0; + for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { + if (ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn) != MA_CHANNEL_NONE) { + accumulationCount += 1; + } + } + + if (accumulationCount > 0) { /* <-- Prevent a division by zero. */ + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float accumulation = 0; + + for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { + ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn); + if (channelIn != MA_CHANNEL_NONE) { + accumulation += pFramesIn[iChannelIn]; + } + } + + pFramesOut[0] = accumulation / accumulationCount; + pFramesOut += 1; + pFramesIn += channelsIn; + } + } else { + ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, 1); + } + + return MA_SUCCESS; +} + +static ma_result ma_channel_map_apply_mono_in_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, ma_uint64 frameCount, ma_mono_expansion_mode monoExpansionMode) +{ + ma_uint64 iFrame; + ma_uint32 iChannelOut; + + if (pFramesOut == NULL || channelsOut == 0 || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + /* Note that the MA_CHANNEL_NONE channel must be ignored in all cases. */ + switch (monoExpansionMode) + { + case ma_mono_expansion_mode_average: + { + float weight; + ma_uint32 validChannelCount = 0; + + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelOut != MA_CHANNEL_NONE) { + validChannelCount += 1; + } + } + + weight = 1.0f / validChannelCount; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelOut != MA_CHANNEL_NONE) { + pFramesOut[iChannelOut] = pFramesIn[0] * weight; + } + } + + pFramesOut += channelsOut; + pFramesIn += 1; + } + } break; + + case ma_mono_expansion_mode_stereo_only: + { + if (channelsOut >= 2) { + ma_uint32 iChannelLeft = (ma_uint32)-1; + ma_uint32 iChannelRight = (ma_uint32)-1; + + /* + We first need to find our stereo channels. We prefer front-left and front-right, but + if they're not available, we'll also try side-left and side-right. If neither are + available we'll fall through to the default case below. + */ + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelOut == MA_CHANNEL_SIDE_LEFT) { + iChannelLeft = iChannelOut; + } + if (channelOut == MA_CHANNEL_SIDE_RIGHT) { + iChannelRight = iChannelOut; + } + } + + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelOut == MA_CHANNEL_FRONT_LEFT) { + iChannelLeft = iChannelOut; + } + if (channelOut == MA_CHANNEL_FRONT_RIGHT) { + iChannelRight = iChannelOut; + } + } + + + if (iChannelLeft != (ma_uint32)-1 && iChannelRight != (ma_uint32)-1) { + /* We found our stereo channels so we can duplicate the signal across those channels. */ + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelOut != MA_CHANNEL_NONE) { + if (iChannelOut == iChannelLeft || iChannelOut == iChannelRight) { + pFramesOut[iChannelOut] = pFramesIn[0]; + } else { + pFramesOut[iChannelOut] = 0.0f; + } + } + } + + pFramesOut += channelsOut; + pFramesIn += 1; + } + + break; /* Get out of the switch. */ + } else { + /* Fallthrough. Does not have left and right channels. */ + goto default_handler; + } + } else { + /* Fallthrough. Does not have stereo channels. */ + goto default_handler; + } + }; /* Fallthrough. See comments above. */ + + case ma_mono_expansion_mode_duplicate: + default: + { + default_handler: + { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelOut != MA_CHANNEL_NONE) { + pFramesOut[iChannelOut] = pFramesIn[0]; + } + } + + pFramesOut += channelsOut; + pFramesIn += 1; + } + } + } break; + } + + return MA_SUCCESS; +} + +static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount, ma_channel_mix_mode mode, ma_mono_expansion_mode monoExpansionMode) +{ + ma_channel_conversion_path conversionPath = ma_channel_map_get_conversion_path(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut, mode); + + /* Optimized Path: Passthrough */ + if (conversionPath == ma_channel_conversion_path_passthrough) { + ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, ma_format_f32, channelsOut); + return; + } + + /* Special Path: Mono Output. */ + if (conversionPath == ma_channel_conversion_path_mono_out) { + ma_channel_map_apply_mono_out_f32(pFramesOut, pFramesIn, pChannelMapIn, channelsIn, frameCount); + return; + } + + /* Special Path: Mono Input. */ + if (conversionPath == ma_channel_conversion_path_mono_in) { + ma_channel_map_apply_mono_in_f32(pFramesOut, pChannelMapOut, channelsOut, pFramesIn, frameCount, monoExpansionMode); + return; + } + + /* Getting here means we aren't running on an optimized conversion path. */ + if (channelsOut <= MA_MAX_CHANNELS) { + ma_result result; + + if (mode == ma_channel_mix_mode_simple) { + ma_channel shuffleTable[MA_MAX_CHANNELS]; + + result = ma_channel_map_build_shuffle_table(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut, shuffleTable); + if (result != MA_SUCCESS) { + return; + } + + result = ma_channel_map_apply_shuffle_table(pFramesOut, channelsOut, pFramesIn, channelsIn, frameCount, shuffleTable, ma_format_f32); + if (result != MA_SUCCESS) { + return; + } + } else { + ma_uint32 iFrame; + ma_uint32 iChannelOut; + ma_uint32 iChannelIn; + float weights[32][32]; /* Do not use MA_MAX_CHANNELS here! */ + + /* + If we have a small enough number of channels, pre-compute the weights. Otherwise we'll just need to + fall back to a slower path because otherwise we'll run out of stack space. + */ + if (channelsIn <= ma_countof(weights) && channelsOut <= ma_countof(weights)) { + /* Pre-compute weights. */ + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { + ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn); + weights[iChannelOut][iChannelIn] = ma_calculate_channel_position_rectangular_weight(channelOut, channelIn); + } + } + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + float accumulation = 0; + + for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { + accumulation += pFramesIn[iChannelIn] * weights[iChannelOut][iChannelIn]; + } + + pFramesOut[iChannelOut] = accumulation; + } + + pFramesOut += channelsOut; + pFramesIn += channelsIn; + } + } else { + /* Cannot pre-compute weights because not enough room in stack-allocated buffer. */ + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + float accumulation = 0; + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + + for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { + ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn); + accumulation += pFramesIn[iChannelIn] * ma_calculate_channel_position_rectangular_weight(channelOut, channelIn); + } + + pFramesOut[iChannelOut] = accumulation; + } + + pFramesOut += channelsOut; + pFramesIn += channelsIn; + } + } + } + } else { + /* Fall back to silence. If you hit this, what are you doing with so many channels?! */ + ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, channelsOut); + } +} + + +typedef struct +{ + size_t sizeInBytes; + size_t channelMapInOffset; + size_t channelMapOutOffset; + size_t shuffleTableOffset; + size_t weightsOffset; +} ma_channel_converter_heap_layout; + +static ma_channel_conversion_path ma_channel_converter_config_get_conversion_path(const ma_channel_converter_config* pConfig) +{ + return ma_channel_map_get_conversion_path(pConfig->pChannelMapIn, pConfig->channelsIn, pConfig->pChannelMapOut, pConfig->channelsOut, pConfig->mixingMode); +} + +static ma_result ma_channel_converter_get_heap_layout(const ma_channel_converter_config* pConfig, ma_channel_converter_heap_layout* pHeapLayout) +{ + ma_channel_conversion_path conversionPath; + + MA_ASSERT(pHeapLayout != NULL); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) { + return MA_INVALID_ARGS; + } + + if (!ma_channel_map_is_valid(pConfig->pChannelMapIn, pConfig->channelsIn)) { + return MA_INVALID_ARGS; + } + + if (!ma_channel_map_is_valid(pConfig->pChannelMapOut, pConfig->channelsOut)) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* Input channel map. Only need to allocate this if we have an input channel map (otherwise default channel map is assumed). */ + pHeapLayout->channelMapInOffset = pHeapLayout->sizeInBytes; + if (pConfig->pChannelMapIn != NULL) { + pHeapLayout->sizeInBytes += sizeof(ma_channel) * pConfig->channelsIn; + } + + /* Output channel map. Only need to allocate this if we have an output channel map (otherwise default channel map is assumed). */ + pHeapLayout->channelMapOutOffset = pHeapLayout->sizeInBytes; + if (pConfig->pChannelMapOut != NULL) { + pHeapLayout->sizeInBytes += sizeof(ma_channel) * pConfig->channelsOut; + } + + /* Alignment for the next section. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + /* Whether or not we use weights of a shuffle table depends on the channel map themselves and the algorithm we've chosen. */ + conversionPath = ma_channel_converter_config_get_conversion_path(pConfig); + + /* Shuffle table */ + pHeapLayout->shuffleTableOffset = pHeapLayout->sizeInBytes; + if (conversionPath == ma_channel_conversion_path_shuffle) { + pHeapLayout->sizeInBytes += sizeof(ma_uint8) * pConfig->channelsOut; + } + + /* Weights */ + pHeapLayout->weightsOffset = pHeapLayout->sizeInBytes; + if (conversionPath == ma_channel_conversion_path_weights) { + pHeapLayout->sizeInBytes += sizeof(float*) * pConfig->channelsIn; + pHeapLayout->sizeInBytes += sizeof(float ) * pConfig->channelsIn * pConfig->channelsOut; + } + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_channel_converter_get_heap_size(const ma_channel_converter_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_channel_converter_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_channel_converter_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_converter_config* pConfig, void* pHeap, ma_channel_converter* pConverter) +{ + ma_result result; + ma_channel_converter_heap_layout heapLayout; + if (pConverter == NULL) { return MA_INVALID_ARGS; } MA_ZERO_OBJECT(pConverter); - if (pConfig == NULL) { - return MA_INVALID_ARGS; + result = ma_channel_converter_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; } - /* Basic validation for channel counts. */ - if (pConfig->channelsIn < MA_MIN_CHANNELS || pConfig->channelsIn > MA_MAX_CHANNELS || - pConfig->channelsOut < MA_MIN_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; - } - - if (!ma_channel_map_valid(pConfig->channelsIn, pConfig->channelMapIn)) { - return MA_INVALID_ARGS; /* Invalid input channel map. */ - } - if (!ma_channel_map_valid(pConfig->channelsOut, pConfig->channelMapOut)) { - return MA_INVALID_ARGS; /* Invalid output channel map. */ - } + pConverter->_pHeap = pHeap; + MA_ZERO_MEMORY(pConverter->_pHeap, heapLayout.sizeInBytes); pConverter->format = pConfig->format; pConverter->channelsIn = pConfig->channelsIn; pConverter->channelsOut = pConfig->channelsOut; - ma_channel_map_copy_or_default(pConverter->channelMapIn, pConfig->channelMapIn, pConfig->channelsIn); - ma_channel_map_copy_or_default(pConverter->channelMapOut, pConfig->channelMapOut, pConfig->channelsOut); pConverter->mixingMode = pConfig->mixingMode; - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - if (pConverter->format == ma_format_f32) { - pConverter->weights.f32[iChannelIn][iChannelOut] = pConfig->weights[iChannelIn][iChannelOut]; - } else { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(pConfig->weights[iChannelIn][iChannelOut]); + if (pConfig->pChannelMapIn != NULL) { + pConverter->pChannelMapIn = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapInOffset); + ma_channel_map_copy_or_default(pConverter->pChannelMapIn, pConfig->channelsIn, pConfig->pChannelMapIn, pConfig->channelsIn); + } else { + pConverter->pChannelMapIn = NULL; /* Use default channel map. */ + } + + if (pConfig->pChannelMapOut != NULL) { + pConverter->pChannelMapOut = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapOutOffset); + ma_channel_map_copy_or_default(pConverter->pChannelMapOut, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelsOut); + } else { + pConverter->pChannelMapOut = NULL; /* Use default channel map. */ + } + + pConverter->conversionPath = ma_channel_converter_config_get_conversion_path(pConfig); + + if (pConverter->conversionPath == ma_channel_conversion_path_shuffle) { + pConverter->pShuffleTable = (ma_uint8*)ma_offset_ptr(pHeap, heapLayout.shuffleTableOffset); + ma_channel_map_build_shuffle_table(pConverter->pChannelMapIn, pConverter->channelsIn, pConverter->pChannelMapOut, pConverter->channelsOut, pConverter->pShuffleTable); + } + + if (pConverter->conversionPath == ma_channel_conversion_path_weights) { + ma_uint32 iChannelIn; + ma_uint32 iChannelOut; + + if (pConverter->format == ma_format_f32) { + pConverter->weights.f32 = (float** )ma_offset_ptr(pHeap, heapLayout.weightsOffset); + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { + pConverter->weights.f32[iChannelIn] = (float*)ma_offset_ptr(pHeap, heapLayout.weightsOffset + ((sizeof(float*) * pConverter->channelsIn) + (sizeof(float) * pConverter->channelsOut * iChannelIn))); + } + } else { + pConverter->weights.s16 = (ma_int32**)ma_offset_ptr(pHeap, heapLayout.weightsOffset); + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { + pConverter->weights.s16[iChannelIn] = (ma_int32*)ma_offset_ptr(pHeap, heapLayout.weightsOffset + ((sizeof(ma_int32*) * pConverter->channelsIn) + (sizeof(ma_int32) * pConverter->channelsOut * iChannelIn))); } } - } - - - /* If the input and output channels and channel maps are the same we should use a passthrough. */ - if (pConverter->channelsIn == pConverter->channelsOut) { - if (ma_channel_map_equal(pConverter->channelsIn, pConverter->channelMapIn, pConverter->channelMapOut)) { - pConverter->isPassthrough = MA_TRUE; - } - if (ma_channel_map_blank(pConverter->channelsIn, pConverter->channelMapIn) || ma_channel_map_blank(pConverter->channelsOut, pConverter->channelMapOut)) { - pConverter->isPassthrough = MA_TRUE; - } - } - - - /* - We can use a simple case for expanding the mono channel. This will used when expanding a mono input into any output so long - as no LFE is present in the output. - */ - if (!pConverter->isPassthrough) { - if (pConverter->channelsIn == 1 && pConverter->channelMapIn[0] == MA_CHANNEL_MONO) { - /* Optimal case if no LFE is in the output channel map. */ - pConverter->isSimpleMonoExpansion = MA_TRUE; - if (ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, MA_CHANNEL_LFE)) { - pConverter->isSimpleMonoExpansion = MA_FALSE; - } - } - } - - /* Another optimized case is stereo to mono. */ - if (!pConverter->isPassthrough) { - if (pConverter->channelsOut == 1 && pConverter->channelMapOut[0] == MA_CHANNEL_MONO && pConverter->channelsIn == 2) { - /* Optimal case if no LFE is in the input channel map. */ - pConverter->isStereoToMono = MA_TRUE; - if (ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, MA_CHANNEL_LFE)) { - pConverter->isStereoToMono = MA_FALSE; - } - } - } - - - /* - Here is where we do a bit of pre-processing to know how each channel should be combined to make up the output. Rules: - - 1) If it's a passthrough, do nothing - it's just a simple memcpy(). - 2) If the channel counts are the same and every channel position in the input map is present in the output map, use a - simple shuffle. An example might be different 5.1 channel layouts. - 3) Otherwise channels are blended based on spatial locality. - */ - if (!pConverter->isPassthrough) { - if (pConverter->channelsIn == pConverter->channelsOut) { - ma_bool32 areAllChannelPositionsPresent = MA_TRUE; - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_bool32 isInputChannelPositionInOutput = MA_FALSE; - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) { - isInputChannelPositionInOutput = MA_TRUE; - break; - } - } - - if (!isInputChannelPositionInOutput) { - areAllChannelPositionsPresent = MA_FALSE; - break; + /* Silence our weights by default. */ + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; iChannelOut += 1) { + if (pConverter->format == ma_format_f32) { + pConverter->weights.f32[iChannelIn][iChannelOut] = 0.0f; + } else { + pConverter->weights.s16[iChannelIn][iChannelOut] = 0; } } + } - if (areAllChannelPositionsPresent) { - pConverter->isSimpleShuffle = MA_TRUE; + /* + We now need to fill out our weights table. This is determined by the mixing mode. + */ + switch (pConverter->mixingMode) + { + case ma_channel_mix_mode_custom_weights: + { + if (pConfig->ppWeights == NULL) { + return MA_INVALID_ARGS; /* Config specified a custom weights mixing mode, but no custom weights have been specified. */ + } - /* - All the router will be doing is rearranging channels which means all we need to do is use a shuffling table which is just - a mapping between the index of the input channel to the index of the output channel. - */ - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) { - pConverter->shuffleTable[iChannelIn] = (ma_uint8)iChannelOut; - break; + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; iChannelOut += 1) { + float weight = pConfig->ppWeights[iChannelIn][iChannelOut]; + + if (pConverter->format == ma_format_f32) { + pConverter->weights.f32[iChannelIn][iChannelOut] = weight; + } else { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); } } } - } - } - } + } break; - - /* - Here is where weights are calculated. Note that we calculate the weights at all times, even when using a passthrough and simple - shuffling. We use different algorithms for calculating weights depending on our mixing mode. - - In simple mode we don't do any blending (except for converting between mono, which is done in a later step). Instead we just - map 1:1 matching channels. In this mode, if no channels in the input channel map correspond to anything in the output channel - map, nothing will be heard! - */ - - /* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */ - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; - - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; - - if (channelPosIn == channelPosOut) { - if (pConverter->format == ma_format_f32) { - pConverter->weights.f32[iChannelIn][iChannelOut] = 1; - } else { - pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT); - } - } - } - } - - /* - The mono channel is accumulated on all other channels, except LFE. Make sure in this loop we exclude output mono channels since - they were handled in the pass above. - */ - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; - - if (channelPosIn == MA_CHANNEL_MONO) { - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; - - if (channelPosOut != MA_CHANNEL_NONE && channelPosOut != MA_CHANNEL_MONO && channelPosOut != MA_CHANNEL_LFE) { + case ma_channel_mix_mode_simple: + { + /* In simple mode, excess channels need to be silenced or dropped. */ + ma_uint32 iChannel; + for (iChannel = 0; iChannel < ma_min(pConverter->channelsIn, pConverter->channelsOut); iChannel += 1) { if (pConverter->format == ma_format_f32) { - pConverter->weights.f32[iChannelIn][iChannelOut] = 1; + if (pConverter->weights.f32[iChannel][iChannel] == 0) { + pConverter->weights.f32[iChannel][iChannel] = 1; + } } else { - pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT); - } - } - } - } - } - - /* The output mono channel is the average of all non-none, non-mono and non-lfe input channels. */ - { - ma_uint32 len = 0; - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; - - if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) { - len += 1; - } - } - - if (len > 0) { - float monoWeight = 1.0f / len; - - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; - - if (channelPosOut == MA_CHANNEL_MONO) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; - - if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) { - if (pConverter->format == ma_format_f32) { - pConverter->weights.f32[iChannelIn][iChannelOut] = monoWeight; - } else { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(monoWeight); - } + if (pConverter->weights.s16[iChannel][iChannel] == 0) { + pConverter->weights.s16[iChannel][iChannel] = ma_channel_converter_float_to_fixed(1); } } } - } - } - } + } break; + case ma_channel_mix_mode_rectangular: + default: + { + /* Unmapped input channels. */ + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = pConverter->pChannelMapIn[iChannelIn]; - /* Input and output channels that are not present on the other side need to be blended in based on spatial locality. */ - switch (pConverter->mixingMode) - { - case ma_channel_mix_mode_rectangular: - { - /* Unmapped input channels. */ - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; + if (ma_is_spatial_channel_position(channelPosIn)) { + if (!ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->pChannelMapOut, channelPosIn)) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_channel channelPosOut = pConverter->pChannelMapOut[iChannelOut]; - if (ma_is_spatial_channel_position(channelPosIn)) { - if (!ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, channelPosIn)) { - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; - - if (ma_is_spatial_channel_position(channelPosOut)) { - float weight = 0; - if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { - weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); - } - - /* Only apply the weight if we haven't already got some contribution from the respective channels. */ - if (pConverter->format == ma_format_f32) { - if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { - pConverter->weights.f32[iChannelIn][iChannelOut] = weight; + if (ma_is_spatial_channel_position(channelPosOut)) { + float weight = 0; + if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { + weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); } - } else { - if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); + + /* Only apply the weight if we haven't already got some contribution from the respective channels. */ + if (pConverter->format == ma_format_f32) { + if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { + pConverter->weights.f32[iChannelIn][iChannelOut] = weight; + } + } else { + if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); + } } } } } } } - } - /* Unmapped output channels. */ - for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { - ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut]; + /* Unmapped output channels. */ + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_channel channelPosOut = pConverter->pChannelMapOut[iChannelOut]; - if (ma_is_spatial_channel_position(channelPosOut)) { - if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, channelPosOut)) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn]; + if (ma_is_spatial_channel_position(channelPosOut)) { + if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->pChannelMapIn, channelPosOut)) { + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = pConverter->pChannelMapIn[iChannelIn]; - if (ma_is_spatial_channel_position(channelPosIn)) { - float weight = 0; - if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { - weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); - } - - /* Only apply the weight if we haven't already got some contribution from the respective channels. */ - if (pConverter->format == ma_format_f32) { - if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { - pConverter->weights.f32[iChannelIn][iChannelOut] = weight; + if (ma_is_spatial_channel_position(channelPosIn)) { + float weight = 0; + if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) { + weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut); } - } else { - if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { - pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); + + /* Only apply the weight if we haven't already got some contribution from the respective channels. */ + if (pConverter->format == ma_format_f32) { + if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) { + pConverter->weights.f32[iChannelIn][iChannelOut] = weight; + } + } else { + if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); + } } } } } } } - } - } break; - - case ma_channel_mix_mode_simple: - { - /* In simple mode, excess channels need to be silenced or dropped. */ - ma_uint32 iChannel; - for (iChannel = 0; iChannel < ma_min(pConverter->channelsIn, pConverter->channelsOut); iChannel += 1) { - if (pConverter->format == ma_format_f32) { - if (pConverter->weights.f32[iChannel][iChannel] == 0) { - pConverter->weights.f32[iChannel][iChannel] = 1; - } - } else { - if (pConverter->weights.s16[iChannel][iChannel] == 0) { - pConverter->weights.s16[iChannel][iChannel] = ma_channel_converter_float_to_fixed(1); - } - } - } - } break; - - case ma_channel_mix_mode_custom_weights: - default: - { - /* Fallthrough. */ - } break; + } break; + } } - return MA_SUCCESS; } -MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter) +MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_channel_converter* pConverter) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_channel_converter_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_channel_converter_init_preallocated(pConfig, pHeap, pConverter); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pConverter->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks) { if (pConverter == NULL) { return; } + + if (pConverter->_ownsHeap) { + ma_free(pConverter->_pHeap, pAllocationCallbacks); + } } static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) @@ -40650,103 +51277,17 @@ static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel return MA_SUCCESS; } -static ma_result ma_channel_converter_process_pcm_frames__simple_shuffle(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +static ma_result ma_channel_converter_process_pcm_frames__shuffle(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) { - ma_uint32 iFrame; - ma_uint32 iChannelIn; - MA_ASSERT(pConverter != NULL); MA_ASSERT(pFramesOut != NULL); MA_ASSERT(pFramesIn != NULL); MA_ASSERT(pConverter->channelsIn == pConverter->channelsOut); - switch (pConverter->format) - { - case ma_format_u8: - { - /* */ ma_uint8* pFramesOutU8 = ( ma_uint8*)pFramesOut; - const ma_uint8* pFramesInU8 = (const ma_uint8*)pFramesIn; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - pFramesOutU8[pConverter->shuffleTable[iChannelIn]] = pFramesInU8[iChannelIn]; - } - - pFramesOutU8 += pConverter->channelsOut; - pFramesInU8 += pConverter->channelsIn; - } - } break; - - case ma_format_s16: - { - /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut; - const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - pFramesOutS16[pConverter->shuffleTable[iChannelIn]] = pFramesInS16[iChannelIn]; - } - - pFramesOutS16 += pConverter->channelsOut; - pFramesInS16 += pConverter->channelsIn; - } - } break; - - case ma_format_s24: - { - /* */ ma_uint8* pFramesOutS24 = ( ma_uint8*)pFramesOut; - const ma_uint8* pFramesInS24 = (const ma_uint8*)pFramesIn; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - ma_uint32 iChannelOut = pConverter->shuffleTable[iChannelIn]; - pFramesOutS24[iChannelOut*3 + 0] = pFramesInS24[iChannelIn*3 + 0]; - pFramesOutS24[iChannelOut*3 + 1] = pFramesInS24[iChannelIn*3 + 1]; - pFramesOutS24[iChannelOut*3 + 2] = pFramesInS24[iChannelIn*3 + 2]; - } - - pFramesOutS24 += pConverter->channelsOut*3; - pFramesInS24 += pConverter->channelsIn*3; - } - } break; - - case ma_format_s32: - { - /* */ ma_int32* pFramesOutS32 = ( ma_int32*)pFramesOut; - const ma_int32* pFramesInS32 = (const ma_int32*)pFramesIn; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - pFramesOutS32[pConverter->shuffleTable[iChannelIn]] = pFramesInS32[iChannelIn]; - } - - pFramesOutS32 += pConverter->channelsOut; - pFramesInS32 += pConverter->channelsIn; - } - } break; - - case ma_format_f32: - { - /* */ float* pFramesOutF32 = ( float*)pFramesOut; - const float* pFramesInF32 = (const float*)pFramesIn; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { - pFramesOutF32[pConverter->shuffleTable[iChannelIn]] = pFramesInF32[iChannelIn]; - } - - pFramesOutF32 += pConverter->channelsOut; - pFramesInF32 += pConverter->channelsIn; - } - } break; - - default: return MA_INVALID_OPERATION; /* Unknown format. */ - } - - return MA_SUCCESS; + return ma_channel_map_apply_shuffle_table(pFramesOut, pConverter->channelsOut, pFramesIn, pConverter->channelsIn, frameCount, pConverter->pShuffleTable, pConverter->format); } -static ma_result ma_channel_converter_process_pcm_frames__simple_mono_expansion(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +static ma_result ma_channel_converter_process_pcm_frames__mono_in(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) { ma_uint64 iFrame; @@ -40846,14 +51387,14 @@ static ma_result ma_channel_converter_process_pcm_frames__simple_mono_expansion( return MA_SUCCESS; } -static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) { ma_uint64 iFrame; + ma_uint32 iChannel; MA_ASSERT(pConverter != NULL); MA_ASSERT(pFramesOut != NULL); MA_ASSERT(pFramesIn != NULL); - MA_ASSERT(pConverter->channelsIn == 2); MA_ASSERT(pConverter->channelsOut == 1); switch (pConverter->format) @@ -40864,7 +51405,12 @@ static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_chan const ma_uint8* pFramesInU8 = (const ma_uint8*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - pFramesOutU8[iFrame] = ma_clip_u8((ma_int16)((ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*2+0]) + ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*2+1])) / 2)); + ma_int32 t = 0; + for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { + t += ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*pConverter->channelsIn + iChannel]); + } + + pFramesOutU8[iFrame] = ma_clip_u8(t / pConverter->channelsOut); } } break; @@ -40874,7 +51420,12 @@ static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_chan const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - pFramesOutS16[iFrame] = (ma_int16)(((ma_int32)pFramesInS16[iFrame*2+0] + (ma_int32)pFramesInS16[iFrame*2+1]) / 2); + ma_int32 t = 0; + for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { + t += pFramesInS16[iFrame*pConverter->channelsIn + iChannel]; + } + + pFramesOutS16[iFrame] = (ma_int16)(t / pConverter->channelsIn); } } break; @@ -40884,9 +51435,12 @@ static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_chan const ma_uint8* pFramesInS24 = (const ma_uint8*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - ma_int64 s24_0 = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*2+0)*3]); - ma_int64 s24_1 = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*2+1)*3]); - ma_pcm_sample_s32_to_s24_no_scale((s24_0 + s24_1) / 2, &pFramesOutS24[iFrame*3]); + ma_int64 t = 0; + for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { + t += ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*pConverter->channelsIn + iChannel)*3]); + } + + ma_pcm_sample_s32_to_s24_no_scale(t / pConverter->channelsIn, &pFramesOutS24[iFrame*3]); } } break; @@ -40896,7 +51450,12 @@ static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_chan const ma_int32* pFramesInS32 = (const ma_int32*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - pFramesOutS32[iFrame] = (ma_int16)(((ma_int32)pFramesInS32[iFrame*2+0] + (ma_int32)pFramesInS32[iFrame*2+1]) / 2); + ma_int64 t = 0; + for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { + t += pFramesInS32[iFrame*pConverter->channelsIn + iChannel]; + } + + pFramesOutS32[iFrame] = (ma_int32)(t / pConverter->channelsIn); } } break; @@ -40906,7 +51465,12 @@ static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_chan const float* pFramesInF32 = (const float*)pFramesIn; for (iFrame = 0; iFrame < frameCount; ++iFrame) { - pFramesOutF32[iFrame] = (pFramesInF32[iFrame*2+0] + pFramesInF32[iFrame*2+1]) * 0.5f; + float t = 0; + for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) { + t += pFramesInF32[iFrame*pConverter->channelsIn + iChannel]; + } + + pFramesOutF32[iFrame] = t / pConverter->channelsIn; } } break; @@ -41037,19 +51601,42 @@ MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* p return MA_SUCCESS; } - if (pConverter->isPassthrough) { - return ma_channel_converter_process_pcm_frames__passthrough(pConverter, pFramesOut, pFramesIn, frameCount); - } else if (pConverter->isSimpleShuffle) { - return ma_channel_converter_process_pcm_frames__simple_shuffle(pConverter, pFramesOut, pFramesIn, frameCount); - } else if (pConverter->isSimpleMonoExpansion) { - return ma_channel_converter_process_pcm_frames__simple_mono_expansion(pConverter, pFramesOut, pFramesIn, frameCount); - } else if (pConverter->isStereoToMono) { - return ma_channel_converter_process_pcm_frames__stereo_to_mono(pConverter, pFramesOut, pFramesIn, frameCount); - } else { - return ma_channel_converter_process_pcm_frames__weights(pConverter, pFramesOut, pFramesIn, frameCount); + switch (pConverter->conversionPath) + { + case ma_channel_conversion_path_passthrough: return ma_channel_converter_process_pcm_frames__passthrough(pConverter, pFramesOut, pFramesIn, frameCount); + case ma_channel_conversion_path_mono_out: return ma_channel_converter_process_pcm_frames__mono_out(pConverter, pFramesOut, pFramesIn, frameCount); + case ma_channel_conversion_path_mono_in: return ma_channel_converter_process_pcm_frames__mono_in(pConverter, pFramesOut, pFramesIn, frameCount); + case ma_channel_conversion_path_shuffle: return ma_channel_converter_process_pcm_frames__shuffle(pConverter, pFramesOut, pFramesIn, frameCount); + case ma_channel_conversion_path_weights: + default: + { + return ma_channel_converter_process_pcm_frames__weights(pConverter, pFramesOut, pFramesIn, frameCount); + } } } +MA_API ma_result ma_channel_converter_get_input_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) +{ + if (pConverter == NULL || pChannelMap == NULL) { + return MA_INVALID_ARGS; + } + + ma_channel_map_copy_or_default(pChannelMap, channelMapCap, pConverter->pChannelMapIn, pConverter->channelsIn); + + return MA_SUCCESS; +} + +MA_API ma_result ma_channel_converter_get_output_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) +{ + if (pConverter == NULL || pChannelMap == NULL) { + return MA_INVALID_ARGS; + } + + ma_channel_map_copy_or_default(pChannelMap, channelMapCap, pConverter->pChannelMapOut, pConverter->channelsOut); + + return MA_SUCCESS; +} + /************************************************************************************************************************************************************** @@ -41063,14 +51650,10 @@ MA_API ma_data_converter_config ma_data_converter_config_init_default() config.ditherMode = ma_dither_mode_none; config.resampling.algorithm = ma_resample_algorithm_linear; - config.resampling.allowDynamicSampleRate = MA_FALSE; /* Disable dynamic sample rates by default because dynamic rate adjustments should be quite rare and it allows an optimization for cases when the in and out sample rates are the same. */ + config.allowDynamicSampleRate = MA_FALSE; /* Disable dynamic sample rates by default because dynamic rate adjustments should be quite rare and it allows an optimization for cases when the in and out sample rates are the same. */ /* Linear resampling defaults. */ config.resampling.linear.lpfOrder = 1; - config.resampling.linear.lpfNyquistFactor = 1; - - /* Speex resampling defaults. */ - config.resampling.speex.quality = 3; return config; } @@ -41080,18 +51663,168 @@ MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn ma_data_converter_config config = ma_data_converter_config_init_default(); config.formatIn = formatIn; config.formatOut = formatOut; - config.channelsIn = ma_min(channelsIn, MA_MAX_CHANNELS); - config.channelsOut = ma_min(channelsOut, MA_MAX_CHANNELS); + config.channelsIn = channelsIn; + config.channelsOut = channelsOut; config.sampleRateIn = sampleRateIn; config.sampleRateOut = sampleRateOut; return config; } -MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, ma_data_converter* pConverter) + +typedef struct +{ + size_t sizeInBytes; + size_t channelConverterOffset; + size_t resamplerOffset; +} ma_data_converter_heap_layout; + +static ma_bool32 ma_data_converter_config_is_resampler_required(const ma_data_converter_config* pConfig) +{ + MA_ASSERT(pConfig != NULL); + + return pConfig->allowDynamicSampleRate || pConfig->sampleRateIn != pConfig->sampleRateOut; +} + +static ma_format ma_data_converter_config_get_mid_format(const ma_data_converter_config* pConfig) +{ + MA_ASSERT(pConfig != NULL); + + /* + We want to avoid as much data conversion as possible. The channel converter and linear + resampler both support s16 and f32 natively. We need to decide on the format to use for this + stage. We call this the mid format because it's used in the middle stage of the conversion + pipeline. If the output format is either s16 or f32 we use that one. If that is not the case it + will do the same thing for the input format. If it's neither we just use f32. If we are using a + custom resampling backend, we can only guarantee that f32 will be supported so we'll be forced + to use that if resampling is required. + */ + if (ma_data_converter_config_is_resampler_required(pConfig) && pConfig->resampling.algorithm != ma_resample_algorithm_linear) { + return ma_format_f32; /* <-- Force f32 since that is the only one we can guarantee will be supported by the resampler. */ + } else { + /* */ if (pConfig->formatOut == ma_format_s16 || pConfig->formatOut == ma_format_f32) { + return pConfig->formatOut; + } else if (pConfig->formatIn == ma_format_s16 || pConfig->formatIn == ma_format_f32) { + return pConfig->formatIn; + } else { + return ma_format_f32; + } + } +} + +static ma_channel_converter_config ma_channel_converter_config_init_from_data_converter_config(const ma_data_converter_config* pConfig) +{ + ma_channel_converter_config channelConverterConfig; + + MA_ASSERT(pConfig != NULL); + + channelConverterConfig = ma_channel_converter_config_init(ma_data_converter_config_get_mid_format(pConfig), pConfig->channelsIn, pConfig->pChannelMapIn, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelMixMode); + channelConverterConfig.ppWeights = pConfig->ppChannelWeights; + + return channelConverterConfig; +} + +static ma_resampler_config ma_resampler_config_init_from_data_converter_config(const ma_data_converter_config* pConfig) +{ + ma_resampler_config resamplerConfig; + ma_uint32 resamplerChannels; + + MA_ASSERT(pConfig != NULL); + + /* The resampler is the most expensive part of the conversion process, so we need to do it at the stage where the channel count is at it's lowest. */ + if (pConfig->channelsIn < pConfig->channelsOut) { + resamplerChannels = pConfig->channelsIn; + } else { + resamplerChannels = pConfig->channelsOut; + } + + resamplerConfig = ma_resampler_config_init(ma_data_converter_config_get_mid_format(pConfig), resamplerChannels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->resampling.algorithm); + resamplerConfig.linear = pConfig->resampling.linear; + resamplerConfig.pBackendVTable = pConfig->resampling.pBackendVTable; + resamplerConfig.pBackendUserData = pConfig->resampling.pBackendUserData; + + return resamplerConfig; +} + +static ma_result ma_data_converter_get_heap_layout(const ma_data_converter_config* pConfig, ma_data_converter_heap_layout* pHeapLayout) { ma_result result; + + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* Channel converter. */ + pHeapLayout->channelConverterOffset = pHeapLayout->sizeInBytes; + { + size_t heapSizeInBytes; + ma_channel_converter_config channelConverterConfig = ma_channel_converter_config_init_from_data_converter_config(pConfig); + + result = ma_channel_converter_get_heap_size(&channelConverterConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += heapSizeInBytes; + } + + /* Resampler. */ + pHeapLayout->resamplerOffset = pHeapLayout->sizeInBytes; + if (ma_data_converter_config_is_resampler_required(pConfig)) { + size_t heapSizeInBytes; + ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig); + + result = ma_resampler_get_heap_size(&resamplerConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes += heapSizeInBytes; + } + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_data_converter_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_data_converter_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter) +{ + ma_result result; + ma_data_converter_heap_layout heapLayout; ma_format midFormat; + ma_bool32 isResamplingRequired; if (pConverter == NULL) { return MA_INVALID_ARGS; @@ -41099,82 +51832,52 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, MA_ZERO_OBJECT(pConverter); - if (pConfig == NULL) { - return MA_INVALID_ARGS; + result = ma_data_converter_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; } - pConverter->config = *pConfig; + pConverter->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); - /* Basic validation. */ - if (pConfig->channelsIn < MA_MIN_CHANNELS || pConfig->channelsOut < MA_MIN_CHANNELS || - pConfig->channelsIn > MA_MAX_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; - } + pConverter->formatIn = pConfig->formatIn; + pConverter->formatOut = pConfig->formatOut; + pConverter->channelsIn = pConfig->channelsIn; + pConverter->channelsOut = pConfig->channelsOut; + pConverter->sampleRateIn = pConfig->sampleRateIn; + pConverter->sampleRateOut = pConfig->sampleRateOut; + pConverter->ditherMode = pConfig->ditherMode; /* - We want to avoid as much data conversion as possible. The channel converter and resampler both support s16 and f32 natively. We need to decide - on the format to use for this stage. We call this the mid format because it's used in the middle stage of the conversion pipeline. If the output - format is either s16 or f32 we use that one. If that is not the case it will do the same thing for the input format. If it's neither we just - use f32. + Determine if resampling is required. We need to do this so we can determine an appropriate + mid format to use. If resampling is required, the mid format must be ma_format_f32 since + that is the only one that is guaranteed to supported by custom resampling backends. */ - /* */ if (pConverter->config.formatOut == ma_format_s16 || pConverter->config.formatOut == ma_format_f32) { - midFormat = pConverter->config.formatOut; - } else if (pConverter->config.formatIn == ma_format_s16 || pConverter->config.formatIn == ma_format_f32) { - midFormat = pConverter->config.formatIn; - } else { - midFormat = ma_format_f32; - } + isResamplingRequired = ma_data_converter_config_is_resampler_required(pConfig); + midFormat = ma_data_converter_config_get_mid_format(pConfig); + /* Channel converter. We always initialize this, but we check if it configures itself as a passthrough to determine whether or not it's needed. */ { - ma_uint32 iChannelIn; - ma_uint32 iChannelOut; - ma_channel_converter_config channelConverterConfig; + ma_channel_converter_config channelConverterConfig = ma_channel_converter_config_init_from_data_converter_config(pConfig); - channelConverterConfig = ma_channel_converter_config_init(midFormat, pConverter->config.channelsIn, pConverter->config.channelMapIn, pConverter->config.channelsOut, pConverter->config.channelMapOut, pConverter->config.channelMixMode); - - /* Channel weights. */ - for (iChannelIn = 0; iChannelIn < pConverter->config.channelsIn; iChannelIn += 1) { - for (iChannelOut = 0; iChannelOut < pConverter->config.channelsOut; iChannelOut += 1) { - channelConverterConfig.weights[iChannelIn][iChannelOut] = pConverter->config.channelWeights[iChannelIn][iChannelOut]; - } - } - - result = ma_channel_converter_init(&channelConverterConfig, &pConverter->channelConverter); + result = ma_channel_converter_init_preallocated(&channelConverterConfig, ma_offset_ptr(pHeap, heapLayout.channelConverterOffset), &pConverter->channelConverter); if (result != MA_SUCCESS) { return result; } /* If the channel converter is not a passthrough we need to enable it. Otherwise we can skip it. */ - if (pConverter->channelConverter.isPassthrough == MA_FALSE) { + if (pConverter->channelConverter.conversionPath != ma_channel_conversion_path_passthrough) { pConverter->hasChannelConverter = MA_TRUE; } } - /* Always enable dynamic sample rates if the input sample rate is different because we're always going to need a resampler in this case anyway. */ - if (pConverter->config.resampling.allowDynamicSampleRate == MA_FALSE) { - pConverter->config.resampling.allowDynamicSampleRate = pConverter->config.sampleRateIn != pConverter->config.sampleRateOut; - } - /* Resampler. */ - if (pConverter->config.resampling.allowDynamicSampleRate) { - ma_resampler_config resamplerConfig; - ma_uint32 resamplerChannels; + if (isResamplingRequired) { + ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig); - /* The resampler is the most expensive part of the conversion process, so we need to do it at the stage where the channel count is at it's lowest. */ - if (pConverter->config.channelsIn < pConverter->config.channelsOut) { - resamplerChannels = pConverter->config.channelsIn; - } else { - resamplerChannels = pConverter->config.channelsOut; - } - - resamplerConfig = ma_resampler_config_init(midFormat, resamplerChannels, pConverter->config.sampleRateIn, pConverter->config.sampleRateOut, pConverter->config.resampling.algorithm); - resamplerConfig.linear.lpfOrder = pConverter->config.resampling.linear.lpfOrder; - resamplerConfig.linear.lpfNyquistFactor = pConverter->config.resampling.linear.lpfNyquistFactor; - resamplerConfig.speex.quality = pConverter->config.resampling.speex.quality; - - result = ma_resampler_init(&resamplerConfig, &pConverter->resampler); + result = ma_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pConverter->resampler); if (result != MA_SUCCESS) { return result; } @@ -41186,7 +51889,7 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, /* We can simplify pre- and post-format conversion if we have neither channel conversion nor resampling. */ if (pConverter->hasChannelConverter == MA_FALSE && pConverter->hasResampler == MA_FALSE) { /* We have neither channel conversion nor resampling so we'll only need one of pre- or post-format conversion, or none if the input and output formats are the same. */ - if (pConverter->config.formatIn == pConverter->config.formatOut) { + if (pConverter->formatIn == pConverter->formatOut) { /* The formats are the same so we can just pass through. */ pConverter->hasPreFormatConversion = MA_FALSE; pConverter->hasPostFormatConversion = MA_FALSE; @@ -41197,10 +51900,10 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, } } else { /* We have a channel converter and/or resampler so we'll need channel conversion based on the mid format. */ - if (pConverter->config.formatIn != midFormat) { - pConverter->hasPreFormatConversion = MA_TRUE; + if (pConverter->formatIn != midFormat) { + pConverter->hasPreFormatConversion = MA_TRUE; } - if (pConverter->config.formatOut != midFormat) { + if (pConverter->formatOut != midFormat) { pConverter->hasPostFormatConversion = MA_TRUE; } } @@ -41213,17 +51916,86 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, pConverter->isPassthrough = MA_TRUE; } + + /* We now need to determine our execution path. */ + if (pConverter->isPassthrough) { + pConverter->executionPath = ma_data_converter_execution_path_passthrough; + } else { + if (pConverter->channelsIn < pConverter->channelsOut) { + /* Do resampling first, if necessary. */ + MA_ASSERT(pConverter->hasChannelConverter == MA_TRUE); + + if (pConverter->hasResampler) { + pConverter->executionPath = ma_data_converter_execution_path_resample_first; + } else { + pConverter->executionPath = ma_data_converter_execution_path_channels_only; + } + } else { + /* Do channel conversion first, if necessary. */ + if (pConverter->hasChannelConverter) { + if (pConverter->hasResampler) { + pConverter->executionPath = ma_data_converter_execution_path_channels_first; + } else { + pConverter->executionPath = ma_data_converter_execution_path_channels_only; + } + } else { + /* Channel routing not required. */ + if (pConverter->hasResampler) { + pConverter->executionPath = ma_data_converter_execution_path_resample_only; + } else { + pConverter->executionPath = ma_data_converter_execution_path_format_only; + } + } + } + } + return MA_SUCCESS; } -MA_API void ma_data_converter_uninit(ma_data_converter* pConverter) +MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_data_converter_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_data_converter_init_preallocated(pConfig, pHeap, pConverter); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pConverter->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks) { if (pConverter == NULL) { return; } if (pConverter->hasResampler) { - ma_resampler_uninit(&pConverter->resampler); + ma_resampler_uninit(&pConverter->resampler, pAllocationCallbacks); + } + + ma_channel_converter_uninit(&pConverter->channelConverter, pAllocationCallbacks); + + if (pConverter->_ownsHeap) { + ma_free(pConverter->_pHeap, pAllocationCallbacks); } } @@ -41249,9 +52021,9 @@ static ma_result ma_data_converter_process_pcm_frames__passthrough(ma_data_conve if (pFramesOut != NULL) { if (pFramesIn != NULL) { - ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); + ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); } else { - ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); } } @@ -41287,9 +52059,9 @@ static ma_result ma_data_converter_process_pcm_frames__format_only(ma_data_conve if (pFramesOut != NULL) { if (pFramesIn != NULL) { - ma_convert_pcm_frames_format(pFramesOut, pConverter->config.formatOut, pFramesIn, pConverter->config.formatIn, frameCount, pConverter->config.channelsIn, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pFramesOut, pConverter->formatOut, pFramesIn, pConverter->formatIn, frameCount, pConverter->channelsIn, pConverter->ditherMode); } else { - ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); } } @@ -41329,20 +52101,20 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv while (framesProcessedOut < frameCountOut) { ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); + const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); const void* pFramesInThisIteration; /* */ void* pFramesOutThisIteration; ma_uint64 frameCountInThisIteration; ma_uint64 frameCountOutThisIteration; if (pFramesIn != NULL) { - pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); + pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); } else { pFramesInThisIteration = NULL; } if (pFramesOut != NULL) { - pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); + pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); } else { pFramesOutThisIteration = NULL; } @@ -41350,7 +52122,7 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv /* Do a pre format conversion if necessary. */ if (pConverter->hasPreFormatConversion) { ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); + const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); frameCountInThisIteration = (frameCountIn - framesProcessedIn); if (frameCountInThisIteration > tempBufferInCap) { @@ -41364,7 +52136,7 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv } if (pFramesInThisIteration != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.format, pFramesInThisIteration, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode); } else { MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn)); } @@ -41405,7 +52177,7 @@ static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conv /* If we are doing a post format conversion we need to do that now. */ if (pConverter->hasPostFormatConversion) { if (pFramesOutThisIteration != NULL) { - ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->resampler.config.channels, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->formatOut, pTempBufferOut, pConverter->resampler.format, frameCountOutThisIteration, pConverter->resampler.channels, pConverter->ditherMode); } } @@ -41482,13 +52254,13 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con ma_uint64 frameCountThisIteration; if (pFramesIn != NULL) { - pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); + pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); } else { pFramesInThisIteration = NULL; } if (pFramesOut != NULL) { - pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); + pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); } else { pFramesOutThisIteration = NULL; } @@ -41510,7 +52282,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con } if (pFramesInThisIteration != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->formatIn, frameCountThisIteration, pConverter->channelsIn, pConverter->ditherMode); } else { MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn)); } @@ -41544,7 +52316,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con /* If we are doing a post format conversion we need to do that now. */ if (pConverter->hasPostFormatConversion) { if (pFramesOutThisIteration != NULL) { - ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->channelConverter.format, frameCountThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->formatOut, pTempBufferOut, pConverter->channelConverter.format, frameCountThisIteration, pConverter->channelConverter.channelsOut, pConverter->ditherMode); } } @@ -41562,7 +52334,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_con return MA_SUCCESS; } -static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) { ma_result result; ma_uint64 frameCountIn; @@ -41577,9 +52349,9 @@ static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_ ma_uint64 tempBufferOutCap; MA_ASSERT(pConverter != NULL); - MA_ASSERT(pConverter->resampler.config.format == pConverter->channelConverter.format); - MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsIn); - MA_ASSERT(pConverter->resampler.config.channels < pConverter->channelConverter.channelsOut); + MA_ASSERT(pConverter->resampler.format == pConverter->channelConverter.format); + MA_ASSERT(pConverter->resampler.channels == pConverter->channelConverter.channelsIn); + MA_ASSERT(pConverter->resampler.channels < pConverter->channelConverter.channelsOut); frameCountIn = 0; if (pFrameCountIn != NULL) { @@ -41594,8 +52366,8 @@ static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_ framesProcessedIn = 0; framesProcessedOut = 0; - tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); - tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); + tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); + tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut); while (framesProcessedOut < frameCountOut) { @@ -41607,10 +52379,10 @@ static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_ void* pChannelsBufferOut; if (pFramesIn != NULL) { - pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); + pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); } if (pFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); + pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); } /* Run input data through the resampler and output it to the temporary buffer. */ @@ -41635,16 +52407,31 @@ static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_ } /* We need to ensure we don't try to process too many input frames that we run out of room in the output buffer. If this happens we'll end up glitching. */ + + /* + We need to try to predict how many input frames will be required for the resampler. If the + resampler can tell us, we'll use that. Otherwise we'll need to make a best guess. The further + off we are from this, the more wasted format conversions we'll end up doing. + */ + #if 1 { - ma_uint64 requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration); + ma_uint64 requiredInputFrameCount; + + result = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration, &requiredInputFrameCount); + if (result != MA_SUCCESS) { + /* Fall back to a best guess. */ + requiredInputFrameCount = (frameCountOutThisIteration * pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut; + } + if (frameCountInThisIteration > requiredInputFrameCount) { frameCountInThisIteration = requiredInputFrameCount; } } + #endif if (pConverter->hasPreFormatConversion) { if (pFramesIn != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.format, pRunningFramesIn, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode); pResampleBufferIn = pTempBufferIn; } else { pResampleBufferIn = NULL; @@ -41677,7 +52464,7 @@ static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_ /* Finally we do post format conversion. */ if (pConverter->hasPostFormatConversion) { - ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pChannelsBufferOut, pConverter->channelConverter.format, frameCountOutThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->formatOut, pChannelsBufferOut, pConverter->channelConverter.format, frameCountOutThisIteration, pConverter->channelConverter.channelsOut, pConverter->ditherMode); } } @@ -41718,9 +52505,9 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co ma_uint64 tempBufferOutCap; MA_ASSERT(pConverter != NULL); - MA_ASSERT(pConverter->resampler.config.format == pConverter->channelConverter.format); - MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsOut); - MA_ASSERT(pConverter->resampler.config.channels < pConverter->channelConverter.channelsIn); + MA_ASSERT(pConverter->resampler.format == pConverter->channelConverter.format); + MA_ASSERT(pConverter->resampler.channels == pConverter->channelConverter.channelsOut); + MA_ASSERT(pConverter->resampler.channels <= pConverter->channelConverter.channelsIn); frameCountIn = 0; if (pFrameCountIn != NULL) { @@ -41737,7 +52524,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn); tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut); - tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels); + tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels); while (framesProcessedOut < frameCountOut) { ma_uint64 frameCountInThisIteration; @@ -41748,22 +52535,67 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co void* pResampleBufferOut; if (pFramesIn != NULL) { - pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn)); + pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); } if (pFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut)); + pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); } - /* Run input data through the channel converter and output it to the temporary buffer. */ - frameCountInThisIteration = (frameCountIn - framesProcessedIn); + /* + Before doing any processing we need to determine how many frames we should try processing + this iteration, for both input and output. The resampler requires us to perform format and + channel conversion before passing any data into it. If we get our input count wrong, we'll + end up peforming redundant pre-processing. This isn't the end of the world, but it does + result in some inefficiencies proportionate to how far our estimates are off. + If the resampler has a means to calculate exactly how much we'll need, we'll use that. + Otherwise we'll make a best guess. In order to do this, we'll need to calculate the output + frame count first. + */ + frameCountOutThisIteration = (frameCountOut - framesProcessedOut); + if (frameCountOutThisIteration > tempBufferMidCap) { + frameCountOutThisIteration = tempBufferMidCap; + } + + if (pConverter->hasPostFormatConversion) { + if (frameCountOutThisIteration > tempBufferOutCap) { + frameCountOutThisIteration = tempBufferOutCap; + } + } + + /* Now that we have the output frame count we can determine the input frame count. */ + frameCountInThisIteration = (frameCountIn - framesProcessedIn); if (pConverter->hasPreFormatConversion) { if (frameCountInThisIteration > tempBufferInCap) { frameCountInThisIteration = tempBufferInCap; } + } + if (frameCountInThisIteration > tempBufferMidCap) { + frameCountInThisIteration = tempBufferMidCap; + } + + #if 1 + { + ma_uint64 requiredInputFrameCount; + + result = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration, &requiredInputFrameCount); + if (result != MA_SUCCESS) { + /* Fall back to a best guess. */ + requiredInputFrameCount = (frameCountOutThisIteration * pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut; + } + + if (frameCountInThisIteration > requiredInputFrameCount) { + frameCountInThisIteration = requiredInputFrameCount; + } + } + #endif + + + /* Pre format conversion. */ + if (pConverter->hasPreFormatConversion) { if (pRunningFramesIn != NULL) { - ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pRunningFramesIn, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode); pChannelsBufferIn = pTempBufferIn; } else { pChannelsBufferIn = NULL; @@ -41772,43 +52604,15 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co pChannelsBufferIn = pRunningFramesIn; } - /* - We can't convert more frames than will fit in the output buffer. We shouldn't actually need to do this check because the channel count is always reduced - in this case which means we should always have capacity, but I'm leaving it here just for safety for future maintenance. - */ - if (frameCountInThisIteration > tempBufferMidCap) { - frameCountInThisIteration = tempBufferMidCap; - } - - /* - Make sure we don't read any more input frames than we need to fill the output frame count. If we do this we will end up in a situation where we lose some - input samples and will end up glitching. - */ - frameCountOutThisIteration = (frameCountOut - framesProcessedOut); - if (frameCountOutThisIteration > tempBufferMidCap) { - frameCountOutThisIteration = tempBufferMidCap; - } - - if (pConverter->hasPostFormatConversion) { - ma_uint64 requiredInputFrameCount; - - if (frameCountOutThisIteration > tempBufferOutCap) { - frameCountOutThisIteration = tempBufferOutCap; - } - - requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration); - if (frameCountInThisIteration > requiredInputFrameCount) { - frameCountInThisIteration = requiredInputFrameCount; - } - } + /* Channel conversion. */ result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferMid, pChannelsBufferIn, frameCountInThisIteration); if (result != MA_SUCCESS) { return result; } - /* At this point we have converted the channels to the output channel count which we now need to resample. */ + /* Resampling. */ if (pConverter->hasPostFormatConversion) { pResampleBufferOut = pTempBufferOut; } else { @@ -41820,13 +52624,15 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co return result; } - /* Finally we can do the post format conversion. */ + + /* Post format conversion. */ if (pConverter->hasPostFormatConversion) { if (pRunningFramesOut != NULL) { - ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pResampleBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->config.channelsOut, pConverter->config.ditherMode); + ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->formatOut, pResampleBufferOut, pConverter->resampler.format, frameCountOutThisIteration, pConverter->channelsOut, pConverter->ditherMode); } } + framesProcessedIn += frameCountInThisIteration; framesProcessedOut += frameCountOutThisIteration; @@ -41854,46 +52660,15 @@ MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConver return MA_INVALID_ARGS; } - if (pConverter->isPassthrough) { - return ma_data_converter_process_pcm_frames__passthrough(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } - - /* - Here is where the real work is done. Getting here means we're not using a passthrough and we need to move the data through each of the relevant stages. The order - of our stages depends on the input and output channel count. If the input channels is less than the output channels we want to do sample rate conversion first so - that it has less work (resampling is the most expensive part of format conversion). - */ - if (pConverter->config.channelsIn < pConverter->config.channelsOut) { - /* Do resampling first, if necessary. */ - MA_ASSERT(pConverter->hasChannelConverter == MA_TRUE); - - if (pConverter->hasResampler) { - /* Resampling first. */ - return ma_data_converter_process_pcm_frames__resampling_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } else { - /* Resampling not required. */ - return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } - } else { - /* Do channel conversion first, if necessary. */ - if (pConverter->hasChannelConverter) { - if (pConverter->hasResampler) { - /* Channel routing first. */ - return ma_data_converter_process_pcm_frames__channels_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } else { - /* Resampling not required. */ - return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } - } else { - /* Channel routing not required. */ - if (pConverter->hasResampler) { - /* Resampling only. */ - return ma_data_converter_process_pcm_frames__resample_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } else { - /* No channel routing nor resampling required. Just format conversion. */ - return ma_data_converter_process_pcm_frames__format_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } - } + switch (pConverter->executionPath) + { + case ma_data_converter_execution_path_passthrough: return ma_data_converter_process_pcm_frames__passthrough(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + case ma_data_converter_execution_path_format_only: return ma_data_converter_process_pcm_frames__format_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + case ma_data_converter_execution_path_channels_only: return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + case ma_data_converter_execution_path_resample_only: return ma_data_converter_process_pcm_frames__resample_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + case ma_data_converter_execution_path_resample_first: return ma_data_converter_process_pcm_frames__resample_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + case ma_data_converter_execution_path_channels_first: return ma_data_converter_process_pcm_frames__channels_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + default: return MA_INVALID_OPERATION; /* Should never hit this. */ } } @@ -41923,32 +52698,6 @@ MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, return ma_resampler_set_rate_ratio(&pConverter->resampler, ratioInOut); } -MA_API ma_uint64 ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount) -{ - if (pConverter == NULL) { - return 0; - } - - if (pConverter->hasResampler) { - return ma_resampler_get_required_input_frame_count(&pConverter->resampler, outputFrameCount); - } else { - return outputFrameCount; /* 1:1 */ - } -} - -MA_API ma_uint64 ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount) -{ - if (pConverter == NULL) { - return 0; - } - - if (pConverter->hasResampler) { - return ma_resampler_get_expected_output_frame_count(&pConverter->resampler, inputFrameCount); - } else { - return inputFrameCount; /* 1:1 */ - } -} - MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter) { if (pConverter == NULL) { @@ -41975,6 +52724,90 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* p return 0; /* No latency without a resampler. */ } +MA_API ma_result ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount) +{ + if (pInputFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + *pInputFrameCount = 0; + + if (pConverter == NULL) { + return MA_INVALID_ARGS; + } + + if (pConverter->hasResampler) { + return ma_resampler_get_required_input_frame_count(&pConverter->resampler, outputFrameCount, pInputFrameCount); + } else { + *pInputFrameCount = outputFrameCount; /* 1:1 */ + return MA_SUCCESS; + } +} + +MA_API ma_result ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount) +{ + if (pOutputFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + *pOutputFrameCount = 0; + + if (pConverter == NULL) { + return MA_INVALID_ARGS; + } + + if (pConverter->hasResampler) { + return ma_resampler_get_expected_output_frame_count(&pConverter->resampler, inputFrameCount, pOutputFrameCount); + } else { + *pOutputFrameCount = inputFrameCount; /* 1:1 */ + return MA_SUCCESS; + } +} + +MA_API ma_result ma_data_converter_get_input_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) +{ + if (pConverter == NULL || pChannelMap == NULL) { + return MA_INVALID_ARGS; + } + + if (pConverter->hasChannelConverter) { + ma_channel_converter_get_output_channel_map(&pConverter->channelConverter, pChannelMap, channelMapCap); + } else { + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pConverter->channelsOut); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_data_converter_get_output_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap) +{ + if (pConverter == NULL || pChannelMap == NULL) { + return MA_INVALID_ARGS; + } + + if (pConverter->hasChannelConverter) { + ma_channel_converter_get_input_channel_map(&pConverter->channelConverter, pChannelMap, channelMapCap); + } else { + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pConverter->channelsIn); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_data_converter_reset(ma_data_converter* pConverter) +{ + if (pConverter == NULL) { + return MA_INVALID_ARGS; + } + + /* There's nothing to do if we're not resampling. */ + if (pConverter->hasResampler == MA_FALSE) { + return MA_SUCCESS; + } + + return ma_resampler_reset(&pConverter->resampler); +} + /************************************************************************************************************************************************************** @@ -41982,7 +52815,32 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* p Channel Maps **************************************************************************************************************************************************************/ -MA_API ma_channel ma_channel_map_get_default_channel(ma_uint32 channelCount, ma_uint32 channelIndex) +static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex); + +MA_API ma_channel ma_channel_map_get_channel(const ma_channel* pChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex) +{ + if (pChannelMap == NULL) { + return ma_channel_map_init_standard_channel(ma_standard_channel_map_default, channelCount, channelIndex); + } else { + if (channelIndex >= channelCount) { + return MA_CHANNEL_NONE; + } + + return pChannelMap[channelIndex]; + } +} + +MA_API void ma_channel_map_init_blank(ma_channel* pChannelMap, ma_uint32 channels) +{ + if (pChannelMap == NULL) { + return; + } + + MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channels); +} + + +static ma_channel ma_channel_map_init_standard_channel_microsoft(ma_uint32 channelCount, ma_uint32 channelIndex) { if (channelCount == 0 || channelIndex >= channelCount) { return MA_CHANNEL_NONE; @@ -41991,7 +52849,7 @@ MA_API ma_channel ma_channel_map_get_default_channel(ma_uint32 channelCount, ma_ /* This is the Microsoft channel map. Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */ switch (channelCount) { - case 0: return MA_CHANNEL_NONE; + case 0: return MA_CHANNEL_NONE; case 1: { @@ -42096,645 +52954,619 @@ MA_API ma_channel ma_channel_map_get_default_channel(ma_uint32 channelCount, ma_ return MA_CHANNEL_NONE; } -MA_API ma_channel ma_channel_map_get_channel(const ma_channel* pChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex) +static ma_channel ma_channel_map_init_standard_channel_alsa(ma_uint32 channelCount, ma_uint32 channelIndex) { - if (pChannelMap == NULL) { - return ma_channel_map_get_default_channel(channelCount, channelIndex); - } else { - if (channelIndex >= channelCount) { - return MA_CHANNEL_NONE; - } - - return pChannelMap[channelIndex]; - } -} - - -MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap) -{ - if (pChannelMap == NULL) { - return; - } - - MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channels); -} - -static void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel* pChannelMap) -{ - /* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */ - switch (channels) + switch (channelCount) { + case 0: return MA_CHANNEL_NONE; + case 1: { - pChannelMap[0] = MA_CHANNEL_MONO; + return MA_CHANNEL_MONO; } break; case 2: { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } } break; - case 3: /* Not defined, but best guess. */ + case 3: { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + } } break; case 4: { -#ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP - /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */ - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_BACK_CENTER; -#else - /* Quad. */ - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; -#endif + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 5: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + case 4: return MA_CHANNEL_FRONT_CENTER; + } + } break; + + case 6: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + case 4: return MA_CHANNEL_FRONT_CENTER; + case 5: return MA_CHANNEL_LFE; + } + } break; + + case 7: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + case 4: return MA_CHANNEL_FRONT_CENTER; + case 5: return MA_CHANNEL_LFE; + case 6: return MA_CHANNEL_BACK_CENTER; + } + } break; + + case 8: + default: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + case 4: return MA_CHANNEL_FRONT_CENTER; + case 5: return MA_CHANNEL_LFE; + case 6: return MA_CHANNEL_SIDE_LEFT; + case 7: return MA_CHANNEL_SIDE_RIGHT; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ + return MA_CHANNEL_NONE; +} + +static ma_channel ma_channel_map_init_standard_channel_rfc3551(ma_uint32 channelCount, ma_uint32 channelIndex) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 3: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + } + } break; + + case 4: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_BACK_CENTER; + } + } break; + + case 5: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 3: return MA_CHANNEL_BACK_LEFT; + case 4: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 6: + default: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_SIDE_LEFT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 3: return MA_CHANNEL_FRONT_RIGHT; + case 4: return MA_CHANNEL_SIDE_RIGHT; + case 5: return MA_CHANNEL_BACK_CENTER; + } + } break; + } + + if (channelCount > 6) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6)); + } + } + + /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ + return MA_CHANNEL_NONE; +} + +static ma_channel ma_channel_map_init_standard_channel_flac(ma_uint32 channelCount, ma_uint32 channelIndex) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 3: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + } + } break; + + case 4: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 5: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 3: return MA_CHANNEL_BACK_LEFT; + case 4: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 6: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 3: return MA_CHANNEL_LFE; + case 4: return MA_CHANNEL_BACK_LEFT; + case 5: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 7: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 3: return MA_CHANNEL_LFE; + case 4: return MA_CHANNEL_BACK_CENTER; + case 5: return MA_CHANNEL_SIDE_LEFT; + case 6: return MA_CHANNEL_SIDE_RIGHT; + } + } break; + + case 8: + default: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 3: return MA_CHANNEL_LFE; + case 4: return MA_CHANNEL_BACK_LEFT; + case 5: return MA_CHANNEL_BACK_RIGHT; + case 6: return MA_CHANNEL_SIDE_LEFT; + case 7: return MA_CHANNEL_SIDE_RIGHT; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ + return MA_CHANNEL_NONE; +} + +static ma_channel ma_channel_map_init_standard_channel_vorbis(ma_uint32 channelCount, ma_uint32 channelIndex) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 3: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 4: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 5: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_BACK_LEFT; + case 4: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 6: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_BACK_LEFT; + case 4: return MA_CHANNEL_BACK_RIGHT; + case 5: return MA_CHANNEL_LFE; + } + } break; + + case 7: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_SIDE_LEFT; + case 4: return MA_CHANNEL_SIDE_RIGHT; + case 5: return MA_CHANNEL_BACK_CENTER; + case 6: return MA_CHANNEL_LFE; + } + } break; + + case 8: + default: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_SIDE_LEFT; + case 4: return MA_CHANNEL_SIDE_RIGHT; + case 5: return MA_CHANNEL_BACK_LEFT; + case 6: return MA_CHANNEL_BACK_RIGHT; + case 7: return MA_CHANNEL_LFE; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ + return MA_CHANNEL_NONE; +} + +static ma_channel ma_channel_map_init_standard_channel_sound4(ma_uint32 channelCount, ma_uint32 channelIndex) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 3: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + } + } break; + + case 4: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 5: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + case 3: return MA_CHANNEL_BACK_LEFT; + case 4: return MA_CHANNEL_BACK_RIGHT; + } + } break; + + case 6: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_BACK_LEFT; + case 4: return MA_CHANNEL_BACK_RIGHT; + case 5: return MA_CHANNEL_LFE; + } + } break; + + case 7: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_SIDE_LEFT; + case 4: return MA_CHANNEL_SIDE_RIGHT; + case 5: return MA_CHANNEL_BACK_CENTER; + case 6: return MA_CHANNEL_LFE; + } + } break; + + case 8: + default: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_CENTER; + case 2: return MA_CHANNEL_FRONT_RIGHT; + case 3: return MA_CHANNEL_SIDE_LEFT; + case 4: return MA_CHANNEL_SIDE_RIGHT; + case 5: return MA_CHANNEL_BACK_LEFT; + case 6: return MA_CHANNEL_BACK_RIGHT; + case 7: return MA_CHANNEL_LFE; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ + return MA_CHANNEL_NONE; +} + +static ma_channel ma_channel_map_init_standard_channel_sndio(ma_uint32 channelCount, ma_uint32 channelIndex) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 3: /* No defined, but best guess. */ + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_FRONT_CENTER; + } + } break; + + case 4: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + } } break; case 5: /* Not defined, but best guess. */ { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_BACK_LEFT; - pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 6: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_LFE; - pChannelMap[4] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[5] = MA_CHANNEL_SIDE_RIGHT; - } break; - - case 7: /* Not defined, but best guess. */ - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_LFE; - pChannelMap[4] = MA_CHANNEL_BACK_CENTER; - pChannelMap[5] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT; - } break; - - case 8: - default: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_LFE; - pChannelMap[4] = MA_CHANNEL_BACK_LEFT; - pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; - } break; - } - - /* Remainder. */ - if (channels > 8) { - ma_uint32 iChannel; - for (iChannel = 8; iChannel < channels; ++iChannel) { - if (iChannel < MA_MAX_CHANNELS) { - pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); - } else { - pChannelMap[iChannel] = MA_CHANNEL_NONE; + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + case 4: return MA_CHANNEL_FRONT_CENTER; } - } - } -} - -static void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel* pChannelMap) -{ - switch (channels) - { - case 1: - { - pChannelMap[0] = MA_CHANNEL_MONO; - } break; - - case 2: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } break; - - case 3: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 4: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 5: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 6: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[5] = MA_CHANNEL_LFE; - } break; - - case 7: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[5] = MA_CHANNEL_LFE; - pChannelMap[6] = MA_CHANNEL_BACK_CENTER; - } break; - - case 8: - default: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[5] = MA_CHANNEL_LFE; - pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; - } break; - } - - /* Remainder. */ - if (channels > 8) { - ma_uint32 iChannel; - for (iChannel = 8; iChannel < channels; ++iChannel) { - if (iChannel < MA_MAX_CHANNELS) { - pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); - } else { - pChannelMap[iChannel] = MA_CHANNEL_NONE; - } - } - } -} - -static void ma_get_standard_channel_map_rfc3551(ma_uint32 channels, ma_channel* pChannelMap) -{ - switch (channels) - { - case 1: - { - pChannelMap[0] = MA_CHANNEL_MONO; - } break; - - case 2: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } break; - - case 3: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 4: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[3] = MA_CHANNEL_BACK_CENTER; - } break; - - case 5: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_BACK_LEFT; - pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 6: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; - pChannelMap[5] = MA_CHANNEL_BACK_CENTER; - } break; - } - - /* Remainder. */ - if (channels > 8) { - ma_uint32 iChannel; - for (iChannel = 6; iChannel < channels; ++iChannel) { - if (iChannel < MA_MAX_CHANNELS) { - pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); - } else { - pChannelMap[iChannel] = MA_CHANNEL_NONE; - } - } - } -} - -static void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel* pChannelMap) -{ - switch (channels) - { - case 1: - { - pChannelMap[0] = MA_CHANNEL_MONO; - } break; - - case 2: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } break; - - case 3: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 4: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 5: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_BACK_LEFT; - pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 6: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_LFE; - pChannelMap[4] = MA_CHANNEL_BACK_LEFT; - pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 7: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_LFE; - pChannelMap[4] = MA_CHANNEL_BACK_CENTER; - pChannelMap[5] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT; - } break; - - case 8: - default: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[3] = MA_CHANNEL_LFE; - pChannelMap[4] = MA_CHANNEL_BACK_LEFT; - pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; - } break; - } - - /* Remainder. */ - if (channels > 8) { - ma_uint32 iChannel; - for (iChannel = 8; iChannel < channels; ++iChannel) { - if (iChannel < MA_MAX_CHANNELS) { - pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); - } else { - pChannelMap[iChannel] = MA_CHANNEL_NONE; - } - } - } -} - -static void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel* pChannelMap) -{ - /* In Vorbis' type 0 channel mapping, the first two channels are not always the standard left/right - it will have the center speaker where the right usually goes. Why?! */ - switch (channels) - { - case 1: - { - pChannelMap[0] = MA_CHANNEL_MONO; - } break; - - case 2: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } break; - - case 3: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; - } break; - - case 4: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 5: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[3] = MA_CHANNEL_BACK_LEFT; - pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 6: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[3] = MA_CHANNEL_BACK_LEFT; - pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[5] = MA_CHANNEL_LFE; - } break; - - case 7: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[3] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; - pChannelMap[5] = MA_CHANNEL_BACK_CENTER; - pChannelMap[6] = MA_CHANNEL_LFE; - } break; - - case 8: - default: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[3] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; - pChannelMap[5] = MA_CHANNEL_BACK_LEFT; - pChannelMap[6] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[7] = MA_CHANNEL_LFE; - } break; - } - - /* Remainder. */ - if (channels > 8) { - ma_uint32 iChannel; - for (iChannel = 8; iChannel < channels; ++iChannel) { - if (iChannel < MA_MAX_CHANNELS) { - pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); - } else { - pChannelMap[iChannel] = MA_CHANNEL_NONE; - } - } - } -} - -static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel* pChannelMap) -{ - switch (channels) - { - case 1: - { - pChannelMap[0] = MA_CHANNEL_MONO; - } break; - - case 2: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } break; - - case 3: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_CENTER; - } break; - - case 4: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 5: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 6: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[5] = MA_CHANNEL_LFE; - } break; - - case 7: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[5] = MA_CHANNEL_BACK_CENTER; - pChannelMap[6] = MA_CHANNEL_LFE; - } break; - - case 8: - default: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[5] = MA_CHANNEL_LFE; - pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; - pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; - } break; - } - - /* Remainder. */ - if (channels > 8) { - ma_uint32 iChannel; - for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { - if (iChannel < MA_MAX_CHANNELS) { - pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); - } else { - pChannelMap[iChannel] = MA_CHANNEL_NONE; - } - } - } -} - -static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel* pChannelMap) -{ - switch (channels) - { - case 1: - { - pChannelMap[0] = MA_CHANNEL_MONO; - } break; - - case 2: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - } break; - - case 3: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 4: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 5: - { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: default: { - pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; - pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; - pChannelMap[2] = MA_CHANNEL_BACK_LEFT; - pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; - pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - pChannelMap[5] = MA_CHANNEL_LFE; + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + case 2: return MA_CHANNEL_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + case 4: return MA_CHANNEL_FRONT_CENTER; + case 5: return MA_CHANNEL_LFE; + } } break; } - /* Remainder. */ - if (channels > 6) { - ma_uint32 iChannel; - for (iChannel = 6; iChannel < channels && iChannel < MA_MAX_CHANNELS; ++iChannel) { - if (iChannel < MA_MAX_CHANNELS) { - pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); - } else { - pChannelMap[iChannel] = MA_CHANNEL_NONE; - } + if (channelCount > 6) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6)); } } + + /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */ + return MA_CHANNEL_NONE; } -MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap) + +static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex) { + if (channelCount == 0 || channelIndex >= channelCount) { + return MA_CHANNEL_NONE; + } + switch (standardChannelMap) { case ma_standard_channel_map_alsa: { - ma_get_standard_channel_map_alsa(channels, pChannelMap); + return ma_channel_map_init_standard_channel_alsa(channelCount, channelIndex); } break; case ma_standard_channel_map_rfc3551: { - ma_get_standard_channel_map_rfc3551(channels, pChannelMap); + return ma_channel_map_init_standard_channel_rfc3551(channelCount, channelIndex); } break; case ma_standard_channel_map_flac: { - ma_get_standard_channel_map_flac(channels, pChannelMap); + return ma_channel_map_init_standard_channel_flac(channelCount, channelIndex); } break; case ma_standard_channel_map_vorbis: { - ma_get_standard_channel_map_vorbis(channels, pChannelMap); + return ma_channel_map_init_standard_channel_vorbis(channelCount, channelIndex); } break; case ma_standard_channel_map_sound4: { - ma_get_standard_channel_map_sound4(channels, pChannelMap); + return ma_channel_map_init_standard_channel_sound4(channelCount, channelIndex); } break; case ma_standard_channel_map_sndio: { - ma_get_standard_channel_map_sndio(channels, pChannelMap); + return ma_channel_map_init_standard_channel_sndio(channelCount, channelIndex); } break; case ma_standard_channel_map_microsoft: /* Also default. */ /*case ma_standard_channel_map_default;*/ default: { - ma_get_standard_channel_map_microsoft(channels, pChannelMap); + return ma_channel_map_init_standard_channel_microsoft(channelCount, channelIndex); } break; } } +MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap, ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channels) +{ + ma_uint32 iChannel; + + if (pChannelMap == NULL || channelMapCap == 0 || channels == 0) { + return; + } + + for (iChannel = 0; iChannel < channels; iChannel += 1) { + if (channelMapCap == 0) { + break; /* Ran out of room. */ + } + + pChannelMap[0] = ma_channel_map_init_standard_channel(standardChannelMap, channels, iChannel); + pChannelMap += 1; + channelMapCap -= 1; + } +} + MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels) { if (pOut != NULL && pIn != NULL && channels > 0) { @@ -42742,7 +53574,7 @@ MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint } } -MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels) +MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCapOut, const ma_channel* pIn, ma_uint32 channels) { if (pOut == NULL || channels == 0) { return; @@ -42751,16 +53583,12 @@ MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, const ma_channel* p if (pIn != NULL) { ma_channel_map_copy(pOut, pIn, channels); } else { - ma_get_standard_channel_map(ma_standard_channel_map_default, channels, pOut); + ma_channel_map_init_standard(ma_standard_channel_map_default, pOut, channelMapCapOut, channels); } } -MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap) +MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint32 channels) { - if (pChannelMap == NULL) { - return MA_FALSE; - } - /* A channel count of 0 is invalid. */ if (channels == 0) { return MA_FALSE; @@ -42770,7 +53598,7 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pCha if (channels > 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { - if (pChannelMap[iChannel] == MA_CHANNEL_MONO) { + if (ma_channel_map_get_channel(pChannelMap, channels, iChannel) == MA_CHANNEL_MONO) { return MA_FALSE; } } @@ -42779,7 +53607,7 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pCha return MA_TRUE; } -MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB) +MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const ma_channel* pChannelMapB, ma_uint32 channels) { ma_uint32 iChannel; @@ -42796,7 +53624,7 @@ MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pCha return MA_TRUE; } -MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap) +MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint32 channels) { ma_uint32 iChannel; @@ -42839,8 +53667,6 @@ MA_API ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_forma ma_data_converter_config config; config = ma_data_converter_config_init(formatIn, formatOut, channelsIn, channelsOut, sampleRateIn, sampleRateOut); - ma_get_standard_channel_map(ma_standard_channel_map_default, channelsOut, config.channelMapOut); - ma_get_standard_channel_map(ma_standard_channel_map_default, channelsIn, config.channelMapIn); config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); return ma_convert_frames_ex(pOut, frameCountOut, pIn, frameCountIn, &config); @@ -42855,13 +53681,31 @@ MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const return 0; } - result = ma_data_converter_init(pConfig, &converter); + result = ma_data_converter_init(pConfig, NULL, &converter); if (result != MA_SUCCESS) { return 0; /* Failed to initialize the data converter. */ } if (pOut == NULL) { - frameCountOut = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn); + result = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn, &frameCountOut); + if (result != MA_SUCCESS) { + if (result == MA_NOT_IMPLEMENTED) { + /* No way to calculate the number of frames, so we'll need to brute force it and loop. */ + frameCountOut = 0; + + while (frameCountIn > 0) { + ma_uint64 framesProcessedIn = frameCountIn; + ma_uint64 framesProcessedOut = 0xFFFFFFFF; + + result = ma_data_converter_process_pcm_frames(&converter, pIn, &framesProcessedIn, NULL, &framesProcessedOut); + if (result != MA_SUCCESS) { + break; + } + + frameCountIn -= framesProcessedIn; + } + } + } } else { result = ma_data_converter_process_pcm_frames(&converter, pIn, &frameCountIn, pOut, &frameCountOut); if (result != MA_SUCCESS) { @@ -42869,7 +53713,7 @@ MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const } } - ma_data_converter_uninit(&converter); + ma_data_converter_uninit(&converter, NULL); return frameCountOut; } @@ -43038,7 +53882,7 @@ MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppB return MA_SUCCESS; } -MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut) +MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes) { ma_uint32 readOffset; ma_uint32 readOffsetInBytes; @@ -43050,11 +53894,6 @@ MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBuffer return MA_INVALID_ARGS; } - /* Validate the buffer. */ - if (pBufferOut != ma_rb__get_read_ptr(pRB)) { - return MA_INVALID_ARGS; - } - readOffset = c89atomic_load_32(&pRB->encodedReadOffset); ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); @@ -43129,7 +53968,7 @@ MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** pp return MA_SUCCESS; } -MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut) +MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes) { ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; @@ -43141,11 +53980,6 @@ MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBuffe return MA_INVALID_ARGS; } - /* Validate the buffer. */ - if (pBufferOut != ma_rb__get_write_ptr(pRB)) { - return MA_INVALID_ARGS; - } - writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset); ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); @@ -43429,13 +54263,13 @@ MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames return MA_SUCCESS; } -MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut) +MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames) { if (pRB == NULL) { return MA_INVALID_ARGS; } - return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut); + return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB)); } MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut) @@ -43458,13 +54292,13 @@ MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrame return MA_SUCCESS; } -MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut) +MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames) { if (pRB == NULL) { return MA_INVALID_ARGS; } - return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut); + return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB)); } MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames) @@ -43665,19 +54499,33 @@ MA_API const char* ma_result_description(ma_result result) MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { - return ma__malloc_from_callbacks(sz, pAllocationCallbacks); + if (pAllocationCallbacks->onMalloc != NULL) { + return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); + } else { + return NULL; /* Do not fall back to the default implementation. */ + } } else { return ma__malloc_default(sz, NULL); } } +MA_API void* ma_calloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +{ + void* p = ma_malloc(sz, pAllocationCallbacks); + if (p != NULL) { + MA_ZERO_MEMORY(p, sz); + } + + return p; +} + MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) { if (pAllocationCallbacks != NULL) { if (pAllocationCallbacks->onRealloc != NULL) { return pAllocationCallbacks->onRealloc(p, sz, pAllocationCallbacks->pUserData); } else { - return NULL; /* This requires a native implementation of realloc(). */ + return NULL; /* Do not fall back to the default implementation. */ } } else { return ma__realloc_default(p, sz, NULL); @@ -43686,8 +54534,16 @@ MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllo MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) { + if (p == NULL) { + return; + } + if (pAllocationCallbacks != NULL) { - ma__free_from_callbacks(p, pAllocationCallbacks); + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } else { + return; /* Do no fall back to the default implementation. */ + } } else { ma__free_default(p, NULL); } @@ -43792,11 +54648,6 @@ MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_da pDataSourceBase->pNext = NULL; pDataSourceBase->onGetNext = NULL; - /* Compatibility: Need to make a copy of the callbacks. This will be removed in version 0.11. */ - if (pConfig->vtable != NULL) { - pDataSourceBase->cb = *pConfig->vtable; - } - return MA_SUCCESS; } @@ -43812,7 +54663,6 @@ MA_API void ma_data_source_uninit(ma_data_source* pDataSource) */ } -#if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) static ma_result ma_data_source_resolve_current(ma_data_source* pDataSource, ma_data_source** ppCurrentDataSource) { ma_data_source_base* pCurrentDataSource = (ma_data_source_base*)pDataSource; @@ -43839,63 +54689,76 @@ static ma_result ma_data_source_resolve_current(ma_data_source* pDataSource, ma_ return MA_SUCCESS; } -static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop) +static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; - + ma_result result; + ma_uint64 framesRead = 0; + ma_bool32 loop = ma_data_source_is_looping(pDataSource); + if (pDataSourceBase == NULL) { return MA_AT_END; } - if (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE)) { - /* No range is set - just read like normal. The data source itself will tell us when the end is reached. */ - return pDataSourceBase->cb.onRead(pDataSourceBase, pFramesOut, frameCount, pFramesRead); + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + + if ((pDataSourceBase->vtable->flags & MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT) != 0 || (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE))) { + /* Either the data source is self-managing the range, or no range is set - just read like normal. The data source itself will tell us when the end is reached. */ + result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); } else { /* Need to clamp to within the range. */ - ma_result result; ma_uint64 cursor; - ma_uint64 framesRead = 0; - ma_uint64 rangeEnd; result = ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase, &cursor); if (result != MA_SUCCESS) { /* Failed to retrieve the cursor. Cannot read within a range or loop points. Just read like normal - this may happen for things like noise data sources where it doesn't really matter. */ - return pDataSourceBase->cb.onRead(pDataSourceBase, pFramesOut, frameCount, pFramesRead); - } + result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); + } else { + ma_uint64 rangeEnd; - /* We have the cursor. We need to make sure we don't read beyond our range. */ - rangeEnd = pDataSourceBase->rangeEndInFrames; + /* We have the cursor. We need to make sure we don't read beyond our range. */ + rangeEnd = pDataSourceBase->rangeEndInFrames; - /* If looping, make sure we're within range. */ - if (loop) { - if (pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) { - rangeEnd = ma_min(rangeEnd, pDataSourceBase->rangeBegInFrames + pDataSourceBase->loopEndInFrames); + /* If looping, make sure we're within range. */ + if (loop) { + if (pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) { + rangeEnd = ma_min(rangeEnd, pDataSourceBase->rangeBegInFrames + pDataSourceBase->loopEndInFrames); + } + } + + if (frameCount > (rangeEnd - cursor) && rangeEnd != ~((ma_uint64)0)) { + frameCount = (rangeEnd - cursor); + } + + /* + If the cursor is sitting on the end of the range the frame count will be set to 0 which can + result in MA_INVALID_ARGS. In this case, we don't want to try reading, but instead return + MA_AT_END so the higher level function can know about it. + */ + if (frameCount > 0) { + result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); + } else { + result = MA_AT_END; /* The cursor is sitting on the end of the range which means we're at the end. */ } } - - if (frameCount > (rangeEnd - cursor) && rangeEnd != ~((ma_uint64)0)) { - frameCount = (rangeEnd - cursor); - } - - result = pDataSourceBase->cb.onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); - - if (pFramesRead != NULL) { - *pFramesRead = framesRead; - } - - /* We need to make sure MA_AT_END is returned if we hit the end of the range. */ - if (result != MA_AT_END && framesRead == 0) { - result = MA_AT_END; - } - - return result; } -} -#endif -MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop) + if (pFramesRead != NULL) { + *pFramesRead = framesRead; + } + + /* We need to make sure MA_AT_END is returned if we hit the end of the range. */ + if (result == MA_SUCCESS && framesRead == 0) { + result = MA_AT_END; + } + + return result; +} + +MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { -#if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) ma_result result = MA_SUCCESS; ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; ma_data_source_base* pCurrentDataSource; @@ -43904,26 +54767,33 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi ma_format format; ma_uint32 channels; ma_uint32 emptyLoopCounter = 0; /* Keeps track of how many times 0 frames have been read. For infinite loop detection of sounds with no audio data. */ + ma_bool32 loop; if (pFramesRead != NULL) { *pFramesRead = 0; } + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pDataSourceBase == NULL) { return MA_INVALID_ARGS; } + loop = ma_data_source_is_looping(pDataSource); + /* We need to know the data format so we can advance the output buffer as we read frames. If this fails, chaining will not work and we'll just read as much as we can from the current source. */ - if (ma_data_source_get_data_format(pDataSource, &format, &channels, NULL) != MA_SUCCESS) { + if (ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0) != MA_SUCCESS) { result = ma_data_source_resolve_current(pDataSource, (ma_data_source**)&pCurrentDataSource); if (result != MA_SUCCESS) { return result; } - return ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pFramesOut, frameCount, pFramesRead, loop); + return ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pFramesOut, frameCount, pFramesRead); } /* @@ -43946,7 +54816,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi break; } - result = ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pRunningFramesOut, framesRemaining, &framesProcessed, loop); + result = ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pRunningFramesOut, framesRemaining, &framesProcessed); totalFramesProcessed += framesProcessed; /* @@ -43958,10 +54828,18 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi } /* - We can determine if we've reached the end by checking the return value of the onRead() - callback. To loop back to the start, all we need to do is seek back to the first frame. + We can determine if we've reached the end by checking if ma_data_source_read_pcm_frames_within_range() returned + MA_AT_END. To loop back to the start, all we need to do is seek back to the first frame. */ if (result == MA_AT_END) { + /* + The result needs to be reset back to MA_SUCCESS (from MA_AT_END) so that we don't + accidentally return MA_AT_END when data has been read in prior loop iterations. at the + end of this function, the result will be checked for MA_SUCCESS, and if the total + number of frames processed is 0, will be explicitly set to MA_AT_END. + */ + result = MA_SUCCESS; + /* We reached the end. If we're looping, we just loop back to the start of the current data source. If we're not looping we need to check if we have another in the chain, and @@ -43977,7 +54855,8 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi emptyLoopCounter = 0; } - if (ma_data_source_seek_to_pcm_frame(pCurrentDataSource, pCurrentDataSource->loopBegInFrames) != MA_SUCCESS) { + result = ma_data_source_seek_to_pcm_frame(pCurrentDataSource, pCurrentDataSource->loopBegInFrames); + if (result != MA_SUCCESS) { break; /* Failed to loop. Abort. */ } @@ -43997,14 +54876,10 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi } /* The next data source needs to be rewound to ensure data is read in looping scenarios. */ - ma_data_source_seek_to_pcm_frame(pDataSourceBase->pCurrent, 0); - - /* - We need to make sure we clear the MA_AT_END result so we don't accidentally return - it in the event that we coincidentally ended reading at the exact transition point - of two data sources in a chain. - */ - result = MA_SUCCESS; + result = ma_data_source_seek_to_pcm_frame(pDataSourceBase->pCurrent, 0); + if (result != MA_SUCCESS) { + break; + } } } @@ -44017,93 +54892,29 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi *pFramesRead = totalFramesProcessed; } + MA_ASSERT(!(result == MA_AT_END && totalFramesProcessed > 0)); /* We should never be returning MA_AT_END if we read some data. */ + + if (result == MA_SUCCESS && totalFramesProcessed == 0) { + result = MA_AT_END; + } + return result; -#else - ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; - - /* Safety. */ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (pCallbacks == NULL) { - return MA_INVALID_ARGS; - } - - if (pCallbacks->onRead == NULL) { - return MA_NOT_IMPLEMENTED; - } - - /* A very small optimization for the non looping case. */ - if (loop == MA_FALSE) { - return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead); - } else { - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - if (ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate) != MA_SUCCESS) { - return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead); /* We don't have a way to retrieve the data format which means we don't know how to offset the output buffer. Just read as much as we can. */ - } else { - ma_result result = MA_SUCCESS; - ma_uint64 totalFramesProcessed; - void* pRunningFramesOut = pFramesOut; - - totalFramesProcessed = 0; - while (totalFramesProcessed < frameCount) { - ma_uint64 framesProcessed; - ma_uint64 framesRemaining = frameCount - totalFramesProcessed; - - result = pCallbacks->onRead(pDataSource, pRunningFramesOut, framesRemaining, &framesProcessed); - totalFramesProcessed += framesProcessed; - - /* - If we encounted an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is - not necessarily considered an error. - */ - if (result != MA_SUCCESS && result != MA_AT_END) { - break; - } - - /* - We can determine if we've reached the end by checking the return value of the onRead() callback. If it's less than what we requested it means - we've reached the end. To loop back to the start, all we need to do is seek back to the first frame. - */ - if (framesProcessed < framesRemaining || result == MA_AT_END) { - if (ma_data_source_seek_to_pcm_frame(pDataSource, 0) != MA_SUCCESS) { - break; - } - } - - if (pRunningFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels)); - } - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesProcessed; - } - - return result; - } - } -#endif } -MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop) +MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked) { - return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked, loop); + return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked); } MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) { -#if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; if (pDataSourceBase == NULL) { return MA_SUCCESS; } - if (pDataSourceBase->cb.onSeek == NULL) { + if (pDataSourceBase->vtable->onSeek == NULL) { return MA_NOT_IMPLEMENTED; } @@ -44111,78 +54922,40 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m return MA_INVALID_OPERATION; /* Trying to seek to far forward. */ } - return pDataSourceBase->cb.onSeek(pDataSource, pDataSourceBase->rangeBegInFrames + frameIndex); -#else - ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; - if (pCallbacks == NULL) { - return MA_INVALID_ARGS; - } - - if (pCallbacks->onSeek == NULL) { - return MA_NOT_IMPLEMENTED; - } - - return pCallbacks->onSeek(pDataSource, frameIndex); -#endif + return pDataSourceBase->vtable->onSeek(pDataSource, pDataSourceBase->rangeBegInFrames + frameIndex); } -MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount) -{ - ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; - if (pCallbacks == NULL) { - return MA_INVALID_ARGS; - } - - if (pCallbacks->onMap == NULL) { - return MA_NOT_IMPLEMENTED; - } - - return pCallbacks->onMap(pDataSource, ppFramesOut, pFrameCount); -} - -MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount) -{ - ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; - if (pCallbacks == NULL) { - return MA_INVALID_ARGS; - } - - if (pCallbacks->onUnmap == NULL) { - return MA_NOT_IMPLEMENTED; - } - - return pCallbacks->onUnmap(pDataSource, frameCount); -} - -MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { + ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; ma_result result; ma_format format; ma_uint32 channels; ma_uint32 sampleRate; - ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; + /* Initialize to defaults for safety just in case the data source does not implement this callback. */ if (pFormat != NULL) { *pFormat = ma_format_unknown; } - if (pChannels != NULL) { *pChannels = 0; } - if (pSampleRate != NULL) { *pSampleRate = 0; } + if (pChannelMap != NULL) { + MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); + } - if (pCallbacks == NULL) { + if (pDataSourceBase == NULL) { return MA_INVALID_ARGS; } - if (pCallbacks->onGetDataFormat == NULL) { + if (pDataSourceBase->vtable->onGetDataFormat == NULL) { return MA_NOT_IMPLEMENTED; } - result = pCallbacks->onGetDataFormat(pDataSource, &format, &channels, &sampleRate); + result = pDataSourceBase->vtable->onGetDataFormat(pDataSource, &format, &channels, &sampleRate, pChannelMap, channelMapCap); if (result != MA_SUCCESS) { return result; } @@ -44197,12 +54970,13 @@ MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_ *pSampleRate = sampleRate; } + /* Channel map was passed in directly to the callback. This is safe due to the channelMapCap parameter. */ + return MA_SUCCESS; } MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor) { -#if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; ma_result result; ma_uint64 cursor; @@ -44217,11 +54991,11 @@ MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSo return MA_SUCCESS; } - if (pDataSourceBase->cb.onGetCursor == NULL) { + if (pDataSourceBase->vtable->onGetCursor == NULL) { return MA_NOT_IMPLEMENTED; } - result = pDataSourceBase->cb.onGetCursor(pDataSourceBase, &cursor); + result = pDataSourceBase->vtable->onGetCursor(pDataSourceBase, &cursor); if (result != MA_SUCCESS) { return result; } @@ -44232,32 +55006,12 @@ MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSo } else { *pCursor = cursor - pDataSourceBase->rangeBegInFrames; } - + return MA_SUCCESS; -#else - ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; - - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; - - if (pCallbacks == NULL) { - return MA_INVALID_ARGS; - } - - if (pCallbacks->onGetCursor == NULL) { - return MA_NOT_IMPLEMENTED; - } - - return pCallbacks->onGetCursor(pDataSource, pCursor); -#endif } MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength) { -#if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; if (pLength == NULL) { @@ -44284,13 +55038,45 @@ MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSo Getting here means a range is not defined so we'll need to get the data source itself to tell us the length. */ - if (pDataSourceBase->cb.onGetLength == NULL) { + if (pDataSourceBase->vtable->onGetLength == NULL) { return MA_NOT_IMPLEMENTED; } - return pDataSourceBase->cb.onGetLength(pDataSource, pLength); -#else - ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; + return pDataSourceBase->vtable->onGetLength(pDataSource, pLength); +} + +MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor) +{ + ma_result result; + ma_uint64 cursorInPCMFrames; + ma_uint32 sampleRate; + + if (pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; + + result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursorInPCMFrames); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; + } + + *pCursor = cursorInPCMFrames / (float)sampleRate; + + return MA_SUCCESS; +} + +MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength) +{ + ma_result result; + ma_uint64 lengthInPCMFrames; + ma_uint32 sampleRate; if (pLength == NULL) { return MA_INVALID_ARGS; @@ -44298,20 +55084,50 @@ MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSo *pLength = 0; - if (pCallbacks == NULL) { + result = ma_data_source_get_length_in_pcm_frames(pDataSource, &lengthInPCMFrames); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; + } + + *pLength = lengthInPCMFrames / (float)sampleRate; + + return MA_SUCCESS; +} + +MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) +{ + ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + + if (pDataSource == NULL) { return MA_INVALID_ARGS; } - if (pCallbacks->onGetLength == NULL) { - return MA_NOT_IMPLEMENTED; + c89atomic_exchange_32(&pDataSourceBase->isLooping, isLooping); + + /* If there's no callback for this just treat it as a successful no-op. */ + if (pDataSourceBase->vtable->onSetLooping == NULL) { + return MA_SUCCESS; } - return pCallbacks->onGetLength(pDataSource, pLength); -#endif + return pDataSourceBase->vtable->onSetLooping(pDataSource, isLooping); } +MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source* pDataSource) +{ + const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; + + if (pDataSource == NULL) { + return MA_FALSE; + } + + return c89atomic_load_32(&pDataSourceBase->isLooping); +} -#if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames) { ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; @@ -44356,12 +55172,12 @@ MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSou } else { pDataSourceBase->loopEndInFrames = 0; } - + if (pDataSourceBase->loopEndInFrames > pDataSourceBase->rangeEndInFrames && pDataSourceBase->loopEndInFrames) { pDataSourceBase->loopEndInFrames = pDataSourceBase->rangeEndInFrames; } } - + /* If the new range is past the current cursor position we need to seek to it. */ result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursor); @@ -44379,9 +55195,9 @@ MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSou return MA_SUCCESS; } -MA_API void ma_data_source_get_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames) +MA_API void ma_data_source_get_range_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; if (pDataSource == NULL) { return; @@ -44423,9 +55239,9 @@ MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDa return MA_SUCCESS; } -MA_API void ma_data_source_get_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames) +MA_API void ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; if (pDataSource == NULL) { return; @@ -44453,9 +55269,9 @@ MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data return MA_SUCCESS; } -MA_API ma_data_source* ma_data_source_get_current(ma_data_source* pDataSource) +MA_API ma_data_source* ma_data_source_get_current(const ma_data_source* pDataSource) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; if (pDataSource == NULL) { return NULL; @@ -44477,9 +55293,9 @@ MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_so return MA_SUCCESS; } -MA_API ma_data_source* ma_data_source_get_next(ma_data_source* pDataSource) +MA_API ma_data_source* ma_data_source_get_next(const ma_data_source* pDataSource) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; if (pDataSource == NULL) { return NULL; @@ -44501,9 +55317,9 @@ MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, m return MA_SUCCESS; } -MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(ma_data_source* pDataSource) +MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source* pDataSource) { - ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; if (pDataSource == NULL) { return NULL; @@ -44511,7 +55327,6 @@ MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(ma_data_sou return pDataSourceBase->onGetNext; } -#endif static ma_result ma_audio_buffer_ref__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) @@ -44535,23 +55350,14 @@ static ma_result ma_audio_buffer_ref__data_source_on_seek(ma_data_source* pDataS return ma_audio_buffer_ref_seek_to_pcm_frame((ma_audio_buffer_ref*)pDataSource, frameIndex); } -static ma_result ma_audio_buffer_ref__data_source_on_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount) -{ - return ma_audio_buffer_ref_map((ma_audio_buffer_ref*)pDataSource, ppFramesOut, pFrameCount); -} - -static ma_result ma_audio_buffer_ref__data_source_on_unmap(ma_data_source* pDataSource, ma_uint64 frameCount) -{ - return ma_audio_buffer_ref_unmap((ma_audio_buffer_ref*)pDataSource, frameCount); -} - -static ma_result ma_audio_buffer_ref__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_audio_buffer_ref__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource; *pFormat = pAudioBufferRef->format; *pChannels = pAudioBufferRef->channels; - *pSampleRate = 0; /* There is no notion of a sample rate with audio buffers. */ + *pSampleRate = pAudioBufferRef->sampleRate; + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pAudioBufferRef->channels); return MA_SUCCESS; } @@ -44578,11 +55384,11 @@ static ma_data_source_vtable g_ma_audio_buffer_ref_data_source_vtable = { ma_audio_buffer_ref__data_source_on_read, ma_audio_buffer_ref__data_source_on_seek, - ma_audio_buffer_ref__data_source_on_map, - ma_audio_buffer_ref__data_source_on_unmap, ma_audio_buffer_ref__data_source_on_get_data_format, ma_audio_buffer_ref__data_source_on_get_cursor, - ma_audio_buffer_ref__data_source_on_get_length + ma_audio_buffer_ref__data_source_on_get_length, + NULL, /* onSetLooping */ + 0 }; MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef) @@ -44606,6 +55412,7 @@ MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, pAudioBufferRef->format = format; pAudioBufferRef->channels = channels; + pAudioBufferRef->sampleRate = 0; /* TODO: Version 0.12. Set this to sampleRate. */ pAudioBufferRef->cursor = 0; pAudioBufferRef->sizeInFrames = sizeInFrames; pAudioBufferRef->pData = pData; @@ -44658,7 +55465,7 @@ MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudio } if (pFramesOut != NULL) { - ma_copy_pcm_frames(pFramesOut, ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)), framesToRead, pAudioBufferRef->format, pAudioBufferRef->channels); + ma_copy_pcm_frames(ma_offset_ptr(pFramesOut, totalFramesRead * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)), ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)), framesToRead, pAudioBufferRef->format, pAudioBufferRef->channels); } totalFramesRead += framesToRead; @@ -44816,10 +55623,11 @@ MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_u ma_audio_buffer_config config; MA_ZERO_OBJECT(&config); - config.format = format; - config.channels = channels; + config.format = format; + config.channels = channels; + config.sampleRate = 0; /* TODO: Version 0.12. Set this to sampleRate. */ config.sizeInFrames = sizeInFrames; - config.pData = pData; + config.pData = pData; ma_allocation_callbacks_init_copy(&config.allocationCallbacks, pAllocationCallbacks); return config; @@ -44848,6 +55656,9 @@ static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, return result; } + /* TODO: Version 0.12. Set this in ma_audio_buffer_ref_init() instead of here. */ + pAudioBuffer->ref.sampleRate = pConfig->sampleRate; + ma_allocation_callbacks_init_copy(&pAudioBuffer->allocationCallbacks, &pConfig->allocationCallbacks); if (doCopy) { @@ -44859,7 +55670,7 @@ static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, return MA_OUT_OF_MEMORY; /* Too big. */ } - pData = ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks); /* Safe cast to size_t. */ + pData = ma_malloc((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks); /* Safe cast to size_t. */ if (pData == NULL) { return MA_OUT_OF_MEMORY; } @@ -44887,11 +55698,11 @@ static void ma_audio_buffer_uninit_ex(ma_audio_buffer* pAudioBuffer, ma_bool32 d } if (pAudioBuffer->ownsData && pAudioBuffer->ref.pData != &pAudioBuffer->_pExtraData[0]) { - ma__free_from_callbacks((void*)pAudioBuffer->ref.pData, &pAudioBuffer->allocationCallbacks); /* Naugty const cast, but OK in this case since we've guarded it with the ownsData check. */ + ma_free((void*)pAudioBuffer->ref.pData, &pAudioBuffer->allocationCallbacks); /* Naugty const cast, but OK in this case since we've guarded it with the ownsData check. */ } if (doFree) { - ma__free_from_callbacks(pAudioBuffer, &pAudioBuffer->allocationCallbacks); + ma_free(pAudioBuffer, &pAudioBuffer->allocationCallbacks); } ma_audio_buffer_ref_uninit(&pAudioBuffer->ref); @@ -44932,7 +55743,7 @@ MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pC return MA_OUT_OF_MEMORY; /* Too big. */ } - pAudioBuffer = (ma_audio_buffer*)ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks); /* Safe cast to size_t. */ + pAudioBuffer = (ma_audio_buffer*)ma_malloc((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks); /* Safe cast to size_t. */ if (pAudioBuffer == NULL) { return MA_OUT_OF_MEMORY; } @@ -44947,7 +55758,7 @@ MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pC result = ma_audio_buffer_init_ex(&innerConfig, MA_FALSE, pAudioBuffer); if (result != MA_SUCCESS) { - ma__free_from_callbacks(pAudioBuffer, &innerConfig.allocationCallbacks); + ma_free(pAudioBuffer, &innerConfig.allocationCallbacks); return result; } @@ -45054,6 +55865,392 @@ MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAu + + +MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData) +{ + if (pData == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pData); + + pData->format = format; + pData->channels = channels; + pData->pTail = &pData->head; + + return MA_SUCCESS; +} + +MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_paged_audio_buffer_page* pPage; + + if (pData == NULL) { + return; + } + + /* All pages need to be freed. */ + pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->head.pNext); + while (pPage != NULL) { + ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext); + + ma_free(pPage, pAllocationCallbacks); + pPage = pNext; + } +} + +MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData) +{ + if (pData == NULL) { + return NULL; + } + + return &pData->head; +} + +MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData) +{ + if (pData == NULL) { + return NULL; + } + + return pData->pTail; +} + +MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength) +{ + ma_paged_audio_buffer_page* pPage; + + if (pLength == NULL) { + return MA_INVALID_ARGS; + } + + *pLength = 0; + + if (pData == NULL) { + return MA_INVALID_ARGS; + } + + /* Calculate the length from the linked list. */ + for (pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->head.pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext)) { + *pLength += pPage->sizeInFrames; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage) +{ + ma_paged_audio_buffer_page* pPage; + ma_uint64 allocationSize; + + if (ppPage == NULL) { + return MA_INVALID_ARGS; + } + + *ppPage = NULL; + + if (pData == NULL) { + return MA_INVALID_ARGS; + } + + allocationSize = sizeof(*pPage) + (pageSizeInFrames * ma_get_bytes_per_frame(pData->format, pData->channels)); + if (allocationSize > MA_SIZE_MAX) { + return MA_OUT_OF_MEMORY; /* Too big. */ + } + + pPage = (ma_paged_audio_buffer_page*)ma_malloc((size_t)allocationSize, pAllocationCallbacks); /* Safe cast to size_t. */ + if (pPage == NULL) { + return MA_OUT_OF_MEMORY; + } + + pPage->pNext = NULL; + pPage->sizeInFrames = pageSizeInFrames; + + if (pInitialData != NULL) { + ma_copy_pcm_frames(pPage->pAudioData, pInitialData, pageSizeInFrames, pData->format, pData->channels); + } + + *ppPage = pPage; + + return MA_SUCCESS; +} + +MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pData == NULL || pPage == NULL) { + return MA_INVALID_ARGS; + } + + /* It's assumed the page is not attached to the list. */ + ma_free(pPage, pAllocationCallbacks); + + return MA_SUCCESS; +} + +MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage) +{ + if (pData == NULL || pPage == NULL) { + return MA_INVALID_ARGS; + } + + /* This function assumes the page has been filled with audio data by this point. As soon as we append, the page will be available for reading. */ + + /* First thing to do is update the tail. */ + for (;;) { + ma_paged_audio_buffer_page* pOldTail = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->pTail); + ma_paged_audio_buffer_page* pNewTail = pPage; + + if (c89atomic_compare_exchange_weak_ptr((volatile void**)&pData->pTail, (void**)&pOldTail, pNewTail)) { + /* Here is where we append the page to the list. After this, the page is attached to the list and ready to be read from. */ + c89atomic_exchange_ptr(&pOldTail->pNext, pPage); + break; /* Done. */ + } + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_result result; + ma_paged_audio_buffer_page* pPage; + + result = ma_paged_audio_buffer_data_allocate_page(pData, pageSizeInFrames, pInitialData, pAllocationCallbacks, &pPage); + if (result != MA_SUCCESS) { + return result; + } + + return ma_paged_audio_buffer_data_append_page(pData, pPage); /* <-- Should never fail. */ +} + + +MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData) +{ + ma_paged_audio_buffer_config config; + + MA_ZERO_OBJECT(&config); + config.pData = pData; + + return config; +} + + +static ma_result ma_paged_audio_buffer__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + return ma_paged_audio_buffer_read_pcm_frames((ma_paged_audio_buffer*)pDataSource, pFramesOut, frameCount, pFramesRead); +} + +static ma_result ma_paged_audio_buffer__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + return ma_paged_audio_buffer_seek_to_pcm_frame((ma_paged_audio_buffer*)pDataSource, frameIndex); +} + +static ma_result ma_paged_audio_buffer__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + ma_paged_audio_buffer* pPagedAudioBuffer = (ma_paged_audio_buffer*)pDataSource; + + *pFormat = pPagedAudioBuffer->pData->format; + *pChannels = pPagedAudioBuffer->pData->channels; + *pSampleRate = 0; /* There is no notion of a sample rate with audio buffers. */ + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pPagedAudioBuffer->pData->channels); + + return MA_SUCCESS; +} + +static ma_result ma_paged_audio_buffer__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) +{ + return ma_paged_audio_buffer_get_cursor_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pCursor); +} + +static ma_result ma_paged_audio_buffer__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength) +{ + return ma_paged_audio_buffer_get_length_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pLength); +} + +static ma_data_source_vtable g_ma_paged_audio_buffer_data_source_vtable = +{ + ma_paged_audio_buffer__data_source_on_read, + ma_paged_audio_buffer__data_source_on_seek, + ma_paged_audio_buffer__data_source_on_get_data_format, + ma_paged_audio_buffer__data_source_on_get_cursor, + ma_paged_audio_buffer__data_source_on_get_length, + NULL, /* onSetLooping */ + 0 +}; + +MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer) +{ + ma_result result; + ma_data_source_config dataSourceConfig; + + if (pPagedAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pPagedAudioBuffer); + + /* A config is required for the format and channel count. */ + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->pData == NULL) { + return MA_INVALID_ARGS; /* No underlying data specified. */ + } + + dataSourceConfig = ma_data_source_config_init(); + dataSourceConfig.vtable = &g_ma_paged_audio_buffer_data_source_vtable; + + result = ma_data_source_init(&dataSourceConfig, &pPagedAudioBuffer->ds); + if (result != MA_SUCCESS) { + return result; + } + + pPagedAudioBuffer->pData = pConfig->pData; + pPagedAudioBuffer->pCurrent = ma_paged_audio_buffer_data_get_head(pConfig->pData); + pPagedAudioBuffer->relativeCursor = 0; + pPagedAudioBuffer->absoluteCursor = 0; + + return MA_SUCCESS; +} + +MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer) +{ + if (pPagedAudioBuffer == NULL) { + return; + } + + /* Nothing to do. The data needs to be deleted separately. */ +} + +MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_result result = MA_SUCCESS; + ma_uint64 totalFramesRead = 0; + ma_format format; + ma_uint32 channels; + + if (pPagedAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + format = pPagedAudioBuffer->pData->format; + channels = pPagedAudioBuffer->pData->channels; + + while (totalFramesRead < frameCount) { + /* Read from the current page. The buffer should never be in a state where this is NULL. */ + ma_uint64 framesRemainingInCurrentPage; + ma_uint64 framesRemainingToRead = frameCount - totalFramesRead; + ma_uint64 framesToReadThisIteration; + + MA_ASSERT(pPagedAudioBuffer->pCurrent != NULL); + + framesRemainingInCurrentPage = pPagedAudioBuffer->pCurrent->sizeInFrames - pPagedAudioBuffer->relativeCursor; + + framesToReadThisIteration = ma_min(framesRemainingInCurrentPage, framesRemainingToRead); + ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), ma_offset_pcm_frames_ptr(pPagedAudioBuffer->pCurrent->pAudioData, pPagedAudioBuffer->relativeCursor, format, channels), framesToReadThisIteration, format, channels); + totalFramesRead += framesToReadThisIteration; + + pPagedAudioBuffer->absoluteCursor += framesToReadThisIteration; + pPagedAudioBuffer->relativeCursor += framesToReadThisIteration; + + /* Move to the next page if necessary. If there's no more pages, we need to return MA_AT_END. */ + MA_ASSERT(pPagedAudioBuffer->relativeCursor <= pPagedAudioBuffer->pCurrent->sizeInFrames); + + if (pPagedAudioBuffer->relativeCursor == pPagedAudioBuffer->pCurrent->sizeInFrames) { + /* We reached the end of the page. Need to move to the next. If there's no more pages, we're done. */ + ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPagedAudioBuffer->pCurrent->pNext); + if (pNext == NULL) { + result = MA_AT_END; + break; /* We've reached the end. */ + } else { + pPagedAudioBuffer->pCurrent = pNext; + pPagedAudioBuffer->relativeCursor = 0; + } + } + } + + if (pFramesRead != NULL) { + *pFramesRead = totalFramesRead; + } + + return result; +} + +MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex) +{ + if (pPagedAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + if (frameIndex == pPagedAudioBuffer->absoluteCursor) { + return MA_SUCCESS; /* Nothing to do. */ + } + + if (frameIndex < pPagedAudioBuffer->absoluteCursor) { + /* Moving backwards. Need to move the cursor back to the start, and then move forward. */ + pPagedAudioBuffer->pCurrent = ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData); + pPagedAudioBuffer->absoluteCursor = 0; + pPagedAudioBuffer->relativeCursor = 0; + + /* Fall through to the forward seeking section below. */ + } + + if (frameIndex > pPagedAudioBuffer->absoluteCursor) { + /* Moving forward. */ + ma_paged_audio_buffer_page* pPage; + ma_uint64 runningCursor = 0; + + for (pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData)->pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext)) { + ma_uint64 pageRangeBeg = runningCursor; + ma_uint64 pageRangeEnd = pageRangeBeg + pPage->sizeInFrames; + + if (frameIndex >= pageRangeBeg) { + if (frameIndex < pageRangeEnd || (frameIndex == pageRangeEnd && pPage == (ma_paged_audio_buffer_page*)c89atomic_load_ptr(ma_paged_audio_buffer_data_get_tail(pPagedAudioBuffer->pData)))) { /* A small edge case - allow seeking to the very end of the buffer. */ + /* We found the page. */ + pPagedAudioBuffer->pCurrent = pPage; + pPagedAudioBuffer->absoluteCursor = frameIndex; + pPagedAudioBuffer->relativeCursor = frameIndex - pageRangeBeg; + return MA_SUCCESS; + } + } + + runningCursor = pageRangeEnd; + } + + /* Getting here means we tried seeking too far forward. Don't change any state. */ + return MA_BAD_SEEK; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor) +{ + if (pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; /* Safety. */ + + if (pPagedAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = pPagedAudioBuffer->absoluteCursor; + + return MA_SUCCESS; +} + +MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength) +{ + return ma_paged_audio_buffer_data_get_length_in_pcm_frames(pPagedAudioBuffer->pData, pLength); +} + + + /************************************************************************************************************************************************************** VFS @@ -45119,6 +56316,8 @@ MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file) MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead) { ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + ma_result result; + size_t bytesRead; if (pBytesRead != NULL) { *pBytesRead = 0; @@ -45132,7 +56331,17 @@ MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t return MA_NOT_IMPLEMENTED; } - return pCallbacks->onRead(pVFS, file, pDst, sizeInBytes, pBytesRead); + result = pCallbacks->onRead(pVFS, file, pDst, sizeInBytes, &bytesRead); + + if (pBytesRead != NULL) { + *pBytesRead = bytesRead; + } + + if (result == MA_SUCCESS && bytesRead == 0 && sizeInBytes > 0) { + result = MA_AT_END; + } + + return result; } MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten) @@ -45212,7 +56421,7 @@ MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo } -static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePath, const wchar_t* pFilePathW, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks, ma_uint32 allocationType) +static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePath, const wchar_t* pFilePathW, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) { ma_result result; ma_vfs_file file; @@ -45220,8 +56429,6 @@ static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePat void* pData; size_t bytesRead; - (void)allocationType; - if (ppData != NULL) { *ppData = NULL; } @@ -45253,7 +56460,7 @@ static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePat return MA_TOO_BIG; } - pData = ma__malloc_from_callbacks((size_t)info.sizeInBytes, pAllocationCallbacks); /* Safe cast. */ + pData = ma_malloc((size_t)info.sizeInBytes, pAllocationCallbacks); /* Safe cast. */ if (pData == NULL) { ma_vfs_close(pVFS, file); return result; @@ -45263,7 +56470,7 @@ static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePat ma_vfs_close(pVFS, file); if (result != MA_SUCCESS) { - ma__free_from_callbacks(pData, pAllocationCallbacks); + ma_free(pData, pAllocationCallbacks); return result; } @@ -45279,12 +56486,12 @@ static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePat MA_API ma_result ma_vfs_open_and_read_file(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_vfs_open_and_read_file_ex(pVFS, pFilePath, NULL, ppData, pSize, pAllocationCallbacks, 0 /*MA_ALLOCATION_TYPE_GENERAL*/); + return ma_vfs_open_and_read_file_ex(pVFS, pFilePath, NULL, ppData, pSize, pAllocationCallbacks); } MA_API ma_result ma_vfs_open_and_read_file_w(ma_vfs* pVFS, const wchar_t* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_vfs_open_and_read_file_ex(pVFS, NULL, pFilePath, ppData, pSize, pAllocationCallbacks, 0 /*MA_ALLOCATION_TYPE_GENERAL*/); + return ma_vfs_open_and_read_file_ex(pVFS, NULL, pFilePath, ppData, pSize, pAllocationCallbacks); } @@ -45992,7 +57199,7 @@ extern "C" { #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) #define DRWAV_VERSION_MAJOR 0 #define DRWAV_VERSION_MINOR 13 -#define DRWAV_VERSION_REVISION 1 +#define DRWAV_VERSION_REVISION 6 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include typedef signed char drwav_int8; @@ -46527,7 +57734,7 @@ extern "C" { #define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 31 +#define DRFLAC_VERSION_REVISION 38 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include typedef signed char drflac_int8; @@ -46536,7 +57743,7 @@ typedef signed short drflac_int16; typedef unsigned short drflac_uint16; typedef signed int drflac_int32; typedef unsigned int drflac_uint32; -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) typedef signed __int64 drflac_int64; typedef unsigned __int64 drflac_uint64; #else @@ -46553,7 +57760,7 @@ typedef unsigned int drflac_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) typedef drflac_uint64 drflac_uintptr; #else typedef drflac_uint32 drflac_uintptr; @@ -46888,7 +58095,7 @@ extern "C" { #define DRMP3_XSTRINGIFY(x) DRMP3_STRINGIFY(x) #define DRMP3_VERSION_MAJOR 0 #define DRMP3_VERSION_MINOR 6 -#define DRMP3_VERSION_REVISION 31 +#define DRMP3_VERSION_REVISION 33 #define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION) #include typedef signed char drmp3_int8; @@ -46897,7 +58104,7 @@ typedef signed short drmp3_int16; typedef unsigned short drmp3_uint16; typedef signed int drmp3_int32; typedef unsigned int drmp3_uint32; -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) typedef signed __int64 drmp3_int64; typedef unsigned __int64 drmp3_uint64; #else @@ -47012,9 +58219,14 @@ typedef drmp3_int32 drmp3_result; #define DRMP3_INLINE __forceinline #elif defined(__GNUC__) #if defined(__STRICT_ANSI__) - #define DRMP3_INLINE __inline__ __attribute__((always_inline)) + #define DRMP3_GNUC_INLINE_HINT __inline__ #else - #define DRMP3_INLINE inline __attribute__((always_inline)) + #define DRMP3_GNUC_INLINE_HINT inline + #endif + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT #endif #elif defined(__WATCOMC__) #define DRMP3_INLINE __inline @@ -47135,43 +58347,22 @@ Decoding static ma_result ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) { - size_t bytesRead; + MA_ASSERT(pDecoder != NULL); - MA_ASSERT(pDecoder != NULL); - MA_ASSERT(pBufferOut != NULL); - MA_ASSERT(bytesToRead > 0); /* It's an error to call this with a byte count of zero. */ - - bytesRead = pDecoder->onRead(pDecoder, pBufferOut, bytesToRead); - - if (pBytesRead != NULL) { - *pBytesRead = bytesRead; - } - - if (bytesRead == 0) { - return MA_AT_END; - } - - return MA_SUCCESS; + return pDecoder->onRead(pDecoder, pBufferOut, bytesToRead, pBytesRead); } static ma_result ma_decoder_seek_bytes(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin) { - ma_bool32 wasSuccessful; - MA_ASSERT(pDecoder != NULL); - wasSuccessful = pDecoder->onSeek(pDecoder, byteOffset, origin); - if (wasSuccessful) { - return MA_SUCCESS; - } else { - return MA_ERROR; - } + return pDecoder->onSeek(pDecoder, byteOffset, origin); } static ma_result ma_decoder_tell_bytes(ma_decoder* pDecoder, ma_int64* pCursor) { MA_ASSERT(pDecoder != NULL); - + if (pDecoder->onTell == NULL) { return MA_NOT_IMPLEMENTED; } @@ -47180,12 +58371,13 @@ static ma_result ma_decoder_tell_bytes(ma_decoder* pDecoder, ma_int64* pCursor) } -MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat) +MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat, ma_uint32 seekPointCount) { ma_decoding_backend_config config; MA_ZERO_OBJECT(&config); config.preferredFormat = preferredFormat; + config.seekPointCount = seekPointCount; return config; } @@ -47195,12 +58387,10 @@ MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint3 { ma_decoder_config config; MA_ZERO_OBJECT(&config); - config.format = outputFormat; - config.channels = ma_min(outputChannels, ma_countof(config.channelMap)); - config.sampleRate = outputSampleRate; - config.resampling.algorithm = ma_resample_algorithm_linear; - config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); - config.resampling.speex.quality = 3; + config.format = outputFormat; + config.channels = outputChannels; + config.sampleRate = outputSampleRate; + config.resampling = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); /* Format/channels/rate doesn't matter here. */ config.encodingFormat = ma_encoding_format_unknown; /* Note that we are intentionally leaving the channel map empty here which will cause the default channel map to be used. */ @@ -47237,19 +58427,11 @@ static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_ MA_ASSERT(pDecoder != NULL); MA_ASSERT(pConfig != NULL); - result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, &internalSampleRate); + result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, &internalSampleRate, internalChannelMap, ma_countof(internalChannelMap)); if (result != MA_SUCCESS) { return result; /* Failed to retrieve the internal data format. */ } - /* Channel map needs to be retrieved separately. */ - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onGetChannelMap != NULL) { - pDecoder->pBackendVTable->onGetChannelMap(pDecoder->pBackendUserData, pDecoder->pBackend, internalChannelMap, ma_countof(internalChannelMap)); - } else { - ma_get_standard_channel_map(ma_standard_channel_map_default, ma_min(internalChannels, ma_countof(internalChannelMap)), internalChannelMap); - } - - /* Make sure we're not asking for too many channels. */ if (pConfig->channels > MA_MAX_CHANNELS) { @@ -47281,28 +58463,57 @@ static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_ pDecoder->outputSampleRate = pConfig->sampleRate; } - if (ma_channel_map_blank(pDecoder->outputChannels, pConfig->channelMap)) { - ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->outputChannels, pDecoder->outputChannelMap); - } else { - MA_COPY_MEMORY(pDecoder->outputChannelMap, pConfig->channelMap, sizeof(pConfig->channelMap)); - } - - converterConfig = ma_data_converter_config_init( internalFormat, pDecoder->outputFormat, internalChannels, pDecoder->outputChannels, internalSampleRate, pDecoder->outputSampleRate ); - ma_channel_map_copy(converterConfig.channelMapIn, internalChannelMap, internalChannels); - ma_channel_map_copy(converterConfig.channelMapOut, pDecoder->outputChannelMap, pDecoder->outputChannels); - converterConfig.channelMixMode = pConfig->channelMixMode; - converterConfig.ditherMode = pConfig->ditherMode; - converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; /* Never allow dynamic sample rate conversion. Setting this to true will disable passthrough optimizations. */ - converterConfig.resampling.algorithm = pConfig->resampling.algorithm; - converterConfig.resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder; - converterConfig.resampling.speex.quality = pConfig->resampling.speex.quality; + converterConfig.pChannelMapIn = internalChannelMap; + converterConfig.pChannelMapOut = pConfig->pChannelMap; + converterConfig.channelMixMode = pConfig->channelMixMode; + converterConfig.ditherMode = pConfig->ditherMode; + converterConfig.allowDynamicSampleRate = MA_FALSE; /* Never allow dynamic sample rate conversion. Setting this to true will disable passthrough optimizations. */ + converterConfig.resampling = pConfig->resampling; - return ma_data_converter_init(&converterConfig, &pDecoder->converter); + result = ma_data_converter_init(&converterConfig, &pDecoder->allocationCallbacks, &pDecoder->converter); + if (result != MA_SUCCESS) { + return result; + } + + /* + Now that we have the decoder we need to determine whether or not we need a heap-allocated cache. We'll + need this if the data converter does not support calculation of the required input frame count. To + determine support for this we'll just run a test. + */ + { + ma_uint64 unused; + + result = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, 1, &unused); + if (result != MA_SUCCESS) { + /* + We were unable to calculate the required input frame count which means we'll need to use + a heap-allocated cache. + */ + ma_uint64 inputCacheCapSizeInBytes; + + pDecoder->inputCacheCap = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(internalFormat, internalChannels); + + /* Not strictly necessary, but keeping here for safety in case we change the default value of pDecoder->inputCacheCap. */ + inputCacheCapSizeInBytes = pDecoder->inputCacheCap * ma_get_bytes_per_frame(internalFormat, internalChannels); + if (inputCacheCapSizeInBytes > MA_SIZE_MAX) { + ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + + pDecoder->pInputCache = ma_malloc((size_t)inputCacheCapSizeInBytes, &pDecoder->allocationCallbacks); /* Safe cast to size_t. */ + if (pDecoder->pInputCache == NULL) { + ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + } + } + + return MA_SUCCESS; } @@ -47346,7 +58557,7 @@ static ma_result ma_decoder_init_from_vtable(const ma_decoding_backend_vtable* p return MA_NOT_IMPLEMENTED; } - backendConfig = ma_decoding_backend_config_init(pConfig->format); + backendConfig = ma_decoding_backend_config_init(pConfig->format, pConfig->seekPointCount); result = pVTable->onInit(pVTableUserData, ma_decoder_internal_on_read__custom, ma_decoder_internal_on_seek__custom, ma_decoder_internal_on_tell__custom, pDecoder, &backendConfig, &pDecoder->allocationCallbacks, &pBackend); if (result != MA_SUCCESS) { @@ -47438,9 +58649,9 @@ static ma_result ma_wav_ds_seek(ma_data_source* pDataSource, ma_uint64 frameInde return ma_wav_seek_to_pcm_frame((ma_wav*)pDataSource, frameIndex); } -static ma_result ma_wav_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_wav_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { - return ma_wav_get_data_format((ma_wav*)pDataSource, pFormat, pChannels, pSampleRate, NULL, 0); + return ma_wav_get_data_format((ma_wav*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); } static ma_result ma_wav_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) @@ -47457,11 +58668,11 @@ static ma_data_source_vtable g_ma_wav_ds_vtable = { ma_wav_ds_read, ma_wav_ds_seek, - NULL, /* onMap() */ - NULL, /* onUnmap() */ ma_wav_ds_get_data_format, ma_wav_ds_get_cursor, - ma_wav_ds_get_length + ma_wav_ds_get_length, + NULL, /* onSetLooping */ + 0 }; @@ -47531,7 +58742,7 @@ static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, } MA_ZERO_OBJECT(pWav); - pWav->format = ma_format_f32; /* f32 by default. */ + pWav->format = ma_format_unknown; /* Use closest match to source file by default. */ if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16 || pConfig->preferredFormat == ma_format_s32)) { pWav->format = pConfig->preferredFormat; @@ -47578,6 +58789,42 @@ MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p return MA_INVALID_FILE; } + /* + If an explicit format was not specified, try picking the closest match based on the internal + format. The format needs to be supported by miniaudio. + */ + if (pWav->format == ma_format_unknown) { + switch (pWav->dr.translatedFormatTag) + { + case DR_WAVE_FORMAT_PCM: + { + if (pWav->dr.bitsPerSample == 8) { + pWav->format = ma_format_u8; + } else if (pWav->dr.bitsPerSample == 16) { + pWav->format = ma_format_s16; + } else if (pWav->dr.bitsPerSample == 24) { + pWav->format = ma_format_s24; + } else if (pWav->dr.bitsPerSample == 32) { + pWav->format = ma_format_s32; + } + } break; + + case DR_WAVE_FORMAT_IEEE_FLOAT: + { + if (pWav->dr.bitsPerSample == 32) { + pWav->format = ma_format_f32; + } + } break; + + default: break; + } + + /* Fall back to f32 if we couldn't find anything. */ + if (pWav->format == ma_format_unknown) { + pWav->format = ma_format_f32; + } + } + return MA_SUCCESS; } #else @@ -47707,6 +58954,14 @@ MA_API void ma_wav_uninit(ma_wav* pWav, const ma_allocation_callbacks* pAllocati MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pWav == NULL) { return MA_INVALID_ARGS; } @@ -47738,7 +58993,7 @@ MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint6 } break; /* Fallback to a raw read. */ - case ma_format_unknown: return MA_INVALID_OPERATION; /* <-- this should never be hit because initialization would just fall back to supported format. */ + case ma_format_unknown: return MA_INVALID_OPERATION; /* <-- this should never be hit because initialization would just fall back to a supported format. */ default: { totalFramesRead = drwav_read_pcm_frames(&pWav->dr, frameCount, pFramesOut); @@ -47754,6 +59009,10 @@ MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint6 *pFramesRead = totalFramesRead; } + if (result == MA_SUCCESS && totalFramesRead == 0) { + result = MA_AT_END; + } + return result; } #else @@ -47779,7 +59038,7 @@ MA_API ma_result ma_wav_seek_to_pcm_frame(ma_wav* pWav, ma_uint64 frameIndex) #if !defined(MA_NO_WAV) { drwav_bool32 wavResult; - + wavResult = drwav_seek_to_pcm_frame(&pWav->dr, frameIndex); if (wavResult != DRWAV_TRUE) { return MA_ERROR; @@ -47834,7 +59093,7 @@ MA_API ma_result ma_wav_get_data_format(ma_wav* pWav, ma_format* pFormat, ma_uin } if (pChannelMap != NULL) { - ma_get_standard_channel_map(ma_standard_channel_map_microsoft, (ma_uint32)ma_min(pWav->dr.channels, channelMapCap), pChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pChannelMap, channelMapCap, pWav->dr.channels); } return MA_SUCCESS; @@ -48015,23 +59274,13 @@ static void ma_decoding_backend_uninit__wav(void* pUserData, ma_data_source* pBa ma_free(pWav, pAllocationCallbacks); } -static ma_result ma_decoding_backend_get_channel_map__wav(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap) -{ - ma_wav* pWav = (ma_wav*)pBackend; - - (void)pUserData; - - return ma_wav_get_data_format(pWav, NULL, NULL, NULL, pChannelMap, channelMapCap); -} - static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_wav = { ma_decoding_backend_init__wav, ma_decoding_backend_init_file__wav, ma_decoding_backend_init_file_w__wav, ma_decoding_backend_init_memory__wav, - ma_decoding_backend_uninit__wav, - ma_decoding_backend_get_channel_map__wav + ma_decoding_backend_uninit__wav }; static ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) @@ -48079,9 +59328,9 @@ static ma_result ma_flac_ds_seek(ma_data_source* pDataSource, ma_uint64 frameInd return ma_flac_seek_to_pcm_frame((ma_flac*)pDataSource, frameIndex); } -static ma_result ma_flac_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_flac_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { - return ma_flac_get_data_format((ma_flac*)pDataSource, pFormat, pChannels, pSampleRate, NULL, 0); + return ma_flac_get_data_format((ma_flac*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); } static ma_result ma_flac_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) @@ -48098,11 +59347,11 @@ static ma_data_source_vtable g_ma_flac_ds_vtable = { ma_flac_ds_read, ma_flac_ds_seek, - NULL, /* onMap() */ - NULL, /* onUnmap() */ ma_flac_ds_get_data_format, ma_flac_ds_get_cursor, - ma_flac_ds_get_length + ma_flac_ds_get_length, + NULL, /* onSetLooping */ + 0 }; @@ -48344,6 +59593,14 @@ MA_API void ma_flac_uninit(ma_flac* pFlac, const ma_allocation_callbacks* pAlloc MA_API ma_result ma_flac_read_pcm_frames(ma_flac* pFlac, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pFlac == NULL) { return MA_INVALID_ARGS; } @@ -48392,6 +59649,10 @@ MA_API ma_result ma_flac_read_pcm_frames(ma_flac* pFlac, void* pFramesOut, ma_ui *pFramesRead = totalFramesRead; } + if (result == MA_SUCCESS && totalFramesRead == 0) { + result = MA_AT_END; + } + return result; } #else @@ -48417,7 +59678,7 @@ MA_API ma_result ma_flac_seek_to_pcm_frame(ma_flac* pFlac, ma_uint64 frameIndex) #if !defined(MA_NO_FLAC) { drflac_bool32 flacResult; - + flacResult = drflac_seek_to_pcm_frame(pFlac->dr, frameIndex); if (flacResult != DRFLAC_TRUE) { return MA_ERROR; @@ -48472,7 +59733,7 @@ MA_API ma_result ma_flac_get_data_format(ma_flac* pFlac, ma_format* pFormat, ma_ } if (pChannelMap != NULL) { - ma_get_standard_channel_map(ma_standard_channel_map_microsoft, (ma_uint32)ma_min(pFlac->dr->channels, channelMapCap), pChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pChannelMap, channelMapCap, pFlac->dr->channels); } return MA_SUCCESS; @@ -48647,23 +59908,13 @@ static void ma_decoding_backend_uninit__flac(void* pUserData, ma_data_source* pB ma_free(pFlac, pAllocationCallbacks); } -static ma_result ma_decoding_backend_get_channel_map__flac(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap) -{ - ma_flac* pFlac = (ma_flac*)pBackend; - - (void)pUserData; - - return ma_flac_get_data_format(pFlac, NULL, NULL, NULL, pChannelMap, channelMapCap); -} - static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_flac = { ma_decoding_backend_init__flac, ma_decoding_backend_init_file__flac, ma_decoding_backend_init_file_w__flac, ma_decoding_backend_init_memory__flac, - ma_decoding_backend_uninit__flac, - ma_decoding_backend_get_channel_map__flac + ma_decoding_backend_uninit__flac }; static ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) @@ -48686,6 +59937,8 @@ typedef struct ma_format format; /* Can be f32 or s16. */ #if !defined(MA_NO_MP3) drmp3 dr; + drmp3_uint32 seekPointCount; + drmp3_seek_point* pSeekPoints; /* Only used if seek table generation is used. */ #endif } ma_mp3; @@ -48711,9 +59964,9 @@ static ma_result ma_mp3_ds_seek(ma_data_source* pDataSource, ma_uint64 frameInde return ma_mp3_seek_to_pcm_frame((ma_mp3*)pDataSource, frameIndex); } -static ma_result ma_mp3_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_mp3_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { - return ma_mp3_get_data_format((ma_mp3*)pDataSource, pFormat, pChannels, pSampleRate, NULL, 0); + return ma_mp3_get_data_format((ma_mp3*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); } static ma_result ma_mp3_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) @@ -48730,11 +59983,11 @@ static ma_data_source_vtable g_ma_mp3_ds_vtable = { ma_mp3_ds_read, ma_mp3_ds_seek, - NULL, /* onMap() */ - NULL, /* onUnmap() */ ma_mp3_ds_get_data_format, ma_mp3_ds_get_cursor, - ma_mp3_ds_get_length + ma_mp3_ds_get_length, + NULL, /* onSetLooping */ + 0 }; @@ -48823,6 +60076,40 @@ static ma_result ma_mp3_init_internal(const ma_decoding_backend_config* pConfig, return MA_SUCCESS; } +static ma_result ma_mp3_generate_seek_table(ma_mp3* pMP3, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks) +{ + drmp3_bool32 mp3Result; + drmp3_uint32 seekPointCount = 0; + drmp3_seek_point* pSeekPoints = NULL; + + MA_ASSERT(pMP3 != NULL); + MA_ASSERT(pConfig != NULL); + + seekPointCount = pConfig->seekPointCount; + if (seekPointCount > 0) { + pSeekPoints = (drmp3_seek_point*)ma_malloc(sizeof(*pMP3->pSeekPoints) * seekPointCount, pAllocationCallbacks); + if (pSeekPoints == NULL) { + return MA_OUT_OF_MEMORY; + } + } + + mp3Result = drmp3_calculate_seek_points(&pMP3->dr, &seekPointCount, pSeekPoints); + if (mp3Result != MA_TRUE) { + return MA_ERROR; + } + + mp3Result = drmp3_bind_seek_table(&pMP3->dr, seekPointCount, pSeekPoints); + if (mp3Result != MA_TRUE) { + ma_free(pSeekPoints, pAllocationCallbacks); + return MA_ERROR; + } + + pMP3->seekPointCount = seekPointCount; + pMP3->pSeekPoints = pSeekPoints; + + return MA_SUCCESS; +} + MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3) { ma_result result; @@ -48851,6 +60138,8 @@ MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p return MA_INVALID_FILE; } + ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks); + return MA_SUCCESS; } #else @@ -48881,6 +60170,8 @@ MA_API ma_result ma_mp3_init_file(const char* pFilePath, const ma_decoding_backe return MA_INVALID_FILE; } + ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks); + return MA_SUCCESS; } #else @@ -48912,6 +60203,8 @@ MA_API ma_result ma_mp3_init_file_w(const wchar_t* pFilePath, const ma_decoding_ return MA_INVALID_FILE; } + ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks); + return MA_SUCCESS; } #else @@ -48943,6 +60236,8 @@ MA_API ma_result ma_mp3_init_memory(const void* pData, size_t dataSize, const ma return MA_INVALID_FILE; } + ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks); + return MA_SUCCESS; } #else @@ -48962,8 +60257,6 @@ MA_API void ma_mp3_uninit(ma_mp3* pMP3, const ma_allocation_callbacks* pAllocati return; } - (void)pAllocationCallbacks; - #if !defined(MA_NO_MP3) { drmp3_uninit(&pMP3->dr); @@ -48975,11 +60268,22 @@ MA_API void ma_mp3_uninit(ma_mp3* pMP3, const ma_allocation_callbacks* pAllocati } #endif + /* Seek points need to be freed after the MP3 decoder has been uninitialized to ensure they're no longer being referenced. */ + ma_free(pMP3->pSeekPoints, pAllocationCallbacks); + ma_data_source_uninit(&pMP3->ds); } MA_API ma_result ma_mp3_read_pcm_frames(ma_mp3* pMP3, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pMP3 == NULL) { return MA_INVALID_ARGS; } @@ -49049,7 +60353,7 @@ MA_API ma_result ma_mp3_seek_to_pcm_frame(ma_mp3* pMP3, ma_uint64 frameIndex) #if !defined(MA_NO_MP3) { drmp3_bool32 mp3Result; - + mp3Result = drmp3_seek_to_pcm_frame(&pMP3->dr, frameIndex); if (mp3Result != DRMP3_TRUE) { return MA_ERROR; @@ -49104,7 +60408,7 @@ MA_API ma_result ma_mp3_get_data_format(ma_mp3* pMP3, ma_format* pFormat, ma_uin } if (pChannelMap != NULL) { - ma_get_standard_channel_map(ma_standard_channel_map_default, (ma_uint32)ma_min(pMP3->dr.channels, channelMapCap), pChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pMP3->dr.channels); } return MA_SUCCESS; @@ -49279,23 +60583,13 @@ static void ma_decoding_backend_uninit__mp3(void* pUserData, ma_data_source* pBa ma_free(pMP3, pAllocationCallbacks); } -static ma_result ma_decoding_backend_get_channel_map__mp3(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap) -{ - ma_mp3* pMP3 = (ma_mp3*)pBackend; - - (void)pUserData; - - return ma_mp3_get_data_format(pMP3, NULL, NULL, NULL, pChannelMap, channelMapCap); -} - static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_mp3 = { ma_decoding_backend_init__mp3, ma_decoding_backend_init_file__mp3, ma_decoding_backend_init_file_w__mp3, ma_decoding_backend_init_memory__mp3, - ma_decoding_backend_uninit__mp3, - ma_decoding_backend_get_channel_map__mp3 + ma_decoding_backend_uninit__mp3 }; static ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) @@ -49359,9 +60653,9 @@ static ma_result ma_stbvorbis_ds_seek(ma_data_source* pDataSource, ma_uint64 fra return ma_stbvorbis_seek_to_pcm_frame((ma_stbvorbis*)pDataSource, frameIndex); } -static ma_result ma_stbvorbis_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_stbvorbis_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { - return ma_stbvorbis_get_data_format((ma_stbvorbis*)pDataSource, pFormat, pChannels, pSampleRate, NULL, 0); + return ma_stbvorbis_get_data_format((ma_stbvorbis*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); } static ma_result ma_stbvorbis_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) @@ -49378,11 +60672,11 @@ static ma_data_source_vtable g_ma_stbvorbis_ds_vtable = { ma_stbvorbis_ds_read, ma_stbvorbis_ds_seek, - NULL, /* onMap() */ - NULL, /* onUnmap() */ ma_stbvorbis_ds_get_data_format, ma_stbvorbis_ds_get_cursor, - ma_stbvorbis_ds_get_length + ma_stbvorbis_ds_get_length, + NULL, /* onSetLooping */ + 0 }; @@ -49645,6 +60939,14 @@ MA_API void ma_stbvorbis_uninit(ma_stbvorbis* pVorbis, const ma_allocation_callb MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pVorbis == NULL) { return MA_INVALID_ARGS; } @@ -49753,7 +61055,7 @@ MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFram while (totalFramesRead < frameCount) { ma_uint64 framesRemaining = (frameCount - totalFramesRead); int framesRead; - + if (framesRemaining > INT_MAX) { framesRemaining = INT_MAX; } @@ -49761,7 +61063,7 @@ MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFram framesRead = stb_vorbis_get_samples_float_interleaved(pVorbis->stb, channels, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), (int)framesRemaining * channels); /* Safe cast. */ totalFramesRead += framesRead; - if (framesRead < framesRemaining) { + if (framesRead < (int)framesRemaining) { break; /* Nothing left to read. Get out. */ } } @@ -49780,6 +61082,10 @@ MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFram *pFramesRead = totalFramesRead; } + if (result == MA_SUCCESS && totalFramesRead == 0) { + result = MA_AT_END; + } + return result; } #else @@ -49910,7 +61216,7 @@ MA_API ma_result ma_stbvorbis_get_data_format(ma_stbvorbis* pVorbis, ma_format* } if (pChannelMap != NULL) { - ma_get_standard_channel_map(ma_standard_channel_map_vorbis, (ma_uint32)ma_min(pVorbis->channels, channelMapCap), pChannelMap); + ma_channel_map_init_standard(ma_standard_channel_map_vorbis, pChannelMap, channelMapCap, pVorbis->channels); } return MA_SUCCESS; @@ -49970,7 +61276,7 @@ MA_API ma_result ma_stbvorbis_get_length_in_pcm_frames(ma_stbvorbis* pVorbis, ma } else { *pLength = stb_vorbis_stream_length_in_samples(pVorbis->stb); } - + return MA_SUCCESS; } #else @@ -50065,23 +61371,13 @@ static void ma_decoding_backend_uninit__stbvorbis(void* pUserData, ma_data_sourc ma_free(pVorbis, pAllocationCallbacks); } -static ma_result ma_decoding_backend_get_channel_map__stbvorbis(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap) -{ - ma_stbvorbis* pVorbis = (ma_stbvorbis*)pBackend; - - (void)pUserData; - - return ma_stbvorbis_get_data_format(pVorbis, NULL, NULL, NULL, pChannelMap, channelMapCap); -} - static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_stbvorbis = { ma_decoding_backend_init__stbvorbis, ma_decoding_backend_init_file__stbvorbis, NULL, /* onInitFileW() */ ma_decoding_backend_init_memory__stbvorbis, - ma_decoding_backend_uninit__stbvorbis, - ma_decoding_backend_get_channel_map__stbvorbis + ma_decoding_backend_uninit__stbvorbis }; static ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) @@ -50106,17 +61402,7 @@ static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config* static ma_result ma_decoder__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { - ma_uint64 framesRead = ma_decoder_read_pcm_frames((ma_decoder*)pDataSource, pFramesOut, frameCount); - - if (pFramesRead != NULL) { - *pFramesRead = framesRead; - } - - if (framesRead == 0) { - return MA_AT_END; - } - - return MA_SUCCESS; + return ma_decoder_read_pcm_frames((ma_decoder*)pDataSource, pFramesOut, frameCount, pFramesRead); } static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) @@ -50124,45 +61410,30 @@ static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma return ma_decoder_seek_to_pcm_frame((ma_decoder*)pDataSource, frameIndex); } -static ma_result ma_decoder__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_decoder__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { - ma_decoder* pDecoder = (ma_decoder*)pDataSource; - - *pFormat = pDecoder->outputFormat; - *pChannels = pDecoder->outputChannels; - *pSampleRate = pDecoder->outputSampleRate; - - return MA_SUCCESS; + return ma_decoder_get_data_format((ma_decoder*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); } static ma_result ma_decoder__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) { - ma_decoder* pDecoder = (ma_decoder*)pDataSource; - - return ma_decoder_get_cursor_in_pcm_frames(pDecoder, pCursor); + return ma_decoder_get_cursor_in_pcm_frames((ma_decoder*)pDataSource, pCursor); } static ma_result ma_decoder__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength) { - ma_decoder* pDecoder = (ma_decoder*)pDataSource; - - *pLength = ma_decoder_get_length_in_pcm_frames(pDecoder); - if (*pLength == 0) { - return MA_NOT_IMPLEMENTED; - } - - return MA_SUCCESS; + return ma_decoder_get_length_in_pcm_frames((ma_decoder*)pDataSource, pLength); } static ma_data_source_vtable g_ma_decoder_data_source_vtable = { ma_decoder__data_source_on_read, ma_decoder__data_source_on_seek, - NULL, /* onMap */ - NULL, /* onUnmap */ ma_decoder__data_source_on_get_data_format, ma_decoder__data_source_on_get_cursor, - ma_decoder__data_source_on_get_length + ma_decoder__data_source_on_get_length, + NULL, /* onSetLooping */ + 0 }; static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, ma_decoder_tell_proc onTell, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) @@ -50206,22 +61477,9 @@ static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_see static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { - ma_result result = MA_SUCCESS; + ma_result result; - /* Basic validation in case the internal decoder supports different limits to miniaudio. */ - { - /* TODO: Remove this block once we remove MA_MIN_CHANNELS and MA_MAX_CHANNELS. */ - ma_uint32 internalChannels; - ma_data_source_get_data_format(pDecoder->pBackend, NULL, &internalChannels, NULL); - - if (internalChannels < MA_MIN_CHANNELS || internalChannels > MA_MAX_CHANNELS) { - result = MA_INVALID_DATA; - } - } - - if (result == MA_SUCCESS) { - result = ma_decoder__init_data_converter(pDecoder, pConfig); - } + result = ma_decoder__init_data_converter(pDecoder, pConfig); /* If we failed post initialization we need to uninitialize the decoder before returning to prevent a memory leak. */ if (result != MA_SUCCESS) { @@ -50232,83 +61490,6 @@ static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decod return result; } -MA_API ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_WAV - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_wav; - - return ma_decoder_init(onRead, onSeek, pUserData, &config, pDecoder); -#else - (void)onRead; - (void)onSeek; - (void)pUserData; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_FLAC - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_flac; - - return ma_decoder_init(onRead, onSeek, pUserData, &config, pDecoder); -#else - (void)onRead; - (void)onSeek; - (void)pUserData; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_MP3 - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_mp3; - - return ma_decoder_init(onRead, onSeek, pUserData, &config, pDecoder); -#else - (void)onRead; - (void)onSeek; - (void)pUserData; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_VORBIS - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_vorbis; - - return ma_decoder_init(onRead, onSeek, pUserData, &config, pDecoder); -#else - (void)onRead; - (void)onSeek; - (void)pUserData; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - - static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { @@ -50431,29 +61612,41 @@ MA_API ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_pr } -static size_t ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) +static ma_result ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) { size_t bytesRemaining; MA_ASSERT(pDecoder->data.memory.dataSize >= pDecoder->data.memory.currentReadPos); + if (pBytesRead != NULL) { + *pBytesRead = 0; + } + bytesRemaining = pDecoder->data.memory.dataSize - pDecoder->data.memory.currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } + if (bytesRemaining == 0) { + return MA_AT_END; + } + if (bytesToRead > 0) { MA_COPY_MEMORY(pBufferOut, pDecoder->data.memory.pData + pDecoder->data.memory.currentReadPos, bytesToRead); pDecoder->data.memory.currentReadPos += bytesToRead; } - return bytesToRead; + if (pBytesRead != NULL) { + *pBytesRead = bytesToRead; + } + + return MA_SUCCESS; } -static ma_bool32 ma_decoder__on_seek_memory(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin) +static ma_result ma_decoder__on_seek_memory(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin) { if (byteOffset > 0 && (ma_uint64)byteOffset > MA_SIZE_MAX) { - return MA_FALSE; /* Too far. */ + return MA_BAD_SEEK; } if (origin == ma_seek_origin_current) { @@ -50490,7 +61683,7 @@ static ma_bool32 ma_decoder__on_seek_memory(ma_decoder* pDecoder, ma_int64 byteO } } - return MA_TRUE; + return MA_SUCCESS; } static ma_result ma_decoder__on_tell_memory(ma_decoder* pDecoder, ma_int64* pCursor) @@ -50537,79 +61730,6 @@ MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, cons return ma_decoder_init__internal(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, &config, pDecoder); } -MA_API ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_WAV - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ - config.encodingFormat = ma_encoding_format_wav; - - return ma_decoder_init_memory(pData, dataSize, &config, pDecoder); -#else - (void)pData; - (void)dataSize; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_FLAC - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ - config.encodingFormat = ma_encoding_format_flac; - - return ma_decoder_init_memory(pData, dataSize, &config, pDecoder); -#else - (void)pData; - (void)dataSize; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_MP3 - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ - config.encodingFormat = ma_encoding_format_mp3; - - return ma_decoder_init_memory(pData, dataSize, &config, pDecoder); -#else - (void)pData; - (void)dataSize; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_VORBIS - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ - config.encodingFormat = ma_encoding_format_vorbis; - - return ma_decoder_init_memory(pData, dataSize, &config, pDecoder); -#else - (void)pData; - (void)dataSize; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - - #if defined(MA_HAS_WAV) || \ defined(MA_HAS_MP3) || \ @@ -50790,30 +61910,19 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e -static size_t ma_decoder__on_read_vfs(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) +static ma_result ma_decoder__on_read_vfs(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) { - size_t bytesRead; - MA_ASSERT(pDecoder != NULL); MA_ASSERT(pBufferOut != NULL); - ma_vfs_or_default_read(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, pBufferOut, bytesToRead, &bytesRead); - - return bytesRead; + return ma_vfs_or_default_read(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, pBufferOut, bytesToRead, pBytesRead); } -static ma_bool32 ma_decoder__on_seek_vfs(ma_decoder* pDecoder, ma_int64 offset, ma_seek_origin origin) +static ma_result ma_decoder__on_seek_vfs(ma_decoder* pDecoder, ma_int64 offset, ma_seek_origin origin) { - ma_result result; - MA_ASSERT(pDecoder != NULL); - result = ma_vfs_or_default_seek(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, offset, origin); - if (result != MA_SUCCESS) { - return MA_FALSE; - } - - return MA_TRUE; + return ma_vfs_or_default_seek(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, offset, origin); } static ma_result ma_decoder__on_tell_vfs(ma_decoder* pDecoder, ma_int64* pCursor) @@ -50955,79 +62064,6 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const return MA_SUCCESS; } -MA_API ma_result ma_decoder_init_vfs_wav(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_WAV - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_wav; - - return ma_decoder_init_vfs(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_vfs_flac(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_FLAC - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_flac; - - return ma_decoder_init_vfs(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_vfs_mp3(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_MP3 - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_mp3; - - return ma_decoder_init_vfs(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_vfs_vorbis(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_VORBIS - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_vorbis; - - return ma_decoder_init_vfs(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - - static ma_result ma_decoder__preinit_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { @@ -51158,132 +62194,16 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c return MA_SUCCESS; } -MA_API ma_result ma_decoder_init_vfs_wav_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_WAV - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_wav; - - return ma_decoder_init_vfs_w(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_vfs_flac_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_FLAC - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_flac; - - return ma_decoder_init_vfs_w(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_vfs_mp3_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_MP3 - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_mp3; - - return ma_decoder_init_vfs_w(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - -MA_API ma_result ma_decoder_init_vfs_vorbis_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ -#ifdef MA_HAS_VORBIS - ma_decoder_config config; - - config = ma_decoder_config_init_copy(pConfig); - config.encodingFormat = ma_encoding_format_vorbis; - - return ma_decoder_init_vfs_w(pVFS, pFilePath, &config, pDecoder); -#else - (void)pVFS; - (void)pFilePath; - (void)pConfig; - (void)pDecoder; - return MA_NO_BACKEND; -#endif -} - - - MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { return ma_decoder_init_vfs(NULL, pFilePath, pConfig, pDecoder); } -MA_API ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_wav(NULL, pFilePath, pConfig, pDecoder); -} - -MA_API ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_flac(NULL, pFilePath, pConfig, pDecoder); -} - -MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_mp3(NULL, pFilePath, pConfig, pDecoder); -} - -MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_vorbis(NULL, pFilePath, pConfig, pDecoder); -} - - - MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { return ma_decoder_init_vfs_w(NULL, pFilePath, pConfig, pDecoder); } -MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_wav_w(NULL, pFilePath, pConfig, pDecoder); -} - -MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_flac_w(NULL, pFilePath, pConfig, pDecoder); -} - -MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_mp3_w(NULL, pFilePath, pConfig, pDecoder); -} - -MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) -{ - return ma_decoder_init_vfs_vorbis_w(NULL, pFilePath, pConfig, pDecoder); -} - MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder) { if (pDecoder == NULL) { @@ -51296,15 +62216,244 @@ MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder) } } - /* Legacy. */ if (pDecoder->onRead == ma_decoder__on_read_vfs) { ma_vfs_or_default_close(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file); pDecoder->data.vfs.file = NULL; } - ma_data_converter_uninit(&pDecoder->converter); + ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks); ma_data_source_uninit(&pDecoder->ds); + if (pDecoder->pInputCache != NULL) { + ma_free(pDecoder->pInputCache, &pDecoder->allocationCallbacks); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_result result = MA_SUCCESS; + ma_uint64 totalFramesReadOut; + void* pRunningFramesOut; + + if (pFramesRead != NULL) { + *pFramesRead = 0; /* Safety. */ + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + if (pDecoder->pBackend == NULL) { + return MA_INVALID_OPERATION; + } + + /* Fast path. */ + if (pDecoder->converter.isPassthrough) { + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pFramesOut, frameCount, &totalFramesReadOut); + } else { + /* + Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we + need to run through each sample because we need to ensure it's internal cache is updated. + */ + if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) { + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut); + } else { + /* Slow path. Need to run everything through the data converter. */ + ma_format internalFormat; + ma_uint32 internalChannels; + + totalFramesReadOut = 0; + pRunningFramesOut = pFramesOut; + + result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, NULL, NULL, 0); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the internal format and channel count. */ + } + + /* + We run a different path depending on whether or not we are using a heap-allocated + intermediary buffer or not. If the data converter does not support the calculation of + the required number of input frames, we'll use the heap-allocated path. Otherwise we'll + use the stack-allocated path. + */ + if (pDecoder->pInputCache != NULL) { + /* We don't have a way of determining the required number of input frames, so need to persistently store input data in a cache. */ + while (totalFramesReadOut < frameCount) { + ma_uint64 framesToReadThisIterationIn; + ma_uint64 framesToReadThisIterationOut; + + /* If there's any data available in the cache, that needs to get processed first. */ + if (pDecoder->inputCacheRemaining > 0) { + framesToReadThisIterationOut = (frameCount - totalFramesReadOut); + framesToReadThisIterationIn = framesToReadThisIterationOut; + if (framesToReadThisIterationIn > pDecoder->inputCacheRemaining) { + framesToReadThisIterationIn = pDecoder->inputCacheRemaining; + } + + result = ma_data_converter_process_pcm_frames(&pDecoder->converter, ma_offset_pcm_frames_ptr(pDecoder->pInputCache, pDecoder->inputCacheConsumed, internalFormat, internalChannels), &framesToReadThisIterationIn, pRunningFramesOut, &framesToReadThisIterationOut); + if (result != MA_SUCCESS) { + break; + } + + pDecoder->inputCacheConsumed += framesToReadThisIterationIn; + pDecoder->inputCacheRemaining -= framesToReadThisIterationIn; + + totalFramesReadOut += framesToReadThisIterationOut; + + if (pRunningFramesOut != NULL) { + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesToReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels)); + } + + if (framesToReadThisIterationIn == 0 && framesToReadThisIterationOut == 0) { + break; /* We're done. */ + } + } + + /* Getting here means there's no data in the cache and we need to fill it up from the data source. */ + if (pDecoder->inputCacheRemaining == 0) { + pDecoder->inputCacheConsumed = 0; + + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pDecoder->pInputCache, pDecoder->inputCacheCap, &pDecoder->inputCacheRemaining); + if (result != MA_SUCCESS) { + break; + } + } + } + } else { + /* We have a way of determining the required number of input frames so just use the stack. */ + while (totalFramesReadOut < frameCount) { + ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In internal format. */ + ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(internalFormat, internalChannels); + ma_uint64 framesToReadThisIterationIn; + ma_uint64 framesReadThisIterationIn; + ma_uint64 framesToReadThisIterationOut; + ma_uint64 framesReadThisIterationOut; + ma_uint64 requiredInputFrameCount; + + framesToReadThisIterationOut = (frameCount - totalFramesReadOut); + framesToReadThisIterationIn = framesToReadThisIterationOut; + if (framesToReadThisIterationIn > intermediaryBufferCap) { + framesToReadThisIterationIn = intermediaryBufferCap; + } + + ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut, &requiredInputFrameCount); + if (framesToReadThisIterationIn > requiredInputFrameCount) { + framesToReadThisIterationIn = requiredInputFrameCount; + } + + if (requiredInputFrameCount > 0) { + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn); + } else { + framesReadThisIterationIn = 0; + } + + /* + At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any + input frames, we still want to try processing frames because there may some output frames generated from cached input data. + */ + framesReadThisIterationOut = framesToReadThisIterationOut; + result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); + if (result != MA_SUCCESS) { + break; + } + + totalFramesReadOut += framesReadThisIterationOut; + + if (pRunningFramesOut != NULL) { + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels)); + } + + if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { + break; /* We're done. */ + } + } + } + } + } + + pDecoder->readPointerInPCMFrames += totalFramesReadOut; + + if (pFramesRead != NULL) { + *pFramesRead = totalFramesReadOut; + } + + if (result == MA_SUCCESS && totalFramesReadOut == 0) { + result = MA_AT_END; + } + + return result; +} + +MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex) +{ + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + if (pDecoder->pBackend != NULL) { + ma_result result; + ma_uint64 internalFrameIndex; + ma_uint32 internalSampleRate; + ma_uint64 currentFrameIndex; + + result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the internal sample rate. */ + } + + if (internalSampleRate == pDecoder->outputSampleRate) { + internalFrameIndex = frameIndex; + } else { + internalFrameIndex = ma_calculate_frame_count_after_resampling(internalSampleRate, pDecoder->outputSampleRate, frameIndex); + } + + /* Only seek if we're requesting a different frame to what we're currently sitting on. */ + ma_data_source_get_cursor_in_pcm_frames(pDecoder->pBackend, ¤tFrameIndex); + if (currentFrameIndex != internalFrameIndex) { + result = ma_data_source_seek_to_pcm_frame(pDecoder->pBackend, internalFrameIndex); + if (result == MA_SUCCESS) { + pDecoder->readPointerInPCMFrames = frameIndex; + } + + /* Reset the data converter so that any cached data in the resampler is cleared. */ + ma_data_converter_reset(&pDecoder->converter); + } + + return result; + } + + /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */ + return MA_INVALID_ARGS; +} + +MA_API ma_result ma_decoder_get_data_format(ma_decoder* pDecoder, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + if (pFormat != NULL) { + *pFormat = pDecoder->outputFormat; + } + + if (pChannels != NULL) { + *pChannels = pDecoder->outputChannels; + } + + if (pSampleRate != NULL) { + *pSampleRate = pDecoder->outputSampleRate; + } + + if (pChannelMap != NULL) { + ma_data_converter_get_output_channel_map(&pDecoder->converter, pChannelMap, channelMapCap); + } + return MA_SUCCESS; } @@ -51325,164 +62474,48 @@ MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_ui return MA_SUCCESS; } -MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder) +MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength) { - if (pDecoder == NULL) { - return 0; + if (pLength == NULL) { + return MA_INVALID_ARGS; } - if (pDecoder->pBackend != NULL) { - ma_result result; - ma_uint64 nativeLengthInPCMFrames; - ma_uint32 internalSampleRate; + *pLength = 0; - ma_data_source_get_length_in_pcm_frames(pDecoder->pBackend, &nativeLengthInPCMFrames); - - result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate); - if (result != MA_SUCCESS) { - return 0; /* Failed to retrieve the internal sample rate. */ - } - - if (internalSampleRate == pDecoder->outputSampleRate) { - return nativeLengthInPCMFrames; - } else { - return ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, internalSampleRate, nativeLengthInPCMFrames); - } - } - - return 0; -} - -MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) -{ - ma_result result; - ma_uint64 totalFramesReadOut; - ma_uint64 totalFramesReadIn; - void* pRunningFramesOut; - - if (pDecoder == NULL) { - return 0; - } - - if (pDecoder->pBackend == NULL) { - return 0; - } - - /* Fast path. */ - if (pDecoder->converter.isPassthrough) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pFramesOut, frameCount, &totalFramesReadOut, MA_FALSE); - } else { - /* - Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we - need to run through each sample because we need to ensure it's internal cache is updated. - */ - if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut, MA_FALSE); - } else { - /* Slow path. Need to run everything through the data converter. */ - ma_format internalFormat; - ma_uint32 internalChannels; - - totalFramesReadOut = 0; - totalFramesReadIn = 0; - pRunningFramesOut = pFramesOut; - - result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, NULL); - if (result != MA_SUCCESS) { - return 0; /* Failed to retrieve the internal format and channel count. */ - } - - while (totalFramesReadOut < frameCount) { - ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In internal format. */ - ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(internalFormat, internalChannels); - ma_uint64 framesToReadThisIterationIn; - ma_uint64 framesReadThisIterationIn; - ma_uint64 framesToReadThisIterationOut; - ma_uint64 framesReadThisIterationOut; - ma_uint64 requiredInputFrameCount; - - framesToReadThisIterationOut = (frameCount - totalFramesReadOut); - framesToReadThisIterationIn = framesToReadThisIterationOut; - if (framesToReadThisIterationIn > intermediaryBufferCap) { - framesToReadThisIterationIn = intermediaryBufferCap; - } - - requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut); - if (framesToReadThisIterationIn > requiredInputFrameCount) { - framesToReadThisIterationIn = requiredInputFrameCount; - } - - if (requiredInputFrameCount > 0) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn, MA_FALSE); - totalFramesReadIn += framesReadThisIterationIn; - } else { - framesReadThisIterationIn = 0; - } - - /* - At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any - input frames, we still want to try processing frames because there may some output frames generated from cached input data. - */ - framesReadThisIterationOut = framesToReadThisIterationOut; - result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut); - if (result != MA_SUCCESS) { - break; - } - - totalFramesReadOut += framesReadThisIterationOut; - - if (pRunningFramesOut != NULL) { - pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels)); - } - - if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) { - break; /* We're done. */ - } - } - } - } - - pDecoder->readPointerInPCMFrames += totalFramesReadOut; - - return totalFramesReadOut; -} - -MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex) -{ if (pDecoder == NULL) { return MA_INVALID_ARGS; } if (pDecoder->pBackend != NULL) { ma_result result; - ma_uint64 internalFrameIndex; + ma_uint64 internalLengthInPCMFrames; ma_uint32 internalSampleRate; - result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate); + result = ma_data_source_get_length_in_pcm_frames(pDecoder->pBackend, &internalLengthInPCMFrames); if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the internal sample rate. */ + return result; /* Failed to retrieve the internal length. */ + } + + result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the internal sample rate. */ } if (internalSampleRate == pDecoder->outputSampleRate) { - internalFrameIndex = frameIndex; + *pLength = internalLengthInPCMFrames; } else { - internalFrameIndex = ma_calculate_frame_count_after_resampling(internalSampleRate, pDecoder->outputSampleRate, frameIndex); + *pLength = ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, internalSampleRate, internalLengthInPCMFrames); } - result = ma_data_source_seek_to_pcm_frame(pDecoder->pBackend, internalFrameIndex); - if (result == MA_SUCCESS) { - pDecoder->readPointerInPCMFrames = frameIndex; - } - - return result; + return MA_SUCCESS; + } else { + return MA_NO_BACKEND; } - - /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */ - return MA_INVALID_ARGS; } MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames) { + ma_result result; ma_uint64 totalFrameCount; if (pAvailableFrames == NULL) { @@ -51495,9 +62528,9 @@ MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64 return MA_INVALID_ARGS; } - totalFrameCount = ma_decoder_get_length_in_pcm_frames(pDecoder); - if (totalFrameCount == 0) { - return MA_NOT_IMPLEMENTED; + result = ma_decoder_get_length_in_pcm_frames(pDecoder, &totalFrameCount); + if (result != MA_SUCCESS) { + return result; } if (totalFrameCount <= pDecoder->readPointerInPCMFrames) { @@ -51506,12 +62539,13 @@ MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64 *pAvailableFrames = totalFrameCount - pDecoder->readPointerInPCMFrames; } - return MA_SUCCESS; /* No frames available. */ + return MA_SUCCESS; } static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_decoder_config* pConfigOut, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) { + ma_result result; ma_uint64 totalFrameCount; ma_uint64 bpf; ma_uint64 dataCapInFrames; @@ -51532,21 +62566,19 @@ static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_dec /* Make room if there's not enough. */ if (totalFrameCount == dataCapInFrames) { void* pNewPCMFramesOut; - ma_uint64 oldDataCapInFrames = dataCapInFrames; ma_uint64 newDataCapInFrames = dataCapInFrames*2; if (newDataCapInFrames == 0) { newDataCapInFrames = 4096; } if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) { - ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks); + ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); return MA_TOO_BIG; } - - pNewPCMFramesOut = (void*)ma__realloc_from_callbacks(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), (size_t)(oldDataCapInFrames * bpf), &pDecoder->allocationCallbacks); + pNewPCMFramesOut = (void*)ma_realloc(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), &pDecoder->allocationCallbacks); if (pNewPCMFramesOut == NULL) { - ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks); + ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); return MA_OUT_OF_MEMORY; } @@ -51557,9 +62589,13 @@ static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_dec frameCountToTryReading = dataCapInFrames - totalFrameCount; MA_ASSERT(frameCountToTryReading > 0); - framesJustRead = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading); + result = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading, &framesJustRead); totalFrameCount += framesJustRead; + if (result != MA_SUCCESS) { + break; + } + if (framesJustRead < frameCountToTryReading) { break; } @@ -51567,16 +62603,15 @@ static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_dec if (pConfigOut != NULL) { - pConfigOut->format = pDecoder->outputFormat; - pConfigOut->channels = pDecoder->outputChannels; + pConfigOut->format = pDecoder->outputFormat; + pConfigOut->channels = pDecoder->outputChannels; pConfigOut->sampleRate = pDecoder->outputSampleRate; - ma_channel_map_copy(pConfigOut->channelMap, pDecoder->outputChannelMap, pDecoder->outputChannels); } if (ppPCMFramesOut != NULL) { *ppPCMFramesOut = pPCMFramesOut; } else { - ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks); + ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); } if (pFrameCountOut != NULL) { @@ -51652,17 +62687,27 @@ MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder static size_t ma_encoder__internal_on_write_wav(void* pUserData, const void* pData, size_t bytesToWrite) { ma_encoder* pEncoder = (ma_encoder*)pUserData; + size_t bytesWritten = 0; + MA_ASSERT(pEncoder != NULL); - return pEncoder->onWrite(pEncoder, pData, bytesToWrite); + pEncoder->onWrite(pEncoder, pData, bytesToWrite, &bytesWritten); + return bytesWritten; } static drwav_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, drwav_seek_origin origin) { ma_encoder* pEncoder = (ma_encoder*)pUserData; + ma_result result; + MA_ASSERT(pEncoder != NULL); - return pEncoder->onSeek(pEncoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); + result = pEncoder->onSeek(pEncoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); + if (result != MA_SUCCESS) { + return DRWAV_FALSE; + } else { + return DRWAV_TRUE; + } } static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder) @@ -51673,7 +62718,7 @@ static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder) MA_ASSERT(pEncoder != NULL); - pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pEncoder->config.allocationCallbacks); + pWav = (drwav*)ma_malloc(sizeof(*pWav), &pEncoder->config.allocationCallbacks); if (pWav == NULL) { return MA_OUT_OF_MEMORY; } @@ -51712,28 +62757,35 @@ static void ma_encoder__on_uninit_wav(ma_encoder* pEncoder) MA_ASSERT(pWav != NULL); drwav_uninit(pWav); - ma__free_from_callbacks(pWav, &pEncoder->config.allocationCallbacks); + ma_free(pWav, &pEncoder->config.allocationCallbacks); } -static ma_uint64 ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount) +static ma_result ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten) { drwav* pWav; + ma_uint64 framesWritten; MA_ASSERT(pEncoder != NULL); pWav = (drwav*)pEncoder->pInternalEncoder; MA_ASSERT(pWav != NULL); - return drwav_write_pcm_frames(pWav, frameCount, pFramesIn); + framesWritten = drwav_write_pcm_frames(pWav, frameCount, pFramesIn); + + if (pFramesWritten != NULL) { + *pFramesWritten = framesWritten; + } + + return MA_SUCCESS; } #endif -MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +MA_API ma_encoder_config ma_encoder_config_init(ma_encoding_format encodingFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) { ma_encoder_config config; MA_ZERO_OBJECT(&config); - config.resourceFormat = resourceFormat; + config.encodingFormat = encodingFormat; config.format = format; config.channels = channels; config.sampleRate = sampleRate; @@ -51784,9 +62836,9 @@ MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_enc pEncoder->onSeek = onSeek; pEncoder->pUserData = pUserData; - switch (pEncoder->config.resourceFormat) + switch (pEncoder->config.encodingFormat) { - case ma_resource_format_wav: + case ma_encoding_format_wav: { #if defined(MA_HAS_WAV) pEncoder->onInit = ma_encoder__on_init_wav; @@ -51806,64 +62858,85 @@ MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_enc /* Getting here means we should have our backend callbacks set up. */ if (result == MA_SUCCESS) { result = pEncoder->onInit(pEncoder); - if (result != MA_SUCCESS) { - return result; - } + } + + return result; +} + +static ma_result ma_encoder__on_write_vfs(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite, size_t* pBytesWritten) +{ + return ma_vfs_or_default_write(pEncoder->data.vfs.pVFS, pEncoder->data.vfs.file, pBufferIn, bytesToWrite, pBytesWritten); +} + +static ma_result ma_encoder__on_seek_vfs(ma_encoder* pEncoder, ma_int64 offset, ma_seek_origin origin) +{ + return ma_vfs_or_default_seek(pEncoder->data.vfs.pVFS, pEncoder->data.vfs.file, offset, origin); +} + +MA_API ma_result ma_encoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) +{ + ma_result result; + ma_vfs_file file; + + result = ma_encoder_preinit(pConfig, pEncoder); + if (result != MA_SUCCESS) { + return result; + } + + /* Now open the file. If this fails we don't need to uninitialize the encoder. */ + result = ma_vfs_or_default_open(pVFS, pFilePath, MA_OPEN_MODE_WRITE, &file); + if (result != MA_SUCCESS) { + return result; + } + + pEncoder->data.vfs.pVFS = pVFS; + pEncoder->data.vfs.file = file; + + result = ma_encoder_init__internal(ma_encoder__on_write_vfs, ma_encoder__on_seek_vfs, NULL, pEncoder); + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, file); + return result; } return MA_SUCCESS; } -MA_API size_t ma_encoder__on_write_stdio(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite) +MA_API ma_result ma_encoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) { - return fwrite(pBufferIn, 1, bytesToWrite, (FILE*)pEncoder->pFile); -} + ma_result result; + ma_vfs_file file; -MA_API ma_bool32 ma_encoder__on_seek_stdio(ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin) -{ - return fseek((FILE*)pEncoder->pFile, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + result = ma_encoder_preinit(pConfig, pEncoder); + if (result != MA_SUCCESS) { + return result; + } + + /* Now open the file. If this fails we don't need to uninitialize the encoder. */ + result = ma_vfs_or_default_open_w(pVFS, pFilePath, MA_OPEN_MODE_WRITE, &file); + if (result != MA_SUCCESS) { + return result; + } + + pEncoder->data.vfs.pVFS = pVFS; + pEncoder->data.vfs.file = file; + + result = ma_encoder_init__internal(ma_encoder__on_write_vfs, ma_encoder__on_seek_vfs, NULL, pEncoder); + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, file); + return result; + } + + return MA_SUCCESS; } MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) { - ma_result result; - FILE* pFile; - - result = ma_encoder_preinit(pConfig, pEncoder); - if (result != MA_SUCCESS) { - return result; - } - - /* Now open the file. If this fails we don't need to uninitialize the encoder. */ - result = ma_fopen(&pFile, pFilePath, "wb"); - if (pFile == NULL) { - return result; - } - - pEncoder->pFile = pFile; - - return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder); + return ma_encoder_init_vfs(NULL, pFilePath, pConfig, pEncoder); } MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder) { - ma_result result; - FILE* pFile; - - result = ma_encoder_preinit(pConfig, pEncoder); - if (result != MA_SUCCESS) { - return result; - } - - /* Now open the file. If this fails we don't need to uninitialize the encoder. */ - result = ma_wfopen(&pFile, pFilePath, L"wb", &pEncoder->config.allocationCallbacks); - if (pFile == NULL) { - return result; - } - - pEncoder->pFile = pFile; - - return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder); + return ma_encoder_init_vfs_w(NULL, pFilePath, pConfig, pEncoder); } MA_API ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, const ma_encoder_config* pConfig, ma_encoder* pEncoder) @@ -51890,19 +62963,24 @@ MA_API void ma_encoder_uninit(ma_encoder* pEncoder) } /* If we have a file handle, close it. */ - if (pEncoder->onWrite == ma_encoder__on_write_stdio) { - fclose((FILE*)pEncoder->pFile); + if (pEncoder->onWrite == ma_encoder__on_write_vfs) { + ma_vfs_or_default_close(pEncoder->data.vfs.pVFS, pEncoder->data.vfs.file); + pEncoder->data.vfs.file = NULL; } } -MA_API ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount) +MA_API ma_result ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten) { - if (pEncoder == NULL || pFramesIn == NULL) { - return 0; + if (pFramesWritten != NULL) { + *pFramesWritten = 0; } - return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount); + if (pEncoder == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount, pFramesWritten); } #endif /* MA_NO_ENCODING */ @@ -51931,17 +63009,7 @@ MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 ch static ma_result ma_waveform__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { - ma_uint64 framesRead = ma_waveform_read_pcm_frames((ma_waveform*)pDataSource, pFramesOut, frameCount); - - if (pFramesRead != NULL) { - *pFramesRead = framesRead; - } - - if (framesRead == 0) { - return MA_AT_END; - } - - return MA_SUCCESS; + return ma_waveform_read_pcm_frames((ma_waveform*)pDataSource, pFramesOut, frameCount, pFramesRead); } static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) @@ -51949,13 +63017,14 @@ static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, m return ma_waveform_seek_to_pcm_frame((ma_waveform*)pDataSource, frameIndex); } -static ma_result ma_waveform__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_waveform__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { ma_waveform* pWaveform = (ma_waveform*)pDataSource; *pFormat = pWaveform->config.format; *pChannels = pWaveform->config.channels; *pSampleRate = pWaveform->config.sampleRate; + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pWaveform->config.channels); return MA_SUCCESS; } @@ -51983,11 +63052,11 @@ static ma_data_source_vtable g_ma_waveform_data_source_vtable = { ma_waveform__data_source_on_read, ma_waveform__data_source_on_seek, - NULL, /* onMap */ - NULL, /* onUnmap */ ma_waveform__data_source_on_get_data_format, ma_waveform__data_source_on_get_cursor, - NULL /* onGetLength. There's no notion of a length in waveforms. */ + NULL, /* onGetLength. There's no notion of a length in waveforms. */ + NULL, /* onSetLooping */ + 0 }; MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform) @@ -52296,10 +63365,18 @@ static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* } } -MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount) +MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pWaveform == NULL) { - return 0; + return MA_INVALID_ARGS; } if (pFramesOut != NULL) { @@ -52325,13 +63402,17 @@ MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFram ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount); } break; - default: return 0; + default: return MA_INVALID_OPERATION; /* Unknown waveform type. */ } } else { pWaveform->time += pWaveform->advance * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */ } - return frameCount; + if (pFramesRead != NULL) { + *pFramesRead = frameCount; + } + + return MA_SUCCESS; } MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex) @@ -52367,17 +63448,7 @@ MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels static ma_result ma_noise__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { - ma_uint64 framesRead = ma_noise_read_pcm_frames((ma_noise*)pDataSource, pFramesOut, frameCount); - - if (pFramesRead != NULL) { - *pFramesRead = framesRead; - } - - if (framesRead == 0) { - return MA_AT_END; - } - - return MA_SUCCESS; + return ma_noise_read_pcm_frames((ma_noise*)pDataSource, pFramesOut, frameCount, pFramesRead); } static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) @@ -52388,13 +63459,14 @@ static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_u return MA_SUCCESS; } -static ma_result ma_noise__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) +static ma_result ma_noise__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { ma_noise* pNoise = (ma_noise*)pDataSource; *pFormat = pNoise->config.format; *pChannels = pNoise->config.channels; *pSampleRate = 0; /* There is no notion of sample rate with noise generation. */ + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pNoise->config.channels); return MA_SUCCESS; } @@ -52403,17 +63475,105 @@ static ma_data_source_vtable g_ma_noise_data_source_vtable = { ma_noise__data_source_on_read, ma_noise__data_source_on_seek, /* No-op for noise. */ - NULL, /* onMap */ - NULL, /* onUnmap */ ma_noise__data_source_on_get_data_format, NULL, /* onGetCursor. No notion of a cursor for noise. */ - NULL /* onGetLength. No notion of a length for noise. */ + NULL, /* onGetLength. No notion of a length for noise. */ + NULL, /* onSetLooping */ + 0 }; -MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) + +#ifndef MA_PINK_NOISE_BIN_SIZE +#define MA_PINK_NOISE_BIN_SIZE 16 +#endif + +typedef struct +{ + size_t sizeInBytes; + struct + { + size_t binOffset; + size_t accumulationOffset; + size_t counterOffset; + } pink; + struct + { + size_t accumulationOffset; + } brownian; +} ma_noise_heap_layout; + +static ma_result ma_noise_get_heap_layout(const ma_noise_config* pConfig, ma_noise_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->channels == 0) { + return MA_INVALID_ARGS; + } + + pHeapLayout->sizeInBytes = 0; + + /* Pink. */ + if (pConfig->type == ma_noise_type_pink) { + /* bin */ + pHeapLayout->pink.binOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(double*) * pConfig->channels; + pHeapLayout->sizeInBytes += sizeof(double ) * pConfig->channels * MA_PINK_NOISE_BIN_SIZE; + + /* accumulation */ + pHeapLayout->pink.accumulationOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels; + + /* counter */ + pHeapLayout->pink.counterOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(ma_uint32) * pConfig->channels; + } + + /* Brownian. */ + if (pConfig->type == ma_noise_type_brownian) { + /* accumulation */ + pHeapLayout->brownian.accumulationOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels; + } + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes) { ma_result result; + ma_noise_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_noise_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise) +{ + ma_result result; + ma_noise_heap_layout heapLayout; ma_data_source_config dataSourceConfig; + ma_uint32 iChannel; if (pNoise == NULL) { return MA_INVALID_ARGS; @@ -52421,13 +63581,13 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) MA_ZERO_OBJECT(pNoise); - if (pConfig == NULL) { - return MA_INVALID_ARGS; + result = ma_noise_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; } - if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { - return MA_INVALID_ARGS; - } + pNoise->_pHeap = pHeap; + MA_ZERO_MEMORY(pNoise->_pHeap, heapLayout.sizeInBytes); dataSourceConfig = ma_data_source_config_init(); dataSourceConfig.vtable = &g_ma_noise_data_source_vtable; @@ -52441,15 +63601,20 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) ma_lcg_seed(&pNoise->lcg, pConfig->seed); if (pNoise->config.type == ma_noise_type_pink) { - ma_uint32 iChannel; + pNoise->state.pink.bin = (double** )ma_offset_ptr(pHeap, heapLayout.pink.binOffset); + pNoise->state.pink.accumulation = (double* )ma_offset_ptr(pHeap, heapLayout.pink.accumulationOffset); + pNoise->state.pink.counter = (ma_uint32*)ma_offset_ptr(pHeap, heapLayout.pink.counterOffset); + for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { + pNoise->state.pink.bin[iChannel] = (double*)ma_offset_ptr(pHeap, heapLayout.pink.binOffset + (sizeof(double*) * pConfig->channels) + (sizeof(double) * MA_PINK_NOISE_BIN_SIZE * iChannel)); pNoise->state.pink.accumulation[iChannel] = 0; pNoise->state.pink.counter[iChannel] = 1; } } if (pNoise->config.type == ma_noise_type_brownian) { - ma_uint32 iChannel; + pNoise->state.brownian.accumulation = (double*)ma_offset_ptr(pHeap, heapLayout.brownian.accumulationOffset); + for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { pNoise->state.brownian.accumulation[iChannel] = 0; } @@ -52458,13 +63623,47 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) return MA_SUCCESS; } -MA_API void ma_noise_uninit(ma_noise* pNoise) +MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_noise_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_noise_init_preallocated(pConfig, pHeap, pNoise); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pNoise->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks) { if (pNoise == NULL) { return; } ma_data_source_uninit(&pNoise->ds); + + if (pNoise->_ownsHeap) { + ma_free(pNoise->_pHeap, pAllocationCallbacks); + } } MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude) @@ -52513,7 +63712,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, voi ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -52607,7 +63806,7 @@ static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel) double binNext; unsigned int ibin; - ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (ma_countof(pNoise->state.pink.bin[0]) - 1); + ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (MA_PINK_NOISE_BIN_SIZE - 1); binPrev = pNoise->state.pink.bin[iChannel][ibin]; binNext = ma_lcg_rand_f64(&pNoise->lcg); @@ -52632,7 +63831,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -52714,7 +63913,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; - MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + MA_ASSUME(channels > 0); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -52772,37 +63971,9798 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, return frameCount; } -MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount) +MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { + ma_uint64 framesRead = 0; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pNoise == NULL) { - return 0; + return MA_INVALID_ARGS; } /* The output buffer is allowed to be NULL. Since we aren't tracking cursors or anything we can just do nothing and pretend to be successful. */ if (pFramesOut == NULL) { - return frameCount; + framesRead = frameCount; + } else { + switch (pNoise->config.type) { + case ma_noise_type_white: framesRead = ma_noise_read_pcm_frames__white (pNoise, pFramesOut, frameCount); break; + case ma_noise_type_pink: framesRead = ma_noise_read_pcm_frames__pink (pNoise, pFramesOut, frameCount); break; + case ma_noise_type_brownian: framesRead = ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount); break; + default: return MA_INVALID_OPERATION; /* Unknown noise type. */ + } } - if (pNoise->config.type == ma_noise_type_white) { - return ma_noise_read_pcm_frames__white(pNoise, pFramesOut, frameCount); + if (pFramesRead != NULL) { + *pFramesRead = framesRead; } - if (pNoise->config.type == ma_noise_type_pink) { - return ma_noise_read_pcm_frames__pink(pNoise, pFramesOut, frameCount); - } - - if (pNoise->config.type == ma_noise_type_brownian) { - return ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount); - } - - /* Should never get here. */ - MA_ASSERT(MA_FALSE); - return 0; + return MA_SUCCESS; } #endif /* MA_NO_GENERATION */ +#ifndef MA_NO_RESOURCE_MANAGER +#ifndef MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS +#define MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS 1000 +#endif + +#ifndef MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY +#define MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY 1024 +#endif + +MA_API ma_resource_manager_pipeline_notifications ma_resource_manager_pipeline_notifications_init(void) +{ + ma_resource_manager_pipeline_notifications notifications; + + MA_ZERO_OBJECT(¬ifications); + + return notifications; +} + +static void ma_resource_manager_pipeline_notifications_signal_all_notifications(const ma_resource_manager_pipeline_notifications* pPipelineNotifications) +{ + if (pPipelineNotifications == NULL) { + return; + } + + if (pPipelineNotifications->init.pNotification) { ma_async_notification_signal(pPipelineNotifications->init.pNotification); } + if (pPipelineNotifications->done.pNotification) { ma_async_notification_signal(pPipelineNotifications->done.pNotification); } +} + +static void ma_resource_manager_pipeline_notifications_acquire_all_fences(const ma_resource_manager_pipeline_notifications* pPipelineNotifications) +{ + if (pPipelineNotifications == NULL) { + return; + } + + if (pPipelineNotifications->init.pFence != NULL) { ma_fence_acquire(pPipelineNotifications->init.pFence); } + if (pPipelineNotifications->done.pFence != NULL) { ma_fence_acquire(pPipelineNotifications->done.pFence); } +} + +static void ma_resource_manager_pipeline_notifications_release_all_fences(const ma_resource_manager_pipeline_notifications* pPipelineNotifications) +{ + if (pPipelineNotifications == NULL) { + return; + } + + if (pPipelineNotifications->init.pFence != NULL) { ma_fence_release(pPipelineNotifications->init.pFence); } + if (pPipelineNotifications->done.pFence != NULL) { ma_fence_release(pPipelineNotifications->done.pFence); } +} + + + +#ifndef MA_DEFAULT_HASH_SEED +#define MA_DEFAULT_HASH_SEED 42 +#endif + +/* MurmurHash3. Based on code from https://github.com/PeterScott/murmur3/blob/master/murmur3.c (public domain). */ +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #if __GNUC__ >= 7 + #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + #endif +#endif + +static MA_INLINE ma_uint32 ma_rotl32(ma_uint32 x, ma_int8 r) +{ + return (x << r) | (x >> (32 - r)); +} + +static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i) +{ + if (ma_is_little_endian()) { + return blocks[i]; + } else { + return ma_swap_endian_uint32(blocks[i]); + } +} + +static MA_INLINE ma_uint32 ma_hash_fmix32(ma_uint32 h) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +static ma_uint32 ma_hash_32(const void* key, int len, ma_uint32 seed) +{ + const ma_uint8* data = (const ma_uint8*)key; + const ma_uint32* blocks; + const ma_uint8* tail; + const int nblocks = len / 4; + ma_uint32 h1 = seed; + ma_uint32 c1 = 0xcc9e2d51; + ma_uint32 c2 = 0x1b873593; + ma_uint32 k1; + int i; + + blocks = (const ma_uint32 *)(data + nblocks*4); + + for(i = -nblocks; i; i++) { + k1 = ma_hash_getblock(blocks,i); + + k1 *= c1; + k1 = ma_rotl32(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = ma_rotl32(h1, 13); + h1 = h1*5 + 0xe6546b64; + } + + + tail = (const ma_uint8*)(data + nblocks*4); + + k1 = 0; + switch(len & 3) { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: k1 ^= tail[0]; + k1 *= c1; k1 = ma_rotl32(k1, 15); k1 *= c2; h1 ^= k1; + }; + + + h1 ^= len; + h1 = ma_hash_fmix32(h1); + + return h1; +} + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push +#endif +/* End MurmurHash3 */ + +static ma_uint32 ma_hash_string_32(const char* str) +{ + return ma_hash_32(str, (int)strlen(str), MA_DEFAULT_HASH_SEED); +} + +static ma_uint32 ma_hash_string_w_32(const wchar_t* str) +{ + return ma_hash_32(str, (int)wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); +} + + + + +/* +Basic BST Functions +*/ +static ma_result ma_resource_manager_data_buffer_node_search(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_resource_manager_data_buffer_node** ppDataBufferNode) +{ + ma_resource_manager_data_buffer_node* pCurrentNode; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(ppDataBufferNode != NULL); + + pCurrentNode = pResourceManager->pRootDataBufferNode; + while (pCurrentNode != NULL) { + if (hashedName32 == pCurrentNode->hashedName32) { + break; /* Found. */ + } else if (hashedName32 < pCurrentNode->hashedName32) { + pCurrentNode = pCurrentNode->pChildLo; + } else { + pCurrentNode = pCurrentNode->pChildHi; + } + } + + *ppDataBufferNode = pCurrentNode; + + if (pCurrentNode == NULL) { + return MA_DOES_NOT_EXIST; + } else { + return MA_SUCCESS; + } +} + +static ma_result ma_resource_manager_data_buffer_node_insert_point(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_resource_manager_data_buffer_node** ppInsertPoint) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager_data_buffer_node* pCurrentNode; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(ppInsertPoint != NULL); + + *ppInsertPoint = NULL; + + if (pResourceManager->pRootDataBufferNode == NULL) { + return MA_SUCCESS; /* No items. */ + } + + /* We need to find the node that will become the parent of the new node. If a node is found that already has the same hashed name we need to return MA_ALREADY_EXISTS. */ + pCurrentNode = pResourceManager->pRootDataBufferNode; + while (pCurrentNode != NULL) { + if (hashedName32 == pCurrentNode->hashedName32) { + result = MA_ALREADY_EXISTS; + break; + } else { + if (hashedName32 < pCurrentNode->hashedName32) { + if (pCurrentNode->pChildLo == NULL) { + result = MA_SUCCESS; + break; + } else { + pCurrentNode = pCurrentNode->pChildLo; + } + } else { + if (pCurrentNode->pChildHi == NULL) { + result = MA_SUCCESS; + break; + } else { + pCurrentNode = pCurrentNode->pChildHi; + } + } + } + } + + *ppInsertPoint = pCurrentNode; + return result; +} + +static ma_result ma_resource_manager_data_buffer_node_insert_at(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_resource_manager_data_buffer_node* pInsertPoint) +{ + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + + /* The key must have been set before calling this function. */ + MA_ASSERT(pDataBufferNode->hashedName32 != 0); + + if (pInsertPoint == NULL) { + /* It's the first node. */ + pResourceManager->pRootDataBufferNode = pDataBufferNode; + } else { + /* It's not the first node. It needs to be inserted. */ + if (pDataBufferNode->hashedName32 < pInsertPoint->hashedName32) { + MA_ASSERT(pInsertPoint->pChildLo == NULL); + pInsertPoint->pChildLo = pDataBufferNode; + } else { + MA_ASSERT(pInsertPoint->pChildHi == NULL); + pInsertPoint->pChildHi = pDataBufferNode; + } + } + + pDataBufferNode->pParent = pInsertPoint; + + return MA_SUCCESS; +} + +#if 0 /* Unused for now. */ +static ma_result ma_resource_manager_data_buffer_node_insert(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + ma_result result; + ma_resource_manager_data_buffer_node* pInsertPoint; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + + result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, pDataBufferNode->hashedName32, &pInsertPoint); + if (result != MA_SUCCESS) { + return MA_INVALID_ARGS; + } + + return ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint); +} +#endif + +static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_min(ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + ma_resource_manager_data_buffer_node* pCurrentNode; + + MA_ASSERT(pDataBufferNode != NULL); + + pCurrentNode = pDataBufferNode; + while (pCurrentNode->pChildLo != NULL) { + pCurrentNode = pCurrentNode->pChildLo; + } + + return pCurrentNode; +} + +static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_max(ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + ma_resource_manager_data_buffer_node* pCurrentNode; + + MA_ASSERT(pDataBufferNode != NULL); + + pCurrentNode = pDataBufferNode; + while (pCurrentNode->pChildHi != NULL) { + pCurrentNode = pCurrentNode->pChildHi; + } + + return pCurrentNode; +} + +static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_successor(ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + MA_ASSERT(pDataBufferNode != NULL); + MA_ASSERT(pDataBufferNode->pChildHi != NULL); + + return ma_resource_manager_data_buffer_node_find_min(pDataBufferNode->pChildHi); +} + +static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_predecessor(ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + MA_ASSERT(pDataBufferNode != NULL); + MA_ASSERT(pDataBufferNode->pChildLo != NULL); + + return ma_resource_manager_data_buffer_node_find_max(pDataBufferNode->pChildLo); +} + +static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + + if (pDataBufferNode->pChildLo == NULL) { + if (pDataBufferNode->pChildHi == NULL) { + /* Simple case - deleting a buffer with no children. */ + if (pDataBufferNode->pParent == NULL) { + MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode); /* There is only a single buffer in the tree which should be equal to the root node. */ + pResourceManager->pRootDataBufferNode = NULL; + } else { + if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { + pDataBufferNode->pParent->pChildLo = NULL; + } else { + pDataBufferNode->pParent->pChildHi = NULL; + } + } + } else { + /* Node has one child - pChildHi != NULL. */ + pDataBufferNode->pChildHi->pParent = pDataBufferNode->pParent; + + if (pDataBufferNode->pParent == NULL) { + MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode); + pResourceManager->pRootDataBufferNode = pDataBufferNode->pChildHi; + } else { + if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { + pDataBufferNode->pParent->pChildLo = pDataBufferNode->pChildHi; + } else { + pDataBufferNode->pParent->pChildHi = pDataBufferNode->pChildHi; + } + } + } + } else { + if (pDataBufferNode->pChildHi == NULL) { + /* Node has one child - pChildLo != NULL. */ + pDataBufferNode->pChildLo->pParent = pDataBufferNode->pParent; + + if (pDataBufferNode->pParent == NULL) { + MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode); + pResourceManager->pRootDataBufferNode = pDataBufferNode->pChildLo; + } else { + if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { + pDataBufferNode->pParent->pChildLo = pDataBufferNode->pChildLo; + } else { + pDataBufferNode->pParent->pChildHi = pDataBufferNode->pChildLo; + } + } + } else { + /* Complex case - deleting a node with two children. */ + ma_resource_manager_data_buffer_node* pReplacementDataBufferNode; + + /* For now we are just going to use the in-order successor as the replacement, but we may want to try to keep this balanced by switching between the two. */ + pReplacementDataBufferNode = ma_resource_manager_data_buffer_node_find_inorder_successor(pDataBufferNode); + MA_ASSERT(pReplacementDataBufferNode != NULL); + + /* + Now that we have our replacement node we can make the change. The simple way to do this would be to just exchange the values, and then remove the replacement + node, however we track specific nodes via pointers which means we can't just swap out the values. We need to instead just change the pointers around. The + replacement node should have at most 1 child. Therefore, we can detach it in terms of our simpler cases above. What we're essentially doing is detaching the + replacement node and reinserting it into the same position as the deleted node. + */ + MA_ASSERT(pReplacementDataBufferNode->pParent != NULL); /* The replacement node should never be the root which means it should always have a parent. */ + MA_ASSERT(pReplacementDataBufferNode->pChildLo == NULL); /* Because we used in-order successor. This would be pChildHi == NULL if we used in-order predecessor. */ + + if (pReplacementDataBufferNode->pChildHi == NULL) { + if (pReplacementDataBufferNode->pParent->pChildLo == pReplacementDataBufferNode) { + pReplacementDataBufferNode->pParent->pChildLo = NULL; + } else { + pReplacementDataBufferNode->pParent->pChildHi = NULL; + } + } else { + pReplacementDataBufferNode->pChildHi->pParent = pReplacementDataBufferNode->pParent; + if (pReplacementDataBufferNode->pParent->pChildLo == pReplacementDataBufferNode) { + pReplacementDataBufferNode->pParent->pChildLo = pReplacementDataBufferNode->pChildHi; + } else { + pReplacementDataBufferNode->pParent->pChildHi = pReplacementDataBufferNode->pChildHi; + } + } + + + /* The replacement node has essentially been detached from the binary tree, so now we need to replace the old data buffer with it. The first thing to update is the parent */ + if (pDataBufferNode->pParent != NULL) { + if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) { + pDataBufferNode->pParent->pChildLo = pReplacementDataBufferNode; + } else { + pDataBufferNode->pParent->pChildHi = pReplacementDataBufferNode; + } + } + + /* Now need to update the replacement node's pointers. */ + pReplacementDataBufferNode->pParent = pDataBufferNode->pParent; + pReplacementDataBufferNode->pChildLo = pDataBufferNode->pChildLo; + pReplacementDataBufferNode->pChildHi = pDataBufferNode->pChildHi; + + /* Now the children of the replacement node need to have their parent pointers updated. */ + if (pReplacementDataBufferNode->pChildLo != NULL) { + pReplacementDataBufferNode->pChildLo->pParent = pReplacementDataBufferNode; + } + if (pReplacementDataBufferNode->pChildHi != NULL) { + pReplacementDataBufferNode->pChildHi->pParent = pReplacementDataBufferNode; + } + + /* Now the root node needs to be updated. */ + if (pResourceManager->pRootDataBufferNode == pDataBufferNode) { + pResourceManager->pRootDataBufferNode = pReplacementDataBufferNode; + } + } + } + + return MA_SUCCESS; +} + +#if 0 /* Unused for now. */ +static ma_result ma_resource_manager_data_buffer_node_remove_by_key(ma_resource_manager* pResourceManager, ma_uint32 hashedName32) +{ + ma_result result; + ma_resource_manager_data_buffer_node* pDataBufferNode; + + result = ma_resource_manager_data_buffer_search(pResourceManager, hashedName32, &pDataBufferNode); + if (result != MA_SUCCESS) { + return result; /* Could not find the data buffer. */ + } + + return ma_resource_manager_data_buffer_remove(pResourceManager, pDataBufferNode); +} +#endif + +static ma_resource_manager_data_supply_type ma_resource_manager_data_buffer_node_get_data_supply_type(ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + return (ma_resource_manager_data_supply_type)c89atomic_load_i32(&pDataBufferNode->data.type); +} + +static void ma_resource_manager_data_buffer_node_set_data_supply_type(ma_resource_manager_data_buffer_node* pDataBufferNode, ma_resource_manager_data_supply_type supplyType) +{ + c89atomic_exchange_i32(&pDataBufferNode->data.type, supplyType); +} + +static ma_result ma_resource_manager_data_buffer_node_increment_ref(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_uint32* pNewRefCount) +{ + ma_uint32 refCount; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + + (void)pResourceManager; + + refCount = c89atomic_fetch_add_32(&pDataBufferNode->refCount, 1) + 1; + + if (pNewRefCount != NULL) { + *pNewRefCount = refCount; + } + + return MA_SUCCESS; +} + +static ma_result ma_resource_manager_data_buffer_node_decrement_ref(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_uint32* pNewRefCount) +{ + ma_uint32 refCount; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + + (void)pResourceManager; + + refCount = c89atomic_fetch_sub_32(&pDataBufferNode->refCount, 1) - 1; + + if (pNewRefCount != NULL) { + *pNewRefCount = refCount; + } + + return MA_SUCCESS; +} + +static void ma_resource_manager_data_buffer_node_free(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + + if (pDataBufferNode->isDataOwnedByResourceManager) { + if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_encoded) { + ma_free((void*)pDataBufferNode->data.backend.encoded.pData, &pResourceManager->config.allocationCallbacks); + pDataBufferNode->data.backend.encoded.pData = NULL; + pDataBufferNode->data.backend.encoded.sizeInBytes = 0; + } else if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_decoded) { + ma_free((void*)pDataBufferNode->data.backend.decoded.pData, &pResourceManager->config.allocationCallbacks); + pDataBufferNode->data.backend.decoded.pData = NULL; + pDataBufferNode->data.backend.decoded.totalFrameCount = 0; + } else if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_decoded_paged) { + ma_paged_audio_buffer_data_uninit(&pDataBufferNode->data.backend.decodedPaged.data, &pResourceManager->config.allocationCallbacks); + } else { + /* Should never hit this if the node was successfully initialized. */ + MA_ASSERT(pDataBufferNode->result != MA_SUCCESS); + } + } + + /* The data buffer itself needs to be freed. */ + ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); +} + +static ma_result ma_resource_manager_data_buffer_node_result(const ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + MA_ASSERT(pDataBufferNode != NULL); + + return (ma_result)c89atomic_load_i32((ma_result*)&pDataBufferNode->result); /* Need a naughty const-cast here. */ +} + + +static ma_bool32 ma_resource_manager_is_threading_enabled(const ma_resource_manager* pResourceManager) +{ + MA_ASSERT(pResourceManager != NULL); + + return (pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) == 0; +} + + +typedef struct +{ + union + { + ma_async_notification_event e; + ma_async_notification_poll p; + } backend; /* Must be the first member. */ + ma_resource_manager* pResourceManager; +} ma_resource_manager_inline_notification; + +static ma_result ma_resource_manager_inline_notification_init(ma_resource_manager* pResourceManager, ma_resource_manager_inline_notification* pNotification) +{ + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pNotification != NULL); + + pNotification->pResourceManager = pResourceManager; + + if (ma_resource_manager_is_threading_enabled(pResourceManager)) { + return ma_async_notification_event_init(&pNotification->backend.e); + } else { + return ma_async_notification_poll_init(&pNotification->backend.p); + } +} + +static void ma_resource_manager_inline_notification_uninit(ma_resource_manager_inline_notification* pNotification) +{ + MA_ASSERT(pNotification != NULL); + + if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) { + ma_async_notification_event_uninit(&pNotification->backend.e); + } else { + /* No need to uninitialize a polling notification. */ + } +} + +static void ma_resource_manager_inline_notification_wait(ma_resource_manager_inline_notification* pNotification) +{ + MA_ASSERT(pNotification != NULL); + + if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) { + ma_async_notification_event_wait(&pNotification->backend.e); + } else { + while (ma_async_notification_poll_is_signalled(&pNotification->backend.p) == MA_FALSE) { + ma_result result = ma_resource_manager_process_next_job(pNotification->pResourceManager); + if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) { + break; + } + } + } +} + +static void ma_resource_manager_inline_notification_wait_and_uninit(ma_resource_manager_inline_notification* pNotification) +{ + ma_resource_manager_inline_notification_wait(pNotification); + ma_resource_manager_inline_notification_uninit(pNotification); +} + + +static void ma_resource_manager_data_buffer_bst_lock(ma_resource_manager* pResourceManager) +{ + MA_ASSERT(pResourceManager != NULL); + + if (ma_resource_manager_is_threading_enabled(pResourceManager)) { + #ifndef MA_NO_THREADING + { + ma_mutex_lock(&pResourceManager->dataBufferBSTLock); + } + #else + { + MA_ASSERT(MA_FALSE); /* Should never hit this. */ + } + #endif + } else { + /* Threading not enabled. Do nothing. */ + } +} + +static void ma_resource_manager_data_buffer_bst_unlock(ma_resource_manager* pResourceManager) +{ + MA_ASSERT(pResourceManager != NULL); + + if (ma_resource_manager_is_threading_enabled(pResourceManager)) { + #ifndef MA_NO_THREADING + { + ma_mutex_unlock(&pResourceManager->dataBufferBSTLock); + } + #else + { + MA_ASSERT(MA_FALSE); /* Should never hit this. */ + } + #endif + } else { + /* Threading not enabled. Do nothing. */ + } +} + +#ifndef MA_NO_THREADING +static ma_thread_result MA_THREADCALL ma_resource_manager_job_thread(void* pUserData) +{ + ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData; + MA_ASSERT(pResourceManager != NULL); + + for (;;) { + ma_result result; + ma_job job; + + result = ma_resource_manager_next_job(pResourceManager, &job); + if (result != MA_SUCCESS) { + break; + } + + /* Terminate if we got a quit message. */ + if (job.toc.breakup.code == MA_JOB_TYPE_QUIT) { + break; + } + + ma_job_process(&job); + } + + return (ma_thread_result)0; +} +#endif + +MA_API ma_resource_manager_config ma_resource_manager_config_init(void) +{ + ma_resource_manager_config config; + + MA_ZERO_OBJECT(&config); + config.decodedFormat = ma_format_unknown; + config.decodedChannels = 0; + config.decodedSampleRate = 0; + config.jobThreadCount = 1; /* A single miniaudio-managed job thread by default. */ + config.jobQueueCapacity = MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY; + + /* Flags. */ + config.flags = 0; + #ifdef MA_NO_THREADING + { + /* Threading is disabled at compile time so disable threading at runtime as well by default. */ + config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; + config.jobThreadCount = 0; + } + #endif + + return config; +} + + +MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager) +{ + ma_result result; + ma_job_queue_config jobQueueConfig; + + if (pResourceManager == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pResourceManager); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + #ifndef MA_NO_THREADING + { + if (pConfig->jobThreadCount > ma_countof(pResourceManager->jobThreads)) { + return MA_INVALID_ARGS; /* Requesting too many job threads. */ + } + } + #endif + + pResourceManager->config = *pConfig; + ma_allocation_callbacks_init_copy(&pResourceManager->config.allocationCallbacks, &pConfig->allocationCallbacks); + + /* Get the log set up early so we can start using it as soon as possible. */ + if (pResourceManager->config.pLog == NULL) { + result = ma_log_init(&pResourceManager->config.allocationCallbacks, &pResourceManager->log); + if (result == MA_SUCCESS) { + pResourceManager->config.pLog = &pResourceManager->log; + } else { + pResourceManager->config.pLog = NULL; /* Logging is unavailable. */ + } + } + + if (pResourceManager->config.pVFS == NULL) { + result = ma_default_vfs_init(&pResourceManager->defaultVFS, &pResourceManager->config.allocationCallbacks); + if (result != MA_SUCCESS) { + return result; /* Failed to initialize the default file system. */ + } + + pResourceManager->config.pVFS = &pResourceManager->defaultVFS; + } + + /* If threading has been disabled at compile time, enfore it at run time as well. */ + #ifdef MA_NO_THREADING + { + pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; + } + #endif + + /* We need to force MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING if MA_RESOURCE_MANAGER_FLAG_NO_THREADING is set. */ + if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) { + pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; + + /* We cannot allow job threads when MA_RESOURCE_MANAGER_FLAG_NO_THREADING has been set. This is an invalid use case. */ + if (pResourceManager->config.jobThreadCount > 0) { + return MA_INVALID_ARGS; + } + } + + /* Job queue. */ + jobQueueConfig.capacity = pResourceManager->config.jobQueueCapacity; + jobQueueConfig.flags = 0; + if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING) != 0) { + if (pResourceManager->config.jobThreadCount > 0) { + return MA_INVALID_ARGS; /* Non-blocking mode is only valid for self-managed job threads. */ + } + + jobQueueConfig.flags |= MA_JOB_QUEUE_FLAG_NON_BLOCKING; + } + + result = ma_job_queue_init(&jobQueueConfig, &pResourceManager->config.allocationCallbacks, &pResourceManager->jobQueue); + if (result != MA_SUCCESS) { + return result; + } + + + /* Custom decoding backends. */ + if (pConfig->ppCustomDecodingBackendVTables != NULL && pConfig->customDecodingBackendCount > 0) { + size_t sizeInBytes = sizeof(*pResourceManager->config.ppCustomDecodingBackendVTables) * pConfig->customDecodingBackendCount; + + pResourceManager->config.ppCustomDecodingBackendVTables = (ma_decoding_backend_vtable**)ma_malloc(sizeInBytes, &pResourceManager->config.allocationCallbacks); + if (pResourceManager->config.ppCustomDecodingBackendVTables == NULL) { + ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + + MA_COPY_MEMORY(pResourceManager->config.ppCustomDecodingBackendVTables, pConfig->ppCustomDecodingBackendVTables, sizeInBytes); + + pResourceManager->config.customDecodingBackendCount = pConfig->customDecodingBackendCount; + pResourceManager->config.pCustomDecodingBackendUserData = pConfig->pCustomDecodingBackendUserData; + } + + + + /* Here is where we initialize our threading stuff. We don't do this if we don't support threading. */ + if (ma_resource_manager_is_threading_enabled(pResourceManager)) { + #ifndef MA_NO_THREADING + { + ma_uint32 iJobThread; + + /* Data buffer lock. */ + result = ma_mutex_init(&pResourceManager->dataBufferBSTLock); + if (result != MA_SUCCESS) { + ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); + return result; + } + + /* Create the job threads last to ensure the threads has access to valid data. */ + for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) { + result = ma_thread_create(&pResourceManager->jobThreads[iJobThread], ma_thread_priority_normal, 0, ma_resource_manager_job_thread, pResourceManager, &pResourceManager->config.allocationCallbacks); + if (result != MA_SUCCESS) { + ma_mutex_uninit(&pResourceManager->dataBufferBSTLock); + ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); + return result; + } + } + } + #else + { + /* Threading is disabled at compile time. We should never get here because validation checks should have already been performed. */ + MA_ASSERT(MA_FALSE); + } + #endif + } + + return MA_SUCCESS; +} + + +static void ma_resource_manager_delete_all_data_buffer_nodes(ma_resource_manager* pResourceManager) +{ + MA_ASSERT(pResourceManager); + + /* If everything was done properly, there shouldn't be any active data buffers. */ + while (pResourceManager->pRootDataBufferNode != NULL) { + ma_resource_manager_data_buffer_node* pDataBufferNode = pResourceManager->pRootDataBufferNode; + ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); + + /* The data buffer has been removed from the BST, so now we need to free it's data. */ + ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); + } +} + +MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager) +{ + if (pResourceManager == NULL) { + return; + } + + /* + Job threads need to be killed first. To do this we need to post a quit message to the message queue and then wait for the thread. The quit message will never be removed from the + queue which means it will never not be returned after being encounted for the first time which means all threads will eventually receive it. + */ + ma_resource_manager_post_job_quit(pResourceManager); + + /* Wait for every job to finish before continuing to ensure nothing is sill trying to access any of our objects below. */ + if (ma_resource_manager_is_threading_enabled(pResourceManager)) { + #ifndef MA_NO_THREADING + { + ma_uint32 iJobThread; + + for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) { + ma_thread_wait(&pResourceManager->jobThreads[iJobThread]); + } + } + #else + { + MA_ASSERT(MA_FALSE); /* Should never hit this. */ + } + #endif + } + + /* At this point the thread should have returned and no other thread should be accessing our data. We can now delete all data buffers. */ + ma_resource_manager_delete_all_data_buffer_nodes(pResourceManager); + + /* The job queue is no longer needed. */ + ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); + + /* We're no longer doing anything with data buffers so the lock can now be uninitialized. */ + if (ma_resource_manager_is_threading_enabled(pResourceManager)) { + #ifndef MA_NO_THREADING + { + ma_mutex_uninit(&pResourceManager->dataBufferBSTLock); + } + #else + { + MA_ASSERT(MA_FALSE); /* Should never hit this. */ + } + #endif + } + + ma_free(pResourceManager->config.ppCustomDecodingBackendVTables, &pResourceManager->config.allocationCallbacks); + + if (pResourceManager->config.pLog == &pResourceManager->log) { + ma_log_uninit(&pResourceManager->log); + } +} + +MA_API ma_log* ma_resource_manager_get_log(ma_resource_manager* pResourceManager) +{ + if (pResourceManager == NULL) { + return NULL; + } + + return pResourceManager->config.pLog; +} + + + +MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_config_init(void) +{ + ma_resource_manager_data_source_config config; + + MA_ZERO_OBJECT(&config); + config.rangeEndInPCMFrames = ~((ma_uint64)0); + config.loopPointEndInPCMFrames = ~((ma_uint64)0); + + return config; +} + + +static ma_decoder_config ma_resource_manager__init_decoder_config(ma_resource_manager* pResourceManager) +{ + ma_decoder_config config; + + config = ma_decoder_config_init(pResourceManager->config.decodedFormat, pResourceManager->config.decodedChannels, pResourceManager->config.decodedSampleRate); + config.allocationCallbacks = pResourceManager->config.allocationCallbacks; + config.ppCustomBackendVTables = pResourceManager->config.ppCustomDecodingBackendVTables; + config.customBackendCount = pResourceManager->config.customDecodingBackendCount; + config.pCustomBackendUserData = pResourceManager->config.pCustomDecodingBackendUserData; + + return config; +} + +static ma_result ma_resource_manager__init_decoder(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_decoder* pDecoder) +{ + ma_result result; + ma_decoder_config config; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pFilePath != NULL || pFilePathW != NULL); + MA_ASSERT(pDecoder != NULL); + + config = ma_resource_manager__init_decoder_config(pResourceManager); + + if (pFilePath != NULL) { + result = ma_decoder_init_vfs(pResourceManager->config.pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%s\". %s.\n", pFilePath, ma_result_description(result)); + return result; + } + } else { + result = ma_decoder_init_vfs_w(pResourceManager->config.pVFS, pFilePathW, &config, pDecoder); + if (result != MA_SUCCESS) { + #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%ls\". %s.\n", pFilePathW, ma_result_description(result)); + #endif + return result; + } + } + + return MA_SUCCESS; +} + +static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource_manager_data_buffer* pDataBuffer) +{ + switch (pDataBuffer->pNode->data.type) + { + case ma_resource_manager_data_supply_type_encoded: return &pDataBuffer->connector.decoder; + case ma_resource_manager_data_supply_type_decoded: return &pDataBuffer->connector.buffer; + case ma_resource_manager_data_supply_type_decoded_paged: return &pDataBuffer->connector.pagedBuffer; + + case ma_resource_manager_data_supply_type_unknown: + default: + { + ma_log_postf(ma_resource_manager_get_log(pDataBuffer->pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to retrieve data buffer connector. Unknown data supply type.\n"); + return NULL; + }; + }; +} + +static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_manager_data_buffer* pDataBuffer, const ma_resource_manager_data_source_config* pConfig, ma_async_notification* pInitNotification, ma_fence* pInitFence) +{ + ma_result result; + + MA_ASSERT(pDataBuffer != NULL); + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pDataBuffer->isConnectorInitialized == MA_FALSE); + + /* The underlying data buffer must be initialized before we'll be able to know how to initialize the backend. */ + result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode); + if (result != MA_SUCCESS && result != MA_BUSY) { + return result; /* The data buffer is in an erroneous state. */ + } + + /* + We need to initialize either a ma_decoder or an ma_audio_buffer depending on whether or not the backing data is encoded or decoded. These act as the + "instance" to the data and are used to form the connection between underlying data buffer and the data source. If the data buffer is decoded, we can use + an ma_audio_buffer. This enables us to use memory mapping when mixing which saves us a bit of data movement overhead. + */ + switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) + { + case ma_resource_manager_data_supply_type_encoded: /* Connector is a decoder. */ + { + ma_decoder_config config; + config = ma_resource_manager__init_decoder_config(pDataBuffer->pResourceManager); + result = ma_decoder_init_memory(pDataBuffer->pNode->data.backend.encoded.pData, pDataBuffer->pNode->data.backend.encoded.sizeInBytes, &config, &pDataBuffer->connector.decoder); + } break; + + case ma_resource_manager_data_supply_type_decoded: /* Connector is an audio buffer. */ + { + ma_audio_buffer_config config; + config = ma_audio_buffer_config_init(pDataBuffer->pNode->data.backend.decoded.format, pDataBuffer->pNode->data.backend.decoded.channels, pDataBuffer->pNode->data.backend.decoded.totalFrameCount, pDataBuffer->pNode->data.backend.decoded.pData, NULL); + result = ma_audio_buffer_init(&config, &pDataBuffer->connector.buffer); + } break; + + case ma_resource_manager_data_supply_type_decoded_paged: /* Connector is a paged audio buffer. */ + { + ma_paged_audio_buffer_config config; + config = ma_paged_audio_buffer_config_init(&pDataBuffer->pNode->data.backend.decodedPaged.data); + result = ma_paged_audio_buffer_init(&config, &pDataBuffer->connector.pagedBuffer); + } break; + + case ma_resource_manager_data_supply_type_unknown: + default: + { + /* Unknown data supply type. Should never happen. Need to post an error here. */ + return MA_INVALID_ARGS; + }; + } + + /* + Initialization of the connector is when we can fire the init notification. This will give the application access to + the format/channels/rate of the data source. + */ + if (result == MA_SUCCESS) { + /* + Make sure the looping state is set before returning in order to handle the case where the + loop state was set on the data buffer before the connector was initialized. + */ + ma_data_source_set_range_in_pcm_frames(pDataBuffer, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); + ma_data_source_set_loop_point_in_pcm_frames(pDataBuffer, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + ma_data_source_set_looping(pDataBuffer, pConfig->isLooping); + + pDataBuffer->isConnectorInitialized = MA_TRUE; + + if (pInitNotification != NULL) { + ma_async_notification_signal(pInitNotification); + } + + if (pInitFence != NULL) { + ma_fence_release(pInitFence); + } + } + + /* At this point the backend should be initialized. We do *not* want to set pDataSource->result here - that needs to be done at a higher level to ensure it's done as the last step. */ + return result; +} + +static ma_result ma_resource_manager_data_buffer_uninit_connector(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer* pDataBuffer) +{ + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBuffer != NULL); + + switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) + { + case ma_resource_manager_data_supply_type_encoded: /* Connector is a decoder. */ + { + ma_decoder_uninit(&pDataBuffer->connector.decoder); + } break; + + case ma_resource_manager_data_supply_type_decoded: /* Connector is an audio buffer. */ + { + ma_audio_buffer_uninit(&pDataBuffer->connector.buffer); + } break; + + case ma_resource_manager_data_supply_type_decoded_paged: /* Connector is a paged audio buffer. */ + { + ma_paged_audio_buffer_uninit(&pDataBuffer->connector.pagedBuffer); + } break; + + case ma_resource_manager_data_supply_type_unknown: + default: + { + /* Unknown data supply type. Should never happen. Need to post an error here. */ + return MA_INVALID_ARGS; + }; + } + + return MA_SUCCESS; +} + +static ma_uint32 ma_resource_manager_data_buffer_node_next_execution_order(ma_resource_manager_data_buffer_node* pDataBufferNode) +{ + MA_ASSERT(pDataBufferNode != NULL); + return c89atomic_fetch_add_32(&pDataBufferNode->executionCounter, 1); +} + +static ma_result ma_resource_manager_data_buffer_node_init_supply_encoded(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pFilePath, const wchar_t* pFilePathW) +{ + ma_result result; + size_t dataSizeInBytes; + void* pData; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + MA_ASSERT(pFilePath != NULL || pFilePathW != NULL); + + result = ma_vfs_open_and_read_file_ex(pResourceManager->config.pVFS, pFilePath, pFilePathW, &pData, &dataSizeInBytes, &pResourceManager->config.allocationCallbacks); + if (result != MA_SUCCESS) { + if (pFilePath != NULL) { + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%s\". %s.\n", pFilePath, ma_result_description(result)); + } else { + #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%ls\". %s.\n", pFilePathW, ma_result_description(result)); + #endif + } + + return result; + } + + pDataBufferNode->data.backend.encoded.pData = pData; + pDataBufferNode->data.backend.encoded.sizeInBytes = dataSizeInBytes; + ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_encoded); /* <-- Must be set last. */ + + return MA_SUCCESS; +} + +static ma_result ma_resource_manager_data_buffer_node_init_supply_decoded(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 flags, ma_decoder** ppDecoder) +{ + ma_result result = MA_SUCCESS; + ma_decoder* pDecoder; + ma_uint64 totalFrameCount; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + MA_ASSERT(ppDecoder != NULL); + MA_ASSERT(pFilePath != NULL || pFilePathW != NULL); + + *ppDecoder = NULL; /* For safety. */ + + pDecoder = (ma_decoder*)ma_malloc(sizeof(*pDecoder), &pResourceManager->config.allocationCallbacks); + if (pDecoder == NULL) { + return MA_OUT_OF_MEMORY; + } + + result = ma_resource_manager__init_decoder(pResourceManager, pFilePath, pFilePathW, pDecoder); + if (result != MA_SUCCESS) { + ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); + return result; + } + + /* + At this point we have the decoder and we now need to initialize the data supply. This will + be either a decoded buffer, or a decoded paged buffer. A regular buffer is just one big heap + allocated buffer, whereas a paged buffer is a linked list of paged-sized buffers. The latter + is used when the length of a sound is unknown until a full decode has been performed. + */ + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH) == 0) { + result = ma_decoder_get_length_in_pcm_frames(pDecoder, &totalFrameCount); + if (result != MA_SUCCESS) { + return result; + } + } else { + totalFrameCount = 0; + } + + if (totalFrameCount > 0) { + /* It's a known length. The data supply is a regular decoded buffer. */ + ma_uint64 dataSizeInBytes; + void* pData; + + dataSizeInBytes = totalFrameCount * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels); + if (dataSizeInBytes > MA_SIZE_MAX) { + ma_decoder_uninit(pDecoder); + ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); + return MA_TOO_BIG; + } + + pData = ma_malloc((size_t)dataSizeInBytes, &pResourceManager->config.allocationCallbacks); + if (pData == NULL) { + ma_decoder_uninit(pDecoder); + ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + + /* The buffer needs to be initialized to silence in case the caller reads from it. */ + ma_silence_pcm_frames(pData, totalFrameCount, pDecoder->outputFormat, pDecoder->outputChannels); + + /* Data has been allocated and the data supply can now be initialized. */ + pDataBufferNode->data.backend.decoded.pData = pData; + pDataBufferNode->data.backend.decoded.totalFrameCount = totalFrameCount; + pDataBufferNode->data.backend.decoded.format = pDecoder->outputFormat; + pDataBufferNode->data.backend.decoded.channels = pDecoder->outputChannels; + pDataBufferNode->data.backend.decoded.sampleRate = pDecoder->outputSampleRate; + pDataBufferNode->data.backend.decoded.decodedFrameCount = 0; + ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_decoded); /* <-- Must be set last. */ + } else { + /* + It's an unknown length. The data supply is a paged decoded buffer. Setting this up is + actually easier than the non-paged decoded buffer because we just need to initialize + a ma_paged_audio_buffer object. + */ + result = ma_paged_audio_buffer_data_init(pDecoder->outputFormat, pDecoder->outputChannels, &pDataBufferNode->data.backend.decodedPaged.data); + if (result != MA_SUCCESS) { + ma_decoder_uninit(pDecoder); + ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); + return result; + } + + pDataBufferNode->data.backend.decodedPaged.sampleRate = pDecoder->outputSampleRate; + pDataBufferNode->data.backend.decodedPaged.decodedFrameCount = 0; + ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_decoded_paged); /* <-- Must be set last. */ + } + + *ppDecoder = pDecoder; + + return MA_SUCCESS; +} + +static ma_result ma_resource_manager_data_buffer_node_decode_next_page(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_decoder* pDecoder) +{ + ma_result result = MA_SUCCESS; + ma_uint64 pageSizeInFrames; + ma_uint64 framesToTryReading; + ma_uint64 framesRead; + + MA_ASSERT(pResourceManager != NULL); + MA_ASSERT(pDataBufferNode != NULL); + MA_ASSERT(pDecoder != NULL); + + /* We need to know the size of a page in frames to know how many frames to decode. */ + pageSizeInFrames = MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (pDecoder->outputSampleRate/1000); + framesToTryReading = pageSizeInFrames; + + /* + Here is where we do the decoding of the next page. We'll run a slightly different path depending + on whether or not we're using a flat or paged buffer because the allocation of the page differs + between the two. For a flat buffer it's an offset to an already-allocated buffer. For a paged + buffer, we need to allocate a new page and attach it to the linked list. + */ + switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode)) + { + case ma_resource_manager_data_supply_type_decoded: + { + /* The destination buffer is an offset to the existing buffer. Don't read more than we originally retrieved when we first initialized the decoder. */ + void* pDst; + ma_uint64 framesRemaining = pDataBufferNode->data.backend.decoded.totalFrameCount - pDataBufferNode->data.backend.decoded.decodedFrameCount; + if (framesToTryReading > framesRemaining) { + framesToTryReading = framesRemaining; + } + + if (framesToTryReading > 0) { + pDst = ma_offset_ptr( + pDataBufferNode->data.backend.decoded.pData, + pDataBufferNode->data.backend.decoded.decodedFrameCount * ma_get_bytes_per_frame(pDataBufferNode->data.backend.decoded.format, pDataBufferNode->data.backend.decoded.channels) + ); + MA_ASSERT(pDst != NULL); + + result = ma_decoder_read_pcm_frames(pDecoder, pDst, framesToTryReading, &framesRead); + if (framesRead > 0) { + pDataBufferNode->data.backend.decoded.decodedFrameCount += framesRead; + } + } else { + framesRead = 0; + } + } break; + + case ma_resource_manager_data_supply_type_decoded_paged: + { + /* The destination buffer is a freshly allocated page. */ + ma_paged_audio_buffer_page* pPage; + + result = ma_paged_audio_buffer_data_allocate_page(&pDataBufferNode->data.backend.decodedPaged.data, framesToTryReading, NULL, &pResourceManager->config.allocationCallbacks, &pPage); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder_read_pcm_frames(pDecoder, pPage->pAudioData, framesToTryReading, &framesRead); + if (framesRead > 0) { + pPage->sizeInFrames = framesRead; + + result = ma_paged_audio_buffer_data_append_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage); + if (result == MA_SUCCESS) { + pDataBufferNode->data.backend.decodedPaged.decodedFrameCount += framesRead; + } else { + /* Failed to append the page. Just abort and set the status to MA_AT_END. */ + ma_paged_audio_buffer_data_free_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage, &pResourceManager->config.allocationCallbacks); + result = MA_AT_END; + } + } else { + /* No frames were read. Free the page and just set the status to MA_AT_END. */ + ma_paged_audio_buffer_data_free_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage, &pResourceManager->config.allocationCallbacks); + result = MA_AT_END; + } + } break; + + case ma_resource_manager_data_supply_type_encoded: + case ma_resource_manager_data_supply_type_unknown: + default: + { + /* Unexpected data supply type. */ + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Unexpected data supply type (%d) when decoding page.", ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode)); + return MA_ERROR; + }; + } + + if (result == MA_SUCCESS && framesRead == 0) { + result = MA_AT_END; + } + + return result; +} + +static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_inline_notification* pInitNotification, ma_resource_manager_data_buffer_node** ppDataBufferNode) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager_data_buffer_node* pDataBufferNode = NULL; + ma_resource_manager_data_buffer_node* pInsertPoint; + + if (ppDataBufferNode != NULL) { + *ppDataBufferNode = NULL; + } + + result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, hashedName32, &pInsertPoint); + if (result == MA_ALREADY_EXISTS) { + /* The node already exists. We just need to increment the reference count. */ + pDataBufferNode = pInsertPoint; + + result = ma_resource_manager_data_buffer_node_increment_ref(pResourceManager, pDataBufferNode, NULL); + if (result != MA_SUCCESS) { + return result; /* Should never happen. Failed to increment the reference count. */ + } + + result = MA_ALREADY_EXISTS; + goto done; + } else { + /* + The node does not already exist. We need to post a LOAD_DATA_BUFFER_NODE job here. This + needs to be done inside the critical section to ensure an uninitialization of the node + does not occur before initialization on another thread. + */ + pDataBufferNode = (ma_resource_manager_data_buffer_node*)ma_malloc(sizeof(*pDataBufferNode), &pResourceManager->config.allocationCallbacks); + if (pDataBufferNode == NULL) { + return MA_OUT_OF_MEMORY; + } + + MA_ZERO_OBJECT(pDataBufferNode); + pDataBufferNode->hashedName32 = hashedName32; + pDataBufferNode->refCount = 1; /* Always set to 1 by default (this is our first reference). */ + + if (pExistingData == NULL) { + pDataBufferNode->data.type = ma_resource_manager_data_supply_type_unknown; /* <-- We won't know this until we start decoding. */ + pDataBufferNode->result = MA_BUSY; /* Must be set to MA_BUSY before we leave the critical section, so might as well do it now. */ + pDataBufferNode->isDataOwnedByResourceManager = MA_TRUE; + } else { + pDataBufferNode->data = *pExistingData; + pDataBufferNode->result = MA_SUCCESS; /* Not loading asynchronously, so just set the status */ + pDataBufferNode->isDataOwnedByResourceManager = MA_FALSE; + } + + result = ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint); + if (result != MA_SUCCESS) { + ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); + return result; /* Should never happen. Failed to insert the data buffer into the BST. */ + } + + /* + Here is where we'll post the job, but only if we're loading asynchronously. If we're + loading synchronously we'll defer loading to a later stage, outside of the critical + section. + */ + if (pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) { + /* Loading asynchronously. Post the job. */ + ma_job job; + char* pFilePathCopy = NULL; + wchar_t* pFilePathWCopy = NULL; + + /* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */ + if (pFilePath != NULL) { + pFilePathCopy = ma_copy_string(pFilePath, &pResourceManager->config.allocationCallbacks); + } else { + pFilePathWCopy = ma_copy_string_w(pFilePathW, &pResourceManager->config.allocationCallbacks); + } + + if (pFilePathCopy == NULL && pFilePathWCopy == NULL) { + ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); + ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification); + } + + /* Acquire init and done fences before posting the job. These will be unacquired by the job thread. */ + if (pInitFence != NULL) { ma_fence_acquire(pInitFence); } + if (pDoneFence != NULL) { ma_fence_acquire(pDoneFence); } + + /* We now have everything we need to post the job to the job thread. */ + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE); + job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); + job.data.resourceManager.loadDataBufferNode.pResourceManager = pResourceManager; + job.data.resourceManager.loadDataBufferNode.pDataBufferNode = pDataBufferNode; + job.data.resourceManager.loadDataBufferNode.pFilePath = pFilePathCopy; + job.data.resourceManager.loadDataBufferNode.pFilePathW = pFilePathWCopy; + job.data.resourceManager.loadDataBufferNode.flags = flags; + job.data.resourceManager.loadDataBufferNode.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? pInitNotification : NULL; + job.data.resourceManager.loadDataBufferNode.pDoneNotification = NULL; + job.data.resourceManager.loadDataBufferNode.pInitFence = pInitFence; + job.data.resourceManager.loadDataBufferNode.pDoneFence = pDoneFence; + + result = ma_resource_manager_post_job(pResourceManager, &job); + if (result != MA_SUCCESS) { + /* Failed to post job. Probably ran out of memory. */ + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); + + /* + Fences were acquired before posting the job, but since the job was not able to + be posted, we need to make sure we release them so nothing gets stuck waiting. + */ + if (pInitFence != NULL) { ma_fence_release(pInitFence); } + if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } + + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification); + } + + ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); + ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); + + ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); + ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); + + return result; + } + } + } + +done: + if (ppDataBufferNode != NULL) { + *ppDataBufferNode = pDataBufferNode; + } + + return result; +} + +static ma_result ma_resource_manager_data_buffer_node_acquire(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_data_buffer_node** ppDataBufferNode) +{ + ma_result result = MA_SUCCESS; + ma_bool32 nodeAlreadyExists = MA_FALSE; + ma_resource_manager_data_buffer_node* pDataBufferNode = NULL; + ma_resource_manager_inline_notification initNotification; /* Used when the WAIT_INIT flag is set. */ + + if (ppDataBufferNode != NULL) { + *ppDataBufferNode = NULL; /* Safety. */ + } + + if (pResourceManager == NULL || (pFilePath == NULL && pFilePathW == NULL && hashedName32 == 0)) { + return MA_INVALID_ARGS; + } + + /* If we're specifying existing data, it must be valid. */ + if (pExistingData != NULL && pExistingData->type == ma_resource_manager_data_supply_type_unknown) { + return MA_INVALID_ARGS; + } + + /* If we don't support threading, remove the ASYNC flag to make the rest of this a bit simpler. */ + if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) { + flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC; + } + + if (hashedName32 == 0) { + if (pFilePath != NULL) { + hashedName32 = ma_hash_string_32(pFilePath); + } else { + hashedName32 = ma_hash_string_w_32(pFilePathW); + } + } + + /* + Here is where we either increment the node's reference count or allocate a new one and add it + to the BST. When allocating a new node, we need to make sure the LOAD_DATA_BUFFER_NODE job is + posted inside the critical section just in case the caller immediately uninitializes the node + as this will ensure the FREE_DATA_BUFFER_NODE job is given an execution order such that the + node is not uninitialized before initialization. + */ + ma_resource_manager_data_buffer_bst_lock(pResourceManager); + { + result = ma_resource_manager_data_buffer_node_acquire_critical_section(pResourceManager, pFilePath, pFilePathW, hashedName32, flags, pExistingData, pInitFence, pDoneFence, &initNotification, &pDataBufferNode); + } + ma_resource_manager_data_buffer_bst_unlock(pResourceManager); + + if (result == MA_ALREADY_EXISTS) { + nodeAlreadyExists = MA_TRUE; + result = MA_SUCCESS; + } else { + if (result != MA_SUCCESS) { + return result; + } + } + + /* + If we're loading synchronously, we'll need to load everything now. When loading asynchronously, + a job will have been posted inside the BST critical section so that an uninitialization can be + allocated an appropriate execution order thereby preventing it from being uninitialized before + the node is initialized by the decoding thread(s). + */ + if (nodeAlreadyExists == MA_FALSE) { /* Don't need to try loading anything if the node already exists. */ + if (pFilePath == NULL && pFilePathW == NULL) { + /* + If this path is hit, it means a buffer is being copied (i.e. initialized from only the + hashed name), but that node has been freed in the meantime, probably from some other + thread. This is an invalid operation. + */ + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Cloning data buffer node failed because the source node was released. The source node must remain valid until the cloning has completed.\n"); + result = MA_INVALID_OPERATION; + goto done; + } + + if (pDataBufferNode->isDataOwnedByResourceManager) { + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0) { + /* Loading synchronously. Load the sound in it's entirety here. */ + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE) == 0) { + /* No decoding. This is the simple case - just store the file contents in memory. */ + result = ma_resource_manager_data_buffer_node_init_supply_encoded(pResourceManager, pDataBufferNode, pFilePath, pFilePathW); + if (result != MA_SUCCESS) { + goto done; + } + } else { + /* Decoding. We do this the same way as we do when loading asynchronously. */ + ma_decoder* pDecoder; + result = ma_resource_manager_data_buffer_node_init_supply_decoded(pResourceManager, pDataBufferNode, pFilePath, pFilePathW, flags, &pDecoder); + if (result != MA_SUCCESS) { + goto done; + } + + /* We have the decoder, now decode page by page just like we do when loading asynchronously. */ + for (;;) { + /* Decode next page. */ + result = ma_resource_manager_data_buffer_node_decode_next_page(pResourceManager, pDataBufferNode, pDecoder); + if (result != MA_SUCCESS) { + break; /* Will return MA_AT_END when the last page has been decoded. */ + } + } + + /* Reaching the end needs to be considered successful. */ + if (result == MA_AT_END) { + result = MA_SUCCESS; + } + + /* + At this point the data buffer is either fully decoded or some error occurred. Either + way, the decoder is no longer necessary. + */ + ma_decoder_uninit(pDecoder); + ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); + } + + /* Getting here means we were successful. Make sure the status of the node is updated accordingly. */ + c89atomic_exchange_i32(&pDataBufferNode->result, result); + } else { + /* Loading asynchronously. We may need to wait for initialization. */ + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + ma_resource_manager_inline_notification_wait(&initNotification); + } + } + } else { + /* The data is not managed by the resource manager so there's nothing else to do. */ + MA_ASSERT(pExistingData != NULL); + } + } + +done: + /* If we failed to initialize the data buffer we need to free it. */ + if (result != MA_SUCCESS) { + if (nodeAlreadyExists == MA_FALSE) { + ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); + ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks); + } + } + + /* + The init notification needs to be uninitialized. This will be used if the node does not already + exist, and we've specified ASYNC | WAIT_INIT. + */ + if (nodeAlreadyExists == MA_FALSE && pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) { + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + ma_resource_manager_inline_notification_uninit(&initNotification); + } + } + + if (ppDataBufferNode != NULL) { + *ppDataBufferNode = pDataBufferNode; + } + + return result; +} + +static ma_result ma_resource_manager_data_buffer_node_unacquire(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pName, const wchar_t* pNameW) +{ + ma_result result = MA_SUCCESS; + ma_uint32 refCount = 0xFFFFFFFF; /* The new reference count of the node after decrementing. Initialize to non-0 to be safe we don't fall into the freeing path. */ + ma_uint32 hashedName32 = 0; + + if (pResourceManager == NULL) { + return MA_INVALID_ARGS; + } + + if (pDataBufferNode == NULL) { + if (pName == NULL && pNameW == NULL) { + return MA_INVALID_ARGS; + } + + if (pName != NULL) { + hashedName32 = ma_hash_string_32(pName); + } else { + hashedName32 = ma_hash_string_w_32(pNameW); + } + } + + /* + The first thing to do is decrement the reference counter of the node. Then, if the reference + count is zero, we need to free the node. If the node is still in the process of loading, we'll + need to post a job to the job queue to free the node. Otherwise we'll just do it here. + */ + ma_resource_manager_data_buffer_bst_lock(pResourceManager); + { + /* Might need to find the node. Must be done inside the critical section. */ + if (pDataBufferNode == NULL) { + result = ma_resource_manager_data_buffer_node_search(pResourceManager, hashedName32, &pDataBufferNode); + if (result != MA_SUCCESS) { + goto stage2; /* Couldn't find the node. */ + } + } + + result = ma_resource_manager_data_buffer_node_decrement_ref(pResourceManager, pDataBufferNode, &refCount); + if (result != MA_SUCCESS) { + goto stage2; /* Should never happen. */ + } + + if (refCount == 0) { + result = ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); + if (result != MA_SUCCESS) { + goto stage2; /* An error occurred when trying to remove the data buffer. This should never happen. */ + } + } + } + ma_resource_manager_data_buffer_bst_unlock(pResourceManager); + +stage2: + if (result != MA_SUCCESS) { + return result; + } + + /* + Here is where we need to free the node. We don't want to do this inside the critical section + above because we want to keep that as small as possible for multi-threaded efficiency. + */ + if (refCount == 0) { + if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) { + /* The sound is still loading. We need to delay the freeing of the node to a safe time. */ + ma_job job; + + /* We need to mark the node as unavailable for the sake of the resource manager worker threads. */ + c89atomic_exchange_i32(&pDataBufferNode->result, MA_UNAVAILABLE); + + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE); + job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); + job.data.resourceManager.freeDataBufferNode.pResourceManager = pResourceManager; + job.data.resourceManager.freeDataBufferNode.pDataBufferNode = pDataBufferNode; + + result = ma_resource_manager_post_job(pResourceManager, &job); + if (result != MA_SUCCESS) { + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); + return result; + } + + /* If we don't support threading, process the job queue here. */ + if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) { + while (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) { + result = ma_resource_manager_process_next_job(pResourceManager); + if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) { + result = MA_SUCCESS; + break; + } + } + } else { + /* Threading is enabled. The job queue will deal with the rest of the cleanup from here. */ + } + } else { + /* The sound isn't loading so we can just free the node here. */ + ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); + } + } + + return result; +} + + + +static ma_uint32 ma_resource_manager_data_buffer_next_execution_order(ma_resource_manager_data_buffer* pDataBuffer) +{ + MA_ASSERT(pDataBuffer != NULL); + return c89atomic_fetch_add_32(&pDataBuffer->executionCounter, 1); +} + +static ma_result ma_resource_manager_data_buffer_cb__read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + return ma_resource_manager_data_buffer_read_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pFramesOut, frameCount, pFramesRead); +} + +static ma_result ma_resource_manager_data_buffer_cb__seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + return ma_resource_manager_data_buffer_seek_to_pcm_frame((ma_resource_manager_data_buffer*)pDataSource, frameIndex); +} + +static ma_result ma_resource_manager_data_buffer_cb__get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + return ma_resource_manager_data_buffer_get_data_format((ma_resource_manager_data_buffer*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); +} + +static ma_result ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor) +{ + return ma_resource_manager_data_buffer_get_cursor_in_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pCursor); +} + +static ma_result ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength) +{ + return ma_resource_manager_data_buffer_get_length_in_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pLength); +} + +static ma_result ma_resource_manager_data_buffer_cb__set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) +{ + ma_resource_manager_data_buffer* pDataBuffer = (ma_resource_manager_data_buffer*)pDataSource; + MA_ASSERT(pDataBuffer != NULL); + + c89atomic_exchange_32(&pDataBuffer->isLooping, isLooping); + + /* The looping state needs to be set on the connector as well or else looping won't work when we read audio data. */ + ma_data_source_set_looping(ma_resource_manager_data_buffer_get_connector(pDataBuffer), isLooping); + + return MA_SUCCESS; +} + +static ma_data_source_vtable g_ma_resource_manager_data_buffer_vtable = +{ + ma_resource_manager_data_buffer_cb__read_pcm_frames, + ma_resource_manager_data_buffer_cb__seek_to_pcm_frame, + ma_resource_manager_data_buffer_cb__get_data_format, + ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames, + ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames, + ma_resource_manager_data_buffer_cb__set_looping, + 0 +}; + +static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_uint32 hashedName32, ma_resource_manager_data_buffer* pDataBuffer) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager_data_buffer_node* pDataBufferNode; + ma_data_source_config dataSourceConfig; + ma_bool32 async; + ma_uint32 flags; + ma_resource_manager_pipeline_notifications notifications; + + if (pDataBuffer == NULL) { + if (pConfig != NULL && pConfig->pNotifications != NULL) { + ma_resource_manager_pipeline_notifications_signal_all_notifications(pConfig->pNotifications); + } + + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDataBuffer); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->pNotifications != NULL) { + notifications = *pConfig->pNotifications; /* From here on out we should be referencing `notifications` instead of `pNotifications`. Set this to NULL to catch errors at testing time. */ + } else { + MA_ZERO_OBJECT(¬ifications); + } + + /* For safety, always remove the ASYNC flag if threading is disabled on the resource manager. */ + flags = pConfig->flags; + if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) { + flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC; + } + + async = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0; + + /* + Fences need to be acquired before doing anything. These must be aquired and released outside of + the node to ensure there's no holes where ma_fence_wait() could prematurely return before the + data buffer has completed initialization. + + When loading asynchronously, the node acquisition routine below will acquire the fences on this + thread and then release them on the async thread when the operation is complete. + + These fences are always released at the "done" tag at the end of this function. They'll be + acquired a second if loading asynchronously. This double acquisition system is just done to + simplify code maintanence. + */ + ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications); + { + /* We first need to acquire a node. If ASYNC is not set, this will not return until the entire sound has been loaded. */ + result = ma_resource_manager_data_buffer_node_acquire(pResourceManager, pConfig->pFilePath, pConfig->pFilePathW, hashedName32, flags, NULL, notifications.init.pFence, notifications.done.pFence, &pDataBufferNode); + if (result != MA_SUCCESS) { + ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); + goto done; + } + + dataSourceConfig = ma_data_source_config_init(); + dataSourceConfig.vtable = &g_ma_resource_manager_data_buffer_vtable; + + result = ma_data_source_init(&dataSourceConfig, &pDataBuffer->ds); + if (result != MA_SUCCESS) { + ma_resource_manager_data_buffer_node_unacquire(pResourceManager, pDataBufferNode, NULL, NULL); + ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); + goto done; + } + + pDataBuffer->pResourceManager = pResourceManager; + pDataBuffer->pNode = pDataBufferNode; + pDataBuffer->flags = flags; + pDataBuffer->result = MA_BUSY; /* Always default to MA_BUSY for safety. It'll be overwritten when loading completes or an error occurs. */ + + /* If we're loading asynchronously we need to post a job to the job queue to initialize the connector. */ + if (async == MA_FALSE || ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_SUCCESS) { + /* Loading synchronously or the data has already been fully loaded. We can just initialize the connector from here without a job. */ + result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, pConfig, NULL, NULL); + c89atomic_exchange_i32(&pDataBuffer->result, result); + + ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); + goto done; + } else { + /* The node's data supply isn't initialized yet. The caller has requested that we load asynchronously so we need to post a job to do this. */ + ma_job job; + ma_resource_manager_inline_notification initNotification; /* Used when the WAIT_INIT flag is set. */ + + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + ma_resource_manager_inline_notification_init(pResourceManager, &initNotification); + } + + /* + The status of the data buffer needs to be set to MA_BUSY before posting the job so that the + worker thread is aware of it's busy state. If the LOAD_DATA_BUFFER job sees a status other + than MA_BUSY, it'll assume an error and fall through to an early exit. + */ + c89atomic_exchange_i32(&pDataBuffer->result, MA_BUSY); + + /* Acquire fences a second time. These will be released by the async thread. */ + ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications); + + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER); + job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer); + job.data.resourceManager.loadDataBuffer.pDataBuffer = pDataBuffer; + job.data.resourceManager.loadDataBuffer.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? &initNotification : notifications.init.pNotification; + job.data.resourceManager.loadDataBuffer.pDoneNotification = notifications.done.pNotification; + job.data.resourceManager.loadDataBuffer.pInitFence = notifications.init.pFence; + job.data.resourceManager.loadDataBuffer.pDoneFence = notifications.done.pFence; + job.data.resourceManager.loadDataBuffer.rangeBegInPCMFrames = pConfig->rangeBegInPCMFrames; + job.data.resourceManager.loadDataBuffer.rangeEndInPCMFrames = pConfig->rangeEndInPCMFrames; + job.data.resourceManager.loadDataBuffer.loopPointBegInPCMFrames = pConfig->loopPointBegInPCMFrames; + job.data.resourceManager.loadDataBuffer.loopPointEndInPCMFrames = pConfig->loopPointEndInPCMFrames; + job.data.resourceManager.loadDataBuffer.isLooping = pConfig->isLooping; + + result = ma_resource_manager_post_job(pResourceManager, &job); + if (result != MA_SUCCESS) { + /* We failed to post the job. Most likely there isn't enough room in the queue's buffer. */ + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER job. %s.\n", ma_result_description(result)); + c89atomic_exchange_i32(&pDataBuffer->result, result); + + /* Release the fences after the result has been set on the data buffer. */ + ma_resource_manager_pipeline_notifications_release_all_fences(¬ifications); + } else { + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + ma_resource_manager_inline_notification_wait(&initNotification); + + if (notifications.init.pNotification != NULL) { + ma_async_notification_signal(notifications.init.pNotification); + } + + /* NOTE: Do not release the init fence here. It will have been done by the job. */ + + /* Make sure we return an error if initialization failed on the async thread. */ + result = ma_resource_manager_data_buffer_result(pDataBuffer); + if (result == MA_BUSY) { + result = MA_SUCCESS; + } + } + } + + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + ma_resource_manager_inline_notification_uninit(&initNotification); + } + } + + if (result != MA_SUCCESS) { + ma_resource_manager_data_buffer_node_unacquire(pResourceManager, pDataBufferNode, NULL, NULL); + goto done; + } + } +done: + if (result == MA_SUCCESS) { + if (pConfig->initialSeekPointInPCMFrames > 0) { + ma_resource_manager_data_buffer_seek_to_pcm_frame(pDataBuffer, pConfig->initialSeekPointInPCMFrames); + } + } + + ma_resource_manager_pipeline_notifications_release_all_fences(¬ifications); + + return result; +} + +MA_API ma_result ma_resource_manager_data_buffer_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_buffer* pDataBuffer) +{ + return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, pConfig, 0, pDataBuffer); +} + +MA_API ma_result ma_resource_manager_data_buffer_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer) +{ + ma_resource_manager_data_source_config config; + + config = ma_resource_manager_data_source_config_init(); + config.pFilePath = pFilePath; + config.flags = flags; + config.pNotifications = pNotifications; + + return ma_resource_manager_data_buffer_init_ex(pResourceManager, &config, pDataBuffer); +} + +MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer) +{ + ma_resource_manager_data_source_config config; + + config = ma_resource_manager_data_source_config_init(); + config.pFilePathW = pFilePath; + config.flags = flags; + config.pNotifications = pNotifications; + + return ma_resource_manager_data_buffer_init_ex(pResourceManager, &config, pDataBuffer); +} + +MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer) +{ + ma_resource_manager_data_source_config config; + + if (pExistingDataBuffer == NULL) { + return MA_INVALID_ARGS; + } + + MA_ASSERT(pExistingDataBuffer->pNode != NULL); /* <-- If you've triggered this, you've passed in an invalid existing data buffer. */ + + config = ma_resource_manager_data_source_config_init(); + config.flags = pExistingDataBuffer->flags; + + return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, &config, pExistingDataBuffer->pNode->hashedName32, pDataBuffer); +} + +static ma_result ma_resource_manager_data_buffer_uninit_internal(ma_resource_manager_data_buffer* pDataBuffer) +{ + MA_ASSERT(pDataBuffer != NULL); + + /* The connector should be uninitialized first. */ + ma_resource_manager_data_buffer_uninit_connector(pDataBuffer->pResourceManager, pDataBuffer); + + /* With the connector uninitialized we can unacquire the node. */ + ma_resource_manager_data_buffer_node_unacquire(pDataBuffer->pResourceManager, pDataBuffer->pNode, NULL, NULL); + + /* The base data source needs to be uninitialized as well. */ + ma_data_source_uninit(&pDataBuffer->ds); + + return MA_SUCCESS; +} + +MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data_buffer* pDataBuffer) +{ + ma_result result; + + if (pDataBuffer == NULL) { + return MA_INVALID_ARGS; + } + + if (ma_resource_manager_data_buffer_result(pDataBuffer) == MA_SUCCESS) { + /* The data buffer can be deleted synchronously. */ + return ma_resource_manager_data_buffer_uninit_internal(pDataBuffer); + } else { + /* + The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will + be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event + to get processed before returning. + */ + ma_resource_manager_inline_notification notification; + ma_job job; + + /* + We need to mark the node as unavailable so we don't try reading from it anymore, but also to + let the loading thread know that it needs to abort it's loading procedure. + */ + c89atomic_exchange_i32(&pDataBuffer->result, MA_UNAVAILABLE); + + result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, ¬ification); + if (result != MA_SUCCESS) { + return result; /* Failed to create the notification. This should rarely, if ever, happen. */ + } + + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER); + job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer); + job.data.resourceManager.freeDataBuffer.pDataBuffer = pDataBuffer; + job.data.resourceManager.freeDataBuffer.pDoneNotification = ¬ification; + job.data.resourceManager.freeDataBuffer.pDoneFence = NULL; + + result = ma_resource_manager_post_job(pDataBuffer->pResourceManager, &job); + if (result != MA_SUCCESS) { + ma_resource_manager_inline_notification_uninit(¬ification); + return result; + } + + ma_resource_manager_inline_notification_wait_and_uninit(¬ification); + } + + return result; +} + +MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_result result = MA_SUCCESS; + ma_uint64 framesRead = 0; + ma_bool32 isDecodedBufferBusy = MA_FALSE; + + /* Safety. */ + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + + /* + We cannot be using the data buffer after it's been uninitialized. If you trigger this assert it means you're trying to read from the data buffer after + it's been uninitialized or is in the process of uninitializing. + */ + MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); + + /* If the node is not initialized we need to abort with a busy code. */ + if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { + return MA_BUSY; /* Still loading. */ + } + + if (pDataBuffer->seekToCursorOnNextRead) { + pDataBuffer->seekToCursorOnNextRead = MA_FALSE; + + result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pDataBuffer->seekTargetInPCMFrames); + if (result != MA_SUCCESS) { + return result; + } + } + + /* + For decoded buffers (not paged) we need to check beforehand how many frames we have available. We cannot + exceed this amount. We'll read as much as we can, and then return MA_BUSY. + */ + if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_decoded) { + ma_uint64 availableFrames; + + isDecodedBufferBusy = (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY); + + if (ma_resource_manager_data_buffer_get_available_frames(pDataBuffer, &availableFrames) == MA_SUCCESS) { + /* Don't try reading more than the available frame count. */ + if (frameCount > availableFrames) { + frameCount = availableFrames; + + /* + If there's no frames available we want to set the status to MA_AT_END. The logic below + will check if the node is busy, and if so, change it to MA_BUSY. The reason we do this + is because we don't want to call `ma_data_source_read_pcm_frames()` if the frame count + is 0 because that'll result in a situation where it's possible MA_AT_END won't get + returned. + */ + if (frameCount == 0) { + result = MA_AT_END; + } + } else { + isDecodedBufferBusy = MA_FALSE; /* We have enough frames available in the buffer to avoid a MA_BUSY status. */ + } + } + } + + /* Don't attempt to read anything if we've got no frames available. */ + if (frameCount > 0) { + result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead); + } + + /* + If we returned MA_AT_END, but the node is still loading, we don't want to return that code or else the caller will interpret the sound + as at the end and terminate decoding. + */ + if (result == MA_AT_END) { + if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) { + result = MA_BUSY; + } + } + + if (isDecodedBufferBusy) { + result = MA_BUSY; + } + + if (pFramesRead != NULL) { + *pFramesRead = framesRead; + } + + if (result == MA_SUCCESS && framesRead == 0) { + result = MA_AT_END; + } + + return result; +} + +MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64 frameIndex) +{ + ma_result result; + + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); + + /* If we haven't yet got a connector we need to abort. */ + if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { + pDataBuffer->seekTargetInPCMFrames = frameIndex; + pDataBuffer->seekToCursorOnNextRead = MA_TRUE; + return MA_BUSY; /* Still loading. */ + } + + result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), frameIndex); + if (result != MA_SUCCESS) { + return result; + } + + pDataBuffer->seekTargetInPCMFrames = ~(ma_uint64)0; /* <-- For identification purposes. */ + pDataBuffer->seekToCursorOnNextRead = MA_FALSE; + + return MA_SUCCESS; +} + +MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_manager_data_buffer* pDataBuffer, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); + + switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) + { + case ma_resource_manager_data_supply_type_encoded: + { + return ma_data_source_get_data_format(&pDataBuffer->connector.decoder, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); + }; + + case ma_resource_manager_data_supply_type_decoded: + { + *pFormat = pDataBuffer->pNode->data.backend.decoded.format; + *pChannels = pDataBuffer->pNode->data.backend.decoded.channels; + *pSampleRate = pDataBuffer->pNode->data.backend.decoded.sampleRate; + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pDataBuffer->pNode->data.backend.decoded.channels); + return MA_SUCCESS; + }; + + case ma_resource_manager_data_supply_type_decoded_paged: + { + *pFormat = pDataBuffer->pNode->data.backend.decodedPaged.data.format; + *pChannels = pDataBuffer->pNode->data.backend.decodedPaged.data.channels; + *pSampleRate = pDataBuffer->pNode->data.backend.decodedPaged.sampleRate; + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pDataBuffer->pNode->data.backend.decoded.channels); + return MA_SUCCESS; + }; + + case ma_resource_manager_data_supply_type_unknown: + { + return MA_BUSY; /* Still loading. */ + }; + + default: + { + /* Unknown supply type. Should never hit this. */ + return MA_INVALID_ARGS; + } + } +} + +MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pCursor) +{ + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); + + if (pDataBuffer == NULL || pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; + + switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) + { + case ma_resource_manager_data_supply_type_encoded: + { + return ma_decoder_get_cursor_in_pcm_frames(&pDataBuffer->connector.decoder, pCursor); + }; + + case ma_resource_manager_data_supply_type_decoded: + { + return ma_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.buffer, pCursor); + }; + + case ma_resource_manager_data_supply_type_decoded_paged: + { + return ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, pCursor); + }; + + case ma_resource_manager_data_supply_type_unknown: + { + return MA_BUSY; + }; + + default: + { + return MA_INVALID_ARGS; + } + } +} + +MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength) +{ + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); + + if (pDataBuffer == NULL || pLength == NULL) { + return MA_INVALID_ARGS; + } + + if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { + return MA_BUSY; /* Still loading. */ + } + + return ma_data_source_get_length_in_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pLength); +} + +MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manager_data_buffer* pDataBuffer) +{ + if (pDataBuffer == NULL) { + return MA_INVALID_ARGS; + } + + return (ma_result)c89atomic_load_i32((ma_result*)&pDataBuffer->result); /* Need a naughty const-cast here. */ +} + +MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping) +{ + return ma_data_source_set_looping(pDataBuffer, isLooping); +} + +MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer) +{ + return ma_data_source_is_looping(pDataBuffer); +} + +MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames) +{ + if (pAvailableFrames == NULL) { + return MA_INVALID_ARGS; + } + + *pAvailableFrames = 0; + + if (pDataBuffer == NULL) { + return MA_INVALID_ARGS; + } + + if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { + if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) { + return MA_BUSY; + } else { + return MA_INVALID_OPERATION; /* No connector. */ + } + } + + switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) + { + case ma_resource_manager_data_supply_type_encoded: + { + return ma_decoder_get_available_frames(&pDataBuffer->connector.decoder, pAvailableFrames); + }; + + case ma_resource_manager_data_supply_type_decoded: + { + return ma_audio_buffer_get_available_frames(&pDataBuffer->connector.buffer, pAvailableFrames); + }; + + case ma_resource_manager_data_supply_type_decoded_paged: + { + ma_uint64 cursor; + ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, &cursor); + + if (pDataBuffer->pNode->data.backend.decodedPaged.decodedFrameCount > cursor) { + *pAvailableFrames = pDataBuffer->pNode->data.backend.decodedPaged.decodedFrameCount - cursor; + } else { + *pAvailableFrames = 0; + } + + return MA_SUCCESS; + }; + + case ma_resource_manager_data_supply_type_unknown: + default: + { + /* Unknown supply type. Should never hit this. */ + return MA_INVALID_ARGS; + } + } +} + +MA_API ma_result ma_resource_manager_register_file(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags) +{ + return ma_resource_manager_data_buffer_node_acquire(pResourceManager, pFilePath, NULL, 0, flags, NULL, NULL, NULL, NULL); +} + +MA_API ma_result ma_resource_manager_register_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags) +{ + return ma_resource_manager_data_buffer_node_acquire(pResourceManager, NULL, pFilePath, 0, flags, NULL, NULL, NULL, NULL); +} + + +static ma_result ma_resource_manager_register_data(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, ma_resource_manager_data_supply* pExistingData) +{ + return ma_resource_manager_data_buffer_node_acquire(pResourceManager, pName, pNameW, 0, 0, pExistingData, NULL, NULL, NULL); +} + +static ma_result ma_resource_manager_register_decoded_data_internal(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +{ + ma_resource_manager_data_supply data; + data.type = ma_resource_manager_data_supply_type_decoded; + data.backend.decoded.pData = pData; + data.backend.decoded.totalFrameCount = frameCount; + data.backend.decoded.format = format; + data.backend.decoded.channels = channels; + data.backend.decoded.sampleRate = sampleRate; + + return ma_resource_manager_register_data(pResourceManager, pName, pNameW, &data); +} + +MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +{ + return ma_resource_manager_register_decoded_data_internal(pResourceManager, pName, NULL, pData, frameCount, format, channels, sampleRate); +} + +MA_API ma_result ma_resource_manager_register_decoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +{ + return ma_resource_manager_register_decoded_data_internal(pResourceManager, NULL, pName, pData, frameCount, format, channels, sampleRate); +} + + +static ma_result ma_resource_manager_register_encoded_data_internal(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, const void* pData, size_t sizeInBytes) +{ + ma_resource_manager_data_supply data; + data.type = ma_resource_manager_data_supply_type_encoded; + data.backend.encoded.pData = pData; + data.backend.encoded.sizeInBytes = sizeInBytes; + + return ma_resource_manager_register_data(pResourceManager, pName, pNameW, &data); +} + +MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes) +{ + return ma_resource_manager_register_encoded_data_internal(pResourceManager, pName, NULL, pData, sizeInBytes); +} + +MA_API ma_result ma_resource_manager_register_encoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, size_t sizeInBytes) +{ + return ma_resource_manager_register_encoded_data_internal(pResourceManager, NULL, pName, pData, sizeInBytes); +} + + +MA_API ma_result ma_resource_manager_unregister_file(ma_resource_manager* pResourceManager, const char* pFilePath) +{ + return ma_resource_manager_unregister_data(pResourceManager, pFilePath); +} + +MA_API ma_result ma_resource_manager_unregister_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath) +{ + return ma_resource_manager_unregister_data_w(pResourceManager, pFilePath); +} + +MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName) +{ + return ma_resource_manager_data_buffer_node_unacquire(pResourceManager, NULL, pName, NULL); +} + +MA_API ma_result ma_resource_manager_unregister_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName) +{ + return ma_resource_manager_data_buffer_node_unacquire(pResourceManager, NULL, NULL, pName); +} + + +static ma_uint32 ma_resource_manager_data_stream_next_execution_order(ma_resource_manager_data_stream* pDataStream) +{ + MA_ASSERT(pDataStream != NULL); + return c89atomic_fetch_add_32(&pDataStream->executionCounter, 1); +} + +static ma_bool32 ma_resource_manager_data_stream_is_decoder_at_end(const ma_resource_manager_data_stream* pDataStream) +{ + MA_ASSERT(pDataStream != NULL); + return c89atomic_load_32((ma_bool32*)&pDataStream->isDecoderAtEnd); +} + +static ma_uint32 ma_resource_manager_data_stream_seek_counter(const ma_resource_manager_data_stream* pDataStream) +{ + MA_ASSERT(pDataStream != NULL); + return c89atomic_load_32((ma_uint32*)&pDataStream->seekCounter); +} + + +static ma_result ma_resource_manager_data_stream_cb__read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + return ma_resource_manager_data_stream_read_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pFramesOut, frameCount, pFramesRead); +} + +static ma_result ma_resource_manager_data_stream_cb__seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + return ma_resource_manager_data_stream_seek_to_pcm_frame((ma_resource_manager_data_stream*)pDataSource, frameIndex); +} + +static ma_result ma_resource_manager_data_stream_cb__get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + return ma_resource_manager_data_stream_get_data_format((ma_resource_manager_data_stream*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); +} + +static ma_result ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor) +{ + return ma_resource_manager_data_stream_get_cursor_in_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pCursor); +} + +static ma_result ma_resource_manager_data_stream_cb__get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength) +{ + return ma_resource_manager_data_stream_get_length_in_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pLength); +} + +static ma_result ma_resource_manager_data_stream_cb__set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) +{ + ma_resource_manager_data_stream* pDataStream = (ma_resource_manager_data_stream*)pDataSource; + MA_ASSERT(pDataStream != NULL); + + c89atomic_exchange_32(&pDataStream->isLooping, isLooping); + + return MA_SUCCESS; +} + +static ma_data_source_vtable g_ma_resource_manager_data_stream_vtable = +{ + ma_resource_manager_data_stream_cb__read_pcm_frames, + ma_resource_manager_data_stream_cb__seek_to_pcm_frame, + ma_resource_manager_data_stream_cb__get_data_format, + ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames, + ma_resource_manager_data_stream_cb__get_length_in_pcm_frames, + ma_resource_manager_data_stream_cb__set_looping, + MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT +}; + +static void ma_resource_manager_data_stream_set_absolute_cursor(ma_resource_manager_data_stream* pDataStream, ma_uint64 absoluteCursor) +{ + /* Loop if possible. */ + if (absoluteCursor > pDataStream->totalLengthInPCMFrames && pDataStream->totalLengthInPCMFrames > 0) { + absoluteCursor = absoluteCursor % pDataStream->totalLengthInPCMFrames; + } + + c89atomic_exchange_64(&pDataStream->absoluteCursor, absoluteCursor); +} + +MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_stream* pDataStream) +{ + ma_result result; + ma_data_source_config dataSourceConfig; + char* pFilePathCopy = NULL; + wchar_t* pFilePathWCopy = NULL; + ma_job job; + ma_bool32 waitBeforeReturning = MA_FALSE; + ma_resource_manager_inline_notification waitNotification; + ma_resource_manager_pipeline_notifications notifications; + + if (pDataStream == NULL) { + if (pConfig != NULL && pConfig->pNotifications != NULL) { + ma_resource_manager_pipeline_notifications_signal_all_notifications(pConfig->pNotifications); + } + + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDataStream); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->pNotifications != NULL) { + notifications = *pConfig->pNotifications; /* From here on out, `notifications` should be used instead of `pNotifications`. Setting this to NULL to catch any errors at testing time. */ + } else { + MA_ZERO_OBJECT(¬ifications); + } + + dataSourceConfig = ma_data_source_config_init(); + dataSourceConfig.vtable = &g_ma_resource_manager_data_stream_vtable; + + result = ma_data_source_init(&dataSourceConfig, &pDataStream->ds); + if (result != MA_SUCCESS) { + ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); + return result; + } + + pDataStream->pResourceManager = pResourceManager; + pDataStream->flags = pConfig->flags; + pDataStream->result = MA_BUSY; + + ma_data_source_set_range_in_pcm_frames(pDataStream, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); + ma_data_source_set_loop_point_in_pcm_frames(pDataStream, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + ma_data_source_set_looping(pDataStream, pConfig->isLooping); + + if (pResourceManager == NULL || (pConfig->pFilePath == NULL && pConfig->pFilePathW == NULL)) { + ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); + return MA_INVALID_ARGS; + } + + /* We want all access to the VFS and the internal decoder to happen on the job thread just to keep things easier to manage for the VFS. */ + + /* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */ + if (pConfig->pFilePath != NULL) { + pFilePathCopy = ma_copy_string(pConfig->pFilePath, &pResourceManager->config.allocationCallbacks); + } else { + pFilePathWCopy = ma_copy_string_w(pConfig->pFilePathW, &pResourceManager->config.allocationCallbacks); + } + + if (pFilePathCopy == NULL && pFilePathWCopy == NULL) { + ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); + return MA_OUT_OF_MEMORY; + } + + /* + We need to check for the presence of MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC. If it's not set, we need to wait before returning. Otherwise we + can return immediately. Likewise, we'll also check for MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT and do the same. + */ + if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0 || (pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { + waitBeforeReturning = MA_TRUE; + ma_resource_manager_inline_notification_init(pResourceManager, &waitNotification); + } + + ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications); + + /* Set the absolute cursor to our initial seek position so retrieval of the cursor returns a good value. */ + ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, pConfig->initialSeekPointInPCMFrames); + + /* We now have everything we need to post the job. This is the last thing we need to do from here. The rest will be done by the job thread. */ + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM); + job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); + job.data.resourceManager.loadDataStream.pDataStream = pDataStream; + job.data.resourceManager.loadDataStream.pFilePath = pFilePathCopy; + job.data.resourceManager.loadDataStream.pFilePathW = pFilePathWCopy; + job.data.resourceManager.loadDataStream.initialSeekPoint = pConfig->initialSeekPointInPCMFrames; + job.data.resourceManager.loadDataStream.pInitNotification = (waitBeforeReturning == MA_TRUE) ? &waitNotification : notifications.init.pNotification; + job.data.resourceManager.loadDataStream.pInitFence = notifications.init.pFence; + result = ma_resource_manager_post_job(pResourceManager, &job); + if (result != MA_SUCCESS) { + ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); + ma_resource_manager_pipeline_notifications_release_all_fences(¬ifications); + + if (waitBeforeReturning) { + ma_resource_manager_inline_notification_uninit(&waitNotification); + } + + ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); + ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); + return result; + } + + /* Wait if needed. */ + if (waitBeforeReturning) { + ma_resource_manager_inline_notification_wait_and_uninit(&waitNotification); + + if (notifications.init.pNotification != NULL) { + ma_async_notification_signal(notifications.init.pNotification); + } + + /* NOTE: Do not release pInitFence here. That will be done by the job. */ + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream) +{ + ma_resource_manager_data_source_config config; + + config = ma_resource_manager_data_source_config_init(); + config.pFilePath = pFilePath; + config.flags = flags; + config.pNotifications = pNotifications; + + return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream); +} + +MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream) +{ + ma_resource_manager_data_source_config config; + + config = ma_resource_manager_data_source_config_init(); + config.pFilePathW = pFilePath; + config.flags = flags; + config.pNotifications = pNotifications; + + return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream); +} + +MA_API ma_result ma_resource_manager_data_stream_uninit(ma_resource_manager_data_stream* pDataStream) +{ + ma_resource_manager_inline_notification freeEvent; + ma_job job; + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + /* The first thing to do is set the result to unavailable. This will prevent future page decoding. */ + c89atomic_exchange_i32(&pDataStream->result, MA_UNAVAILABLE); + + /* + We need to post a job to ensure we're not in the middle or decoding or anything. Because the object is owned by the caller, we'll need + to wait for it to complete before returning which means we need an event. + */ + ma_resource_manager_inline_notification_init(pDataStream->pResourceManager, &freeEvent); + + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM); + job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); + job.data.resourceManager.freeDataStream.pDataStream = pDataStream; + job.data.resourceManager.freeDataStream.pDoneNotification = &freeEvent; + job.data.resourceManager.freeDataStream.pDoneFence = NULL; + ma_resource_manager_post_job(pDataStream->pResourceManager, &job); + + /* We need to wait for the job to finish processing before we return. */ + ma_resource_manager_inline_notification_wait_and_uninit(&freeEvent); + + return MA_SUCCESS; +} + + +static ma_uint32 ma_resource_manager_data_stream_get_page_size_in_frames(ma_resource_manager_data_stream* pDataStream) +{ + MA_ASSERT(pDataStream != NULL); + MA_ASSERT(pDataStream->isDecoderInitialized == MA_TRUE); + + return MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (pDataStream->decoder.outputSampleRate/1000); +} + +static void* ma_resource_manager_data_stream_get_page_data_pointer(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex, ma_uint32 relativeCursor) +{ + MA_ASSERT(pDataStream != NULL); + MA_ASSERT(pDataStream->isDecoderInitialized == MA_TRUE); + MA_ASSERT(pageIndex == 0 || pageIndex == 1); + + return ma_offset_ptr(pDataStream->pPageData, ((ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * pageIndex) + relativeCursor) * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels)); +} + +static void ma_resource_manager_data_stream_fill_page(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex) +{ + ma_result result = MA_SUCCESS; + ma_uint64 pageSizeInFrames; + ma_uint64 totalFramesReadForThisPage = 0; + void* pPageData = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pageIndex, 0); + + pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream); + + /* The decoder needs to inherit the stream's looping and range state. */ + { + ma_uint64 rangeBeg; + ma_uint64 rangeEnd; + ma_uint64 loopPointBeg; + ma_uint64 loopPointEnd; + + ma_data_source_set_looping(&pDataStream->decoder, ma_resource_manager_data_stream_is_looping(pDataStream)); + + ma_data_source_get_range_in_pcm_frames(pDataStream, &rangeBeg, &rangeEnd); + ma_data_source_set_range_in_pcm_frames(&pDataStream->decoder, rangeBeg, rangeEnd); + + ma_data_source_get_loop_point_in_pcm_frames(pDataStream, &loopPointBeg, &loopPointEnd); + ma_data_source_set_loop_point_in_pcm_frames(&pDataStream->decoder, loopPointBeg, loopPointEnd); + } + + /* Just read straight from the decoder. It will deal with ranges and looping for us. */ + result = ma_data_source_read_pcm_frames(&pDataStream->decoder, pPageData, pageSizeInFrames, &totalFramesReadForThisPage); + if (result == MA_AT_END || totalFramesReadForThisPage < pageSizeInFrames) { + c89atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_TRUE); + } + + c89atomic_exchange_32(&pDataStream->pageFrameCount[pageIndex], (ma_uint32)totalFramesReadForThisPage); + c89atomic_exchange_32(&pDataStream->isPageValid[pageIndex], MA_TRUE); +} + +static void ma_resource_manager_data_stream_fill_pages(ma_resource_manager_data_stream* pDataStream) +{ + ma_uint32 iPage; + + MA_ASSERT(pDataStream != NULL); + + for (iPage = 0; iPage < 2; iPage += 1) { + ma_resource_manager_data_stream_fill_page(pDataStream, iPage); + } +} + + +static ma_result ma_resource_manager_data_stream_map(ma_resource_manager_data_stream* pDataStream, void** ppFramesOut, ma_uint64* pFrameCount) +{ + ma_uint64 framesAvailable; + ma_uint64 frameCount = 0; + + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); + + if (pFrameCount != NULL) { + frameCount = *pFrameCount; + *pFrameCount = 0; + } + if (ppFramesOut != NULL) { + *ppFramesOut = NULL; + } + + if (pDataStream == NULL || ppFramesOut == NULL || pFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { + return MA_INVALID_OPERATION; + } + + /* Don't attempt to read while we're in the middle of seeking. Tell the caller that we're busy. */ + if (ma_resource_manager_data_stream_seek_counter(pDataStream) > 0) { + return MA_BUSY; + } + + /* If the page we're on is invalid it means we've caught up to the job thread. */ + if (c89atomic_load_32(&pDataStream->isPageValid[pDataStream->currentPageIndex]) == MA_FALSE) { + framesAvailable = 0; + } else { + /* + The page we're on is valid so we must have some frames available. We need to make sure that we don't overflow into the next page, even if it's valid. The reason is + that the unmap process will only post an update for one page at a time. Keeping mapping tied to page boundaries makes this simpler. + */ + ma_uint32 currentPageFrameCount = c89atomic_load_32(&pDataStream->pageFrameCount[pDataStream->currentPageIndex]); + MA_ASSERT(currentPageFrameCount >= pDataStream->relativeCursor); + + framesAvailable = currentPageFrameCount - pDataStream->relativeCursor; + } + + /* If there's no frames available and the result is set to MA_AT_END we need to return MA_AT_END. */ + if (framesAvailable == 0) { + if (ma_resource_manager_data_stream_is_decoder_at_end(pDataStream)) { + return MA_AT_END; + } else { + return MA_BUSY; /* There are no frames available, but we're not marked as EOF so we might have caught up to the job thread. Need to return MA_BUSY and wait for more data. */ + } + } + + MA_ASSERT(framesAvailable > 0); + + if (frameCount > framesAvailable) { + frameCount = framesAvailable; + } + + *ppFramesOut = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pDataStream->currentPageIndex, pDataStream->relativeCursor); + *pFrameCount = frameCount; + + return MA_SUCCESS; +} + +static ma_result ma_resource_manager_data_stream_unmap(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameCount) +{ + ma_uint32 newRelativeCursor; + ma_uint32 pageSizeInFrames; + ma_job job; + + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { + return MA_INVALID_OPERATION; + } + + /* The frame count should always fit inside a 32-bit integer. */ + if (frameCount > 0xFFFFFFFF) { + return MA_INVALID_ARGS; + } + + pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream); + + /* The absolute cursor needs to be updated for ma_resource_manager_data_stream_get_cursor_in_pcm_frames(). */ + ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, c89atomic_load_64(&pDataStream->absoluteCursor) + frameCount); + + /* Here is where we need to check if we need to load a new page, and if so, post a job to load it. */ + newRelativeCursor = pDataStream->relativeCursor + (ma_uint32)frameCount; + + /* If the new cursor has flowed over to the next page we need to mark the old one as invalid and post an event for it. */ + if (newRelativeCursor >= pageSizeInFrames) { + newRelativeCursor -= pageSizeInFrames; + + /* Here is where we post the job start decoding. */ + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM); + job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); + job.data.resourceManager.pageDataStream.pDataStream = pDataStream; + job.data.resourceManager.pageDataStream.pageIndex = pDataStream->currentPageIndex; + + /* The page needs to be marked as invalid so that the public API doesn't try reading from it. */ + c89atomic_exchange_32(&pDataStream->isPageValid[pDataStream->currentPageIndex], MA_FALSE); + + /* Before posting the job we need to make sure we set some state. */ + pDataStream->relativeCursor = newRelativeCursor; + pDataStream->currentPageIndex = (pDataStream->currentPageIndex + 1) & 0x01; + return ma_resource_manager_post_job(pDataStream->pResourceManager, &job); + } else { + /* We haven't moved into a new page so we can just move the cursor forward. */ + pDataStream->relativeCursor = newRelativeCursor; + return MA_SUCCESS; + } +} + + +MA_API ma_result ma_resource_manager_data_stream_read_pcm_frames(ma_resource_manager_data_stream* pDataStream, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_result result = MA_SUCCESS; + ma_uint64 totalFramesProcessed; + ma_format format; + ma_uint32 channels; + + /* Safety. */ + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { + return MA_INVALID_OPERATION; + } + + /* Don't attempt to read while we're in the middle of seeking. Tell the caller that we're busy. */ + if (ma_resource_manager_data_stream_seek_counter(pDataStream) > 0) { + return MA_BUSY; + } + + ma_resource_manager_data_stream_get_data_format(pDataStream, &format, &channels, NULL, NULL, 0); + + /* Reading is implemented in terms of map/unmap. We need to run this in a loop because mapping is clamped against page boundaries. */ + totalFramesProcessed = 0; + while (totalFramesProcessed < frameCount) { + void* pMappedFrames; + ma_uint64 mappedFrameCount; + + mappedFrameCount = frameCount - totalFramesProcessed; + result = ma_resource_manager_data_stream_map(pDataStream, &pMappedFrames, &mappedFrameCount); + if (result != MA_SUCCESS) { + break; + } + + /* Copy the mapped data to the output buffer if we have one. It's allowed for pFramesOut to be NULL in which case a relative forward seek is performed. */ + if (pFramesOut != NULL) { + ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesProcessed, format, channels), pMappedFrames, mappedFrameCount, format, channels); + } + + totalFramesProcessed += mappedFrameCount; + + result = ma_resource_manager_data_stream_unmap(pDataStream, mappedFrameCount); + if (result != MA_SUCCESS) { + break; /* This is really bad - will only get an error here if we failed to post a job to the queue for loading the next page. */ + } + } + + if (pFramesRead != NULL) { + *pFramesRead = totalFramesProcessed; + } + + if (result == MA_SUCCESS && totalFramesProcessed == 0) { + result = MA_AT_END; + } + + return result; +} + +MA_API ma_result ma_resource_manager_data_stream_seek_to_pcm_frame(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameIndex) +{ + ma_job job; + ma_result streamResult; + + streamResult = ma_resource_manager_data_stream_result(pDataStream); + + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(streamResult != MA_UNAVAILABLE); + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + if (streamResult != MA_SUCCESS && streamResult != MA_BUSY) { + return MA_INVALID_OPERATION; + } + + /* If we're not already seeking and we're sitting on the same frame, just make this a no-op. */ + if (c89atomic_load_32(&pDataStream->seekCounter) == 0) { + if (c89atomic_load_64(&pDataStream->absoluteCursor) == frameIndex) { + return MA_SUCCESS; + } + } + + + /* Increment the seek counter first to indicate to read_paged_pcm_frames() and map_paged_pcm_frames() that we are in the middle of a seek and MA_BUSY should be returned. */ + c89atomic_fetch_add_32(&pDataStream->seekCounter, 1); + + /* Update the absolute cursor so that ma_resource_manager_data_stream_get_cursor_in_pcm_frames() returns the new position. */ + ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, frameIndex); + + /* + We need to clear our currently loaded pages so that the stream starts playback from the new seek point as soon as possible. These are for the purpose of the public + API and will be ignored by the seek job. The seek job will operate on the assumption that both pages have been marked as invalid and the cursor is at the start of + the first page. + */ + pDataStream->relativeCursor = 0; + pDataStream->currentPageIndex = 0; + c89atomic_exchange_32(&pDataStream->isPageValid[0], MA_FALSE); + c89atomic_exchange_32(&pDataStream->isPageValid[1], MA_FALSE); + + /* Make sure the data stream is not marked as at the end or else if we seek in response to hitting the end, we won't be able to read any more data. */ + c89atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_FALSE); + + /* + The public API is not allowed to touch the internal decoder so we need to use a job to perform the seek. When seeking, the job thread will assume both pages + are invalid and any content contained within them will be discarded and replaced with newly decoded data. + */ + job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM); + job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream); + job.data.resourceManager.seekDataStream.pDataStream = pDataStream; + job.data.resourceManager.seekDataStream.frameIndex = frameIndex; + return ma_resource_manager_post_job(pDataStream->pResourceManager, &job); +} + +MA_API ma_result ma_resource_manager_data_stream_get_data_format(ma_resource_manager_data_stream* pDataStream, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); + + if (pFormat != NULL) { + *pFormat = ma_format_unknown; + } + + if (pChannels != NULL) { + *pChannels = 0; + } + + if (pSampleRate != NULL) { + *pSampleRate = 0; + } + + if (pChannelMap != NULL) { + MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap); + } + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { + return MA_INVALID_OPERATION; + } + + /* + We're being a little bit naughty here and accessing the internal decoder from the public API. The output data format is constant, and we've defined this function + such that the application is responsible for ensuring it's not called while uninitializing so it should be safe. + */ + return ma_data_source_get_data_format(&pDataStream->decoder, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); +} + +MA_API ma_result ma_resource_manager_data_stream_get_cursor_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pCursor) +{ + ma_result result; + + if (pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; + + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE); + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + /* + If the stream is in an erroneous state we need to return an invalid operation. We can allow + this to be called when the data stream is in a busy state because the caller may have asked + for an initial seek position and it's convenient to return that as the cursor position. + */ + result = ma_resource_manager_data_stream_result(pDataStream); + if (result != MA_SUCCESS && result != MA_BUSY) { + return MA_INVALID_OPERATION; + } + + *pCursor = c89atomic_load_64(&pDataStream->absoluteCursor); + + return MA_SUCCESS; +} + +MA_API ma_result ma_resource_manager_data_stream_get_length_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pLength) +{ + ma_result streamResult; + + if (pLength == NULL) { + return MA_INVALID_ARGS; + } + + *pLength = 0; + + streamResult = ma_resource_manager_data_stream_result(pDataStream); + + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(streamResult != MA_UNAVAILABLE); + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + if (streamResult != MA_SUCCESS) { + return streamResult; + } + + /* + We most definitely do not want to be calling ma_decoder_get_length_in_pcm_frames() directly. Instead we want to use a cached value that we + calculated when we initialized it on the job thread. + */ + *pLength = pDataStream->totalLengthInPCMFrames; + if (*pLength == 0) { + return MA_NOT_IMPLEMENTED; /* Some decoders may not have a known length. */ + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream) +{ + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + return (ma_result)c89atomic_load_i32(&pDataStream->result); +} + +MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping) +{ + return ma_data_source_set_looping(pDataStream, isLooping); +} + +MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream) +{ + if (pDataStream == NULL) { + return MA_FALSE; + } + + return c89atomic_load_32((ma_bool32*)&pDataStream->isLooping); /* Naughty const-cast. Value won't change from here in practice (maybe from another thread). */ +} + +MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames) +{ + ma_uint32 pageIndex0; + ma_uint32 pageIndex1; + ma_uint32 relativeCursor; + ma_uint64 availableFrames; + + if (pAvailableFrames == NULL) { + return MA_INVALID_ARGS; + } + + *pAvailableFrames = 0; + + if (pDataStream == NULL) { + return MA_INVALID_ARGS; + } + + pageIndex0 = pDataStream->currentPageIndex; + pageIndex1 = (pDataStream->currentPageIndex + 1) & 0x01; + relativeCursor = pDataStream->relativeCursor; + + availableFrames = 0; + if (c89atomic_load_32(&pDataStream->isPageValid[pageIndex0])) { + availableFrames += c89atomic_load_32(&pDataStream->pageFrameCount[pageIndex0]) - relativeCursor; + if (c89atomic_load_32(&pDataStream->isPageValid[pageIndex1])) { + availableFrames += c89atomic_load_32(&pDataStream->pageFrameCount[pageIndex1]); + } + } + + *pAvailableFrames = availableFrames; + return MA_SUCCESS; +} + + +static ma_result ma_resource_manager_data_source_preinit(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDataSource); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pResourceManager == NULL) { + return MA_INVALID_ARGS; + } + + pDataSource->flags = pConfig->flags; + + return MA_SUCCESS; +} + +MA_API ma_result ma_resource_manager_data_source_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource) +{ + ma_result result; + + result = ma_resource_manager_data_source_preinit(pResourceManager, pConfig, pDataSource); + if (result != MA_SUCCESS) { + return result; + } + + /* The data source itself is just a data stream or a data buffer. */ + if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_init_ex(pResourceManager, pConfig, &pDataSource->backend.stream); + } else { + return ma_resource_manager_data_buffer_init_ex(pResourceManager, pConfig, &pDataSource->backend.buffer); + } +} + +MA_API ma_result ma_resource_manager_data_source_init(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource) +{ + ma_resource_manager_data_source_config config; + + config = ma_resource_manager_data_source_config_init(); + config.pFilePath = pName; + config.flags = flags; + config.pNotifications = pNotifications; + + return ma_resource_manager_data_source_init_ex(pResourceManager, &config, pDataSource); +} + +MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pResourceManager, const wchar_t* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource) +{ + ma_resource_manager_data_source_config config; + + config = ma_resource_manager_data_source_config_init(); + config.pFilePathW = pName; + config.flags = flags; + config.pNotifications = pNotifications; + + return ma_resource_manager_data_source_init_ex(pResourceManager, &config, pDataSource); +} + +MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource) +{ + ma_result result; + ma_resource_manager_data_source_config config; + + if (pExistingDataSource == NULL) { + return MA_INVALID_ARGS; + } + + config = ma_resource_manager_data_source_config_init(); + config.flags = pExistingDataSource->flags; + + result = ma_resource_manager_data_source_preinit(pResourceManager, &config, pDataSource); + if (result != MA_SUCCESS) { + return result; + } + + /* Copying can only be done from data buffers. Streams cannot be copied. */ + if ((pExistingDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return MA_INVALID_OPERATION; + } + + return ma_resource_manager_data_buffer_init_copy(pResourceManager, &pExistingDataSource->backend.buffer, &pDataSource->backend.buffer); +} + +MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + /* All we need to is uninitialize the underlying data buffer or data stream. */ + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_uninit(&pDataSource->backend.stream); + } else { + return ma_resource_manager_data_buffer_uninit(&pDataSource->backend.buffer); + } +} + +MA_API ma_result ma_resource_manager_data_source_read_pcm_frames(ma_resource_manager_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + /* Safety. */ + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_read_pcm_frames(&pDataSource->backend.stream, pFramesOut, frameCount, pFramesRead); + } else { + return ma_resource_manager_data_buffer_read_pcm_frames(&pDataSource->backend.buffer, pFramesOut, frameCount, pFramesRead); + } +} + +MA_API ma_result ma_resource_manager_data_source_seek_to_pcm_frame(ma_resource_manager_data_source* pDataSource, ma_uint64 frameIndex) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_seek_to_pcm_frame(&pDataSource->backend.stream, frameIndex); + } else { + return ma_resource_manager_data_buffer_seek_to_pcm_frame(&pDataSource->backend.buffer, frameIndex); + } +} + +MA_API ma_result ma_resource_manager_data_source_map(ma_resource_manager_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_map(&pDataSource->backend.stream, ppFramesOut, pFrameCount); + } else { + return MA_NOT_IMPLEMENTED; /* Mapping not supported with data buffers. */ + } +} + +MA_API ma_result ma_resource_manager_data_source_unmap(ma_resource_manager_data_source* pDataSource, ma_uint64 frameCount) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_unmap(&pDataSource->backend.stream, frameCount); + } else { + return MA_NOT_IMPLEMENTED; /* Mapping not supported with data buffers. */ + } +} + +MA_API ma_result ma_resource_manager_data_source_get_data_format(ma_resource_manager_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_get_data_format(&pDataSource->backend.stream, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); + } else { + return ma_resource_manager_data_buffer_get_data_format(&pDataSource->backend.buffer, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); + } +} + +MA_API ma_result ma_resource_manager_data_source_get_cursor_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pCursor) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_get_cursor_in_pcm_frames(&pDataSource->backend.stream, pCursor); + } else { + return ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(&pDataSource->backend.buffer, pCursor); + } +} + +MA_API ma_result ma_resource_manager_data_source_get_length_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pLength) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_get_length_in_pcm_frames(&pDataSource->backend.stream, pLength); + } else { + return ma_resource_manager_data_buffer_get_length_in_pcm_frames(&pDataSource->backend.buffer, pLength); + } +} + +MA_API ma_result ma_resource_manager_data_source_result(const ma_resource_manager_data_source* pDataSource) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_result(&pDataSource->backend.stream); + } else { + return ma_resource_manager_data_buffer_result(&pDataSource->backend.buffer); + } +} + +MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager_data_source* pDataSource, ma_bool32 isLooping) +{ + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_set_looping(&pDataSource->backend.stream, isLooping); + } else { + return ma_resource_manager_data_buffer_set_looping(&pDataSource->backend.buffer, isLooping); + } +} + +MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource) +{ + if (pDataSource == NULL) { + return MA_FALSE; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_is_looping(&pDataSource->backend.stream); + } else { + return ma_resource_manager_data_buffer_is_looping(&pDataSource->backend.buffer); + } +} + +MA_API ma_result ma_resource_manager_data_source_get_available_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pAvailableFrames) +{ + if (pAvailableFrames == NULL) { + return MA_INVALID_ARGS; + } + + *pAvailableFrames = 0; + + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { + return ma_resource_manager_data_stream_get_available_frames(&pDataSource->backend.stream, pAvailableFrames); + } else { + return ma_resource_manager_data_buffer_get_available_frames(&pDataSource->backend.buffer, pAvailableFrames); + } +} + + +MA_API ma_result ma_resource_manager_post_job(ma_resource_manager* pResourceManager, const ma_job* pJob) +{ + if (pResourceManager == NULL) { + return MA_INVALID_ARGS; + } + + return ma_job_queue_post(&pResourceManager->jobQueue, pJob); +} + +MA_API ma_result ma_resource_manager_post_job_quit(ma_resource_manager* pResourceManager) +{ + ma_job job = ma_job_init(MA_JOB_TYPE_QUIT); + return ma_resource_manager_post_job(pResourceManager, &job); +} + +MA_API ma_result ma_resource_manager_next_job(ma_resource_manager* pResourceManager, ma_job* pJob) +{ + if (pResourceManager == NULL) { + return MA_INVALID_ARGS; + } + + return ma_job_queue_next(&pResourceManager->jobQueue, pJob); +} + + +static ma_result ma_job_process__resource_manager__load_data_buffer_node(ma_job* pJob) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager* pResourceManager; + ma_resource_manager_data_buffer_node* pDataBufferNode; + + MA_ASSERT(pJob != NULL); + + pResourceManager = (ma_resource_manager*)pJob->data.resourceManager.loadDataBufferNode.pResourceManager; + MA_ASSERT(pResourceManager != NULL); + + pDataBufferNode = (ma_resource_manager_data_buffer_node*)pJob->data.resourceManager.loadDataBufferNode.pDataBufferNode; + MA_ASSERT(pDataBufferNode != NULL); + MA_ASSERT(pDataBufferNode->isDataOwnedByResourceManager == MA_TRUE); /* The data should always be owned by the resource manager. */ + + /* The data buffer is not getting deleted, but we may be getting executed out of order. If so, we need to push the job back onto the queue and return. */ + if (pJob->order != c89atomic_load_32(&pDataBufferNode->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Attempting to execute out of order. Probably interleaved with a MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER job. */ + } + + /* First thing we need to do is check whether or not the data buffer is getting deleted. If so we just abort. */ + if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) != MA_BUSY) { + result = ma_resource_manager_data_buffer_node_result(pDataBufferNode); /* The data buffer may be getting deleted before it's even been loaded. */ + goto done; + } + + /* + We're ready to start loading. Essentially what we're doing here is initializing the data supply + of the node. Once this is complete, data buffers can have their connectors initialized which + will allow then to have audio data read from them. + + Note that when the data supply type has been moved away from "unknown", that is when other threads + will determine that the node is available for data delivery and the data buffer connectors can be + initialized. Therefore, it's important that it is set after the data supply has been initialized. + */ + if ((pJob->data.resourceManager.loadDataBufferNode.flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE) != 0) { + /* + Decoding. This is the complex case because we're not going to be doing the entire decoding + process here. Instead it's going to be split of multiple jobs and loaded in pages. The + reason for this is to evenly distribute decoding time across multiple sounds, rather than + having one huge sound hog all the available processing resources. + + The first thing we do is initialize a decoder. This is allocated on the heap and is passed + around to the paging jobs. When the last paging job has completed it's processing, it'll + free the decoder for us. + + This job does not do any actual decoding. It instead just posts a PAGE_DATA_BUFFER_NODE job + which is where the actual decoding work will be done. However, once this job is complete, + the node will be in a state where data buffer connectors can be initialized. + */ + ma_decoder* pDecoder; /* <-- Free'd on the last page decode. */ + ma_job pageDataBufferNodeJob; + + /* Allocate the decoder by initializing a decoded data supply. */ + result = ma_resource_manager_data_buffer_node_init_supply_decoded(pResourceManager, pDataBufferNode, pJob->data.resourceManager.loadDataBufferNode.pFilePath, pJob->data.resourceManager.loadDataBufferNode.pFilePathW, pJob->data.resourceManager.loadDataBufferNode.flags, &pDecoder); + + /* + Don't ever propagate an MA_BUSY result code or else the resource manager will think the + node is just busy decoding rather than in an error state. This should never happen, but + including this logic for safety just in case. + */ + if (result == MA_BUSY) { + result = MA_ERROR; + } + + if (result != MA_SUCCESS) { + if (pJob->data.resourceManager.loadDataBufferNode.pFilePath != NULL) { + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to initialize data supply for \"%s\". %s.\n", pJob->data.resourceManager.loadDataBufferNode.pFilePath, ma_result_description(result)); + } else { + #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to initialize data supply for \"%ls\", %s.\n", pJob->data.resourceManager.loadDataBufferNode.pFilePathW, ma_result_description(result)); + #endif + } + + goto done; + } + + /* + At this point the node's data supply is initialized and other threads can start initializing + their data buffer connectors. However, no data will actually be available until we start to + actually decode it. To do this, we need to post a paging job which is where the decoding + work is done. + + Note that if an error occurred at an earlier point, this section will have been skipped. + */ + pageDataBufferNodeJob = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE); + pageDataBufferNodeJob.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); + pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pResourceManager = pResourceManager; + pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDataBufferNode = pDataBufferNode; + pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDecoder = pDecoder; + pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDoneNotification = pJob->data.resourceManager.loadDataBufferNode.pDoneNotification; + pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDoneFence = pJob->data.resourceManager.loadDataBufferNode.pDoneFence; + + /* The job has been set up so it can now be posted. */ + result = ma_resource_manager_post_job(pResourceManager, &pageDataBufferNodeJob); + + /* + When we get here, we want to make sure the result code is set to MA_BUSY. The reason for + this is that the result will be copied over to the node's internal result variable. In + this case, since the decoding is still in-progress, we need to make sure the result code + is set to MA_BUSY. + */ + if (result != MA_SUCCESS) { + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE job. %s\n", ma_result_description(result)); + ma_decoder_uninit(pDecoder); + ma_free(pDecoder, &pResourceManager->config.allocationCallbacks); + } else { + result = MA_BUSY; + } + } else { + /* No decoding. This is the simple case. We need only read the file content into memory and we're done. */ + result = ma_resource_manager_data_buffer_node_init_supply_encoded(pResourceManager, pDataBufferNode, pJob->data.resourceManager.loadDataBufferNode.pFilePath, pJob->data.resourceManager.loadDataBufferNode.pFilePathW); + } + + +done: + /* File paths are no longer needed. */ + ma_free(pJob->data.resourceManager.loadDataBufferNode.pFilePath, &pResourceManager->config.allocationCallbacks); + ma_free(pJob->data.resourceManager.loadDataBufferNode.pFilePathW, &pResourceManager->config.allocationCallbacks); + + /* + We need to set the result to at the very end to ensure no other threads try reading the data before we've fully initialized the object. Other threads + are going to be inspecting this variable to determine whether or not they're ready to read data. We can only change the result if it's set to MA_BUSY + because otherwise we may be changing away from an error code which would be bad. An example is if the application creates a data buffer, but then + immediately deletes it before we've got to this point. In this case, pDataBuffer->result will be MA_UNAVAILABLE, and setting it to MA_SUCCESS or any + other error code would cause the buffer to look like it's in a state that it's not. + */ + c89atomic_compare_and_swap_i32(&pDataBufferNode->result, MA_BUSY, result); + + /* At this point initialization is complete and we can signal the notification if any. */ + if (pJob->data.resourceManager.loadDataBufferNode.pInitNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.loadDataBufferNode.pInitNotification); + } + if (pJob->data.resourceManager.loadDataBufferNode.pInitFence != NULL) { + ma_fence_release(pJob->data.resourceManager.loadDataBufferNode.pInitFence); + } + + /* If we have a success result it means we've fully loaded the buffer. This will happen in the non-decoding case. */ + if (result != MA_BUSY) { + if (pJob->data.resourceManager.loadDataBufferNode.pDoneNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.loadDataBufferNode.pDoneNotification); + } + if (pJob->data.resourceManager.loadDataBufferNode.pDoneFence != NULL) { + ma_fence_release(pJob->data.resourceManager.loadDataBufferNode.pDoneFence); + } + } + + /* Increment the node's execution pointer so that the next jobs can be processed. This is how we keep decoding of pages in-order. */ + c89atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1); + return result; +} + +static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* pJob) +{ + ma_resource_manager* pResourceManager; + ma_resource_manager_data_buffer_node* pDataBufferNode; + + MA_ASSERT(pJob != NULL); + + pResourceManager = (ma_resource_manager*)pJob->data.resourceManager.freeDataBufferNode.pResourceManager; + MA_ASSERT(pResourceManager != NULL); + + pDataBufferNode = (ma_resource_manager_data_buffer_node*)pJob->data.resourceManager.freeDataBufferNode.pDataBufferNode; + MA_ASSERT(pDataBufferNode != NULL); + + if (pJob->order != c89atomic_load_32(&pDataBufferNode->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ + } + + ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); + + /* The event needs to be signalled last. */ + if (pJob->data.resourceManager.freeDataBufferNode.pDoneNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.freeDataBufferNode.pDoneNotification); + } + + if (pJob->data.resourceManager.freeDataBufferNode.pDoneFence != NULL) { + ma_fence_release(pJob->data.resourceManager.freeDataBufferNode.pDoneFence); + } + + c89atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1); + return MA_SUCCESS; +} + +static ma_result ma_job_process__resource_manager__page_data_buffer_node(ma_job* pJob) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager* pResourceManager; + ma_resource_manager_data_buffer_node* pDataBufferNode; + + MA_ASSERT(pJob != NULL); + + pResourceManager = (ma_resource_manager*)pJob->data.resourceManager.pageDataBufferNode.pResourceManager; + MA_ASSERT(pResourceManager != NULL); + + pDataBufferNode = (ma_resource_manager_data_buffer_node*)pJob->data.resourceManager.pageDataBufferNode.pDataBufferNode; + MA_ASSERT(pDataBufferNode != NULL); + + if (pJob->order != c89atomic_load_32(&pDataBufferNode->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ + } + + /* Don't do any more decoding if the data buffer has started the uninitialization process. */ + result = ma_resource_manager_data_buffer_node_result(pDataBufferNode); + if (result != MA_BUSY) { + goto done; + } + + /* We're ready to decode the next page. */ + result = ma_resource_manager_data_buffer_node_decode_next_page(pResourceManager, pDataBufferNode, (ma_decoder*)pJob->data.resourceManager.pageDataBufferNode.pDecoder); + + /* + If we have a success code by this point, we want to post another job. We're going to set the + result back to MA_BUSY to make it clear that there's still more to load. + */ + if (result == MA_SUCCESS) { + ma_job newJob; + newJob = *pJob; /* Everything is the same as the input job, except the execution order. */ + newJob.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode); /* We need a fresh execution order. */ + + result = ma_resource_manager_post_job(pResourceManager, &newJob); + + /* Since the sound isn't yet fully decoded we want the status to be set to busy. */ + if (result == MA_SUCCESS) { + result = MA_BUSY; + } + } + +done: + /* If there's still more to decode the result will be set to MA_BUSY. Otherwise we can free the decoder. */ + if (result != MA_BUSY) { + ma_decoder_uninit((ma_decoder*)pJob->data.resourceManager.pageDataBufferNode.pDecoder); + ma_free(pJob->data.resourceManager.pageDataBufferNode.pDecoder, &pResourceManager->config.allocationCallbacks); + } + + /* If we reached the end we need to treat it as successful. */ + if (result == MA_AT_END) { + result = MA_SUCCESS; + } + + /* Make sure we set the result of node in case some error occurred. */ + c89atomic_compare_and_swap_i32(&pDataBufferNode->result, MA_BUSY, result); + + /* Signal the notification after setting the result in case the notification callback wants to inspect the result code. */ + if (result != MA_BUSY) { + if (pJob->data.resourceManager.pageDataBufferNode.pDoneNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.pageDataBufferNode.pDoneNotification); + } + + if (pJob->data.resourceManager.pageDataBufferNode.pDoneFence != NULL) { + ma_fence_release(pJob->data.resourceManager.pageDataBufferNode.pDoneFence); + } + } + + c89atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1); + return result; +} + + +static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager* pResourceManager; + ma_resource_manager_data_buffer* pDataBuffer; + ma_resource_manager_data_supply_type dataSupplyType = ma_resource_manager_data_supply_type_unknown; + ma_bool32 isConnectorInitialized = MA_FALSE; + + /* + All we're doing here is checking if the node has finished loading. If not, we just re-post the job + and keep waiting. Otherwise we increment the execution counter and set the buffer's result code. + */ + MA_ASSERT(pJob != NULL); + + pDataBuffer = (ma_resource_manager_data_buffer*)pJob->data.resourceManager.loadDataBuffer.pDataBuffer; + MA_ASSERT(pDataBuffer != NULL); + + pResourceManager = pDataBuffer->pResourceManager; + + if (pJob->order != c89atomic_load_32(&pDataBuffer->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Attempting to execute out of order. Probably interleaved with a MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER job. */ + } + + /* + First thing we need to do is check whether or not the data buffer is getting deleted. If so we + just abort, but making sure we increment the execution pointer. + */ + result = ma_resource_manager_data_buffer_result(pDataBuffer); + if (result != MA_BUSY) { + goto done; /* <-- This will ensure the exucution pointer is incremented. */ + } else { + result = MA_SUCCESS; /* <-- Make sure this is reset. */ + } + + /* Try initializing the connector if we haven't already. */ + isConnectorInitialized = pDataBuffer->isConnectorInitialized; + if (isConnectorInitialized == MA_FALSE) { + dataSupplyType = ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode); + + if (dataSupplyType != ma_resource_manager_data_supply_type_unknown) { + /* We can now initialize the connector. If this fails, we need to abort. It's very rare for this to fail. */ + ma_resource_manager_data_source_config dataSourceConfig; /* For setting initial looping state and range. */ + dataSourceConfig = ma_resource_manager_data_source_config_init(); + dataSourceConfig.rangeBegInPCMFrames = pJob->data.resourceManager.loadDataBuffer.rangeBegInPCMFrames; + dataSourceConfig.rangeEndInPCMFrames = pJob->data.resourceManager.loadDataBuffer.rangeEndInPCMFrames; + dataSourceConfig.loopPointBegInPCMFrames = pJob->data.resourceManager.loadDataBuffer.loopPointBegInPCMFrames; + dataSourceConfig.loopPointEndInPCMFrames = pJob->data.resourceManager.loadDataBuffer.loopPointEndInPCMFrames; + dataSourceConfig.isLooping = pJob->data.resourceManager.loadDataBuffer.isLooping; + + result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, &dataSourceConfig, pJob->data.resourceManager.loadDataBuffer.pInitNotification, pJob->data.resourceManager.loadDataBuffer.pInitFence); + if (result != MA_SUCCESS) { + ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to initialize connector for data buffer. %s.\n", ma_result_description(result)); + goto done; + } + } else { + /* Don't have a known data supply type. Most likely the data buffer node is still loading, but it could be that an error occurred. */ + } + } else { + /* The connector is already initialized. Nothing to do here. */ + } + + /* + If the data node is still loading, we need to repost the job and *not* increment the execution + pointer (i.e. we need to not fall through to the "done" label). + + There is a hole between here and the where the data connector is initialized where the data + buffer node may have finished initializing. We need to check for this by checking the result of + the data buffer node and whether or not we had an unknown data supply type at the time of + trying to initialize the data connector. + */ + result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode); + if (result == MA_BUSY || (result == MA_SUCCESS && isConnectorInitialized == MA_FALSE && dataSupplyType == ma_resource_manager_data_supply_type_unknown)) { + return ma_resource_manager_post_job(pResourceManager, pJob); + } + +done: + /* Only move away from a busy code so that we don't trash any existing error codes. */ + c89atomic_compare_and_swap_i32(&pDataBuffer->result, MA_BUSY, result); + + /* Only signal the other threads after the result has been set just for cleanliness sake. */ + if (pJob->data.resourceManager.loadDataBuffer.pDoneNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.loadDataBuffer.pDoneNotification); + } + if (pJob->data.resourceManager.loadDataBuffer.pDoneFence != NULL) { + ma_fence_release(pJob->data.resourceManager.loadDataBuffer.pDoneFence); + } + + /* + If at this point the data buffer has not had it's connector initialized, it means the + notification event was never signalled which means we need to signal it here. + */ + if (pDataBuffer->isConnectorInitialized == MA_FALSE && result != MA_SUCCESS) { + if (pJob->data.resourceManager.loadDataBuffer.pInitNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.loadDataBuffer.pInitNotification); + } + if (pJob->data.resourceManager.loadDataBuffer.pInitFence != NULL) { + ma_fence_release(pJob->data.resourceManager.loadDataBuffer.pInitFence); + } + } + + c89atomic_fetch_add_32(&pDataBuffer->executionPointer, 1); + return result; +} + +static ma_result ma_job_process__resource_manager__free_data_buffer(ma_job* pJob) +{ + ma_resource_manager* pResourceManager; + ma_resource_manager_data_buffer* pDataBuffer; + + MA_ASSERT(pJob != NULL); + + pDataBuffer = (ma_resource_manager_data_buffer*)pJob->data.resourceManager.freeDataBuffer.pDataBuffer; + MA_ASSERT(pDataBuffer != NULL); + + pResourceManager = pDataBuffer->pResourceManager; + + if (pJob->order != c89atomic_load_32(&pDataBuffer->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ + } + + ma_resource_manager_data_buffer_uninit_internal(pDataBuffer); + + /* The event needs to be signalled last. */ + if (pJob->data.resourceManager.freeDataBuffer.pDoneNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.freeDataBuffer.pDoneNotification); + } + + if (pJob->data.resourceManager.freeDataBuffer.pDoneFence != NULL) { + ma_fence_release(pJob->data.resourceManager.freeDataBuffer.pDoneFence); + } + + c89atomic_fetch_add_32(&pDataBuffer->executionPointer, 1); + return MA_SUCCESS; +} + +static ma_result ma_job_process__resource_manager__load_data_stream(ma_job* pJob) +{ + ma_result result = MA_SUCCESS; + ma_decoder_config decoderConfig; + ma_uint32 pageBufferSizeInBytes; + ma_resource_manager* pResourceManager; + ma_resource_manager_data_stream* pDataStream; + + MA_ASSERT(pJob != NULL); + + pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.loadDataStream.pDataStream; + MA_ASSERT(pDataStream != NULL); + + pResourceManager = pDataStream->pResourceManager; + + if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ + } + + if (ma_resource_manager_data_stream_result(pDataStream) != MA_BUSY) { + result = MA_INVALID_OPERATION; /* Most likely the data stream is being uninitialized. */ + goto done; + } + + /* We need to initialize the decoder first so we can determine the size of the pages. */ + decoderConfig = ma_resource_manager__init_decoder_config(pResourceManager); + + if (pJob->data.resourceManager.loadDataStream.pFilePath != NULL) { + result = ma_decoder_init_vfs(pResourceManager->config.pVFS, pJob->data.resourceManager.loadDataStream.pFilePath, &decoderConfig, &pDataStream->decoder); + } else { + result = ma_decoder_init_vfs_w(pResourceManager->config.pVFS, pJob->data.resourceManager.loadDataStream.pFilePathW, &decoderConfig, &pDataStream->decoder); + } + if (result != MA_SUCCESS) { + goto done; + } + + /* Retrieve the total length of the file before marking the decoder are loaded. */ + if ((pDataStream->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH) == 0) { + result = ma_decoder_get_length_in_pcm_frames(&pDataStream->decoder, &pDataStream->totalLengthInPCMFrames); + if (result != MA_SUCCESS) { + goto done; /* Failed to retrieve the length. */ + } + } else { + pDataStream->totalLengthInPCMFrames = 0; + } + + /* + Only mark the decoder as initialized when the length of the decoder has been retrieved because that can possibly require a scan over the whole file + and we don't want to have another thread trying to access the decoder while it's scanning. + */ + pDataStream->isDecoderInitialized = MA_TRUE; + + /* We have the decoder so we can now initialize our page buffer. */ + pageBufferSizeInBytes = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * 2 * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels); + + pDataStream->pPageData = ma_malloc(pageBufferSizeInBytes, &pResourceManager->config.allocationCallbacks); + if (pDataStream->pPageData == NULL) { + ma_decoder_uninit(&pDataStream->decoder); + result = MA_OUT_OF_MEMORY; + goto done; + } + + /* Seek to our initial seek point before filling the initial pages. */ + ma_decoder_seek_to_pcm_frame(&pDataStream->decoder, pJob->data.resourceManager.loadDataStream.initialSeekPoint); + + /* We have our decoder and our page buffer, so now we need to fill our pages. */ + ma_resource_manager_data_stream_fill_pages(pDataStream); + + /* And now we're done. We want to make sure the result is MA_SUCCESS. */ + result = MA_SUCCESS; + +done: + ma_free(pJob->data.resourceManager.loadDataStream.pFilePath, &pResourceManager->config.allocationCallbacks); + ma_free(pJob->data.resourceManager.loadDataStream.pFilePathW, &pResourceManager->config.allocationCallbacks); + + /* We can only change the status away from MA_BUSY. If it's set to anything else it means an error has occurred somewhere or the uninitialization process has started (most likely). */ + c89atomic_compare_and_swap_i32(&pDataStream->result, MA_BUSY, result); + + /* Only signal the other threads after the result has been set just for cleanliness sake. */ + if (pJob->data.resourceManager.loadDataStream.pInitNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.loadDataStream.pInitNotification); + } + if (pJob->data.resourceManager.loadDataStream.pInitFence != NULL) { + ma_fence_release(pJob->data.resourceManager.loadDataStream.pInitFence); + } + + c89atomic_fetch_add_32(&pDataStream->executionPointer, 1); + return result; +} + +static ma_result ma_job_process__resource_manager__free_data_stream(ma_job* pJob) +{ + ma_resource_manager* pResourceManager; + ma_resource_manager_data_stream* pDataStream; + + MA_ASSERT(pJob != NULL); + + pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.freeDataStream.pDataStream; + MA_ASSERT(pDataStream != NULL); + + pResourceManager = pDataStream->pResourceManager; + + if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ + } + + /* If our status is not MA_UNAVAILABLE we have a bug somewhere. */ + MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) == MA_UNAVAILABLE); + + if (pDataStream->isDecoderInitialized) { + ma_decoder_uninit(&pDataStream->decoder); + } + + if (pDataStream->pPageData != NULL) { + ma_free(pDataStream->pPageData, &pResourceManager->config.allocationCallbacks); + pDataStream->pPageData = NULL; /* Just in case... */ + } + + ma_data_source_uninit(&pDataStream->ds); + + /* The event needs to be signalled last. */ + if (pJob->data.resourceManager.freeDataStream.pDoneNotification != NULL) { + ma_async_notification_signal(pJob->data.resourceManager.freeDataStream.pDoneNotification); + } + if (pJob->data.resourceManager.freeDataStream.pDoneFence != NULL) { + ma_fence_release(pJob->data.resourceManager.freeDataStream.pDoneFence); + } + + /*c89atomic_fetch_add_32(&pDataStream->executionPointer, 1);*/ + return MA_SUCCESS; +} + +static ma_result ma_job_process__resource_manager__page_data_stream(ma_job* pJob) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager* pResourceManager; + ma_resource_manager_data_stream* pDataStream; + + MA_ASSERT(pJob != NULL); + + pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.pageDataStream.pDataStream; + MA_ASSERT(pDataStream != NULL); + + pResourceManager = pDataStream->pResourceManager; + + if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ + } + + /* For streams, the status should be MA_SUCCESS. */ + if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) { + result = MA_INVALID_OPERATION; + goto done; + } + + ma_resource_manager_data_stream_fill_page(pDataStream, pJob->data.resourceManager.pageDataStream.pageIndex); + +done: + c89atomic_fetch_add_32(&pDataStream->executionPointer, 1); + return result; +} + +static ma_result ma_job_process__resource_manager__seek_data_stream(ma_job* pJob) +{ + ma_result result = MA_SUCCESS; + ma_resource_manager* pResourceManager; + ma_resource_manager_data_stream* pDataStream; + + MA_ASSERT(pJob != NULL); + + pDataStream = (ma_resource_manager_data_stream*)pJob->data.resourceManager.seekDataStream.pDataStream; + MA_ASSERT(pDataStream != NULL); + + pResourceManager = pDataStream->pResourceManager; + + if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) { + return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ + } + + /* For streams the status should be MA_SUCCESS for this to do anything. */ + if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS || pDataStream->isDecoderInitialized == MA_FALSE) { + result = MA_INVALID_OPERATION; + goto done; + } + + /* + With seeking we just assume both pages are invalid and the relative frame cursor at position 0. This is basically exactly the same as loading, except + instead of initializing the decoder, we seek to a frame. + */ + ma_decoder_seek_to_pcm_frame(&pDataStream->decoder, pJob->data.resourceManager.seekDataStream.frameIndex); + + /* After seeking we'll need to reload the pages. */ + ma_resource_manager_data_stream_fill_pages(pDataStream); + + /* We need to let the public API know that we're done seeking. */ + c89atomic_fetch_sub_32(&pDataStream->seekCounter, 1); + +done: + c89atomic_fetch_add_32(&pDataStream->executionPointer, 1); + return result; +} + +MA_API ma_result ma_resource_manager_process_job(ma_resource_manager* pResourceManager, ma_job* pJob) +{ + if (pResourceManager == NULL || pJob == NULL) { + return MA_INVALID_ARGS; + } + + return ma_job_process(pJob); +} + +MA_API ma_result ma_resource_manager_process_next_job(ma_resource_manager* pResourceManager) +{ + ma_result result; + ma_job job; + + if (pResourceManager == NULL) { + return MA_INVALID_ARGS; + } + + /* This will return MA_CANCELLED if the next job is a quit job. */ + result = ma_resource_manager_next_job(pResourceManager, &job); + if (result != MA_SUCCESS) { + return result; + } + + return ma_job_process(&job); +} +#else +/* We'll get here if the resource manager is being excluded from the build. We need to define the job processing callbacks as no-ops. */ +static ma_result ma_job_process__resource_manager__load_data_buffer_node(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__page_data_buffer_node(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__free_data_buffer(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__load_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__free_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__page_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } +static ma_result ma_job_process__resource_manager__seek_data_stream(ma_job* pJob) { return ma_job_process__noop(pJob); } +#endif /* MA_NO_RESOURCE_MANAGER */ + + +#ifndef MA_NO_NODE_GRAPH +/* 10ms @ 48K = 480. Must never exceed 65535. */ +#ifndef MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS +#define MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS 480 +#endif + + +static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime); + +MA_API void ma_debug_fill_pcm_frames_with_sine_wave(float* pFramesOut, ma_uint32 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +{ + #ifndef MA_NO_GENERATION + { + ma_waveform_config waveformConfig; + ma_waveform waveform; + + waveformConfig = ma_waveform_config_init(format, channels, sampleRate, ma_waveform_type_sine, 1.0, 400); + ma_waveform_init(&waveformConfig, &waveform); + ma_waveform_read_pcm_frames(&waveform, pFramesOut, frameCount, NULL); + } + #else + { + (void)pFramesOut; + (void)frameCount; + (void)format; + (void)channels; + (void)sampleRate; + #if defined(MA_DEBUG_OUTPUT) + { + #if _MSC_VER + #pragma message ("ma_debug_fill_pcm_frames_with_sine_wave() will do nothing because MA_NO_GENERATION is enabled.") + #endif + } + #endif + } + #endif +} + + + +static ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume) +{ + ma_uint64 iSample; + ma_uint64 sampleCount; + + if (pDst == NULL || pSrc == NULL || channels == 0) { + return MA_INVALID_ARGS; + } + + if (volume == 0) { + return MA_SUCCESS; /* No changes if the volume is 0. */ + } + + sampleCount = frameCount * channels; + + if (volume == 1) { + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pDst[iSample] += pSrc[iSample]; + } + } else { + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pDst[iSample] += ma_apply_volume_unclipped_f32(pSrc[iSample], volume); + } + } + + return MA_SUCCESS; +} + + +MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels) +{ + ma_node_graph_config config; + + MA_ZERO_OBJECT(&config); + config.channels = channels; + config.nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; + + return config; +} + + +static void ma_node_graph_set_is_reading(ma_node_graph* pNodeGraph, ma_bool32 isReading) +{ + MA_ASSERT(pNodeGraph != NULL); + c89atomic_exchange_32(&pNodeGraph->isReading, isReading); +} + +#if 0 +static ma_bool32 ma_node_graph_is_reading(ma_node_graph* pNodeGraph) +{ + MA_ASSERT(pNodeGraph != NULL); + return c89atomic_load_32(&pNodeGraph->isReading); +} +#endif + + +static void ma_node_graph_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_node_graph* pNodeGraph = (ma_node_graph*)pNode; + ma_uint64 framesRead; + + ma_node_graph_read_pcm_frames(pNodeGraph, ppFramesOut[0], *pFrameCountOut, &framesRead); + + *pFrameCountOut = (ma_uint32)framesRead; /* Safe cast. */ + + (void)ppFramesIn; + (void)pFrameCountIn; +} + +static ma_node_vtable g_node_graph_node_vtable = +{ + ma_node_graph_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 0, /* 0 input buses. */ + 1, /* 1 output bus. */ + 0 /* Flags. */ +}; + +static void ma_node_graph_endpoint_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + MA_ASSERT(pNode != NULL); + MA_ASSERT(ma_node_get_input_bus_count(pNode) == 1); + MA_ASSERT(ma_node_get_output_bus_count(pNode) == 1); + + /* Input channel count needs to be the same as the output channel count. */ + MA_ASSERT(ma_node_get_input_channels(pNode, 0) == ma_node_get_output_channels(pNode, 0)); + + /* We don't need to do anything here because it's a passthrough. */ + (void)pNode; + (void)ppFramesIn; + (void)pFrameCountIn; + (void)ppFramesOut; + (void)pFrameCountOut; + +#if 0 + /* The data has already been mixed. We just need to move it to the output buffer. */ + if (ppFramesIn != NULL) { + ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, ma_node_get_output_channels(pNode, 0)); + } +#endif +} + +static ma_node_vtable g_node_graph_endpoint_vtable = +{ + ma_node_graph_endpoint_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* 1 input bus. */ + 1, /* 1 output bus. */ + MA_NODE_FLAG_PASSTHROUGH /* Flags. The endpoint is a passthrough. */ +}; + +MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph) +{ + ma_result result; + ma_node_config baseConfig; + ma_node_config endpointConfig; + + if (pNodeGraph == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNodeGraph); + pNodeGraph->nodeCacheCapInFrames = pConfig->nodeCacheCapInFrames; + if (pNodeGraph->nodeCacheCapInFrames == 0) { + pNodeGraph->nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; + } + + + /* Base node so we can use the node graph as a node into another graph. */ + baseConfig = ma_node_config_init(); + baseConfig.vtable = &g_node_graph_node_vtable; + baseConfig.pOutputChannels = &pConfig->channels; + + result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pNodeGraph->base); + if (result != MA_SUCCESS) { + return result; + } + + + /* Endpoint. */ + endpointConfig = ma_node_config_init(); + endpointConfig.vtable = &g_node_graph_endpoint_vtable; + endpointConfig.pInputChannels = &pConfig->channels; + endpointConfig.pOutputChannels = &pConfig->channels; + + result = ma_node_init(pNodeGraph, &endpointConfig, pAllocationCallbacks, &pNodeGraph->endpoint); + if (result != MA_SUCCESS) { + ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); + return result; + } + + return MA_SUCCESS; +} + +MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pNodeGraph == NULL) { + return; + } + + ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks); +} + +MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph) +{ + if (pNodeGraph == NULL) { + return NULL; + } + + return &pNodeGraph->endpoint; +} + +MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_result result = MA_SUCCESS; + ma_uint64 totalFramesRead; + ma_uint32 channels; + + if (pFramesRead != NULL) { + *pFramesRead = 0; /* Safety. */ + } + + if (pNodeGraph == NULL) { + return MA_INVALID_ARGS; + } + + channels = ma_node_get_output_channels(&pNodeGraph->endpoint, 0); + + + /* We'll be nice and try to do a full read of all frameCount frames. */ + totalFramesRead = 0; + while (totalFramesRead < frameCount) { + ma_uint32 framesJustRead; + ma_uint64 framesToRead = frameCount - totalFramesRead; + + if (framesToRead > 0xFFFFFFFF) { + framesToRead = 0xFFFFFFFF; + } + + ma_node_graph_set_is_reading(pNodeGraph, MA_TRUE); + { + result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), (ma_uint32)framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint)); + } + ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE); + + totalFramesRead += framesJustRead; + + if (result != MA_SUCCESS) { + break; + } + + /* Abort if we weren't able to read any frames or else we risk getting stuck in a loop. */ + if (framesJustRead == 0) { + break; + } + } + + /* Let's go ahead and silence any leftover frames just for some added safety to ensure the caller doesn't try emitting garbage out of the speakers. */ + if (totalFramesRead < frameCount) { + ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), (frameCount - totalFramesRead), ma_format_f32, channels); + } + + if (pFramesRead != NULL) { + *pFramesRead = totalFramesRead; + } + + return result; +} + +MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph) +{ + if (pNodeGraph == NULL) { + return 0; + } + + return ma_node_get_output_channels(&pNodeGraph->endpoint, 0); +} + +MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph) +{ + if (pNodeGraph == NULL) { + return 0; + } + + return ma_node_get_time(&pNodeGraph->endpoint); /* Global time is just the local time of the endpoint. */ +} + +MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime) +{ + if (pNodeGraph == NULL) { + return MA_INVALID_ARGS; + } + + return ma_node_set_time(&pNodeGraph->endpoint, globalTime); /* Global time is just the local time of the endpoint. */ +} + + +#define MA_NODE_OUTPUT_BUS_FLAG_HAS_READ 0x01 /* Whether or not this bus ready to read more data. Only used on nodes with multiple output buses. */ + +static ma_result ma_node_output_bus_init(ma_node* pNode, ma_uint32 outputBusIndex, ma_uint32 channels, ma_node_output_bus* pOutputBus) +{ + MA_ASSERT(pOutputBus != NULL); + MA_ASSERT(outputBusIndex < MA_MAX_NODE_BUS_COUNT); + MA_ASSERT(outputBusIndex < ma_node_get_output_bus_count(pNode)); + MA_ASSERT(channels < 256); + + MA_ZERO_OBJECT(pOutputBus); + + if (channels == 0) { + return MA_INVALID_ARGS; + } + + pOutputBus->pNode = pNode; + pOutputBus->outputBusIndex = (ma_uint8)outputBusIndex; + pOutputBus->channels = (ma_uint8)channels; + pOutputBus->flags = MA_NODE_OUTPUT_BUS_FLAG_HAS_READ; /* <-- Important that this flag is set by default. */ + pOutputBus->volume = 1; + + return MA_SUCCESS; +} + +static void ma_node_output_bus_lock(ma_node_output_bus* pOutputBus) +{ + ma_spinlock_lock(&pOutputBus->lock); +} + +static void ma_node_output_bus_unlock(ma_node_output_bus* pOutputBus) +{ + ma_spinlock_unlock(&pOutputBus->lock); +} + + +static ma_uint32 ma_node_output_bus_get_channels(const ma_node_output_bus* pOutputBus) +{ + return pOutputBus->channels; +} + + +static void ma_node_output_bus_set_has_read(ma_node_output_bus* pOutputBus, ma_bool32 hasRead) +{ + if (hasRead) { + c89atomic_fetch_or_32(&pOutputBus->flags, MA_NODE_OUTPUT_BUS_FLAG_HAS_READ); + } else { + c89atomic_fetch_and_32(&pOutputBus->flags, (ma_uint32)~MA_NODE_OUTPUT_BUS_FLAG_HAS_READ); + } +} + +static ma_bool32 ma_node_output_bus_has_read(ma_node_output_bus* pOutputBus) +{ + return (c89atomic_load_32(&pOutputBus->flags) & MA_NODE_OUTPUT_BUS_FLAG_HAS_READ) != 0; +} + + +static void ma_node_output_bus_set_is_attached(ma_node_output_bus* pOutputBus, ma_bool32 isAttached) +{ + c89atomic_exchange_32(&pOutputBus->isAttached, isAttached); +} + +static ma_bool32 ma_node_output_bus_is_attached(ma_node_output_bus* pOutputBus) +{ + return c89atomic_load_32(&pOutputBus->isAttached); +} + + +static ma_result ma_node_output_bus_set_volume(ma_node_output_bus* pOutputBus, float volume) +{ + MA_ASSERT(pOutputBus != NULL); + + if (volume < 0.0f) { + volume = 0.0f; + } + + c89atomic_exchange_f32(&pOutputBus->volume, volume); + + return MA_SUCCESS; +} + +static float ma_node_output_bus_get_volume(const ma_node_output_bus* pOutputBus) +{ + return c89atomic_load_f32((float*)&pOutputBus->volume); +} + + +static ma_result ma_node_input_bus_init(ma_uint32 channels, ma_node_input_bus* pInputBus) +{ + MA_ASSERT(pInputBus != NULL); + MA_ASSERT(channels < 256); + + MA_ZERO_OBJECT(pInputBus); + + if (channels == 0) { + return MA_INVALID_ARGS; + } + + pInputBus->channels = (ma_uint8)channels; + + return MA_SUCCESS; +} + +static void ma_node_input_bus_lock(ma_node_input_bus* pInputBus) +{ + ma_spinlock_lock(&pInputBus->lock); +} + +static void ma_node_input_bus_unlock(ma_node_input_bus* pInputBus) +{ + ma_spinlock_unlock(&pInputBus->lock); +} + + +static void ma_node_input_bus_next_begin(ma_node_input_bus* pInputBus) +{ + c89atomic_fetch_add_32(&pInputBus->nextCounter, 1); +} + +static void ma_node_input_bus_next_end(ma_node_input_bus* pInputBus) +{ + c89atomic_fetch_sub_32(&pInputBus->nextCounter, 1); +} + +static ma_uint32 ma_node_input_bus_get_next_counter(ma_node_input_bus* pInputBus) +{ + return c89atomic_load_32(&pInputBus->nextCounter); +} + + +static ma_uint32 ma_node_input_bus_get_channels(const ma_node_input_bus* pInputBus) +{ + return pInputBus->channels; +} + + +static void ma_node_input_bus_detach__no_output_bus_lock(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus) +{ + MA_ASSERT(pInputBus != NULL); + MA_ASSERT(pOutputBus != NULL); + + /* + Mark the output bus as detached first. This will prevent future iterations on the audio thread + from iterating this output bus. + */ + ma_node_output_bus_set_is_attached(pOutputBus, MA_FALSE); + + /* + We cannot use the output bus lock here since it'll be getting used at a higher level, but we do + still need to use the input bus lock since we'll be updating pointers on two different output + buses. The same rules apply here as the attaching case. Although we're using a lock here, we're + *not* using a lock when iterating over the list in the audio thread. We therefore need to craft + this in a way such that the iteration on the audio thread doesn't break. + + The the first thing to do is swap out the "next" pointer of the previous output bus with the + new "next" output bus. This is the operation that matters for iteration on the audio thread. + After that, the previous pointer on the new "next" pointer needs to be updated, after which + point the linked list will be in a good state. + */ + ma_node_input_bus_lock(pInputBus); + { + ma_node_output_bus* pOldPrev = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pPrev); + ma_node_output_bus* pOldNext = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pNext); + + if (pOldPrev != NULL) { + c89atomic_exchange_ptr(&pOldPrev->pNext, pOldNext); /* <-- This is where the output bus is detached from the list. */ + } + if (pOldNext != NULL) { + c89atomic_exchange_ptr(&pOldNext->pPrev, pOldPrev); /* <-- This is required for detachment. */ + } + } + ma_node_input_bus_unlock(pInputBus); + + /* At this point the output bus is detached and the linked list is completely unaware of it. Reset some data for safety. */ + c89atomic_exchange_ptr(&pOutputBus->pNext, NULL); /* Using atomic exchanges here, mainly for the benefit of analysis tools which don't always recognize spinlocks. */ + c89atomic_exchange_ptr(&pOutputBus->pPrev, NULL); /* As above. */ + pOutputBus->pInputNode = NULL; + pOutputBus->inputNodeInputBusIndex = 0; + + + /* + For thread-safety reasons, we don't want to be returning from this straight away. We need to + wait for the audio thread to finish with the output bus. There's two things we need to wait + for. The first is the part that selects the next output bus in the list, and the other is the + part that reads from the output bus. Basically all we're doing is waiting for the input bus + to stop referencing the output bus. + + We're doing this part last because we want the section above to run while the audio thread + is finishing up with the output bus, just for efficiency reasons. We marked the output bus as + detached right at the top of this function which is going to prevent the audio thread from + iterating the output bus again. + */ + + /* Part 1: Wait for the current iteration to complete. */ + while (ma_node_input_bus_get_next_counter(pInputBus) > 0) { + ma_yield(); + } + + /* Part 2: Wait for any reads to complete. */ + while (c89atomic_load_32(&pOutputBus->refCount) > 0) { + ma_yield(); + } + + /* + At this point we're done detaching and we can be guaranteed that the audio thread is not going + to attempt to reference this output bus again (until attached again). + */ +} + +#if 0 /* Not used at the moment, but leaving here in case I need it later. */ +static void ma_node_input_bus_detach(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus) +{ + MA_ASSERT(pInputBus != NULL); + MA_ASSERT(pOutputBus != NULL); + + ma_node_output_bus_lock(pOutputBus); + { + ma_node_input_bus_detach__no_output_bus_lock(pInputBus, pOutputBus); + } + ma_node_output_bus_unlock(pOutputBus); +} +#endif + +static void ma_node_input_bus_attach(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus, ma_node* pNewInputNode, ma_uint32 inputNodeInputBusIndex) +{ + MA_ASSERT(pInputBus != NULL); + MA_ASSERT(pOutputBus != NULL); + + ma_node_output_bus_lock(pOutputBus); + { + ma_node_output_bus* pOldInputNode = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pInputNode); + + /* Detach from any existing attachment first if necessary. */ + if (pOldInputNode != NULL) { + ma_node_input_bus_detach__no_output_bus_lock(pInputBus, pOutputBus); + } + + /* + At this point we can be sure the output bus is not attached to anything. The linked list in the + old input bus has been updated so that pOutputBus will not get iterated again. + */ + pOutputBus->pInputNode = pNewInputNode; /* No need for an atomic assignment here because modification of this variable always happens within a lock. */ + pOutputBus->inputNodeInputBusIndex = (ma_uint8)inputNodeInputBusIndex; /* As above. */ + + /* + Now we need to attach the output bus to the linked list. This involves updating two pointers on + two different output buses so I'm going to go ahead and keep this simple and just use a lock. + There are ways to do this without a lock, but it's just too hard to maintain for it's value. + + Although we're locking here, it's important to remember that we're *not* locking when iterating + and reading audio data since that'll be running on the audio thread. As a result we need to be + careful how we craft this so that we don't break iteration. What we're going to do is always + attach the new item so that it becomes the first item in the list. That way, as we're iterating + we won't break any links in the list and iteration will continue safely. The detaching case will + also be crafted in a way as to not break list iteration. It's important to remember to use + atomic exchanges here since no locking is happening on the audio thread during iteration. + */ + ma_node_input_bus_lock(pInputBus); + { + ma_node_output_bus* pNewPrev = &pInputBus->head; + ma_node_output_bus* pNewNext = (ma_node_output_bus*)c89atomic_load_ptr(&pInputBus->head.pNext); + + /* Update the local output bus. */ + c89atomic_exchange_ptr(&pOutputBus->pPrev, pNewPrev); + c89atomic_exchange_ptr(&pOutputBus->pNext, pNewNext); + + /* Update the other output buses to point back to the local output bus. */ + c89atomic_exchange_ptr(&pInputBus->head.pNext, pOutputBus); /* <-- This is where the output bus is actually attached to the input bus. */ + + /* Do the previous pointer last. This is only used for detachment. */ + if (pNewNext != NULL) { + c89atomic_exchange_ptr(&pNewNext->pPrev, pOutputBus); + } + } + ma_node_input_bus_unlock(pInputBus); + + /* + Mark the node as attached last. This is used to controlling whether or the output bus will be + iterated on the audio thread. Mainly required for detachment purposes. + */ + ma_node_output_bus_set_is_attached(pOutputBus, MA_TRUE); + } + ma_node_output_bus_unlock(pOutputBus); +} + +static ma_node_output_bus* ma_node_input_bus_next(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus) +{ + ma_node_output_bus* pNext; + + MA_ASSERT(pInputBus != NULL); + + if (pOutputBus == NULL) { + return NULL; + } + + ma_node_input_bus_next_begin(pInputBus); + { + pNext = pOutputBus; + for (;;) { + pNext = (ma_node_output_bus*)c89atomic_load_ptr(&pNext->pNext); + if (pNext == NULL) { + break; /* Reached the end. */ + } + + if (ma_node_output_bus_is_attached(pNext) == MA_FALSE) { + continue; /* The node is not attached. Keep checking. */ + } + + /* The next node has been selected. */ + break; + } + + /* We need to increment the reference count of the selected node. */ + if (pNext != NULL) { + c89atomic_fetch_add_32(&pNext->refCount, 1); + } + + /* The previous node is no longer being referenced. */ + c89atomic_fetch_sub_32(&pOutputBus->refCount, 1); + } + ma_node_input_bus_next_end(pInputBus); + + return pNext; +} + +static ma_node_output_bus* ma_node_input_bus_first(ma_node_input_bus* pInputBus) +{ + return ma_node_input_bus_next(pInputBus, &pInputBus->head); +} + + + +static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_input_bus* pInputBus, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime) +{ + ma_result result = MA_SUCCESS; + ma_node_output_bus* pOutputBus; + ma_node_output_bus* pFirst; + ma_uint32 inputChannels; + ma_bool32 doesOutputBufferHaveContent = MA_FALSE; + + /* + This will be called from the audio thread which means we can't be doing any locking. Basically, + this function will not perfom any locking, whereas attaching and detaching will, but crafted in + such a way that we don't need to perform any locking here. The important thing to remember is + to always iterate in a forward direction. + + In order to process any data we need to first read from all input buses. That's where this + function comes in. This iterates over each of the attachments and accumulates/mixes them. We + also convert the channels to the nodes output channel count before mixing. We want to do this + channel conversion so that the caller of this function can invoke the processing callback + without having to do it themselves. + + When we iterate over each of the attachments on the input bus, we need to read as much data as + we can from each of them so that we don't end up with holes between each of the attachments. To + do this, we need to read from each attachment in a loop and read as many frames as we can, up + to `frameCount`. + */ + MA_ASSERT(pInputNode != NULL); + MA_ASSERT(pFramesRead != NULL); /* pFramesRead is critical and must always be specified. On input it's undefined and on output it'll be set to the number of frames actually read. */ + + *pFramesRead = 0; /* Safety. */ + + inputChannels = ma_node_input_bus_get_channels(pInputBus); + + /* + We need to be careful with how we call ma_node_input_bus_first() and ma_node_input_bus_next(). They + are both critical to our lock-free thread-safety system. We can only call ma_node_input_bus_first() + once per iteration, however we have an optimization to checks whether or not it's the first item in + the list. We therefore need to store a pointer to the first item rather than repeatedly calling + ma_node_input_bus_first(). It's safe to keep hold of this pointer, so long as we don't dereference it + after calling ma_node_input_bus_next(), which we won't be. + */ + pFirst = ma_node_input_bus_first(pInputBus); + if (pFirst == NULL) { + return MA_SUCCESS; /* No attachments. Read nothing. */ + } + + for (pOutputBus = pFirst; pOutputBus != NULL; pOutputBus = ma_node_input_bus_next(pInputBus, pOutputBus)) { + ma_uint32 framesProcessed = 0; + ma_bool32 isSilentOutput = MA_FALSE; + + MA_ASSERT(pOutputBus->pNode != NULL); + + isSilentOutput = (((ma_node_base*)pOutputBus->pNode)->vtable->flags & MA_NODE_FLAG_SILENT_OUTPUT) != 0; + + if (pFramesOut != NULL) { + /* Read. */ + float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)]; + ma_uint32 tempCapInFrames = ma_countof(temp) / inputChannels; + + while (framesProcessed < frameCount) { + float* pRunningFramesOut; + ma_uint32 framesToRead; + ma_uint32 framesJustRead; + + framesToRead = frameCount - framesProcessed; + if (framesToRead > tempCapInFrames) { + framesToRead = tempCapInFrames; + } + + pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(pFramesOut, framesProcessed, inputChannels); + + if (doesOutputBufferHaveContent == MA_FALSE) { + /* Fast path. First attachment. We just read straight into the output buffer (no mixing required). */ + result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pRunningFramesOut, framesToRead, &framesJustRead, globalTime + framesProcessed); + } else { + /* Slow path. Not the first attachment. Mixing required. */ + result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, temp, framesToRead, &framesJustRead, globalTime + framesProcessed); + if (result == MA_SUCCESS || result == MA_AT_END) { + if (isSilentOutput == MA_FALSE) { /* Don't mix if the node outputs silence. */ + ma_mix_pcm_frames_f32(pRunningFramesOut, temp, framesJustRead, inputChannels, /*volume*/1); + } + } + } + + framesProcessed += framesJustRead; + + /* If we reached the end or otherwise failed to read any data we need to finish up with this output node. */ + if (result != MA_SUCCESS) { + break; + } + + /* If we didn't read anything, abort so we don't get stuck in a loop. */ + if (framesJustRead == 0) { + break; + } + } + + /* If it's the first attachment we didn't do any mixing. Any leftover samples need to be silenced. */ + if (pOutputBus == pFirst && framesProcessed < frameCount) { + ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, framesProcessed, ma_format_f32, inputChannels), (frameCount - framesProcessed), ma_format_f32, inputChannels); + } + + if (isSilentOutput == MA_FALSE) { + doesOutputBufferHaveContent = MA_TRUE; + } + } else { + /* Seek. */ + ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, NULL, frameCount, &framesProcessed, globalTime); + } + } + + /* If we didn't output anything, output silence. */ + if (doesOutputBufferHaveContent == MA_FALSE && pFramesOut != NULL) { + ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, inputChannels); + } + + /* In this path we always "process" the entire amount. */ + *pFramesRead = frameCount; + + return result; +} + + +MA_API ma_node_config ma_node_config_init(void) +{ + ma_node_config config; + + MA_ZERO_OBJECT(&config); + config.initialState = ma_node_state_started; /* Nodes are started by default. */ + config.inputBusCount = MA_NODE_BUS_COUNT_UNKNOWN; + config.outputBusCount = MA_NODE_BUS_COUNT_UNKNOWN; + + return config; +} + + + +static ma_result ma_node_detach_full(ma_node* pNode); + +static float* ma_node_get_cached_input_ptr(ma_node* pNode, ma_uint32 inputBusIndex) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_uint32 iInputBus; + float* pBasePtr; + + MA_ASSERT(pNodeBase != NULL); + + /* Input data is stored at the front of the buffer. */ + pBasePtr = pNodeBase->pCachedData; + for (iInputBus = 0; iInputBus < inputBusIndex; iInputBus += 1) { + pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iInputBus]); + } + + return pBasePtr; +} + +static float* ma_node_get_cached_output_ptr(ma_node* pNode, ma_uint32 outputBusIndex) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_uint32 iInputBus; + ma_uint32 iOutputBus; + float* pBasePtr; + + MA_ASSERT(pNodeBase != NULL); + + /* Cached output data starts after the input data. */ + pBasePtr = pNodeBase->pCachedData; + for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) { + pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iInputBus]); + } + + for (iOutputBus = 0; iOutputBus < outputBusIndex; iOutputBus += 1) { + pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iOutputBus]); + } + + return pBasePtr; +} + + +typedef struct +{ + size_t sizeInBytes; + size_t inputBusOffset; + size_t outputBusOffset; + size_t cachedDataOffset; + ma_uint32 inputBusCount; /* So it doesn't have to be calculated twice. */ + ma_uint32 outputBusCount; /* So it doesn't have to be calculated twice. */ +} ma_node_heap_layout; + +static ma_result ma_node_translate_bus_counts(const ma_node_config* pConfig, ma_uint32* pInputBusCount, ma_uint32* pOutputBusCount) +{ + ma_uint32 inputBusCount; + ma_uint32 outputBusCount; + + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pInputBusCount != NULL); + MA_ASSERT(pOutputBusCount != NULL); + + /* Bus counts are determined by the vtable, unless they're set to `MA_NODE_BUS_COUNT_UNKNWON`, in which case they're taken from the config. */ + if (pConfig->vtable->inputBusCount == MA_NODE_BUS_COUNT_UNKNOWN) { + inputBusCount = pConfig->inputBusCount; + } else { + inputBusCount = pConfig->vtable->inputBusCount; + + if (pConfig->inputBusCount != MA_NODE_BUS_COUNT_UNKNOWN && pConfig->inputBusCount != pConfig->vtable->inputBusCount) { + return MA_INVALID_ARGS; /* Invalid configuration. You must not specify a conflicting bus count between the node's config and the vtable. */ + } + } + + if (pConfig->vtable->outputBusCount == MA_NODE_BUS_COUNT_UNKNOWN) { + outputBusCount = pConfig->outputBusCount; + } else { + outputBusCount = pConfig->vtable->outputBusCount; + + if (pConfig->outputBusCount != MA_NODE_BUS_COUNT_UNKNOWN && pConfig->outputBusCount != pConfig->vtable->outputBusCount) { + return MA_INVALID_ARGS; /* Invalid configuration. You must not specify a conflicting bus count between the node's config and the vtable. */ + } + } + + /* Bus counts must be within limits. */ + if (inputBusCount > MA_MAX_NODE_BUS_COUNT || outputBusCount > MA_MAX_NODE_BUS_COUNT) { + return MA_INVALID_ARGS; + } + + + /* We must have channel counts for each bus. */ + if ((inputBusCount > 0 && pConfig->pInputChannels == NULL) || (outputBusCount > 0 && pConfig->pOutputChannels == NULL)) { + return MA_INVALID_ARGS; /* You must specify channel counts for each input and output bus. */ + } + + + /* Some special rules for passthrough nodes. */ + if ((pConfig->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) { + if (pConfig->vtable->inputBusCount != 1 || pConfig->vtable->outputBusCount != 1) { + return MA_INVALID_ARGS; /* Passthrough nodes must have exactly 1 input bus and 1 output bus. */ + } + + if (pConfig->pInputChannels[0] != pConfig->pOutputChannels[0]) { + return MA_INVALID_ARGS; /* Passthrough nodes must have the same number of channels between input and output nodes. */ + } + } + + + *pInputBusCount = inputBusCount; + *pOutputBusCount = outputBusCount; + + return MA_SUCCESS; +} + +static ma_result ma_node_get_heap_layout(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, ma_node_heap_layout* pHeapLayout) +{ + ma_result result; + ma_uint32 inputBusCount; + ma_uint32 outputBusCount; + + MA_ASSERT(pHeapLayout != NULL); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL || pConfig->vtable == NULL || pConfig->vtable->onProcess == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_node_translate_bus_counts(pConfig, &inputBusCount, &outputBusCount); + if (result != MA_SUCCESS) { + return result; + } + + pHeapLayout->sizeInBytes = 0; + + /* Input buses. */ + if (inputBusCount > MA_MAX_NODE_LOCAL_BUS_COUNT) { + pHeapLayout->inputBusOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(sizeof(ma_node_input_bus) * inputBusCount); + } else { + pHeapLayout->inputBusOffset = MA_SIZE_MAX; /* MA_SIZE_MAX indicates that no heap allocation is required for the input bus. */ + } + + /* Output buses. */ + if (outputBusCount > MA_MAX_NODE_LOCAL_BUS_COUNT) { + pHeapLayout->outputBusOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(sizeof(ma_node_output_bus) * outputBusCount); + } else { + pHeapLayout->outputBusOffset = MA_SIZE_MAX; + } + + /* + Cached audio data. + + We need to allocate memory for a caching both input and output data. We have an optimization + where no caching is necessary for specific conditions: + + - The node has 0 inputs and 1 output. + + When a node meets the above conditions, no cache is allocated. + + The size choice for this buffer is a little bit finicky. We don't want to be too wasteful by + allocating too much, but at the same time we want it be large enough so that enough frames can + be processed for each call to ma_node_read_pcm_frames() so that it keeps things efficient. For + now I'm going with 10ms @ 48K which is 480 frames per bus. This is configurable at compile + time. It might also be worth investigating whether or not this can be configured at run time. + */ + if (inputBusCount == 0 && outputBusCount == 1) { + /* Fast path. No cache needed. */ + pHeapLayout->cachedDataOffset = MA_SIZE_MAX; + } else { + /* Slow path. Cache needed. */ + size_t cachedDataSizeInBytes = 0; + ma_uint32 iBus; + + for (iBus = 0; iBus < inputBusCount; iBus += 1) { + cachedDataSizeInBytes += pNodeGraph->nodeCacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pInputChannels[iBus]); + } + + for (iBus = 0; iBus < outputBusCount; iBus += 1) { + cachedDataSizeInBytes += pNodeGraph->nodeCacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pOutputChannels[iBus]); + } + + pHeapLayout->cachedDataOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(cachedDataSizeInBytes); + } + + + /* + Not technically part of the heap, but we can output the input and output bus counts so we can + avoid a redundant call to ma_node_translate_bus_counts(). + */ + pHeapLayout->inputBusCount = inputBusCount; + pHeapLayout->outputBusCount = outputBusCount; + + /* Make sure allocation size is aligned. */ + pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes); + + return MA_SUCCESS; +} + +MA_API ma_result ma_node_get_heap_size(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_node_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_node_get_heap_layout(pNodeGraph, pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_result result; + ma_node_heap_layout heapLayout; + ma_uint32 iInputBus; + ma_uint32 iOutputBus; + + if (pNodeBase == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNodeBase); + + result = ma_node_get_heap_layout(pNodeGraph, pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pNodeBase->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pNodeBase->pNodeGraph = pNodeGraph; + pNodeBase->vtable = pConfig->vtable; + pNodeBase->state = pConfig->initialState; + pNodeBase->stateTimes[ma_node_state_started] = 0; + pNodeBase->stateTimes[ma_node_state_stopped] = (ma_uint64)(ma_int64)-1; /* Weird casting for VC6 compatibility. */ + pNodeBase->inputBusCount = heapLayout.inputBusCount; + pNodeBase->outputBusCount = heapLayout.outputBusCount; + + if (heapLayout.inputBusOffset != MA_SIZE_MAX) { + pNodeBase->pInputBuses = (ma_node_input_bus*)ma_offset_ptr(pHeap, heapLayout.inputBusOffset); + } else { + pNodeBase->pInputBuses = pNodeBase->_inputBuses; + } + + if (heapLayout.outputBusOffset != MA_SIZE_MAX) { + pNodeBase->pOutputBuses = (ma_node_output_bus*)ma_offset_ptr(pHeap, heapLayout.inputBusOffset); + } else { + pNodeBase->pOutputBuses = pNodeBase->_outputBuses; + } + + if (heapLayout.cachedDataOffset != MA_SIZE_MAX) { + pNodeBase->pCachedData = (float*)ma_offset_ptr(pHeap, heapLayout.cachedDataOffset); + pNodeBase->cachedDataCapInFramesPerBus = pNodeGraph->nodeCacheCapInFrames; + } else { + pNodeBase->pCachedData = NULL; + } + + + + /* We need to run an initialization step for each input and output bus. */ + for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) { + result = ma_node_input_bus_init(pConfig->pInputChannels[iInputBus], &pNodeBase->pInputBuses[iInputBus]); + if (result != MA_SUCCESS) { + return result; + } + } + + for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNodeBase); iOutputBus += 1) { + result = ma_node_output_bus_init(pNodeBase, iOutputBus, pConfig->pOutputChannels[iOutputBus], &pNodeBase->pOutputBuses[iOutputBus]); + if (result != MA_SUCCESS) { + return result; + } + } + + + /* The cached data needs to be initialized to silence (or a sine wave tone if we're debugging). */ + if (pNodeBase->pCachedData != NULL) { + ma_uint32 iBus; + + #if 1 /* Toggle this between 0 and 1 to turn debugging on or off. 1 = fill with a sine wave for debugging; 0 = fill with silence. */ + /* For safety we'll go ahead and default the buffer to silence. */ + for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) { + ma_silence_pcm_frames(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iBus])); + } + for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) { + ma_silence_pcm_frames(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iBus])); + } + #else + /* For debugging. Default to a sine wave. */ + for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) { + ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iBus]), 48000); + } + for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) { + ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iBus]), 48000); + } + #endif + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_node_get_heap_size(pNodeGraph, pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_node_init_preallocated(pNodeGraph, pConfig, pHeap, pNode); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + ((ma_node_base*)pNode)->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + + if (pNodeBase == NULL) { + return; + } + + /* + The first thing we need to do is fully detach the node. This will detach all inputs and + outputs. We need to do this first because it will sever the connection with the node graph and + allow us to complete uninitialization without needing to worry about thread-safety with the + audio thread. The detachment process will wait for any local processing of the node to finish. + */ + ma_node_detach_full(pNode); + + /* + At this point the node should be completely unreferenced by the node graph and we can finish up + the uninitialization process without needing to worry about thread-safety. + */ + if (pNodeBase->_ownsHeap) { + ma_free(pNodeBase->_pHeap, pAllocationCallbacks); + } +} + +MA_API ma_node_graph* ma_node_get_node_graph(const ma_node* pNode) +{ + if (pNode == NULL) { + return NULL; + } + + return ((const ma_node_base*)pNode)->pNodeGraph; +} + +MA_API ma_uint32 ma_node_get_input_bus_count(const ma_node* pNode) +{ + if (pNode == NULL) { + return 0; + } + + return ((ma_node_base*)pNode)->inputBusCount; +} + +MA_API ma_uint32 ma_node_get_output_bus_count(const ma_node* pNode) +{ + if (pNode == NULL) { + return 0; + } + + return ((ma_node_base*)pNode)->outputBusCount; +} + + +MA_API ma_uint32 ma_node_get_input_channels(const ma_node* pNode, ma_uint32 inputBusIndex) +{ + const ma_node_base* pNodeBase = (const ma_node_base*)pNode; + + if (pNode == NULL) { + return 0; + } + + if (inputBusIndex >= ma_node_get_input_bus_count(pNode)) { + return 0; /* Invalid bus index. */ + } + + return ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[inputBusIndex]); +} + +MA_API ma_uint32 ma_node_get_output_channels(const ma_node* pNode, ma_uint32 outputBusIndex) +{ + const ma_node_base* pNodeBase = (const ma_node_base*)pNode; + + if (pNode == NULL) { + return 0; + } + + if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { + return 0; /* Invalid bus index. */ + } + + return ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[outputBusIndex]); +} + + +static ma_result ma_node_detach_full(ma_node* pNode) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_uint32 iInputBus; + + if (pNodeBase == NULL) { + return MA_INVALID_ARGS; + } + + /* + Make sure the node is completely detached first. This will not return until the output bus is + guaranteed to no longer be referenced by the audio thread. + */ + ma_node_detach_all_output_buses(pNode); + + /* + At this point all output buses will have been detached from the graph and we can be guaranteed + that none of it's input nodes will be getting processed by the graph. We can detach these + without needing to worry about the audio thread touching them. + */ + for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNode); iInputBus += 1) { + ma_node_input_bus* pInputBus; + ma_node_output_bus* pOutputBus; + + pInputBus = &pNodeBase->pInputBuses[iInputBus]; + + /* + This is important. We cannot be using ma_node_input_bus_first() or ma_node_input_bus_next(). Those + functions are specifically for the audio thread. We'll instead just manually iterate using standard + linked list logic. We don't need to worry about the audio thread referencing these because the step + above severed the connection to the graph. + */ + for (pOutputBus = (ma_node_output_bus*)c89atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pNext)) { + ma_node_detach_output_bus(pOutputBus->pNode, pOutputBus->outputBusIndex); /* This won't do any waiting in practice and should be efficient. */ + } + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_node_detach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex) +{ + ma_result result = MA_SUCCESS; + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_node_base* pInputNodeBase; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { + return MA_INVALID_ARGS; /* Invalid output bus index. */ + } + + /* We need to lock the output bus because we need to inspect the input node and grab it's input bus. */ + ma_node_output_bus_lock(&pNodeBase->pOutputBuses[outputBusIndex]); + { + pInputNodeBase = (ma_node_base*)pNodeBase->pOutputBuses[outputBusIndex].pInputNode; + if (pInputNodeBase != NULL) { + ma_node_input_bus_detach__no_output_bus_lock(&pInputNodeBase->pInputBuses[pNodeBase->pOutputBuses[outputBusIndex].inputNodeInputBusIndex], &pNodeBase->pOutputBuses[outputBusIndex]); + } + } + ma_node_output_bus_unlock(&pNodeBase->pOutputBuses[outputBusIndex]); + + return result; +} + +MA_API ma_result ma_node_detach_all_output_buses(ma_node* pNode) +{ + ma_uint32 iOutputBus; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNode); iOutputBus += 1) { + ma_node_detach_output_bus(pNode, iOutputBus); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_node_attach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex, ma_node* pOtherNode, ma_uint32 otherNodeInputBusIndex) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_node_base* pOtherNodeBase = (ma_node_base*)pOtherNode; + + if (pNodeBase == NULL || pOtherNodeBase == NULL) { + return MA_INVALID_ARGS; + } + + if (pNodeBase == pOtherNodeBase) { + return MA_INVALID_OPERATION; /* Cannot attach a node to itself. */ + } + + if (outputBusIndex >= ma_node_get_output_bus_count(pNode) || otherNodeInputBusIndex >= ma_node_get_input_bus_count(pOtherNode)) { + return MA_INVALID_OPERATION; /* Invalid bus index. */ + } + + /* The output channel count of the output node must be the same as the input channel count of the input node. */ + if (ma_node_get_output_channels(pNode, outputBusIndex) != ma_node_get_input_channels(pOtherNode, otherNodeInputBusIndex)) { + return MA_INVALID_OPERATION; /* Channel count is incompatible. */ + } + + /* This will deal with detaching if the output bus is already attached to something. */ + ma_node_input_bus_attach(&pOtherNodeBase->pInputBuses[otherNodeInputBusIndex], &pNodeBase->pOutputBuses[outputBusIndex], pOtherNode, otherNodeInputBusIndex); + + return MA_SUCCESS; +} + +MA_API ma_result ma_node_set_output_bus_volume(ma_node* pNode, ma_uint32 outputBusIndex, float volume) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + + if (pNodeBase == NULL) { + return MA_INVALID_ARGS; + } + + if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { + return MA_INVALID_ARGS; /* Invalid bus index. */ + } + + return ma_node_output_bus_set_volume(&pNodeBase->pOutputBuses[outputBusIndex], volume); +} + +MA_API float ma_node_get_output_bus_volume(const ma_node* pNode, ma_uint32 outputBusIndex) +{ + const ma_node_base* pNodeBase = (const ma_node_base*)pNode; + + if (pNodeBase == NULL) { + return 0; + } + + if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) { + return 0; /* Invalid bus index. */ + } + + return ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex]); +} + +MA_API ma_result ma_node_set_state(ma_node* pNode, ma_node_state state) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + + if (pNodeBase == NULL) { + return MA_INVALID_ARGS; + } + + c89atomic_exchange_i32(&pNodeBase->state, state); + + return MA_SUCCESS; +} + +MA_API ma_node_state ma_node_get_state(const ma_node* pNode) +{ + const ma_node_base* pNodeBase = (const ma_node_base*)pNode; + + if (pNodeBase == NULL) { + return ma_node_state_stopped; + } + + return (ma_node_state)c89atomic_load_i32(&pNodeBase->state); +} + +MA_API ma_result ma_node_set_state_time(ma_node* pNode, ma_node_state state, ma_uint64 globalTime) +{ + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + /* Validation check for safety since we'll be using this as an index into stateTimes[]. */ + if (state != ma_node_state_started && state != ma_node_state_stopped) { + return MA_INVALID_ARGS; + } + + c89atomic_exchange_64(&((ma_node_base*)pNode)->stateTimes[state], globalTime); + + return MA_SUCCESS; +} + +MA_API ma_uint64 ma_node_get_state_time(const ma_node* pNode, ma_node_state state) +{ + if (pNode == NULL) { + return 0; + } + + /* Validation check for safety since we'll be using this as an index into stateTimes[]. */ + if (state != ma_node_state_started && state != ma_node_state_stopped) { + return 0; + } + + return c89atomic_load_64(&((ma_node_base*)pNode)->stateTimes[state]); +} + +MA_API ma_node_state ma_node_get_state_by_time(const ma_node* pNode, ma_uint64 globalTime) +{ + if (pNode == NULL) { + return ma_node_state_stopped; + } + + return ma_node_get_state_by_time_range(pNode, globalTime, globalTime); +} + +MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_uint64 globalTimeBeg, ma_uint64 globalTimeEnd) +{ + ma_node_state state; + + if (pNode == NULL) { + return ma_node_state_stopped; + } + + state = ma_node_get_state(pNode); + + /* An explicitly stopped node is always stopped. */ + if (state == ma_node_state_stopped) { + return ma_node_state_stopped; + } + + /* + Getting here means the node is marked as started, but it may still not be truly started due to + it's start time not having been reached yet. Also, the stop time may have also been reached in + which case it'll be considered stopped. + */ + if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeBeg) { + return ma_node_state_stopped; /* Start time has not yet been reached. */ + } + + if (ma_node_get_state_time(pNode, ma_node_state_stopped) <= globalTimeEnd) { + return ma_node_state_stopped; /* Stop time has been reached. */ + } + + /* Getting here means the node is marked as started and is within it's start/stop times. */ + return ma_node_state_started; +} + +MA_API ma_uint64 ma_node_get_time(const ma_node* pNode) +{ + if (pNode == NULL) { + return 0; + } + + return c89atomic_load_64(&((ma_node_base*)pNode)->localTime); +} + +MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime) +{ + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + c89atomic_exchange_64(&((ma_node_base*)pNode)->localTime, localTime); + + return MA_SUCCESS; +} + + + +static void ma_node_process_pcm_frames_internal(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + + MA_ASSERT(pNode != NULL); + + if (pNodeBase->vtable->onProcess) { + pNodeBase->vtable->onProcess(pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut); + } +} + +static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_result result = MA_SUCCESS; + ma_uint32 iInputBus; + ma_uint32 iOutputBus; + ma_uint32 inputBusCount; + ma_uint32 outputBusCount; + ma_uint32 totalFramesRead = 0; + float* ppFramesIn[MA_MAX_NODE_BUS_COUNT]; + float* ppFramesOut[MA_MAX_NODE_BUS_COUNT]; + ma_uint64 globalTimeBeg; + ma_uint64 globalTimeEnd; + ma_uint64 startTime; + ma_uint64 stopTime; + ma_uint32 timeOffsetBeg; + ma_uint32 timeOffsetEnd; + ma_uint32 frameCountIn; + ma_uint32 frameCountOut; + + /* + pFramesRead is mandatory. It must be used to determine how many frames were read. It's normal and + expected that the number of frames read may be different to that requested. Therefore, the caller + must look at this value to correctly determine how many frames were read. + */ + MA_ASSERT(pFramesRead != NULL); /* <-- If you've triggered this assert, you're using this function wrong. You *must* use this variable and inspect it after the call returns. */ + if (pFramesRead == NULL) { + return MA_INVALID_ARGS; + } + + *pFramesRead = 0; /* Safety. */ + + if (pNodeBase == NULL) { + return MA_INVALID_ARGS; + } + + if (outputBusIndex >= ma_node_get_output_bus_count(pNodeBase)) { + return MA_INVALID_ARGS; /* Invalid output bus index. */ + } + + /* Don't do anything if we're in a stopped state. */ + if (ma_node_get_state_by_time_range(pNode, globalTime, globalTime + frameCount) != ma_node_state_started) { + return MA_SUCCESS; /* We're in a stopped state. This is not an error - we just need to not read anything. */ + } + + + globalTimeBeg = globalTime; + globalTimeEnd = globalTime + frameCount; + startTime = ma_node_get_state_time(pNode, ma_node_state_started); + stopTime = ma_node_get_state_time(pNode, ma_node_state_stopped); + + /* + At this point we know that we are inside our start/stop times. However, we may need to adjust + our frame count and output pointer to accomodate since we could be straddling the time period + that this function is getting called for. + + It's possible (and likely) that the start time does not line up with the output buffer. We + therefore need to offset it by a number of frames to accomodate. The same thing applies for + the stop time. + */ + timeOffsetBeg = (globalTimeBeg < startTime) ? (ma_uint32)(globalTimeEnd - startTime) : 0; + timeOffsetEnd = (globalTimeEnd > stopTime) ? (ma_uint32)(globalTimeEnd - stopTime) : 0; + + /* Trim based on the start offset. We need to silence the start of the buffer. */ + if (timeOffsetBeg > 0) { + ma_silence_pcm_frames(pFramesOut, timeOffsetBeg, ma_format_f32, ma_node_get_output_channels(pNode, outputBusIndex)); + pFramesOut += timeOffsetBeg * ma_node_get_output_channels(pNode, outputBusIndex); + frameCount -= timeOffsetBeg; + } + + /* Trim based on the end offset. We don't need to silence the tail section because we'll just have a reduced value written to pFramesRead. */ + if (timeOffsetEnd > 0) { + frameCount -= timeOffsetEnd; + } + + + /* We run on different paths depending on the bus counts. */ + inputBusCount = ma_node_get_input_bus_count(pNode); + outputBusCount = ma_node_get_output_bus_count(pNode); + + /* + Run a simplified path when there are no inputs and one output. In this case there's nothing to + actually read and we can go straight to output. This is a very common scenario because the vast + majority of data source nodes will use this setup so this optimization I think is worthwhile. + */ + if (inputBusCount == 0 && outputBusCount == 1) { + /* Fast path. No need to read from input and no need for any caching. */ + frameCountIn = 0; + frameCountOut = frameCount; /* Just read as much as we can. The callback will return what was actually read. */ + + ppFramesOut[0] = pFramesOut; + ma_node_process_pcm_frames_internal(pNode, NULL, &frameCountIn, ppFramesOut, &frameCountOut); + totalFramesRead = frameCountOut; + } else { + /* Slow path. Need to read input data. */ + if ((pNodeBase->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) { + /* + Fast path. We're running a passthrough. We need to read directly into the output buffer, but + still fire the callback so that event handling and trigger nodes can do their thing. Since + it's a passthrough there's no need for any kind of caching logic. + */ + MA_ASSERT(outputBusCount == inputBusCount); + MA_ASSERT(outputBusCount == 1); + MA_ASSERT(outputBusIndex == 0); + + /* We just read directly from input bus to output buffer, and then afterwards fire the callback. */ + ppFramesOut[0] = pFramesOut; + ppFramesIn[0] = ppFramesOut[0]; + + result = ma_node_input_bus_read_pcm_frames(pNodeBase, &pNodeBase->pInputBuses[0], ppFramesIn[0], frameCount, &totalFramesRead, globalTime); + if (result == MA_SUCCESS) { + /* Even though it's a passthrough, we still need to fire the callback. */ + frameCountIn = totalFramesRead; + frameCountOut = totalFramesRead; + + if (totalFramesRead > 0) { + ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */ + } + + /* + A passthrough should never have modified the input and output frame counts. If you're + triggering these assers you need to fix your processing callback. + */ + MA_ASSERT(frameCountIn == totalFramesRead); + MA_ASSERT(frameCountOut == totalFramesRead); + } + } else { + /* Slow path. Need to do caching. */ + ma_uint32 framesToProcessIn; + ma_uint32 framesToProcessOut; + ma_bool32 consumeNullInput = MA_FALSE; + + /* + We use frameCount as a basis for the number of frames to read since that's what's being + requested, however we still need to clamp it to whatever can fit in the cache. + + This will also be used as the basis for determining how many input frames to read. This is + not ideal because it can result in too many input frames being read which introduces latency. + To solve this, nodes can implement an optional callback called onGetRequiredInputFrameCount + which is used as hint to miniaudio as to how many input frames it needs to read at a time. This + callback is completely optional, and if it's not set, miniaudio will assume `frameCount`. + + This function will be called multiple times for each period of time, once for each output node. + We cannot read from each input node each time this function is called. Instead we need to check + whether or not this is first output bus to be read from for this time period, and if so, read + from our input data. + + To determine whether or not we're ready to read data, we check a flag. There will be one flag + for each output. When the flag is set, it means data has been read previously and that we're + ready to advance time forward for our input nodes by reading fresh data. + */ + framesToProcessOut = frameCount; + if (framesToProcessOut > pNodeBase->cachedDataCapInFramesPerBus) { + framesToProcessOut = pNodeBase->cachedDataCapInFramesPerBus; + } + + framesToProcessIn = frameCount; + if (pNodeBase->vtable->onGetRequiredInputFrameCount) { + pNodeBase->vtable->onGetRequiredInputFrameCount(pNode, framesToProcessOut, &framesToProcessIn); /* <-- It does not matter if this fails. */ + } + if (framesToProcessIn > pNodeBase->cachedDataCapInFramesPerBus) { + framesToProcessIn = pNodeBase->cachedDataCapInFramesPerBus; + } + + + MA_ASSERT(framesToProcessIn <= 0xFFFF); + MA_ASSERT(framesToProcessOut <= 0xFFFF); + + if (ma_node_output_bus_has_read(&pNodeBase->pOutputBuses[outputBusIndex])) { + /* Getting here means we need to do another round of processing. */ + pNodeBase->cachedFrameCountOut = 0; + + for (;;) { + frameCountOut = 0; + + /* + We need to prepare our output frame pointers for processing. In the same iteration we need + to mark every output bus as unread so that future calls to this function for different buses + for the current time period don't pull in data when they should instead be reading from cache. + */ + for (iOutputBus = 0; iOutputBus < outputBusCount; iOutputBus += 1) { + ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[iOutputBus], MA_FALSE); /* <-- This is what tells the next calls to this function for other output buses for this time period to read from cache instead of pulling in more data. */ + ppFramesOut[iOutputBus] = ma_node_get_cached_output_ptr(pNode, iOutputBus); + } + + /* We only need to read from input buses if there isn't already some data in the cache. */ + if (pNodeBase->cachedFrameCountIn == 0) { + ma_uint32 maxFramesReadIn = 0; + + /* Here is where we pull in data from the input buses. This is what will trigger an advance in time. */ + for (iInputBus = 0; iInputBus < inputBusCount; iInputBus += 1) { + ma_uint32 framesRead; + + /* The first thing to do is get the offset within our bulk allocation to store this input data. */ + ppFramesIn[iInputBus] = ma_node_get_cached_input_ptr(pNode, iInputBus); + + /* Once we've determined our destination pointer we can read. Note that we must inspect the number of frames read and fill any leftovers with silence for safety. */ + result = ma_node_input_bus_read_pcm_frames(pNodeBase, &pNodeBase->pInputBuses[iInputBus], ppFramesIn[iInputBus], framesToProcessIn, &framesRead, globalTime); + if (result != MA_SUCCESS) { + /* It doesn't really matter if we fail because we'll just fill with silence. */ + framesRead = 0; /* Just for safety, but I don't think it's really needed. */ + } + + /* TODO: Minor optimization opportunity here. If no frames were read and the buffer is already filled with silence, no need to re-silence it. */ + /* Any leftover frames need to silenced for safety. */ + if (framesRead < framesToProcessIn) { + ma_silence_pcm_frames(ppFramesIn[iInputBus] + (framesRead * ma_node_get_input_channels(pNodeBase, iInputBus)), (framesToProcessIn - framesRead), ma_format_f32, ma_node_get_input_channels(pNodeBase, iInputBus)); + } + + maxFramesReadIn = ma_max(maxFramesReadIn, framesRead); + } + + /* This was a fresh load of input data so reset our consumption counter. */ + pNodeBase->consumedFrameCountIn = 0; + + /* + We don't want to keep processing if there's nothing to process, so set the number of cached + input frames to the maximum number we read from each attachment (the lesser will be padded + with silence). If we didn't read anything, this will be set to 0 and the entire buffer will + have been assigned to silence. This being equal to 0 is an important property for us because + it allows us to detect when NULL can be passed into the processing callback for the input + buffer for the purpose of continuous processing. + */ + pNodeBase->cachedFrameCountIn = (ma_uint16)maxFramesReadIn; + } else { + /* We don't need to read anything, but we do need to prepare our input frame pointers. */ + for (iInputBus = 0; iInputBus < inputBusCount; iInputBus += 1) { + ppFramesIn[iInputBus] = ma_node_get_cached_input_ptr(pNode, iInputBus) + (pNodeBase->consumedFrameCountIn * ma_node_get_input_channels(pNodeBase, iInputBus)); + } + } + + /* + At this point we have our input data so now we need to do some processing. Sneaky little + optimization here - we can set the pointer to the output buffer for this output bus so + that the final copy into the output buffer is done directly by onProcess(). + */ + if (pFramesOut != NULL) { + ppFramesOut[outputBusIndex] = ma_offset_pcm_frames_ptr_f32(pFramesOut, pNodeBase->cachedFrameCountOut, ma_node_get_output_channels(pNode, outputBusIndex)); + } + + + /* Give the processing function the entire capacity of the output buffer. */ + frameCountOut = (framesToProcessOut - pNodeBase->cachedFrameCountOut); + + /* + We need to treat nodes with continuous processing a little differently. For these ones, + we always want to fire the callback with the requested number of frames, regardless of + pNodeBase->cachedFrameCountIn, which could be 0. Also, we want to check if we can pass + in NULL for the input buffer to the callback. + */ + if ((pNodeBase->vtable->flags & MA_NODE_FLAG_CONTINUOUS_PROCESSING) != 0) { + /* We're using continuous processing. Make sure we specify the whole frame count at all times. */ + frameCountIn = framesToProcessIn; /* Give the processing function as much input data as we've got in the buffer, including any silenced padding from short reads. */ + + if ((pNodeBase->vtable->flags & MA_NODE_FLAG_ALLOW_NULL_INPUT) != 0 && pNodeBase->consumedFrameCountIn == 0 && pNodeBase->cachedFrameCountIn == 0) { + consumeNullInput = MA_TRUE; + } else { + consumeNullInput = MA_FALSE; + } + + /* + Since we're using continuous processing we're always passing in a full frame count + regardless of how much input data was read. If this is greater than what we read as + input, we'll end up with an underflow. We instead need to make sure our cached frame + count is set to the number of frames we'll be passing to the data callback. Not + doing this will result in an underflow when we "consume" the cached data later on. + + Note that this check needs to be done after the "consumeNullInput" check above because + we use the property of cachedFrameCountIn being 0 to determine whether or not we + should be passing in a null pointer to the processing callback for when the node is + configured with MA_NODE_FLAG_ALLOW_NULL_INPUT. + */ + if (pNodeBase->cachedFrameCountIn < (ma_uint16)frameCountIn) { + pNodeBase->cachedFrameCountIn = (ma_uint16)frameCountIn; + } + } else { + frameCountIn = pNodeBase->cachedFrameCountIn; /* Give the processing function as much valid input data as we've got. */ + consumeNullInput = MA_FALSE; + } + + /* + Process data slightly differently depending on whether or not we're consuming NULL + input (checked just above). + */ + if (consumeNullInput) { + ma_node_process_pcm_frames_internal(pNode, NULL, &frameCountIn, ppFramesOut, &frameCountOut); + } else { + /* + We want to skip processing if there's no input data, but we can only do that safely if + we know that there is no chance of any output frames being produced. If continuous + processing is being used, this won't be a problem because the input frame count will + always be non-0. However, if continuous processing is *not* enabled and input and output + data is processed at different rates, we still need to process that last input frame + because there could be a few excess output frames needing to be produced from cached + data. The `MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES` flag is used as the indicator for + determining whether or not we need to process the node even when there are no input + frames available right now. + */ + if (frameCountIn > 0 || (pNodeBase->vtable->flags & MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES) != 0) { + ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */ + } else { + frameCountOut = 0; /* No data was processed. */ + } + } + + /* + Thanks to our sneaky optimization above we don't need to do any data copying directly into + the output buffer - the onProcess() callback just did that for us. We do, however, need to + apply the number of input and output frames that were processed. Note that due to continuous + processing above, we need to do explicit checks here. If we just consumed a NULL input + buffer it means that no actual input data was processed from the internal buffers and we + don't want to be modifying any counters. + */ + if (consumeNullInput == MA_FALSE) { + pNodeBase->consumedFrameCountIn += (ma_uint16)frameCountIn; + pNodeBase->cachedFrameCountIn -= (ma_uint16)frameCountIn; + } + + /* The cached output frame count is always equal to what we just read. */ + pNodeBase->cachedFrameCountOut += (ma_uint16)frameCountOut; + + /* If we couldn't process any data, we're done. The loop needs to be terminated here or else we'll get stuck in a loop. */ + if (pNodeBase->cachedFrameCountOut == framesToProcessOut || (frameCountOut == 0 && frameCountIn == 0)) { + break; + } + } + } else { + /* + We're not needing to read anything from the input buffer so just read directly from our + already-processed data. + */ + if (pFramesOut != NULL) { + ma_copy_pcm_frames(pFramesOut, ma_node_get_cached_output_ptr(pNodeBase, outputBusIndex), pNodeBase->cachedFrameCountOut, ma_format_f32, ma_node_get_output_channels(pNodeBase, outputBusIndex)); + } + } + + /* The number of frames read is always equal to the number of cached output frames. */ + totalFramesRead = pNodeBase->cachedFrameCountOut; + + /* Now that we've read the data, make sure our read flag is set. */ + ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[outputBusIndex], MA_TRUE); + } + } + + /* Apply volume, if necessary. */ + ma_apply_volume_factor_f32(pFramesOut, totalFramesRead * ma_node_get_output_channels(pNodeBase, outputBusIndex), ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex])); + + /* Advance our local time forward. */ + c89atomic_fetch_add_64(&pNodeBase->localTime, (ma_uint64)totalFramesRead); + + *pFramesRead = totalFramesRead + timeOffsetBeg; /* Must include the silenced section at the start of the buffer. */ + return result; +} + + + + +/* Data source node. */ +MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource) +{ + ma_data_source_node_config config; + + MA_ZERO_OBJECT(&config); + config.nodeConfig = ma_node_config_init(); + config.pDataSource = pDataSource; + + return config; +} + + +static void ma_data_source_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_data_source_node* pDataSourceNode = (ma_data_source_node*)pNode; + ma_format format; + ma_uint32 channels; + ma_uint32 frameCount; + ma_uint64 framesRead = 0; + + MA_ASSERT(pDataSourceNode != NULL); + MA_ASSERT(pDataSourceNode->pDataSource != NULL); + MA_ASSERT(ma_node_get_input_bus_count(pDataSourceNode) == 0); + MA_ASSERT(ma_node_get_output_bus_count(pDataSourceNode) == 1); + + /* We don't want to read from ppFramesIn at all. Instead we read from the data source. */ + (void)ppFramesIn; + (void)pFrameCountIn; + + frameCount = *pFrameCountOut; + + /* miniaudio should never be calling this with a frame count of zero. */ + MA_ASSERT(frameCount > 0); + + if (ma_data_source_get_data_format(pDataSourceNode->pDataSource, &format, &channels, NULL, NULL, 0) == MA_SUCCESS) { /* <-- Don't care about sample rate here. */ + /* The node graph system requires samples be in floating point format. This is checked in ma_data_source_node_init(). */ + MA_ASSERT(format == ma_format_f32); + (void)format; /* Just to silence some static analysis tools. */ + + ma_data_source_read_pcm_frames(pDataSourceNode->pDataSource, ppFramesOut[0], frameCount, &framesRead); + } + + *pFrameCountOut = (ma_uint32)framesRead; +} + +static ma_node_vtable g_ma_data_source_node_vtable = +{ + ma_data_source_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 0, /* 0 input buses. */ + 1, /* 1 output bus. */ + 0 +}; + +MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_data_source_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source_node* pDataSourceNode) +{ + ma_result result; + ma_format format; /* For validating the format, which must be ma_format_f32. */ + ma_uint32 channels; /* For specifying the channel count of the output bus. */ + ma_node_config baseConfig; + + if (pDataSourceNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDataSourceNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_data_source_get_data_format(pConfig->pDataSource, &format, &channels, NULL, NULL, 0); /* Don't care about sample rate. This will check pDataSource for NULL. */ + if (result != MA_SUCCESS) { + return result; + } + + MA_ASSERT(format == ma_format_f32); /* <-- If you've triggered this it means your data source is not outputting floating-point samples. You must configure your data source to use ma_format_f32. */ + if (format != ma_format_f32) { + return MA_INVALID_ARGS; /* Invalid format. */ + } + + /* The channel count is defined by the data source. If the caller has manually changed the channels we just ignore it. */ + baseConfig = pConfig->nodeConfig; + baseConfig.vtable = &g_ma_data_source_node_vtable; /* Explicitly set the vtable here to prevent callers from setting it incorrectly. */ + + /* + The channel count is defined by the data source. It is invalid for the caller to manually set + the channel counts in the config. `ma_data_source_node_config_init()` will have defaulted the + channel count pointer to NULL which is how it must remain. If you trigger any of these asserts + it means you're explicitly setting the channel count. Instead, configure the output channel + count of your data source to be the necessary channel count. + */ + if (baseConfig.pOutputChannels != NULL) { + return MA_INVALID_ARGS; + } + + baseConfig.pOutputChannels = &channels; + + result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pDataSourceNode->base); + if (result != MA_SUCCESS) { + return result; + } + + pDataSourceNode->pDataSource = pConfig->pDataSource; + + return MA_SUCCESS; +} + +MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_node_uninit(&pDataSourceNode->base, pAllocationCallbacks); +} + +MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping) +{ + if (pDataSourceNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_data_source_set_looping(pDataSourceNode->pDataSource, isLooping); +} + +MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode) +{ + if (pDataSourceNode == NULL) { + return MA_FALSE; + } + + return ma_data_source_is_looping(pDataSourceNode->pDataSource); +} + + + +/* Splitter Node. */ +MA_API ma_splitter_node_config ma_splitter_node_config_init(ma_uint32 channels) +{ + ma_splitter_node_config config; + + MA_ZERO_OBJECT(&config); + config.nodeConfig = ma_node_config_init(); + config.channels = channels; + + return config; +} + + +static void ma_splitter_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_node_base* pNodeBase = (ma_node_base*)pNode; + ma_uint32 iOutputBus; + ma_uint32 channels; + + MA_ASSERT(pNodeBase != NULL); + MA_ASSERT(ma_node_get_input_bus_count(pNodeBase) == 1); + MA_ASSERT(ma_node_get_output_bus_count(pNodeBase) >= 2); + + /* We don't need to consider the input frame count - it'll be the same as the output frame count and we process everything. */ + (void)pFrameCountIn; + + /* NOTE: This assumes the same number of channels for all inputs and outputs. This was checked in ma_splitter_node_init(). */ + channels = ma_node_get_input_channels(pNodeBase, 0); + + /* Splitting is just copying the first input bus and copying it over to each output bus. */ + for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNodeBase); iOutputBus += 1) { + ma_copy_pcm_frames(ppFramesOut[iOutputBus], ppFramesIn[0], *pFrameCountOut, ma_format_f32, channels); + } +} + +static ma_node_vtable g_ma_splitter_node_vtable = +{ + ma_splitter_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* 1 input bus. */ + 2, /* 2 output buses. */ + 0 +}; + +MA_API ma_result ma_splitter_node_init(ma_node_graph* pNodeGraph, const ma_splitter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_splitter_node* pSplitterNode) +{ + ma_result result; + ma_node_config baseConfig; + ma_uint32 pInputChannels[1]; + ma_uint32 pOutputChannels[2]; + + if (pSplitterNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pSplitterNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + /* Splitters require the same number of channels between inputs and outputs. */ + pInputChannels[0] = pConfig->channels; + pOutputChannels[0] = pConfig->channels; + pOutputChannels[1] = pConfig->channels; + + baseConfig = pConfig->nodeConfig; + baseConfig.vtable = &g_ma_splitter_node_vtable; + baseConfig.pInputChannels = pInputChannels; + baseConfig.pOutputChannels = pOutputChannels; + + result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pSplitterNode->base); + if (result != MA_SUCCESS) { + return result; /* Failed to initialize the base node. */ + } + + return MA_SUCCESS; +} + +MA_API void ma_splitter_node_uninit(ma_splitter_node* pSplitterNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_node_uninit(pSplitterNode, pAllocationCallbacks); +} + + +/* +Biquad Node +*/ +MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2) +{ + ma_biquad_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.biquad = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2); + + return config; +} + +static void ma_biquad_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_biquad_process_pcm_frames(&pLPFNode->biquad, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_biquad_node_vtable = +{ + ma_biquad_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->biquad.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_biquad_init(&pConfig->biquad, pAllocationCallbacks, &pNode->biquad); + if (result != MA_SUCCESS) { + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_biquad_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->biquad.channels; + baseNodeConfig.pOutputChannels = &pConfig->biquad.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_biquad_node_reinit(const ma_biquad_config* pConfig, ma_biquad_node* pNode) +{ + ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode; + + MA_ASSERT(pNode != NULL); + + return ma_biquad_reinit(pConfig, &pLPFNode->biquad); +} + +MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_biquad_uninit(&pLPFNode->biquad, pAllocationCallbacks); +} + + + +/* +Low Pass Filter Node +*/ +MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_lpf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.lpf = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); + + return config; +} + +static void ma_lpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_lpf_process_pcm_frames(&pLPFNode->lpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_lpf_node_vtable = +{ + ma_lpf_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->lpf.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_lpf_init(&pConfig->lpf, pAllocationCallbacks, &pNode->lpf); + if (result != MA_SUCCESS) { + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_lpf_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->lpf.channels; + baseNodeConfig.pOutputChannels = &pConfig->lpf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_lpf_node_reinit(const ma_lpf_config* pConfig, ma_lpf_node* pNode) +{ + ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_lpf_reinit(pConfig, &pLPFNode->lpf); +} + +MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_lpf_uninit(&pLPFNode->lpf, pAllocationCallbacks); +} + + + +/* +High Pass Filter Node +*/ +MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_hpf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.hpf = ma_hpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); + + return config; +} + +static void ma_hpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_hpf_process_pcm_frames(&pHPFNode->hpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_hpf_node_vtable = +{ + ma_hpf_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->hpf.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_hpf_init(&pConfig->hpf, pAllocationCallbacks, &pNode->hpf); + if (result != MA_SUCCESS) { + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_hpf_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->hpf.channels; + baseNodeConfig.pOutputChannels = &pConfig->hpf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_hpf_node_reinit(const ma_hpf_config* pConfig, ma_hpf_node* pNode) +{ + ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_hpf_reinit(pConfig, &pHPFNode->hpf); +} + +MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_hpf_uninit(&pHPFNode->hpf, pAllocationCallbacks); +} + + + + +/* +Band Pass Filter Node +*/ +MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_bpf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.bpf = ma_bpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); + + return config; +} + +static void ma_bpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_bpf_process_pcm_frames(&pBPFNode->bpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_bpf_node_vtable = +{ + ma_bpf_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->bpf.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_bpf_init(&pConfig->bpf, pAllocationCallbacks, &pNode->bpf); + if (result != MA_SUCCESS) { + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_bpf_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->bpf.channels; + baseNodeConfig.pOutputChannels = &pConfig->bpf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_bpf_node_reinit(const ma_bpf_config* pConfig, ma_bpf_node* pNode) +{ + ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_bpf_reinit(pConfig, &pBPFNode->bpf); +} + +MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_bpf_uninit(&pBPFNode->bpf, pAllocationCallbacks); +} + + + +/* +Notching Filter Node +*/ +MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency) +{ + ma_notch_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.notch = ma_notch2_config_init(ma_format_f32, channels, sampleRate, q, frequency); + + return config; +} + +static void ma_notch_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_notch_node* pBPFNode = (ma_notch_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_notch2_process_pcm_frames(&pBPFNode->notch, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_notch_node_vtable = +{ + ma_notch_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->notch.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_notch2_init(&pConfig->notch, pAllocationCallbacks, &pNode->notch); + if (result != MA_SUCCESS) { + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_notch_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->notch.channels; + baseNodeConfig.pOutputChannels = &pConfig->notch.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_notch_node_reinit(const ma_notch_config* pConfig, ma_notch_node* pNode) +{ + ma_notch_node* pNotchNode = (ma_notch_node*)pNode; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_notch2_reinit(pConfig, &pNotchNode->notch); +} + +MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_notch_node* pNotchNode = (ma_notch_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_notch2_uninit(&pNotchNode->notch, pAllocationCallbacks); +} + + + +/* +Peaking Filter Node +*/ +MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) +{ + ma_peak_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.peak = ma_peak2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); + + return config; +} + +static void ma_peak_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_peak_node* pBPFNode = (ma_peak_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_peak2_process_pcm_frames(&pBPFNode->peak, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_peak_node_vtable = +{ + ma_peak_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->peak.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_peak2_init(&pConfig->peak, pAllocationCallbacks, &pNode->peak); + if (result != MA_SUCCESS) { + ma_node_uninit(pNode, pAllocationCallbacks); + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_peak_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->peak.channels; + baseNodeConfig.pOutputChannels = &pConfig->peak.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_peak_node_reinit(const ma_peak_config* pConfig, ma_peak_node* pNode) +{ + ma_peak_node* pPeakNode = (ma_peak_node*)pNode; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_peak2_reinit(pConfig, &pPeakNode->peak); +} + +MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_peak_node* pPeakNode = (ma_peak_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_peak2_uninit(&pPeakNode->peak, pAllocationCallbacks); +} + + + +/* +Low Shelf Filter Node +*/ +MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) +{ + ma_loshelf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.loshelf = ma_loshelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); + + return config; +} + +static void ma_loshelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_loshelf_node* pBPFNode = (ma_loshelf_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_loshelf2_process_pcm_frames(&pBPFNode->loshelf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_loshelf_node_vtable = +{ + ma_loshelf_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->loshelf.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_loshelf2_init(&pConfig->loshelf, pAllocationCallbacks, &pNode->loshelf); + if (result != MA_SUCCESS) { + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_loshelf_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->loshelf.channels; + baseNodeConfig.pOutputChannels = &pConfig->loshelf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_loshelf_node_reinit(const ma_loshelf_config* pConfig, ma_loshelf_node* pNode) +{ + ma_loshelf_node* pLoshelfNode = (ma_loshelf_node*)pNode; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_loshelf2_reinit(pConfig, &pLoshelfNode->loshelf); +} + +MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_loshelf_node* pLoshelfNode = (ma_loshelf_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_loshelf2_uninit(&pLoshelfNode->loshelf, pAllocationCallbacks); +} + + + +/* +High Shelf Filter Node +*/ +MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) +{ + ma_hishelf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.hishelf = ma_hishelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); + + return config; +} + +static void ma_hishelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_hishelf_node* pBPFNode = (ma_hishelf_node*)pNode; + + MA_ASSERT(pNode != NULL); + (void)pFrameCountIn; + + ma_hishelf2_process_pcm_frames(&pBPFNode->hishelf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_hishelf_node_vtable = +{ + ma_hishelf_node_process_pcm_frames, + NULL, /* onGetRequiredInputFrameCount */ + 1, /* One input. */ + 1, /* One output. */ + 0 /* Default flags. */ +}; + +MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode) +{ + ma_result result; + ma_node_config baseNodeConfig; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNode); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->hishelf.format != ma_format_f32) { + return MA_INVALID_ARGS; /* The format must be f32. */ + } + + result = ma_hishelf2_init(&pConfig->hishelf, pAllocationCallbacks, &pNode->hishelf); + if (result != MA_SUCCESS) { + return result; + } + + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_hishelf_node_vtable; + baseNodeConfig.pInputChannels = &pConfig->hishelf.channels; + baseNodeConfig.pOutputChannels = &pConfig->hishelf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + if (result != MA_SUCCESS) { + return result; + } + + return result; +} + +MA_API ma_result ma_hishelf_node_reinit(const ma_hishelf_config* pConfig, ma_hishelf_node* pNode) +{ + ma_hishelf_node* pHishelfNode = (ma_hishelf_node*)pNode; + + if (pNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_hishelf2_reinit(pConfig, &pHishelfNode->hishelf); +} + +MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_hishelf_node* pHishelfNode = (ma_hishelf_node*)pNode; + + if (pNode == NULL) { + return; + } + + ma_node_uninit(pNode, pAllocationCallbacks); + ma_hishelf2_uninit(&pHishelfNode->hishelf, pAllocationCallbacks); +} + + + + +MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay) +{ + ma_delay_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.delay = ma_delay_config_init(channels, sampleRate, delayInFrames, decay); + + return config; +} + + +static void ma_delay_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_delay_node* pDelayNode = (ma_delay_node*)pNode; + + (void)pFrameCountIn; + + ma_delay_process_pcm_frames(&pDelayNode->delay, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_delay_node_vtable = +{ + ma_delay_node_process_pcm_frames, + NULL, + 1, /* 1 input channels. */ + 1, /* 1 output channel. */ + MA_NODE_FLAG_CONTINUOUS_PROCESSING /* Delay requires continuous processing to ensure the tail get's processed. */ +}; + +MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode) +{ + ma_result result; + ma_node_config baseConfig; + + if (pDelayNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDelayNode); + + result = ma_delay_init(&pConfig->delay, pAllocationCallbacks, &pDelayNode->delay); + if (result != MA_SUCCESS) { + return result; + } + + baseConfig = pConfig->nodeConfig; + baseConfig.vtable = &g_ma_delay_node_vtable; + baseConfig.pInputChannels = &pConfig->delay.channels; + baseConfig.pOutputChannels = &pConfig->delay.channels; + + result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pDelayNode->baseNode); + if (result != MA_SUCCESS) { + ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks); + return result; + } + + return result; +} + +MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pDelayNode == NULL) { + return; + } + + /* The base node is always uninitialized first. */ + ma_node_uninit(pDelayNode, pAllocationCallbacks); + ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks); +} + +MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value) +{ + if (pDelayNode == NULL) { + return; + } + + ma_delay_set_wet(&pDelayNode->delay, value); +} + +MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode) +{ + if (pDelayNode == NULL) { + return 0; + } + + return ma_delay_get_wet(&pDelayNode->delay); +} + +MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value) +{ + if (pDelayNode == NULL) { + return; + } + + ma_delay_set_dry(&pDelayNode->delay, value); +} + +MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode) +{ + if (pDelayNode == NULL) { + return 0; + } + + return ma_delay_get_dry(&pDelayNode->delay); +} + +MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value) +{ + if (pDelayNode == NULL) { + return; + } + + ma_delay_set_decay(&pDelayNode->delay, value); +} + +MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode) +{ + if (pDelayNode == NULL) { + return 0; + } + + return ma_delay_get_decay(&pDelayNode->delay); +} +#endif /* MA_NO_NODE_GRAPH */ + + +#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) +/************************************************************************************************************************************************************** + +Engine + +**************************************************************************************************************************************************************/ +#define MA_SEEK_TARGET_NONE (~(ma_uint64)0) + +MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags) +{ + ma_engine_node_config config; + + MA_ZERO_OBJECT(&config); + config.pEngine = pEngine; + config.type = type; + config.isPitchDisabled = (flags & MA_SOUND_FLAG_NO_PITCH) != 0; + config.isSpatializationDisabled = (flags & MA_SOUND_FLAG_NO_SPATIALIZATION) != 0; + + return config; +} + + +static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode) +{ + ma_bool32 isUpdateRequired = MA_FALSE; + float newPitch; + + MA_ASSERT(pEngineNode != NULL); + + newPitch = c89atomic_load_explicit_f32(&pEngineNode->pitch, c89atomic_memory_order_acquire); + + if (pEngineNode->oldPitch != newPitch) { + pEngineNode->oldPitch = newPitch; + isUpdateRequired = MA_TRUE; + } + + if (pEngineNode->oldDopplerPitch != pEngineNode->spatializer.dopplerPitch) { + pEngineNode->oldDopplerPitch = pEngineNode->spatializer.dopplerPitch; + isUpdateRequired = MA_TRUE; + } + + if (isUpdateRequired) { + float basePitch = (float)pEngineNode->sampleRate / ma_engine_get_sample_rate(pEngineNode->pEngine); + ma_linear_resampler_set_rate_ratio(&pEngineNode->resampler, basePitch * pEngineNode->oldPitch * pEngineNode->oldDopplerPitch); + } +} + +static ma_bool32 ma_engine_node_is_pitching_enabled(const ma_engine_node* pEngineNode) +{ + MA_ASSERT(pEngineNode != NULL); + + /* Don't try to be clever by skiping resampling in the pitch=1 case or else you'll glitch when moving away from 1. */ + return !c89atomic_load_explicit_32(&pEngineNode->isPitchDisabled, c89atomic_memory_order_acquire); +} + +static ma_bool32 ma_engine_node_is_spatialization_enabled(const ma_engine_node* pEngineNode) +{ + MA_ASSERT(pEngineNode != NULL); + + return !c89atomic_load_explicit_32(&pEngineNode->isSpatializationDisabled, c89atomic_memory_order_acquire); +} + +static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_node* pEngineNode, ma_uint64 outputFrameCount) +{ + ma_uint64 inputFrameCount = 0; + + if (ma_engine_node_is_pitching_enabled(pEngineNode)) { + ma_result result = ma_linear_resampler_get_required_input_frame_count(&pEngineNode->resampler, outputFrameCount, &inputFrameCount); + if (result != MA_SUCCESS) { + inputFrameCount = 0; + } + } else { + inputFrameCount = outputFrameCount; /* No resampling, so 1:1. */ + } + + return inputFrameCount; +} + +static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_uint32 frameCountIn; + ma_uint32 frameCountOut; + ma_uint32 totalFramesProcessedIn; + ma_uint32 totalFramesProcessedOut; + ma_uint32 channelsIn; + ma_uint32 channelsOut; + ma_bool32 isPitchingEnabled; + ma_bool32 isFadingEnabled; + ma_bool32 isSpatializationEnabled; + ma_bool32 isPanningEnabled; + + frameCountIn = *pFrameCountIn; + frameCountOut = *pFrameCountOut; + + channelsIn = ma_spatializer_get_input_channels(&pEngineNode->spatializer); + channelsOut = ma_spatializer_get_output_channels(&pEngineNode->spatializer); + + totalFramesProcessedIn = 0; + totalFramesProcessedOut = 0; + + isPitchingEnabled = ma_engine_node_is_pitching_enabled(pEngineNode); + isFadingEnabled = pEngineNode->fader.volumeBeg != 1 || pEngineNode->fader.volumeEnd != 1; + isSpatializationEnabled = ma_engine_node_is_spatialization_enabled(pEngineNode); + isPanningEnabled = pEngineNode->panner.pan != 0 && channelsOut != 1; + + /* Keep going while we've still got data available for processing. */ + while (totalFramesProcessedOut < frameCountOut) { + /* + We need to process in a specific order. We always do resampling first because it's likely + we're going to be increasing the channel count after spatialization. Also, I want to do + fading based on the output sample rate. + + We'll first read into a buffer from the resampler. Then we'll do all processing that + operates on the on the input channel count. We'll then get the spatializer to output to + the output buffer and then do all effects from that point directly in the output buffer + in-place. + + Note that we're always running the resampler. If we try to be clever and skip resampling + when the pitch is 1, we'll get a glitch when we move away from 1, back to 1, and then + away from 1 again. We'll want to implement any pitch=1 optimizations in the resampler + itself. + + There's a small optimization here that we'll utilize since it might be a fairly common + case. When the input and output channel counts are the same, we'll read straight into the + output buffer from the resampler and do everything in-place. + */ + const float* pRunningFramesIn; + float* pRunningFramesOut; + float* pWorkingBuffer; /* This is the buffer that we'll be processing frames in. This is in input channels. */ + float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)]; + ma_uint32 tempCapInFrames = ma_countof(temp) / channelsIn; + ma_uint32 framesAvailableIn; + ma_uint32 framesAvailableOut; + ma_uint32 framesJustProcessedIn; + ma_uint32 framesJustProcessedOut; + ma_bool32 isWorkingBufferValid = MA_FALSE; + + framesAvailableIn = frameCountIn - totalFramesProcessedIn; + framesAvailableOut = frameCountOut - totalFramesProcessedOut; + + pRunningFramesIn = ma_offset_pcm_frames_const_ptr_f32(ppFramesIn[0], totalFramesProcessedIn, channelsIn); + pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesProcessedOut, channelsOut); + + if (channelsIn == channelsOut) { + /* Fast path. Channel counts are the same. No need for an intermediary input buffer. */ + pWorkingBuffer = pRunningFramesOut; + } else { + /* Slow path. Channel counts are different. Need to use an intermediary input buffer. */ + pWorkingBuffer = temp; + if (framesAvailableOut > tempCapInFrames) { + framesAvailableOut = tempCapInFrames; + } + } + + /* First is resampler. */ + if (isPitchingEnabled) { + ma_uint64 resampleFrameCountIn = framesAvailableIn; + ma_uint64 resampleFrameCountOut = framesAvailableOut; + + ma_linear_resampler_process_pcm_frames(&pEngineNode->resampler, pRunningFramesIn, &resampleFrameCountIn, pWorkingBuffer, &resampleFrameCountOut); + isWorkingBufferValid = MA_TRUE; + + framesJustProcessedIn = (ma_uint32)resampleFrameCountIn; + framesJustProcessedOut = (ma_uint32)resampleFrameCountOut; + } else { + framesJustProcessedIn = ma_min(framesAvailableIn, framesAvailableOut); + framesJustProcessedOut = framesJustProcessedIn; /* When no resampling is being performed, the number of output frames is the same as input frames. */ + } + + /* Fading. */ + if (isFadingEnabled) { + if (isWorkingBufferValid) { + ma_fader_process_pcm_frames(&pEngineNode->fader, pWorkingBuffer, pWorkingBuffer, framesJustProcessedOut); /* In-place processing. */ + } else { + ma_fader_process_pcm_frames(&pEngineNode->fader, pWorkingBuffer, pRunningFramesIn, framesJustProcessedOut); + isWorkingBufferValid = MA_TRUE; + } + } + + /* + If at this point we still haven't actually done anything with the working buffer we need + to just read straight from the input buffer. + */ + if (isWorkingBufferValid == MA_FALSE) { + pWorkingBuffer = (float*)pRunningFramesIn; /* Naughty const cast, but it's safe at this point because we won't ever be writing to it from this point out. */ + } + + /* Spatialization. */ + if (isSpatializationEnabled) { + ma_uint32 iListener; + + /* + When determining the listener to use, we first check to see if the sound is pinned to a + specific listener. If so, we use that. Otherwise we just use the closest listener. + */ + if (pEngineNode->pinnedListenerIndex != MA_LISTENER_INDEX_CLOSEST && pEngineNode->pinnedListenerIndex < ma_engine_get_listener_count(pEngineNode->pEngine)) { + iListener = pEngineNode->pinnedListenerIndex; + } else { + iListener = ma_engine_find_closest_listener(pEngineNode->pEngine, pEngineNode->spatializer.position.x, pEngineNode->spatializer.position.y, pEngineNode->spatializer.position.z); + } + + ma_spatializer_process_pcm_frames(&pEngineNode->spatializer, &pEngineNode->pEngine->listeners[iListener], pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut); + } else { + /* No spatialization, but we still need to do channel conversion. */ + if (channelsIn == channelsOut) { + /* No channel conversion required. Just copy straight to the output buffer. */ + ma_copy_pcm_frames(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut, ma_format_f32, channelsOut); + } else { + /* Channel conversion required. TODO: Add support for channel maps here. */ + ma_channel_map_apply_f32(pRunningFramesOut, NULL, channelsOut, pWorkingBuffer, NULL, channelsIn, framesJustProcessedOut, ma_channel_mix_mode_simple, pEngineNode->pEngine->monoExpansionMode); + } + } + + /* At this point we can guarantee that the output buffer contains valid data. We can process everything in place now. */ + + /* Panning. */ + if (isPanningEnabled) { + ma_panner_process_pcm_frames(&pEngineNode->panner, pRunningFramesOut, pRunningFramesOut, framesJustProcessedOut); /* In-place processing. */ + } + + /* We're done for this chunk. */ + totalFramesProcessedIn += framesJustProcessedIn; + totalFramesProcessedOut += framesJustProcessedOut; + + /* If we didn't process any output frames this iteration it means we've either run out of input data, or run out of room in the output buffer. */ + if (framesJustProcessedOut == 0) { + break; + } + } + + /* At this point we're done processing. */ + *pFrameCountIn = totalFramesProcessedIn; + *pFrameCountOut = totalFramesProcessedOut; +} + +static void ma_engine_node_process_pcm_frames__sound(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + /* For sounds, we need to first read from the data source. Then we need to apply the engine effects (pan, pitch, fades, etc.). */ + ma_result result = MA_SUCCESS; + ma_sound* pSound = (ma_sound*)pNode; + ma_uint32 frameCount = *pFrameCountOut; + ma_uint32 totalFramesRead = 0; + ma_format dataSourceFormat; + ma_uint32 dataSourceChannels; + ma_uint8 temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 tempCapInFrames; + ma_uint64 seekTarget; + + /* This is a data source node which means no input buses. */ + (void)ppFramesIn; + (void)pFrameCountIn; + + /* If we're marked at the end we need to stop the sound and do nothing. */ + if (ma_sound_at_end(pSound)) { + ma_sound_stop(pSound); + *pFrameCountOut = 0; + return; + } + + /* If we're seeking, do so now before reading. */ + seekTarget = c89atomic_load_64(&pSound->seekTarget); + if (seekTarget != MA_SEEK_TARGET_NONE) { + ma_data_source_seek_to_pcm_frame(pSound->pDataSource, seekTarget); + + /* Any time-dependant effects need to have their times updated. */ + ma_node_set_time(pSound, seekTarget); + + c89atomic_exchange_64(&pSound->seekTarget, MA_SEEK_TARGET_NONE); + } + + /* + We want to update the pitch once. For sounds, this can be either at the start or at the end. If + we don't force this to only ever be updating once, we could end up in a situation where + retrieving the required input frame count ends up being different to what we actually retrieve. + What could happen is that the required input frame count is calculated, the pitch is update, + and then this processing function is called resulting in a different number of input frames + being processed. Do not call this in ma_engine_node_process_pcm_frames__general() or else + you'll hit the aforementioned bug. + */ + ma_engine_node_update_pitch_if_required(&pSound->engineNode); + + /* + For the convenience of the caller, we're doing to allow data sources to use non-floating-point formats and channel counts that differ + from the main engine. + */ + result = ma_data_source_get_data_format(pSound->pDataSource, &dataSourceFormat, &dataSourceChannels, NULL, NULL, 0); + if (result == MA_SUCCESS) { + tempCapInFrames = sizeof(temp) / ma_get_bytes_per_frame(dataSourceFormat, dataSourceChannels); + + /* Keep reading until we've read as much as was requested or we reach the end of the data source. */ + while (totalFramesRead < frameCount) { + ma_uint32 framesRemaining = frameCount - totalFramesRead; + ma_uint32 framesToRead; + ma_uint64 framesJustRead; + ma_uint32 frameCountIn; + ma_uint32 frameCountOut; + const float* pRunningFramesIn; + float* pRunningFramesOut; + + /* + The first thing we need to do is read into the temporary buffer. We can calculate exactly + how many input frames we'll need after resampling. + */ + framesToRead = (ma_uint32)ma_engine_node_get_required_input_frame_count(&pSound->engineNode, framesRemaining); + if (framesToRead > tempCapInFrames) { + framesToRead = tempCapInFrames; + } + + result = ma_data_source_read_pcm_frames(pSound->pDataSource, temp, framesToRead, &framesJustRead); + + /* If we reached the end of the sound we'll want to mark it as at the end and stop it. This should never be returned for looping sounds. */ + if (result == MA_AT_END) { + c89atomic_exchange_32(&pSound->atEnd, MA_TRUE); /* This will be set to false in ma_sound_start(). */ + } + + pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesRead, ma_engine_get_channels(ma_sound_get_engine(pSound))); + + frameCountIn = (ma_uint32)framesJustRead; + frameCountOut = framesRemaining; + + /* Convert if necessary. */ + if (dataSourceFormat == ma_format_f32) { + /* Fast path. No data conversion necessary. */ + pRunningFramesIn = (float*)temp; + ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut); + } else { + /* Slow path. Need to do sample format conversion to f32. If we give the f32 buffer the same count as the first temp buffer, we're guaranteed it'll be large enough. */ + float tempf32[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* Do not do `MA_DATA_CONVERTER_STACK_BUFFER_SIZE/sizeof(float)` here like we've done in other places. */ + ma_convert_pcm_frames_format(tempf32, ma_format_f32, temp, dataSourceFormat, framesJustRead, dataSourceChannels, ma_dither_mode_none); + + /* Now that we have our samples in f32 format we can process like normal. */ + pRunningFramesIn = tempf32; + ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut); + } + + /* We should have processed all of our input frames since we calculated the required number of input frames at the top. */ + MA_ASSERT(frameCountIn == framesJustRead); + totalFramesRead += (ma_uint32)frameCountOut; /* Safe cast. */ + + if (result != MA_SUCCESS || ma_sound_at_end(pSound)) { + break; /* Might have reached the end. */ + } + } + } + + *pFrameCountOut = totalFramesRead; +} + +static void ma_engine_node_process_pcm_frames__group(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + /* + Make sure the pitch is updated before trying to read anything. It's important that this is done + only once and not in ma_engine_node_process_pcm_frames__general(). The reason for this is that + ma_engine_node_process_pcm_frames__general() will call ma_engine_node_get_required_input_frame_count(), + and if another thread modifies the pitch just after that call it can result in a glitch due to + the input rate changing. + */ + ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode); + + /* For groups, the input data has already been read and we just need to apply the effect. */ + ma_engine_node_process_pcm_frames__general((ma_engine_node*)pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut); +} + +static ma_result ma_engine_node_get_required_input_frame_count__group(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount) +{ + ma_uint64 inputFrameCount; + + MA_ASSERT(pInputFrameCount != NULL); + + /* Our pitch will affect this calculation. We need to update it. */ + ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode); + + inputFrameCount = ma_engine_node_get_required_input_frame_count((ma_engine_node*)pNode, outputFrameCount); + if (inputFrameCount > 0xFFFFFFFF) { + inputFrameCount = 0xFFFFFFFF; /* Will never happen because miniaudio will only ever process in relatively small chunks. */ + } + + *pInputFrameCount = (ma_uint32)inputFrameCount; + + return MA_SUCCESS; +} + + +static ma_node_vtable g_ma_engine_node_vtable__sound = +{ + ma_engine_node_process_pcm_frames__sound, + NULL, /* onGetRequiredInputFrameCount */ + 0, /* Sounds are data source nodes which means they have zero inputs (their input is drawn from the data source itself). */ + 1, /* Sounds have one output bus. */ + 0 /* Default flags. */ +}; + +static ma_node_vtable g_ma_engine_node_vtable__group = +{ + ma_engine_node_process_pcm_frames__group, + ma_engine_node_get_required_input_frame_count__group, + 1, /* Groups have one input bus. */ + 1, /* Groups have one output bus. */ + MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES /* The engine node does resampling so should let miniaudio know about it. */ +}; + + + +static ma_node_config ma_engine_node_base_node_config_init(const ma_engine_node_config* pConfig) +{ + ma_node_config baseNodeConfig; + + if (pConfig->type == ma_engine_node_type_sound) { + /* Sound. */ + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_engine_node_vtable__sound; + baseNodeConfig.initialState = ma_node_state_stopped; /* Sounds are stopped by default. */ + } else { + /* Group. */ + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_engine_node_vtable__group; + baseNodeConfig.initialState = ma_node_state_started; /* Groups are started by default. */ + } + + return baseNodeConfig; +} + +static ma_spatializer_config ma_engine_node_spatializer_config_init(const ma_node_config* pBaseNodeConfig) +{ + return ma_spatializer_config_init(pBaseNodeConfig->pInputChannels[0], pBaseNodeConfig->pOutputChannels[0]); +} + +typedef struct +{ + size_t sizeInBytes; + size_t baseNodeOffset; + size_t resamplerOffset; + size_t spatializerOffset; +} ma_engine_node_heap_layout; + +static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pConfig, ma_engine_node_heap_layout* pHeapLayout) +{ + ma_result result; + size_t tempHeapSize; + ma_node_config baseNodeConfig; + ma_linear_resampler_config resamplerConfig; + ma_spatializer_config spatializerConfig; + ma_uint32 channelsIn; + ma_uint32 channelsOut; + + MA_ASSERT(pHeapLayout); + + MA_ZERO_OBJECT(pHeapLayout); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->pEngine == NULL) { + return MA_INVALID_ARGS; /* An engine must be specified. */ + } + + pHeapLayout->sizeInBytes = 0; + + channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine); + channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine); + + + /* Base node. */ + baseNodeConfig = ma_engine_node_base_node_config_init(pConfig); + baseNodeConfig.pInputChannels = &channelsIn; + baseNodeConfig.pOutputChannels = &channelsOut; + + result = ma_node_get_heap_size(ma_engine_get_node_graph(pConfig->pEngine), &baseNodeConfig, &tempHeapSize); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the size of the heap for the base node. */ + } + + pHeapLayout->baseNodeOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize); + + + /* Resmapler. */ + resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, channelsIn, 1, 1); /* Input and output sample rates don't affect the calculation of the heap size. */ + resamplerConfig.lpfOrder = 0; + + result = ma_linear_resampler_get_heap_size(&resamplerConfig, &tempHeapSize); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the size of the heap for the resampler. */ + } + + pHeapLayout->resamplerOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize); + + + /* Spatializer. */ + spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig); + + result = ma_spatializer_get_heap_size(&spatializerConfig, &tempHeapSize); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the size of the heap for the spatializer. */ + } + + pHeapLayout->spatializerOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize); + + + return MA_SUCCESS; +} + +MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_engine_node_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_engine_node_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode) +{ + ma_result result; + ma_engine_node_heap_layout heapLayout; + ma_node_config baseNodeConfig; + ma_linear_resampler_config resamplerConfig; + ma_fader_config faderConfig; + ma_spatializer_config spatializerConfig; + ma_panner_config pannerConfig; + ma_uint32 channelsIn; + ma_uint32 channelsOut; + + if (pEngineNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pEngineNode); + + result = ma_engine_node_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + if (pConfig->pinnedListenerIndex != MA_LISTENER_INDEX_CLOSEST && pConfig->pinnedListenerIndex >= ma_engine_get_listener_count(pConfig->pEngine)) { + return MA_INVALID_ARGS; /* Invalid listener. */ + } + + pEngineNode->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pEngineNode->pEngine = pConfig->pEngine; + pEngineNode->sampleRate = (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine); + pEngineNode->pitch = 1; + pEngineNode->oldPitch = 1; + pEngineNode->oldDopplerPitch = 1; + pEngineNode->isPitchDisabled = pConfig->isPitchDisabled; + pEngineNode->isSpatializationDisabled = pConfig->isSpatializationDisabled; + pEngineNode->pinnedListenerIndex = pConfig->pinnedListenerIndex; + + + channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine); + channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine); + + + /* Base node. */ + baseNodeConfig = ma_engine_node_base_node_config_init(pConfig); + baseNodeConfig.pInputChannels = &channelsIn; + baseNodeConfig.pOutputChannels = &channelsOut; + + result = ma_node_init_preallocated(&pConfig->pEngine->nodeGraph, &baseNodeConfig, ma_offset_ptr(pHeap, heapLayout.baseNodeOffset), &pEngineNode->baseNode); + if (result != MA_SUCCESS) { + goto error0; + } + + + /* + We can now initialize the effects we need in order to implement the engine node. There's a + defined order of operations here, mainly centered around when we convert our channels from the + data source's native channel count to the engine's channel count. As a rule, we want to do as + much computation as possible before spatialization because there's a chance that will increase + the channel count, thereby increasing the amount of work needing to be done to process. + */ + + /* We'll always do resampling first. */ + resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], pEngineNode->sampleRate, ma_engine_get_sample_rate(pEngineNode->pEngine)); + resamplerConfig.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ + + result = ma_linear_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pEngineNode->resampler); + if (result != MA_SUCCESS) { + goto error1; + } + + + /* After resampling will come the fader. */ + faderConfig = ma_fader_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], ma_engine_get_sample_rate(pEngineNode->pEngine)); + + result = ma_fader_init(&faderConfig, &pEngineNode->fader); + if (result != MA_SUCCESS) { + goto error2; + } + + + /* + Spatialization comes next. We spatialize based ont he node's output channel count. It's up the caller to + ensure channels counts link up correctly in the node graph. + */ + spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig); + spatializerConfig.gainSmoothTimeInFrames = pEngineNode->pEngine->gainSmoothTimeInFrames; + + result = ma_spatializer_init_preallocated(&spatializerConfig, ma_offset_ptr(pHeap, heapLayout.spatializerOffset), &pEngineNode->spatializer); + if (result != MA_SUCCESS) { + goto error2; + } + + + /* + After spatialization comes panning. We need to do this after spatialization because otherwise we wouldn't + be able to pan mono sounds. + */ + pannerConfig = ma_panner_config_init(ma_format_f32, baseNodeConfig.pOutputChannels[0]); + + result = ma_panner_init(&pannerConfig, &pEngineNode->panner); + if (result != MA_SUCCESS) { + goto error3; + } + + return MA_SUCCESS; + + /* No need for allocation callbacks here because we use a preallocated heap. */ +error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL); +error2: ma_linear_resampler_uninit(&pEngineNode->resampler, NULL); +error1: ma_node_uninit(&pEngineNode->baseNode, NULL); +error0: return result; +} + +MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_engine_node_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_engine_node_init_preallocated(pConfig, pHeap, pEngineNode); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pEngineNode->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + /* + The base node always needs to be uninitialized first to ensure it's detached from the graph completely before we + destroy anything that might be in the middle of being used by the processing function. + */ + ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks); + + /* Now that the node has been uninitialized we can safely uninitialize the rest. */ + ma_spatializer_uninit(&pEngineNode->spatializer, pAllocationCallbacks); + ma_linear_resampler_uninit(&pEngineNode->resampler, pAllocationCallbacks); + + /* Free the heap last. */ + if (pEngineNode->_ownsHeap) { + ma_free(pEngineNode->_pHeap, pAllocationCallbacks); + } +} + + +MA_API ma_sound_config ma_sound_config_init(void) +{ + ma_sound_config config; + + MA_ZERO_OBJECT(&config); + config.rangeEndInPCMFrames = ~((ma_uint64)0); + config.loopPointEndInPCMFrames = ~((ma_uint64)0); + + return config; +} + +MA_API ma_sound_group_config ma_sound_group_config_init(void) +{ + ma_sound_group_config config; + + MA_ZERO_OBJECT(&config); + + return config; +} + + +MA_API ma_engine_config ma_engine_config_init(void) +{ + ma_engine_config config; + + MA_ZERO_OBJECT(&config); + config.listenerCount = 1; /* Always want at least one listener. */ + config.monoExpansionMode = ma_mono_expansion_mode_default; + + return config; +} + + +#if !defined(MA_NO_DEVICE_IO) +static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) +{ + ma_engine* pEngine = (ma_engine*)pDevice->pUserData; + + (void)pFramesIn; + + /* + Experiment: Try processing a resource manager job if we're on the Emscripten build. + + This serves two purposes: + + 1) It ensures jobs are actually processed at some point since we cannot guarantee that the + caller is doing the right thing and calling ma_resource_manager_process_next_job(); and + + 2) It's an attempt at working around an issue where processing jobs on the Emscripten main + loop doesn't work as well as it should. When trying to load sounds without the `DECODE` + flag or with the `ASYNC` flag, the sound data is just not able to be loaded in time + before the callback is processed. I think it's got something to do with the single- + threaded nature of Web, but I'm not entirely sure. + */ + #if !defined(MA_NO_RESOURCE_MANAGER) && defined(MA_EMSCRIPTEN) + { + if (pEngine->pResourceManager != NULL) { + if ((pEngine->pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) { + ma_resource_manager_process_next_job(pEngine->pResourceManager); + } + } + } + #endif + + ma_engine_read_pcm_frames(pEngine, pFramesOut, frameCount, NULL); +} +#endif + +MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine) +{ + ma_result result; + ma_node_graph_config nodeGraphConfig; + ma_engine_config engineConfig; + ma_spatializer_listener_config listenerConfig; + ma_uint32 iListener; + + if (pEngine == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pEngine); + + /* The config is allowed to be NULL in which case we use defaults for everything. */ + if (pConfig != NULL) { + engineConfig = *pConfig; + } else { + engineConfig = ma_engine_config_init(); + } + + pEngine->monoExpansionMode = engineConfig.monoExpansionMode; + ma_allocation_callbacks_init_copy(&pEngine->allocationCallbacks, &engineConfig.allocationCallbacks); + + #if !defined(MA_NO_RESOURCE_MANAGER) + { + pEngine->pResourceManager = engineConfig.pResourceManager; + } + #endif + + #if !defined(MA_NO_DEVICE_IO) + { + pEngine->pDevice = engineConfig.pDevice; + + /* If we don't have a device, we need one. */ + if (pEngine->pDevice == NULL && engineConfig.noDevice == MA_FALSE) { + ma_device_config deviceConfig; + + pEngine->pDevice = (ma_device*)ma_malloc(sizeof(*pEngine->pDevice), &pEngine->allocationCallbacks); + if (pEngine->pDevice == NULL) { + return MA_OUT_OF_MEMORY; + } + + deviceConfig = ma_device_config_init(ma_device_type_playback); + deviceConfig.playback.pDeviceID = engineConfig.pPlaybackDeviceID; + deviceConfig.playback.format = ma_format_f32; + deviceConfig.playback.channels = engineConfig.channels; + deviceConfig.sampleRate = engineConfig.sampleRate; + deviceConfig.dataCallback = ma_engine_data_callback_internal; + deviceConfig.pUserData = pEngine; + deviceConfig.periodSizeInFrames = engineConfig.periodSizeInFrames; + deviceConfig.periodSizeInMilliseconds = engineConfig.periodSizeInMilliseconds; + deviceConfig.noPreSilencedOutputBuffer = MA_TRUE; /* We'll always be outputting to every frame in the callback so there's no need for a pre-silenced buffer. */ + deviceConfig.noClip = MA_TRUE; /* The engine will do clipping itself. */ + + if (engineConfig.pContext == NULL) { + ma_context_config contextConfig = ma_context_config_init(); + contextConfig.allocationCallbacks = pEngine->allocationCallbacks; + contextConfig.pLog = engineConfig.pLog; + + /* If the engine config does not specify a log, use the resource manager's if we have one. */ + #ifndef MA_NO_RESOURCE_MANAGER + { + if (contextConfig.pLog == NULL && engineConfig.pResourceManager != NULL) { + contextConfig.pLog = ma_resource_manager_get_log(engineConfig.pResourceManager); + } + } + #endif + + result = ma_device_init_ex(NULL, 0, &contextConfig, &deviceConfig, pEngine->pDevice); + } else { + result = ma_device_init(engineConfig.pContext, &deviceConfig, pEngine->pDevice); + } + + if (result != MA_SUCCESS) { + ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); + pEngine->pDevice = NULL; + return result; + } + + pEngine->ownsDevice = MA_TRUE; + } + + /* Update the channel count and sample rate of the engine config so we can reference it below. */ + if (pEngine->pDevice != NULL) { + engineConfig.channels = pEngine->pDevice->playback.channels; + engineConfig.sampleRate = pEngine->pDevice->sampleRate; + } + } + #endif + + if (engineConfig.channels == 0 || engineConfig.sampleRate == 0) { + return MA_INVALID_ARGS; + } + + pEngine->sampleRate = engineConfig.sampleRate; + + /* The engine always uses either the log that was passed into the config, or the context's log is available. */ + if (engineConfig.pLog != NULL) { + pEngine->pLog = engineConfig.pLog; + } else { + #if !defined(MA_NO_DEVICE_IO) + { + pEngine->pLog = ma_device_get_log(pEngine->pDevice); + } + #else + { + pEngine->pLog = NULL; + } + #endif + } + + + /* The engine is a node graph. This needs to be initialized after we have the device so we can can determine the channel count. */ + nodeGraphConfig = ma_node_graph_config_init(engineConfig.channels); + nodeGraphConfig.nodeCacheCapInFrames = (engineConfig.periodSizeInFrames > 0xFFFF) ? 0xFFFF : (ma_uint16)engineConfig.periodSizeInFrames; + + result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph); + if (result != MA_SUCCESS) { + goto on_error_1; + } + + + /* We need at least one listener. */ + if (engineConfig.listenerCount == 0) { + engineConfig.listenerCount = 1; + } + + if (engineConfig.listenerCount > MA_ENGINE_MAX_LISTENERS) { + result = MA_INVALID_ARGS; /* Too many listeners. */ + goto on_error_1; + } + + for (iListener = 0; iListener < engineConfig.listenerCount; iListener += 1) { + listenerConfig = ma_spatializer_listener_config_init(ma_node_graph_get_channels(&pEngine->nodeGraph)); + + /* + If we're using a device, use the device's channel map for the listener. Otherwise just use + miniaudio's default channel map. + */ + #if !defined(MA_NO_DEVICE_IO) + { + if (pEngine->pDevice != NULL) { + /* + Temporarily disabled. There is a subtle bug here where front-left and front-right + will be used by the device's channel map, but this is not what we want to use for + spatialization. Instead we want to use side-left and side-right. I need to figure + out a better solution for this. For now, disabling the user of device channel maps. + */ + /*listenerConfig.pChannelMapOut = pEngine->pDevice->playback.channelMap;*/ + } + } + #endif + + result = ma_spatializer_listener_init(&listenerConfig, &pEngine->allocationCallbacks, &pEngine->listeners[iListener]); /* TODO: Change this to a pre-allocated heap. */ + if (result != MA_SUCCESS) { + goto on_error_2; + } + + pEngine->listenerCount += 1; + } + + + /* Gain smoothing for spatialized sounds. */ + pEngine->gainSmoothTimeInFrames = engineConfig.gainSmoothTimeInFrames; + if (pEngine->gainSmoothTimeInFrames == 0) { + ma_uint32 gainSmoothTimeInMilliseconds = engineConfig.gainSmoothTimeInMilliseconds; + if (gainSmoothTimeInMilliseconds == 0) { + gainSmoothTimeInMilliseconds = 8; + } + + pEngine->gainSmoothTimeInFrames = (gainSmoothTimeInMilliseconds * ma_engine_get_sample_rate(pEngine)) / 1000; /* 8ms by default. */ + } + + + /* We need a resource manager. */ + #ifndef MA_NO_RESOURCE_MANAGER + { + if (pEngine->pResourceManager == NULL) { + ma_resource_manager_config resourceManagerConfig; + + pEngine->pResourceManager = (ma_resource_manager*)ma_malloc(sizeof(*pEngine->pResourceManager), &pEngine->allocationCallbacks); + if (pEngine->pResourceManager == NULL) { + result = MA_OUT_OF_MEMORY; + goto on_error_2; + } + + resourceManagerConfig = ma_resource_manager_config_init(); + resourceManagerConfig.pLog = pEngine->pLog; /* Always use the engine's log for internally-managed resource managers. */ + resourceManagerConfig.decodedFormat = ma_format_f32; + resourceManagerConfig.decodedChannels = 0; /* Leave the decoded channel count as 0 so we can get good spatialization. */ + resourceManagerConfig.decodedSampleRate = ma_engine_get_sample_rate(pEngine); + ma_allocation_callbacks_init_copy(&resourceManagerConfig.allocationCallbacks, &pEngine->allocationCallbacks); + resourceManagerConfig.pVFS = engineConfig.pResourceManagerVFS; + + /* The Emscripten build cannot use threads. */ + #if defined(MA_EMSCRIPTEN) + { + resourceManagerConfig.jobThreadCount = 0; + resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; + } + #endif + + result = ma_resource_manager_init(&resourceManagerConfig, pEngine->pResourceManager); + if (result != MA_SUCCESS) { + goto on_error_3; + } + + pEngine->ownsResourceManager = MA_TRUE; + } + } + #endif + + /* Setup some stuff for inlined sounds. That is sounds played with ma_engine_play_sound(). */ + pEngine->inlinedSoundLock = 0; + pEngine->pInlinedSoundHead = NULL; + + /* Start the engine if required. This should always be the last step. */ + #if !defined(MA_NO_DEVICE_IO) + { + if (engineConfig.noAutoStart == MA_FALSE && pEngine->pDevice != NULL) { + result = ma_engine_start(pEngine); + if (result != MA_SUCCESS) { + goto on_error_4; /* Failed to start the engine. */ + } + } + } + #endif + + return MA_SUCCESS; + +#if !defined(MA_NO_DEVICE_IO) +on_error_4: +#endif +#if !defined(MA_NO_RESOURCE_MANAGER) +on_error_3: + if (pEngine->ownsResourceManager) { + ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks); + } +#endif /* MA_NO_RESOURCE_MANAGER */ +on_error_2: + for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { + ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks); + } + + ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks); +on_error_1: + #if !defined(MA_NO_DEVICE_IO) + { + if (pEngine->ownsDevice) { + ma_device_uninit(pEngine->pDevice); + ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); + } + } + #endif + + return result; +} + +MA_API void ma_engine_uninit(ma_engine* pEngine) +{ + ma_uint32 iListener; + + if (pEngine == NULL) { + return; + } + + /* The device must be uninitialized before the node graph to ensure the audio thread doesn't try accessing it. */ + #if !defined(MA_NO_DEVICE_IO) + { + if (pEngine->ownsDevice) { + ma_device_uninit(pEngine->pDevice); + ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); + } else { + if (pEngine->pDevice != NULL) { + ma_device_stop(pEngine->pDevice); + } + } + } + #endif + + /* + All inlined sounds need to be deleted. I'm going to use a lock here just to future proof in case + I want to do some kind of garbage collection later on. + */ + ma_spinlock_lock(&pEngine->inlinedSoundLock); + { + for (;;) { + ma_sound_inlined* pSoundToDelete = pEngine->pInlinedSoundHead; + if (pSoundToDelete == NULL) { + break; /* Done. */ + } + + pEngine->pInlinedSoundHead = pSoundToDelete->pNext; + + ma_sound_uninit(&pSoundToDelete->sound); + ma_free(pSoundToDelete, &pEngine->allocationCallbacks); + } + } + ma_spinlock_unlock(&pEngine->inlinedSoundLock); + + for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { + ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks); + } + + /* Make sure the node graph is uninitialized after the audio thread has been shutdown to prevent accessing of the node graph after being uninitialized. */ + ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks); + + /* Uninitialize the resource manager last to ensure we don't have a thread still trying to access it. */ +#ifndef MA_NO_RESOURCE_MANAGER + if (pEngine->ownsResourceManager) { + ma_resource_manager_uninit(pEngine->pResourceManager); + ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks); + } +#endif +} + +MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + return ma_node_graph_read_pcm_frames(&pEngine->nodeGraph, pFramesOut, frameCount, pFramesRead); +} + +MA_API ma_node_graph* ma_engine_get_node_graph(ma_engine* pEngine) +{ + if (pEngine == NULL) { + return NULL; + } + + return &pEngine->nodeGraph; +} + +#if !defined(MA_NO_RESOURCE_MANAGER) +MA_API ma_resource_manager* ma_engine_get_resource_manager(ma_engine* pEngine) +{ + if (pEngine == NULL) { + return NULL; + } + + #if !defined(MA_NO_RESOURCE_MANAGER) + { + return pEngine->pResourceManager; + } + #else + { + return NULL; + } + #endif +} +#endif + +MA_API ma_device* ma_engine_get_device(ma_engine* pEngine) +{ + if (pEngine == NULL) { + return NULL; + } + + #if !defined(MA_NO_DEVICE_IO) + { + return pEngine->pDevice; + } + #else + { + return NULL; + } + #endif +} + +MA_API ma_log* ma_engine_get_log(ma_engine* pEngine) +{ + if (pEngine == NULL) { + return NULL; + } + + if (pEngine->pLog != NULL) { + return pEngine->pLog; + } else { + #if !defined(MA_NO_DEVICE_IO) + { + return ma_device_get_log(ma_engine_get_device(pEngine)); + } + #else + { + return NULL; + } + #endif + } +} + +MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine) +{ + return ma_node_graph_get_endpoint(&pEngine->nodeGraph); +} + +MA_API ma_uint64 ma_engine_get_time(const ma_engine* pEngine) +{ + return ma_node_graph_get_time(&pEngine->nodeGraph); +} + +MA_API ma_result ma_engine_set_time(ma_engine* pEngine, ma_uint64 globalTime) +{ + return ma_node_graph_set_time(&pEngine->nodeGraph, globalTime); +} + +MA_API ma_uint32 ma_engine_get_channels(const ma_engine* pEngine) +{ + return ma_node_graph_get_channels(&pEngine->nodeGraph); +} + +MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine) +{ + if (pEngine == NULL) { + return 0; + } + + return pEngine->sampleRate; +} + + +MA_API ma_result ma_engine_start(ma_engine* pEngine) +{ + ma_result result; + + if (pEngine == NULL) { + return MA_INVALID_ARGS; + } + + #if !defined(MA_NO_DEVICE_IO) + { + if (pEngine->pDevice != NULL) { + result = ma_device_start(pEngine->pDevice); + } else { + result = MA_INVALID_OPERATION; /* The engine is running without a device which means there's no real notion of "starting" the engine. */ + } + } + #else + { + result = MA_INVALID_OPERATION; /* Device IO is disabled, so there's no real notion of "starting" the engine. */ + } + #endif + + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_engine_stop(ma_engine* pEngine) +{ + ma_result result; + + if (pEngine == NULL) { + return MA_INVALID_ARGS; + } + + #if !defined(MA_NO_DEVICE_IO) + { + if (pEngine->pDevice != NULL) { + result = ma_device_stop(pEngine->pDevice); + } else { + result = MA_INVALID_OPERATION; /* The engine is running without a device which means there's no real notion of "stopping" the engine. */ + } + } + #else + { + result = MA_INVALID_OPERATION; /* Device IO is disabled, so there's no real notion of "stopping" the engine. */ + } + #endif + + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume) +{ + if (pEngine == NULL) { + return MA_INVALID_ARGS; + } + + return ma_node_set_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0, volume); +} + +MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB) +{ + if (pEngine == NULL) { + return MA_INVALID_ARGS; + } + + return ma_node_set_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0, ma_volume_db_to_linear(gainDB)); +} + + +MA_API ma_uint32 ma_engine_get_listener_count(const ma_engine* pEngine) +{ + if (pEngine == NULL) { + return 0; + } + + return pEngine->listenerCount; +} + +MA_API ma_uint32 ma_engine_find_closest_listener(const ma_engine* pEngine, float absolutePosX, float absolutePosY, float absolutePosZ) +{ + ma_uint32 iListener; + ma_uint32 iListenerClosest; + float closestLen2 = MA_FLT_MAX; + + if (pEngine == NULL || pEngine->listenerCount == 1) { + return 0; + } + + iListenerClosest = 0; + for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { + if (ma_engine_listener_is_enabled(pEngine, iListener)) { + float len2 = ma_vec3f_len2(ma_vec3f_sub(pEngine->listeners[iListener].position, ma_vec3f_init_3f(absolutePosX, absolutePosY, absolutePosZ))); + if (closestLen2 > len2) { + closestLen2 = len2; + iListenerClosest = iListener; + } + } + } + + MA_ASSERT(iListenerClosest < 255); + return iListenerClosest; +} + +MA_API void ma_engine_listener_set_position(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return; + } + + ma_spatializer_listener_set_position(&pEngine->listeners[listenerIndex], x, y, z); +} + +MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uint32 listenerIndex) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return ma_spatializer_listener_get_position(&pEngine->listeners[listenerIndex]); +} + +MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return; + } + + ma_spatializer_listener_set_direction(&pEngine->listeners[listenerIndex], x, y, z); +} + +MA_API ma_vec3f ma_engine_listener_get_direction(const ma_engine* pEngine, ma_uint32 listenerIndex) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return ma_vec3f_init_3f(0, 0, -1); + } + + return ma_spatializer_listener_get_direction(&pEngine->listeners[listenerIndex]); +} + +MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return; + } + + ma_spatializer_listener_set_velocity(&pEngine->listeners[listenerIndex], x, y, z); +} + +MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return ma_spatializer_listener_get_velocity(&pEngine->listeners[listenerIndex]); +} + +MA_API void ma_engine_listener_set_cone(ma_engine* pEngine, ma_uint32 listenerIndex, float innerAngleInRadians, float outerAngleInRadians, float outerGain) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return; + } + + ma_spatializer_listener_set_cone(&pEngine->listeners[listenerIndex], innerAngleInRadians, outerAngleInRadians, outerGain); +} + +MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 listenerIndex, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) +{ + if (pInnerAngleInRadians != NULL) { + *pInnerAngleInRadians = 0; + } + + if (pOuterAngleInRadians != NULL) { + *pOuterAngleInRadians = 0; + } + + if (pOuterGain != NULL) { + *pOuterGain = 0; + } + + ma_spatializer_listener_get_cone(&pEngine->listeners[listenerIndex], pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain); +} + +MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return; + } + + ma_spatializer_listener_set_world_up(&pEngine->listeners[listenerIndex], x, y, z); +} + +MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return ma_vec3f_init_3f(0, 1, 0); + } + + return ma_spatializer_listener_get_world_up(&pEngine->listeners[listenerIndex]); +} + +MA_API void ma_engine_listener_set_enabled(ma_engine* pEngine, ma_uint32 listenerIndex, ma_bool32 isEnabled) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return; + } + + ma_spatializer_listener_set_enabled(&pEngine->listeners[listenerIndex], isEnabled); +} + +MA_API ma_bool32 ma_engine_listener_is_enabled(const ma_engine* pEngine, ma_uint32 listenerIndex) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return MA_FALSE; + } + + return ma_spatializer_listener_is_enabled(&pEngine->listeners[listenerIndex]); +} + + +#ifndef MA_NO_RESOURCE_MANAGER +MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePath, ma_node* pNode, ma_uint32 nodeInputBusIndex) +{ + ma_result result = MA_SUCCESS; + ma_sound_inlined* pSound = NULL; + ma_sound_inlined* pNextSound = NULL; + + if (pEngine == NULL || pFilePath == NULL) { + return MA_INVALID_ARGS; + } + + /* Attach to the endpoint node if nothing is specicied. */ + if (pNode == NULL) { + pNode = ma_node_graph_get_endpoint(&pEngine->nodeGraph); + nodeInputBusIndex = 0; + } + + /* + We want to check if we can recycle an already-allocated inlined sound. Since this is just a + helper I'm not *too* concerned about performance here and I'm happy to use a lock to keep + the implementation simple. Maybe this can be optimized later if there's enough demand, but + if this function is being used it probably means the caller doesn't really care too much. + + What we do is check the atEnd flag. When this is true, we can recycle the sound. Otherwise + we just keep iterating. If we reach the end without finding a sound to recycle we just + allocate a new one. This doesn't scale well for a massive number of sounds being played + simultaneously as we don't ever actually free the sound objects. Some kind of garbage + collection routine might be valuable for this which I'll think about. + */ + ma_spinlock_lock(&pEngine->inlinedSoundLock); + { + ma_uint32 soundFlags = 0; + + for (pNextSound = pEngine->pInlinedSoundHead; pNextSound != NULL; pNextSound = pNextSound->pNext) { + if (ma_sound_at_end(&pNextSound->sound)) { + /* + The sound is at the end which means it's available for recycling. All we need to do + is uninitialize it and reinitialize it. All we're doing is recycling memory. + */ + pSound = pNextSound; + c89atomic_fetch_sub_32(&pEngine->inlinedSoundCount, 1); + break; + } + } + + if (pSound != NULL) { + /* + We actually want to detach the sound from the list here. The reason is because we want the sound + to be in a consistent state at the non-recycled case to simplify the logic below. + */ + if (pEngine->pInlinedSoundHead == pSound) { + pEngine->pInlinedSoundHead = pSound->pNext; + } + + if (pSound->pPrev != NULL) { + pSound->pPrev->pNext = pSound->pNext; + } + if (pSound->pNext != NULL) { + pSound->pNext->pPrev = pSound->pPrev; + } + + /* Now the previous sound needs to be uninitialized. */ + ma_sound_uninit(&pNextSound->sound); + } else { + /* No sound available for recycling. Allocate one now. */ + pSound = (ma_sound_inlined*)ma_malloc(sizeof(*pSound), &pEngine->allocationCallbacks); + } + + if (pSound != NULL) { /* Safety check for the allocation above. */ + /* + At this point we should have memory allocated for the inlined sound. We just need + to initialize it like a normal sound now. + */ + soundFlags |= MA_SOUND_FLAG_ASYNC; /* For inlined sounds we don't want to be sitting around waiting for stuff to load so force an async load. */ + soundFlags |= MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT; /* We want specific control over where the sound is attached in the graph. We'll attach it manually just before playing the sound. */ + soundFlags |= MA_SOUND_FLAG_NO_PITCH; /* Pitching isn't usable with inlined sounds, so disable it to save on speed. */ + soundFlags |= MA_SOUND_FLAG_NO_SPATIALIZATION; /* Not currently doing spatialization with inlined sounds, but this might actually change later. For now disable spatialization. Will be removed if we ever add support for spatialization here. */ + + result = ma_sound_init_from_file(pEngine, pFilePath, soundFlags, NULL, NULL, &pSound->sound); + if (result == MA_SUCCESS) { + /* Now attach the sound to the graph. */ + result = ma_node_attach_output_bus(pSound, 0, pNode, nodeInputBusIndex); + if (result == MA_SUCCESS) { + /* At this point the sound should be loaded and we can go ahead and add it to the list. The new item becomes the new head. */ + pSound->pNext = pEngine->pInlinedSoundHead; + pSound->pPrev = NULL; + + pEngine->pInlinedSoundHead = pSound; /* <-- This is what attaches the sound to the list. */ + if (pSound->pNext != NULL) { + pSound->pNext->pPrev = pSound; + } + } else { + ma_free(pSound, &pEngine->allocationCallbacks); + } + } else { + ma_free(pSound, &pEngine->allocationCallbacks); + } + } else { + result = MA_OUT_OF_MEMORY; + } + } + ma_spinlock_unlock(&pEngine->inlinedSoundLock); + + if (result != MA_SUCCESS) { + return result; + } + + /* Finally we can start playing the sound. */ + result = ma_sound_start(&pSound->sound); + if (result != MA_SUCCESS) { + /* Failed to start the sound. We need to mark it for recycling and return an error. */ + c89atomic_exchange_32(&pSound->sound.atEnd, MA_TRUE); + return result; + } + + c89atomic_fetch_add_32(&pEngine->inlinedSoundCount, 1); + return result; +} + +MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup) +{ + return ma_engine_play_sound_ex(pEngine, pFilePath, pGroup, 0); +} +#endif + + +static ma_result ma_sound_preinit(ma_engine* pEngine, ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pSound); + pSound->seekTarget = MA_SEEK_TARGET_NONE; + + if (pEngine == NULL) { + return MA_INVALID_ARGS; + } + + return MA_SUCCESS; +} + +static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound) +{ + ma_result result; + ma_engine_node_config engineNodeConfig; + ma_engine_node_type type; /* Will be set to ma_engine_node_type_group if no data source is specified. */ + + /* Do not clear pSound to zero here - that's done at a higher level with ma_sound_preinit(). */ + MA_ASSERT(pEngine != NULL); + MA_ASSERT(pSound != NULL); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + pSound->pDataSource = pConfig->pDataSource; + + if (pConfig->pDataSource != NULL) { + type = ma_engine_node_type_sound; + } else { + type = ma_engine_node_type_group; + } + + /* + Sounds are engine nodes. Before we can initialize this we need to determine the channel count. + If we can't do this we need to abort. It's up to the caller to ensure they're using a data + source that provides this information upfront. + */ + engineNodeConfig = ma_engine_node_config_init(pEngine, type, pConfig->flags); + engineNodeConfig.channelsIn = pConfig->channelsIn; + engineNodeConfig.channelsOut = pConfig->channelsOut; + + /* If we're loading from a data source the input channel count needs to be the data source's native channel count. */ + if (pConfig->pDataSource != NULL) { + result = ma_data_source_get_data_format(pConfig->pDataSource, NULL, &engineNodeConfig.channelsIn, &engineNodeConfig.sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; /* Failed to retrieve the channel count. */ + } + + if (engineNodeConfig.channelsIn == 0) { + return MA_INVALID_OPERATION; /* Invalid channel count. */ + } + + if (engineNodeConfig.channelsOut == MA_SOUND_SOURCE_CHANNEL_COUNT) { + engineNodeConfig.channelsOut = engineNodeConfig.channelsIn; + } + } + + + /* Getting here means we should have a valid channel count and we can initialize the engine node. */ + result = ma_engine_node_init(&engineNodeConfig, &pEngine->allocationCallbacks, &pSound->engineNode); + if (result != MA_SUCCESS) { + return result; + } + + /* If no attachment is specified, attach the sound straight to the endpoint. */ + if (pConfig->pInitialAttachment == NULL) { + /* No group. Attach straight to the endpoint by default, unless the caller has requested that do not. */ + if ((pConfig->flags & MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT) == 0) { + result = ma_node_attach_output_bus(pSound, 0, ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0); + } + } else { + /* An attachment is specified. Attach to it by default. The sound has only a single output bus, and the config will specify which input bus to attach to. */ + result = ma_node_attach_output_bus(pSound, 0, pConfig->pInitialAttachment, pConfig->initialAttachmentInputBusIndex); + } + + if (result != MA_SUCCESS) { + ma_engine_node_uninit(&pSound->engineNode, &pEngine->allocationCallbacks); + return result; + } + + + /* Apply initial range and looping state to the data source if applicable. */ + if (pConfig->rangeBegInPCMFrames != 0 || pConfig->rangeEndInPCMFrames != ~((ma_uint64)0)) { + ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); + } + + if (pConfig->loopPointBegInPCMFrames != 0 || pConfig->loopPointEndInPCMFrames != ~((ma_uint64)0)) { + ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + } + + ma_sound_set_looping(pSound, pConfig->isLooping); + + return MA_SUCCESS; +} + +#ifndef MA_NO_RESOURCE_MANAGER +MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound) +{ + ma_result result = MA_SUCCESS; + ma_uint32 flags; + ma_sound_config config; + ma_resource_manager_pipeline_notifications notifications; + + /* + The engine requires knowledge of the channel count of the underlying data source before it can + initialize the sound. Therefore, we need to make the resource manager wait until initialization + of the underlying data source to be initialized so we can get access to the channel count. To + do this, the MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT is forced. + + Because we're initializing the data source before the sound, there's a chance the notification + will get triggered before this function returns. This is OK, so long as the caller is aware of + it and can avoid accessing the sound from within the notification. + */ + flags = pConfig->flags | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT; + + pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks); + if (pSound->pResourceManagerDataSource == NULL) { + return MA_OUT_OF_MEMORY; + } + + notifications = ma_resource_manager_pipeline_notifications_init(); + notifications.done.pFence = pConfig->pDoneFence; + + /* + We must wrap everything around the fence if one was specified. This ensures ma_fence_wait() does + not return prematurely before the sound has finished initializing. + */ + if (notifications.done.pFence) { ma_fence_acquire(notifications.done.pFence); } + { + ma_resource_manager_data_source_config resourceManagerDataSourceConfig = ma_resource_manager_data_source_config_init(); + resourceManagerDataSourceConfig.pFilePath = pConfig->pFilePath; + resourceManagerDataSourceConfig.pFilePathW = pConfig->pFilePathW; + resourceManagerDataSourceConfig.flags = flags; + resourceManagerDataSourceConfig.pNotifications = ¬ifications; + resourceManagerDataSourceConfig.initialSeekPointInPCMFrames = pConfig->initialSeekPointInPCMFrames; + resourceManagerDataSourceConfig.rangeBegInPCMFrames = pConfig->rangeBegInPCMFrames; + resourceManagerDataSourceConfig.rangeEndInPCMFrames = pConfig->rangeEndInPCMFrames; + resourceManagerDataSourceConfig.loopPointBegInPCMFrames = pConfig->loopPointBegInPCMFrames; + resourceManagerDataSourceConfig.loopPointEndInPCMFrames = pConfig->loopPointEndInPCMFrames; + resourceManagerDataSourceConfig.isLooping = pConfig->isLooping; + + result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource); + if (result != MA_SUCCESS) { + goto done; + } + + pSound->ownsDataSource = MA_TRUE; /* <-- Important. Not setting this will result in the resource manager data source never getting uninitialized. */ + + /* We need to use a slightly customized version of the config so we'll need to make a copy. */ + config = *pConfig; + config.pFilePath = NULL; + config.pFilePathW = NULL; + config.pDataSource = pSound->pResourceManagerDataSource; + + result = ma_sound_init_from_data_source_internal(pEngine, &config, pSound); + if (result != MA_SUCCESS) { + ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource); + ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); + MA_ZERO_OBJECT(pSound); + goto done; + } + } +done: + if (notifications.done.pFence) { ma_fence_release(notifications.done.pFence); } + return result; +} + +MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound) +{ + ma_sound_config config = ma_sound_config_init(); + config.pFilePath = pFilePath; + config.flags = flags; + config.pInitialAttachment = pGroup; + config.pDoneFence = pDoneFence; + return ma_sound_init_ex(pEngine, &config, pSound); +} + +MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound) +{ + ma_sound_config config = ma_sound_config_init(); + config.pFilePathW = pFilePath; + config.flags = flags; + config.pInitialAttachment = pGroup; + config.pDoneFence = pDoneFence; + return ma_sound_init_ex(pEngine, &config, pSound); +} + +MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound) +{ + ma_result result; + ma_sound_config config; + + result = ma_sound_preinit(pEngine, pSound); + if (result != MA_SUCCESS) { + return result; + } + + if (pExistingSound == NULL) { + return MA_INVALID_ARGS; + } + + /* Cloning only works for data buffers (not streams) that are loaded from the resource manager. */ + if (pExistingSound->pResourceManagerDataSource == NULL) { + return MA_INVALID_OPERATION; + } + + /* + We need to make a clone of the data source. If the data source is not a data buffer (i.e. a stream) + the this will fail. + */ + pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks); + if (pSound->pResourceManagerDataSource == NULL) { + return MA_OUT_OF_MEMORY; + } + + result = ma_resource_manager_data_source_init_copy(pEngine->pResourceManager, pExistingSound->pResourceManagerDataSource, pSound->pResourceManagerDataSource); + if (result != MA_SUCCESS) { + ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); + return result; + } + + config = ma_sound_config_init(); + config.pDataSource = pSound->pResourceManagerDataSource; + config.flags = flags; + config.pInitialAttachment = pGroup; + + result = ma_sound_init_from_data_source_internal(pEngine, &config, pSound); + if (result != MA_SUCCESS) { + ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource); + ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); + MA_ZERO_OBJECT(pSound); + return result; + } + + return MA_SUCCESS; +} +#endif + +MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound) +{ + ma_sound_config config = ma_sound_config_init(); + config.pDataSource = pDataSource; + config.flags = flags; + config.pInitialAttachment = pGroup; + return ma_sound_init_ex(pEngine, &config, pSound); +} + +MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound) +{ + ma_result result; + + result = ma_sound_preinit(pEngine, pSound); + if (result != MA_SUCCESS) { + return result; + } + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + /* We need to load the sound differently depending on whether or not we're loading from a file. */ +#ifndef MA_NO_RESOURCE_MANAGER + if (pConfig->pFilePath != NULL || pConfig->pFilePathW != NULL) { + return ma_sound_init_from_file_internal(pEngine, pConfig, pSound); + } else +#endif + { + /* + Getting here means we're not loading from a file. We may be loading from an already-initialized + data source, or none at all. If we aren't specifying any data source, we'll be initializing the + the equivalent to a group. ma_data_source_init_from_data_source_internal() will deal with this + for us, so no special treatment required here. + */ + return ma_sound_init_from_data_source_internal(pEngine, pConfig, pSound); + } +} + +MA_API void ma_sound_uninit(ma_sound* pSound) +{ + if (pSound == NULL) { + return; + } + + /* + Always uninitialize the node first. This ensures it's detached from the graph and does not return until it has done + so which makes thread safety beyond this point trivial. + */ + ma_engine_node_uninit(&pSound->engineNode, &pSound->engineNode.pEngine->allocationCallbacks); + + /* Once the sound is detached from the group we can guarantee that it won't be referenced by the mixer thread which means it's safe for us to destroy the data source. */ +#ifndef MA_NO_RESOURCE_MANAGER + if (pSound->ownsDataSource) { + ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource); + ma_free(pSound->pResourceManagerDataSource, &pSound->engineNode.pEngine->allocationCallbacks); + pSound->pDataSource = NULL; + } +#else + MA_ASSERT(pSound->ownsDataSource == MA_FALSE); +#endif +} + +MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound) +{ + if (pSound == NULL) { + return NULL; + } + + return pSound->engineNode.pEngine; +} + +MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound) +{ + if (pSound == NULL) { + return NULL; + } + + return pSound->pDataSource; +} + +MA_API ma_result ma_sound_start(ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* If the sound is already playing, do nothing. */ + if (ma_sound_is_playing(pSound)) { + return MA_SUCCESS; + } + + /* If the sound is at the end it means we want to start from the start again. */ + if (ma_sound_at_end(pSound)) { + ma_result result = ma_data_source_seek_to_pcm_frame(pSound->pDataSource, 0); + if (result != MA_SUCCESS && result != MA_NOT_IMPLEMENTED) { + return result; /* Failed to seek back to the start. */ + } + + /* Make sure we clear the end indicator. */ + c89atomic_exchange_32(&pSound->atEnd, MA_FALSE); + } + + /* Make sure the sound is started. If there's a start delay, the sound won't actually start until the start time is reached. */ + ma_node_set_state(pSound, ma_node_state_started); + + return MA_SUCCESS; +} + +MA_API ma_result ma_sound_stop(ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* This will stop the sound immediately. Use ma_sound_set_stop_time() to stop the sound at a specific time. */ + ma_node_set_state(pSound, ma_node_state_stopped); + + return MA_SUCCESS; +} + +MA_API void ma_sound_set_volume(ma_sound* pSound, float volume) +{ + if (pSound == NULL) { + return; + } + + /* The volume is controlled via the output bus. */ + ma_node_set_output_bus_volume(pSound, 0, volume); +} + +MA_API float ma_sound_get_volume(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_node_get_output_bus_volume(pSound, 0); +} + +MA_API void ma_sound_set_pan(ma_sound* pSound, float pan) +{ + if (pSound == NULL) { + return; + } + + ma_panner_set_pan(&pSound->engineNode.panner, pan); +} + +MA_API float ma_sound_get_pan(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_panner_get_pan(&pSound->engineNode.panner); +} + +MA_API void ma_sound_set_pan_mode(ma_sound* pSound, ma_pan_mode panMode) +{ + if (pSound == NULL) { + return; + } + + ma_panner_set_mode(&pSound->engineNode.panner, panMode); +} + +MA_API ma_pan_mode ma_sound_get_pan_mode(const ma_sound* pSound) +{ + if (pSound == NULL) { + return ma_pan_mode_balance; + } + + return ma_panner_get_mode(&pSound->engineNode.panner); +} + +MA_API void ma_sound_set_pitch(ma_sound* pSound, float pitch) +{ + if (pSound == NULL) { + return; + } + + if (pitch <= 0) { + return; + } + + c89atomic_exchange_explicit_f32(&pSound->engineNode.pitch, pitch, c89atomic_memory_order_release); +} + +MA_API float ma_sound_get_pitch(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return c89atomic_load_f32(&pSound->engineNode.pitch); /* Naughty const-cast for this. */ +} + +MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enabled) +{ + if (pSound == NULL) { + return; + } + + c89atomic_exchange_explicit_32(&pSound->engineNode.isSpatializationDisabled, !enabled, c89atomic_memory_order_release); +} + +MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_FALSE; + } + + return ma_engine_node_is_spatialization_enabled(&pSound->engineNode); +} + +MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex) +{ + if (pSound == NULL || listenerIndex >= ma_engine_get_listener_count(ma_sound_get_engine(pSound))) { + return; + } + + c89atomic_exchange_explicit_32(&pSound->engineNode.pinnedListenerIndex, listenerIndex, c89atomic_memory_order_release); +} + +MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_LISTENER_INDEX_CLOSEST; + } + + return c89atomic_load_explicit_32(&pSound->engineNode.pinnedListenerIndex, c89atomic_memory_order_acquire); +} + +MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound) +{ + ma_uint32 listenerIndex; + + if (pSound == NULL) { + return 0; + } + + listenerIndex = ma_sound_get_pinned_listener_index(pSound); + if (listenerIndex == MA_LISTENER_INDEX_CLOSEST) { + ma_vec3f position = ma_sound_get_position(pSound); + return ma_engine_find_closest_listener(ma_sound_get_engine(pSound), position.x, position.y, position.z); + } + + return listenerIndex; +} + +MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound) +{ + ma_vec3f relativePos; + ma_engine* pEngine; + + if (pSound == NULL) { + return ma_vec3f_init_3f(0, 0, -1); + } + + pEngine = ma_sound_get_engine(pSound); + if (pEngine == NULL) { + return ma_vec3f_init_3f(0, 0, -1); + } + + ma_spatializer_get_relative_position_and_direction(&pSound->engineNode.spatializer, &pEngine->listeners[ma_sound_get_listener_index(pSound)], &relativePos, NULL); + + return ma_vec3f_normalize(ma_vec3f_neg(relativePos)); +} + +MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_position(&pSound->engineNode.spatializer, x, y, z); +} + +MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound) +{ + if (pSound == NULL) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return ma_spatializer_get_position(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_direction(&pSound->engineNode.spatializer, x, y, z); +} + +MA_API ma_vec3f ma_sound_get_direction(const ma_sound* pSound) +{ + if (pSound == NULL) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return ma_spatializer_get_direction(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_velocity(ma_sound* pSound, float x, float y, float z) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_velocity(&pSound->engineNode.spatializer, x, y, z); +} + +MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound) +{ + if (pSound == NULL) { + return ma_vec3f_init_3f(0, 0, 0); + } + + return ma_spatializer_get_velocity(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_attenuation_model(&pSound->engineNode.spatializer, attenuationModel); +} + +MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound) +{ + if (pSound == NULL) { + return ma_attenuation_model_none; + } + + return ma_spatializer_get_attenuation_model(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_positioning(&pSound->engineNode.spatializer, positioning); +} + +MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound) +{ + if (pSound == NULL) { + return ma_positioning_absolute; + } + + return ma_spatializer_get_positioning(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_rolloff(&pSound->engineNode.spatializer, rolloff); +} + +MA_API float ma_sound_get_rolloff(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_spatializer_get_rolloff(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_min_gain(&pSound->engineNode.spatializer, minGain); +} + +MA_API float ma_sound_get_min_gain(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_spatializer_get_min_gain(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_max_gain(ma_sound* pSound, float maxGain) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_max_gain(&pSound->engineNode.spatializer, maxGain); +} + +MA_API float ma_sound_get_max_gain(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_spatializer_get_max_gain(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_min_distance(ma_sound* pSound, float minDistance) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_min_distance(&pSound->engineNode.spatializer, minDistance); +} + +MA_API float ma_sound_get_min_distance(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_spatializer_get_min_distance(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_max_distance(ma_sound* pSound, float maxDistance) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_max_distance(&pSound->engineNode.spatializer, maxDistance); +} + +MA_API float ma_sound_get_max_distance(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_spatializer_get_max_distance(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float outerAngleInRadians, float outerGain) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_cone(&pSound->engineNode.spatializer, innerAngleInRadians, outerAngleInRadians, outerGain); +} + +MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) +{ + if (pInnerAngleInRadians != NULL) { + *pInnerAngleInRadians = 0; + } + + if (pOuterAngleInRadians != NULL) { + *pOuterAngleInRadians = 0; + } + + if (pOuterGain != NULL) { + *pOuterGain = 0; + } + + ma_spatializer_get_cone(&pSound->engineNode.spatializer, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain); +} + +MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_doppler_factor(&pSound->engineNode.spatializer, dopplerFactor); +} + +MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_spatializer_get_doppler_factor(&pSound->engineNode.spatializer); +} + +MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_directional_attenuation_factor(&pSound->engineNode.spatializer, directionalAttenuationFactor); +} + +MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 1; + } + + return ma_spatializer_get_directional_attenuation_factor(&pSound->engineNode.spatializer); +} + + +MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames) +{ + if (pSound == NULL) { + return; + } + + ma_fader_set_fade(&pSound->engineNode.fader, volumeBeg, volumeEnd, fadeLengthInFrames); +} + +MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds) +{ + if (pSound == NULL) { + return; + } + + ma_sound_set_fade_in_pcm_frames(pSound, volumeBeg, volumeEnd, (fadeLengthInMilliseconds * pSound->engineNode.fader.config.sampleRate) / 1000); +} + +MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + return ma_fader_get_current_volume(&pSound->engineNode.fader); +} + +MA_API void ma_sound_set_start_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames) +{ + if (pSound == NULL) { + return; + } + + ma_node_set_state_time(pSound, ma_node_state_started, absoluteGlobalTimeInFrames); +} + +MA_API void ma_sound_set_start_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds) +{ + if (pSound == NULL) { + return; + } + + ma_sound_set_start_time_in_pcm_frames(pSound, absoluteGlobalTimeInMilliseconds * ma_engine_get_sample_rate(ma_sound_get_engine(pSound)) / 1000); +} + +MA_API void ma_sound_set_stop_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames) +{ + if (pSound == NULL) { + return; + } + + ma_node_set_state_time(pSound, ma_node_state_stopped, absoluteGlobalTimeInFrames); +} + +MA_API void ma_sound_set_stop_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds) +{ + if (pSound == NULL) { + return; + } + + ma_sound_set_stop_time_in_pcm_frames(pSound, absoluteGlobalTimeInMilliseconds * ma_engine_get_sample_rate(ma_sound_get_engine(pSound)) / 1000); +} + +MA_API ma_bool32 ma_sound_is_playing(const ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_FALSE; + } + + return ma_node_get_state_by_time(pSound, ma_engine_get_time(ma_sound_get_engine(pSound))) == ma_node_state_started; +} + +MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_node_get_time(pSound); +} + +MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping) +{ + if (pSound == NULL) { + return; + } + + /* Looping is only a valid concept if the sound is backed by a data source. */ + if (pSound->pDataSource == NULL) { + return; + } + + /* The looping state needs to be applied to the data source in order for any looping to actually happen. */ + ma_data_source_set_looping(pSound->pDataSource, isLooping); +} + +MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_FALSE; + } + + /* There is no notion of looping for sounds that are not backed by a data source. */ + if (pSound->pDataSource == NULL) { + return MA_FALSE; + } + + return ma_data_source_is_looping(pSound->pDataSource); +} + +MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound) +{ + if (pSound == NULL) { + return MA_FALSE; + } + + /* There is no notion of an end of a sound if it's not backed by a data source. */ + if (pSound->pDataSource == NULL) { + return MA_FALSE; + } + + return c89atomic_load_32(&pSound->atEnd); +} + +MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* Seeking is only valid for sounds that are backed by a data source. */ + if (pSound->pDataSource == NULL) { + return MA_INVALID_OPERATION; + } + + /* We can't be seeking while reading at the same time. We just set the seek target and get the mixing thread to do the actual seek. */ + c89atomic_exchange_64(&pSound->seekTarget, frameIndex); + + return MA_SUCCESS; +} + +MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* The data format is retrieved directly from the data source if the sound is backed by one. Otherwise we pull it from the node. */ + if (pSound->pDataSource == NULL) { + ma_uint32 channels; + + if (pFormat != NULL) { + *pFormat = ma_format_f32; + } + + channels = ma_node_get_input_channels(&pSound->engineNode, 0); + if (pChannels != NULL) { + *pChannels = channels; + } + + if (pSampleRate != NULL) { + *pSampleRate = pSound->engineNode.resampler.config.sampleRateIn; + } + + if (pChannelMap != NULL) { + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channels); + } + + return MA_SUCCESS; + } else { + return ma_data_source_get_data_format(pSound->pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); + } +} + +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* The notion of a cursor is only valid for sounds that are backed by a data source. */ + if (pSound->pDataSource == NULL) { + return MA_INVALID_OPERATION; + } + + return ma_data_source_get_cursor_in_pcm_frames(pSound->pDataSource, pCursor); +} + +MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* The notion of a sound length is only valid for sounds that are backed by a data source. */ + if (pSound->pDataSource == NULL) { + return MA_INVALID_OPERATION; + } + + return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength); +} + +MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* The notion of a cursor is only valid for sounds that are backed by a data source. */ + if (pSound->pDataSource == NULL) { + return MA_INVALID_OPERATION; + } + + return ma_data_source_get_cursor_in_seconds(pSound->pDataSource, pCursor); +} + +MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength) +{ + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + /* The notion of a sound length is only valid for sounds that are backed by a data source. */ + if (pSound->pDataSource == NULL) { + return MA_INVALID_OPERATION; + } + + return ma_data_source_get_length_in_seconds(pSound->pDataSource, pLength); +} + + +MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup) +{ + ma_sound_group_config config = ma_sound_group_config_init(); + config.flags = flags; + config.pInitialAttachment = pParentGroup; + return ma_sound_group_init_ex(pEngine, &config, pGroup); +} + +MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup) +{ + ma_sound_config soundConfig; + + if (pGroup == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pGroup); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + /* A sound group is just a sound without a data source. */ + soundConfig = *pConfig; + soundConfig.pFilePath = NULL; + soundConfig.pFilePathW = NULL; + soundConfig.pDataSource = NULL; + + /* + Groups need to have spatialization disabled by default because I think it'll be pretty rare + that programs will want to spatialize groups (but not unheard of). Certainly it feels like + disabling this by default feels like the right option. Spatialization can be enabled with a + call to ma_sound_group_set_spatialization_enabled(). + */ + soundConfig.flags |= MA_SOUND_FLAG_NO_SPATIALIZATION; + + return ma_sound_init_ex(pEngine, &soundConfig, pGroup); +} + +MA_API void ma_sound_group_uninit(ma_sound_group* pGroup) +{ + ma_sound_uninit(pGroup); +} + +MA_API ma_engine* ma_sound_group_get_engine(const ma_sound_group* pGroup) +{ + return ma_sound_get_engine(pGroup); +} + +MA_API ma_result ma_sound_group_start(ma_sound_group* pGroup) +{ + return ma_sound_start(pGroup); +} + +MA_API ma_result ma_sound_group_stop(ma_sound_group* pGroup) +{ + return ma_sound_stop(pGroup); +} + +MA_API void ma_sound_group_set_volume(ma_sound_group* pGroup, float volume) +{ + ma_sound_set_volume(pGroup, volume); +} + +MA_API float ma_sound_group_get_volume(const ma_sound_group* pGroup) +{ + return ma_sound_get_volume(pGroup); +} + +MA_API void ma_sound_group_set_pan(ma_sound_group* pGroup, float pan) +{ + ma_sound_set_pan(pGroup, pan); +} + +MA_API float ma_sound_group_get_pan(const ma_sound_group* pGroup) +{ + return ma_sound_get_pan(pGroup); +} + +MA_API void ma_sound_group_set_pan_mode(ma_sound_group* pGroup, ma_pan_mode panMode) +{ + ma_sound_set_pan_mode(pGroup, panMode); +} + +MA_API ma_pan_mode ma_sound_group_get_pan_mode(const ma_sound_group* pGroup) +{ + return ma_sound_get_pan_mode(pGroup); +} + +MA_API void ma_sound_group_set_pitch(ma_sound_group* pGroup, float pitch) +{ + ma_sound_set_pitch(pGroup, pitch); +} + +MA_API float ma_sound_group_get_pitch(const ma_sound_group* pGroup) +{ + return ma_sound_get_pitch(pGroup); +} + +MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma_bool32 enabled) +{ + ma_sound_set_spatialization_enabled(pGroup, enabled); +} + +MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup) +{ + return ma_sound_is_spatialization_enabled(pGroup); +} + +MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex) +{ + ma_sound_set_pinned_listener_index(pGroup, listenerIndex); +} + +MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup) +{ + return ma_sound_get_pinned_listener_index(pGroup); +} + +MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup) +{ + return ma_sound_get_listener_index(pGroup); +} + +MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup) +{ + return ma_sound_get_direction_to_listener(pGroup); +} + +MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z) +{ + ma_sound_set_position(pGroup, x, y, z); +} + +MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup) +{ + return ma_sound_get_position(pGroup); +} + +MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z) +{ + ma_sound_set_direction(pGroup, x, y, z); +} + +MA_API ma_vec3f ma_sound_group_get_direction(const ma_sound_group* pGroup) +{ + return ma_sound_get_direction(pGroup); +} + +MA_API void ma_sound_group_set_velocity(ma_sound_group* pGroup, float x, float y, float z) +{ + ma_sound_set_velocity(pGroup, x, y, z); +} + +MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup) +{ + return ma_sound_get_velocity(pGroup); +} + +MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel) +{ + ma_sound_set_attenuation_model(pGroup, attenuationModel); +} + +MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup) +{ + return ma_sound_get_attenuation_model(pGroup); +} + +MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning) +{ + ma_sound_set_positioning(pGroup, positioning); +} + +MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup) +{ + return ma_sound_get_positioning(pGroup); +} + +MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff) +{ + ma_sound_set_rolloff(pGroup, rolloff); +} + +MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup) +{ + return ma_sound_get_rolloff(pGroup); +} + +MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain) +{ + ma_sound_set_min_gain(pGroup, minGain); +} + +MA_API float ma_sound_group_get_min_gain(const ma_sound_group* pGroup) +{ + return ma_sound_get_min_gain(pGroup); +} + +MA_API void ma_sound_group_set_max_gain(ma_sound_group* pGroup, float maxGain) +{ + ma_sound_set_max_gain(pGroup, maxGain); +} + +MA_API float ma_sound_group_get_max_gain(const ma_sound_group* pGroup) +{ + return ma_sound_get_max_gain(pGroup); +} + +MA_API void ma_sound_group_set_min_distance(ma_sound_group* pGroup, float minDistance) +{ + ma_sound_set_min_distance(pGroup, minDistance); +} + +MA_API float ma_sound_group_get_min_distance(const ma_sound_group* pGroup) +{ + return ma_sound_get_min_distance(pGroup); +} + +MA_API void ma_sound_group_set_max_distance(ma_sound_group* pGroup, float maxDistance) +{ + ma_sound_set_max_distance(pGroup, maxDistance); +} + +MA_API float ma_sound_group_get_max_distance(const ma_sound_group* pGroup) +{ + return ma_sound_get_max_distance(pGroup); +} + +MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRadians, float outerAngleInRadians, float outerGain) +{ + ma_sound_set_cone(pGroup, innerAngleInRadians, outerAngleInRadians, outerGain); +} + +MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain) +{ + ma_sound_get_cone(pGroup, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain); +} + +MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor) +{ + ma_sound_set_doppler_factor(pGroup, dopplerFactor); +} + +MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup) +{ + return ma_sound_get_doppler_factor(pGroup); +} + +MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor) +{ + ma_sound_set_directional_attenuation_factor(pGroup, directionalAttenuationFactor); +} + +MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup) +{ + return ma_sound_get_directional_attenuation_factor(pGroup); +} + +MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames) +{ + ma_sound_set_fade_in_pcm_frames(pGroup, volumeBeg, volumeEnd, fadeLengthInFrames); +} + +MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds) +{ + ma_sound_set_fade_in_milliseconds(pGroup, volumeBeg, volumeEnd, fadeLengthInMilliseconds); +} + +MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup) +{ + return ma_sound_get_current_fade_volume(pGroup); +} + +MA_API void ma_sound_group_set_start_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames) +{ + ma_sound_set_start_time_in_pcm_frames(pGroup, absoluteGlobalTimeInFrames); +} + +MA_API void ma_sound_group_set_start_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds) +{ + ma_sound_set_start_time_in_milliseconds(pGroup, absoluteGlobalTimeInMilliseconds); +} + +MA_API void ma_sound_group_set_stop_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames) +{ + ma_sound_set_stop_time_in_pcm_frames(pGroup, absoluteGlobalTimeInFrames); +} + +MA_API void ma_sound_group_set_stop_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds) +{ + ma_sound_set_stop_time_in_milliseconds(pGroup, absoluteGlobalTimeInMilliseconds); +} + +MA_API ma_bool32 ma_sound_group_is_playing(const ma_sound_group* pGroup) +{ + return ma_sound_is_playing(pGroup); +} + +MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGroup) +{ + return ma_sound_get_time_in_pcm_frames(pGroup); +} +#endif /* MA_NO_ENGINE */ + + + /************************************************************************************************************************************************************** *************************************************************************************************************************************************************** @@ -52852,6 +73812,7 @@ code below please report the bug to the respective repository for the relevant p #define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) #define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) +#define drwav_offset_ptr(p, offset) (((drwav_uint8*)(p)) + (offset)) #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 #if defined(__x86_64__) || defined(_M_X64) #define DRWAV_X64 @@ -52864,9 +73825,14 @@ code below please report the bug to the respective repository for the relevant p #define DRWAV_INLINE __forceinline #elif defined(__GNUC__) #if defined(__STRICT_ANSI__) - #define DRWAV_INLINE __inline__ __attribute__((always_inline)) + #define DRWAV_GNUC_INLINE_HINT __inline__ #else - #define DRWAV_INLINE inline __attribute__((always_inline)) + #define DRWAV_GNUC_INLINE_HINT inline + #endif + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT #endif #elif defined(__WATCOMC__) #define DRWAV_INLINE __inline @@ -53095,6 +74061,9 @@ static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 s { switch (bytesPerSample) { + case 1: + { + } break; case 2: { drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); @@ -53353,7 +74322,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_pr fmtOut->extendedSize = 0; fmtOut->validBitsPerSample = 0; fmtOut->channelMask = 0; - memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); + DRWAV_ZERO_MEMORY(fmtOut->subFormat, sizeof(fmtOut->subFormat)); if (header.sizeInBytes > 16) { drwav_uint8 fmt_cbSize[2]; int bytesReadSoFar = 0; @@ -53486,7 +74455,7 @@ DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metad DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks) { if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) { - free(pParser->pData); + pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData); pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData); pParser->pDataCursor = pParser->pData; if (pParser->pData == NULL) { @@ -53505,12 +74474,13 @@ DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead); } } -DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES]; drwav_uint64 totalBytesRead = 0; size_t bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); + DRWAV_ASSERT(pChunkHeader != NULL); if (bytesJustRead == sizeof(smplHeaderData)) { drwav_uint32 iSampleLoop; pMetadata->type = drwav_metadata_type_smpl; @@ -53523,30 +74493,32 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars pMetadata->data.smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData + 24); pMetadata->data.smpl.sampleLoopCount = drwav_bytes_to_u32(smplHeaderData + 28); pMetadata->data.smpl.samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32); - pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); - for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { - drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); - if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); - } else { - break; + if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) { + pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT); + for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) { + drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); + if (bytesJustRead == sizeof(smplLoopData)) { + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); + } else { + break; + } + } + if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { + pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); + DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); + drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); } - } - if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1); - DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead); } } return totalBytesRead; } -DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata) +DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata) { drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES]; drwav_uint64 totalBytesRead = 0; @@ -53555,25 +74527,27 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parse if (bytesJustRead == sizeof(cueHeaderSectionData)) { pMetadata->type = drwav_metadata_type_cue; pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData); - pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); - DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); - if (pMetadata->data.cue.cuePointCount > 0) { - drwav_uint32 iCuePoint; - for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { - drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; - bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); - if (bytesJustRead == sizeof(cuePointData)) { - pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); - pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; - pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; - pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); - pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); - } else { - break; + if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) { + pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT); + DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL); + if (pMetadata->data.cue.cuePointCount > 0) { + drwav_uint32 iCuePoint; + for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) { + drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES]; + bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead); + if (bytesJustRead == sizeof(cuePointData)) { + pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0); + pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4); + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10]; + pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; + pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); + pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); + } else { + break; + } } } } @@ -53615,7 +74589,15 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_pars } return bytesRead; } -DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) +DRWAV_PRIVATE size_t drwav__strlen(const char* str) +{ + size_t result = 0; + while (*str++) { + result += 1; + } + return result; +} +DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead) { size_t result = 0; while (*str++ && result < maxToRead) { @@ -53623,71 +74605,147 @@ DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead) } return result; } -DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, char* str, size_t maxToRead) +DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead) { size_t len = drwav__strlen_clamped(str, maxToRead); if (len) { char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1); DRWAV_ASSERT(result != NULL); - memcpy(result, str, len); + DRWAV_COPY_MEMORY(result, str, len); result[len] = '\0'; return result; } else { return NULL; } } +typedef struct +{ + const void* pBuffer; + size_t sizeInBytes; + size_t cursor; +} drwav_buffer_reader; +DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pBuffer != NULL); + DRWAV_ASSERT(pReader != NULL); + DRWAV_ZERO_OBJECT(pReader); + pReader->pBuffer = pBuffer; + pReader->sizeInBytes = sizeInBytes; + pReader->cursor = 0; + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader) +{ + DRWAV_ASSERT(pReader != NULL); + return drwav_offset_ptr(pReader->pBuffer, pReader->cursor); +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek) +{ + DRWAV_ASSERT(pReader != NULL); + if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) { + return DRWAV_BAD_SEEK; + } + pReader->cursor += bytesToSeek; + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead) +{ + drwav_result result = DRWAV_SUCCESS; + size_t bytesRemaining; + DRWAV_ASSERT(pReader != NULL); + if (pBytesRead != NULL) { + *pBytesRead = 0; + } + bytesRemaining = (pReader->sizeInBytes - pReader->cursor); + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + if (pDst == NULL) { + result = drwav_buffer_reader_seek(pReader, bytesToRead); + } else { + DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead); + pReader->cursor += bytesToRead; + } + DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes); + if (result == DRWAV_SUCCESS) { + if (pBytesRead != NULL) { + *pBytesRead = bytesToRead; + } + } + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[2]; + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + *pDst = 0; + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + *pDst = drwav_bytes_to_u16(data); + return DRWAV_SUCCESS; +} +DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst) +{ + drwav_result result; + size_t bytesRead; + drwav_uint8 data[4]; + DRWAV_ASSERT(pReader != NULL); + DRWAV_ASSERT(pDst != NULL); + *pDst = 0; + result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead); + if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) { + return result; + } + *pDst = drwav_bytes_to_u32(data); + return DRWAV_SUCCESS; +} DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize) { drwav_uint8 bextData[DRWAV_BEXT_BYTES]; - drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); + size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); if (bytesRead == sizeof(bextData)) { - drwav_uint8* pReadPointer; + drwav_buffer_reader reader; drwav_uint32 timeReferenceLow; drwav_uint32 timeReferenceHigh; size_t extraBytes; pMetadata->type = drwav_metadata_type_bext; - pReadPointer = bextData; - pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_DESCRIPTION_BYTES); - pReadPointer += DRWAV_BEXT_DESCRIPTION_BYTES; - pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_NAME_BYTES; - pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_REF_BYTES); - pReadPointer += DRWAV_BEXT_ORIGINATOR_REF_BYTES; - memcpy(pReadPointer, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationDate); - memcpy(pReadPointer, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime)); - pReadPointer += sizeof(pMetadata->data.bext.pOriginationTime); - timeReferenceLow = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - timeReferenceHigh = drwav_bytes_to_u32(pReadPointer); - pReadPointer += sizeof(drwav_uint32); - pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; - pMetadata->data.bext.version = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); - memcpy(pMetadata->data.bext.pUMID, pReadPointer, DRWAV_BEXT_UMID_BYTES); - pReadPointer += DRWAV_BEXT_UMID_BYTES; - pMetadata->data.bext.loudnessValue = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.loudnessRange = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxTruePeakLevel = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxMomentaryLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - pMetadata->data.bext.maxShortTermLoudness = drwav_bytes_to_u16(pReadPointer); - pReadPointer += sizeof(drwav_uint16); - DRWAV_ASSERT((pReadPointer + DRWAV_BEXT_RESERVED_BYTES) == (bextData + DRWAV_BEXT_BYTES)); - extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); - if (extraBytes > 0) { - pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); - DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); - bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); - pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); - } else { - pMetadata->data.bext.pCodingHistory = NULL; - pMetadata->data.bext.codingHistorySize = 0; + if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) { + pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES); + pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES); + pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES); + drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL); + drwav_buffer_reader_read_u32(&reader, &timeReferenceLow); + drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh); + pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version); + pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1); + drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness); + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness); + DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES)); + extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES); + if (extraBytes > 0) { + pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1); + DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); + bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); + pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__strlen(pMetadata->data.bext.pCodingHistory); + } else { + pMetadata->data.bext.pCodingHistory = NULL; + pMetadata->data.bext.codingHistorySize = 0; + } } } return bytesRead; @@ -53707,7 +74765,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav_ pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1; pMetadata->data.labelOrNote.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelOrNote.stringLength = 0; pMetadata->data.labelOrNote.pString = NULL; @@ -53739,7 +74797,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj( pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1; pMetadata->data.labelledCueRegion.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1); DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL); - bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); + drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead); } else { pMetadata->data.labelledCueRegion.stringLength = 0; pMetadata->data.labelledCueRegion.pString = NULL; @@ -53805,11 +74863,11 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata } return bytesRead; } -DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_uint64 allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) +DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID) { return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID); } -DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_uint64 allowedMetadataTypes) +DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes) { const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc; drwav_uint64 bytesRead = 0; @@ -53825,16 +74883,21 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); if (bytesJustRead == sizeof(buffer)) { drwav_uint32 loopCount = drwav_bytes_to_u32(buffer); - bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); - if (bytesJustRead == sizeof(buffer)) { - drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); - pParser->metadataCount += 1; - drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); - drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); + drwav_uint64 calculatedLoopCount; + calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES; + if (calculatedLoopCount == loopCount) { + bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead); + if (bytesJustRead == sizeof(buffer)) { + drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer); + pParser->metadataCount += 1; + drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT); + drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1); + } + } else { } } } else { - bytesRead = drwav__read_smpl_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -53876,7 +74939,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES; drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT); } else { - bytesRead = drwav__read_cue_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]); + bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); if (bytesRead == pChunkHeader->sizeInBytes) { pParser->metadataCursor += 1; } else { @@ -53895,19 +74958,19 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* if (bytesJustRead != DRWAV_BEXT_DESCRIPTION_BYTES) { return bytesRead; } - allocSizeNeeded += strlen(buffer) + 1; + allocSizeNeeded += drwav__strlen(buffer) + 1; buffer[DRWAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0'; bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead); if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_NAME_BYTES) { return bytesRead; } - allocSizeNeeded += strlen(buffer) + 1; + allocSizeNeeded += drwav__strlen(buffer) + 1; buffer[DRWAV_BEXT_ORIGINATOR_REF_BYTES] = '\0'; bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead); if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_REF_BYTES) { return bytesRead; } - allocSizeNeeded += strlen(buffer) + 1; + allocSizeNeeded += drwav__strlen(buffer) + 1; allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); pParser->metadataCount += 1; @@ -53991,7 +75054,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album); } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber); - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } bytesRead += subchunkBytesRead; @@ -54010,18 +75073,25 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* bytesRead += 1; } } - } else if (allowedMetadataTypes & drwav_metadata_type_unknown) { + } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) { bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level); } return bytesRead; } DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) { + drwav_uint32 bytesPerFrame; if ((pWav->bitsPerSample & 0x7) == 0) { - return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3; } else { - return pWav->fmt.blockAlign; + bytesPerFrame = pWav->fmt.blockAlign; } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + if (bytesPerFrame != pWav->fmt.channels) { + return 0; + } + } + return bytesPerFrame; } DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) { @@ -54167,7 +75237,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0); } - memset(&metadataParser, 0, sizeof(metadataParser)); + DRWAV_ZERO_MEMORY(&metadataParser, sizeof(metadataParser)); if (!sequential && pWav->allowedMetadataTypes != drwav_metadata_type_none && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64)) { drwav_uint64 cursorForMetadata = cursor; metadataParser.onRead = pWav->onRead; @@ -54302,7 +75372,11 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; } else { - pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; + } + pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 totalBlockHeaderSizeInBytes; drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -54328,6 +75402,9 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on return DRWAV_FALSE; } } + if (drwav_get_bytes_per_pcm_frame(pWav) == 0) { + return DRWAV_FALSE; + } #ifdef DR_WAV_LIBSNDFILE_COMPAT if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -54592,7 +75669,7 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxTruePeakLevel); bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness); bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness); - memset(reservedBuf, 0, sizeof(reservedBuf)); + DRWAV_ZERO_MEMORY(reservedBuf, sizeof(reservedBuf)); bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf)); if (pMetadata->data.bext.codingHistorySize > 0) { bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pCodingHistory, pMetadata->data.bext.codingHistorySize); @@ -55829,6 +76906,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav) DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { size_t bytesRead; + drwav_uint32 bytesPerFrame; if (pWav == NULL || bytesToRead == 0) { return 0; } @@ -55838,6 +76916,10 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu if (bytesToRead == 0) { return 0; } + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } if (pBufferOut != NULL) { bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); } else { @@ -55866,7 +76948,7 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu } } } - pWav->readCursorInPCMFrames += bytesRead / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame; pWav->bytesRemaining -= bytesRead; return bytesRead; } @@ -55897,7 +76979,11 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 frames { drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); if (pBufferOut != NULL) { - drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels, pWav->translatedFormatTag); } return framesRead; } @@ -55941,8 +77027,8 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF if (pWav->totalPCMFrameCount == 0) { return DRWAV_TRUE; } - if (targetFrameIndex >= pWav->totalPCMFrameCount) { - targetFrameIndex = pWav->totalPCMFrameCount - 1; + if (targetFrameIndex > pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount; } if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { if (targetFrameIndex < pWav->readCursorInPCMFrames) { @@ -55977,10 +77063,15 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF drwav_uint64 currentBytePos; drwav_uint64 targetBytePos; drwav_uint64 offset; - totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint32 bytesPerFrame; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return DRWAV_FALSE; + } + totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame; DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); + targetBytePos = targetFrameIndex * bytesPerFrame; if (currentBytePos < targetBytePos) { offset = (targetBytePos - currentBytePos); } else { @@ -55994,7 +77085,7 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { return DRWAV_FALSE; } - pWav->readCursorInPCMFrames += offset32 / drwav_get_bytes_per_pcm_frame(pWav); + pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; pWav->bytesRemaining -= offset32; offset -= offset32; } @@ -56080,6 +77171,9 @@ DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 frame bytesWritten = 0; pRunningData = (const drwav_uint8*)pData; bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; + if (bytesPerSample == 0) { + return 0; + } while (bytesToWrite > 0) { drwav_uint8 temp[4096]; drwav_uint32 sampleCount; @@ -56278,7 +77372,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin return totalFramesRead; } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; pWav->ima.cachedFrameCount = 1; } else { @@ -56293,9 +77387,9 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin return totalFramesRead; } pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; + pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4); - pWav->ima.stepIndex[1] = header[6]; + pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1); pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; pWav->ima.cachedFrameCount = 1; @@ -56409,7 +77503,7 @@ static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) } DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - unsigned int i; + size_t i; if (bytesPerSample == 1) { drwav_u8_to_s16(pOut, pIn, totalSampleCount); return; @@ -56461,8 +77555,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -56470,14 +77566,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56486,8 +77593,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -56495,14 +77604,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56511,8 +77631,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -56520,14 +77642,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56536,8 +77669,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pBufferOut == NULL) { return drwav_read_pcm_frames(pWav, framesToRead, NULL); } @@ -56545,14 +77680,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_u if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56733,49 +77879,50 @@ DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - drwav_uint64 totalFramesRead = 0; + drwav_uint64 totalFramesRead; drwav_int16 samples16[2048]; + totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) -{ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; @@ -56786,8 +77933,10 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -56795,14 +77944,25 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56811,19 +77971,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56832,19 +78006,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -56864,8 +78052,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); @@ -56876,9 +78064,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); - } return 0; } DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) @@ -57035,8 +78220,10 @@ DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; + drwav_uint8 sampleData[4096] = {0}; drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); } @@ -57044,44 +78231,41 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uin if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } return totalFramesRead; } -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead = 0; drwav_int16 samples16[2048]; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); - if (framesRead == 0) { - break; - } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; - framesToRead -= framesRead; - totalFramesRead += framesRead; - } - return totalFramesRead; -} -DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) -{ - drwav_uint64 totalFramesRead = 0; - drwav_int16 samples16[2048]; - while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels); + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16); if (framesRead == 0) { break; } + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); pBufferOut += framesRead*pWav->channels; framesToRead -= framesRead; @@ -57092,19 +78276,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uin DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -57113,19 +78311,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -57134,19 +78346,33 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_ui DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { drwav_uint64 totalFramesRead; - drwav_uint8 sampleData[4096]; - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } + bytesPerSample = bytesPerFrame / pWav->channels; + if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) { + return 0; + } totalFramesRead = 0; while (framesToRead > 0) { - drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame); + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData); if (framesRead == 0) { break; } - drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); - pBufferOut += framesRead*pWav->channels; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); + samplesRead = framesRead * pWav->channels; + if ((samplesRead * bytesPerSample) > sizeof(sampleData)) { + DRWAV_ASSERT(DRWAV_FALSE); + break; + } + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + pBufferOut += samplesRead; framesToRead -= framesRead; totalFramesRead += framesRead; } @@ -57166,8 +78392,8 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); @@ -57178,9 +78404,6 @@ DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 frame if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); - } return 0; } DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) @@ -57677,9 +78900,14 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) #define DRFLAC_INLINE __forceinline #elif defined(__GNUC__) #if defined(__STRICT_ANSI__) - #define DRFLAC_INLINE __inline__ __attribute__((always_inline)) + #define DRFLAC_GNUC_INLINE_HINT __inline__ #else - #define DRFLAC_INLINE inline __attribute__((always_inline)) + #define DRFLAC_GNUC_INLINE_HINT inline + #endif + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT #endif #elif defined(__WATCOMC__) #define DRFLAC_INLINE __inline @@ -57690,7 +78918,7 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) #define DRFLAC_X64 #elif defined(__i386) || defined(_M_IX86) #define DRFLAC_X86 -#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64) +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) #define DRFLAC_ARM #endif #if !defined(DR_FLAC_NO_SIMD) @@ -57727,13 +78955,6 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) #if defined(DRFLAC_ARM) #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) #define DRFLAC_SUPPORT_NEON - #endif - #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) - #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include() - #define DRFLAC_SUPPORT_NEON - #endif - #endif - #if defined(DRFLAC_SUPPORT_NEON) #include #endif #endif @@ -58136,6 +79357,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) } return n; } +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3); +} static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) { if (drflac__is_little_endian()) { @@ -58150,6 +79376,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) } return n; } +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24; +} static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) { drflac_uint32 result = 0; @@ -58535,6 +79766,9 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + return DRFLAC_FALSE; + } *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); bs->consumedBits += bitCountLo; bs->cache <<= bitCountLo; @@ -58876,8 +80110,18 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, return DRFLAC_FALSE; } } + if (bs->cache == 1) { + *pOffsetOut = zeroCounter + (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs) - 1; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + return DRFLAC_TRUE; + } setBitOffsetPlus1 = drflac__clz(bs->cache); setBitOffsetPlus1 += 1; + if (setBitOffsetPlus1 > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + return DRFLAC_FALSE; + } bs->consumedBits += setBitOffsetPlus1; bs->cache <<= setBitOffsetPlus1; *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1; @@ -58963,6 +80207,24 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 *pCRCOut = crc; return DRFLAC_SUCCESS; } +static DRFLAC_INLINE drflac_uint32 drflac__ilog2_u32(drflac_uint32 x) +{ +#if 1 + drflac_uint32 result = 0; + while (x > 0) { + result += 1; + x >>= 1; + } + return result; +#endif +} +static DRFLAC_INLINE drflac_bool32 drflac__use_64_bit_prediction(drflac_uint32 bitsPerSample, drflac_uint32 order, drflac_uint32 precision) +{ + return bitsPerSample + precision + drflac__ilog2_u32(order) > 32; +} +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { drflac_int32 prediction = 0; @@ -59173,7 +80435,7 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 return (drflac_int32)(prediction >> shift); } #if 0 -static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); @@ -59205,10 +80467,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla } else { decodedRice = (decodedRice >> 1); } - if (bitsPerSample+shift >= 32) { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } } return DRFLAC_TRUE; @@ -59287,6 +80549,9 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + return DRFLAC_FALSE; + } } riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); bs->consumedBits += bitCountLo; @@ -59334,6 +80599,9 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + return DRFLAC_FALSE; + } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; } @@ -59403,6 +80671,9 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + return DRFLAC_FALSE; + } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; } @@ -59464,7 +80735,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorde } return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; drflac_uint32 zeroCountPart0 = 0; @@ -59480,12 +80751,12 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); - if (order == 0) { - return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + if (lpcOrder == 0) { + return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } riceParamMask = (drflac_uint32)~((~0UL) << riceParam); pSamplesOutEnd = pSamplesOut + (count & ~3); - if (bitsPerSample+shift > 32) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { while (pSamplesOut < pSamplesOutEnd) { if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || @@ -59505,10 +80776,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } } else { @@ -59531,10 +80802,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } } @@ -59546,10 +80817,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b riceParamPart0 &= riceParamMask; riceParamPart0 |= (zeroCountPart0 << riceParam); riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; - if (bitsPerSample+shift > 32) { - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); } else { - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); } i += 1; pSamplesOut += 1; @@ -59894,18 +81165,18 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac } return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); - if (order > 0 && order <= 12) { - if (bitsPerSample+shift > 32) { - return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } else { - return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } } else { - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } } #endif @@ -60244,37 +81515,37 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ } return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); - if (order > 0 && order <= 12) { - if (bitsPerSample+shift > 32) { - return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } else { - return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } } else { - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } } #endif -static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { #if defined(DRFLAC_SUPPORT_SSE41) if (drflac__gIsSSE41Supported) { - return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } else #elif defined(DRFLAC_SUPPORT_NEON) if (drflac__gIsNEONSupported) { - return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } else #endif { #if 0 - return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); #else - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); #endif } } @@ -60289,7 +81560,10 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ } return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); @@ -60303,15 +81577,15 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* } else { pSamplesOut[i] = 0; } - if (bitsPerSample >= 24) { - pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] += drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); + pSamplesOut[i] += drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } } return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { drflac_uint8 residualMethod; drflac_uint8 partitionOrder; @@ -60326,17 +81600,17 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { return DRFLAC_FALSE; } - pDecodedSamples += order; + pDecodedSamples += lpcOrder; if (!drflac__read_uint8(bs, 4, &partitionOrder)) { return DRFLAC_FALSE; } if (partitionOrder > 8) { return DRFLAC_FALSE; } - if ((blockSize / (1 << partitionOrder)) < order) { + if ((blockSize / (1 << partitionOrder)) < lpcOrder) { return DRFLAC_FALSE; } - samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; partitionsRemaining = (1 << partitionOrder); for (;;) { drflac_uint8 riceParam = 0; @@ -60356,7 +81630,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } } if (riceParam != 0xFF) { - if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } else { @@ -60364,7 +81638,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { return DRFLAC_FALSE; } - if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } @@ -60484,7 +81758,7 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 } pDecodedSamples[i] = sample; } - if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { return DRFLAC_FALSE; } return DRFLAC_TRUE; @@ -60521,7 +81795,7 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl return DRFLAC_FALSE; } } - if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } return DRFLAC_TRUE; @@ -60630,6 +81904,9 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u return DRFLAC_FALSE; } crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16); + if (header->blockSizeInPCMFrames == 0xFFFF) { + return DRFLAC_FALSE; + } header->blockSizeInPCMFrames += 1; } else { DRFLAC_ASSERT(blockSize >= 8); @@ -60662,6 +81939,9 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u if (header->bitsPerSample == 0) { header->bitsPerSample = streaminfoBitsPerSample; } + if (header->bitsPerSample != streaminfoBitsPerSample) { + return DRFLAC_FALSE; + } if (!drflac__read_uint8(bs, 8, &header->crc8)) { return DRFLAC_FALSE; } @@ -60732,6 +82012,9 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { subframeBitsPerSample += 1; } + if (subframeBitsPerSample > 32) { + return DRFLAC_FALSE; + } if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { return DRFLAC_FALSE; } @@ -61215,6 +82498,9 @@ static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { return DRFLAC_FALSE; } + if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) { + return DRFLAC_FALSE; + } for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { break; @@ -61558,13 +82844,13 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d metadata.rawDataSize = blockSize; pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; - metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; @@ -61576,7 +82862,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } - commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + commentLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; @@ -61660,24 +82946,24 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d metadata.rawDataSize = blockSize; pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; - metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); @@ -62563,7 +83849,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac #ifndef DR_FLAC_NO_OGG if (init.container == drflac_container_ogg) { drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize); - *pInternalOggbs = oggbs; + DRFLAC_COPY_MEMORY(pInternalOggbs, &oggbs, sizeof(oggbs)); pFlac->bs.onRead = drflac__on_read_ogg; pFlac->bs.onSeek = drflac__on_seek_ogg; pFlac->bs.pUserData = (void*)pInternalOggbs; @@ -65798,7 +87084,7 @@ DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { return NULL; } - length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); + length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData); pIter->pRunningData += 4; pComment = pIter->pRunningData; pIter->pRunningData += length; @@ -67301,7 +88587,11 @@ static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins) vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); #endif #else + #if DRMP3_HAVE_SSE static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + #else + const drmp3_f4 g_scale = vdupq_n_f32(1.0f/32768.0f); + #endif a = DRMP3_VMUL(a, g_scale); b = DRMP3_VMUL(b, g_scale); #if DRMP3_HAVE_SSE @@ -67575,7 +88865,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num } } } -#include #if defined(SIZE_MAX) #define DRMP3_SIZE_MAX SIZE_MAX #else @@ -67621,18 +88910,6 @@ static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b) } return a; } -static DRMP3_INLINE double drmp3_sin(double x) -{ - return sin(x); -} -static DRMP3_INLINE double drmp3_exp(double x) -{ - return exp(x); -} -static DRMP3_INLINE double drmp3_cos(double x) -{ - return drmp3_sin((DRMP3_PI_D*0.5) - x); -} static void* drmp3__malloc_default(size_t sz, void* pUserData) { (void)pUserData; @@ -69134,1093 +90411,6 @@ DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocation #endif /* miniaudio_c */ #endif /* MINIAUDIO_IMPLEMENTATION */ -/* -RELEASE NOTES - VERSION 0.10.x -============================== -Version 0.10 includes major API changes and refactoring, mostly concerned with the data conversion system. Data conversion is performed internally to convert -audio data between the format requested when initializing the `ma_device` object and the format of the internal device used by the backend. The same applies -to the `ma_decoder` object. The previous design has several design flaws and missing features which necessitated a complete redesign. - - -Changes to Data Conversion --------------------------- -The previous data conversion system used callbacks to deliver input data for conversion. This design works well in some specific situations, but in other -situations it has some major readability and maintenance issues. The decision was made to replace this with a more iterative approach where you just pass in a -pointer to the input data directly rather than dealing with a callback. - -The following are the data conversion APIs that have been removed and their replacements: - - - ma_format_converter -> ma_convert_pcm_frames_format() - - ma_channel_router -> ma_channel_converter - - ma_src -> ma_resampler - - ma_pcm_converter -> ma_data_converter - -The previous conversion APIs accepted a callback in their configs. There are no longer any callbacks to deal with. Instead you just pass the data into the -`*_process_pcm_frames()` function as a pointer to a buffer. - -The simplest aspect of data conversion is sample format conversion. To convert between two formats, just call `ma_convert_pcm_frames_format()`. Channel -conversion is also simple which you can do with `ma_channel_converter` via `ma_channel_converter_process_pcm_frames()`. - -Resampling is more complicated because the number of output frames that are processed is different to the number of input frames that are consumed. When you -call `ma_resampler_process_pcm_frames()` you need to pass in the number of input frames available for processing and the number of output frames you want to -output. Upon returning they will receive the number of input frames that were consumed and the number of output frames that were generated. - -The `ma_data_converter` API is a wrapper around format, channel and sample rate conversion and handles all of the data conversion you'll need which probably -makes it the best option if you need to do data conversion. - -In addition to changes to the API design, a few other changes have been made to the data conversion pipeline: - - - The sinc resampler has been removed. This was completely broken and never actually worked properly. - - The linear resampler now uses low-pass filtering to remove aliasing. The quality of the low-pass filter can be controlled via the resampler config with the - `lpfOrder` option, which has a maximum value of MA_MAX_FILTER_ORDER. - - Data conversion now supports s16 natively which runs through a fixed point pipeline. Previously everything needed to be converted to floating point before - processing, whereas now both s16 and f32 are natively supported. Other formats still require conversion to either s16 or f32 prior to processing, however - `ma_data_converter` will handle this for you. - - -Custom Memory Allocators ------------------------- -miniaudio has always supported macro level customization for memory allocation via MA_MALLOC, MA_REALLOC and MA_FREE, however some scenarios require more -flexibility by allowing a user data pointer to be passed to the custom allocation routines. Support for this has been added to version 0.10 via the -`ma_allocation_callbacks` structure. Anything making use of heap allocations has been updated to accept this new structure. - -The `ma_context_config` structure has been updated with a new member called `allocationCallbacks`. Leaving this set to it's defaults returned by -`ma_context_config_init()` will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. Likewise, The `ma_decoder_config` structure has been updated in the same -way, and leaving everything as-is after `ma_decoder_config_init()` will cause it to use the same defaults. - -The following APIs have been updated to take a pointer to a `ma_allocation_callbacks` object. Setting this parameter to NULL will cause it to use defaults. -Otherwise they will use the relevant callback in the structure. - - - ma_malloc() - - ma_realloc() - - ma_free() - - ma_aligned_malloc() - - ma_aligned_free() - - ma_rb_init() / ma_rb_init_ex() - - ma_pcm_rb_init() / ma_pcm_rb_init_ex() - -Note that you can continue to use MA_MALLOC, MA_REALLOC and MA_FREE as per normal. These will continue to be used by default if you do not specify custom -allocation callbacks. - - -Buffer and Period Configuration Changes ---------------------------------------- -The way in which the size of the internal buffer and periods are specified in the device configuration have changed. In previous versions, the config variables -`bufferSizeInFrames` and `bufferSizeInMilliseconds` defined the size of the entire buffer, with the size of a period being the size of this variable divided by -the period count. This became confusing because people would expect the value of `bufferSizeInFrames` or `bufferSizeInMilliseconds` to independantly determine -latency, when in fact it was that value divided by the period count that determined it. These variables have been removed and replaced with new ones called -`periodSizeInFrames` and `periodSizeInMilliseconds`. - -These new configuration variables work in the same way as their predecessors in that if one is set to 0, the other will be used, but the main difference is -that you now set these to you desired latency rather than the size of the entire buffer. The benefit of this is that it's much easier and less confusing to -configure latency. - -The following unused APIs have been removed: - - ma_get_default_buffer_size_in_milliseconds() - ma_get_default_buffer_size_in_frames() - -The following macros have been removed: - - MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY - MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE - - -Other API Changes ------------------ -Other less major API changes have also been made in version 0.10. - -`ma_device_set_stop_callback()` has been removed. If you require a stop callback, you must now set it via the device config just like the data callback. - -The `ma_sine_wave` API has been replaced with a more general API called `ma_waveform`. This supports generation of different types of waveforms, including -sine, square, triangle and sawtooth. Use `ma_waveform_init()` in place of `ma_sine_wave_init()` to initialize the waveform object. This takes a configuration -object called `ma_waveform_config` which defines the properties of the waveform. Use `ma_waveform_config_init()` to initialize a `ma_waveform_config` object. -Use `ma_waveform_read_pcm_frames()` in place of `ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()`. - -`ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies -the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to -take a pointer to a `ma_data_converter_config` object to specify the input and output formats to convert between. This was done to make it more flexible, to -prevent the parameter list getting too long, and to prevent API breakage whenever a new conversion property is added. - -`ma_calculate_frame_count_after_src()` has been renamed to `ma_calculate_frame_count_after_resampling()` for consistency with the new `ma_resampler` API. - - -Filters -------- -The following filters have been added: - - |-------------|-------------------------------------------------------------------| - | API | Description | - |-------------|-------------------------------------------------------------------| - | ma_biquad | Biquad filter (transposed direct form 2) | - | ma_lpf1 | First order low-pass filter | - | ma_lpf2 | Second order low-pass filter | - | ma_lpf | High order low-pass filter (Butterworth) | - | ma_hpf1 | First order high-pass filter | - | ma_hpf2 | Second order high-pass filter | - | ma_hpf | High order high-pass filter (Butterworth) | - | ma_bpf2 | Second order band-pass filter | - | ma_bpf | High order band-pass filter | - | ma_peak2 | Second order peaking filter | - | ma_notch2 | Second order notching filter | - | ma_loshelf2 | Second order low shelf filter | - | ma_hishelf2 | Second order high shelf filter | - |-------------|-------------------------------------------------------------------| - -These filters all support 32-bit floating point and 16-bit signed integer formats natively. Other formats need to be converted beforehand. - - -Sine, Square, Triangle and Sawtooth Waveforms ---------------------------------------------- -Previously miniaudio supported only sine wave generation. This has now been generalized to support sine, square, triangle and sawtooth waveforms. The old -`ma_sine_wave` API has been removed and replaced with the `ma_waveform` API. Use `ma_waveform_config_init()` to initialize a config object, and then pass it -into `ma_waveform_init()`. Then use `ma_waveform_read_pcm_frames()` to read PCM data. - - -Noise Generation ----------------- -A noise generation API has been added. This is used via the `ma_noise` API. Currently white, pink and Brownian noise is supported. The `ma_noise` API is -similar to the waveform API. Use `ma_noise_config_init()` to initialize a config object, and then pass it into `ma_noise_init()` to initialize a `ma_noise` -object. Then use `ma_noise_read_pcm_frames()` to read PCM data. - - -Miscellaneous Changes ---------------------- -The MA_NO_STDIO option has been removed. This would disable file I/O APIs, however this has proven to be too hard to maintain for it's perceived value and was -therefore removed. - -Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report. - -The `ma_device` structure is no longer defined as being aligned to MA_SIMD_ALIGNMENT. This resulted in a possible crash when allocating a `ma_device` object on -the heap, but not aligning it to MA_SIMD_ALIGNMENT. This crash would happen due to the compiler seeing the alignment specified on the structure and assuming it -was always aligned as such and thinking it was safe to emit alignment-dependant SIMD instructions. Since miniaudio's philosophy is for things to just work, -this has been removed from all structures. - -Results codes have been overhauled. Unnecessary result codes have been removed, and some have been renumbered for organisation purposes. If you are are binding -maintainer you will need to update your result codes. Support has also been added for retrieving a human readable description of a given result code via the -`ma_result_description()` API. - -ALSA: The automatic format conversion, channel conversion and resampling performed by ALSA is now disabled by default as they were causing some compatibility -issues with certain devices and configurations. These can be individually enabled via the device config: - - ```c - deviceConfig.alsa.noAutoFormat = MA_TRUE; - deviceConfig.alsa.noAutoChannels = MA_TRUE; - deviceConfig.alsa.noAutoResample = MA_TRUE; - ``` -*/ - -/* -RELEASE NOTES - VERSION 0.9.x -============================= -Version 0.9 includes major API changes, centered mostly around full-duplex and the rebrand to "miniaudio". Before I go into detail about the major changes I -would like to apologize. I know it's annoying dealing with breaking API changes, but I think it's best to get these changes out of the way now while the -library is still relatively young and unknown. - -There's been a lot of refactoring with this release so there's a good chance a few bugs have been introduced. I apologize in advance for this. You may want to -hold off on upgrading for the short term if you're worried. If mini_al v0.8.14 works for you, and you don't need full-duplex support, you can avoid upgrading -(though you won't be getting future bug fixes). - - -Rebranding to "miniaudio" -------------------------- -The decision was made to rename mini_al to miniaudio. Don't worry, it's the same project. The reason for this is simple: - -1) Having the word "audio" in the title makes it immediately clear that the library is related to audio; and -2) I don't like the look of the underscore. - -This rebrand has necessitated a change in namespace from "mal" to "ma". I know this is annoying, and I apologize, but it's better to get this out of the road -now rather than later. Also, since there are necessary API changes for full-duplex support I think it's better to just get the namespace change over and done -with at the same time as the full-duplex changes. I'm hoping this will be the last of the major API changes. Fingers crossed! - -The implementation define is now "#define MINIAUDIO_IMPLEMENTATION". You can also use "#define MA_IMPLEMENTATION" if that's your preference. - - -Full-Duplex Support -------------------- -The major feature added to version 0.9 is full-duplex. This has necessitated a few API changes. - -1) The data callback has now changed. Previously there was one type of callback for playback and another for capture. I wanted to avoid a third callback just - for full-duplex so the decision was made to break this API and unify the callbacks. Now, there is just one callback which is the same for all three modes - (playback, capture, duplex). The new callback looks like the following: - - void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - - This callback allows you to move data straight out of the input buffer and into the output buffer in full-duplex mode. In playback-only mode, pInput will be - null. Likewise, pOutput will be null in capture-only mode. The sample count is no longer returned from the callback since it's not necessary for miniaudio - anymore. - -2) The device config needed to change in order to support full-duplex. Full-duplex requires the ability to allow the client to choose a different PCM format - for the playback and capture sides. The old ma_device_config object simply did not allow this and needed to change. With these changes you now specify the - device ID, format, channels, channel map and share mode on a per-playback and per-capture basis (see example below). The sample rate must be the same for - playback and capture. - - Since the device config API has changed I have also decided to take the opportunity to simplify device initialization. Now, the device ID, device type and - callback user data are set in the config. ma_device_init() is now simplified down to taking just the context, device config and a pointer to the device - object being initialized. The rationale for this change is that it just makes more sense to me that these are set as part of the config like everything - else. - - Example device initialization: - - ma_device_config config = ma_device_config_init(ma_device_type_duplex); // Or ma_device_type_playback or ma_device_type_capture. - config.playback.pDeviceID = &myPlaybackDeviceID; // Or NULL for the default playback device. - config.playback.format = ma_format_f32; - config.playback.channels = 2; - config.capture.pDeviceID = &myCaptureDeviceID; // Or NULL for the default capture device. - config.capture.format = ma_format_s16; - config.capture.channels = 1; - config.sampleRate = 44100; - config.dataCallback = data_callback; - config.pUserData = &myUserData; - - result = ma_device_init(&myContext, &config, &device); - if (result != MA_SUCCESS) { - ... handle error ... - } - - Note that the "onDataCallback" member of ma_device_config has been renamed to "dataCallback". Also, "onStopCallback" has been renamed to "stopCallback". - -This is the first pass for full-duplex and there is a known bug. You will hear crackling on the following backends when sample rate conversion is required for -the playback device: - - Core Audio - - JACK - - AAudio - - OpenSL - - WebAudio - -In addition to the above, not all platforms have been absolutely thoroughly tested simply because I lack the hardware for such thorough testing. If you -experience a bug, an issue report on GitHub or an email would be greatly appreciated (and a sample program that reproduces the issue if possible). - - -Other API Changes ------------------ -In addition to the above, the following API changes have been made: - -- The log callback is no longer passed to ma_context_config_init(). Instead you need to set it manually after initialization. -- The onLogCallback member of ma_context_config has been renamed to "logCallback". -- The log callback now takes a logLevel parameter. The new callback looks like: void log_callback(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) - - You can use ma_log_level_to_string() to convert the logLevel to human readable text if you want to log it. -- Some APIs have been renamed: - - mal_decoder_read() -> ma_decoder_read_pcm_frames() - - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame() - - mal_sine_wave_read() -> ma_sine_wave_read_f32() - - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex() -- Some APIs have been removed: - - mal_device_get_buffer_size_in_bytes() - - mal_device_set_recv_callback() - - mal_device_set_send_callback() - - mal_src_set_input_sample_rate() - - mal_src_set_output_sample_rate() -- Error codes have been rearranged. If you're a binding maintainer you will need to update. -- The ma_backend enums have been rearranged to priority order. The rationale for this is to simplify automatic backend selection and to make it easier to see - the priority. If you're a binding maintainer you will need to update. -- ma_dsp has been renamed to ma_pcm_converter. The rationale for this change is that I'm expecting "ma_dsp" to conflict with some future planned high-level - APIs. -- For functions that take a pointer/count combo, such as ma_decoder_read_pcm_frames(), the parameter order has changed so that the pointer comes before the - count. The rationale for this is to keep it consistent with things like memcpy(). - - -Miscellaneous Changes ---------------------- -The following miscellaneous changes have also been made. - -- The AAudio backend has been added for Android 8 and above. This is Android's new "High-Performance Audio" API. (For the record, this is one of the nicest - audio APIs out there, just behind the BSD audio APIs). -- The WebAudio backend has been added. This is based on ScriptProcessorNode. This removes the need for SDL. -- The SDL and OpenAL backends have been removed. These were originally implemented to add support for platforms for which miniaudio was not explicitly - supported. These are no longer needed and have therefore been removed. -- Device initialization now fails if the requested share mode is not supported. If you ask for exclusive mode, you either get an exclusive mode device, or an - error. The rationale for this change is to give the client more control over how to handle cases when the desired shared mode is unavailable. -- A lock-free ring buffer API has been added. There are two varients of this. "ma_rb" operates on bytes, whereas "ma_pcm_rb" operates on PCM frames. -- The library is now licensed as a choice of Public Domain (Unlicense) _or_ MIT-0 (No Attribution) which is the same as MIT, but removes the attribution - requirement. The rationale for this is to support countries that don't recognize public domain. -*/ - -/* -REVISION HISTORY -================ -v0.10.42 - 2021-08-22 - - Fix a possible deadlock when stopping devices. - -v0.10.41 - 2021-08-15 - - Core Audio: Fix some deadlock errors. - -v0.10.40 - 2021-07-23 - - Fix a bug when converting from stereo to mono. - - PulseAudio: Fix a glitch when pausing and resuming a device. - -v0.10.39 - 2021-07-20 - - Core Audio: Fix a deadlock when the default device is changed. - - Core Audio: Fix compilation errors on macOS and iOS. - - PulseAudio: Fix a bug where the stop callback is not fired when a device is unplugged. - - PulseAudio: Fix a null pointer dereference. - -v0.10.38 - 2021-07-14 - - Fix a linking error when MA_DEBUG_OUTPUT is not enabled. - - Fix an error where ma_log_postv() does not return a value. - - OpenSL: Fix a bug with setting of stream types and recording presets. - -0.10.37 - 2021-07-06 - - Fix a bug with log message formatting. - - Fix build when compiling with MA_NO_THREADING. - - Minor updates to channel mapping. - -0.10.36 - 2021-07-03 - - Add support for custom decoding backends. - - Fix some bugs with the Vorbis decoder. - - PulseAudio: Fix a bug with channel mapping. - - PulseAudio: Fix a bug where miniaudio does not fall back to a supported format when PulseAudio - defaults to a format not known to miniaudio. - - OpenSL: Fix a crash when initializing a capture device when a recording preset other than the - default is specified. - - Silence some warnings when compiling with MA_DEBUG_OUTPUT - - Improvements to logging. See the `ma_log` API for details. The logCallback variable used by - ma_context has been deprecated and will be replaced with the new system in version 0.11. - - Initialize an `ma_log` object with `ma_log_init()`. - - Register a callback with `ma_log_register_callback()`. - - In the context config, set `pLog` to your `ma_log` object and stop using `logCallback`. - - Prep work for some upcoming changes to data sources. These changes are still compatible with - existing code, however code will need to be updated in preparation for version 0.11 which will - be breaking. You should make these changes now for any custom data sources: - - Change your base data source object from `ma_data_source_callbacks` to `ma_data_source_base`. - - Call `ma_data_source_init()` for your base object in your custom data source's initialization - routine. This takes a config object which includes a pointer to a vtable which is now where - your custom callbacks are defined. - - Call `ma_data_source_uninit()` in your custom data source's uninitialization routine. This - doesn't currently do anything, but it placeholder in case some future uninitialization code - is required to be added at a later date. - -v0.10.35 - 2021-04-27 - - Fix the C++ build. - -v0.10.34 - 2021-04-26 - - WASAPI: Fix a bug where a result code is not getting checked at initialization time. - - WASAPI: Bug fixes for loopback mode. - - ALSA: Fix a possible deadlock when stopping devices. - - Mark devices as default on the null backend. - -v0.10.33 - 2021-04-04 - - Core Audio: Fix a memory leak. - - Core Audio: Fix a bug where the performance profile is not being used by playback devices. - - JACK: Fix loading of 64-bit JACK on Windows. - - Fix a calculation error and add a safety check to the following APIs to prevent a division by zero: - - ma_calculate_buffer_size_in_milliseconds_from_frames() - - ma_calculate_buffer_size_in_frames_from_milliseconds() - - Fix compilation errors relating to c89atomic. - - Update FLAC decoder. - -v0.10.32 - 2021-02-23 - - WASAPI: Fix a deadlock in exclusive mode. - - WASAPI: No longer return an error from ma_context_get_device_info() when an exclusive mode format - cannot be retrieved. - - WASAPI: Attempt to fix some bugs with device uninitialization. - - PulseAudio: Yet another refactor, this time to remove the dependency on `pa_threaded_mainloop`. - - Web Audio: Fix a bug on Chrome and any other browser using the same engine. - - Web Audio: Automatically start the device on some user input if the device has been started. This - is to work around Google's policy of not starting audio if no user input has yet been performed. - - Fix a bug where thread handles are not being freed. - - Fix some static analysis warnings in FLAC, WAV and MP3 decoders. - - Fix a warning due to referencing _MSC_VER when it is undefined. - - Update to latest version of c89atomic. - - Internal refactoring to migrate over to the new backend callback system for the following backends: - - PulseAudio - - ALSA - - Core Audio - - AAudio - - OpenSL|ES - - OSS - - audio(4) - - sndio - -v0.10.31 - 2021-01-17 - - Make some functions const correct. - - Update ma_data_source_read_pcm_frames() to initialize pFramesRead to 0 for safety. - - Add the MA_ATOMIC annotation for use with variables that should be used atomically and remove unnecessary volatile qualifiers. - - Add support for enabling only specific backends at compile time. This is the reverse of the pre-existing system. With the new - system, all backends are first disabled with `MA_ENABLE_ONLY_SPECIFIC_BACKENDS`, which is then followed with `MA_ENABLE_*`. The - old system where you disable backends with `MA_NO_*` still exists and is still the default. - -v0.10.30 - 2021-01-10 - - Fix a crash in ma_audio_buffer_read_pcm_frames(). - - Update spinlock APIs to take a volatile parameter as input. - - Silence some unused parameter warnings. - - Fix a warning on GCC when compiling as C++. - -v0.10.29 - 2020-12-26 - - Fix some subtle multi-threading bugs on non-x86 platforms. - - Fix a bug resulting in superfluous memory allocations when enumerating devices. - - Core Audio: Fix a compilation error when compiling for iOS. - -v0.10.28 - 2020-12-16 - - Fix a crash when initializing a POSIX thread. - - OpenSL|ES: Respect the MA_NO_RUNTIME_LINKING option. - -v0.10.27 - 2020-12-04 - - Add support for dynamically configuring some properties of `ma_noise` objects post-initialization. - - Add support for configuring the channel mixing mode in the device config. - - Fix a bug with simple channel mixing mode (drop or silence excess channels). - - Fix some bugs with trying to access uninitialized variables. - - Fix some errors with stopping devices for synchronous backends where the backend's stop callback would get fired twice. - - Fix a bug in the decoder due to using an uninitialized variable. - - Fix some data race errors. - -v0.10.26 - 2020-11-24 - - WASAPI: Fix a bug where the exclusive mode format may not be retrieved correctly due to accessing freed memory. - - Fix a bug with ma_waveform where glitching occurs after changing frequency. - - Fix compilation with OpenWatcom. - - Fix compilation with TCC. - - Fix compilation with Digital Mars. - - Fix compilation warnings. - - Remove bitfields from public structures to aid in binding maintenance. - -v0.10.25 - 2020-11-15 - - PulseAudio: Fix a bug where the stop callback isn't fired. - - WebAudio: Fix an error that occurs when Emscripten increases the size of it's heap. - - Custom Backends: Change the onContextInit and onDeviceInit callbacks to take a parameter which is a pointer to the config that was - passed into ma_context_init() and ma_device_init(). This replaces the deviceType parameter of onDeviceInit. - - Fix compilation warnings on older versions of GCC. - -v0.10.24 - 2020-11-10 - - Fix a bug where initialization of a backend can fail due to some bad state being set from a prior failed attempt at initializing a - lower priority backend. - -v0.10.23 - 2020-11-09 - - AAudio: Add support for configuring a playback stream's usage. - - Fix a compilation error when all built-in asynchronous backends are disabled at compile time. - - Fix compilation errors when compiling as C++. - -v0.10.22 - 2020-11-08 - - Add support for custom backends. - - Add support for detecting default devices during device enumeration and with `ma_context_get_device_info()`. - - Refactor to the PulseAudio backend. This simplifies the implementation and fixes a capture bug. - - ALSA: Fix a bug in `ma_context_get_device_info()` where the PCM handle is left open in the event of an error. - - Core Audio: Further improvements to sample rate selection. - - Core Audio: Fix some bugs with capture mode. - - OpenSL: Add support for configuring stream types and recording presets. - - AAudio: Add support for configuring content types and input presets. - - Fix bugs in `ma_decoder_init_file*()` where the file handle is not closed after a decoding error. - - Fix some compilation warnings on GCC and Clang relating to the Speex resampler. - - Fix a compilation error for the Linux build when the ALSA and JACK backends are both disabled. - - Fix a compilation error for the BSD build. - - Fix some compilation errors on older versions of GCC. - - Add documentation for `MA_NO_RUNTIME_LINKING`. - -v0.10.21 - 2020-10-30 - - Add ma_is_backend_enabled() and ma_get_enabled_backends() for retrieving enabled backends at run-time. - - WASAPI: Fix a copy and paste bug relating to loopback mode. - - Core Audio: Fix a bug when using multiple contexts. - - Core Audio: Fix a compilation warning. - - Core Audio: Improvements to sample rate selection. - - Core Audio: Improvements to format/channels/rate selection when requesting defaults. - - Core Audio: Add notes regarding the Apple notarization process. - - Fix some bugs due to null pointer dereferences. - -v0.10.20 - 2020-10-06 - - Fix build errors with UWP. - - Minor documentation updates. - -v0.10.19 - 2020-09-22 - - WASAPI: Return an error when exclusive mode is requested, but the native format is not supported by miniaudio. - - Fix a bug where ma_decoder_seek_to_pcm_frames() never returns MA_SUCCESS even though it was successful. - - Store the sample rate in the `ma_lpf` and `ma_hpf` structures. - -v0.10.18 - 2020-08-30 - - Fix build errors with VC6. - - Fix a bug in channel converter for s32 format. - - Change channel converter configs to use the default channel map instead of a blank channel map when no channel map is specified when initializing the - config. This fixes an issue where the optimized mono expansion path would never get used. - - Use a more appropriate default format for FLAC decoders. This will now use ma_format_s16 when the FLAC is encoded as 16-bit. - - Update FLAC decoder. - - Update links to point to the new repository location (https://github.com/mackron/miniaudio). - -v0.10.17 - 2020-08-28 - - Fix an error where the WAV codec is incorrectly excluded from the build depending on which compile time options are set. - - Fix a bug in ma_audio_buffer_read_pcm_frames() where it isn't returning the correct number of frames processed. - - Fix compilation error on Android. - - Core Audio: Fix a bug with full-duplex mode. - - Add ma_decoder_get_cursor_in_pcm_frames(). - - Update WAV codec. - -v0.10.16 - 2020-08-14 - - WASAPI: Fix a potential crash due to using an uninitialized variable. - - OpenSL: Enable runtime linking. - - OpenSL: Fix a multithreading bug when initializing and uninitializing multiple contexts at the same time. - - iOS: Improvements to device enumeration. - - Fix a crash in ma_data_source_read_pcm_frames() when the output frame count parameter is NULL. - - Fix a bug in ma_data_source_read_pcm_frames() where looping doesn't work. - - Fix some compilation warnings on Windows when both DirectSound and WinMM are disabled. - - Fix some compilation warnings when no decoders are enabled. - - Add ma_audio_buffer_get_available_frames(). - - Add ma_decoder_get_available_frames(). - - Add sample rate to ma_data_source_get_data_format(). - - Change volume APIs to take 64-bit frame counts. - - Updates to documentation. - -v0.10.15 - 2020-07-15 - - Fix a bug when converting bit-masked channel maps to miniaudio channel maps. This affects the WASAPI and OpenSL backends. - -v0.10.14 - 2020-07-14 - - Fix compilation errors on Android. - - Fix compilation errors with -march=armv6. - - Updates to the documentation. - -v0.10.13 - 2020-07-11 - - Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS. - - Fix compilation error on Emscripten. - - Silence some unused function warnings. - - Increase the default buffer size on the Web Audio backend. This fixes glitching issues on some browsers. - - Bring FLAC decoder up-to-date with dr_flac. - - Bring MP3 decoder up-to-date with dr_mp3. - -v0.10.12 - 2020-07-04 - - Fix compilation errors on the iOS build. - -v0.10.11 - 2020-06-28 - - Fix some bugs with device tracking on Core Audio. - - Updates to documentation. - -v0.10.10 - 2020-06-26 - - Add include guard for the implementation section. - - Mark ma_device_sink_info_callback() as static. - - Fix compilation errors with MA_NO_DECODING and MA_NO_ENCODING. - - Fix compilation errors with MA_NO_DEVICE_IO - -v0.10.9 - 2020-06-24 - - Amalgamation of dr_wav, dr_flac and dr_mp3. With this change, including the header section of these libraries before the implementation of miniaudio is no - longer required. Decoding of WAV, FLAC and MP3 should be supported seamlessly without any additional libraries. Decoders can be excluded from the build - with the following options: - - MA_NO_WAV - - MA_NO_FLAC - - MA_NO_MP3 - If you get errors about multiple definitions you need to either enable the options above, move the implementation of dr_wav, dr_flac and/or dr_mp3 to before - the implementation of miniaudio, or update dr_wav, dr_flac and/or dr_mp3. - - Changes to the internal atomics library. This has been replaced with c89atomic.h which is embedded within this file. - - Fix a bug when a decoding backend reports configurations outside the limits of miniaudio's decoder abstraction. - - Fix the UWP build. - - Fix the Core Audio build. - - Fix the -std=c89 build on GCC. - -v0.10.8 - 2020-06-22 - - Remove dependency on ma_context from mutexes. - - Change ma_data_source_read_pcm_frames() to return a result code and output the frames read as an output parameter. - - Change ma_data_source_seek_pcm_frames() to return a result code and output the frames seeked as an output parameter. - - Change ma_audio_buffer_unmap() to return MA_AT_END when the end has been reached. This should be considered successful. - - Change playback.pDeviceID and capture.pDeviceID to constant pointers in ma_device_config. - - Add support for initializing decoders from a virtual file system object. This is achieved via the ma_vfs API and allows the application to customize file - IO for the loading and reading of raw audio data. Passing in NULL for the VFS will use defaults. New APIs: - - ma_decoder_init_vfs() - - ma_decoder_init_vfs_wav() - - ma_decoder_init_vfs_flac() - - ma_decoder_init_vfs_mp3() - - ma_decoder_init_vfs_vorbis() - - ma_decoder_init_vfs_w() - - ma_decoder_init_vfs_wav_w() - - ma_decoder_init_vfs_flac_w() - - ma_decoder_init_vfs_mp3_w() - - ma_decoder_init_vfs_vorbis_w() - - Add support for memory mapping to ma_data_source. - - ma_data_source_map() - - ma_data_source_unmap() - - Add ma_offset_pcm_frames_ptr() and ma_offset_pcm_frames_const_ptr() which can be used for offsetting a pointer by a specified number of PCM frames. - - Add initial implementation of ma_yield() which is useful for spin locks which will be used in some upcoming work. - - Add documentation for log levels. - - The ma_event API has been made public in preparation for some uncoming work. - - Fix a bug in ma_decoder_seek_to_pcm_frame() where the internal sample rate is not being taken into account for determining the seek location. - - Fix some bugs with the linear resampler when dynamically changing the sample rate. - - Fix compilation errors with MA_NO_DEVICE_IO. - - Fix some warnings with GCC and -std=c89. - - Fix some formatting warnings with GCC and -Wall and -Wpedantic. - - Fix some warnings with VC6. - - Minor optimization to ma_copy_pcm_frames(). This is now a no-op when the input and output buffers are the same. - -v0.10.7 - 2020-05-25 - - Fix a compilation error in the C++ build. - - Silence a warning. - -v0.10.6 - 2020-05-24 - - Change ma_clip_samples_f32() and ma_clip_pcm_frames_f32() to take a 64-bit sample/frame count. - - Change ma_zero_pcm_frames() to clear to 128 for ma_format_u8. - - Add ma_silence_pcm_frames() which replaces ma_zero_pcm_frames(). ma_zero_pcm_frames() will be removed in version 0.11. - - Add support for u8, s24 and s32 formats to ma_channel_converter. - - Add compile-time and run-time version querying. - - MA_VERSION_MINOR - - MA_VERSION_MAJOR - - MA_VERSION_REVISION - - MA_VERSION_STRING - - ma_version() - - ma_version_string() - - Add ma_audio_buffer for reading raw audio data directly from memory. - - Fix a bug in shuffle mode in ma_channel_converter. - - Fix compilation errors in certain configurations for ALSA and PulseAudio. - - The data callback now initializes the output buffer to 128 when the playback sample format is ma_format_u8. - -v0.10.5 - 2020-05-05 - - Change ma_zero_pcm_frames() to take a 64-bit frame count. - - Add ma_copy_pcm_frames(). - - Add MA_NO_GENERATION build option to exclude the `ma_waveform` and `ma_noise` APIs from the build. - - Add support for formatted logging to the VC6 build. - - Fix a crash in the linear resampler when LPF order is 0. - - Fix compilation errors and warnings with older versions of Visual Studio. - - Minor documentation updates. - -v0.10.4 - 2020-04-12 - - Fix a data conversion bug when converting from the client format to the native device format. - -v0.10.3 - 2020-04-07 - - Bring up to date with breaking changes to dr_mp3. - - Remove MA_NO_STDIO. This was causing compilation errors and the maintenance cost versus practical benefit is no longer worthwhile. - - Fix a bug with data conversion where it was unnecessarily converting to s16 or f32 and then straight back to the original format. - - Fix compilation errors and warnings with Visual Studio 2005. - - ALSA: Disable ALSA's automatic data conversion by default and add configuration options to the device config: - - alsa.noAutoFormat - - alsa.noAutoChannels - - alsa.noAutoResample - - WASAPI: Add some overrun recovery for ma_device_type_capture devices. - -v0.10.2 - 2020-03-22 - - Decorate some APIs with MA_API which were missed in the previous version. - - Fix a bug in ma_linear_resampler_set_rate() and ma_linear_resampler_set_rate_ratio(). - -v0.10.1 - 2020-03-17 - - Add MA_API decoration. This can be customized by defining it before including miniaudio.h. - - Fix a bug where opening a file would return a success code when in fact it failed. - - Fix compilation errors with Visual Studio 6 and 2003. - - Fix warnings on macOS. - -v0.10.0 - 2020-03-07 - - API CHANGE: Refactor data conversion APIs - - ma_format_converter has been removed. Use ma_convert_pcm_frames_format() instead. - - ma_channel_router has been replaced with ma_channel_converter. - - ma_src has been replaced with ma_resampler - - ma_pcm_converter has been replaced with ma_data_converter - - API CHANGE: Add support for custom memory allocation callbacks. The following APIs have been updated to take an extra parameter for the allocation - callbacks: - - ma_malloc() - - ma_realloc() - - ma_free() - - ma_aligned_malloc() - - ma_aligned_free() - - ma_rb_init() / ma_rb_init_ex() - - ma_pcm_rb_init() / ma_pcm_rb_init_ex() - - API CHANGE: Simplify latency specification in device configurations. The bufferSizeInFrames and bufferSizeInMilliseconds parameters have been replaced with - periodSizeInFrames and periodSizeInMilliseconds respectively. The previous variables defined the size of the entire buffer, whereas the new ones define the - size of a period. The following APIs have been removed since they are no longer relevant: - - ma_get_default_buffer_size_in_milliseconds() - - ma_get_default_buffer_size_in_frames() - - API CHANGE: ma_device_set_stop_callback() has been removed. If you require a stop callback, you must now set it via the device config just like the data - callback. - - API CHANGE: The ma_sine_wave API has been replaced with ma_waveform. The following APIs have been removed: - - ma_sine_wave_init() - - ma_sine_wave_read_f32() - - ma_sine_wave_read_f32_ex() - - API CHANGE: ma_convert_frames() has been updated to take an extra parameter which is the size of the output buffer in PCM frames. Parameters have also been - reordered. - - API CHANGE: ma_convert_frames_ex() has been changed to take a pointer to a ma_data_converter_config object to specify the input and output formats to - convert between. - - API CHANGE: ma_calculate_frame_count_after_src() has been renamed to ma_calculate_frame_count_after_resampling(). - - Add support for the following filters: - - Biquad (ma_biquad) - - First order low-pass (ma_lpf1) - - Second order low-pass (ma_lpf2) - - Low-pass with configurable order (ma_lpf) - - First order high-pass (ma_hpf1) - - Second order high-pass (ma_hpf2) - - High-pass with configurable order (ma_hpf) - - Second order band-pass (ma_bpf2) - - Band-pass with configurable order (ma_bpf) - - Second order peaking EQ (ma_peak2) - - Second order notching (ma_notch2) - - Second order low shelf (ma_loshelf2) - - Second order high shelf (ma_hishelf2) - - Add waveform generation API (ma_waveform) with support for the following: - - Sine - - Square - - Triangle - - Sawtooth - - Add noise generation API (ma_noise) with support for the following: - - White - - Pink - - Brownian - - Add encoding API (ma_encoder). This only supports outputting to WAV files via dr_wav. - - Add ma_result_description() which is used to retrieve a human readable description of a given result code. - - Result codes have been changed. Binding maintainers will need to update their result code constants. - - More meaningful result codes are now returned when a file fails to open. - - Internal functions have all been made static where possible. - - Fix potential crash when ma_device object's are not aligned to MA_SIMD_ALIGNMENT. - - Fix a bug in ma_decoder_get_length_in_pcm_frames() where it was returning the length based on the internal sample rate rather than the output sample rate. - - Fix bugs in some backends where the device is not drained properly in ma_device_stop(). - - Improvements to documentation. - -v0.9.10 - 2020-01-15 - - Fix compilation errors due to #if/#endif mismatches. - - WASAPI: Fix a bug where automatic stream routing is being performed for devices that are initialized with an explicit device ID. - - iOS: Fix a crash on device uninitialization. - -v0.9.9 - 2020-01-09 - - Fix compilation errors with MinGW. - - Fix compilation errors when compiling on Apple platforms. - - WASAPI: Add support for disabling hardware offloading. - - WASAPI: Add support for disabling automatic stream routing. - - Core Audio: Fix bugs in the case where the internal device uses deinterleaved buffers. - - Core Audio: Add support for controlling the session category (AVAudioSessionCategory) and options (AVAudioSessionCategoryOptions). - - JACK: Fix bug where incorrect ports are connected. - -v0.9.8 - 2019-10-07 - - WASAPI: Fix a potential deadlock when starting a full-duplex device. - - WASAPI: Enable automatic resampling by default. Disable with config.wasapi.noAutoConvertSRC. - - Core Audio: Fix bugs with automatic stream routing. - - Add support for controlling whether or not the content of the output buffer passed in to the data callback is pre-initialized - to zero. By default it will be initialized to zero, but this can be changed by setting noPreZeroedOutputBuffer in the device - config. Setting noPreZeroedOutputBuffer to true will leave the contents undefined. - - Add support for clipping samples after the data callback has returned. This only applies when the playback sample format is - configured as ma_format_f32. If you are doing clipping yourself, you can disable this overhead by setting noClip to true in - the device config. - - Add support for master volume control for devices. - - Use ma_device_set_master_volume() to set the volume to a factor between 0 and 1, where 0 is silence and 1 is full volume. - - Use ma_device_set_master_gain_db() to set the volume in decibels where 0 is full volume and < 0 reduces the volume. - - Fix warnings emitted by GCC when `__inline__` is undefined or defined as nothing. - -v0.9.7 - 2019-08-28 - - Add support for loopback mode (WASAPI only). - - To use this, set the device type to ma_device_type_loopback, and then fill out the capture section of the device config. - - If you need to capture from a specific output device, set the capture device ID to that of a playback device. - - Fix a crash when an error is posted in ma_device_init(). - - Fix a compilation error when compiling for ARM architectures. - - Fix a bug with the audio(4) backend where the device is incorrectly being opened in non-blocking mode. - - Fix memory leaks in the Core Audio backend. - - Minor refactoring to the WinMM, ALSA, PulseAudio, OSS, audio(4), sndio and null backends. - -v0.9.6 - 2019-08-04 - - Add support for loading decoders using a wchar_t string for file paths. - - Don't trigger an assert when ma_device_start() is called on a device that is already started. This will now log a warning - and return MA_INVALID_OPERATION. The same applies for ma_device_stop(). - - Try fixing an issue with PulseAudio taking a long time to start playback. - - Fix a bug in ma_convert_frames() and ma_convert_frames_ex(). - - Fix memory leaks in the WASAPI backend. - - Fix a compilation error with Visual Studio 2010. - -v0.9.5 - 2019-05-21 - - Add logging to ma_dlopen() and ma_dlsym(). - - Add ma_decoder_get_length_in_pcm_frames(). - - Fix a bug with capture on the OpenSL|ES backend. - - Fix a bug with the ALSA backend where a device would not restart after being stopped. - -v0.9.4 - 2019-05-06 - - Add support for C89. With this change, miniaudio should compile clean with GCC/Clang with "-std=c89 -ansi -pedantic" and - Microsoft compilers back to VC6. Other compilers should also work, but have not been tested. - -v0.9.3 - 2019-04-19 - - Fix compiler errors on GCC when compiling with -std=c99. - -v0.9.2 - 2019-04-08 - - Add support for per-context user data. - - Fix a potential bug with context configs. - - Fix some bugs with PulseAudio. - -v0.9.1 - 2019-03-17 - - Fix a bug where the output buffer is not getting zeroed out before calling the data callback. This happens when - the device is running in passthrough mode (not doing any data conversion). - - Fix an issue where the data callback is getting called too frequently on the WASAPI and DirectSound backends. - - Fix error on the UWP build. - - Fix a build error on Apple platforms. - -v0.9 - 2019-03-06 - - Rebranded to "miniaudio". All namespaces have been renamed from "mal" to "ma". - - API CHANGE: ma_device_init() and ma_device_config_init() have changed significantly: - - The device type, device ID and user data pointer have moved from ma_device_init() to the config. - - All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init(). - - ma_device_config_init() now takes only one parameter which is the device type. All other properties need - to be set on the returned object directly. - - The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback" - and "stopCallback". - - The ID of the physical device is now split into two: one for the playback device and the other for the - capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID". - - API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than - being separate for each. It now takes two pointers - one containing input data and the other output data. This - design in required for full-duplex. The return value is now void instead of the number of frames written. The - new callback looks like the following: - void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - - API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change, - ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The - new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The - "onLog" member of ma_context_config has been renamed to "logCallback". - - API CHANGE: Remove ma_device_get_buffer_size_in_bytes(). - - API CHANGE: Rename decoding APIs to "pcm_frames" convention. - - mal_decoder_read() -> ma_decoder_read_pcm_frames() - - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame() - - API CHANGE: Rename sine wave reading APIs to f32 convention. - - mal_sine_wave_read() -> ma_sine_wave_read_f32() - - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex() - - API CHANGE: Remove some deprecated APIs - - mal_device_set_recv_callback() - - mal_device_set_send_callback() - - mal_src_set_input_sample_rate() - - mal_src_set_output_sample_rate() - - API CHANGE: Add log level to the log callback. New signature: - - void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) - - API CHANGE: Changes to result codes. Constants have changed and unused codes have been removed. If you're - a binding mainainer you will need to update your result code constants. - - API CHANGE: Change the order of the ma_backend enums to priority order. If you are a binding maintainer, you - will need to update. - - API CHANGE: Rename mal_dsp to ma_pcm_converter. All functions have been renamed from mal_dsp_*() to - ma_pcm_converter_*(). All structures have been renamed from mal_dsp* to ma_pcm_converter*. - - API CHANGE: Reorder parameters of ma_decoder_read_pcm_frames() to be consistent with the new parameter order scheme. - - The resampling algorithm has been changed from sinc to linear. The rationale for this is that the sinc implementation - is too inefficient right now. This will hopefully be improved at a later date. - - Device initialization will no longer fall back to shared mode if exclusive mode is requested but is unusable. - With this change, if you request an device in exclusive mode, but exclusive mode is not supported, it will not - automatically fall back to shared mode. The client will need to reinitialize the device in shared mode if that's - what they want. - - Add ring buffer API. This is ma_rb and ma_pcm_rb, the difference being that ma_rb operates on bytes and - ma_pcm_rb operates on PCM frames. - - Add Web Audio backend. This is used when compiling with Emscripten. The SDL backend, which was previously - used for web support, will be removed in a future version. - - Add AAudio backend (Android Audio). This is the new priority backend for Android. Support for AAudio starts - with Android 8. OpenSL|ES is used as a fallback for older versions of Android. - - Remove OpenAL and SDL backends. - - Fix a possible deadlock when rapidly stopping the device after it has started. - - Update documentation. - - Change licensing to a choice of public domain _or_ MIT-0 (No Attribution). - -v0.8.14 - 2018-12-16 - - Core Audio: Fix a bug where the device state is not set correctly after stopping. - - Add support for custom weights to the channel router. - - Update decoders to use updated APIs in dr_flac, dr_mp3 and dr_wav. - -v0.8.13 - 2018-12-04 - - Core Audio: Fix a bug with channel mapping. - - Fix a bug with channel routing where the back/left and back/right channels have the wrong weight. - -v0.8.12 - 2018-11-27 - - Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2". - - Fix a linking error with ALSA. - - Fix a bug on iOS where the device name is not set correctly. - -v0.8.11 - 2018-11-21 - - iOS bug fixes. - - Minor tweaks to PulseAudio. - -v0.8.10 - 2018-10-21 - - Core Audio: Fix a hang when uninitializing a device. - - Fix a bug where an incorrect value is returned from mal_device_stop(). - -v0.8.9 - 2018-09-28 - - Fix a bug with the SDL backend where device initialization fails. - -v0.8.8 - 2018-09-14 - - Fix Linux build with the ALSA backend. - - Minor documentation fix. - -v0.8.7 - 2018-09-12 - - Fix a bug with UWP detection. - -v0.8.6 - 2018-08-26 - - Automatically switch the internal device when the default device is unplugged. Note that this is still in the - early stages and not all backends handle this the same way. As of this version, this will not detect a default - device switch when changed from the operating system's audio preferences (unless the backend itself handles - this automatically). This is not supported in exclusive mode. - - WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the - user switches the default device via the operating system's audio preferences, miniaudio will automatically switch - the internal device to the new default. This is not supported in exclusive mode. - - WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer. - - WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer. - - Add support for compiling the UWP build as C. - - mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this - when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0. - -v0.8.5 - 2018-08-12 - - Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in - frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0 - then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used. - - Add support for the audio(4) backend to OpenBSD. - - Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the - Raspberry Pi experience. - - Fix a bug where an incorrect number of samples is returned from sinc resampling. - - Add support for setting the value to be passed to internal calls to CoInitializeEx(). - - WASAPI and WinMM: Stop the device when it is unplugged. - -v0.8.4 - 2018-08-06 - - Add sndio backend for OpenBSD. - - Add audio(4) backend for NetBSD. - - Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD. - - Formats are now native-endian (were previously little-endian). - - Mark some APIs as deprecated: - - mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate(). - - mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate(). - - Fix a bug when capturing using the WASAPI backend. - - Fix some aliasing issues with resampling, specifically when increasing the sample rate. - - Fix warnings. - -v0.8.3 - 2018-07-15 - - Fix a crackling bug when resampling in capture mode. - - Core Audio: Fix a bug where capture does not work. - - ALSA: Fix a bug where the worker thread can get stuck in an infinite loop. - - PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable. - - JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable. - -v0.8.2 - 2018-07-07 - - Fix a bug on macOS with Core Audio where the internal callback is not called. - -v0.8.1 - 2018-07-06 - - Fix compilation errors and warnings. - -v0.8 - 2018-07-05 - - Changed MAL_IMPLEMENTATION to MINI_AL_IMPLEMENTATION for consistency with other libraries. The old - way is still supported for now, but you should update as it may be removed in the future. - - API CHANGE: Replace device enumeration APIs. mal_enumerate_devices() has been replaced with - mal_context_get_devices(). An additional low-level device enumration API has been introduced called - mal_context_enumerate_devices() which uses a callback to report devices. - - API CHANGE: Rename mal_get_sample_size_in_bytes() to mal_get_bytes_per_sample() and add - mal_get_bytes_per_frame(). - - API CHANGE: Replace mal_device_config.preferExclusiveMode with mal_device_config.shareMode. - - This new config can be set to mal_share_mode_shared (default) or mal_share_mode_exclusive. - - API CHANGE: Remove excludeNullDevice from mal_context_config.alsa. - - API CHANGE: Rename MAL_MAX_SAMPLE_SIZE_IN_BYTES to MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES. - - API CHANGE: Change the default channel mapping to the standard Microsoft mapping. - - API CHANGE: Remove backend-specific result codes. - - API CHANGE: Changes to the format conversion APIs (mal_pcm_f32_to_s16(), etc.) - - Add support for Core Audio (Apple). - - Add support for PulseAudio. - - This is the highest priority backend on Linux (higher priority than ALSA) since it is commonly - installed by default on many of the popular distros and offer's more seamless integration on - platforms where PulseAudio is used. In addition, if PulseAudio is installed and running (which - is extremely common), it's better to just use PulseAudio directly rather than going through the - "pulse" ALSA plugin (which is what the "default" ALSA device is likely set to). - - Add support for JACK. - - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no - longer required to build miniaudio. - - Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some - distributions of MinGW. - - Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some - distributions of MinGW. - - Add support for dithering to format conversion. - - Add support for configuring the priority of the worker thread. - - Add a sine wave generator. - - Improve efficiency of sample rate conversion. - - Introduce the notion of standard channel maps. Use mal_get_standard_channel_map(). - - Introduce the notion of default device configurations. A default config uses the same configuration - as the backend's internal device, and as such results in a pass-through data transmission pipeline. - - Add support for passing in NULL for the device config in mal_device_init(), which uses a default - config. This requires manually calling mal_device_set_send/recv_callback(). - - Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.) - - Make mal_device_init_ex() more robust. - - Make some APIs more const-correct. - - Fix errors with SDL detection on Apple platforms. - - Fix errors with OpenAL detection. - - Fix some memory leaks. - - Fix a bug with opening decoders from memory. - - Early work on SSE2, AVX2 and NEON optimizations. - - Miscellaneous bug fixes. - - Documentation updates. - -v0.7 - 2018-02-25 - - API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts. - - Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files. - - Allow opening of devices without a context. - - In this case the context is created and managed internally by the device. - - Change the default channel mapping to the same as that used by FLAC. - - Fix build errors with macOS. - -v0.6c - 2018-02-12 - - Fix build errors with BSD/OSS. - -v0.6b - 2018-02-03 - - Fix some warnings when compiling with Visual C++. - -v0.6a - 2018-01-26 - - Fix errors with channel mixing when increasing the channel count. - - Improvements to the build system for the OpenAL backend. - - Documentation fixes. - -v0.6 - 2017-12-08 - - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll - need to update. - - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively. - - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent. - - Add support for SDL and Emscripten. - - Simplify the build system further for when development packages for various backends are not installed. - With this change, when the compiler supports __has_include, backends without the relevant development - packages installed will be ignored. This fixes the build for old versions of MinGW. - - Fixes to the Android build. - - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of - audio data to a different format. - - Improvements to f32 -> u8/s16/s24/s32 conversion routines. - - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend. - - Fixes and improvements for Raspberry Pi. - - Warning fixes. - -v0.5 - 2017-11-11 - - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for - configuring the context. The works in the same kind of way as the device config. The rationale for this - change is to give applications better control over context-level properties, add support for backend- - specific configurations, and support extensibility without breaking the API. - - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for - anything anymore. - - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications - can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config - variable. - - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If - this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now - honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above) - which is by design. - - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable. - - ALSA: Fix a bug with channel mapping which causes an assertion to fail. - - Fix errors with enumeration when pInfo is set to NULL. - - OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill. - -v0.4 - 2017-11-05 - - API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to - mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic - messages at the context level. Previously this was only available at the device level. - - API CHANGE: The device config passed to mal_device_init() is now const. - - Added support for OSS which enables support on BSD platforms. - - Added support for WinMM (waveOut/waveIn). - - Added support for UWP (Universal Windows Platform) applications. Currently C++ only. - - Added support for exclusive mode for selected backends. Currently supported on WASAPI. - - POSIX builds no longer require explicit linking to libpthread (-lpthread). - - ALSA: Explicit linking to libasound (-lasound) is no longer required. - - ALSA: Latency improvements. - - ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config. - - ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the - alsa.preferPlugHW config. - - WASAPI is now the highest priority backend on Windows platforms. - - Fixed an error with sample rate conversion which was causing crackling when capturing. - - Improved error handling. - - Improved compiler support. - - Miscellaneous bug fixes. - -v0.3 - 2017-06-19 - - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for - enumerating and creating devices. Now, applications must first create a context, and then use that to - enumerate and create devices. The reason for this change is to ensure device enumeration and creation is - tied to the same backend. In addition, some backends are better suited to this design. - - API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard - to test and maintain, and just generally unreliable. - - Added helper APIs for initializing mal_device_config objects. - - Null Backend: Fixed a crash when recording. - - Fixed build for UWP. - - Added support for f32 formats to the OpenSL|ES backend. - - Added initial implementation of the WASAPI backend. - - Added initial implementation of the OpenAL backend. - - Added support for low quality linear sample rate conversion. - - Added early support for basic channel mapping. - -v0.2 - 2016-10-28 - - API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this - change is to ensure the logging callback has access to the user data during initialization. - - API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale: - 1) The number of parameters is just getting too much. - 2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a - chance there will be support added for backend-specific properties. - - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the - added maintenance cost. - - DirectSound: Increased the default buffer size for capture devices. - - Added initial implementation of the OpenSL|ES backend. - -v0.1 - 2016-10-21 - - Initial versioned release. -*/ - /* This software is available as a choice of the following licenses. Choose diff --git a/vendor/miniaudio/synchronization.odin b/vendor/miniaudio/synchronization.odin new file mode 100644 index 000000000..7615e8f45 --- /dev/null +++ b/vendor/miniaudio/synchronization.odin @@ -0,0 +1,152 @@ +package miniaudio + +when ODIN_OS == .Windows { + foreign import lib "lib/miniaudio.lib" +} else when ODIN_OS == .Linux { + foreign import lib "lib/miniaudio.a" +} else { + foreign import lib "system:miniaudio" +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + /* + Locks a spinlock. + */ + spinlock_lock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result --- + + /* + Locks a spinlock, but does not yield() when looping. + */ + spinlock_lock_noyield :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result --- + + /* + Unlocks a spinlock. + */ + spinlock_unlock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result --- + +when NO_THREADING { + /* + Creates a mutex. + + A mutex must be created from a valid context. A mutex is initially unlocked. + */ + mutex_init :: proc(pMutex: ^mutex) -> result --- + + /* + Deletes a mutex. + */ + mutex_uninit :: proc(pMutex: ^mutex) --- + + /* + Locks a mutex with an infinite timeout. + */ + mutex_lock :: proc(pMutex: ^mutex) --- + + /* + Unlocks a mutex. + */ + mutex_unlock :: proc(pMutex: ^mutex) --- + + + /* + Initializes an auto-reset event. + */ + event_init :: proc(pEvent: ^event) -> result --- + + /* + Uninitializes an auto-reset event. + */ + event_uninit :: proc(pEvent: ^event) --- + + /* + Waits for the specified auto-reset event to become signalled. + */ + event_wait :: proc(pEvent: ^event) -> result --- + + /* + Signals the specified auto-reset event. + */ + event_signal :: proc(pEvent: ^event) -> result --- +} /* NO_THREADING */ + +} + +/* +Fence +===== +This locks while the counter is larger than 0. Counter can be incremented and decremented by any +thread, but care needs to be taken when waiting. It is possible for one thread to acquire the +fence just as another thread returns from ma_fence_wait(). + +The idea behind a fence is to allow you to wait for a group of operations to complete. When an +operation starts, the counter is incremented which locks the fence. When the operation completes, +the fence will be released which decrements the counter. ma_fence_wait() will block until the +counter hits zero. + +If threading is disabled, ma_fence_wait() will spin on the counter. +*/ +fence :: struct { + e: (struct {} when NO_THREADING else event), + counter: (u32 when NO_THREADING else struct {}), +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + fence_init :: proc(pFence: ^fence) -> result --- + fence_uninit :: proc(pFence: ^fence) --- + fence_acquire :: proc(pFence: ^fence) -> result --- /* Increment counter. */ + fence_release :: proc(pFence: ^fence) -> result --- /* Decrement counter. */ + fence_wait :: proc(pFence: ^fence) -> result --- /* Wait for counter to reach 0. */ +} + + +/* +Notification callback for asynchronous operations. +*/ +async_notification :: struct {} + +async_notification_callbacks :: struct { + onSignal: proc "c" (pNotification: ^async_notification), +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + async_notification_signal :: proc(pNotification: ^async_notification) -> result --- +} + + +/* +Simple polling notification. + +This just sets a variable when the notification has been signalled which is then polled with ma_async_notification_poll_is_signalled() +*/ +async_notification_poll :: struct { + cb: async_notification_callbacks, + signalled: b32, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + async_notification_poll_init :: proc(pNotificationPoll: ^async_notification_poll) -> result --- + async_notification_poll_is_signalled :: proc(pNotificationPoll: ^async_notification_poll) -> b32 --- +} + + +/* +Event Notification + +This uses an ma_event. If threading is disabled (MA_NO_THREADING), initialization will fail. +*/ +async_notification_event :: struct { + cb: async_notification_callbacks, + e: (struct {} when NO_THREADING else event), +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + async_notification_event_init :: proc(pNotificationEvent: ^async_notification_event) -> result --- + async_notification_event_uninit :: proc(pNotificationEvent: ^async_notification_event) -> result --- + async_notification_event_wait :: proc(pNotificationEvent: ^async_notification_event) -> result --- + async_notification_event_signal :: proc(pNotificationEvent: ^async_notification_event) -> result --- +} diff --git a/vendor/miniaudio/utilities.odin b/vendor/miniaudio/utilities.odin index 9ced019f5..791482cbf 100644 --- a/vendor/miniaudio/utilities.odin +++ b/vendor/miniaudio/utilities.odin @@ -1,5 +1,7 @@ package miniaudio +import c "core:c/libc" + when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" } else when ODIN_OS == .Linux { @@ -10,13 +12,6 @@ when ODIN_OS == .Windows { @(default_calling_convention="c", link_prefix="ma_") foreign lib { - /* - Adjust buffer size based on a scaling factor. - - This just multiplies the base size by the scaling factor, making sure it's a size of at least 1. - */ - scale_buffer_size :: proc(baseBufferSize: u32, scale: f32) -> u32 --- - /* Calculates a buffer size in milliseconds from the specified number of frames and sample rate. */ @@ -51,9 +46,14 @@ foreign lib { /* - Clips f32 samples. + Clips samples. */ - clip_samples_f32 :: proc(p: [^]f32, sampleCount: u64) --- + clip_samples_u8 :: proc(pDst: [^]u8, pSrc: [^]i16, count: u64) --- + clip_samples_s16 :: proc(pDst: [^]i16, pSrc: [^]i32, count: u64) --- + clip_samples_s24 :: proc(pDst: [^]u8, pSrc: [^]i64, count: u64) --- + clip_samples_s32 :: proc(pDst: [^]i32, pSrc: [^]i64, count: u64) --- + clip_samples_f32 :: proc(pDst, pSrc: [^]f32, count: u64) --- + clip_pcm_frames :: proc(pDst, pSrc: rawptr, frameCount: u64, format: format, channels: u32) --- /* Helper for applying a volume factor to samples. @@ -86,20 +86,26 @@ foreign lib { apply_volume_factor_pcm_frames_f32 :: proc(pFrames: [^]f32, frameCount: u64, channels: u32, factor: f32) --- apply_volume_factor_pcm_frames :: proc(pFrames: rawptr, frameCount: u64, format: format, channels: u32, factor: f32) --- + copy_and_apply_volume_factor_per_channel_f32 :: proc(pFramesOut, pFramesIn: [^]f32, frameCount: u64, channels: u32, pChannelGains: [^]f32) --- + + + ma_copy_and_apply_volume_and_clip_samples_u8 :: proc(pDst: [^]u8, pSrc: [^]i16, count: u64, volume: f32) --- + ma_copy_and_apply_volume_and_clip_samples_s16 :: proc(pDst: [^]i16, pSrc: [^]i32, count: u64, volume: f32) --- + ma_copy_and_apply_volume_and_clip_samples_s24 :: proc(pDst: [^]u8, pSrc: [^]i64, count: u64, volume: f32) --- + ma_copy_and_apply_volume_and_clip_samples_s32 :: proc(pDst: [^]i32, pSrc: [^]i64, count: u64, volume: f32) --- + ma_copy_and_apply_volume_and_clip_samples_f32 :: proc(pDst, pSrc: [^]f32, count: u64, volume: f32) --- + ma_copy_and_apply_volume_and_clip_pcm_frames :: proc(pDst, pSrc: rawptr, frameCount: u64, format: format, channels: u32, volume: f32) --- + /* Helper for converting a linear factor to gain in decibels. */ - factor_to_gain_db :: proc(factor: f32) -> f32 --- + volume_linear_to_db :: proc(factor: f32) -> f32 --- /* Helper for converting gain in decibels to a linear factor. */ - gain_db_to_factor :: proc(gain: f32) -> f32 --- -} - -zero_pcm_frames :: #force_inline proc "c" (p: rawptr, frameCount: u64, format: format, channels: u32) { - silence_pcm_frames(p, frameCount, format, channels) + volume_db_to_linear :: proc(gain: f32) -> f32 --- } offset_pcm_frames_ptr_f32 :: #force_inline proc "c" (p: [^]f32, offsetInFrames: u64, channels: u32) -> [^]f32 { @@ -109,23 +115,20 @@ offset_pcm_frames_const_ptr_f32 :: #force_inline proc "c" (p: [^]f32, offsetInFr return cast([^]f32)offset_pcm_frames_ptr(p, offsetInFrames, .f32, channels) } -clip_pcm_frames_f32 :: #force_inline proc "c" (p: [^]f32, frameCount: u64, channels: u32) { - clip_samples_f32(p, frameCount*u64(channels)) -} - data_source :: struct {} +DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT :: 0x00000001 + data_source_vtable :: struct { onRead: proc "c" (pDataSource: ^data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result, onSeek: proc "c" (pDataSource: ^data_source, frameIndex: u64) -> result, - onMap: proc "c" (pDataSource: ^data_source, ppFramesOut: ^rawptr, pFrameCount: ^u64) -> result, /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ - onUnmap: proc "c" (pDataSource: ^data_source, frameCount: u64) -> result, - onGetDataFormat: proc "c" (pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32) -> result, + onGetDataFormat: proc "c" (pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result, onGetCursor: proc "c" (pDataSource: ^data_source, pCursor: ^u64) -> result, onGetLength: proc "c" (pDataSource: ^data_source, pLength: ^u64) -> result, + onSetLooping: proc "c" (pDataSource: ^data_source, isLooping: b32) -> result, + flags: u32, } -data_source_callbacks :: data_source_vtable /* TODO: Remove ma_data_source_callbacks in version 0.11. */ data_source_get_next_proc :: proc "c" (pDataSource: ^data_source) -> ^data_source @@ -134,45 +137,43 @@ data_source_config :: struct { } data_source_base :: struct { - cb: data_source_callbacks, /* TODO: Remove this. */ - - /* Variables below are placeholder and not yet used. */ vtable: ^data_source_vtable, rangeBegInFrames: u64, - rangeEndInFrames: u64, /* Set to -1 for unranged (default). */ - loopBegInFrames: u64, /* Relative to rangeBegInFrames. */ - loopEndInFrames: u64, /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */ - pCurrent: ^data_source, /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */ - pNext: ^data_source, /* When set to NULL, onGetNext will be used. */ - onGetNext: ^data_source_get_next_proc, /* Will be used when pNext is NULL. If both are NULL, no next will be used. */ + rangeEndInFrames: u64, /* Set to -1 for unranged (default). */ + loopBegInFrames: u64, /* Relative to rangeBegInFrames. */ + loopEndInFrames: u64, /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */ + pCurrent: ^data_source, /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */ + pNext: ^data_source, /* When set to NULL, onGetNext will be used. */ + onGetNext: data_source_get_next_proc, /* Will be used when pNext is NULL. If both are NULL, no next will be used. */ + isLooping: b32, /*atomic*/ } @(default_calling_convention="c", link_prefix="ma_") foreign lib { - ma_data_source_config_init :: proc() -> data_source_config --- + data_source_config_init :: proc() -> data_source_config --- - data_source_init :: proc(pConfig: ^data_source_config, pDataSource: ^data_source) -> result --- - data_source_uninit :: proc(pDataSource: ^data_source) --- - data_source_read_pcm_frames :: proc(pDataSource: ^data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64, loop: b32) -> result --- /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ - data_source_seek_pcm_frames :: proc(pDataSource: ^data_source, frameCount: u64, pFramesSeeked: ^u64, loop: b32) -> result --- /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */ - data_source_seek_to_pcm_frame :: proc(pDataSource: ^data_source, frameIndex: u64) -> result --- - data_source_map :: proc(pDataSource: ^data_source, ppFramesOut: ^rawptr, pFrameCount: ^u64) -> result --- /* Returns MA_NOT_IMPLEMENTED if mapping is not supported. */ - data_source_unmap :: proc(pDataSource: ^data_source, frameCount: u64) -> result --- /* Returns MA_AT_END if the end has been reached. */ - data_source_get_data_format :: proc(pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32) -> result --- - data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^data_source, pCursor: ^u64) -> result --- - data_source_get_length_in_pcm_frames :: proc(pDataSource: ^data_source, pLength: ^u64) -> result --- /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ - // #if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING) - // MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames); - // MA_API void ma_data_source_get_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames); - // MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames); - // MA_API void ma_data_source_get_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames); - // MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource); - // MA_API ma_data_source* ma_data_source_get_current(ma_data_source* pDataSource); - // MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource); - // MA_API ma_data_source* ma_data_source_get_next(ma_data_source* pDataSource); - // MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext); - // MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(ma_data_source* pDataSource); - // #endif + data_source_init :: proc(pConfig: ^data_source_config, pDataSource: ^data_source) -> result --- + data_source_uninit :: proc(pDataSource: ^data_source) --- + data_source_read_pcm_frames :: proc(pDataSource: ^data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ + data_source_seek_pcm_frames :: proc(pDataSource: ^data_source, frameCount: u64, pFramesSeeked: ^u64) -> result --- /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */ + data_source_seek_to_pcm_frame :: proc(pDataSource: ^data_source, frameIndex: u64) -> result --- + data_source_get_data_format :: proc(pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- + data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^data_source, pCursor: ^u64) -> result --- + data_source_get_length_in_pcm_frames :: proc(pDataSource: ^data_source, pLength: ^u64) -> result --- /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ + data_source_get_cursor_in_seconds :: proc(pDataSource: ^data_source, pCursor: ^f32) -> result --- + data_source_get_length_in_seconds :: proc(pDataSource: ^data_source, pLength: ^f32) -> result --- + data_source_set_looping :: proc(pDataSource: ^data_source, isLooping: b32) -> result --- + data_source_is_looping :: proc(pDataSource: ^data_source) -> b32 --- + data_source_set_range_in_pcm_frames :: proc(pDataSource: ^data_source, rangeBegInFrames: u64, rangeEndInFrames: u64) -> result --- + data_source_get_range_in_pcm_frames :: proc(pDataSource: ^data_source, pRangeBegInFrames: ^u64, pRangeEndInFrames: ^u64) --- + data_source_set_loop_point_in_pcm_frames :: proc(pDataSource: ^data_source, loopBegInFrames: u64, loopEndInFrames: u64) -> result --- + data_source_get_loop_point_in_pcm_frames :: proc(pDataSource: ^data_source, pLoopBegInFrames: ^u64, pLoopEndInFrames: ^u64) --- + data_source_set_current :: proc(pDataSource: ^data_source, pCurrentDataSource: ^data_source) -> result --- + data_source_get_current :: proc(pDataSource: ^data_source) -> ^data_source --- + data_source_set_next :: proc(pDataSource: ^data_source, pNextDataSource: ^data_source) -> result --- + data_source_get_next :: proc(pDataSource: ^data_source) -> ^data_source --- + data_source_set_next_callback :: proc(pDataSource: ^data_source, onGetNext: ^data_source_get_next_proc) -> result --- + data_source_get_next_callback :: proc(pDataSource: ^data_source) -> ^data_source_get_next_proc --- } @@ -180,6 +181,7 @@ audio_buffer_ref :: struct { ds: data_source_base, format: format, channels: u32, + sampleRate: u32, cursor: u64, sizeInFrames: u64, pData: rawptr, @@ -204,6 +206,7 @@ foreign lib { audio_buffer_config :: struct { format: format, channels: u32, + sampleRate: u32, sizeInFrames: u64, pData: rawptr, /* If set to NULL, will allocate a block of memory for you. */ allocationCallbacks: allocation_callbacks, @@ -234,3 +237,65 @@ foreign lib { audio_buffer_get_length_in_pcm_frames :: proc(pAudioBuffer: ^audio_buffer, pLength: ^u64) -> result --- audio_buffer_get_available_frames :: proc(pAudioBuffer: ^audio_buffer, pAvailableFrames: ^u64) -> result --- } + +/* +Paged Audio Buffer +================== +A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It +can be used for cases where audio data is streamed in asynchronously while allowing data to be read +at the same time. + +This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across +simultaneously across different threads, however only one thread at a time can append, and only one +thread at a time can read and seek. +*/ +paged_audio_buffer_page :: struct { + pNext: ^paged_audio_buffer_page, /*atomic*/ + sizeInFrames: u64, + pAudioData: [1]u8, +}; + +paged_audio_buffer_data :: struct { + format: format, + channels: u32, + head: paged_audio_buffer_page, /* Dummy head for the lock-free algorithm. Always has a size of 0. */ + pTail: ^paged_audio_buffer_page, /*atomic*/ /* Never null. Initially set to &head. */ +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + paged_audio_buffer_data_init :: proc(format: format, channels: u32, pData: ^paged_audio_buffer_data) -> result --- + paged_audio_buffer_data_uninit :: proc(pData: ^paged_audio_buffer_data, pAllocationCallbacks: ^allocation_callbacks) --- + paged_audio_buffer_data_get_head :: proc(pData: ^paged_audio_buffer_data) -> ^paged_audio_buffer_page --- + paged_audio_buffer_data_get_tail :: proc(pData: ^paged_audio_buffer_data) -> ^paged_audio_buffer_page --- + paged_audio_buffer_data_get_length_in_pcm_frames :: proc(pData: ^paged_audio_buffer_data, pLength: ^u64) -> result --- + paged_audio_buffer_data_allocate_page :: proc(pData: ^paged_audio_buffer_data, pageSizeInFrames: u64, pInitialData: rawptr, pAllocationCallbacks: ^allocation_callbacks, ppPage: ^^paged_audio_buffer_page) -> result --- + paged_audio_buffer_data_free_page :: proc(pData: ^paged_audio_buffer_data, pPage: ^paged_audio_buffer_page, pAllocationCallbacks: ^allocation_callbacks) -> result --- + paged_audio_buffer_data_append_page :: proc(pData: ^paged_audio_buffer_data, pPage: ^paged_audio_buffer_page) -> result --- + paged_audio_buffer_data_allocate_and_append_page :: proc(pData: ^paged_audio_buffer_data, pageSizeInFrames: u32, pInitialData: rawptr, pAllocationCallbacks: ^allocation_callbacks) -> result --- +} + + +paged_audio_buffer_config :: struct { + pData: ^paged_audio_buffer_data, /* Must not be null. */ +} + +paged_audio_buffer :: struct { + ds: data_source_base, + pData: ^paged_audio_buffer_data, /* Audio data is read from here. Cannot be null. */ + pCurrent: ^paged_audio_buffer_page, + relativeCursor: u64, /* Relative to the current page. */ + absoluteCursor: u64, +} + +@(default_calling_convention="c", link_prefix="ma_") +foreign lib { + paged_audio_buffer_config_init :: proc(pData: ^paged_audio_buffer_data) -> paged_audio_buffer_config --- + + paged_audio_buffer_init :: proc(pConfig: ^paged_audio_buffer_config, pPagedAudioBuffer: ^paged_audio_buffer) -> result --- + paged_audio_buffer_uninit :: proc(pPagedAudioBuffer: ^paged_audio_buffer) --- + paged_audio_buffer_read_pcm_frames :: proc(pPagedAudioBuffer: ^paged_audio_buffer, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- /* Returns MA_AT_END if no more pages available. */ + paged_audio_buffer_seek_to_pcm_frame :: proc(pPagedAudioBuffer: ^paged_audio_buffer, frameIndex: u64) -> result --- + paged_audio_buffer_get_cursor_in_pcm_frames :: proc(pPagedAudioBuffer: ^paged_audio_buffer, pCursor: ^u64) -> result --- + paged_audio_buffer_get_length_in_pcm_frames :: proc(pPagedAudioBuffer: ^paged_audio_buffer, pLength: ^u64) -> result --- +} diff --git a/vendor/miniaudio/vfs.odin b/vendor/miniaudio/vfs.odin index 85571341e..9731c713f 100644 --- a/vendor/miniaudio/vfs.odin +++ b/vendor/miniaudio/vfs.odin @@ -22,8 +22,10 @@ appropriate for a given situation. vfs :: struct {} vfs_file :: distinct handle -OPEN_MODE_READ :: 0x00000001 -OPEN_MODE_WRITE :: 0x00000002 +open_mode_flags :: enum c.int { + READ = 0x00000001, + WRITE = 0x00000002, +} seek_origin :: enum c.int { start, @@ -71,10 +73,6 @@ foreign lib { default_vfs_init :: proc(pVFS: ^default_vfs, pAllocationCallbacks: ^allocation_callbacks) -> result --- } -resource_format :: enum c.int { - wav, -} - encoding_format :: enum c.int { unknown = 0, wav, From 4911df9f99d8c0de4531c794c8fc7e7fccf009f0 Mon Sep 17 00:00:00 2001 From: bkrypt <4868093+bkrypt@users.noreply.github.com> Date: Fri, 29 Apr 2022 21:39:10 +0200 Subject: [PATCH 0629/1052] Remove unneeded semicolons --- vendor/miniaudio/node_graph.odin | 4 ++-- vendor/miniaudio/resource_manager.odin | 2 +- vendor/miniaudio/utilities.odin | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/miniaudio/node_graph.odin b/vendor/miniaudio/node_graph.odin index ac47d43d8..c0df39c0f 100644 --- a/vendor/miniaudio/node_graph.odin +++ b/vendor/miniaudio/node_graph.odin @@ -156,7 +156,7 @@ node_base :: struct { _outputBuses: [MAX_NODE_LOCAL_BUS_COUNT]node_output_bus, _pHeap: rawptr, /* A heap allocation for internal use only. pInputBuses and/or pOutputBuses will point to this if the bus count exceeds MA_MAX_NODE_LOCAL_BUS_COUNT. */ _ownsHeap: b32, /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */ -}; +} @(default_calling_convention="c", link_prefix="ma_") foreign lib { @@ -199,7 +199,7 @@ node_graph :: struct { /* Read and written by multiple threads. */ isReading: b32, /*atomic*/ -}; +} @(default_calling_convention="c", link_prefix="ma_") foreign lib { diff --git a/vendor/miniaudio/resource_manager.odin b/vendor/miniaudio/resource_manager.odin index c4d722342..e67d4a475 100644 --- a/vendor/miniaudio/resource_manager.odin +++ b/vendor/miniaudio/resource_manager.odin @@ -218,7 +218,7 @@ foreign lib { /* Init. */ resource_manager_init :: proc(pConfig: ^resource_manager_config, pResourceManager: ^resource_manager) -> result --- resource_manager_uninit :: proc(pResourceManager: ^resource_manager) --- - resource_manager_get_log :: proc(pResourceManager: ^resource_manager) -> ^log ---; + resource_manager_get_log :: proc(pResourceManager: ^resource_manager) -> ^log --- /* Registration. */ resource_manager_register_file :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32) -> result --- diff --git a/vendor/miniaudio/utilities.odin b/vendor/miniaudio/utilities.odin index 791482cbf..708cc820e 100644 --- a/vendor/miniaudio/utilities.odin +++ b/vendor/miniaudio/utilities.odin @@ -253,7 +253,7 @@ paged_audio_buffer_page :: struct { pNext: ^paged_audio_buffer_page, /*atomic*/ sizeInFrames: u64, pAudioData: [1]u8, -}; +} paged_audio_buffer_data :: struct { format: format, From 0ad448f1c71da7bc522012a894f02c9864e448d6 Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 30 Apr 2022 11:21:37 +0300 Subject: [PATCH 0630/1052] sys/windows: add a couple of procedures and types --- core/image/common.odin | 2 +- core/sys/windows/gdi32.odin | 5 +++++ core/sys/windows/types.odin | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/core/image/common.odin b/core/image/common.odin index 8c77ec48a..9955f0ee1 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -1131,4 +1131,4 @@ write_bytes :: proc(buf: ^bytes.Buffer, data: []u8) -> (err: compress.General_Er return compress.General_Error.Resize_Failed } return nil -} \ No newline at end of file +} diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 15d5567c7..8c686f2dc 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -62,5 +62,10 @@ foreign gdi32 { ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int --- SwapBuffers :: proc(HDC) -> BOOL --- + SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- PatBlt :: proc(hdc: HDC, x, y, w, h: c_int, rop: DWORD) -> BOOL --- } + +RGB :: proc(r, g, b: u8) -> COLORREF { + return COLORREF(COLORREF(r) | COLORREF(g) << 8 | COLORREF(b) << 16) +} diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 6bded29e1..4093fd3f9 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -55,6 +55,8 @@ UINT_PTR :: uintptr ULONG :: c_ulong UCHAR :: BYTE NTSTATUS :: c.long +COLORREF :: DWORD +LPCOLORREF :: ^COLORREF LPARAM :: LONG_PTR WPARAM :: UINT_PTR LRESULT :: LONG_PTR From 40bea95fb0c1f561f2bb53c967c698823c8c951b Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 30 Apr 2022 12:41:04 +0300 Subject: [PATCH 0631/1052] sys/windows: add GetDCBrushColor --- core/sys/windows/gdi32.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 8c686f2dc..eb863b586 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -63,6 +63,7 @@ foreign gdi32 { SwapBuffers :: proc(HDC) -> BOOL --- SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- + GetDCBrushColor :: proc(hdc: HDC) -> COLORREF --- PatBlt :: proc(hdc: HDC, x, y, w, h: c_int, rop: DWORD) -> BOOL --- } From 8c7f3fd1e6f9b04da2b01e25bd7a5dee6feeee28 Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 30 Apr 2022 13:34:11 +0300 Subject: [PATCH 0632/1052] sys/windows: change macro and add comment --- core/sys/windows/gdi32.odin | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index eb863b586..bec5225a7 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -67,6 +67,8 @@ foreign gdi32 { PatBlt :: proc(hdc: HDC, x, y, w, h: c_int, rop: DWORD) -> BOOL --- } -RGB :: proc(r, g, b: u8) -> COLORREF { - return COLORREF(COLORREF(r) | COLORREF(g) << 8 | COLORREF(b) << 16) +// Windows colors are packed as ABGR +RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF { + res: [4]u8 = {0, rgb.b, rgb.g, rgb.r} + return transmute(COLORREF)res } From d2bac0c35e8f7c2347b6bd3763d64de6e902494b Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 30 Apr 2022 13:40:38 +0300 Subject: [PATCH 0633/1052] sys/windows: fix build issues --- core/sys/windows/gdi32.odin | 2 +- core/sys/windows/types.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index bec5225a7..e728503d2 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -69,6 +69,6 @@ foreign gdi32 { // Windows colors are packed as ABGR RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF { - res: [4]u8 = {0, rgb.b, rgb.g, rgb.r} + res: [4]u8 = {0, b, g, r} return transmute(COLORREF)res } diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 4093fd3f9..c3e461ba0 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -55,7 +55,7 @@ UINT_PTR :: uintptr ULONG :: c_ulong UCHAR :: BYTE NTSTATUS :: c.long -COLORREF :: DWORD +COLORREF :: DWORD // Windows colors are packed as ABGR LPCOLORREF :: ^COLORREF LPARAM :: LONG_PTR WPARAM :: UINT_PTR From dd6337224f817044be01fd270e9d70ddbc0571a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 30 Apr 2022 11:42:28 +0100 Subject: [PATCH 0634/1052] Correct explicit atomic orderings --- core/sync/primitives_atomic.odin | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index 665b515ba..a0f08c412 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -298,7 +298,7 @@ atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) { } atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) { - state := u32(atomic_load(&c.state)) + state := u32(atomic_load_explicit(&c.state, .Relaxed)) unlock(m) ok = futex_wait_with_timeout(&c.state, state, duration) lock(m) @@ -307,12 +307,12 @@ atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duratio atomic_cond_signal :: proc(c: ^Atomic_Cond) { - atomic_add_explicit(&c.state, 1, .Relaxed) + atomic_add_explicit(&c.state, 1, .Release) futex_signal(&c.state) } atomic_cond_broadcast :: proc(c: ^Atomic_Cond) { - atomic_add_explicit(&c.state, 1, .Relaxed) + atomic_add_explicit(&c.state, 1, .Release) futex_broadcast(&c.state) } @@ -351,7 +351,6 @@ atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) return false } for { - original_count := atomic_load_explicit(&s.count, .Relaxed) for start := time.tick_now(); original_count == 0; /**/ { remaining := duration - time.tick_since(start) From d5886c1572c6b093079e3be9911d5aaad0e65a7d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 30 Apr 2022 12:37:14 +0100 Subject: [PATCH 0635/1052] Remove the wait group based semaphore implementation It was a misuse of the data structure --- core/sync/extended.odin | 15 ++++-------- core/sync/primitives_internal.odin | 19 +++++++++++++++ core/sync/sema_internal.odin | 39 ------------------------------ 3 files changed, 24 insertions(+), 49 deletions(-) delete mode 100644 core/sync/sema_internal.odin diff --git a/core/sync/extended.odin b/core/sync/extended.odin index 2cca6f961..180d9b633 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -16,8 +16,7 @@ wait_group_add :: proc(wg: ^Wait_Group, delta: int) { return } - mutex_lock(&wg.mutex) - defer mutex_unlock(&wg.mutex) + guard(&wg.mutex) atomic_add(&wg.counter, delta) if wg.counter < 0 { @@ -36,8 +35,7 @@ wait_group_done :: proc(wg: ^Wait_Group) { } wait_group_wait :: proc(wg: ^Wait_Group) { - mutex_lock(&wg.mutex) - defer mutex_unlock(&wg.mutex) + guard(&wg.mutex) if wg.counter != 0 { cond_wait(&wg.cond, &wg.mutex) @@ -51,8 +49,7 @@ wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) - if duration <= 0 { return false } - mutex_lock(&wg.mutex) - defer mutex_unlock(&wg.mutex) + guard(&wg.mutex) if wg.counter != 0 { if !cond_wait_with_timeout(&wg.cond, &wg.mutex, duration) { @@ -119,8 +116,7 @@ barrier_init :: proc(b: ^Barrier, thread_count: int) { // Block the current thread until all threads have rendezvoused // Barrier can be reused after all threads rendezvoused once, and can be used continuously barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) { - mutex_lock(&b.mutex) - defer mutex_unlock(&b.mutex) + guard(&b.mutex) local_gen := b.generation_id b.index += 1 if b.index < b.thread_count { @@ -289,8 +285,7 @@ Once :: struct { once_do :: proc(o: ^Once, fn: proc()) { @(cold) do_slow :: proc(o: ^Once, fn: proc()) { - mutex_lock(&o.m) - defer mutex_unlock(&o.m) + guard(&o.m) if !o.done { fn() atomic_store_explicit(&o.done, true, .Release) diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin index de9aca991..deacf632c 100644 --- a/core/sync/primitives_internal.odin +++ b/core/sync/primitives_internal.odin @@ -1,6 +1,25 @@ //+private package sync +import "core:time" + +_Sema :: struct { + atomic: Atomic_Sema, +} + +_sema_post :: proc(s: ^Sema, count := 1) { + atomic_sema_post(&s.impl.atomic, count) +} + +_sema_wait :: proc(s: ^Sema) { + atomic_sema_wait(&s.impl.atomic) +} + +_sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { + return atomic_sema_wait_with_timeout(&s.impl.atomic, duration) +} + + when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _Recursive_Mutex :: struct { owner: Futex, diff --git a/core/sync/sema_internal.odin b/core/sync/sema_internal.odin deleted file mode 100644 index 5e2203c34..000000000 --- a/core/sync/sema_internal.odin +++ /dev/null @@ -1,39 +0,0 @@ -//+private -package sync - -import "core:time" - - -when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { - _Sema :: struct { - atomic: Atomic_Sema, - } - - _sema_post :: proc(s: ^Sema, count := 1) { - atomic_sema_post(&s.impl.atomic, count) - } - - _sema_wait :: proc(s: ^Sema) { - atomic_sema_wait(&s.impl.atomic) - } - - _sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { - return atomic_sema_wait_with_timeout(&s.impl.atomic, duration) - } -} else { - _Sema :: struct { - wg: Wait_Group, - } - - _sema_post :: proc(s: ^Sema, count := 1) { - wait_group_add(&s.impl.wg, count) - } - - _sema_wait :: proc(s: ^Sema) { - wait_group_wait(&s.impl.wg) - } - - _sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { - return wait_group_wait_with_timeout(&s.impl.wg, duration) - } -} \ No newline at end of file From 78a8da5fea73538fab2597a4691f87e63972535f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 30 Apr 2022 12:37:39 +0100 Subject: [PATCH 0636/1052] Add `sync.Parker` --- core/sync/extended.odin | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/core/sync/extended.odin b/core/sync/extended.odin index 180d9b633..49d296c90 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -297,3 +297,59 @@ once_do :: proc(o: ^Once, fn: proc()) { do_slow(o, fn) } } + + + +// A Parker is an associated token which is initially not present: +// * The `park` procedure blocks the current thread unless or until the token +// is available, at which point the token is consumed. +// * The `park_with_timeout` procedures works the same as `park` but only +// blocks for the specified duration. +// * The `unpark` procedure automatically makes the token available if it +// was not already. +Parker :: struct { + state: Futex, +} + +// Blocks the current thread until the token is made available. +// +// Assumes this is only called by the thread that owns the Parker. +park :: proc(p: ^Parker) { + EMPTY :: 0 + NOTIFIED :: 1 + PARKED :: max(u32) + if atomic_sub_explicit(&p.state, 1, .Acquire) == NOTIFIED { + return + } + for { + futex_wait(&p.state, PARKED) + if _, ok := atomic_compare_exchange_strong_explicit(&p.state, NOTIFIED, EMPTY, .Acquire, .Acquire); ok { + return + } + } +} + +// Blocks the current thread until the token is made available, but only +// for a limited duration. +// +// Assumes this is only called by the thread that owns the Parker +park_with_timeout :: proc(p: ^Parker, duration: time.Duration) { + EMPTY :: 0 + NOTIFIED :: 1 + PARKED :: max(u32) + if atomic_sub_explicit(&p.state, 1, .Acquire) == NOTIFIED { + return + } + futex_wait_with_timeout(&p.state, PARKED, duration) + atomic_exchange_explicit(&p.state, EMPTY, .Acquire) +} + +// Automatically makes thee token available if it was not already. +unpark :: proc(p: ^Parker) { + EMPTY :: 0 + NOTIFIED :: 1 + PARKED :: max(Futex) + if atomic_exchange_explicit(&p.state, NOTIFIED, .Release) == PARKED { + futex_signal(&p.state) + } +} \ No newline at end of file From 4e39629a9a316817b20387b2dc7860f95ab110b4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 30 Apr 2022 13:09:24 +0100 Subject: [PATCH 0637/1052] Unify implementation for *nix platforms --- core/sync/primitives_darwin.odin | 38 -------- core/sync/primitives_freebsd.odin | 36 ------- core/sync/primitives_internal.odin | 145 +++++++++++++---------------- core/sync/primitives_linux.odin | 37 -------- core/sync/primitives_openbsd.odin | 36 ------- 5 files changed, 67 insertions(+), 225 deletions(-) diff --git a/core/sync/primitives_darwin.odin b/core/sync/primitives_darwin.odin index 514f66f3e..521c8fe35 100644 --- a/core/sync/primitives_darwin.odin +++ b/core/sync/primitives_darwin.odin @@ -17,41 +17,3 @@ _current_thread_id :: proc "contextless" () -> int { pthread_threadid_np(nil, &tid) return int(tid) } - - - -_Mutex :: struct { - mutex: Atomic_Mutex, -} - -_mutex_lock :: proc(m: ^Mutex) { - atomic_mutex_lock(&m.impl.mutex) -} - -_mutex_unlock :: proc(m: ^Mutex) { - atomic_mutex_unlock(&m.impl.mutex) -} - -_mutex_try_lock :: proc(m: ^Mutex) -> bool { - return atomic_mutex_try_lock(&m.impl.mutex) -} - -_Cond :: struct { - cond: Atomic_Cond, -} - -_cond_wait :: proc(c: ^Cond, m: ^Mutex) { - atomic_cond_wait(&c.impl.cond, &m.impl.mutex) -} - -_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { - return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) -} - -_cond_signal :: proc(c: ^Cond) { - atomic_cond_signal(&c.impl.cond) -} - -_cond_broadcast :: proc(c: ^Cond) { - atomic_cond_broadcast(&c.impl.cond) -} diff --git a/core/sync/primitives_freebsd.odin b/core/sync/primitives_freebsd.odin index b88fca181..9fdabb7c9 100644 --- a/core/sync/primitives_freebsd.odin +++ b/core/sync/primitives_freebsd.odin @@ -8,39 +8,3 @@ import "core:time" _current_thread_id :: proc "contextless" () -> int { return os.current_thread_id() } - -_Mutex :: struct { - mutex: Atomic_Mutex, -} - -_mutex_lock :: proc(m: ^Mutex) { - atomic_mutex_lock(&m.impl.mutex) -} - -_mutex_unlock :: proc(m: ^Mutex) { - atomic_mutex_unlock(&m.impl.mutex) -} - -_mutex_try_lock :: proc(m: ^Mutex) -> bool { - return atomic_mutex_try_lock(&m.impl.mutex) -} - -_Cond :: struct { - cond: Atomic_Cond, -} - -_cond_wait :: proc(c: ^Cond, m: ^Mutex) { - atomic_cond_wait(&c.impl.cond, &m.impl.mutex) -} - -_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { - return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) -} - -_cond_signal :: proc(c: ^Cond) { - atomic_cond_signal(&c.impl.cond) -} - -_cond_broadcast :: proc(c: ^Cond) { - atomic_cond_broadcast(&c.impl.cond) -} diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin index deacf632c..ba17c2eb5 100644 --- a/core/sync/primitives_internal.odin +++ b/core/sync/primitives_internal.odin @@ -20,99 +20,89 @@ _sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { } -when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { - _Recursive_Mutex :: struct { - owner: Futex, - recursion: i32, - } +_Recursive_Mutex :: struct { + owner: Futex, + recursion: i32, +} - _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { - tid := Futex(current_thread_id()) - for { - prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire) - switch prev_owner { - case 0, tid: - m.impl.recursion += 1 - // inside the lock - return - } - - futex_wait(&m.impl.owner, u32(prev_owner)) - } - } - - _recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) { - m.impl.recursion -= 1 - if m.impl.recursion != 0 { - return - } - atomic_exchange_explicit(&m.impl.owner, 0, .Release) - - futex_signal(&m.impl.owner) - // outside the lock - - } - - _recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { - tid := Futex(current_thread_id()) +_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { + tid := Futex(current_thread_id()) + for { prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire) switch prev_owner { case 0, tid: m.impl.recursion += 1 // inside the lock - return true + return } - return false - } -} else { - _Recursive_Mutex :: struct { - owner: int, - recursion: int, - mutex: Mutex, - } - _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { - tid := current_thread_id() - if tid != m.impl.owner { - mutex_lock(&m.impl.mutex) - } - // inside the lock - m.impl.owner = tid + futex_wait(&m.impl.owner, u32(prev_owner)) + } +} + +_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) { + m.impl.recursion -= 1 + if m.impl.recursion != 0 { + return + } + atomic_exchange_explicit(&m.impl.owner, 0, .Release) + + futex_signal(&m.impl.owner) + // outside the lock + +} + +_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { + tid := Futex(current_thread_id()) + prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire) + switch prev_owner { + case 0, tid: m.impl.recursion += 1 - } - - _recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) { - tid := current_thread_id() - assert(tid == m.impl.owner) - m.impl.recursion -= 1 - recursion := m.impl.recursion - if recursion == 0 { - m.impl.owner = 0 - } - if recursion == 0 { - mutex_unlock(&m.impl.mutex) - } - // outside the lock - - } - - _recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { - tid := current_thread_id() - if m.impl.owner == tid { - return mutex_try_lock(&m.impl.mutex) - } - if !mutex_try_lock(&m.impl.mutex) { - return false - } // inside the lock - m.impl.owner = tid - m.impl.recursion += 1 return true } + return false } when ODIN_OS != .Windows { + _Mutex :: struct { + mutex: Atomic_Mutex, + } + + _mutex_lock :: proc(m: ^Mutex) { + atomic_mutex_lock(&m.impl.mutex) + } + + _mutex_unlock :: proc(m: ^Mutex) { + atomic_mutex_unlock(&m.impl.mutex) + } + + _mutex_try_lock :: proc(m: ^Mutex) -> bool { + return atomic_mutex_try_lock(&m.impl.mutex) + } + + _Cond :: struct { + cond: Atomic_Cond, + } + + _cond_wait :: proc(c: ^Cond, m: ^Mutex) { + atomic_cond_wait(&c.impl.cond, &m.impl.mutex) + } + + _cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) + } + + _cond_signal :: proc(c: ^Cond) { + atomic_cond_signal(&c.impl.cond) + } + + _cond_broadcast :: proc(c: ^Cond) { + atomic_cond_broadcast(&c.impl.cond) + } + + _RW_Mutex :: struct { mutex: Atomic_RW_Mutex, } @@ -140,5 +130,4 @@ when ODIN_OS != .Windows { _rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool { return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex) } - } \ No newline at end of file diff --git a/core/sync/primitives_linux.odin b/core/sync/primitives_linux.odin index 0a9f0cc33..4cc99bdf1 100644 --- a/core/sync/primitives_linux.odin +++ b/core/sync/primitives_linux.odin @@ -8,40 +8,3 @@ import "core:time" _current_thread_id :: proc "contextless" () -> int { return unix.sys_gettid() } - - -_Mutex :: struct { - mutex: Atomic_Mutex, -} - -_mutex_lock :: proc(m: ^Mutex) { - atomic_mutex_lock(&m.impl.mutex) -} - -_mutex_unlock :: proc(m: ^Mutex) { - atomic_mutex_unlock(&m.impl.mutex) -} - -_mutex_try_lock :: proc(m: ^Mutex) -> bool { - return atomic_mutex_try_lock(&m.impl.mutex) -} - -_Cond :: struct { - cond: Atomic_Cond, -} - -_cond_wait :: proc(c: ^Cond, m: ^Mutex) { - atomic_cond_wait(&c.impl.cond, &m.impl.mutex) -} - -_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { - return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) -} - -_cond_signal :: proc(c: ^Cond) { - atomic_cond_signal(&c.impl.cond) -} - -_cond_broadcast :: proc(c: ^Cond) { - atomic_cond_broadcast(&c.impl.cond) -} diff --git a/core/sync/primitives_openbsd.odin b/core/sync/primitives_openbsd.odin index 7794016f8..fd56a4837 100644 --- a/core/sync/primitives_openbsd.odin +++ b/core/sync/primitives_openbsd.odin @@ -8,39 +8,3 @@ import "core:time" _current_thread_id :: proc "contextless" () -> int { return os.current_thread_id() } - -_Mutex :: struct { - mutex: Atomic_Mutex, -} - -_mutex_lock :: proc(m: ^Mutex) { - atomic_mutex_lock(&m.impl.mutex) -} - -_mutex_unlock :: proc(m: ^Mutex) { - atomic_mutex_unlock(&m.impl.mutex) -} - -_mutex_try_lock :: proc(m: ^Mutex) -> bool { - return atomic_mutex_try_lock(&m.impl.mutex) -} - -_Cond :: struct { - cond: Atomic_Cond, -} - -_cond_wait :: proc(c: ^Cond, m: ^Mutex) { - atomic_cond_wait(&c.impl.cond, &m.impl.mutex) -} - -_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { - return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) -} - -_cond_signal :: proc(c: ^Cond) { - atomic_cond_signal(&c.impl.cond) -} - -_cond_broadcast :: proc(c: ^Cond) { - atomic_cond_broadcast(&c.impl.cond) -} From 2720f64c06da7e9aaf49b96e25230c8036055203 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 30 Apr 2022 13:28:45 +0100 Subject: [PATCH 0638/1052] Remove unused imports --- core/sync/primitives_darwin.odin | 1 - core/sync/primitives_freebsd.odin | 1 - core/sync/primitives_linux.odin | 1 - core/sync/primitives_openbsd.odin | 1 - 4 files changed, 4 deletions(-) diff --git a/core/sync/primitives_darwin.odin b/core/sync/primitives_darwin.odin index 521c8fe35..726113ae7 100644 --- a/core/sync/primitives_darwin.odin +++ b/core/sync/primitives_darwin.odin @@ -3,7 +3,6 @@ package sync import "core:c" -import "core:time" import "core:intrinsics" foreign import pthread "System.framework" diff --git a/core/sync/primitives_freebsd.odin b/core/sync/primitives_freebsd.odin index 9fdabb7c9..e6219acf1 100644 --- a/core/sync/primitives_freebsd.odin +++ b/core/sync/primitives_freebsd.odin @@ -3,7 +3,6 @@ package sync import "core:os" -import "core:time" _current_thread_id :: proc "contextless" () -> int { return os.current_thread_id() diff --git a/core/sync/primitives_linux.odin b/core/sync/primitives_linux.odin index 4cc99bdf1..1e75891df 100644 --- a/core/sync/primitives_linux.odin +++ b/core/sync/primitives_linux.odin @@ -3,7 +3,6 @@ package sync import "core:sys/unix" -import "core:time" _current_thread_id :: proc "contextless" () -> int { return unix.sys_gettid() diff --git a/core/sync/primitives_openbsd.odin b/core/sync/primitives_openbsd.odin index fd56a4837..4072a14e8 100644 --- a/core/sync/primitives_openbsd.odin +++ b/core/sync/primitives_openbsd.odin @@ -3,7 +3,6 @@ package sync import "core:os" -import "core:time" _current_thread_id :: proc "contextless" () -> int { return os.current_thread_id() From d6a8216ce48eb9478f307ccf70e5295424bd78ed Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 14:34:07 +0200 Subject: [PATCH 0639/1052] [pbm] Normalize some errors, correct .depth --- core/image/common.odin | 41 +++++++++++------- core/image/netpbm/netpbm.odin | 61 +++++++++++---------------- core/image/png/png.odin | 16 +++---- core/image/qoi/qoi.odin | 12 +++--- core/image/tga/tga.odin | 5 +-- tests/core/image/test_core_image.odin | 12 +++--- 6 files changed, 70 insertions(+), 77 deletions(-) diff --git a/core/image/common.odin b/core/image/common.odin index 2196565bd..6722036ff 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -45,7 +45,7 @@ Image :: struct { width: int, height: int, channels: int, - depth: int, + depth: int, // Channel depth in bits, typically 8 or 16 pixels: bytes.Buffer, /* Some image loaders/writers can return/take an optional background color. @@ -141,13 +141,14 @@ Option :: enum { alpha_drop_if_present, // Unimplemented for QOI. Returns error. alpha_premultiply, // Unimplemented for QOI. Returns error. blend_background, // Ignored for non-PNG formats + // Unimplemented do_not_expand_grayscale, do_not_expand_indexed, do_not_expand_channels, // SAVE OPTIONS - qoi_all_channels_linear, // QOI, informative info. If not set, defaults to sRGB with linear alpha. + qoi_all_channels_linear, // QOI, informative only. If not set, defaults to sRGB with linear alpha. } Options :: distinct bit_set[Option] @@ -166,12 +167,29 @@ Error :: union #shared_nil { General_Image_Error :: enum { None = 0, + // File I/O + Unable_To_Read_File, + Unable_To_Write_File, + + // Invalid + Invalid_Signature, + Invalid_Input_Image, + Image_Dimensions_Too_Large, Invalid_Image_Dimensions, Invalid_Number_Of_Channels, - Image_Dimensions_Too_Large, Image_Does_Not_Adhere_to_Spec, - Invalid_Input_Image, + Invalid_Image_Depth, + Invalid_Bit_Depth, + Invalid_Color_Space, + + // More data than pixels to decode into, for example. + Corrupt, + + // Output buffer is the wrong size Invalid_Output, + + // Allocation + Unable_To_Allocate_Or_Resize, } /* @@ -201,8 +219,6 @@ Netpbm_Error :: enum { None = 0, // reading - File_Not_Readable, - Invalid_Signature, Invalid_Header_Token_Character, Incomplete_Header, Invalid_Header_Value, @@ -212,9 +228,7 @@ Netpbm_Error :: enum { Invalid_Buffer_Value, // writing - File_Not_Writable, Invalid_Format, - Invalid_Image_Depth, } /* @@ -222,7 +236,6 @@ Netpbm_Error :: enum { */ PNG_Error :: enum { None = 0, - Invalid_PNG_Signature, IHDR_Not_First_Chunk, IHDR_Corrupt, IDAT_Missing, @@ -338,14 +351,10 @@ PNG_Interlace_Method :: enum u8 { */ QOI_Error :: enum { None = 0, - Invalid_QOI_Signature, - Invalid_Bit_Depth, // QOI supports only 8-bit images, error only returned from writer. - Invalid_Color_Space, // QOI allows 0 = sRGB or 1 = linear. - Corrupt, // More data than pixels to decode into, for example. Missing_Or_Corrupt_Trailer, // Image seemed to have decoded okay, but trailer is missing or corrupt. } -QOI_Magic :: u32be(0x716f6966) // "qoif" +QOI_Magic :: u32be(0x716f6966) // "qoif" QOI_Color_Space :: enum u8 { sRGB = 0, @@ -1170,10 +1179,10 @@ write_bytes :: proc(buf: ^bytes.Buffer, data: []u8) -> (err: compress.General_Er return nil } else if len(data) == 1 { if bytes.buffer_write_byte(buf, data[0]) != nil { - return compress.General_Error.Resize_Failed + return .Resize_Failed } } else if n, _ := bytes.buffer_write(buf, data); n != len(data) { - return compress.General_Error.Resize_Failed + return .Resize_Failed } return nil } \ No newline at end of file diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index 5c082e384..54935d6c6 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -9,8 +9,6 @@ import "core:strconv" import "core:strings" import "core:unicode" - - Image :: image.Image Format :: image.Netpbm_Format Header :: image.Netpbm_Header @@ -18,8 +16,6 @@ Info :: image.Netpbm_Info Error :: image.Error Format_Error :: image.Netpbm_Error - - Formats :: bit_set[Format] PBM :: Formats{.P1, .P4} PGM :: Formats{.P2, .P5} @@ -30,14 +26,12 @@ PFM :: Formats{.Pf, .PF} ASCII :: Formats{.P1, .P2, .P3} BINARY :: Formats{.P4, .P5, .P6} + PAM + PFM - - -read :: proc { - read_from_file, - read_from_buffer, +load :: proc { + load_from_file, + load_from_buffer, } -read_from_file :: proc(filename: string, allocator := context.allocator) -> (img: Image, err: Error) { +load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: Image, err: Error) { context.allocator = allocator data, ok := os.read_entire_file(filename); defer delete(data) @@ -49,7 +43,7 @@ read_from_file :: proc(filename: string, allocator := context.allocator) -> (img return read_from_buffer(data) } -read_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { +load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { context.allocator = allocator header: Header; defer header_destroy(&header) @@ -70,14 +64,12 @@ read_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: return } - - -write :: proc { - write_to_file, - write_to_buffer, +save :: proc { + save_to_file, + save_to_buffer, } -write_to_file :: proc(filename: string, img: Image, allocator := context.allocator) -> (err: Error) { +save_to_file :: proc(filename: string, img: Image, allocator := context.allocator) -> (err: Error) { context.allocator = allocator data: []byte; defer delete(data) @@ -90,7 +82,7 @@ write_to_file :: proc(filename: string, img: Image, allocator := context.allocat return Format_Error.None } -write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: []byte, err: Error) { +save_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: []byte, err: Error) { context.allocator = allocator info, ok := img.metadata.(^image.Netpbm_Info) @@ -109,12 +101,12 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: } if header.format in (PNM + PAM) { - if header.maxval <= int(max(u8)) && img.depth != 1 \ - || header.maxval > int(max(u8)) && header.maxval <= int(max(u16)) && img.depth != 2 { + if header.maxval <= int(max(u8)) && img.depth != 8 \ + || header.maxval > int(max(u8)) && header.maxval <= int(max(u16)) && img.depth != 16 { err = Format_Error.Invalid_Image_Depth return } - } else if header.format in PFM && img.depth != 4 { + } else if header.format in PFM && img.depth != 32 { err = Format_Error.Invalid_Image_Depth return } @@ -179,7 +171,7 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: mem.copy(raw_data(data.buf[len(header_buf):]), raw_data(pixels), len(pixels)) // convert from native endianness - if img.depth == 2 { + if img.depth == 16 { pixels := mem.slice_data_cast([]u16be, data.buf[len(header_buf):]) for p in &pixels { p = u16be(transmute(u16) p) @@ -212,7 +204,7 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: // Token ASCII case .P2, .P3: switch img.depth { - case 1: + case 8: pixels := img.pixels.buf[:] for y in 0 ..< img.height { for x in 0 ..< img.width { @@ -226,7 +218,7 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: fmt.sbprint(&data, "\n") } - case 2: + case 16: pixels := mem.slice_data_cast([]u16, img.pixels.buf[:]) for y in 0 ..< img.height { for x in 0 ..< img.width { @@ -251,8 +243,6 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: return data.buf[:], Format_Error.None } - - parse_header :: proc(data: []byte, allocator := context.allocator) -> (header: Header, length: int, err: Error) { context.allocator = allocator @@ -351,7 +341,7 @@ _parse_header_pnm :: proc(data: []byte) -> (header: Header, length: int, err: Er // set extra info header.channels = 3 if header.format in PPM else 1 - header.depth = 2 if header.maxval > int(max(u8)) else 1 + header.depth = 16 if header.maxval > int(max(u8)) else 8 // limit checking if current_field < len(header_fields) { @@ -448,12 +438,11 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head } // extra info - header.depth = 2 if header.maxval > int(max(u8)) else 1 + header.depth = 16 if header.maxval > int(max(u8)) else 8 // limit checking if header.width < 1 \ || header.height < 1 \ - || header.depth < 1 \ || header.maxval < 1 \ || header.maxval > int(max(u16)) { err = Format_Error.Invalid_Header_Value @@ -484,7 +473,7 @@ _parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Er } // floating point - header.depth = 4 + header.depth = 32 // width field, ok = strings.fields_iterator(&field_iterator) @@ -542,8 +531,6 @@ _parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Er return } - - decode_image :: proc(header: Header, data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { context.allocator = allocator @@ -554,7 +541,7 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato depth = header.depth, } - buffer_size := img.width * img.height * img.channels * img.depth + buffer_size := image.compute_buffer_size(img.width, img.height, img.channels, img.depth) // we can check data size for binary formats if header.format in BINARY { @@ -615,7 +602,7 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato } } } else { - if img.depth == 2 { + if img.depth == 16 { pixels := mem.slice_data_cast([]u16, img.pixels.buf[:]) for p in &pixels { p = u16(transmute(u16be) p) @@ -658,9 +645,9 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato } switch img.depth { - case 1: + case 8: bytes.buffer_write_byte(&img.pixels, u8(value)) - case 2: + case 16: vb := transmute([2]u8) u16(value) bytes.buffer_write(&img.pixels, vb[:]) } @@ -678,4 +665,4 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato err = Format_Error.None return -} +} \ No newline at end of file diff --git a/core/image/png/png.odin b/core/image/png/png.odin index ba888cb78..d526dfb27 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -238,7 +238,7 @@ append_chunk :: proc(list: ^[dynamic]image.PNG_Chunk, src: image.PNG_Chunk, allo append(list, c) if len(list) != length + 1 { // Resize during append failed. - return mem.Allocator_Error.Out_Of_Memory + return .Unable_To_Allocate_Or_Resize } return @@ -347,7 +347,7 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont return load_from_slice(data, options) } else { img = new(Image) - return img, compress.General_Error.File_Not_Found + return img, .Unable_To_Read_File } } @@ -381,7 +381,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a signature, io_error := compress.read_data(ctx, Signature) if io_error != .None || signature != .PNG { - return img, .Invalid_PNG_Signature + return img, .Invalid_Signature } idat: []u8 @@ -747,7 +747,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8) t := bytes.Buffer{} if !resize(&t.buf, dest_raw_size) { - return {}, mem.Allocator_Error.Out_Of_Memory + return {}, .Unable_To_Allocate_Or_Resize } i := 0; j := 0 @@ -828,7 +828,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16) t := bytes.Buffer{} if !resize(&t.buf, dest_raw_size) { - return {}, mem.Allocator_Error.Out_Of_Memory + return {}, .Unable_To_Allocate_Or_Resize } p16 := mem.slice_data_cast([]u16, temp.buf[:]) @@ -1027,7 +1027,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8) t := bytes.Buffer{} if !resize(&t.buf, dest_raw_size) { - return {}, mem.Allocator_Error.Out_Of_Memory + return {}, .Unable_To_Allocate_Or_Resize } p := mem.slice_data_cast([]u8, temp.buf[:]) @@ -1535,7 +1535,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8) if !resize(&img.pixels.buf, num_bytes) { - return mem.Allocator_Error.Out_Of_Memory + return .Unable_To_Allocate_Or_Resize } filter_ok: bool @@ -1577,7 +1577,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH temp: bytes.Buffer temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8) if !resize(&temp.buf, temp_len) { - return mem.Allocator_Error.Out_Of_Memory + return .Unable_To_Allocate_Or_Resize } params := Filter_Params{ diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin index fdbaab686..83b212be8 100644 --- a/core/image/qoi/qoi.odin +++ b/core/image/qoi/qoi.odin @@ -12,14 +12,12 @@ // The QOI specification is at https://qoiformat.org. package qoi -import "core:mem" import "core:image" import "core:compress" import "core:bytes" import "core:os" Error :: image.Error -General :: compress.General_Error Image :: image.Image Options :: image.Options @@ -57,7 +55,7 @@ save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{} max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be) if !resize(&output.buf, max_size) { - return General.Resize_Failed + return .Unable_To_Allocate_Or_Resize } header := image.QOI_Header{ @@ -177,7 +175,7 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato save_to_memory(out, img, options) or_return write_ok := os.write_entire_file(output, out.buf[:]) - return nil if write_ok else General.Cannot_Open_File + return nil if write_ok else .Unable_To_Write_File } save :: proc{save_to_memory, save_to_file} @@ -201,7 +199,7 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont return load_from_slice(data, options) } else { img = new(Image) - return img, compress.General_Error.File_Not_Found + return img, .Unable_To_Read_File } } @@ -221,7 +219,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a header := image.read_data(ctx, image.QOI_Header) or_return if header.magic != image.QOI_Magic { - return img, .Invalid_QOI_Signature + return img, .Invalid_Signature } if img == nil { @@ -264,7 +262,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8) if !resize(&img.pixels.buf, bytes_needed) { - return img, mem.Allocator_Error.Out_Of_Memory + return img, .Unable_To_Allocate_Or_Resize } /* diff --git a/core/image/tga/tga.odin b/core/image/tga/tga.odin index 3c860cb62..0539706b3 100644 --- a/core/image/tga/tga.odin +++ b/core/image/tga/tga.odin @@ -17,7 +17,6 @@ import "core:bytes" import "core:os" Error :: image.Error -General :: compress.General_Error Image :: image.Image Options :: image.Options @@ -55,7 +54,7 @@ save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{} necessary := pixels * img.channels + size_of(image.TGA_Header) if !resize(&output.buf, necessary) { - return General.Resize_Failed + return .Unable_To_Allocate_Or_Resize } header := image.TGA_Header{ @@ -97,7 +96,7 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato save_to_memory(out, img, options) or_return write_ok := os.write_entire_file(output, out.buf[:]) - return nil if write_ok else General.Cannot_Open_File + return nil if write_ok else .Unable_To_Write_File } save :: proc{save_to_memory, save_to_file} \ No newline at end of file diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 0c11ca5ae..c328757e4 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -1199,37 +1199,37 @@ Corrupt_PNG_Tests := []PNG_Test{ { "xs1n0g01", // signature byte 1 MSBit reset to zero { - {Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, + {Default, .Invalid_Signature, {}, 0x_0000_0000}, }, }, { "xs2n0g01", // signature byte 2 is a 'Q' { - {Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, + {Default, .Invalid_Signature, {}, 0x_0000_0000}, }, }, { "xs4n0g01", // signature byte 4 lowercase { - {Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, + {Default, .Invalid_Signature, {}, 0x_0000_0000}, }, }, { "xs7n0g01", // 7th byte a space instead of control-Z { - {Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, + {Default, .Invalid_Signature, {}, 0x_0000_0000}, }, }, { "xcrn0g04", // added cr bytes { - {Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, + {Default, .Invalid_Signature, {}, 0x_0000_0000}, }, }, { "xlfn0g04", // added lf bytes { - {Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, + {Default, .Invalid_Signature, {}, 0x_0000_0000}, }, }, { From 3978e7e1cac9305698e9270fec02d7cd9557cf35 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 14:43:58 +0200 Subject: [PATCH 0640/1052] [xml] Add `parse_from_string` overload. `parse` now takes either a `[]u8` slice or a string. `load_from_file` takes a path string. --- core/encoding/xml/xml_reader.odin | 13 ++++++++++--- tests/core/encoding/xml/test_core_xml.odin | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 6d0d4e1aa..151d44e2a 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -493,7 +493,16 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err return doc, .None } -parse_from_file :: proc(filename: string, options := DEFAULT_Options, error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) { +parse_from_string :: proc(data: string, options := DEFAULT_Options, path := "", error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) { + _data := transmute([]u8)data + + return parse_from_slice(_data, options, path, error_handler, allocator) +} + +parse :: proc { parse_from_string, parse_from_slice } + +// Load an XML file +load_from_file :: proc(filename: string, options := DEFAULT_Options, error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) { context.allocator = allocator options := options @@ -505,8 +514,6 @@ parse_from_file :: proc(filename: string, options := DEFAULT_Options, error_hand return parse_from_slice(data, options, filename, error_handler, allocator) } -parse :: proc { parse_from_file, parse_from_slice } - destroy :: proc(doc: ^Document) { if doc == nil { return } diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 07cbc1779..c8b02b635 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -295,7 +295,7 @@ run_tests :: proc(t: ^testing.T) { path := test_file_path(test.filename) log(t, fmt.tprintf("Trying to parse %v", path)) - doc, err := xml.parse(path, test.options, Silent) + doc, err := xml.load_from_file(path, test.options, Silent) defer xml.destroy(doc) tree_string := doc_to_string(doc) From d24bebdb9eb6a0a1e733fc2b325bc3472c648af9 Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 30 Apr 2022 16:55:26 +0300 Subject: [PATCH 0641/1052] sys/windows: add a couple procedures and tons of constants --- core/sys/windows/system_params.odin | 271 ++++++++++++++++++++++++++++ core/sys/windows/user32.odin | 4 + 2 files changed, 275 insertions(+) create mode 100644 core/sys/windows/system_params.odin diff --git a/core/sys/windows/system_params.odin b/core/sys/windows/system_params.odin new file mode 100644 index 000000000..e94d777bf --- /dev/null +++ b/core/sys/windows/system_params.odin @@ -0,0 +1,271 @@ +// +build windows +package sys_windows + +// Parameter for SystemParametersInfo. +SPI_GETBEEP :: 0x0001 +SPI_SETBEEP :: 0x0002 +SPI_GETMOUSE :: 0x0003 +SPI_SETMOUSE :: 0x0004 +SPI_GETBORDER :: 0x0005 +SPI_SETBORDER :: 0x0006 +SPI_GETKEYBOARDSPEED :: 0x000A +SPI_SETKEYBOARDSPEED :: 0x000B +SPI_LANGDRIVER :: 0x000C +SPI_ICONHORIZONTALSPACING :: 0x000D +SPI_GETSCREENSAVETIMEOUT :: 0x000E +SPI_SETSCREENSAVETIMEOUT :: 0x000F +SPI_GETSCREENSAVEACTIVE :: 0x0010 +SPI_SETSCREENSAVEACTIVE :: 0x0011 +SPI_GETGRIDGRANULARITY :: 0x0012 +SPI_SETGRIDGRANULARITY :: 0x0013 +SPI_SETDESKWALLPAPER :: 0x0014 +SPI_SETDESKPATTERN :: 0x0015 +SPI_GETKEYBOARDDELAY :: 0x0016 +SPI_SETKEYBOARDDELAY :: 0x0017 +SPI_ICONVERTICALSPACING :: 0x0018 +SPI_GETICONTITLEWRAP :: 0x0019 +SPI_SETICONTITLEWRAP :: 0x001A +SPI_GETMENUDROPALIGNMENT :: 0x001B +SPI_SETMENUDROPALIGNMENT :: 0x001C +SPI_SETDOUBLECLKWIDTH :: 0x001D +SPI_SETDOUBLECLKHEIGHT :: 0x001E +SPI_GETICONTITLELOGFONT :: 0x001F +SPI_SETDOUBLECLICKTIME :: 0x0020 +SPI_SETMOUSEBUTTONSWAP :: 0x0021 +SPI_SETICONTITLELOGFONT :: 0x0022 +SPI_GETFASTTASKSWITCH :: 0x0023 +SPI_SETFASTTASKSWITCH :: 0x0024 + +SPI_SETDRAGFULLWINDOWS :: 0x0025 +SPI_GETDRAGFULLWINDOWS :: 0x0026 +SPI_GETNONCLIENTMETRICS :: 0x0029 +SPI_SETNONCLIENTMETRICS :: 0x002A +SPI_GETMINIMIZEDMETRICS :: 0x002B +SPI_SETMINIMIZEDMETRICS :: 0x002C +SPI_GETICONMETRICS :: 0x002D +SPI_SETICONMETRICS :: 0x002E +SPI_SETWORKAREA :: 0x002F +SPI_GETWORKAREA :: 0x0030 +SPI_SETPENWINDOWS :: 0x0031 +SPI_GETHIGHCONTRAST :: 0x0042 +SPI_SETHIGHCONTRAST :: 0x0043 +SPI_GETKEYBOARDPREF :: 0x0044 +SPI_SETKEYBOARDPREF :: 0x0045 +SPI_GETSCREENREADER :: 0x0046 +SPI_SETSCREENREADER :: 0x0047 +SPI_GETANIMATION :: 0x0048 +SPI_SETANIMATION :: 0x0049 +SPI_GETFONTSMOOTHING :: 0x004A +SPI_SETFONTSMOOTHING :: 0x004B +SPI_SETDRAGWIDTH :: 0x004C +SPI_SETDRAGHEIGHT :: 0x004D +SPI_SETHANDHELD :: 0x004E +SPI_GETLOWPOWERTIMEOUT :: 0x004F +SPI_GETPOWEROFFTIMEOUT :: 0x0050 +SPI_SETLOWPOWERTIMEOUT :: 0x0051 +SPI_SETPOWEROFFTIMEOUT :: 0x0052 +SPI_GETLOWPOWERACTIVE :: 0x0053 +SPI_GETPOWEROFFACTIVE :: 0x0054 +SPI_SETLOWPOWERACTIVE :: 0x0055 +SPI_SETPOWEROFFACTIVE :: 0x0056 +SPI_SETCURSORS :: 0x0057 +SPI_SETICONS :: 0x0058 +SPI_GETDEFAULTINPUTLANG :: 0x0059 +SPI_SETDEFAULTINPUTLANG :: 0x005A +SPI_SETLANGTOGGLE :: 0x005B +SPI_GETWINDOWSEXTENSION :: 0x005C +SPI_SETMOUSETRAILS :: 0x005D +SPI_GETMOUSETRAILS :: 0x005E +SPI_SETSCREENSAVERRUNNING :: 0x0061 + +SPI_SCREENSAVERRUNNING :: SPI_SETSCREENSAVERRUNNING +SPI_GETFILTERKEYS :: 0x0032 +SPI_SETFILTERKEYS :: 0x0033 +SPI_GETTOGGLEKEYS :: 0x0034 +SPI_SETTOGGLEKEYS :: 0x0035 +SPI_GETMOUSEKEYS :: 0x0036 +SPI_SETMOUSEKEYS :: 0x0037 +SPI_GETSHOWSOUNDS :: 0x0038 +SPI_SETSHOWSOUNDS :: 0x0039 +SPI_GETSTICKYKEYS :: 0x003A +SPI_SETSTICKYKEYS :: 0x003B +SPI_GETACCESSTIMEOUT :: 0x003C +SPI_SETACCESSTIMEOUT :: 0x003D +SPI_GETSERIALKEYS :: 0x003E +SPI_SETSERIALKEYS :: 0x003F +SPI_GETSOUNDSENTRY :: 0x0040 +SPI_SETSOUNDSENTRY :: 0x0041 +SPI_GETSNAPTODEFBUTTON :: 0x005F +SPI_SETSNAPTODEFBUTTON :: 0x0060 +SPI_GETMOUSEHOVERWIDTH :: 0x0062 +SPI_SETMOUSEHOVERWIDTH :: 0x0063 +SPI_GETMOUSEHOVERHEIGHT :: 0x0064 +SPI_SETMOUSEHOVERHEIGHT :: 0x0065 +SPI_GETMOUSEHOVERTIME :: 0x0066 +SPI_SETMOUSEHOVERTIME :: 0x0067 +SPI_GETWHEELSCROLLLINES :: 0x0068 +SPI_SETWHEELSCROLLLINES :: 0x0069 +SPI_GETMENUSHOWDELAY :: 0x006A +SPI_SETMENUSHOWDELAY :: 0x006B + +SPI_GETWHEELSCROLLCHARS :: 0x006C +SPI_SETWHEELSCROLLCHARS :: 0x006D +SPI_GETSHOWIMEUI :: 0x006E +SPI_SETSHOWIMEUI :: 0x006F +SPI_GETMOUSESPEED :: 0x0070 +SPI_SETMOUSESPEED :: 0x0071 +SPI_GETSCREENSAVERRUNNING :: 0x0072 +SPI_GETDESKWALLPAPER :: 0x0073 +SPI_GETAUDIODESCRIPTION :: 0x0074 +SPI_SETAUDIODESCRIPTION :: 0x0075 +SPI_GETSCREENSAVESECURE :: 0x0076 +SPI_SETSCREENSAVESECURE :: 0x0077 + +SPI_GETHUNGAPPTIMEOUT :: 0x0078 +SPI_SETHUNGAPPTIMEOUT :: 0x0079 +SPI_GETWAITTOKILLTIMEOUT :: 0x007A +SPI_SETWAITTOKILLTIMEOUT :: 0x007B +SPI_GETWAITTOKILLSERVICETIMEOUT :: 0x007C +SPI_SETWAITTOKILLSERVICETIMEOUT :: 0x007D +SPI_GETMOUSEDOCKTHRESHOLD :: 0x007E +SPI_SETMOUSEDOCKTHRESHOLD :: 0x007F +SPI_GETPENDOCKTHRESHOLD :: 0x0080 +SPI_SETPENDOCKTHRESHOLD :: 0x0081 +SPI_GETWINARRANGING :: 0x0082 +SPI_SETWINARRANGING :: 0x0083 +SPI_GETMOUSEDRAGOUTTHRESHOLD :: 0x0084 +SPI_SETMOUSEDRAGOUTTHRESHOLD :: 0x0085 +SPI_GETPENDRAGOUTTHRESHOLD :: 0x0086 +SPI_SETPENDRAGOUTTHRESHOLD :: 0x0087 +SPI_GETMOUSESIDEMOVETHRESHOLD :: 0x0088 +SPI_SETMOUSESIDEMOVETHRESHOLD :: 0x0089 +SPI_GETPENSIDEMOVETHRESHOLD :: 0x008A +SPI_SETPENSIDEMOVETHRESHOLD :: 0x008B +SPI_GETDRAGFROMMAXIMIZE :: 0x008C +SPI_SETDRAGFROMMAXIMIZE :: 0x008D +SPI_GETSNAPSIZING :: 0x008E +SPI_SETSNAPSIZING :: 0x008F +SPI_GETDOCKMOVING :: 0x0090 +SPI_SETDOCKMOVING :: 0x0091 + +SPI_GETACTIVEWINDOWTRACKING :: 0x1000 +SPI_SETACTIVEWINDOWTRACKING :: 0x1001 +SPI_GETMENUANIMATION :: 0x1002 +SPI_SETMENUANIMATION :: 0x1003 +SPI_GETCOMBOBOXANIMATION :: 0x1004 +SPI_SETCOMBOBOXANIMATION :: 0x1005 +SPI_GETLISTBOXSMOOTHSCROLLING :: 0x1006 +SPI_SETLISTBOXSMOOTHSCROLLING :: 0x1007 +SPI_GETGRADIENTCAPTIONS :: 0x1008 +SPI_SETGRADIENTCAPTIONS :: 0x1009 +SPI_GETKEYBOARDCUES :: 0x100A +SPI_SETKEYBOARDCUES :: 0x100B +SPI_GETMENUUNDERLINES :: SPI_GETKEYBOARDCUES +SPI_SETMENUUNDERLINES :: SPI_SETKEYBOARDCUES +SPI_GETACTIVEWNDTRKZORDER :: 0x100C +SPI_SETACTIVEWNDTRKZORDER :: 0x100D +SPI_GETHOTTRACKING :: 0x100E +SPI_SETHOTTRACKING :: 0x100F +SPI_GETMENUFADE :: 0x1012 +SPI_SETMENUFADE :: 0x1013 +SPI_GETSELECTIONFADE :: 0x1014 +SPI_SETSELECTIONFADE :: 0x1015 +SPI_GETTOOLTIPANIMATION :: 0x1016 +SPI_SETTOOLTIPANIMATION :: 0x1017 +SPI_GETTOOLTIPFADE :: 0x1018 +SPI_SETTOOLTIPFADE :: 0x1019 +SPI_GETCURSORSHADOW :: 0x101A +SPI_SETCURSORSHADOW :: 0x101B +SPI_GETMOUSESONAR :: 0x101C +SPI_SETMOUSESONAR :: 0x101D +SPI_GETMOUSECLICKLOCK :: 0x101E +SPI_SETMOUSECLICKLOCK :: 0x101F +SPI_GETMOUSEVANISH :: 0x1020 +SPI_SETMOUSEVANISH :: 0x1021 +SPI_GETFLATMENU :: 0x1022 +SPI_SETFLATMENU :: 0x1023 +SPI_GETDROPSHADOW :: 0x1024 +SPI_SETDROPSHADOW :: 0x1025 +SPI_GETBLOCKSENDINPUTRESETS :: 0x1026 +SPI_SETBLOCKSENDINPUTRESETS :: 0x1027 +SPI_GETUIEFFECTS :: 0x103E +SPI_SETUIEFFECTS :: 0x103F +SPI_GETDISABLEOVERLAPPEDCONTENT :: 0x1040 +SPI_SETDISABLEOVERLAPPEDCONTENT :: 0x1041 +SPI_GETCLIENTAREAANIMATION :: 0x1042 +SPI_SETCLIENTAREAANIMATION :: 0x1043 +SPI_GETCLEARTYPE :: 0x1048 +SPI_SETCLEARTYPE :: 0x1049 +SPI_GETSPEECHRECOGNITION :: 0x104A +SPI_SETSPEECHRECOGNITION :: 0x104B +SPI_GETCARETBROWSING :: 0x104C +SPI_SETCARETBROWSING :: 0x104D +SPI_GETTHREADLOCALINPUTSETTINGS :: 0x104E +SPI_SETTHREADLOCALINPUTSETTINGS :: 0x104F +SPI_GETSYSTEMLANGUAGEBAR :: 0x1050 +SPI_SETSYSTEMLANGUAGEBAR :: 0x1051 +SPI_GETFOREGROUNDLOCKTIMEOUT :: 0x2000 +SPI_SETFOREGROUNDLOCKTIMEOUT :: 0x2001 +SPI_GETACTIVEWNDTRKTIMEOUT :: 0x2002 +SPI_SETACTIVEWNDTRKTIMEOUT :: 0x2003 +SPI_GETFOREGROUNDFLASHCOUNT :: 0x2004 +SPI_SETFOREGROUNDFLASHCOUNT :: 0x2005 +SPI_GETCARETWIDTH :: 0x2006 +SPI_SETCARETWIDTH :: 0x2007 +SPI_GETMOUSECLICKLOCKTIME :: 0x2008 +SPI_SETMOUSECLICKLOCKTIME :: 0x2009 +SPI_GETFONTSMOOTHINGTYPE :: 0x200A +SPI_SETFONTSMOOTHINGTYPE :: 0x200B +// constants for SPI_GETFONTSMOOTHINGTYPE and SPI_SETFONTSMOOTHINGTYPE: +FE_FONTSMOOTHINGSTANDARD :: 0x0001 +FE_FONTSMOOTHINGCLEARTYPE :: 0x0002 + +SPI_GETFONTSMOOTHINGCONTRAST :: 0x200C +SPI_SETFONTSMOOTHINGCONTRAST :: 0x200D + +SPI_GETFOCUSBORDERWIDTH :: 0x200E +SPI_SETFOCUSBORDERWIDTH :: 0x200F +SPI_GETFOCUSBORDERHEIGHT :: 0x2010 +SPI_SETFOCUSBORDERHEIGHT :: 0x2011 + +SPI_GETFONTSMOOTHINGORIENTATION :: 0x2012 +SPI_SETFONTSMOOTHINGORIENTATION :: 0x2013 + +// constants for SPI_GETFONTSMOOTHINGORIENTATION and SPI_SETFONTSMOOTHINGORIENTATION: +FE_FONTSMOOTHINGORIENTATIONBGR :: 0x0000 +FE_FONTSMOOTHINGORIENTATIONRGB :: 0x0001 + +SPI_GETMINIMUMHITRADIUS :: 0x2014 +SPI_SETMINIMUMHITRADIUS :: 0x2015 +SPI_GETMESSAGEDURATION :: 0x2016 +SPI_SETMESSAGEDURATION :: 0x2017 + +SPI_GETCONTACTVISUALIZATION :: 0x2018 +SPI_SETCONTACTVISUALIZATION :: 0x2019 +// constants for SPI_GETCONTACTVISUALIZATION and SPI_SETCONTACTVISUALIZATION +CONTACTVISUALIZATION_OFF :: 0x0000 +CONTACTVISUALIZATION_ON :: 0x0001 +CONTACTVISUALIZATION_PRESENTATIONMODE :: 0x0002 + +SPI_GETGESTUREVISUALIZATION :: 0x201A +SPI_SETGESTUREVISUALIZATION :: 0x201B +// constants for SPI_GETGESTUREVISUALIZATION and SPI_SETGESTUREVISUALIZATION +GESTUREVISUALIZATION_OFF :: 0x0000 +GESTUREVISUALIZATION_ON :: 0x001F +GESTUREVISUALIZATION_TAP :: 0x0001 +GESTUREVISUALIZATION_DOUBLETAP :: 0x0002 +GESTUREVISUALIZATION_PRESSANDTAP :: 0x0004 +GESTUREVISUALIZATION_PRESSANDHOLD :: 0x0008 +GESTUREVISUALIZATION_RIGHTTAP :: 0x0010 + +SPI_GETMOUSEWHEELROUTING :: 0x201C +SPI_SETMOUSEWHEELROUTING :: 0x201D + +MOUSEWHEEL_ROUTING_FOCUS :: 0 +MOUSEWHEEL_ROUTING_HYBRID :: 1 +MOUSEWHEEL_ROUTING_MOUSE_POS :: 2 + +// Flags +SPIF_UPDATEINIFILE :: 0x0001 +SPIF_SENDWININICHANGE :: 0x0002 +SPIF_SENDCHANGE :: SPIF_SENDWININICHANGE diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index dd45df42a..6f42267db 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -114,10 +114,14 @@ foreign user32 { cy: c_int, uFlags: UINT, ) -> BOOL --- + MoveWindow :: proc(hWnd: HWND, X, Y, hWidth, hHeight: c_int, bRepaint: BOOL) -> BOOL --- GetSystemMetrics :: proc(nIndex: c_int) -> c_int --- AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL --- AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL --- + SystemParametersInfoA :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL --- + SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL --- + GetWindowDC :: proc(hWnd: HWND) -> HDC --- GetDC :: proc(hWnd: HWND) -> HDC --- ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> c_int --- From dd8b71e353bc72eecf95ca2ae45c437dc01e89bf Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 17:52:23 +0200 Subject: [PATCH 0642/1052] [pbm] WIP unit tests. --- core/image/netpbm/helpers.odin | 1 + core/image/netpbm/netpbm.odin | 138 +++++++++++++++++++++----- tests/core/image/test_core_image.odin | 58 ++++++++--- 3 files changed, 155 insertions(+), 42 deletions(-) diff --git a/core/image/netpbm/helpers.odin b/core/image/netpbm/helpers.odin index 5a3000a87..8c5cdd622 100644 --- a/core/image/netpbm/helpers.odin +++ b/core/image/netpbm/helpers.odin @@ -14,6 +14,7 @@ destroy :: proc(img: ^image.Image) -> bool { header_destroy(&info.header) free(info) img.metadata = nil + free(img) return true } diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index 54935d6c6..cccf7e865 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -31,19 +31,19 @@ load :: proc { load_from_buffer, } -load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: Image, err: Error) { +load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator data, ok := os.read_entire_file(filename); defer delete(data) if !ok { - err = .File_Not_Readable + err = .Unable_To_Read_File return } - return read_from_buffer(data) + return load_from_buffer(data) } -load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { +load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator header: Header; defer header_destroy(&header) @@ -51,7 +51,9 @@ load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: header, header_size = parse_header(data) or_return img_data := data[header_size:] - img = decode_image(header, img_data) or_return + + img = new(Image) + decode_image(img, header, img_data) or_return info := new(Info) info.header = header @@ -69,27 +71,42 @@ save :: proc { save_to_buffer, } -save_to_file :: proc(filename: string, img: Image, allocator := context.allocator) -> (err: Error) { +save_to_file :: proc(filename: string, img: ^Image, custom_info: Info = {}, allocator := context.allocator) -> (err: Error) { context.allocator = allocator data: []byte; defer delete(data) - data = write_to_buffer(img) or_return + data = save_to_buffer(img, custom_info) or_return if ok := os.write_entire_file(filename, data); !ok { - return .File_Not_Writable + return .Unable_To_Write_File } return Format_Error.None } -save_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: []byte, err: Error) { +save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context.allocator) -> (buffer: []byte, err: Error) { context.allocator = allocator - info, ok := img.metadata.(^image.Netpbm_Info) - if !ok { - err = image.General_Image_Error.Invalid_Input_Image - return + info: Info = {} + if custom_info.header.width > 0 { + // Custom info has been set, use it. + info = custom_info + } else { + img_info, ok := img.metadata.(^image.Netpbm_Info) + if !ok { + // image doesn't have .Netpbm info, guess it + auto_info, auto_info_found := autoselect_pbm_format_from_image(img) + if auto_info_found { + info = auto_info + } else { + return {}, .Invalid_Input_Image + } + } else { + // use info as stored on image + info = img_info^ + } } + // using info so we can just talk about the header using info @@ -103,11 +120,11 @@ save_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: [ if header.format in (PNM + PAM) { if header.maxval <= int(max(u8)) && img.depth != 8 \ || header.maxval > int(max(u8)) && header.maxval <= int(max(u16)) && img.depth != 16 { - err = Format_Error.Invalid_Image_Depth + err = .Invalid_Image_Depth return } } else if header.format in PFM && img.depth != 32 { - err = Format_Error.Invalid_Image_Depth + err = .Invalid_Image_Depth return } @@ -233,11 +250,11 @@ save_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: [ } case: - return data.buf[:], Format_Error.Invalid_Image_Depth + return data.buf[:], .Invalid_Image_Depth } case: - return data.buf[:], Format_Error.Invalid_Format + return data.buf[:], .Invalid_Format } return data.buf[:], Format_Error.None @@ -263,7 +280,7 @@ parse_header :: proc(data: []byte, allocator := context.allocator) -> (header: H } } - err = Format_Error.Invalid_Signature + err = .Invalid_Signature return } @@ -366,7 +383,7 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head // the spec needs the newline apparently if string(data[0:3]) != "P7\n" { - err = Format_Error.Invalid_Signature + err = .Invalid_Signature return } header.format = .P7 @@ -468,7 +485,7 @@ _parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Er header.format = .PF header.channels = 3 case: - err = Format_Error.Invalid_Signature + err = .Invalid_Signature return } @@ -531,18 +548,18 @@ _parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Er return } -decode_image :: proc(header: Header, data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { +decode_image :: proc(img: ^Image, header: Header, data: []byte, allocator := context.allocator) -> (err: Error) { + assert(img != nil) context.allocator = allocator - img = Image { - width = header.width, - height = header.height, - channels = header.channels, - depth = header.depth, - } + img.width = header.width + img.height = header.height + img.channels = header.channels + img.depth = header.depth buffer_size := image.compute_buffer_size(img.width, img.height, img.channels, img.depth) + when false { // we can check data size for binary formats if header.format in BINARY { if header.format == .P4 { @@ -558,6 +575,7 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato } } } + } // for ASCII and P4, we use length for the termination condition, so start at 0 // BINARY will be a simple memcopy so the buffer length should also be initialised @@ -665,4 +683,70 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato err = Format_Error.None return +} + +// Automatically try to select an appropriate format to save to based on `img.channel` and `img.depth` +autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, force_black_and_white := false, pfm_scale := f32(1.0)) -> (res: Info, ok: bool) { + /* + PBM (P1, P4): Portable Bit Map, stores black and white images (1 channel) + PGM (P2, P5): Portable Gray Map, stores greyscale images (1 channel, 1 or 2 bytes per value) + PPM (P3, P6): Portable Pixel Map, stores colour images (3 channel, 1 or 2 bytes per value) + PAM (P7 ): Portable Arbitrary Map, stores arbitrary channel images (1 or 2 bytes per value) + PFM (Pf, PF): Portable Float Map, stores floating-point images (Pf: 1 channel, PF: 3 channel) + + ASCII :: Formats{.P1, .P2, .P3} + */ + using res.header + + width = img.width + height = img.height + channels = img.channels + depth = img.depth + maxval = 255 if img.depth == 8 else 65535 + little_endian = true if ODIN_ENDIAN == .Little else false + + // Assume we'll find a suitable format + ok = true + + switch img.channels { + case 1: + // Must be Portable Float Map + if img.depth == 32 { + format = .Pf + return + } + + if force_black_and_white { + // Portable Bit Map + format = .P4 if prefer_binary else .P1 + maxval = 1 + return + } else { + // Portable Gray Map + format = .P5 if prefer_binary else .P2 + return + } + + case 3: + // Must be Portable Float Map + if img.depth == 32 { + format = .PF + return + } + + // Portable Pixel Map + format = .P6 if prefer_binary else .P3 + return + + case: + // Portable Arbitrary Map + if img.depth == 8 || img.depth == 16 { + format = .P7 + scale = pfm_scale + return + } + } + + // We couldn't find a suitable format + return {}, false } \ No newline at end of file diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index c328757e4..1ffd3b93d 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -13,6 +13,7 @@ import "core:testing" import "core:compress" import "core:image" +import pbm "core:image/netpbm" import "core:image/png" import "core:image/qoi" @@ -1506,26 +1507,53 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { passed &= test.hash == png_hash - // Roundtrip through QOI to test the QOI encoder and decoder. - if passed && img.depth == 8 && (img.channels == 3 || img.channels == 4) { - qoi_buffer: bytes.Buffer - defer bytes.buffer_destroy(&qoi_buffer) - qoi_save_err := qoi.save(&qoi_buffer, img) + if passed { + // Roundtrip through QOI to test the QOI encoder and decoder. + if img.depth == 8 && (img.channels == 3 || img.channels == 4) { + qoi_buffer: bytes.Buffer + defer bytes.buffer_destroy(&qoi_buffer) + qoi_save_err := qoi.save(&qoi_buffer, img) - error = fmt.tprintf("%v test %v QOI save failed with %v.", file.file, count, qoi_save_err) - expect(t, qoi_save_err == nil, error) + error = fmt.tprintf("%v test %v QOI save failed with %v.", file.file, count, qoi_save_err) + expect(t, qoi_save_err == nil, error) - if qoi_save_err == nil { - qoi_img, qoi_load_err := qoi.load(qoi_buffer.buf[:]) - defer qoi.destroy(qoi_img) + if qoi_save_err == nil { + qoi_img, qoi_load_err := qoi.load(qoi_buffer.buf[:]) + defer qoi.destroy(qoi_img) - error = fmt.tprintf("%v test %v QOI load failed with %v.", file.file, count, qoi_load_err) - expect(t, qoi_load_err == nil, error) + error = fmt.tprintf("%v test %v QOI load failed with %v.", file.file, count, qoi_load_err) + expect(t, qoi_load_err == nil, error) - qoi_hash := hash.crc32(qoi_img.pixels.buf[:]) - error = fmt.tprintf("%v test %v QOI load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, qoi_hash, png_hash, test.options) - expect(t, qoi_hash == png_hash, error) + qoi_hash := hash.crc32(qoi_img.pixels.buf[:]) + error = fmt.tprintf("%v test %v QOI load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, qoi_hash, png_hash, test.options) + expect(t, qoi_hash == png_hash, error) + } } + + // Roundtrip through PBM to test the PBM encoders and decoders - prefer binary + pbm_buf, pbm_save_err := pbm.save_to_buffer(img) + defer delete(pbm_buf) + + error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) + expect(t, pbm_save_err == nil, error) + + if pbm_save_err == nil { + // Try to load it again. + pbm_img, pbm_load_err := pbm.load(pbm_buf) + defer pbm.destroy(pbm_img) + + if pbm_load_err == nil { + fmt.printf("%v test %v PBM load worked with %v.\n", file.file, count, pbm_load_err) + } + error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) + expect(t, pbm_load_err == nil, error) + } + + // Roundtrip through PBM to test the PBM encoders and decoders - prefer ASCII + // pbm_info, pbm_format_selected = pbm.autoselect_pbm_format_from_image(img, false) + // fmt.printf("Autoselect PBM: %v (%v)\n", pbm_info, pbm_format_selected) + + } if .return_metadata in test.options { From 234d52986776812641a2766de40e63798b55c857 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 19:25:16 +0200 Subject: [PATCH 0643/1052] [pbm] WIP unit tests. part deux. --- tests/core/image/test_core_image.odin | 28 +++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 1ffd3b93d..93baa76ec 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -1534,6 +1534,9 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { pbm_buf, pbm_save_err := pbm.save_to_buffer(img) defer delete(pbm_buf) + filename := fmt.tprintf("%v-%v.ppm", file.file, count) + pbm.save_to_file(filename, img) + error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) expect(t, pbm_save_err == nil, error) @@ -1544,9 +1547,30 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { if pbm_load_err == nil { fmt.printf("%v test %v PBM load worked with %v.\n", file.file, count, pbm_load_err) + + pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) + if pbm_hash == png_hash { + fmt.printf("\t%v test %v PBM load hash %08x matched PNG's\n", file.file, count, png_hash) + } else { + if img.width != pbm_img.width || img.height != pbm_img.height || img.channels != pbm_img.channels || img.depth != pbm_img.depth { + fmt.printf("\tHash failed. IMG: %v, %v, %v, %v PBM: %v, %v, %v, %v\n", img.width, img.height, img.channels, img.depth, pbm_img.width, pbm_img.height, pbm_img.channels, pbm_img.depth) + } else if len(img.pixels.buf) != len(pbm_img.pixels.buf) { + fmt.printf("\tLengths differ. IMG: %v PBM: %v\n", len(img.pixels.buf), len(pbm_img.pixels.buf)) + } else if file.file[:3] == "bas" { + for v, i in img.pixels.buf { + if v != pbm_img.pixels.buf[i] { + fmt.printf("\tChannels: %v, Depth: %v, Pixel %v differs. PNG: %v, PBM: %v\n", img.channels, img.depth, i, img.pixels.buf[i:][:4], pbm_img.pixels.buf[i:][:4]) + break + } + } + } + // error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) + // expect(t, pbm_hash == png_hash, error) + } + } else { + // error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) + // expect(t, pbm_load_err == nil, error) } - error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) - expect(t, pbm_load_err == nil, error) } // Roundtrip through PBM to test the PBM encoders and decoders - prefer ASCII From 9e694523277b75a44e0dc58dafec910c2fa0e8f6 Mon Sep 17 00:00:00 2001 From: bkrypt <4868093+bkrypt@users.noreply.github.com> Date: Sat, 30 Apr 2022 20:42:42 +0200 Subject: [PATCH 0644/1052] Remove unnecessary value (`count`) from enum --- vendor/miniaudio/common.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index d7b901714..1d64dc182 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -193,7 +193,6 @@ format :: enum c.int { s24 = 3, /* Tightly packed. 3 bytes per sample. */ s32 = 4, f32 = 5, - count, } standard_sample_rate :: enum u32 { From be9b935953c50b7a9e8ee73442717335155ccb03 Mon Sep 17 00:00:00 2001 From: bkrypt <4868093+bkrypt@users.noreply.github.com> Date: Sat, 30 Apr 2022 20:43:22 +0200 Subject: [PATCH 0645/1052] Fix indentation --- vendor/miniaudio/device_io_types.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vendor/miniaudio/device_io_types.odin b/vendor/miniaudio/device_io_types.odin index b3ecb2301..5a2c4bc73 100644 --- a/vendor/miniaudio/device_io_types.odin +++ b/vendor/miniaudio/device_io_types.odin @@ -19,11 +19,11 @@ SUPPORT_CUSTOM :: true SUPPORT_NULL :: true // ODIN_OS != .Emscripten device_state :: enum c.int { - uninitialized = 0, - stopped = 1, /* The device's default state after initialization. */ - started = 2, /* The device is started and is requesting and/or delivering audio data. */ - starting = 3, /* Transitioning from a stopped state to started. */ - stopping = 4, /* Transitioning from a started state to stopped. */ + uninitialized = 0, + stopped = 1, /* The device's default state after initialization. */ + started = 2, /* The device is started and is requesting and/or delivering audio data. */ + starting = 3, /* Transitioning from a stopped state to started. */ + stopping = 4, /* Transitioning from a started state to stopped. */ } @@ -985,7 +985,7 @@ device :: struct { noPreSilencedOutputBuffer: b8, noClip: b8, noDisableDenormals: b8, - noFixedSizedCallback: b8, + noFixedSizedCallback: b8, masterVolumeFactor: f32, /*atomic*/ /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ duplexRB: duplex_rb, /* Intermediary buffer for duplex device on asynchronous backends. */ resampling: struct { From 8bd16c32f3bbe724321127fcaaf798a1928cf0fe Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 21:00:32 +0200 Subject: [PATCH 0646/1052] [pbm] Fixes. --- core/image/netpbm/helpers.odin | 5 +- core/image/netpbm/netpbm.odin | 45 ++++++++-------- tests/core/image/test_core_image.odin | 76 ++++++++++++++------------- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/core/image/netpbm/helpers.odin b/core/image/netpbm/helpers.odin index 8c5cdd622..2fbd32ecc 100644 --- a/core/image/netpbm/helpers.odin +++ b/core/image/netpbm/helpers.odin @@ -6,15 +6,16 @@ import "core:image" destroy :: proc(img: ^image.Image) -> bool { if img == nil do return false + defer free(img) + bytes.buffer_destroy(&img.pixels) + //! TEMP CAST info, ok := img.metadata.(^image.Netpbm_Info) if !ok do return false - bytes.buffer_destroy(&img.pixels) header_destroy(&info.header) free(info) img.metadata = nil - free(img) return true } diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index cccf7e865..768c06110 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -46,13 +46,13 @@ load_from_file :: proc(filename: string, allocator := context.allocator) -> (img load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator + img = new(Image) + header: Header; defer header_destroy(&header) header_size: int header, header_size = parse_header(data) or_return img_data := data[header_size:] - - img = new(Image) decode_image(img, header, img_data) or_return info := new(Info) @@ -62,8 +62,7 @@ load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: } img.metadata = info - err = Format_Error.None - return + return img, nil } save :: proc { @@ -140,8 +139,14 @@ save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context fmt.sbprintf(&data, "%i\n", header.maxval) } } else if header.format in PAM { - fmt.sbprintf(&data, "WIDTH %i\nHEIGHT %i\nMAXVAL %i\nDEPTH %i\nTUPLTYPE %s\nENDHDR\n", - img.width, img.height, header.maxval, img.channels, header.tupltype) + if len(header.tupltype) > 0 { + fmt.sbprintf(&data, "WIDTH %i\nHEIGHT %i\nMAXVAL %i\nDEPTH %i\nTUPLTYPE %s\nENDHDR\n", + img.width, img.height, header.maxval, img.channels, header.tupltype) + } else { + fmt.sbprintf(&data, "WIDTH %i\nHEIGHT %i\nMAXVAL %i\nDEPTH %i\nENDHDR\n", + img.width, img.height, header.maxval, img.channels) + } + } else if header.format in PFM { scale := -header.scale if header.little_endian else header.scale fmt.sbprintf(&data, "%i %i\n%f\n", img.width, img.height, scale) @@ -369,10 +374,12 @@ _parse_header_pnm :: proc(data: []byte) -> (header: Header, length: int, err: Er if header.width < 1 \ || header.height < 1 \ || header.maxval < 1 || header.maxval > int(max(u16)) { - err = Format_Error.Invalid_Header_Value + fmt.printf("[pnm] Header: {{width = %v, height = %v, maxval: %v}}\n", header.width, header.height, header.maxval) + err = .Invalid_Header_Value return } + length -= 1 err = Format_Error.None return } @@ -427,7 +434,7 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head case "TUPLTYPE": if len(value) == 0 { - err = Format_Error.Invalid_Header_Value + err = .Invalid_Header_Value return } @@ -462,6 +469,7 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head || header.height < 1 \ || header.maxval < 1 \ || header.maxval > int(max(u16)) { + fmt.printf("[pam] Header: {{width = %v, height = %v, maxval: %v}}\n", header.width, header.height, header.maxval) err = Format_Error.Invalid_Header_Value return } @@ -540,7 +548,8 @@ _parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Er if header.width < 1 \ || header.height < 1 \ || header.scale == 0.0 { - err = Format_Error.Invalid_Header_Value + fmt.printf("[pfm] Header: {{width = %v, height = %v, scale: %v}}\n", header.width, header.height, header.scale) + err = .Invalid_Header_Value return } @@ -559,23 +568,13 @@ decode_image :: proc(img: ^Image, header: Header, data: []byte, allocator := con buffer_size := image.compute_buffer_size(img.width, img.height, img.channels, img.depth) - when false { // we can check data size for binary formats if header.format in BINARY { - if header.format == .P4 { - p4_size := (img.width / 8 + 1) * img.height - if len(data) < p4_size { - err = Format_Error.Buffer_Too_Small - return - } - } else { - if len(data) < buffer_size { - err = Format_Error.Buffer_Too_Small - return - } + if len(data) < buffer_size { + fmt.printf("len(data): %v, buffer size: %v\n", len(data), buffer_size) + return .Buffer_Too_Small } } - } // for ASCII and P4, we use length for the termination condition, so start at 0 // BINARY will be a simple memcopy so the buffer length should also be initialised @@ -605,7 +604,7 @@ decode_image :: proc(img: ^Image, header: Header, data: []byte, allocator := con // Simple binary case .P5, .P6, .P7, .Pf, .PF: - mem.copy(raw_data(img.pixels.buf), raw_data(data), buffer_size) + copy(img.pixels.buf[:], data[:]) // convert to native endianness if header.format in PFM { diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 93baa76ec..f1f1e1244 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -1530,54 +1530,56 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { } } - // Roundtrip through PBM to test the PBM encoders and decoders - prefer binary - pbm_buf, pbm_save_err := pbm.save_to_buffer(img) - defer delete(pbm_buf) + { + // Roundtrip through PBM to test the PBM encoders and decoders - prefer binary + pbm_buf, pbm_save_err := pbm.save_to_buffer(img) + defer delete(pbm_buf) - filename := fmt.tprintf("%v-%v.ppm", file.file, count) - pbm.save_to_file(filename, img) + error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) + expect(t, pbm_save_err == nil, error) - error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) - expect(t, pbm_save_err == nil, error) + if pbm_save_err == nil { + // Try to load it again. + pbm_img, pbm_load_err := pbm.load(pbm_buf) + defer pbm.destroy(pbm_img) - if pbm_save_err == nil { - // Try to load it again. - pbm_img, pbm_load_err := pbm.load(pbm_buf) - defer pbm.destroy(pbm_img) + error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) + expect(t, pbm_load_err == nil, error) - if pbm_load_err == nil { - fmt.printf("%v test %v PBM load worked with %v.\n", file.file, count, pbm_load_err) + if pbm_load_err == nil { + pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) - pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) - if pbm_hash == png_hash { - fmt.printf("\t%v test %v PBM load hash %08x matched PNG's\n", file.file, count, png_hash) - } else { - if img.width != pbm_img.width || img.height != pbm_img.height || img.channels != pbm_img.channels || img.depth != pbm_img.depth { - fmt.printf("\tHash failed. IMG: %v, %v, %v, %v PBM: %v, %v, %v, %v\n", img.width, img.height, img.channels, img.depth, pbm_img.width, pbm_img.height, pbm_img.channels, pbm_img.depth) - } else if len(img.pixels.buf) != len(pbm_img.pixels.buf) { - fmt.printf("\tLengths differ. IMG: %v PBM: %v\n", len(img.pixels.buf), len(pbm_img.pixels.buf)) - } else if file.file[:3] == "bas" { - for v, i in img.pixels.buf { - if v != pbm_img.pixels.buf[i] { - fmt.printf("\tChannels: %v, Depth: %v, Pixel %v differs. PNG: %v, PBM: %v\n", img.channels, img.depth, i, img.pixels.buf[i:][:4], pbm_img.pixels.buf[i:][:4]) - break - } - } - } - // error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) - // expect(t, pbm_hash == png_hash, error) + error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) + expect(t, pbm_hash == png_hash, error) } - } else { - // error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) - // expect(t, pbm_load_err == nil, error) } } - // Roundtrip through PBM to test the PBM encoders and decoders - prefer ASCII - // pbm_info, pbm_format_selected = pbm.autoselect_pbm_format_from_image(img, false) - // fmt.printf("Autoselect PBM: %v (%v)\n", pbm_info, pbm_format_selected) + { + // Roundtrip through PBM to test the PBM encoders and decoders - prefer ASCII + pbm_info, pbm_format_selected := pbm.autoselect_pbm_format_from_image(img, false) + pbm_buf, pbm_save_err := pbm.save_to_buffer(img, pbm_info) + defer delete(pbm_buf) + error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) + expect(t, pbm_save_err == nil, error) + if pbm_save_err == nil { + // Try to load it again. + pbm_img, pbm_load_err := pbm.load(pbm_buf) + defer pbm.destroy(pbm_img) + + error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) + expect(t, pbm_load_err == nil, error) + + if pbm_load_err == nil { + pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) + + error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) + expect(t, pbm_hash == png_hash, error) + } + } + } } if .return_metadata in test.options { From 7a032cf9f9818cfb566e91b7f5926bd7278daf07 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 21:57:14 +0200 Subject: [PATCH 0647/1052] [pbm] Also test PFM formats. --- tests/core/image/test_core_image.odin | 109 ++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 14 deletions(-) diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index f1f1e1244..2ecc67151 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -1558,25 +1558,106 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { { // Roundtrip through PBM to test the PBM encoders and decoders - prefer ASCII pbm_info, pbm_format_selected := pbm.autoselect_pbm_format_from_image(img, false) - pbm_buf, pbm_save_err := pbm.save_to_buffer(img, pbm_info) - defer delete(pbm_buf) - error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) - expect(t, pbm_save_err == nil, error) + // We already tested the binary formats above. + if pbm_info.header.format in pbm.ASCII { + pbm_buf, pbm_save_err := pbm.save_to_buffer(img, pbm_info) + defer delete(pbm_buf) - if pbm_save_err == nil { - // Try to load it again. - pbm_img, pbm_load_err := pbm.load(pbm_buf) - defer pbm.destroy(pbm_img) + error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) + expect(t, pbm_save_err == nil, error) - error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) - expect(t, pbm_load_err == nil, error) + if pbm_save_err == nil { + // Try to load it again. + pbm_img, pbm_load_err := pbm.load(pbm_buf) + defer pbm.destroy(pbm_img) - if pbm_load_err == nil { - pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) + error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) + expect(t, pbm_load_err == nil, error) - error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) - expect(t, pbm_hash == png_hash, error) + if pbm_load_err == nil { + pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) + + error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) + expect(t, pbm_hash == png_hash, error) + } + } + } + } + + { + // We still need to test Portable Float Maps + if (img.channels == 1 || img.channels == 3) && (img.depth == 8 || img.depth == 16) { + + // Make temporary float image + float_img := new(image.Image) + defer png.destroy(float_img) + + float_img.width = img.width + float_img.height = img.height + float_img.channels = img.channels + float_img.depth = 32 + + buffer_size := image.compute_buffer_size(img.width, img.height, img.channels, 32) + resize(&float_img.pixels.buf, buffer_size) + + pbm_info := pbm.Info { + header = { + width = img.width, + height = img.height, + channels = img.channels, + depth = img.depth, + maxval = 255 if img.depth == 8 else 65535, + little_endian = true if ODIN_ENDIAN == .Little else false, + scale = 1.0, + format = .Pf if img.channels == 1 else .PF, + }, + } + + // Transform data... + orig_float := mem.slice_data_cast([]f32, float_img.pixels.buf[:]) + + switch img.depth { + case 8: + for v, i in img.pixels.buf { + orig_float[i] = f32(v) / f32(256) + } + case 16: + wide := mem.slice_data_cast([]u16, img.pixels.buf[:]) + for v, i in wide { + orig_float[i] = f32(v) / f32(65536) + } + } + + float_pbm_buf, float_pbm_save_err := pbm.save_to_buffer(float_img, pbm_info) + defer delete(float_pbm_buf) + + error = fmt.tprintf("%v test %v save as PFM failed with %v", file.file, count, float_pbm_save_err) + expect(t, float_pbm_save_err == nil, error) + + if float_pbm_save_err == nil { + // Load float image and compare. + float_pbm_img, float_pbm_load_err := pbm.load(float_pbm_buf) + defer pbm.destroy(float_pbm_img) + + error = fmt.tprintf("%v test %v PFM load failed with %v", file.file, count, float_pbm_load_err) + expect(t, float_pbm_load_err == nil, error) + + load_float := mem.slice_data_cast([]f32, float_pbm_img.pixels.buf[:]) + + error = fmt.tprintf("%v test %v PFM load returned %v floats, expected %v", file.file, count, len(load_float), len(orig_float)) + expect(t, len(load_float) == len(orig_float), error) + + // Compare floats + equal := true + for orig, i in orig_float { + if orig != load_float[i] { + equal = false + break + } + } + error = fmt.tprintf("%v test %v PFM loaded floats to match", file.file, count) + expect(t, equal, error) } } } From 2081f8fcd66efa71ab526d10751bbe882be228ba Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 22:04:47 +0200 Subject: [PATCH 0648/1052] [tests/core/image] Remove old crappy PPM writer. --- tests/core/image/test_core_image.odin | 201 -------------------------- 1 file changed, 201 deletions(-) diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 2ecc67151..9c9831199 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -27,7 +27,6 @@ import "core:time" import "core:runtime" -WRITE_PPM_ON_FAIL :: #config(WRITE_PPM_ON_FAIL, false) TEST_SUITE_PATH :: "assets/PNG" TEST_count := 0 @@ -1879,12 +1878,6 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { } } - if WRITE_PPM_ON_FAIL && !passed && err == nil { // It loaded but had an error in its compares. - testing.logf(t, "Test failed, writing ppm/%v-%v.ppm to help debug.\n", file.file, count) - output := fmt.tprintf("ppm/%v-%v.ppm", file.file, count) - write_image_as_ppm(output, img) - } - png.destroy(img) for _, v in track.allocation_map { @@ -1895,198 +1888,4 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { } return -} - -// Crappy PPM writer used during testing. Don't use in production. -write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: bool) { - - _bg :: proc(x, y: int, high := true) -> (res: [3]u16) { - if high { - l := u16(30 * 256 + 30) - - if (x & 4 == 0) ~ (y & 4 == 0) { - res = [3]u16{l, l, l} - } else { - res = [3]u16{l >> 1, l >> 1, l >> 1} - } - } else { - if (x & 4 == 0) ~ (y & 4 == 0) { - res = [3]u16{30, 30, 30} - } else { - res = [3]u16{15, 15, 15} - } - } - return - } - - using image - using os - - flags: int = O_WRONLY|O_CREATE|O_TRUNC - - img := image - - // PBM 16-bit images are big endian - when ODIN_ENDIAN == .Little { - if img.depth == 16 { - // The pixel components are in Big Endian. Let's byteswap back. - input := mem.slice_data_cast([]u16, img.pixels.buf[:]) - output := mem.slice_data_cast([]u16be, img.pixels.buf[:]) - #no_bounds_check for v, i in input { - output[i] = u16be(v) - } - } - } - - pix := bytes.buffer_to_bytes(&img.pixels) - - if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) { - return false - } - - mode: int = 0 - when ODIN_OS == .Linux || ODIN_OS == .Darwin { - // NOTE(justasd): 644 (owner read, write; group read; others read) - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH - } - - fd, err := open(filename, flags, mode) - if err != 0 { - return false - } - defer close(fd) - - write_string(fd, - fmt.tprintf("P6\n%v %v\n%v\n", width, height, (1 << uint(depth) -1)), - ) - - if channels == 3 { - // We don't handle transparency here... - write_ptr(fd, raw_data(pix), len(pix)) - } else { - bpp := depth == 16 ? 2 : 1 - bytes_needed := width * height * 3 * bpp - - op := bytes.Buffer{} - bytes.buffer_init_allocator(&op, bytes_needed, bytes_needed) - defer bytes.buffer_destroy(&op) - - if channels == 1 { - if depth == 16 { - assert(len(pix) == width * height * 2) - p16 := mem.slice_data_cast([]u16, pix) - o16 := mem.slice_data_cast([]u16, op.buf[:]) - #no_bounds_check for len(p16) != 0 { - r := u16(p16[0]) - o16[0] = r - o16[1] = r - o16[2] = r - p16 = p16[1:] - o16 = o16[3:] - } - } else { - o := 0 - for i := 0; i < len(pix); i += 1 { - r := pix[i] - op.buf[o ] = r - op.buf[o+1] = r - op.buf[o+2] = r - o += 3 - } - } - write_ptr(fd, raw_data(op.buf), len(op.buf)) - } else if channels == 2 { - if depth == 16 { - p16 := mem.slice_data_cast([]u16, pix) - o16 := mem.slice_data_cast([]u16, op.buf[:]) - - bgcol := img.background - - #no_bounds_check for len(p16) != 0 { - r := f64(u16(p16[0])) - bg: f64 - if bgcol != nil { - v := bgcol.([3]u16)[0] - bg = f64(v) - } - a := f64(u16(p16[1])) / 65535.0 - l := (a * r) + (1 / a) * bg - - o16[0] = u16(l) - o16[1] = u16(l) - o16[2] = u16(l) - - p16 = p16[2:] - o16 = o16[3:] - } - } else { - o := 0 - for i := 0; i < len(pix); i += 2 { - r := pix[i]; a := pix[i+1]; a1 := f32(a) / 255.0 - c := u8(f32(r) * a1) - op.buf[o ] = c - op.buf[o+1] = c - op.buf[o+2] = c - o += 3 - } - } - write_ptr(fd, raw_data(op.buf), len(op.buf)) - } else if channels == 4 { - if depth == 16 { - p16 := mem.slice_data_cast([]u16be, pix) - o16 := mem.slice_data_cast([]u16be, op.buf[:]) - - i := 0 - for len(p16) > 0 { - i += 1 - x := i % width - y := i / width - bg := _bg(x, y, true) - - r := f32(p16[0]) - g := f32(p16[1]) - b := f32(p16[2]) - a := f32(p16[3]) / 65535.0 - - lr := (a * r) + (1 / a) * f32(bg[0]) - lg := (a * g) + (1 / a) * f32(bg[1]) - lb := (a * b) + (1 / a) * f32(bg[2]) - - o16[0] = u16be(lr) - o16[1] = u16be(lg) - o16[2] = u16be(lb) - - p16 = p16[4:] - o16 = o16[3:] - } - } else { - o := 0 - - for i := 0; i < len(pix); i += 4 { - - x := (i / 4) % width - y := i / width / 4 - _b := _bg(x, y, false) - bgcol := [3]u8{u8(_b[0]), u8(_b[1]), u8(_b[2])} - - r := f32(pix[i]) - g := f32(pix[i+1]) - b := f32(pix[i+2]) - a := f32(pix[i+3]) / 255.0 - - lr := u8(f32(r) * a + (1 / a) * f32(bgcol[0])) - lg := u8(f32(g) * a + (1 / a) * f32(bgcol[1])) - lb := u8(f32(b) * a + (1 / a) * f32(bgcol[2])) - op.buf[o ] = lr - op.buf[o+1] = lg - op.buf[o+2] = lb - o += 3 - } - } - write_ptr(fd, raw_data(op.buf), len(op.buf)) - } else { - return false - } - } - return true } \ No newline at end of file From 6ade9acc4d220a9912fb7d88ae26d82131351e12 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 30 Apr 2022 22:54:53 +0200 Subject: [PATCH 0649/1052] [pbm] Remove stray comment. --- core/image/netpbm/helpers.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/image/netpbm/helpers.odin b/core/image/netpbm/helpers.odin index 2fbd32ecc..016f9453e 100644 --- a/core/image/netpbm/helpers.odin +++ b/core/image/netpbm/helpers.odin @@ -9,7 +9,6 @@ destroy :: proc(img: ^image.Image) -> bool { defer free(img) bytes.buffer_destroy(&img.pixels) - //! TEMP CAST info, ok := img.metadata.(^image.Netpbm_Info) if !ok do return false From b2fdb881eb6734b973b4bb0a8ff04a3a775c9454 Mon Sep 17 00:00:00 2001 From: hikari Date: Sun, 1 May 2022 13:21:28 +0300 Subject: [PATCH 0650/1052] sys/windows: remove A variant for one SystemParametersInfoW --- core/sys/windows/user32.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 6f42267db..f83713a33 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -119,7 +119,6 @@ foreign user32 { AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL --- AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL --- - SystemParametersInfoA :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL --- SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL --- GetWindowDC :: proc(hWnd: HWND) -> HDC --- From 335b7242099153f0777ce5417b8ef8261de03ec8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 1 May 2022 12:47:05 +0200 Subject: [PATCH 0651/1052] [xxh3] Fix flaws in streaming implementation --- core/hash/xxhash/streaming.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/hash/xxhash/streaming.odin b/core/hash/xxhash/streaming.odin index d6df1089f..68a4920a5 100644 --- a/core/hash/xxhash/streaming.odin +++ b/core/hash/xxhash/streaming.odin @@ -52,9 +52,6 @@ XXH3_128_reset_with_seed :: proc(state: ^XXH3_state, seed: XXH64_hash) -> (err: XXH3_64_reset_with_seed :: XXH3_128_reset_with_seed XXH3_128_update :: proc(state: ^XXH3_state, input: []u8) -> (err: Error) { - if len(input) < XXH3_MIDSIZE_MAX { - return .Error - } return XXH3_update(state, input, XXH3_accumulate_512, XXH3_scramble_accumulator) } XXH3_64_update :: XXH3_128_update @@ -127,6 +124,7 @@ XXH3_create_state :: proc(allocator := context.allocator) -> (res: ^XXH3_state, err = nil if mem_error == nil else .Error XXH3_init_state(state) + XXH3_128_reset(state) return state, nil } @@ -234,7 +232,9 @@ XXH3_update :: #force_inline proc( */ if state.buffered_size > 0 { load_size := int(XXH3_INTERNAL_BUFFER_SIZE - state.buffered_size) - mem_copy(&state.buffer[state.buffered_size], &input[0], load_size) + + state_ptr := rawptr(uintptr(raw_data(state.buffer[:])) + uintptr(state.buffered_size)) + mem_copy(state_ptr, raw_data(input), load_size) input = input[load_size:] XXH3_consume_stripes( From 74d3bcec05e693889b075ef64d88ee3ef985d13c Mon Sep 17 00:00:00 2001 From: WalterPlinge <22519813+WalterPlinge@users.noreply.github.com> Date: Sun, 1 May 2022 21:29:09 +0100 Subject: [PATCH 0652/1052] Fixed the depth values in the doc file, made some info more clear --- core/image/netpbm/doc.odin | 19 ++++++++++--------- core/image/netpbm/netpbm.odin | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/core/image/netpbm/doc.odin b/core/image/netpbm/doc.odin index baeb99968..1b5b46856 100644 --- a/core/image/netpbm/doc.odin +++ b/core/image/netpbm/doc.odin @@ -6,24 +6,25 @@ Formats: PAM (P7 ): Portable Arbitrary Map, stores arbitrary channel images (1 or 2 bytes per value) PFM (Pf, PF): Portable Float Map, stores floating-point images (Pf: 1 channel, PF: 3 channel) -Reading +Reading: All formats fill out header fields `format`, `width`, `height`, `channels`, `depth` Specific formats use more fields - PGM, PPM, and PAM set `maxval` - PAM also sets `tupltype`, and is able to set `channels` to an arbitrary value - PFM sets `scale` and `little_endian` + PGM, PPM, and PAM set `maxval` (maximum of 65535) + PAM sets `tupltype` if there is one, and can set `channels` to any value (not just 1 or 3) + PFM sets `scale` (float equivalent of `maxval`) and `little_endian` (endianness of stored floats) Currently doesn't support reading multiple images from one binary-format file -Writing +Writing: + You can use your own `Netpbm_Info` struct to control how images are written All formats require the header field `format` to be specified Additional header fields are required for specific formats - PGM, PPM, and PAM require `maxval` + PGM, PPM, and PAM require `maxval` (maximum of 65535) PAM also uses `tupltype`, though it may be left as default (empty or nil string) - PFM requires `scale` and `little_endian`, though the latter may be left untouched (default is false) + PFM requires `scale`, and optionally `little_endian` Some syntax differences from the specifications: - `channels` stores what the PAM specification calls `depth` - `depth` instead stores how many bytes will fit `maxval` (should only be 1, 2, or 4) + `channels` stores the number of values per pixel, what the PAM specification calls `depth` + `depth` instead is the number of bits for a single value (32 for PFM, 16 or 8 otherwise) `scale` and `little_endian` are separated, so the `header` will always store a positive `scale` `little_endian` will only be true for a negative `scale` PFM, every other format will be false `little_endian` only describes the netpbm data being read/written, the image buffer will be native diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index 768c06110..9574faa26 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -109,7 +109,7 @@ save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context // using info so we can just talk about the header using info - //? validation + // validation if header.format in (PBM + PGM + Formats{.Pf}) && img.channels != 1 \ || header.format in (PPM + Formats{.PF}) && img.channels != 3 { err = .Invalid_Number_Of_Channels From 10a311092b3a025921bdf62710972bcd91b57730 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 May 2022 23:15:06 +0100 Subject: [PATCH 0653/1052] Add basic arm32 ABI support (linux_arm32) --- src/build_settings.cpp | 15 ++++++- src/llvm_abi.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 89d370144..1619c342b 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -30,6 +30,7 @@ enum TargetArchKind : u16 { TargetArch_amd64, TargetArch_i386, + TargetArch_arm32, TargetArch_arm64, TargetArch_wasm32, TargetArch_wasm64, @@ -75,6 +76,7 @@ String target_arch_names[TargetArch_COUNT] = { str_lit(""), str_lit("amd64"), str_lit("i386"), + str_lit("arm32"), str_lit("arm64"), str_lit("wasm32"), str_lit("wasm64"), @@ -98,6 +100,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = { TargetEndian_Little, TargetEndian_Little, TargetEndian_Little, + TargetEndian_Little, }; #ifndef ODIN_VERSION_RAW @@ -367,7 +370,16 @@ gb_global TargetMetrics target_linux_arm64 = { 8, 16, str_lit("aarch64-linux-elf"), - str_lit("e-m:e-i8:8:32-i16:32-i64:64-i128:128-n32:64-S128"), + str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"), +}; + +gb_global TargetMetrics target_linux_arm32 = { + TargetOs_linux, + TargetArch_arm32, + 4, + 8, + str_lit("aapcs-linux-gnu"), + str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"), }; gb_global TargetMetrics target_darwin_amd64 = { @@ -483,6 +495,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("linux_i386"), &target_linux_i386 }, { str_lit("linux_amd64"), &target_linux_amd64 }, { str_lit("linux_arm64"), &target_linux_arm64 }, + { str_lit("linux_arm32"), &target_linux_arm32 }, { str_lit("windows_i386"), &target_windows_i386 }, { str_lit("windows_amd64"), &target_windows_amd64 }, { str_lit("freebsd_i386"), &target_freebsd_i386 }, diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 07d2dd6e3..c6ff12f95 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -516,6 +516,10 @@ namespace lbAbiAmd64SysV { bool is_register(LLVMTypeRef type) { LLVMTypeKind kind = LLVMGetTypeKind(type); + i64 sz = lb_sizeof(type); + if (sz == 0) { + return false; + } switch (kind) { case LLVMIntegerTypeKind: case LLVMHalfTypeKind: @@ -1164,6 +1168,88 @@ namespace lbAbiWasm32 { } } +namespace lbAbiArm32 { + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention); + lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined); + + LB_ABI_INFO(abi_info) { + lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + ft->ctx = c; + ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention); + ft->ret = compute_return_type(c, return_type, return_is_defined); + ft->calling_convention = calling_convention; + return ft; + } + + bool is_register(LLVMTypeRef type, bool is_return) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMHalfTypeKind: + case LLVMFloatTypeKind: + case LLVMDoubleTypeKind: + return true; + case LLVMIntegerTypeKind: + return lb_sizeof(type) <= 8; + case LLVMFunctionTypeKind: + return true; + case LLVMPointerTypeKind: + return true; + case LLVMVectorTypeKind: + return true; + } + return false; + } + + lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) { + LLVMAttributeRef attr = nullptr; + LLVMTypeRef i1 = LLVMInt1TypeInContext(c); + if (type == i1) { + attr = lb_create_enum_attribute(c, "zeroext"); + } + return lb_arg_type_direct(type, nullptr, nullptr, attr); + } + + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) { + auto args = array_make(heap_allocator(), arg_count); + + for (unsigned i = 0; i < arg_count; i++) { + LLVMTypeRef t = arg_types[i]; + if (is_register(t, false)) { + args[i] = non_struct(c, t, false); + } else { + i64 sz = lb_sizeof(t); + i64 a = lb_alignof(t); + if (is_calling_convention_odin(calling_convention) && sz > 8) { + // Minor change to improve performance using the Odin calling conventions + args[i] = lb_arg_type_indirect(t, nullptr); + } else if (a <= 4) { + unsigned n = cast(unsigned)((sz + 3) / 4); + args[i] = lb_arg_type_direct(LLVMArrayType(LLVMIntTypeInContext(c, 32), n)); + } else { + unsigned n = cast(unsigned)((sz + 7) / 8); + args[i] = lb_arg_type_direct(LLVMArrayType(LLVMIntTypeInContext(c, 64), n)); + } + } + } + return args; + } + + lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) { + if (!return_is_defined) { + return lb_arg_type_direct(LLVMVoidTypeInContext(c)); + } else if (!is_register(return_type, true)) { + switch (lb_sizeof(return_type)) { + case 1: return lb_arg_type_direct(LLVMIntTypeInContext(c, 8), return_type, nullptr, nullptr); + case 2: return lb_arg_type_direct(LLVMIntTypeInContext(c, 16), return_type, nullptr, nullptr); + case 3: case 4: return lb_arg_type_direct(LLVMIntTypeInContext(c, 32), return_type, nullptr, nullptr); + } + LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); + return lb_arg_type_indirect(return_type, attr); + } + return non_struct(c, return_type, true); + } +}; + LB_ABI_INFO(lb_get_abi_info) { switch (calling_convention) { @@ -1203,6 +1289,8 @@ LB_ABI_INFO(lb_get_abi_info) { } case TargetArch_i386: return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + case TargetArch_arm32: + return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); case TargetArch_arm64: return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); case TargetArch_wasm32: From 0e27b27b81f4b51ae4691d4dc84ae130867b3f67 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 May 2022 23:28:32 +0100 Subject: [PATCH 0654/1052] Fix building issues with arm32 --- src/build_settings.cpp | 46 +++++++++++++++++++++++++----------------- src/checker.cpp | 1 + 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 1619c342b..e596e54e5 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -378,7 +378,7 @@ gb_global TargetMetrics target_linux_arm32 = { TargetArch_arm32, 4, 8, - str_lit("aapcs-linux-gnu"), + str_lit("arm-linux-gnu"), str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"), }; @@ -1127,6 +1127,15 @@ void init_build_context(TargetMetrics *cross_target) { bc->link_flags = str_lit("-arch x86 "); break; } + } else if (bc->metrics.arch == TargetArch_arm32) { + switch (bc->metrics.os) { + case TargetOs_linux: + bc->link_flags = str_lit("-arch arm "); + break; + default: + gb_printf_err("Compiler Error: Unsupported architecture\n"); + gb_exit(1); + } } else if (bc->metrics.arch == TargetArch_arm64) { switch (bc->metrics.os) { case TargetOs_darwin: @@ -1214,27 +1223,28 @@ bool init_build_paths(String init_filename) { return false; } - GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); - GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - - if (find_result.windows_sdk_root.len > 0) { - bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); - } - if (find_result.windows_sdk_um_library_path.len > 0) { - bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path); - } + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - if (find_result.windows_sdk_ucrt_library_path.len > 0) { - bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path); - } + if (find_result.windows_sdk_root.len > 0) { + bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); + } - if (find_result.vs_exe_path.len > 0) { - bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path); - } + if (find_result.windows_sdk_um_library_path.len > 0) { + bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path); + } - if (find_result.vs_library_path.len > 0) { - bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path); + if (find_result.windows_sdk_ucrt_library_path.len > 0) { + bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path); + } + + if (find_result.vs_exe_path.len > 0) { + bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path); + } + + if (find_result.vs_library_path.len > 0) { + bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path); + } } gb_free(ha, find_result.windows_sdk_root.text); diff --git a/src/checker.cpp b/src/checker.cpp index 1bb786ea1..1e33c6e9d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -944,6 +944,7 @@ void init_universal(void) { {"Unknown", TargetArch_Invalid}, {"amd64", TargetArch_amd64}, {"i386", TargetArch_i386}, + {"arm32", TargetArch_arm32}, {"arm64", TargetArch_arm64}, {"wasm32", TargetArch_wasm32}, {"wasm64", TargetArch_wasm64}, From 18ad6c33ef896fc7b7bbf27af8b807b36b59e561 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 May 2022 23:32:31 +0100 Subject: [PATCH 0655/1052] Implement syscall for arm32 --- src/llvm_backend_proc.cpp | 167 ++++++++++++++++++++++---------------- 1 file changed, 96 insertions(+), 71 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 96ff19d10..06a74f625 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -189,7 +189,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) GB_ASSERT(entity->kind == Entity_Procedure); String link_name = entity->Procedure.link_name; if (entity->flags & EntityFlag_CustomLinkName && - link_name != "") { + link_name != "") { if (string_starts_with(link_name, str_lit("__"))) { LLVMSetLinkage(p->value, LLVMExternalLinkage); } else { @@ -200,12 +200,12 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) } } lb_set_linkage_from_entity_flags(p->module, p->value, entity->flags); - - + + if (p->is_foreign) { lb_set_wasm_import_attributes(p->value, entity, p->name); } - + // NOTE(bill): offset==0 is the return value isize offset = 1; @@ -280,7 +280,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) if (p->body != nullptr) { // String debug_name = entity->token.string.text; String debug_name = p->name; - + p->debug_info = LLVMDIBuilderCreateFunction(m->debug_builder, scope, cast(char const *)debug_name.text, debug_name.len, cast(char const *)p->name.text, p->name.len, @@ -1315,22 +1315,22 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_clamp: return lb_emit_clamp(p, type_of_expr(expr), - lb_build_expr(p, ce->args[0]), - lb_build_expr(p, ce->args[1]), - lb_build_expr(p, ce->args[2])); + lb_build_expr(p, ce->args[0]), + lb_build_expr(p, ce->args[1]), + lb_build_expr(p, ce->args[2])); case BuiltinProc_soa_zip: return lb_soa_zip(p, ce, tv); case BuiltinProc_soa_unzip: return lb_soa_unzip(p, ce, tv); - + case BuiltinProc_transpose: { lbValue m = lb_build_expr(p, ce->args[0]); return lb_emit_matrix_tranpose(p, m, tv.type); } - + case BuiltinProc_outer_product: { lbValue a = lb_build_expr(p, ce->args[0]); @@ -1347,13 +1347,13 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_ASSERT(is_type_matrix(tv.type)); return lb_emit_arith_matrix(p, Token_Mul, a, b, tv.type, true); } - + case BuiltinProc_matrix_flatten: { lbValue m = lb_build_expr(p, ce->args[0]); return lb_emit_matrix_flatten(p, m, tv.type); } - + // "Intrinsics" case BuiltinProc_alloca: @@ -1370,7 +1370,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_cpu_relax: if (build_context.metrics.arch == TargetArch_i386 || - build_context.metrics.arch == TargetArch_amd64) { + build_context.metrics.arch == TargetArch_amd64) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("pause"), {}, true); GB_ASSERT(the_asm != nullptr); @@ -1538,7 +1538,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue dst = lb_build_expr(p, ce->args[0]); lbValue src = lb_build_expr(p, ce->args[1]); lbValue len = lb_build_expr(p, ce->args[2]); - + lb_mem_copy_overlapping(p, dst, src, len, false); return {}; } @@ -1547,7 +1547,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue dst = lb_build_expr(p, ce->args[0]); lbValue src = lb_build_expr(p, ce->args[1]); lbValue len = lb_build_expr(p, ce->args[2]); - + lb_mem_copy_non_overlapping(p, dst, src, len, false); return {}; } @@ -1651,7 +1651,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.type = type_deref(dst.type); return res; } - + case BuiltinProc_unaligned_store: { lbValue dst = lb_build_expr(p, ce->args[0]); @@ -1661,7 +1661,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lb_mem_copy_non_overlapping(p, dst, src, lb_const_int(p->module, t_int, type_size_of(t)), false); return {}; } - + case BuiltinProc_unaligned_load: { lbValue src = lb_build_expr(p, ce->args[0]); @@ -1843,7 +1843,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.type = t; return lb_emit_conv(p, res, t); } - + case BuiltinProc_prefetch_read_instruction: case BuiltinProc_prefetch_read_data: case BuiltinProc_prefetch_write_instruction: @@ -1871,27 +1871,27 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, cache = 1; break; } - + char const *name = "llvm.prefetch"; - + LLVMTypeRef types[1] = {lb_type(p->module, t_rawptr)}; unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - + LLVMTypeRef llvm_i32 = lb_type(p->module, t_i32); LLVMValueRef args[4] = {}; args[0] = ptr.value; args[1] = LLVMConstInt(llvm_i32, rw, false); args[2] = LLVMConstInt(llvm_i32, locality, false); args[3] = LLVMConstInt(llvm_i32, cache, false); - + lbValue res = {}; res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.type = nullptr; return res; } - + case BuiltinProc___entry_point: if (p->module->info->entry_point) { lbValue entry_point = lb_find_procedure_value_from_entity(p->module, p->module->info->entry_point); @@ -1909,22 +1909,22 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, arg = lb_emit_conv(p, arg, t_uintptr); args[i] = arg.value; } - + LLVMTypeRef llvm_uintptr = lb_type(p->module, t_uintptr); LLVMTypeRef *llvm_arg_types = gb_alloc_array(permanent_allocator(), LLVMTypeRef, arg_count); for (unsigned i = 0; i < arg_count; i++) { llvm_arg_types[i] = llvm_uintptr; } - + LLVMTypeRef func_type = LLVMFunctionType(llvm_uintptr, llvm_arg_types, arg_count, false); - + LLVMValueRef inline_asm = nullptr; - + switch (build_context.metrics.arch) { case TargetArch_amd64: { GB_ASSERT(arg_count <= 7); - + char asm_string[] = "syscall"; gbString constraints = gb_string_make(heap_allocator(), "={rax}"); for (unsigned i = 0; i < arg_count; i++) { @@ -1963,11 +1963,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case TargetArch_i386: { GB_ASSERT(arg_count <= 7); - + char asm_string_default[] = "int $0x80"; char *asm_string = asm_string_default; gbString constraints = gb_string_make(heap_allocator(), "={eax}"); - + for (unsigned i = 0; i < gb_min(arg_count, 6); i++) { constraints = gb_string_appendc(constraints, ",{"); static char const *regs[] = { @@ -1984,56 +1984,81 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, if (arg_count == 7) { char asm_string7[] = "push %[arg6]\npush %%ebp\nmov 4(%%esp), %%ebp\nint $0x80\npop %%ebp\nadd $4, %%esp"; asm_string = asm_string7; - + constraints = gb_string_appendc(constraints, ",rm"); } - + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; case TargetArch_arm64: { - GB_ASSERT(arg_count <= 7); - - if(build_context.metrics.os == TargetOs_darwin) { - char asm_string[] = "svc #0x80"; - gbString constraints = gb_string_make(heap_allocator(), "={x0}"); - for (unsigned i = 0; i < arg_count; i++) { - constraints = gb_string_appendc(constraints, ",{"); - static char const *regs[] = { - "x16", - "x0", - "x1", - "x2", - "x3", - "x4", - "x5", - }; - constraints = gb_string_appendc(constraints, regs[i]); - constraints = gb_string_appendc(constraints, "}"); - } + GB_ASSERT(arg_count <= 7); - inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); - } else { - char asm_string[] = "svc #0"; - gbString constraints = gb_string_make(heap_allocator(), "={x0}"); - for (unsigned i = 0; i < arg_count; i++) { - constraints = gb_string_appendc(constraints, ",{"); - static char const *regs[] = { - "x8", - "x0", - "x1", - "x2", - "x3", - "x4", - "x5", - }; - constraints = gb_string_appendc(constraints, regs[i]); - constraints = gb_string_appendc(constraints, "}"); - } + if(build_context.metrics.os == TargetOs_darwin) { + char asm_string[] = "svc #0x80"; + gbString constraints = gb_string_make(heap_allocator(), "={x0}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "x16", + "x0", + "x1", + "x2", + "x3", + "x4", + "x5", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } - inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); - } + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } else { + char asm_string[] = "svc #0"; + gbString constraints = gb_string_make(heap_allocator(), "={x0}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "x8", + "x0", + "x1", + "x2", + "x3", + "x4", + "x5", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } + } + break; + case TargetArch_arm32: + { + // TODO(bill): Check this is correct + GB_ASSERT(arg_count <= 7); + + char asm_string[] = "svc #0"; + gbString constraints = gb_string_make(heap_allocator(), "={r0}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "r8", + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; default: From be8de4a1ffd0c555b94579351d5363f830a58272 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 May 2022 23:52:55 +0100 Subject: [PATCH 0656/1052] Update arch enum --- core/runtime/core.odin | 1 + core/runtime/core_builtin.odin | 6 ++++-- core/sys/unix/syscalls_linux.odin | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 4269450de..e2933d20a 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -415,6 +415,7 @@ Odin_OS_Type :: type_of(ODIN_OS) Unknown, amd64, i386, + arm32, arm64, wasm32, wasm64, diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 13e464a76..43b9ee1bf 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -631,13 +631,15 @@ assert :: proc(condition: bool, message := "", loc := #caller_location) { // to improve performance to make the CPU not // execute speculatively, making it about an order of // magnitude faster - proc(message: string, loc: Source_Code_Location) { + @(cold) + internal :: proc(message: string, loc: Source_Code_Location) { p := context.assertion_failure_proc if p == nil { p = default_assertion_failure_proc } p("runtime assertion", message, loc) - }(message, loc) + } + internal(message, loc) } } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 3d06d42d4..f50ae825b 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1114,7 +1114,7 @@ when ODIN_ARCH == .amd64 { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when false /*ODIN_ARCH == .arm*/ { // TODO +} else when ODIN_ARCH == .arm32 { // TODO SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 From 8023c8abc7087c763da5e843252d3899784e57be Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 May 2022 14:10:02 +0100 Subject: [PATCH 0657/1052] Fix `@(disable=...)` --- src/llvm_backend_proc.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 06a74f625..a0e9a5da5 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -823,12 +823,6 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, GB_ASSERT(pt->kind == Type_Proc); Type *results = pt->Proc.results; - if (p->entity != nullptr) { - if (p->entity->flags & EntityFlag_Disabled) { - return {}; - } - } - lbAddr context_ptr = {}; if (pt->Proc.calling_convention == ProcCC_Odin) { context_ptr = lb_find_or_generate_context_ptr(p); @@ -2280,6 +2274,15 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { // NOTE(bill): Regular call lbValue value = {}; Ast *proc_expr = unparen_expr(ce->proc); + + Entity *proc_entity = entity_of_node(proc_expr); + if (proc_entity != nullptr) { + if (proc_entity->flags & EntityFlag_Disabled) { + GB_ASSERT(tv.type == nullptr); + return {}; + } + } + if (proc_expr->tav.mode == Addressing_Constant) { ExactValue v = proc_expr->tav.value; switch (v.kind) { @@ -2306,13 +2309,6 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - Entity *proc_entity = entity_of_node(proc_expr); - if (proc_entity != nullptr) { - if (proc_entity->flags & EntityFlag_Disabled) { - return {}; - } - } - if (value.value == nullptr) { value = lb_build_expr(p, proc_expr); } From 97717d65efde6f83e502f0261a3fb08a34ea3f04 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 May 2022 16:09:09 +0100 Subject: [PATCH 0658/1052] Add `vendor:openexr` No foreign library yet --- vendor/openexr/exr_attr.odin | 397 +++++++++++++++++ vendor/openexr/exr_base.odin | 170 ++++++++ vendor/openexr/exr_chunkio.odin | 143 +++++++ vendor/openexr/exr_coding.odin | 119 ++++++ vendor/openexr/exr_context.odin | 485 +++++++++++++++++++++ vendor/openexr/exr_debug.odin | 8 + vendor/openexr/exr_decode.odin | 288 +++++++++++++ vendor/openexr/exr_encode.odin | 319 ++++++++++++++ vendor/openexr/exr_errors.odin | 62 +++ vendor/openexr/exr_part.odin | 733 ++++++++++++++++++++++++++++++++ 10 files changed, 2724 insertions(+) create mode 100644 vendor/openexr/exr_attr.odin create mode 100644 vendor/openexr/exr_base.odin create mode 100644 vendor/openexr/exr_chunkio.odin create mode 100644 vendor/openexr/exr_coding.odin create mode 100644 vendor/openexr/exr_context.odin create mode 100644 vendor/openexr/exr_debug.odin create mode 100644 vendor/openexr/exr_decode.odin create mode 100644 vendor/openexr/exr_encode.odin create mode 100644 vendor/openexr/exr_errors.odin create mode 100644 vendor/openexr/exr_part.odin diff --git a/vendor/openexr/exr_attr.odin b/vendor/openexr/exr_attr.odin new file mode 100644 index 000000000..eb07142ec --- /dev/null +++ b/vendor/openexr/exr_attr.odin @@ -0,0 +1,397 @@ +package vendor_openexr + +import "core:c" + +// Enum declaring allowed values for \c u8 value stored in built-in compression type. +compression_t :: enum c.int { + NONE = 0, + RLE = 1, + ZIPS = 2, + ZIP = 3, + PIZ = 4, + PXR24 = 5, + B44 = 6, + B44A = 7, + DWAA = 8, + DWAB = 9, +} + +// Enum declaring allowed values for \c u8 value stored in built-in env map type. +envmap_t :: enum c.int { + LATLONG = 0, + CUBE = 1, +} + +// Enum declaring allowed values for \c u8 value stored in \c lineOrder type. +lineorder_t :: enum c.int { + INCREASING_Y = 0, + DECREASING_Y = 1, + RANDOM_Y = 2, +} + +// Enum declaring allowed values for part type. +storage_t :: enum c.int { + SCANLINE = 0, // Corresponds to type of \c scanlineimage. + TILED, // Corresponds to type of \c tiledimage. + DEEP_SCANLINE, // Corresponds to type of \c deepscanline. + DEEP_TILED, // Corresponds to type of \c deeptile. +} + +// @brief Enum representing what type of tile information is contained. +tile_level_mode_t :: enum c.int { + ONE_LEVEL = 0, // Single level of image data. + MIPMAP_LEVELS = 1, // Mipmapped image data. + RIPMAP_LEVELS = 2, // Ripmapped image data. +} + +/** @brief Enum representing how to scale positions between levels. */ +tile_round_mode_t :: enum c.int { + DOWN = 0, + UP = 1, +} + +/** @brief Enum capturing the underlying data type on a channel. */ +pixel_type_t :: enum c.int { + UINT = 0, + HALF = 1, + FLOAT = 2, +} + +/* /////////////////////////////////////// */ +/* First set of structs are data where we can read directly with no allocation needed... */ + +/** @brief Struct to hold color chromaticities to interpret the tristimulus color values in the image data. */ +attr_chromaticities_t :: struct #packed { + red_x: f32, + red_y: f32, + green_x: f32, + green_y: f32, + blue_x: f32, + blue_y: f32, + white_x: f32, + white_y: f32, +} + +/** @brief Struct to hold keycode information. */ +attr_keycode_t :: struct #packed { + film_mfc_code: i32, + film_type: i32, + prefix: i32, + count: i32, + perf_offset: i32, + perfs_per_frame: i32, + perfs_per_count: i32, +} + +/** @brief struct to hold a 32-bit floating-point 3x3 matrix. */ +attr_m33f_t :: struct #packed { + m: [9]f32, +} + +/** @brief struct to hold a 64-bit floating-point 3x3 matrix. */ +attr_m33d_t :: struct #packed { + m: [9]f64, +} + +/** @brief Struct to hold a 32-bit floating-point 4x4 matrix. */ +attr_m44f_t :: struct #packed { + m: [16]f32, +} + +/** @brief Struct to hold a 64-bit floating-point 4x4 matrix. */ +attr_m44d_t :: struct #packed { + m: [16]f64, +} + +/** @brief Struct to hold an integer ratio value. */ +attr_rational_t :: struct #packed { + num: i32, + denom: u32, +} + +/** @brief Struct to hold timecode information. */ +attr_timecode_t :: struct #packed { + time_and_flags: u32, + user_data: u32, +} + +/** @brief Struct to hold a 2-element integer vector. */ +attr_v2i_t :: distinct [2]i32 + +/** @brief Struct to hold a 2-element 32-bit float vector. */ +attr_v2f_t :: distinct [2]f32 + +/** @brief Struct to hold a 2-element 64-bit float vector. */ +attr_v2d_t :: distinct [2]f64 + +/** @brief Struct to hold a 3-element integer vector. */ +attr_v3i_t :: distinct [3]i32 + +/** @brief Struct to hold a 3-element 32-bit float vector. */ +attr_v3f_t :: distinct [3]f32 + +/** @brief Struct to hold a 3-element 64-bit float vector. */ +attr_v3d_t :: distinct [3]f64 + +/** @brief Struct to hold an integer box/region definition. */ +attr_box2i_t :: struct #packed { + min: attr_v2i_t, + max: attr_v2i_t, +} + +/** @brief Struct to hold a floating-point box/region definition. */ +attr_box2f_t:: struct #packed { + min: attr_v2f_t, + max: attr_v2f_t, +} + +/** @brief Struct holding base tiledesc attribute type defined in spec + * + * NB: This is in a tightly packed area so it can be read directly, be + * careful it doesn't become padded to the next \c uint32_t boundary. + */ +attr_tiledesc_t :: struct #packed { + x_size: u32, + y_size: u32, + level_and_round: u8, +} + +/** @brief Macro to access type of tiling from packed structure. */ +GET_TILE_LEVEL_MODE :: #force_inline proc "c" (tiledesc: attr_tiledesc_t) -> tile_level_mode_t { + return tile_level_mode_t(tiledesc.level_and_round & 0xf) +} +/** @brief Macro to access the rounding mode of tiling from packed structure. */ +GET_TILE_ROUND_MODE :: #force_inline proc "c" (tiledesc: attr_tiledesc_t) -> tile_round_mode_t { + return tile_round_mode_t((tiledesc.level_and_round >> 4) & 0xf) +} +/** @brief Macro to pack the tiling type and rounding mode into packed structure. */ +PACK_TILE_LEVEL_ROUND :: #force_inline proc "c" (lvl: tile_level_mode_t, mode: tile_round_mode_t) -> u8 { + return ((u8(mode) & 0xf) << 4) | (u8(lvl) & 0xf) +} + + +/* /////////////////////////////////////// */ +/* Now structs that involve heap allocation to store data. */ + +/** Storage for a string. */ +attr_string_t :: struct { + length: i32, + /** If this is non-zero, the string owns the data, if 0, is a const ref to a static string. */ + alloc_size: i32, + + str: cstring, +} + +/** Storage for a string vector. */ +attr_string_vector_t :: struct { + n_strings: i32, + /** If this is non-zero, the string vector owns the data, if 0, is a const ref. */ + alloc_size: i32, + + strings: [^]attr_string_t, +} + +/** Float vector storage struct. */ +attr_float_vector_t :: struct { + length: i32, + /** If this is non-zero, the float vector owns the data, if 0, is a const ref. */ + alloc_size: i32, + + arr: [^]f32, +} + +/** Hint for lossy compression methods about how to treat values + * (logarithmic or linear), meaning a human sees values like R, G, B, + * luminance difference between 0.1 and 0.2 as about the same as 1.0 + * to 2.0 (logarithmic), where chroma coordinates are closer to linear + * (0.1 and 0.2 is about the same difference as 1.0 and 1.1). + */ +perceptual_treatment_t :: enum c.int { + LOGARITHMIC = 0, + LINEAR = 1, +} + +/** Individual channel information. */ +attr_chlist_entry_t :: struct { + name: attr_string_t, + /** Data representation for these pixels: uint, half, float. */ + pixel_type: pixel_type_t, + /** Possible values are 0 and 1 per docs perceptual_treatment_t. */ + p_linear: u8, + reserved: [3]u8, + x_sampling: i32, + y_sampling: i32, +} + +/** List of channel information (sorted alphabetically). */ +attr_chlist_t :: struct { + num_channels: c.int, + num_alloced: c.int, + + entries: [^]attr_chlist_entry_t, +} + +/** @brief Struct to define attributes of an embedded preview image. */ +attr_preview_t :: struct { + width: u32, + height: u32, + /** If this is non-zero, the preview owns the data, if 0, is a const ref. */ + alloc_size: c.size_t, + + rgba: [^]u8, +} + +/** Custom storage structure for opaque data. + * + * Handlers for opaque types can be registered, then when a + * non-builtin type is encountered with a registered handler, the + * function pointers to unpack/pack it will be set up. + * + * @sa register_attr_type_handler + */ +attr_opaquedata_t :: struct { + size: i32, + unpacked_size: i32, + /** If this is non-zero, the struct owns the data, if 0, is a const ref. */ + packed_alloc_size: i32, + pad: [4]u8, + + packed_data: rawptr, + + /** When an application wants to have custom data, they can store + * an unpacked form here which will be requested to be destroyed + * upon destruction of the attribute. + */ + unpacked_data: rawptr, + + /** An application can register an attribute handler which then + * fills in these function pointers. This allows a user to delay + * the expansion of the custom type until access is desired, and + * similarly, to delay the packing of the data until write time. + */ + unpack_func_ptr: proc "c" ( + ctxt: context_t, + data: rawptr, + attrsize: i32, + outsize: ^i32, + outbuffer: ^rawptr) -> result_t, + pack_func_ptr: proc "c" ( + ctxt: context_t, + data: rawptr, + datasize: i32, + outsize: ^i32, + outbuffer: rawptr) -> result_t, + destroy_unpacked_func_ptr: proc "c" ( + ctxt: context_t, data: rawptr, attrsize: i32), +} + +/* /////////////////////////////////////// */ + +/** @brief Built-in/native attribute type enum. + * + * This will enable us to do a tagged type struct to generically store + * attributes. + */ +attribute_type_t :: enum c.int { + UNKNOWN = 0, // Type indicating an error or uninitialized attribute. + BOX2I, // Integer region definition. @see attr_box2i_t. + BOX2F, // Float region definition. @see attr_box2f_t. + CHLIST, // Definition of channels in file @see chlist_entry. + CHROMATICITIES, // Values to specify color space of colors in file @see attr_chromaticities_t. + COMPRESSION, // ``u8`` declaring compression present. + DOUBLE, // Double precision floating point number. + ENVMAP, // ``u8`` declaring environment map type. + FLOAT, // Normal (4 byte) precision floating point number. + FLOAT_VECTOR, // List of normal (4 byte) precision floating point numbers. + INT, // 32-bit signed integer value. + KEYCODE, // Struct recording keycode @see attr_keycode_t. + LINEORDER, // ``u8`` declaring scanline ordering. + M33F, // 9 32-bit floats representing a 3x3 matrix. + M33D, // 9 64-bit floats representing a 3x3 matrix. + M44F, // 16 32-bit floats representing a 4x4 matrix. + M44D, // 16 64-bit floats representing a 4x4 matrix. + PREVIEW, // 2 ``unsigned ints`` followed by 4 x w x h ``u8`` image. + RATIONAL, // \c int followed by ``unsigned int`` + STRING, // ``int`` (length) followed by char string data. + STRING_VECTOR, // 0 or more text strings (int + string). number is based on attribute size. + TILEDESC, // 2 ``unsigned ints`` ``xSize``, ``ySize`` followed by mode. + TIMECODE, // 2 ``unsigned ints`` time and flags, user data. + V2I, // Pair of 32-bit integers. + V2F, // Pair of 32-bit floats. + V2D, // Pair of 64-bit floats. + V3I, // Set of 3 32-bit integers. + V3F, // Set of 3 32-bit floats. + V3D, // Set of 3 64-bit floats. + OPAQUE, // User/unknown provided type. +} + +/** @brief Storage, name and type information for an attribute. + * + * Attributes (metadata) for the file cause a surprising amount of + * overhead. It is not uncommon for a production-grade EXR to have + * many attributes. As such, the attribute struct is designed in a + * slightly more complicated manner. It is optimized to have the + * storage for that attribute: the struct itself, the name, the type, + * and the data all allocated as one block. Further, the type and + * standard names may use a static string to avoid allocating space + * for those as necessary with the pointers pointing to static strings + * (not to be freed). Finally, small values are optimized for. + */ +attribute_t :: struct { + /** Name of the attribute. */ + name: cstring, + /** String type name of the attribute. */ + type_name: cstring, + /** Length of name string (short flag is 31 max, long allows 255). */ + name_length: u8, + /** Length of type string (short flag is 31 max, long allows 255). */ + type_name_length: u8, + + pad: [2]u8, + + /** Enum of the attribute type. */ + type: attribute_type_t, + + /** Union of pointers of different types that can be used to type + * pun to an appropriate type for builtins. Do note that while + * this looks like a big thing, it is only the size of a single + * pointer. These are all pointers into some other data block + * storing the value you want, with the exception of the pod types + * which are just put in place (i.e. small value optimization). + * + * The attribute type \c type should directly correlate to one + * of these entries. + */ + using _: struct #raw_union { + // NB: not pointers for POD types + uc: u8, + d: f64, + f: f32, + i: i32, + + box2i: ^attr_box2i_t, + box2f: ^attr_box2f_t, + chlist: ^attr_chlist_t, + chromaticities: ^attr_chromaticities_t, + keycode: ^attr_keycode_t, + floatvector: ^attr_float_vector_t, + m33f: ^attr_m33f_t, + m33d: ^attr_m33d_t, + m44f: ^attr_m44f_t, + m44d: ^attr_m44d_t, + preview: ^attr_preview_t, + rational: ^attr_rational_t, + string: ^attr_string_t, + stringvector: ^attr_string_vector_t, + tiledesc: ^attr_tiledesc_t, + timecode: ^attr_timecode_t, + v2i: ^attr_v2i_t, + v2f: ^attr_v2f_t, + v2d: ^attr_v2d_t, + v3i: ^attr_v3i_t, + v3f: ^attr_v3f_t, + v3d: ^attr_v3d_t, + opaque: ^attr_opaquedata_t, + rawptr: ^u8, + }, +} \ No newline at end of file diff --git a/vendor/openexr/exr_base.odin b/vendor/openexr/exr_base.odin new file mode 100644 index 000000000..0db4cc7ff --- /dev/null +++ b/vendor/openexr/exr_base.odin @@ -0,0 +1,170 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +import "core:c" + +/** @brief Function pointer used to hold a malloc-like routine. + * + * Providing these to a context will override what memory is used to + * allocate the context itself, as well as any allocations which + * happen during processing of a file or stream. This can be used by + * systems which provide rich malloc tracking routines to override the + * internal allocations performed by the library. + * + * This function is expected to allocate and return a new memory + * handle, or `NULL` if allocation failed (which the library will then + * handle and return an out-of-memory error). + * + * If one is provided, both should be provided. + * @sa exr_memory_free_func_t + */ +memory_allocation_func_t :: proc "c" (bytes: c.size_t) -> rawptr + +/** @brief Function pointer used to hold a free-like routine. + * + * Providing these to a context will override what memory is used to + * allocate the context itself, as well as any allocations which + * happen during processing of a file or stream. This can be used by + * systems which provide rich malloc tracking routines to override the + * internal allocations performed by the library. + * + * This function is expected to return memory to the system, ala free + * from the C library. + * + * If providing one, probably need to provide both routines. + * @sa exr_memory_allocation_func_t + */ +memory_free_func_t :: proc "c" (ptr: rawptr) + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + /** @brief Retrieve the current library version. The @p extra string is for + * custom installs, and is a static string, do not free the returned + * pointer. + */ + get_library_version :: proc(maj, min, patch: ^c.int, extra: ^cstring) --- + + /** @brief Limit the size of image allowed to be parsed or created by + * the library. + * + * This is used as a safety check against corrupt files, but can also + * serve to avoid potential issues on machines which have very + * constrained RAM. + * + * These values are among the only globals in the core layer of + * OpenEXR. The intended use is for applications to define a global + * default, which will be combined with the values provided to the + * individual context creation routine. The values are used to check + * against parsed header values. This adds some level of safety from + * memory overruns where a corrupt file given to the system may cause + * a large allocation to happen, enabling buffer overruns or other + * potential security issue. + * + * These global values are combined with the values in + * \ref exr_context_initializer_t using the following rules: + * + * 1. negative values are ignored. + * + * 2. if either value has a positive (non-zero) value, and the other + * has 0, the positive value is preferred. + * + * 3. If both are positive (non-zero), the minimum value is used. + * + * 4. If both values are 0, this disables the constrained size checks. + * + * This function does not fail. + */ + set_default_maximum_image_size :: proc(w, h: c.int) --- + + /** @brief Retrieve the global default maximum image size. + * + * This function does not fail. + */ + get_default_maximum_image_size :: proc(w, h: ^c.int) --- + + /** @brief Limit the size of an image tile allowed to be parsed or + * created by the library. + * + * Similar to image size, this places constraints on the maximum tile + * size as a safety check against bad file data + * + * This is used as a safety check against corrupt files, but can also + * serve to avoid potential issues on machines which have very + * constrained RAM + * + * These values are among the only globals in the core layer of + * OpenEXR. The intended use is for applications to define a global + * default, which will be combined with the values provided to the + * individual context creation routine. The values are used to check + * against parsed header values. This adds some level of safety from + * memory overruns where a corrupt file given to the system may cause + * a large allocation to happen, enabling buffer overruns or other + * potential security issue. + * + * These global values are combined with the values in + * \ref exr_context_initializer_t using the following rules: + * + * 1. negative values are ignored. + * + * 2. if either value has a positive (non-zero) value, and the other + * has 0, the positive value is preferred. + * + * 3. If both are positive (non-zero), the minimum value is used. + * + * 4. If both values are 0, this disables the constrained size checks. + * + * This function does not fail. + */ + set_default_maximum_tile_size :: proc(w, h: c.int) --- + + /** @brief Retrieve the global maximum tile size. + * + * This function does not fail. + */ + get_default_maximum_tile_size :: proc(w, h: ^c.int) --- + + /** @} */ + + /** + * @defgroup CompressionDefaults Provides default compression settings + * @{ + */ + + /** @brief Assigns a default zip compression level. + * + * This value may be controlled separately on each part, but this + * global control determines the initial value. + */ + set_default_zip_compression_level :: proc(l: c.int) --- + + /** @brief Retrieve the global default zip compression value + */ + get_default_zip_compression_level :: proc(l: ^c.int) --- + + /** @brief Assigns a default DWA compression quality level. + * + * This value may be controlled separately on each part, but this + * global control determines the initial value. + */ + set_default_dwa_compression_quality :: proc(q: f32) --- + + /** @brief Retrieve the global default dwa compression quality + */ + get_default_dwa_compression_quality :: proc(q: ^f32) --- + + /** @brief Allow the user to override default allocator used internal + * allocations necessary for files, attributes, and other temporary + * memory. + * + * These routines may be overridden when creating a specific context, + * however this provides global defaults such that the default can be + * applied. + * + * If either pointer is 0, the appropriate malloc/free routine will be + * substituted. + * + * This function does not fail. + */ + set_default_memory_routines :: proc(alloc_func: memory_allocation_func_t, free_func: memory_free_func_t) --- +} \ No newline at end of file diff --git a/vendor/openexr/exr_chunkio.odin b/vendor/openexr/exr_chunkio.odin new file mode 100644 index 000000000..612db2cb3 --- /dev/null +++ b/vendor/openexr/exr_chunkio.odin @@ -0,0 +1,143 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +import "core:c" + +/** + * Struct describing raw data information about a chunk. + * + * A chunk is the generic term for a pixel data block in an EXR file, + * as described in the OpenEXR File Layout documentation. This is + * common between all different forms of data that can be stored. + */ +chunk_info_t :: struct { + idx: i32, + + /** For tiles, this is the tilex; for scans it is the x. */ + start_x: i32, + /** For tiles, this is the tiley; for scans it is the scanline y. */ + start_y: i32, + height: i32, /**< For this chunk. */ + width: i32, /**< For this chunk. */ + + level_x: u8, /**< For tiled files. */ + level_y: u8, /**< For tiled files. */ + + type: u8, + compression: u8, + + data_offset: u64, + packed_size: u64, + unpacked_size: u64, + + sample_count_data_offset: u64, + sample_count_table_size: u64, +} + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + read_scanline_chunk_info :: proc(ctxt: const_context_t, part_index: c.int, y: c.int, cinfo: ^chunk_info_t) -> result_t --- + + read_tile_chunk_info :: proc( + ctxt: const_context_t, + part_index: c.int, + tilex: c.int, + tiley: c.int, + levelx: c.int, + levely: c.int, + cinfo: ^chunk_info_t) -> result_t --- + + /** Read the packed data block for a chunk. + * + * This assumes that the buffer pointed to by @p packed_data is + * large enough to hold the chunk block info packed_size bytes. + */ + read_chunk :: proc( + ctxt: const_context_t, + part_index: c.int, + cinfo: ^chunk_info_t, + packed_data: rawptr) -> result_t --- + + /** + * Read chunk for deep data. + * + * This allows one to read the packed data, the sample count data, or both. + * \c exr_read_chunk also works to read deep data packed data, + * but this is a routine to get the sample count table and the packed + * data in one go, or if you want to pre-read the sample count data, + * you can get just that buffer. + */ + read_deep_chunk :: proc( + ctxt: const_context_t, + part_index: c.int, + cinfo: ^chunk_info_t, + packed_data: rawptr, + sample_data: rawptr) -> result_t --- + + /**************************************/ + + /** Initialize a \c chunk_info_t structure when encoding scanline + * data (similar to read but does not do anything with a chunk + * table). + */ + write_scanline_chunk_info :: proc(ctxt: context_t, part_index: c.int, y: c.int, cinfo: ^chunk_info_t) -> result_t --- + + /** Initialize a \c chunk_info_t structure when encoding tiled data + * (similar to read but does not do anything with a chunk table). + */ + write_tile_chunk_info :: proc( + ctxt: context_t, + part_index: c.int, + tilex: c.int, + tiley: c.int, + levelx: c.int, + levely: c.int, + cinfo: ^chunk_info_t) -> result_t --- + + /** + * @p y must the appropriate starting y for the specified chunk. + */ + write_scanline_chunk :: proc( + ctxt: context_t, + part_index: int, + y: int, + packed_data: rawptr, + packed_size: u64) -> result_t --- + + /** + * @p y must the appropriate starting y for the specified chunk. + */ + write_deep_scanline_chunk :: proc( + ctxt: context_t, + part_index: c.int, + y: c.int, + packed_data: rawptr, + packed_size: u64, + unpacked_size: u64, + sample_data: rawptr, + sample_data_size: u64) -> result_t --- + + write_tile_chunk :: proc( + ctxt: context_t, + part_index: c.int, + tilex: c.int, + tiley: c.int, + levelx: c.int, + levely: c.int, + packed_data: rawptr, + packed_size: u64) -> result_t --- + + write_deep_tile_chunk :: proc( + ctxt: context_t, + part_index: c.int, + tilex: c.int, + tiley: c.int, + levelx: c.int, + levely: c.int, + packed_data: rawptr, + packed_size: u64, + unpacked_size: u64, + sample_data: rawptr, + sample_data_size: u64) -> result_t --- +} \ No newline at end of file diff --git a/vendor/openexr/exr_coding.odin b/vendor/openexr/exr_coding.odin new file mode 100644 index 000000000..337475edf --- /dev/null +++ b/vendor/openexr/exr_coding.odin @@ -0,0 +1,119 @@ +package vendor_openexr + +import "core:c" +/** + * Enum for use in a custom allocator in the encode/decode pipelines + * (that is, so the implementor knows whether to allocate on which + * device based on the buffer disposition). + */ +transcoding_pipeline_buffer_id_t :: enum c.int { + PACKED, + UNPACKED, + COMPRESSED, + SCRATCH1, + SCRATCH2, + PACKED_SAMPLES, + SAMPLES, +} + +/** @brief Struct for negotiating buffers when decoding/encoding + * chunks of data. + * + * This is generic and meant to negotiate exr data bi-directionally, + * in that the same structure is used for both decoding and encoding + * chunks for read and write, respectively. + * + * The first half of the structure will be filled by the library, and + * the caller is expected to fill the second half appropriately. + */ +coding_channel_info_t :: struct { + /************************************************** + * Elements below are populated by the library when + * decoding is initialized/updated and must be left + * untouched when using the default decoder routines. + **************************************************/ + + /** Channel name. + * + * This is provided as a convenient reference. Do not free, this + * refers to the internal data structure in the context. + */ + channel_name: cstring, + + /** Number of lines for this channel in this chunk. + * + * May be 0 or less than overall image height based on sampling + * (i.e. when in 4:2:0 type sampling) + */ + height: i32, + + /** Width in pixel count. + * + * May be 0 or less than overall image width based on sampling + * (i.e. 4:2:2 will have some channels have fewer values). + */ + width: i32, + + /** Horizontal subsampling information. */ + x_samples: i32, + /** Vertical subsampling information. */ + y_samples: i32, + + /** Linear flag from channel definition (used by b44). */ + p_linear: u8, + + /** How many bytes per pixel this channel consumes (2 for float16, + * 4 for float32/uint32). + */ + bytes_per_element: i8, + + /** Small form of exr_pixel_type_t enum (EXR_PIXEL_UINT/HALF/FLOAT). */ + data_type: u16, + + /************************************************** + * Elements below must be edited by the caller + * to control encoding/decoding. + **************************************************/ + + /** How many bytes per pixel the input is or output should be + * (2 for float16, 4 for float32/uint32). Defaults to same + * size as input. + */ + user_bytes_per_element: i16, + + /** Small form of exr_pixel_type_t enum + * (EXR_PIXEL_UINT/HALF/FLOAT). Defaults to same type as input. + */ + user_data_type: u16, + + /** Increment to get to next pixel. + * + * This is in bytes. Must be specified when the decode pointer is + * specified (and always for encode). + * + * This is useful for implementing transcoding generically of + * planar or interleaved data. For planar data, where the layout + * is RRRRRGGGGGBBBBB, you can pass in 1 * bytes per component. + */ + + user_pixel_stride: i32, + + /** When \c lines > 1 for a chunk, this is the increment used to get + * from beginning of line to beginning of next line. + * + * This is in bytes. Must be specified when the decode pointer is + * specified (and always for encode). + */ + user_line_stride: i32, + + /** This data member has different requirements reading vs + * writing. When reading, if this is left as `NULL`, the channel + * will be skipped during read and not filled in. During a write + * operation, this pointer is considered const and not + * modified. To make this more clear, a union is used here. + */ + using _: struct #raw_union { + decode_to_ptr: ^u8, + encode_from_ptr: ^u8, + }, +} diff --git a/vendor/openexr/exr_context.odin b/vendor/openexr/exr_context.odin new file mode 100644 index 000000000..958e30490 --- /dev/null +++ b/vendor/openexr/exr_context.odin @@ -0,0 +1,485 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +import "core:c" + +#assert(size_of(c.int) == size_of(b32)) + +context_t :: distinct rawptr +const_context_t :: context_t + +/** + * @defgroup ContextFunctions OpenEXR Context Stream/File Functions + * + * @brief These are a group of function interfaces used to customize + * the error handling, memory allocations, or I/O behavior of an + * OpenEXR context. + * + * @{ + */ + +/** @brief Stream error notifier + * + * This function pointer is provided to the stream functions by the + * library such that they can provide a nice error message to the + * user during stream operations. + */ +stream_error_func_ptr_t :: proc "c" (ctxt: const_context_t, code: result_t, fmt: cstring, #c_vararg args: ..any) -> result_t + +/** @brief Error callback function + * + * Because a file can be read from using many threads at once, it is + * difficult to store an error message for later retrieval. As such, + * when a file is constructed, a callback function can be provided + * which delivers an error message for the calling application to + * handle. This will then be delivered on the same thread causing the + * error. + */ +error_handler_cb_t :: proc "c" (ctxt: const_context_t, code: result_t, msg: cstring) + +/** Destroy custom stream function pointer + * + * Generic callback to clean up user data for custom streams. + * This is called when the file is closed and expected not to + * error. + * + * @param failed Indicates the write operation failed, the + * implementor may wish to cleanup temporary files + */ +destroy_stream_func_ptr_t :: proc "c" (ctxt: const_context_t, userdata: rawptr, failed: c.int) + +/** Query stream size function pointer + * + * Used to query the size of the file, or amount of data representing + * the openexr file in the data stream. + * + * This is used to validate requests against the file. If the size is + * unavailable, return -1, which will disable these validation steps + * for this file, although appropriate memory safeguards must be in + * place in the calling application. + */ +query_size_func_ptr_t :: proc "c" (ctxt: const_context_t, userdata: rawptr) -> i64 + +/** @brief Read custom function pointer + * + * Used to read data from a custom output. Expects similar semantics to + * pread or ReadFile with overlapped data under win32. + * + * It is required that this provides thread-safe concurrent access to + * the same file. If the stream/input layer you are providing does + * not have this guarantee, your are responsible for providing + * appropriate serialization of requests. + * + * A file should be expected to be accessed in the following pattern: + * - upon open, the header and part information attributes will be read + * - upon the first image read request, the offset tables will be read + * multiple threads accessing this concurrently may actually read + * these values at the same time + * - chunks can then be read in any order as preferred by the + * application + * + * While this should mean that the header will be read in 'stream' + * order (no seeks required), no guarantee is made beyond that to + * retrieve image/deep data in order. So if the backing file is + * truly a stream, it is up to the provider to implement appropriate + * caching of data to give the appearance of being able to seek/read + * atomically. + */ +read_func_ptr_t :: proc "c" ( + ctxt: const_context_t, + userdata: rawptr, + buffer: rawptr, + sz: u64, + offset: u64, + error_cb: stream_error_func_ptr_t) -> i64 + +/** Write custom function pointer + * + * Used to write data to a custom output. Expects similar semantics to + * pwrite or WriteFile with overlapped data under win32. + * + * It is required that this provides thread-safe concurrent access to + * the same file. While it is unlikely that multiple threads will + * be used to write data for compressed forms, it is possible. + * + * A file should be expected to be accessed in the following pattern: + * - upon open, the header and part information attributes is constructed. + * + * - when the write_header routine is called, the header becomes immutable + * and is written to the file. This computes the space to store the chunk + * offsets, but does not yet write the values. + * + * - Image chunks are written to the file, and appear in the order + * they are written, not in the ordering that is required by the + * chunk offset table (unless written in that order). This may vary + * slightly if the size of the chunks is not directly known and + * tight packing of data is necessary. + * + * - at file close, the chunk offset tables are written to the file. + */ +write_func_ptr_t :: proc "c" ( + ctxt: const_context_t, + userdata: rawptr, + buffer: rawptr, + sz: u64, + offset: u64, + error_cb: stream_error_func_ptr_t) -> i64 + +/** @brief Struct used to pass function pointers into the context + * initialization routines. + * + * This partly exists to avoid the chicken and egg issue around + * creating the storage needed for the context on systems which want + * to override the malloc/free routines. + * + * However, it also serves to make a tidier/simpler set of functions + * to create and start processing exr files. + * + * The size member is required for version portability. + * + * It can be initialized using \c EXR_DEFAULT_CONTEXT_INITIALIZER. + * + * \code{.c} + * exr_context_initializer_t myctxtinit = DEFAULT_CONTEXT_INITIALIZER; + * myctxtinit.error_cb = &my_super_cool_error_callback_function; + * ... + * \endcode + * + */ +context_initializer_t :: struct { + /** @brief Size member to tag initializer for version stability. + * + * This should be initialized to the size of the current + * structure. This allows EXR to add functions or other + * initializers in the future, and retain version compatibility + */ + size: c.size_t, + + /** @brief Error callback function pointer + * + * The error callback is allowed to be `NULL`, and will use a + * default print which outputs to \c stderr. + * + * @sa exr_error_handler_cb_t + */ + error_handler_fn: error_handler_cb_t, + + /** Custom allocator, if `NULL`, will use malloc. @sa memory_allocation_func_t */ + alloc_fn: memory_allocation_func_t, + + /** Custom deallocator, if `NULL`, will use free. @sa memory_free_func_t */ + free_fn: memory_free_func_t, + + /** Blind data passed to custom read, size, write, destroy + * functions below. Up to user to manage this pointer. + */ + user_data: rawptr, + + /** @brief Custom read routine. + * + * This is only used during read or update contexts. If this is + * provided, it is expected that the caller has previously made + * the stream available, and placed whatever stream/file data + * into \c user_data above. + * + * If this is `NULL`, and the context requested is for reading an + * exr file, an internal implementation is provided for reading + * from normal filesystem files, and the filename provided is + * attempted to be opened as such. + * + * Expected to be `NULL` for a write-only operation, but is ignored + * if it is provided. + * + * For update contexts, both read and write functions must be + * provided if either is. + * + * @sa exr_read_func_ptr_t + */ + read_fn: read_func_ptr_t, + + /** @brief Custom size query routine. + * + * Used to provide validation when reading header values. If this + * is not provided, but a custom read routine is provided, this + * will disable some of the validation checks when parsing the + * image header. + * + * Expected to be `NULL` for a write-only operation, but is ignored + * if it is provided. + * + * @sa exr_query_size_func_ptr_t + */ + size_fn: query_size_func_ptr_t, + + /** @brief Custom write routine. + * + * This is only used during write or update contexts. If this is + * provided, it is expected that the caller has previously made + * the stream available, and placed whatever stream/file data + * into \c user_data above. + * + * If this is `NULL`, and the context requested is for writing an + * exr file, an internal implementation is provided for reading + * from normal filesystem files, and the filename provided is + * attempted to be opened as such. + * + * For update contexts, both read and write functions must be + * provided if either is. + * + * @sa exr_write_func_ptr_t + */ + write_fn: write_func_ptr_t, + + /** @brief Optional function to destroy the user data block of a custom stream. + * + * Allows one to free any user allocated data, and close any handles. + * + * @sa exr_destroy_stream_func_ptr_t + * */ + destroy_fn: destroy_stream_func_ptr_t, + + /** Initialize a field specifying what the maximum image width + * allowed by the context is. See exr_set_default_maximum_image_size() to + * understand how this interacts with global defaults. + */ + max_image_width: c.int, + + /** Initialize a field specifying what the maximum image height + * allowed by the context is. See exr_set_default_maximum_image_size() to + * understand how this interacts with global defaults. + */ + max_image_height: c.int, + + /** Initialize a field specifying what the maximum tile width + * allowed by the context is. See exr_set_default_maximum_tile_size() to + * understand how this interacts with global defaults. + */ + max_tile_width: c.int, + + /** Initialize a field specifying what the maximum tile height + * allowed by the context is. See exr_set_default_maximum_tile_size() to + * understand how this interacts with global defaults. + */ + max_tile_height: c.int, + + /** Initialize a field specifying what the default zip compression level should be + * for this context. See exr_set_default_zip_compresion_level() to + * set it for all contexts. + */ + zip_level: c.int, + + /** Initialize the default dwa compression quality. See + * exr_set_default_dwa_compression_quality() to set the default + * for all contexts. + */ + dwa_quality: f32, + + /** Initialize with a bitwise or of the various context flags + */ + flags: c.int, +} + +/** @brief context flag which will enforce strict header validation + * checks and may prevent reading of files which could otherwise be + * processed. + */ +CONTEXT_FLAG_STRICT_HEADER :: (1 << 0) + +/** @brief Disables error messages while parsing headers + * + * The return values will remain the same, but error reporting will be + * skipped. This is only valid for reading contexts + */ +CONTEXT_FLAG_SILENT_HEADER_PARSE :: (1 << 1) + +/** @brief Disables reconstruction logic upon corrupt / missing data chunks + * + * This will disable the reconstruction logic that searches through an + * incomplete file, and will instead just return errors at read + * time. This is only valid for reading contexts + */ +CONTEXT_FLAG_DISABLE_CHUNK_RECONSTRUCTION :: (1 << 2) + +/** @brief Simple macro to initialize the context initializer with default values. */ +DEFAULT_CONTEXT_INITIALIZER :: context_initializer_t{zip_level = -2, dwa_quality = -1} + +/** @} */ /* context function pointer declarations */ + + +/** @brief Enum describing how default files are handled during write. */ +default_write_mode_t :: enum c.int { + WRITE_FILE_DIRECTLY = 0, /**< Overwrite filename provided directly, deleted upon error. */ + INTERMEDIATE_TEMP_FILE = 1, /**< Create a temporary file, renaming it upon successful write, leaving original upon error */ +} + + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + /** @brief Check the magic number of the file and report + * `EXR_ERR_SUCCESS` if the file appears to be a valid file (or at least + * has the correct magic number and can be read). + */ + test_file_header :: proc(filename: cstring, ctxtdata: ^context_initializer_t) -> result_t --- + + /** @brief Close and free any internally allocated memory, + * calling any provided destroy function for custom streams. + * + * If the file was opened for write, first save the chunk offsets + * or any other unwritten data. + */ + finish :: proc(ctxt: ^context_t) -> result_t --- + + /** @brief Create and initialize a read-only exr read context. + * + * If a custom read function is provided, the filename is for + * informational purposes only, the system assumes the user has + * previously opened a stream, file, or whatever and placed relevant + * data in userdata to access that. + * + * One notable attribute of the context is that once it has been + * created and returned a successful code, it has parsed all the + * header data. This is done as one step such that it is easier to + * provide a safe context for multiple threads to request data from + * the same context concurrently. + * + * Once finished reading data, use exr_finish() to clean up + * the context. + * + * If you have custom I/O requirements, see the initializer context + * documentation \ref exr_context_initializer_t. The @p ctxtdata parameter + * is optional, if `NULL`, default values will be used. + */ + start_read :: proc( + ctxt: ^context_t, + filename: cstring, + ctxtdata: ^context_initializer_t) -> result_t --- + + /** @brief Create and initialize a write-only context. + * + * If a custom write function is provided, the filename is for + * informational purposes only, and the @p default_mode parameter will be + * ignored. As such, the system assumes the user has previously opened + * a stream, file, or whatever and placed relevant data in userdata to + * access that. + * + * Multi-Threading: To avoid issues with creating multi-part EXR + * files, the library approaches writing as a multi-step process, so + * the same concurrent guarantees can not be made for writing a + * file. The steps are: + * + * 1. Context creation (this function) + * + * 2. Part definition (required attributes and additional metadata) + * + * 3. Transition to writing data (this "commits" the part definitions, + * any changes requested after will result in an error) + * + * 4. Write part data in sequential order of parts (part0 + * -> partN-1). + * + * 5. Within each part, multiple threads can be encoding and writing + * data concurrently. For some EXR part definitions, this may be able + * to write data concurrently when it can predict the chunk sizes, or + * data is allowed to be padded. For others, it may need to + * temporarily cache chunks until the data is received to flush in + * order. The concurrency around this is handled by the library + * + * 6. Once finished writing data, use exr_finish() to clean + * up the context, which will flush any unwritten data such as the + * final chunk offset tables, and handle the temporary file flags. + * + * If you have custom I/O requirements, see the initializer context + * documentation \ref exr_context_initializer_t. The @p ctxtdata + * parameter is optional, if `NULL`, default values will be used. + */ + start_write :: proc( + ctxt: ^context_t, + filename: cstring, + default_mode: default_write_mode_t, + ctxtdata: ^context_initializer_t) -> result_t --- + + /** @brief Create a new context for updating an exr file in place. + * + * This is a custom mode that allows one to modify the value of a + * metadata entry, although not to change the size of the header, or + * any of the image data. + * + * If you have custom I/O requirements, see the initializer context + * documentation \ref exr_context_initializer_t. The @p ctxtdata parameter + * is optional, if `NULL`, default values will be used. + */ + start_inplace_header_update :: proc( + ctxt: ^context_t, + filename: cstring, + ctxtdata: ^context_initializer_t) -> result_t --- + + /** @brief Retrieve the file name the context is for as provided + * during the start routine. + * + * Do not free the resulting string. + */ + + get_file_name :: proc(ctxt: const_context_t, name: ^cstring) -> result_t --- + + /** @brief Query the user data the context was constructed with. This + * is perhaps useful in the error handler callback to jump back into + * an object the user controls. + */ + + get_user_data :: proc(ctxt: const_context_t, userdata: ^rawptr) -> result_t --- + + /** Any opaque attribute data entry of the specified type is tagged + * with these functions enabling downstream users to unpack (or pack) + * the data. + * + * The library handles the memory packed data internally, but the + * handler is expected to allocate and manage memory for the + * *unpacked* buffer (the library will call the destroy function). + * + * NB: the pack function will be called twice (unless there is a + * memory failure), the first with a `NULL` buffer, requesting the + * maximum size (or exact size if known) for the packed buffer, then + * the second to fill the output packed buffer, at which point the + * size can be re-updated to have the final, precise size to put into + * the file. + */ + register_attr_type_handler :: proc( + ctxt: context_t, + type: cstring, + unpack_func_ptr: proc "c" ( + ctxt: context_t, + data: rawptr, + attrsize: i32, + outsize: ^i32, + outbuffer: ^rawptr) -> result_t, + pack_func_ptr: proc "c" ( + ctxt: context_t, + data: rawptr, + datasize: i32, + outsize: ^i32, + outbuffer: rawptr) -> result_t, + destroy_unpacked_func_ptr: proc "c" ( + ctxt: context_t, data: rawptr, datasize: i32), + ) -> result_t --- + + /** @brief Enable long name support in the output context */ + + set_longname_support :: proc(ctxt: context_t, onoff: b32) -> result_t --- + + /** @brief Write the header data. + * + * Opening a new output file has a small initialization state problem + * compared to opening for read/update: we need to enable the user + * to specify an arbitrary set of metadata across an arbitrary number + * of parts. To avoid having to create the list of parts and entire + * metadata up front, prior to calling the above exr_start_write(), + * allow the data to be set, then once this is called, it switches + * into a mode where the library assumes the data is now valid. + * + * It will recompute the number of chunks that will be written, and + * reset the chunk offsets. If you modify file attributes or part + * information after a call to this, it will error. + */ + write_header :: proc(ctxt: context_t) -> result_t --- +} \ No newline at end of file diff --git a/vendor/openexr/exr_debug.odin b/vendor/openexr/exr_debug.odin new file mode 100644 index 000000000..f2c8e18cb --- /dev/null +++ b/vendor/openexr/exr_debug.odin @@ -0,0 +1,8 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + print_context_info :: proc(c: const_context_t, verbose: b32) -> result_t --- +} \ No newline at end of file diff --git a/vendor/openexr/exr_decode.odin b/vendor/openexr/exr_decode.odin new file mode 100644 index 000000000..7eca819f7 --- /dev/null +++ b/vendor/openexr/exr_decode.odin @@ -0,0 +1,288 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +import "core:c" + +/** Can be bit-wise or'ed into the decode_flags in the decode pipeline. + * + * Indicates that the sample count table should be decoded to a an + * individual sample count list (n, m, o, ...), with an extra int at + * the end containing the total samples. + * + * Without this (i.e. a value of 0 in that bit), indicates the sample + * count table should be decoded to a cumulative list (n, n+m, n+m+o, + * ...), which is the on-disk representation. + */ +DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL :: u16(1 << 0) + +/** Can be bit-wise or'ed into the decode_flags in the decode pipeline. + * + * Indicates that the data in the channel pointers to decode to is not + * a direct pointer, but instead is a pointer-to-pointers. In this + * mode, the user_pixel_stride and user_line_stride are used to + * advance the pointer offsets for each pixel in the output, but the + * user_bytes_per_element and user_data_type are used to put + * (successive) entries into each destination pointer (if not `NULL`). + * + * So each channel pointer must then point to an array of + * chunk.width * chunk.height pointers. + * + * With this, you can only extract desired pixels (although all the + * pixels must be initially decompressed) to handle such operations + * like proxying where you might want to read every other pixel. + * + * If this is NOT set (0), the default unpacking routine assumes the + * data will be planar and contiguous (each channel is a separate + * memory block), ignoring user_line_stride and user_pixel_stride. + */ +DECODE_NON_IMAGE_DATA_AS_POINTERS :: u16(1 << 1) + +/** + * When reading non-image data (i.e. deep), only read the sample table. + */ +DECODE_SAMPLE_DATA_ONLY :: u16(1 << 2) + +/** + * Struct meant to be used on a per-thread basis for reading exr data + * + * As should be obvious, this structure is NOT thread safe, but rather + * meant to be used by separate threads, which can all be accessing + * the same context concurrently. + */ +decode_pipeline_t :: struct { + /** The output channel information for this chunk. + * + * User is expected to fill the channel pointers for the desired + * output channels (any that are `NULL` will be skipped) if you are + * going to use exr_decoding_choose_default_routines(). If all that is + * desired is to read and decompress the data, this can be left + * uninitialized. + * + * Describes the channel information. This information is + * allocated dynamically during exr_decoding_initialize(). + */ + channels: [^]coding_channel_info_t, + channel_count: i16, + + /** Decode flags to control the behavior. */ + decode_flags: u16, + + /** Copy of the parameters given to the initialize/update for + * convenience. + */ + part_index: c.int, + ctx: const_context_t, + chunk: chunk_info_t, + + /** Can be used by the user to pass custom context data through + * the decode pipeline. + */ + decoding_user_data: rawptr, + + /** The (compressed) buffer. + * + * If `NULL`, will be allocated during the run of the pipeline. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + packed_buffer: rawptr, + + /** Used when re-using the same decode pipeline struct to know if + * chunk is changed size whether current buffer is large enough. + */ + packed_alloc_size: c.size_t, + + /** The decompressed buffer (unpacked_size from the chunk block + * info), but still packed into storage order, only needed for + * compressed files. + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + unpacked_buffer: rawptr, + + /** Used when re-using the same decode pipeline struct to know if + * chunk is changed size whether current buffer is large enough. + */ + unpacked_alloc_size: c.size_t, + + /** For deep or other non-image data: packed sample table + * (compressed, raw on disk representation). + */ + packed_sample_count_table: rawptr, + packed_sample_count_alloc_size: c.size_t, + + /** Usable, native sample count table. Depending on the flag set + * above, will be decoded to either a cumulative list (n, n+m, + * n+m+o, ...), or an individual table (n, m, o, ...). As an + * optimization, if the latter individual count table is chosen, + * an extra int32_t will be allocated at the end of the table to + * contain the total count of samples, so the table will be n+1 + * samples in size. + */ + sample_count_table: [^]i32, + sample_count_alloc_size: c.size_t, + + /** A scratch buffer of unpacked_size for intermediate results. + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + scratch_buffer_1: rawptr, + + /** Used when re-using the same decode pipeline struct to know if + * chunk is changed size whether current buffer is large enough. + */ + scratch_alloc_size_1: c.size_t, + + /** Some decompression routines may need a second scratch buffer (zlib). + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + scratch_buffer_2: rawptr, + + /** Used when re-using the same decode pipeline struct to know if + * chunk is changed size whether current buffer is large enough. + */ + scratch_alloc_size_2: c.size_t, + + /** Enable a custom allocator for the different buffers (if + * decoding on a GPU). If `NULL`, will use the allocator from the + * context. + */ + alloc_fn: proc "c" (transcoding_pipeline_buffer_id_t, c.size_t) -> rawptr, + + /** Enable a custom allocator for the different buffers (if + * decoding on a GPU). If `NULL`, will use the allocator from the + * context. + */ + free_fn: proc "c" (transcoding_pipeline_buffer_id_t, rawptr), + + /** Function chosen to read chunk data from the context. + * + * Initialized to a default generic read routine, may be updated + * based on channel information when + * exr_decoding_choose_default_routines() is called. This is done such that + * if the file is uncompressed and the output channel data is + * planar and the same type, the read function can read straight + * into the output channels, getting closer to a zero-copy + * operation. Otherwise a more traditional read, decompress, then + * unpack pipeline will be used with a default reader. + * + * This is allowed to be overridden, but probably is not necessary + * in most scenarios. + */ + read_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t, + + /** Function chosen based on the compression type of the part to + * decompress data. + * + * If the user has a custom decompression method for the + * compression on this part, this can be changed after + * initialization. + * + * If only compressed data is desired, then assign this to `NULL` + * after initialization. + */ + decompress_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t, + + /** Function which can be provided if you have bespoke handling for + * non-image data and need to re-allocate the data to handle the + * about-to-be unpacked data. + * + * If left `NULL`, will assume the memory pointed to by the channel + * pointers is sufficient. + */ + realloc_nonimage_data_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t, + + /** Function chosen based on the output layout of the channels of the part to + * decompress data. + * + * This will be `NULL` after initialization, until the user + * specifies a custom routine, or initializes the channel data and + * calls exr_decoding_choose_default_routines(). + * + * If only compressed data is desired, then leave or assign this + * to `NULL` after initialization. + */ + unpack_and_convert_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t, + + /** Small stash of channel info values. This is faster than calling + * malloc when the channel count in the part is small (RGBAZ), + * which is super common, however if there are a large number of + * channels, it will allocate space for that, so do not rely on + * this being used. + */ + _quick_chan_store: [5]coding_channel_info_t, +} + +DECODE_PIPELINE_INITIALIZER :: decode_pipeline_t{} + + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + /** Initialize the decoding pipeline structure with the channel info + * for the specified part, and the first block to be read. + * + * NB: The decode->unpack_and_convert_fn field will be `NULL` after this. If that + * stage is desired, initialize the channel output information and + * call exr_decoding_choose_default_routines(). + */ + decoding_initialize :: proc( + ctxt: const_context_t, + part_index: c.int, + cinfo: ^chunk_info_t, + decode: ^decode_pipeline_t) -> result_t --- + + /** Given an initialized decode pipeline, find appropriate functions + * to read and shuffle/convert data into the defined channel outputs. + * + * Calling this is not required if custom routines will be used, or if + * just the raw compressed data is desired. Although in that scenario, + * it is probably easier to just read the chunk directly using + * exr_read_chunk(). + */ + decoding_choose_default_routines :: proc( + ctxt: const_context_t, part_index: c.int, decode: ^decode_pipeline_t) -> result_t --- + + /** Given a decode pipeline previously initialized, update it for the + * new chunk to be read. + * + * In this manner, memory buffers can be re-used to avoid continual + * malloc/free calls. Further, it allows the previous choices for + * the various functions to be quickly re-used. + */ + decoding_update :: proc( + ctxt: const_context_t, + part_index: c.int, + cinfo: ^chunk_info_t, + decode: ^decode_pipeline_t) -> result_t --- + + /** Execute the decoding pipeline. */ + decoding_run :: proc( + ctxt: const_context_t, part_index: c.int, decode: ^decode_pipeline_t) -> result_t --- + + /** Free any intermediate memory in the decoding pipeline. + * + * This does *not* free any pointers referred to in the channel info + * areas, but rather only the intermediate buffers and memory needed + * for the structure itself. + */ + decoding_destroy :: proc(ctxt: const_context_t, decode: ^decode_pipeline_t) -> result_t --- +} \ No newline at end of file diff --git a/vendor/openexr/exr_encode.odin b/vendor/openexr/exr_encode.odin new file mode 100644 index 000000000..402aaba81 --- /dev/null +++ b/vendor/openexr/exr_encode.odin @@ -0,0 +1,319 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +import "core:c" + +/** Can be bit-wise or'ed into the decode_flags in the decode pipeline. + * + * Indicates that the sample count table should be encoded from an + * individual sample count list (n, m, o, ...), meaning it will have + * to compute the cumulative counts on the fly. + * + * Without this (i.e. a value of 0 in that bit), indicates the sample + * count table is already a cumulative list (n, n+m, n+m+o, ...), + * which is the on-disk representation. + */ +ENCODE_DATA_SAMPLE_COUNTS_ARE_INDIVIDUAL :: u16(1 << 0) + +/** Can be bit-wise or'ed into the decode_flags in the decode pipeline. + * + * Indicates that the data in the channel pointers to encode from is not + * a direct pointer, but instead is a pointer-to-pointers. In this + * mode, the user_pixel_stride and user_line_stride are used to + * advance the pointer offsets for each pixel in the output, but the + * user_bytes_per_element and user_data_type are used to put + * (successive) entries into each destination. + * + * So each channel pointer must then point to an array of + * chunk.width * chunk.height pointers. If an entry is + * `NULL`, 0 samples will be placed in the output. + * + * If this is NOT set (0), the default packing routine assumes the + * data will be planar and contiguous (each channel is a separate + * memory block), ignoring user_line_stride and user_pixel_stride and + * advancing only by the sample counts and bytes per element. + */ +ENCODE_NON_IMAGE_DATA_AS_POINTERS :: u16(1 << 1) + +/** Struct meant to be used on a per-thread basis for writing exr data. + * + * As should be obvious, this structure is NOT thread safe, but rather + * meant to be used by separate threads, which can all be accessing + * the same context concurrently. + */ + encode_pipeline_t :: struct { + /** The output channel information for this chunk. + * + * User is expected to fill the channel pointers for the input + * channels. For writing, all channels must be initialized prior + * to using exr_encoding_choose_default_routines(). If a custom pack routine + * is written, that is up to the implementor. + * + * Describes the channel information. This information is + * allocated dynamically during exr_encoding_initialize(). + */ + channels: [^]coding_channel_info_t, + channel_count: i16, + + /** Encode flags to control the behavior. */ + encode_flags: u16, + + /** Copy of the parameters given to the initialize/update for convenience. */ + part_index: c.int, + ctx: const_context_t, + chunk: chunk_info_t, + + /** Can be used by the user to pass custom context data through + * the encode pipeline. + */ + encoding_user_data: rawptr, + + /** The packed buffer where individual channels have been put into here. + * + * If `NULL`, will be allocated during the run of the pipeline. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + packed_buffer: rawptr, + + /** Differing from the allocation size, the number of actual bytes */ + packed_bytes: u64, + + /** Used when re-using the same encode pipeline struct to know if + * chunk is changed size whether current buffer is large enough + * + * If `NULL`, will be allocated during the run of the pipeline. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + packed_alloc_size: c.size_t, + + /** For deep data. NB: the members NOT const because we need to + * temporarily swap it to xdr order and restore it (to avoid a + * duplicate buffer allocation). + * + * Depending on the flag set above, will be treated either as a + * cumulative list (n, n+m, n+m+o, ...), or an individual table + * (n, m, o, ...). */ + sample_count_table: [^]i32, + + /** Allocated table size (to avoid re-allocations). Number of + * samples must always be width * height for the chunk. + */ + sample_count_alloc_size: c.size_t, + + /** Packed sample table (compressed, raw on disk representation) + * for deep or other non-image data. + */ + packed_sample_count_table: rawptr, + + /** Number of bytes to write (actual size) for the + * packed_sample_count_table. + */ + packed_sample_count_bytes: c.size_t, + + /** Allocated size (to avoid re-allocations) for the + * packed_sample_count_table. + */ + packed_sample_count_alloc_size: c.size_t, + + /** The compressed buffer, only needed for compressed files. + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + compressed_buffer: rawptr, + + /** Must be filled in as the pipeline runs to inform the writing + * software about the compressed size of the chunk (if it is an + * uncompressed file or the compression would make the file + * larger, it is expected to be the packed_buffer) + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to zero here. Be cognizant of any + * custom allocators. + */ + compressed_bytes: c.size_t, + + /** Used when re-using the same encode pipeline struct to know if + * chunk is changed size whether current buffer is large enough. + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to zero here. Be cognizant of any + * custom allocators. + */ + compressed_alloc_size: c.size_t, + + /** A scratch buffer for intermediate results. + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + scratch_buffer_1: rawptr, + + /** Used when re-using the same encode pipeline struct to know if + * chunk is changed size whether current buffer is large enough. + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + scratch_alloc_size_1: c.size_t, + + /** Some compression routines may need a second scratch buffer. + * + * If `NULL`, will be allocated during the run of the pipeline when + * needed. + * + * If the caller wishes to take control of the buffer, simple + * adopt the pointer and set it to `NULL` here. Be cognizant of any + * custom allocators. + */ + scratch_buffer_2: rawptr, + + /** Used when re-using the same encode pipeline struct to know if + * chunk is changed size whether current buffer is large enough. + */ + scratch_alloc_size_2: c.size_t, + + /** Enable a custom allocator for the different buffers (if + * encoding on a GPU). If `NULL`, will use the allocator from the + * context. + */ + alloc_fn: proc "c" (transcoding_pipeline_buffer_id_t, c.size_t) -> rawptr, + + /** Enable a custom allocator for the different buffers (if + * encoding on a GPU). If `NULL`, will use the allocator from the + * context. + */ + free_fn: proc "c" (transcoding_pipeline_buffer_id_t, rawptr), + + /** Function chosen based on the output layout of the channels of the part to + * decompress data. + * + * If the user has a custom method for the + * compression on this part, this can be changed after + * initialization. + */ + convert_and_pack_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t, + + /** Function chosen based on the compression type of the part to + * compress data. + * + * If the user has a custom compression method for the compression + * type on this part, this can be changed after initialization. + */ + compress_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t, + + /** This routine is used when waiting for other threads to finish + * writing previous chunks such that this thread can write this + * chunk. This is used for parts which have a specified chunk + * ordering (increasing/decreasing y) and the chunks can not be + * written randomly (as could be true for uncompressed). + * + * This enables the calling application to contribute thread time + * to other computation as needed, or just use something like + * pthread_yield(). + * + * By default, this routine will be assigned to a function which + * returns an error, failing the encode immediately. In this way, + * it assumes that there is only one thread being used for + * writing. + * + * It is up to the user to provide an appropriate routine if + * performing multi-threaded writing. + */ + yield_until_ready_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t, + + /** Function chosen to write chunk data to the context. + * + * This is allowed to be overridden, but probably is not necessary + * in most scenarios. + */ + write_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t, + + /** Small stash of channel info values. This is faster than calling + * malloc when the channel count in the part is small (RGBAZ), + * which is super common, however if there are a large number of + * channels, it will allocate space for that, so do not rely on + * this being used. + */ + _quick_chan_store: [5]coding_channel_info_t, +} + +ENCODE_PIPELINE_INITIALIZER :: encode_pipeline_t{} + + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + /** Initialize the encoding pipeline structure with the channel info + * for the specified part based on the chunk to be written. + * + * NB: The encode_pipe->pack_and_convert_fn field will be `NULL` after this. If that + * stage is desired, initialize the channel output information and + * call exr_encoding_choose_default_routines(). + */ + encoding_initialize :: proc( + ctxt: const_context_t, + part_index: c.int, + cinfo: ^chunk_info_t, + encode_pipe: ^encode_pipeline_t) -> result_t --- + + /** Given an initialized encode pipeline, find an appropriate + * function to shuffle and convert data into the defined channel + * outputs. + * + * Calling this is not required if a custom routine will be used, or + * if just the raw decompressed data is desired. + */ + encoding_choose_default_routines :: proc( + ctxt: const_context_t, + part_index: c.int, + encode_pipe: ^encode_pipeline_t) -> result_t --- + + /** Given a encode pipeline previously initialized, update it for the + * new chunk to be written. + * + * In this manner, memory buffers can be re-used to avoid continual + * malloc/free calls. Further, it allows the previous choices for + * the various functions to be quickly re-used. + */ + encoding_update :: proc( + ctxt: const_context_t, + part_index: c.int, + cinfo: ^chunk_info_t, + encode_pipe: ^encode_pipeline_t) -> result_t --- + + /** Execute the encoding pipeline. */ + encoding_run :: proc( + ctxt: const_context_t, + part_index: c.int, + encode_pipe: ^encode_pipeline_t) -> result_t --- + + /** Free any intermediate memory in the encoding pipeline. + * + * This does NOT free any pointers referred to in the channel info + * areas, but rather only the intermediate buffers and memory needed + * for the structure itself. + */ + encoding_destroy :: proc(ctxt: const_context_t, encode_pipe: ^encode_pipeline_t) -> result_t --- +} \ No newline at end of file diff --git a/vendor/openexr/exr_errors.odin b/vendor/openexr/exr_errors.odin new file mode 100644 index 000000000..cf2194756 --- /dev/null +++ b/vendor/openexr/exr_errors.odin @@ -0,0 +1,62 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +import "core:c" +#assert(size_of(c.int) == size_of(i32)) + +/** Error codes that may be returned by various functions. */ +error_code_t :: enum i32 { + SUCCESS = 0, + OUT_OF_MEMORY, + MISSING_CONTEXT_ARG, + INVALID_ARGUMENT, + ARGUMENT_OUT_OF_RANGE, + FILE_ACCESS, + FILE_BAD_HEADER, + NOT_OPEN_READ, + NOT_OPEN_WRITE, + HEADER_NOT_WRITTEN, + READ_IO, + WRITE_IO, + NAME_TOO_LONG, + MISSING_REQ_ATTR, + INVALID_ATTR, + NO_ATTR_BY_NAME, + ATTR_TYPE_MISMATCH, + ATTR_SIZE_MISMATCH, + SCAN_TILE_MIXEDAPI, + TILE_SCAN_MIXEDAPI, + MODIFY_SIZE_CHANGE, + ALREADY_WROTE_ATTRS, + BAD_CHUNK_LEADER, + CORRUPT_CHUNK, + INCORRECT_PART, + INCORRECT_CHUNK, + USE_SCAN_DEEP_WRITE, + USE_TILE_DEEP_WRITE, + USE_SCAN_NONDEEP_WRITE, + USE_TILE_NONDEEP_WRITE, + INVALID_SAMPLE_DATA, + FEATURE_NOT_IMPLEMENTED, + UNKNOWN, +} + +/** Return type for all functions. */ +result_t :: error_code_t + + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + /** @brief Return a static string corresponding to the specified error code. + * + * The string should not be freed (it is compiled into the binary). + */ + get_default_error_message :: proc(code: result_t) -> cstring --- + + /** @brief Return a static string corresponding to the specified error code. + * + * The string should not be freed (it is compiled into the binary). + */ + get_error_code_as_string :: proc(code: result_t) -> cstring --- +} diff --git a/vendor/openexr/exr_part.odin b/vendor/openexr/exr_part.odin new file mode 100644 index 000000000..24e1eb081 --- /dev/null +++ b/vendor/openexr/exr_part.odin @@ -0,0 +1,733 @@ +package vendor_openexr + +foreign import lib "exr.lib" + +import "core:c" + +attr_list_access_mode_t :: enum c.int { + FILE_ORDER, /**< Order they appear in the file */ + SORTED_ORDER, /**< Alphabetically sorted */ +} + +@(link_prefix="exr_", default_calling_convention="c") +foreign lib { + /** @brief Query how many parts are in the file. */ + get_count :: proc (ctxt: const_context_t, count: ^c.int) -> result_t --- + + /** @brief Query the part name for the specified part. + * + * NB: If this file is a single part file and name has not been set, this + * will return `NULL`. + */ + get_name :: proc(ctxt: const_context_t, part_index: c.int, out: ^cstring) -> result_t --- + + /** @brief Query the storage type for the specified part. */ + get_storage :: proc(ctxt: const_context_t, part_index: c.int, out: ^storage_t) -> result_t --- + + /** @brief Define a new part in the file. */ + add_part :: proc( + ctxt: context_t, + partname: rawptr, + type: storage_t, + new_index: ^c.int) -> result_t --- + + /** @brief Query how many levels are in the specified part. + * + * If the part is a tiled part, fill in how many tile levels are present. + * + * Return `ERR_SUCCESS` on success, an error otherwise (i.e. if the part + * is not tiled). + * + * It is valid to pass `NULL` to either of the @p levelsx or @p levelsy + * arguments, which enables testing if this part is a tiled part, or + * if you don't need both (i.e. in the case of a mip-level tiled + * image) + */ + get_tile_levels :: proc( + ctxt: const_context_t, + part_index: c.int, + levelsx: ^i32, + levelsy: ^i32) -> result_t --- + + /** @brief Query the tile size for a particular level in the specified part. + * + * If the part is a tiled part, fill in the tile size for the + * specified part/level. + * + * Return `ERR_SUCCESS` on success, an error otherwise (i.e. if the + * part is not tiled). + * + * It is valid to pass `NULL` to either of the @p tilew or @p tileh + * arguments, which enables testing if this part is a tiled part, or + * if you don't need both (i.e. in the case of a mip-level tiled + * image) + */ + get_tile_sizes :: proc( + ctxt: const_context_t, + part_index: c.int, + levelx: c.int, + levely: c.int, + tilew: ^i32, + tileh: ^i32) -> result_t --- + + /** @brief Query the data sizes for a particular level in the specified part. + * + * If the part is a tiled part, fill in the width/height for the + * specified levels. + * + * Return `ERR_SUCCESS` on success, an error otherwise (i.e. if the part + * is not tiled). + * + * It is valid to pass `NULL` to either of the @p levw or @p levh + * arguments, which enables testing if this part is a tiled part, or + * if you don't need both for some reason. + */ + get_level_sizes :: proc( + ctxt: const_context_t, + part_index: c.int, + levelx: c.int, + levely: c.int, + levw: ^i32, + levh: ^i32) -> result_t --- + + /** Return the number of chunks contained in this part of the file. + * + * As in the technical documentation for OpenEXR, the chunk is the + * generic term for a pixel data block. This is the atomic unit that + * this library uses to negotiate data to and from a context. + * + * This should be used as a basis for splitting up how a file is + * processed. Depending on the compression, a different number of + * scanlines are encoded in each chunk, and since those need to be + * encoded/decoded as a block, the chunk should be the basis for I/O + * as well. + */ + get_chunk_count :: proc(ctxt: const_context_t, part_index: c.int, out: ^i32) -> result_t --- + + /** Return the number of scanlines chunks for this file part. + * + * When iterating over a scanline file, this may be an easier metric + * for multi-threading or other access than only negotiating chunk + * counts, and so is provided as a utility. + */ + get_scanlines_per_chunk :: proc(ctxt: const_context_t, part_index: c.int, out: ^i32) -> result_t --- + + /** Return the maximum unpacked size of a chunk for the file part. + * + * This may be used ahead of any actual reading of data, so can be + * used to pre-allocate buffers for multiple threads in one block or + * whatever your application may require. + */ + get_chunk_unpacked_size :: proc(ctxt: const_context_t, part_index: c.int, out: ^u64) -> result_t --- + + /** @brief Retrieve the zip compression level used for the specified part. + * + * This only applies when the compression method involves using zip + * compression (zip, zips, some modes of DWAA/DWAB). + * + * This value is NOT persisted in the file, and only exists for the + * lifetime of the context, so will be at the default value when just + * reading a file. + */ + get_zip_compression_level :: proc(ctxt: const_context_t, part_index: c.int, level: ^c.int) -> result_t --- + + /** @brief Set the zip compression method used for the specified part. + * + * This only applies when the compression method involves using zip + * compression (zip, zips, some modes of DWAA/DWAB). + * + * This value is NOT persisted in the file, and only exists for the + * lifetime of the context, so this value will be ignored when + * reading a file. + */ + set_zip_compression_level :: proc(ctxt: context_t, part_index: c.int, level: c.int) -> result_t --- + + /** @brief Retrieve the dwa compression level used for the specified part. + * + * This only applies when the compression method is DWAA/DWAB. + * + * This value is NOT persisted in the file, and only exists for the + * lifetime of the context, so will be at the default value when just + * reading a file. + */ + get_dwa_compression_level :: proc(ctxt: const_context_t, part_index: c.int, level: ^f32) -> result_t --- + + /** @brief Set the dwa compression method used for the specified part. + * + * This only applies when the compression method is DWAA/DWAB. + * + * This value is NOT persisted in the file, and only exists for the + * lifetime of the context, so this value will be ignored when + * reading a file. + */ + set_dwa_compression_level :: proc(ctxt: context_t, part_index: c.int, level: f32) -> result_t --- + + /**************************************/ + + /** @defgroup PartMetadata Functions to get and set metadata for a particular part. + * @{ + * + */ + + /** @brief Query the count of attributes in a part. */ + get_attribute_count :: proc(ctxt: const_context_t, part_index: c.int, count: ^i32) -> result_t --- + + /** @brief Query a particular attribute by index. */ + get_attribute_by_index :: proc( + ctxt: const_context_t, + part_index: c.int, + mode: attr_list_access_mode_t, + idx: i32, + outattr: ^^attribute_t) -> result_t --- + + /** @brief Query a particular attribute by name. */ + get_attribute_by_name :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + outattr: ^^attribute_t) -> result_t --- + + /** @brief Query the list of attributes in a part. + * + * This retrieves a list of attributes currently defined in a part. + * + * If outlist is `NULL`, this function still succeeds, filling only the + * count. In this manner, the user can allocate memory for the list of + * attributes, then re-call this function to get the full list. + */ + get_attribute_list :: proc( + ctxt: const_context_t, + part_index: c.int, + mode: attr_list_access_mode_t, + count: ^i32, + outlist: ^[^]attribute_t) -> result_t --- + + /** Declare an attribute within the specified part. + * + * Only valid when a file is opened for write. + */ + attr_declare_by_type :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + type: cstring, + newattr: ^^attribute_t) -> result_t --- + + /** @brief Declare an attribute within the specified part. + * + * Only valid when a file is opened for write. + */ + attr_declare :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + type: attribute_type_t, + newattr: ^^attribute_t) -> result_t --- + + /** + * @defgroup RequiredAttributeHelpers Required Attribute Utililities + * + * @brief These are a group of functions for attributes that are + * required to be in every part of every file. + * + * @{ + */ + + /** @brief Initialize all required attributes for all files. + * + * NB: other file types do require other attributes, such as the tile + * description for a tiled file. + */ + initialize_required_attr :: proc( + ctxt: context_t, + part_index: c.int, + displayWindow: ^attr_box2i_t, + dataWindow: ^attr_box2i_t, + pixelaspectratio: f32, + screenWindowCenter: attr_v2f_t, + screenWindowWidth: f32, + lineorder: lineorder_t, + ctype: compression_t) -> result_t --- + + /** @brief Initialize all required attributes to default values: + * + * - `displayWindow` is set to (0, 0 -> @p width - 1, @p height - 1) + * - `dataWindow` is set to (0, 0 -> @p width - 1, @p height - 1) + * - `pixelAspectRatio` is set to 1.0 + * - `screenWindowCenter` is set to 0.f, 0.f + * - `screenWindowWidth` is set to 1.f + * - `lineorder` is set to `INCREASING_Y` + * - `compression` is set to @p ctype + */ + initialize_required_attr_simple :: proc( + ctxt: context_t, + part_index: c.int, + width: i32, + height: i32, + ctype: compression_t) -> result_t --- + + /** @brief Copy the attributes from one part to another. + * + * This allows one to quickly unassigned attributes from one source to another. + * + * If an attribute in the source part has not been yet set in the + * destination part, the item will be copied over. + * + * For example, when you add a part, the storage type and name + * attributes are required arguments to the definition of a new part, + * but channels has not yet been assigned. So by calling this with an + * input file as the source, you can copy the channel definitions (and + * any other unassigned attributes from the source). + */ + copy_unset_attributes :: proc( + ctxt: context_t, + part_index: c.int, + source: const_context_t, + src_part_index: c.int) -> result_t --- + + /** @brief Retrieve the list of channels. */ + get_channels :: proc(ctxt: const_context_t, part_index: c.int, chlist: ^^attr_chlist_t) -> result_t --- + + /** @brief Define a new channel to the output file part. + * + * The @p percept parameter is used for lossy compression techniques + * to indicate that the value represented is closer to linear (1) or + * closer to logarithmic (0). For r, g, b, luminance, this is normally + * 0. + */ + add_channel :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + ptype: pixel_type_t, + percept: perceptual_treatment_t, + xsamp: i32, + ysamp: i32) -> c.int --- + + /** @brief Copy the channels from another source. + * + * Useful if you are manually constructing the list or simply copying + * from an input file. + */ + set_channels :: proc(ctxt: context_t, part_index: c.int, channels: ^attr_chlist_t) -> result_t --- + + /** @brief Retrieve the compression method used for the specified part. */ + get_compression :: proc(ctxt: const_context_t, part_index: c.int, compression: ^compression_t) -> result_t --- + /** @brief Set the compression method used for the specified part. */ + set_compression :: proc(ctxt: context_t, part_index: c.int, ctype: compression_t) -> result_t --- + + /** @brief Retrieve the data window for the specified part. */ + get_data_window :: proc(ctxt: const_context_t, part_index: c.int, out: ^attr_box2i_t) -> result_t --- + /** @brief Set the data window for the specified part. */ + set_data_window :: proc(ctxt: context_t, part_index: c.int, dw: ^attr_box2i_t) -> c.int --- + + /** @brief Retrieve the display window for the specified part. */ + get_display_window :: proc(ctxt: const_context_t, part_index: c.int, out: ^attr_box2i_t) -> result_t --- + /** @brief Set the display window for the specified part. */ + set_display_window :: proc(ctxt: context_t, part_index: c.int, dw: ^attr_box2i_t) -> c.int --- + + /** @brief Retrieve the line order for storing data in the specified part (use 0 for single part images). */ + get_lineorder :: proc(ctxt: const_context_t, part_index: c.int, out: ^lineorder_t) -> result_t --- + /** @brief Set the line order for storing data in the specified part (use 0 for single part images). */ + set_lineorder :: proc(ctxt: context_t, part_index: c.int, lo: lineorder_t) -> result_t --- + + /** @brief Retrieve the pixel aspect ratio for the specified part (use 0 for single part images). */ + get_pixel_aspect_ratio :: proc(ctxt: const_context_t, part_index: c.int, par: ^f32) -> result_t --- + /** @brief Set the pixel aspect ratio for the specified part (use 0 for single part images). */ + set_pixel_aspect_ratio :: proc(ctxt: context_t, part_index: c.int, par: f32) -> result_t --- + + /** @brief Retrieve the screen oriented window center for the specified part (use 0 for single part images). */ + get_screen_window_center :: proc(ctxt: const_context_t, part_index: c.int, wc: ^attr_v2f_t) -> result_t --- + /** @brief Set the screen oriented window center for the specified part (use 0 for single part images). */ + set_screen_window_center :: proc(ctxt: context_t, part_index: c.int, wc: ^attr_v2f_t) -> c.int --- + + /** @brief Retrieve the screen oriented window width for the specified part (use 0 for single part images). */ + get_screen_window_width :: proc(ctxt: const_context_t, part_index: c.int, out: ^f32) -> result_t --- + /** @brief Set the screen oriented window width for the specified part (use 0 for single part images). */ + set_screen_window_width :: proc(ctxt: context_t, part_index: c.int, ssw: f32) -> result_t --- + + /** @brief Retrieve the tiling info for a tiled part (use 0 for single part images). */ + get_tile_descriptor :: proc( + ctxt: const_context_t, + part_index: c.int, + xsize: ^u32, + ysize: ^u32, + level: ^tile_level_mode_t, + round: ^tile_round_mode_t) -> result_t --- + + /** @brief Set the tiling info for a tiled part (use 0 for single part images). */ + set_tile_descriptor :: proc( + ctxt: context_t, + part_index: c.int, + x_size: u32, + y_size: u32, + level_mode: tile_level_mode_t, + round_mode: tile_round_mode_t) -> result_t --- + + set_name :: proc(ctxt: context_t, part_index: c.int, val: cstring) -> result_t --- + + get_version :: proc(ctxt: const_context_t, part_index: c.int, out: ^i32) -> result_t --- + + set_version :: proc(ctxt: context_t, part_index: c.int, val: i32) -> result_t --- + + set_chunk_count :: proc(ctxt: context_t, part_index: c.int, val: i32) -> result_t --- + + /** @} */ /* required attr group. */ + + /** + * @defgroup BuiltinAttributeHelpers Attribute utilities for builtin types + * + * @brief These are a group of functions for attributes that use the builtin types. + * + * @{ + */ + + attr_get_box2i :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + outval: ^attr_box2i_t) -> result_t --- + + attr_set_box2i :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + val: ^attr_box2i_t) -> result_t --- + + attr_get_box2f :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + outval: ^attr_box2f_t) -> result_t --- + + attr_set_box2f :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + val: ^attr_box2f_t) -> result_t --- + + /** @brief Zero-copy query of channel data. + * + * Do not free or manipulate the @p chlist data, or use + * after the lifetime of the context. + */ + attr_get_channels :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + chlist: ^^attr_chlist_t) -> result_t --- + + /** @brief This allows one to quickly copy the channels from one file + * to another. + */ + attr_set_channels :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + channels: ^attr_chlist_t) -> result_t --- + + attr_get_chromaticities :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + chroma: ^attr_chromaticities_t) -> result_t --- + + attr_set_chromaticities :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + chroma: ^attr_chromaticities_t) -> result_t --- + + attr_get_compression :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^compression_t) -> result_t --- + + attr_set_compression :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + comp: compression_t) -> result_t --- + + attr_get_double :: proc(ctxt: const_context_t, part_index: c.int, name: cstring, out: f64) -> result_t --- + + attr_set_double :: proc(ctxt: context_t, part_index: c.int, name: cstring, val: f64) -> result_t --- + + attr_get_envmap :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^envmap_t) -> result_t --- + + attr_set_envmap :: proc(ctxt: context_t, part_index: c.int, name: cstring, emap: envmap_t) -> result_t --- + + attr_get_float :: proc(ctxt: const_context_t, part_index: c.int, name: cstring, out: ^f32) -> result_t --- + + attr_set_float :: proc(ctxt: context_t, part_index: c.int, name: cstring, val: f32) -> result_t --- + + /** @brief Zero-copy query of float data. + * + * Do not free or manipulate the @p out data, or use after the + * lifetime of the context. + */ + attr_get_float_vector :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + sz: ^i32, + out: ^[^]f32) -> result_t --- + + attr_set_float_vector :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + sz: i32, + vals: [^]f32) -> result_t --- + + attr_get_int :: proc(ctxt: const_context_t, part_index: c.int, name: cstring, out: ^i32) -> result_t --- + + attr_set_int :: proc(ctxt: context_t, part_index: c.int, name: cstring, val: i32) -> result_t --- + + attr_get_keycode :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_keycode_t) -> result_t --- + + attr_set_keycode :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + kc: ^attr_keycode_t) -> result_t --- + + attr_get_lineorder :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^lineorder_t) -> result_t --- + + attr_set_lineorder :: proc(ctxt: context_t, part_index: c.int, name: cstring, lo: lineorder_t) -> result_t --- + + attr_get_m33f :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_m33f_t) -> result_t --- + + attr_set_m33f :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + m: ^attr_m33f_t) -> result_t --- + + attr_get_m33d :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_m33d_t) -> result_t --- + + attr_set_m33d :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + m: ^attr_m33d_t) -> result_t --- + + attr_get_m44f :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_m44f_t) -> result_t --- + + attr_set_m44f :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + m: ^attr_m44f_t) -> result_t --- + + attr_get_m44d :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_m44d_t) -> result_t --- + + attr_set_m44d :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + m: ^attr_m44d_t) -> result_t --- + + attr_get_preview :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_preview_t) -> result_t --- + + attr_set_preview :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + p: ^attr_preview_t) -> result_t --- + + attr_get_rational :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_rational_t) -> result_t --- + + attr_set_rational :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + r: ^attr_rational_t) -> result_t --- + + /** @brief Zero-copy query of string value. + * + * Do not modify the string pointed to by @p out, and do not use + * after the lifetime of the context. + */ + attr_get_string :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + length: ^i32, + out: ^cstring) -> result_t --- + + attr_set_string :: proc(ctxt: context_t, part_index: c.int, name: cstring, s: cstring) -> result_t --- + + /** @brief Zero-copy query of string data. + * + * Do not free the strings pointed to by the array. + * + * Must provide @p size. + * + * \p out must be a ``^cstring`` array large enough to hold + * the string pointers for the string vector when provided. + */ + attr_get_string_vector :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + size: ^i32, + out: ^cstring) -> result_t --- + + attr_set_string_vector :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + size: i32, + sv: ^cstring) -> result_t --- + + attr_get_tiledesc :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_tiledesc_t) -> result_t --- + + attr_set_tiledesc :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + td: ^attr_tiledesc_t) -> result_t --- + + attr_get_timecode :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_timecode_t) -> result_t --- + + attr_set_timecode :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + tc: ^attr_timecode_t) -> result_t --- + + attr_get_v2i :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_v2i_t) -> result_t --- + + attr_set_v2i :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + v: ^attr_v2i_t) -> result_t --- + + attr_get_v2f :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_v2f_t) -> result_t --- + + attr_set_v2f :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + v: ^attr_v2f_t) -> result_t --- + + attr_get_v2d :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_v2d_t) -> result_t --- + + attr_set_v2d :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + v: ^attr_v2d_t) -> result_t --- + + attr_get_v3i :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_v3i_t) -> result_t --- + + attr_set_v3i :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + v: ^attr_v3i_t) -> result_t --- + + attr_get_v3f :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_v3f_t) -> result_t --- + + attr_set_v3f :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + v: ^attr_v3f_t) -> result_t --- + + attr_get_v3d :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + out: ^attr_v3d_t) -> result_t --- + + attr_set_v3d :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + v: ^attr_v3d_t) -> result_t --- + + attr_get_user :: proc( + ctxt: const_context_t, + part_index: c.int, + name: cstring, + type: ^cstring, + size: ^i32, + out: ^rawptr) -> result_t --- + + attr_set_user :: proc( + ctxt: context_t, + part_index: c.int, + name: cstring, + type: cstring, + size: i32, + out: rawptr) -> result_t --- + +} \ No newline at end of file From 6985181961ec2ed8910ea4650d1b6898952084c8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 2 May 2022 17:51:39 +0200 Subject: [PATCH 0659/1052] [xxhash] Add tests for large inputs Test XXH32, XXH64, XXH3-64 and XXH3-128 for large inputs, with both all-at-once and streaming APIs. XXH32_create_state and XXH64_create_state now implicitly call their "reset state" variants to simplify the streaming API to 3 steps: - create state / defer destroy - update - digest (finalize) These are tested with an array of 1, 2, 4, 8 and 16 megabytes worth of zeroes. All return the same hashes as do both the one-shot version, as well as that of the official xxhsum tool. 3778/3778 tests successful. --- core/hash/xxhash/xxhash_32.odin | 3 +- core/hash/xxhash/xxhash_64.odin | 1 + tests/core/hash/test_core_hash.odin | 86 +++++++++++++++++++++++- tests/core/hash/test_vectors_xxhash.odin | 72 +++++++++++++++++++- 4 files changed, 158 insertions(+), 4 deletions(-) diff --git a/core/hash/xxhash/xxhash_32.odin b/core/hash/xxhash/xxhash_32.odin index e63d998dd..5bc87c2c0 100644 --- a/core/hash/xxhash/xxhash_32.odin +++ b/core/hash/xxhash/xxhash_32.odin @@ -197,6 +197,7 @@ XXH32 :: proc(input: []u8, seed := XXH32_DEFAULT_SEED) -> (digest: XXH32_hash) { */ XXH32_create_state :: proc(allocator := context.allocator) -> (res: ^XXH32_state, err: Error) { state := new(XXH32_state, allocator) + XXH32_reset_state(state) return state, .None if state != nil else .Error } @@ -258,7 +259,7 @@ XXH32_update :: proc(state: ^XXH32_state, input: []u8) -> (err: Error) { v3 := state.v3 v4 := state.v4 - for len(buf) >= 15 { + for len(buf) >= 16 { #no_bounds_check v1 = XXH32_round(v1, XXH32_read32(buf, .Unaligned)); buf = buf[4:] #no_bounds_check v2 = XXH32_round(v2, XXH32_read32(buf, .Unaligned)); buf = buf[4:] #no_bounds_check v3 = XXH32_round(v3, XXH32_read32(buf, .Unaligned)); buf = buf[4:] diff --git a/core/hash/xxhash/xxhash_64.odin b/core/hash/xxhash/xxhash_64.odin index e95842168..9280e9c59 100644 --- a/core/hash/xxhash/xxhash_64.odin +++ b/core/hash/xxhash/xxhash_64.odin @@ -163,6 +163,7 @@ XXH64 :: proc(input: []u8, seed := XXH64_DEFAULT_SEED) -> (digest: XXH64_hash) { */ XXH64_create_state :: proc(allocator := context.allocator) -> (res: ^XXH64_state, err: Error) { state := new(XXH64_state, allocator) + XXH64_reset_state(state) return state, .None if state != nil else .Error } diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index 607642339..86c05fd44 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -31,8 +31,10 @@ when ODIN_TEST { main :: proc() { t := testing.T{} test_benchmark_runner(&t) - test_xxhash_vectors(&t) test_crc64_vectors(&t) + test_xxhash_vectors(&t) + test_xxhash_large(&t) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) if TEST_fail > 0 { os.exit(1) @@ -191,6 +193,88 @@ test_benchmark_runner :: proc(t: ^testing.T) { benchmark_print(name, options) } +@test +test_xxhash_large :: proc(t: ^testing.T) { + many_zeroes := make([]u8, 16 * 1024 * 1024) + defer delete(many_zeroes) + + // All at once. + for i, v in ZERO_VECTORS { + b := many_zeroes[:i] + + xxh32 := xxhash.XXH32(b) + xxh64 := xxhash.XXH64(b) + xxh3_64 := xxhash.XXH3_64(b) + xxh3_128 := xxhash.XXH3_128(b) + + xxh32_error := fmt.tprintf("[ XXH32(%03d) ] Expected: %08x. Got: %08x.", i, v.xxh_32, xxh32) + xxh64_error := fmt.tprintf("[ XXH64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh_64, xxh64) + xxh3_64_error := fmt.tprintf("[XXH3_64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh3_64, xxh3_64) + xxh3_128_error := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128) + + expect(t, xxh32 == v.xxh_32, xxh32_error) + expect(t, xxh64 == v.xxh_64, xxh64_error) + expect(t, xxh3_64 == v.xxh3_64, xxh3_64_error) + expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) + } + + // Streamed + for i, v in ZERO_VECTORS { + b := many_zeroes[:i] + + bytes_per_update := []int{1, 42, 13, 7, 16, 5, 23, 74, 1024, 511, 1023, 47} + update_size_idx: int + + xxh_32_state, xxh_32_err := xxhash.XXH32_create_state() + defer xxhash.XXH32_destroy_state(xxh_32_state) + expect(t, xxh_32_err == nil, "Problem initializing XXH_32 state.") + + xxh_64_state, xxh_64_err := xxhash.XXH64_create_state() + defer xxhash.XXH64_destroy_state(xxh_64_state) + expect(t, xxh_64_err == nil, "Problem initializing XXH_64 state.") + + xxh3_64_state, xxh3_64_err := xxhash.XXH3_create_state() + defer xxhash.XXH3_destroy_state(xxh3_64_state) + expect(t, xxh3_64_err == nil, "Problem initializing XXH3_64 state.") + + xxh3_128_state, xxh3_128_err := xxhash.XXH3_create_state() + defer xxhash.XXH3_destroy_state(xxh3_128_state) + expect(t, xxh3_128_err == nil, "Problem initializing XXH3_128 state.") + + // XXH3_128_update + + for len(b) > 0 { + update_size := min(len(b), bytes_per_update[update_size_idx % len(bytes_per_update)]) + update_size_idx += 1 + + xxhash.XXH32_update (xxh_32_state, b[:update_size]) + xxhash.XXH64_update (xxh_64_state, b[:update_size]) + + xxhash.XXH3_64_update (xxh3_64_state, b[:update_size]) + xxhash.XXH3_128_update(xxh3_128_state, b[:update_size]) + + b = b[update_size:] + } + + // Now finalize + xxh32 := xxhash.XXH32_digest(xxh_32_state) + xxh64 := xxhash.XXH64_digest(xxh_64_state) + + xxh3_64 := xxhash.XXH3_64_digest(xxh3_64_state) + xxh3_128 := xxhash.XXH3_128_digest(xxh3_128_state) + + xxh32_error := fmt.tprintf("[ XXH32(%03d) ] Expected: %08x. Got: %08x.", i, v.xxh_32, xxh32) + xxh64_error := fmt.tprintf("[ XXH64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh_64, xxh64) + xxh3_64_error := fmt.tprintf("[XXH3_64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh3_64, xxh3_64) + xxh3_128_error := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128) + + expect(t, xxh32 == v.xxh_32, xxh32_error) + expect(t, xxh64 == v.xxh_64, xxh64_error) + expect(t, xxh3_64 == v.xxh3_64, xxh3_64_error) + expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) + } +} + @test test_xxhash_vectors :: proc(t: ^testing.T) { fmt.println("Verifying against XXHASH_TEST_VECTOR_SEEDED:") diff --git a/tests/core/hash/test_vectors_xxhash.odin b/tests/core/hash/test_vectors_xxhash.odin index dccda5e53..6a37aef30 100644 --- a/tests/core/hash/test_vectors_xxhash.odin +++ b/tests/core/hash/test_vectors_xxhash.odin @@ -3,7 +3,7 @@ */ package test_core_hash -XXHASH_Test_Vectors_With_Seed :: struct #packed { +XXHASH_Test_Vectors :: struct #packed { /* Old hashes */ @@ -17,7 +17,75 @@ XXHASH_Test_Vectors_With_Seed :: struct #packed { xxh3_128: u128, } -XXHASH_TEST_VECTOR_SEEDED := map[u64][257]XXHASH_Test_Vectors_With_Seed{ +ZERO_VECTORS := map[int]XXHASH_Test_Vectors{ + 1024 * 1024 = { + /* + Old hashes + */ + xxh_32 = 0x9430f97f, // xxhsum -H0 + xxh_64 = 0x87d2a1b6e1163ef1, // xxhsum -H1 + + /* + XXH3 hashes + */ + xxh3_128 = 0xb6ef17a3448492b6918780b90550bf34, // xxhsum -H2 + xxh3_64 = 0x918780b90550bf34, // xxhsum -H3 + }, + 1024 * 2048 = { + /* + Old hashes + */ + xxh_32 = 0xeeb74ca1, // xxhsum -H0 + xxh_64 = 0xeb8a7322f88e23db, // xxhsum -H1 + + /* + XXH3 hashes + */ + xxh3_128 = 0x7b3e6abe1456fd0094e26d8e04364852, // xxhsum -H2 + xxh3_64 = 0x94e26d8e04364852, // xxhsum -H3 + }, + 1024 * 4096 = { + /* + Old hashes + */ + xxh_32 = 0xa59010b8, // xxhsum -H0 + xxh_64 = 0x639f9e1a7cbc9d28, // xxhsum -H1 + + /* + XXH3 hashes + */ + xxh3_128 = 0x34001ae2f947e773165f453a5f35c459, // xxhsum -H2 + xxh3_64 = 0x165f453a5f35c459, // xxhsum -H3 + }, + 1024 * 8192 = { + /* + Old hashes + */ + xxh_32 = 0xfed1d084, // xxhsum -H0 + xxh_64 = 0x86823cbc61f6df0f, // xxhsum -H1 + + /* + XXH3 hashes + */ + xxh3_128 = 0x9d6bf1a4e92df02ce881a25e37e37b19, // xxhsum -H2 + xxh3_64 = 0xe881a25e37e37b19, // xxhsum -H3 + }, + 1024 * 16384 = { + /* + Old hashes + */ + xxh_32 = 0x0ee4ebf9, // xxhsum -H0 + xxh_64 = 0x412f1e415ee2d80b, // xxhsum -H1 + + /* + XXH3 hashes + */ + xxh3_128 = 0x14d914cac1f4c1b1c4979470a1b529a1, // xxhsum -H2 + xxh3_64 = 0xc4979470a1b529a1, // xxhsum -H3 + }, +} + +XXHASH_TEST_VECTOR_SEEDED := map[u64][257]XXHASH_Test_Vectors{ 0 = { { // Length: 000 /* XXH32 with seed */ 0x02cc5d05, From b99940f33a50cf2ed5eaa39ffcdb00950f15ad27 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 2 May 2022 19:20:25 +0200 Subject: [PATCH 0660/1052] [xxhash] For the streaming tests, randomly select the size to use. Randomize size used with `update`. It'll print "Using user-selected seed {18109872483301276539,2000259725719371} for update size randomness." If a streaming test then fails, you can repeat it using: `odin run . -define:RAND_STATE=18109872483301276539 -define:RAND_INC=2000259725719371` --- core/hash/xxhash/streaming.odin | 4 +++- tests/core/hash/test_core_hash.odin | 28 +++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/core/hash/xxhash/streaming.odin b/core/hash/xxhash/streaming.odin index 68a4920a5..6f630b042 100644 --- a/core/hash/xxhash/streaming.odin +++ b/core/hash/xxhash/streaming.odin @@ -211,7 +211,9 @@ XXH3_update :: #force_inline proc( length := len(input) secret := state.custom_secret[:] if len(state.external_secret) == 0 else state.external_secret[:] - assert(len(input) > 0) + if len(input) == 0 { + return + } state.total_length += u64(length) assert(state.buffered_size <= XXH3_INTERNAL_BUFFER_SIZE) diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index 86c05fd44..e69490143 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -6,6 +6,8 @@ import "core:time" import "core:testing" import "core:fmt" import "core:os" +import "core:math/rand" +import "core:intrinsics" TEST_count := 0 TEST_fail := 0 @@ -202,6 +204,8 @@ test_xxhash_large :: proc(t: ^testing.T) { for i, v in ZERO_VECTORS { b := many_zeroes[:i] + fmt.printf("[test_xxhash_large] All at once. Size: %v\n", i) + xxh32 := xxhash.XXH32(b) xxh64 := xxhash.XXH64(b) xxh3_64 := xxhash.XXH3_64(b) @@ -218,12 +222,25 @@ test_xxhash_large :: proc(t: ^testing.T) { expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) } + when #config(RAND_STATE, -1) >= 0 && #config(RAND_INC, -1) >= 0 { + random_seed := rand.Rand{ + state = u64(#config(RAND_STATE, -1)), + inc = u64(#config(RAND_INC, -1)), + } + fmt.printf("Using user-selected seed {{%v,%v}} for update size randomness.\n", random_seed.state, random_seed.inc) + } else { + random_seed := rand.create(u64(intrinsics.read_cycle_counter())) + fmt.printf("Randonly selected seed {{%v,%v}} for update size randomness.\n", random_seed.state, random_seed.inc) + } + // Streamed for i, v in ZERO_VECTORS { b := many_zeroes[:i] - bytes_per_update := []int{1, 42, 13, 7, 16, 5, 23, 74, 1024, 511, 1023, 47} - update_size_idx: int + fmt.printf("[test_xxhash_large] Streamed. Size: %v\n", i) + + // bytes_per_update := []int{1, 42, 13, 7, 16, 5, 23, 74, 1024, 511, 1023, 47} + // update_size_idx: int xxh_32_state, xxh_32_err := xxhash.XXH32_create_state() defer xxhash.XXH32_destroy_state(xxh_32_state) @@ -244,9 +261,10 @@ test_xxhash_large :: proc(t: ^testing.T) { // XXH3_128_update for len(b) > 0 { - update_size := min(len(b), bytes_per_update[update_size_idx % len(bytes_per_update)]) - update_size_idx += 1 - + update_size := min(len(b), rand.int_max(8192, &random_seed)) + if update_size > 4096 { + update_size %= 73 + } xxhash.XXH32_update (xxh_32_state, b[:update_size]) xxhash.XXH64_update (xxh_64_state, b[:update_size]) From 8bac82320fbba53a440bf42b117c702e726db093 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 3 May 2022 11:44:55 +0200 Subject: [PATCH 0661/1052] Fix -opt: parsing. --- src/main.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 818a783e1..86c1544a4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -961,7 +961,26 @@ bool parse_build_flags(Array args) { bad_flags = true; break; } - build_context.optimization_level = cast(i32)big_int_to_i64(&value.value_integer); + // NOTE(Jeroen): We can't rely on `value.value_integer` here, because words will be returned as `0`. + // Meaning that -opt:speed will coerce to opt:0. That's not what the user intended. + // Instead we'll just compare 0..3 directly. + if (param == "0") { + build_context.optimization_level = 0; + } else if (param == "1") { + build_context.optimization_level = 1; + } else if (param == "2") { + build_context.optimization_level = 2; + } else if (param == "3") { + build_context.optimization_level = 3; + } else { + gb_printf_err("Invalid optimization level for -o:, got %.*s\n", LIT(param)); + gb_printf_err("Valid optimization levels:\n"); + gb_printf_err("\t0\n"); + gb_printf_err("\t1\n"); + gb_printf_err("\t2\n"); + gb_printf_err("\t3\n"); + bad_flags = true; + } break; } case BuildFlag_OptimizationMode: { From 59f55a21193ec7461205f4bb95303b69f3f7ce1c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 3 May 2022 13:15:49 +0200 Subject: [PATCH 0662/1052] Make `big_int_from_string` return an error if not an integer. --- src/big_int.cpp | 30 +++++++++++++++++++++++++++--- src/exact_value.cpp | 6 +++++- src/main.cpp | 17 ++++------------- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/big_int.cpp b/src/big_int.cpp index 20f940e8e..8203f0522 100644 --- a/src/big_int.cpp +++ b/src/big_int.cpp @@ -40,7 +40,7 @@ typedef mp_int BigInt; void big_int_from_u64(BigInt *dst, u64 x); void big_int_from_i64(BigInt *dst, i64 x); void big_int_init (BigInt *dst, BigInt const *src); -void big_int_from_string(BigInt *dst, String const &s); +void big_int_from_string(BigInt *dst, String const &s, bool &success); void big_int_dealloc(BigInt *dst) { mp_clear(dst); @@ -84,7 +84,7 @@ void big_int_quo_eq(BigInt *dst, BigInt const *x); void big_int_rem_eq(BigInt *dst, BigInt const *x); bool big_int_is_neg(BigInt const *x); - +void big_int_neg(BigInt *dst, BigInt const *x); void big_int_add_eq(BigInt *dst, BigInt const *x) { BigInt res = {}; @@ -169,7 +169,11 @@ BigInt big_int_make_i64(i64 x) { } -void big_int_from_string(BigInt *dst, String const &s) { +void big_int_from_string(BigInt *dst, String const &s, bool *success) { + *success = true; + + bool is_negative = false; + u64 base = 10; bool has_prefix = false; if (s.len > 2 && s[0] == '0') { @@ -197,11 +201,26 @@ void big_int_from_string(BigInt *dst, String const &s) { isize i = 0; for (; i < len; i++) { Rune r = cast(Rune)text[i]; + + if (r == '-') { + if (is_negative) { + // NOTE(Jeroen): Can't have a doubly negative number. + *success = false; + return; + } + is_negative = true; + continue; + } + if (r == '_') { continue; } u64 v = u64_digit_value(r); if (v >= base) { + // NOTE(Jeroen): Can still be a valid integer if the next character is an `e` or `E`. + if (r != 'e' && r != 'E') { + *success = false; + } break; } BigInt val = big_int_make_u64(v); @@ -225,6 +244,7 @@ void big_int_from_string(BigInt *dst, String const &s) { if (gb_char_is_digit(r)) { v = u64_digit_value(r); } else { + *success = false; break; } exp *= 10; @@ -234,6 +254,10 @@ void big_int_from_string(BigInt *dst, String const &s) { big_int_mul_eq(dst, &b); } } + + if (is_negative) { + big_int_neg(dst, dst); + } } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index cedef48c4..175cb61f6 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -177,7 +177,11 @@ ExactValue exact_value_typeid(Type *type) { ExactValue exact_value_integer_from_string(String const &string) { ExactValue result = {ExactValue_Integer}; - big_int_from_string(&result.value_integer, string); + bool success; + big_int_from_string(&result.value_integer, string, &success); + if (!success) { + result = {ExactValue_Invalid}; + } return result; } diff --git a/src/main.cpp b/src/main.cpp index 86c1544a4..8bd6fc618 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -961,19 +961,10 @@ bool parse_build_flags(Array args) { bad_flags = true; break; } - // NOTE(Jeroen): We can't rely on `value.value_integer` here, because words will be returned as `0`. - // Meaning that -opt:speed will coerce to opt:0. That's not what the user intended. - // Instead we'll just compare 0..3 directly. - if (param == "0") { - build_context.optimization_level = 0; - } else if (param == "1") { - build_context.optimization_level = 1; - } else if (param == "2") { - build_context.optimization_level = 2; - } else if (param == "3") { - build_context.optimization_level = 3; - } else { - gb_printf_err("Invalid optimization level for -o:, got %.*s\n", LIT(param)); + + build_context.optimization_level = cast(i32)big_int_to_i64(&value.value_integer); + if (build_context.optimization_level < 0 || build_context.optimization_level > 3) { + gb_printf_err("Invalid optimization level for -o:, got %d\n", build_context.optimization_level); gb_printf_err("Valid optimization levels:\n"); gb_printf_err("\t0\n"); gb_printf_err("\t1\n"); From 47f637d23bf44b637041383b739780d9959331db Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 3 May 2022 13:37:07 +0200 Subject: [PATCH 0663/1052] Add deprecation warnings for -opt and flag=value insted of flag:value. --- src/main.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8bd6fc618..2633f8e55 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -825,11 +825,19 @@ bool parse_build_flags(Array args) { String name = substring(flag, 1, flag.len); isize end = 0; + bool have_equals = false; for (; end < name.len; end++) { if (name[end] == ':') break; - if (name[end] == '=') break; // IMPORTANT TODO(bill): DEPRECATE THIS!!!! + if (name[end] == '=') { + have_equals = true; + break; + } } name = substring(name, 0, end); + if (have_equals && name != "opt") { + gb_printf_err("`flag=value` has been deprecated and will be removed next release. Use `%.*s:` instead.\n", LIT(name), LIT(name)); + } + String param = {}; if (end < flag.len-1) param = substring(flag, 2+end, flag.len); @@ -903,35 +911,35 @@ bool parse_build_flags(Array args) { switch (bf.param_kind) { case BuildFlagParam_None: if (value.kind != ExactValue_Invalid) { - gb_printf_err("%.*s expected no value, got %.*s", LIT(name), LIT(param)); + gb_printf_err("%.*s expected no value, got %.*s\n", LIT(name), LIT(param)); bad_flags = true; ok = false; } break; case BuildFlagParam_Boolean: if (value.kind != ExactValue_Bool) { - gb_printf_err("%.*s expected a boolean, got %.*s", LIT(name), LIT(param)); + gb_printf_err("%.*s expected a boolean, got %.*s\n", LIT(name), LIT(param)); bad_flags = true; ok = false; } break; case BuildFlagParam_Integer: if (value.kind != ExactValue_Integer) { - gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param)); + gb_printf_err("%.*s expected an integer, got %.*s\n", LIT(name), LIT(param)); bad_flags = true; ok = false; } break; case BuildFlagParam_Float: if (value.kind != ExactValue_Float) { - gb_printf_err("%.*s expected a floating pointer number, got %.*s", LIT(name), LIT(param)); + gb_printf_err("%.*s expected a floating pointer number, got %.*s\n", LIT(name), LIT(param)); bad_flags = true; ok = false; } break; case BuildFlagParam_String: if (value.kind != ExactValue_String) { - gb_printf_err("%.*s expected a string, got %.*s", LIT(name), LIT(param)); + gb_printf_err("%.*s expected a string, got %.*s\n", LIT(name), LIT(param)); bad_flags = true; ok = false; } @@ -972,6 +980,9 @@ bool parse_build_flags(Array args) { gb_printf_err("\t3\n"); bad_flags = true; } + + // Deprecation warning. + gb_printf_err("`-opt` has been deprecated and will be removed next release. Use `-o:minimal`, etc.\n"); break; } case BuildFlag_OptimizationMode: { From d9b0c05acf72206d00068e708c1e2ebd872b2586 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 3 May 2022 13:47:13 +0200 Subject: [PATCH 0664/1052] Typo. --- src/big_int.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/big_int.cpp b/src/big_int.cpp index 8203f0522..5509545ca 100644 --- a/src/big_int.cpp +++ b/src/big_int.cpp @@ -40,7 +40,7 @@ typedef mp_int BigInt; void big_int_from_u64(BigInt *dst, u64 x); void big_int_from_i64(BigInt *dst, i64 x); void big_int_init (BigInt *dst, BigInt const *src); -void big_int_from_string(BigInt *dst, String const &s, bool &success); +void big_int_from_string(BigInt *dst, String const &s, bool *success); void big_int_dealloc(BigInt *dst) { mp_clear(dst); From 6e7a50c02f10a2a031687138f74172c95f3280c2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 May 2022 14:11:26 +0100 Subject: [PATCH 0665/1052] Add .lib for `vendor:openexr` --- vendor/openexr/OpenEXRCore-3_1.lib | Bin 0 -> 1064780 bytes vendor/openexr/exr_base.odin | 2 +- vendor/openexr/exr_chunkio.odin | 2 +- vendor/openexr/exr_context.odin | 2 +- vendor/openexr/exr_debug.odin | 2 +- vendor/openexr/exr_decode.odin | 2 +- vendor/openexr/exr_encode.odin | 2 +- vendor/openexr/exr_errors.odin | 8 ++++---- vendor/openexr/exr_part.odin | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 vendor/openexr/OpenEXRCore-3_1.lib diff --git a/vendor/openexr/OpenEXRCore-3_1.lib b/vendor/openexr/OpenEXRCore-3_1.lib new file mode 100644 index 0000000000000000000000000000000000000000..f70938101ea9c0adaf29e80352fe296ccc15bdbe GIT binary patch literal 1064780 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
      V&OOqD|9@Ji9XqJ;e{Lpis1pzr%0?rvESB_H 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

      {qi%|T0)xLLl)&<)N`|(R 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%0A^;Z@c=eQ-AJd-<3lHEw_h?49N`x-|S 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 WyX6c{H#N%GDH0kGLgTxz1VA z$eO?rWpgQU90zZSoYe^AEV&q3p$J(s7kn@_+8gEK$wA$A3C1aNH0Kl2N*Z4>i5S^g z6bA??kdOkW9Auak8o?t zq~0mT6y&egNgq4RsYO~PJl>S?I+j`saaxO@(WDyrTU70LYJsDeEOK408tK}Vd{0(c zai`QXp_rol)rt^fPj~7mcIyFh#)~+uM^J21jr=XDE_Uj9Rq6qQbM>4q^$12Ix5j855L!8!AruE3*qUtiIp7l~sYgawPr5?T~i{zQBhobz|7im2gIrUVy z^#D2b5U2H2Xg%_`sJgj84=Ax`TV zq4mh$qUsS&JwK3omPsfM)lrVBGpAws@*8UAr3oJ zwCYLhao93*98GqEctR~nhH>ymxilMO&KZ=`-uo< zH*}ACme)JW{0u5AK)-P6`s~4%+3kk~?M)_=y)`Tr29BlQ)B;Kim8acIPAft%mG-k_ z(v94%9Tq~XMbcclaQQkdj>=8aT)LF++HT20<*mIX3;P~J(~Ggwd)p6%QuDJ2gx~n7 zG}(SGD9oOxZCyT_L?{`CzYdqBBKgVMlI`n)T;2%VFC{0A2=070Xz$+sZu5>iCWq`V zl96UiEW|5qaA*6$-6YJj-wEzK5RP81rI*&Jg*gbKzXfXxI|629L2JDGp-P;GmxfCI|Jjy8I$%X;=R2jnD}c!c60OY zJAW6mzY?*fT~iBV^owT&FrcEL(n_m&y3;KhS8H!!sttZ1+?cZLus>$sUWfB@%9#Ym zWQRxbG0tB0hA`c+>HBL_z9n3!d$hJ{y|w75vbMgIpr9D5!9)eDMY9O4MQMhOmD7Hn zIT&jD?h7V^h3H6a-(5gl9-%a_pn-WFM>Z=Oel&_nV``nbTyD8Dit-flIoAOnY za*vzxRX61xNm=Noe9@%b<)(bmO}R@_4iU=Yrhdkx-bQM8oq&D?o^f+*6XvV7Ds3gc zuN>C;`q|OcyaKL3)}|)QKn~>+AJ=2<+^-{F!{C{b_nPXHV}_Zsl4JZ*`O#d(W6f~Z zIK!D7Iw-gp@7K| zbVRdon17unYBD_4Bql|5QSSghDJjv_O%h$*ltXY_Y%Q<`M+h&XRBC~DDw;1P8g?Gt zXRaFI?)_|he`cS!&@^sJ5N7WsA>>jXifL0jxhFmCG(np5kDHM%tq{S*FD=nF@YTu9 z!0JN?EY_k|m`Yh}59n}?+ru!XYL3LF@46yYxGE}=iyRiPHUqWg&qVF?#PZwn+dvGz`NvrB>GTWIbv8L?dmjS2;?hm|rakyqK(rFj<7Bu99FAOTUvV>Bg1xsOXd0DCrwYYl?c+6m>Qwp?#9RohOCS zYItWU%xvIJ(|<|#ic851s2%3cz+#cD@jx*xQn|%Y zXWIz*FWH8#$ zGYYT*QQgC6pw$Z9;6mR7TBBj|IE8`sxX=JJqbBTr7rF`ap~p1GuYev`XaHos%ZXPv zZJ6#wT(C%N$wsCp_hBSrPRgSk#aC@<7!$U?xd(&}R&BcdW3{P;uL8%sZCqf%tHria z+4?~|xQrLUs!aXkKmE{ z@zWY_^?Bka@%VQ`c`)(VAz2j-=N_o;m)CGM-w*KVc}x@msuBt&7m7|O^HojovbAbt zELD9Pvf>CXM$El}>$|9^&gJSBi^v?S(9{C1ST!Eb)?3oj?7Fe3LT{vM>w-Uqs-6p3 zq2Ec)VRFMD@eXF>Q&?U`A$3BqLn~vV93@nND53mv(vFc2dw5#x1b@gs>;x09v(o&q zu>LDi)e6FX;Z@d%kRp}1wpr(0RLaNKAeJ1FOp20Z%GXf5qJ>8i!l9K}!YZ3^9r0x`==}Fp}x;~F+OrFNQJR@ZNdpb;d$Z_kj z87PXu`qM@(*lnoqhsj&!tRRJvx2tMGDRKiiHEx%%%&IJGD4irndvZuYZ|H8|`t*6U zWVbGd8ldMDiU7T!&BB|UA04dcZN$hl7a2z9O?q9p+pjlOUVq31+ zrSfYd*>gze8O*;6RnIMF92Y1grl`Y2Gt8AJ6nV4-6S<+0>>jhU8%Kg(+ZzJh&P*IS zYi~5pG(}xup|34agaO znurPWE$#(_=cD#M@dqLo4R^ryaX<8&5mbz=!5mFmY&rLr)X^2jy-R+cZvNa z&DA%*_R#ZQj^3m*9L(+QJvQ-p1xkXz>>Fr<;=652K*YN-*|hm0ARbxZFE2FbN4%}c zCFv0oHpbUI*(ic4HztnetpV^@A>MV+G7_z&lBY18HQ%~+#FWkqrz{L}SwxJ%uEN;Z z=eYpLoGc2FH?fxk-KeqS+}LSAPw6D*7T@GUf@7!4H4oN^Sx*oNPO4BO=|bGo6N$Pn zPlffU)8J5$;tiJMihrRSMZr{D%$p;r`2!-}cjattc+?K)0K5ln1}z zr=~J)np_HB7fIY&Y<>znac;5SigSqn)IbP9;?}OflPrHerBHzXa>{WE>AIaLgmIeA zmu%x-P)JUZZ%`=L7U%Y(Q1e{txF+s`tdKUnHEBwcGEGS(Zb>m-;VOFpLexo+2L{^n z{UHv6Hv+~hR5}d?3e{aG87nObi~kZX<7_vCKCym8TB!4nG)EZy5)YH)iV^~Dis~ie zyM5(&u&;>k^%e0QjX1s=ri$akO%2C~n+lE(H|66K1Zye70~j=@#8R)Rw2@xsyn*b9 z57PPTya^T>20NC_m&KKVO~!z`7=D(CmRD;1!4k3D4u}yqiy~GUk?=Y-=bmPUcDh$x z8iYW$nJ71J5vH8qSwb)PZSb1kc_KdWy+D5LP}59nMU9WUToBfNYY9S9pEEF+3LNSD z9bYlA8j*Xb!qvzsJRxFF;9|JFA;?lYEoR3`C+Xer?>dQz+E%$yZ+=58xHq;)%CyI` z3m6liNb2F=XwVi}hbP%JX!F?EY6@t#QPXA61&<{Z`aj;-W6N&ECK6ycBIKnMMT^#2WH#75c6cx!lLLlL*ATcr4rUvK2cTE

$sr;R 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 diff --git a/tests/core/os2/test_os2.odin b/tests/core/os2/test_os2.odin index f8ef133a5..a629063bd 100644 --- a/tests/core/os2/test_os2.odin +++ b/tests/core/os2/test_os2.odin @@ -1,5 +1,6 @@ package test_os2 +import "core:os" import "core:fmt" import "core:os/os2" import "core:testing" @@ -22,7 +23,7 @@ when ODIN_TEST { TEST_count += 1 ok := value == expected if !ok { - fmt.printf("expected %v, got %v", expected, value) + fmt.printf("expected %v, got %v\n", expected, value) TEST_fail += 1 return } @@ -45,12 +46,13 @@ when ODIN_TEST { } } -main :: proc() +main :: proc() { t: testing.T file_test(&t) path_test(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + os.exit(TEST_fail > 0 ? 1 : 0) } @private @@ -59,7 +61,7 @@ _expect_no_error :: proc(t: ^testing.T, e: os2.Error, loc := #caller_location) { } -F_OK :: 0 // Test for file existance +F_OK :: 0 // Test for file existence X_OK :: 1 // Test for execute permission W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission @@ -84,44 +86,92 @@ file_test :: proc(t: ^testing.T) { expect(t, err != nil, "missing error") expect_value(t, fd, os2.INVALID_HANDLE) - fd, err = os2.open("write.txt", {.Write, .Create, .Trunc}, 0o664) + // NOTE: no executable permissions here + fd, err = os2.open("file.txt", {.Write, .Create, .Trunc}, 0o664) _expect_no_error(t, err) expect(t, fd != os2.INVALID_HANDLE, "unexpected handle") - s1 := "hello" - b1 := transmute([]u8)s1 - + s := "hello" n: int - n, err = os2.write_at(fd, b1, 10) + n, err = os2.write_at(fd, transmute([]u8)s, 10) _expect_no_error(t, err) expect_value(t, n, 5) - s2 := "abcdefghij" - b2 := transmute([]u8)s2 - - n, err = os2.write(fd, b2) + s = "abcdefghij" + n, err = os2.write(fd, transmute([]u8)s) _expect_no_error(t, err) expect_value(t, n, 10) + // seek to the "ll" in "hello" + n64: i64 + n64, err = os2.seek(fd, 12, .Start) + _expect_no_error(t, err) + expect_value(t, n64, 12) + + s = "11" + n, err = os2.write(fd, transmute([]u8)s) + _expect_no_error(t, err) + expect_value(t, n, 2) + + // seek to the "e" in "he11o" + n64, err = os2.seek(fd, -3, .Current) + _expect_no_error(t, err) + expect_value(t, n64, 11) + + s = "3" + n, err = os2.write(fd, transmute([]u8)s) + _expect_no_error(t, err) + expect_value(t, n, 1) + + // seek to the "o" in "h311o" + n64, err = os2.seek(fd, -1, .End) + _expect_no_error(t, err) + expect_value(t, n64, 14) + + s = "0" + n, err = os2.write(fd, transmute([]u8)s) + _expect_no_error(t, err) + expect_value(t, n, 1) + _expect_no_error(t, os2.sync(fd)) + + // Add executable permissions to current file (as well as read/write to all) + err = os2.chmod(fd, 0o766) + _expect_no_error(t, err) + + when ODIN_OS == .Linux { + expect(t, unix.sys_access("file.txt", X_OK) == 0, "expected exec permission") + } + + // NOTE: chown not possible without root user + //_expect_no_error(t, os2.chown(fd, 0, 0)) _expect_no_error(t, os2.close(fd)) - fd, err = os2.open("write.txt") + + fd, err = os2.open("file.txt") _expect_no_error(t, err) buf: [32]u8 - + n, err = os2.read(fd, buf[:]) _expect_no_error(t, err) expect_value(t, n, 15) - expect_value(t, string(buf[:n]), "abcdefghijhello") + expect_value(t, string(buf[:n]), "abcdefghijh3110") n, err = os2.read_at(fd, buf[0:2], 1) _expect_no_error(t, err) expect_value(t, n, 2) expect_value(t, string(buf[0:2]), "bc") + n64, err = os2.file_size(fd) + _expect_no_error(t, err) + expect_value(t, n64, 15) + _expect_no_error(t, os2.close(fd)) + + _expect_no_error(t, os2.remove("file.txt")) + _expect_no_error(t, os2.mkdir("empty dir", 0)) + _expect_no_error(t, os2.remove("empty dir")) } @test @@ -131,7 +181,7 @@ path_test :: proc(t: ^testing.T) { err = os2.remove_all("a") _expect_no_error(t, err) } - + err = os2.mkdir_all("a/b/c/d", 0) _expect_no_error(t, err) @@ -141,23 +191,25 @@ path_test :: proc(t: ^testing.T) { fd, err = os2.create("a/b/c/file.txt", 0o644) _expect_no_error(t, err) - err = os2.close(fd) - _expect_no_error(t, err) when ODIN_OS == .Linux { expect(t, unix.sys_access("a/b/c/file.txt", X_OK) < 0, "unexpected exec permission") + } else { + expect(t, os2.exists("a/b/c/file.txt"), "file does not exist") } err = os2.rename("a/b/c/file.txt", "a/b/file.txt") _expect_no_error(t, err) when ODIN_OS == .Linux { - expect(t, unix.sys_access("a/b/c/file.txt", F_OK) < 0, "unexpected exec permission") + expect(t, unix.sys_access("a/b/c/file.txt", F_OK) < 0, "unexpected file existence") + } else { + expect(t, !os2.exists("a/b/c/file.txt"), "unexpected file existence") } err = os2.symlink("b/c/d", "a/symlink_to_d") _expect_no_error(t, err) - + symlink: string symlink, err = os2.read_link("a/symlink_to_d") _expect_no_error(t, err) @@ -171,8 +223,10 @@ path_test :: proc(t: ^testing.T) { when ODIN_OS == .Linux { expect_value(t, unix.sys_access("a/b/c/d/shnt.txt", X_OK | R_OK | W_OK), 0) + } else { + expect(t, os2.exists("a/b/c/d/shnt.txt"), "file does not exist") } - + err = os2.remove_all("a") _expect_no_error(t, err) From b21e7e4518a82713910d959841a4a0eef88fc4a2 Mon Sep 17 00:00:00 2001 From: CiD- Date: Mon, 14 Mar 2022 15:44:34 -0400 Subject: [PATCH 0401/1052] rewrite mkdir_all --- core/os/os2/path_linux.odin | 63 +++++++++++++++++++++++++++++-- core/sys/unix/syscalls_linux.odin | 48 +++++++++++++++-------- tests/core/Makefile | 16 +++----- tests/core/os2/test_os2.odin | 9 +++-- 4 files changed, 101 insertions(+), 35 deletions(-) diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index b474ae207..e47bd36b0 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -24,18 +24,73 @@ _is_path_separator :: proc(c: byte) -> bool { } _mkdir :: proc(path: string, perm: File_Mode) -> Error { - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - perm_i: int if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { return .Invalid_Argument } + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777))) } -// TODO _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { - return nil + _mkdirat :: proc(dfd: Handle, path: []u8, perm: int, has_created: ^bool) -> Error { + if len(path) == 0 { + return nil + } + i: int + for /**/; i < len(path) - 1 && path[i] != '/'; i += 1 {} + path[i] = 0 + new_dfd := unix.sys_openat(int(dfd), cstring(&path[0]), _OPENDIR_FLAGS) + switch new_dfd { + case -ENOENT: + res := unix.sys_mkdirat(int(dfd), cstring(&path[0]), perm) + if res < 0 { + return _get_platform_error(res) + } + has_created^ = true + new_dfd = unix.sys_openat(int(dfd), cstring(&path[0]), _OPENDIR_FLAGS) + if new_dfd < 0 { + return _get_platform_error(new_dfd) + } + fallthrough + case 0: + unix.sys_close(int(dfd)) + // skip consecutive '/' + for i += 1; i < len(path) && path[i] == '/'; i += 1 {} + return _mkdirat(Handle(new_dfd), path[i:], perm, has_created) + case: + return _get_platform_error(new_dfd) + } + unreachable() + } + + if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { + return .Invalid_Argument + } + + // need something we can edit, and use to generate cstrings + path_bytes := make([]u8, len(path) + 1, context.temp_allocator) + copy(path_bytes, path) + path_bytes[len(path)] = 0 + + dfd: int + if path_bytes[0] == '/' { + dfd = unix.sys_open("/", _OPENDIR_FLAGS) + path_bytes = path_bytes[1:] + } else { + dfd = unix.sys_open(".", _OPENDIR_FLAGS) + } + if dfd < 0 { + return _get_platform_error(dfd) + } + + has_created: bool + _mkdirat(Handle(dfd), path_bytes, int(perm & 0o777), &has_created) or_return + if has_created { + return nil + } + return .Exist + //return has_created ? nil : .Exist } dirent64 :: struct { diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 8cfb97076..8a1aadb9c 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1518,7 +1518,7 @@ when ODIN_ARCH == .amd64 { #panic("Unsupported architecture") } -AT_FDCWD :: -100 +AT_FDCWD :: ~uintptr(99) AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_FOLLOW :: uintptr(0x400) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) @@ -1535,7 +1535,7 @@ sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open - return int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) + return int(intrinsics.syscall(SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } } @@ -1593,7 +1593,7 @@ sys_stat :: proc(path: cstring, stat: rawptr) -> int { } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have stat - return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0)) + return int(intrinsics.syscall(SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0)) } } @@ -1611,7 +1611,7 @@ sys_lstat :: proc(path: cstring, stat: rawptr) -> int { } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have any lstat - return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) + return int(intrinsics.syscall(SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) } } @@ -1619,7 +1619,7 @@ sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } else { // NOTE: arm64 does not have readlink - return int(intrinsics.syscall(SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) + return int(intrinsics.syscall(SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } } @@ -1627,7 +1627,7 @@ sys_symlink :: proc(old_name: cstring, new_name: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_symlink, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have symlink - return int(intrinsics.syscall(SYS_symlinkat, uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)))) + return int(intrinsics.syscall(SYS_symlinkat, uintptr(rawptr(old_name)), AT_FDCWD, uintptr(rawptr(new_name)))) } } @@ -1635,7 +1635,7 @@ sys_access :: proc(path: cstring, mask: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_access, uintptr(rawptr(path)), uintptr(mask))) } else { // NOTE: arm64 does not have access - return int(intrinsics.syscall(SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask))) + return int(intrinsics.syscall(SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask))) } } @@ -1655,7 +1655,7 @@ sys_chmod :: proc(path: cstring, mode: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have chmod - return int(intrinsics.syscall(SYS_fchmodat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + return int(intrinsics.syscall(SYS_fchmodat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) } } @@ -1667,7 +1667,7 @@ sys_chown :: proc(path: cstring, user: int, group: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have chown - return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), 0)) + return int(intrinsics.syscall(SYS_fchownat, AT_FDCWD, uintptr(rawptr(path)), uintptr(user), uintptr(group), 0)) } } @@ -1679,7 +1679,7 @@ sys_lchown :: proc(path: cstring, user: int, group: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_lchown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have lchown - return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), AT_SYMLINK_NOFOLLOW)) + return int(intrinsics.syscall(SYS_fchownat, AT_FDCWD, uintptr(rawptr(path)), uintptr(user), uintptr(group), AT_SYMLINK_NOFOLLOW)) } } @@ -1687,7 +1687,7 @@ sys_rename :: proc(old, new: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) } else { // NOTE: arm64 does not have rename - return int(intrinsics.syscall(SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new)))) + return int(intrinsics.syscall(SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new)))) } } @@ -1695,7 +1695,7 @@ sys_link :: proc(old_name: cstring, new_name: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_link, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have link - return int(intrinsics.syscall(SYS_linkat, uintptr(AT_FDCWD), uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)), AT_SYMLINK_FOLLOW)) + return int(intrinsics.syscall(SYS_linkat, AT_FDCWD, uintptr(rawptr(old_name)), AT_FDCWD, uintptr(rawptr(new_name)), AT_SYMLINK_FOLLOW)) } } @@ -1703,7 +1703,7 @@ sys_unlink :: proc(path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_unlink, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have unlink - return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0))) + return int(intrinsics.syscall(SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0)) } } @@ -1715,7 +1715,7 @@ sys_rmdir :: proc(path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have rmdir - return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR)) + return int(intrinsics.syscall(SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR)) } } @@ -1723,18 +1723,26 @@ sys_mkdir :: proc(path: cstring, mode: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir - return int(intrinsics.syscall(SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + return int(intrinsics.syscall(SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) } } +sys_mkdirat :: proc(dfd: int, path: cstring, mode: int) -> int { + return int(intrinsics.syscall(SYS_mkdirat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode))) +} + sys_mknod :: proc(path: cstring, mode: int, dev: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mknod, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } else { // NOTE: arm64 does not have mknod - return int(intrinsics.syscall(SYS_mknodat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) + return int(intrinsics.syscall(SYS_mknodat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } } +sys_mknodat :: proc(dfd: int, path: cstring, mode: int, dev: int) -> int { + return int(intrinsics.syscall(SYS_mknodat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) +} + sys_truncate :: proc(path: cstring, length: i64) -> int { when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_truncate, uintptr(rawptr(path)), uintptr(length))) @@ -1763,6 +1771,14 @@ sys_getdents64 :: proc(fd: int, dirent: rawptr, count: int) -> int { return int(intrinsics.syscall(SYS_getdents64, uintptr(fd), uintptr(dirent), uintptr(count))) } +sys_fork :: proc() -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_fork)) + } else { + return int(intrinsics.syscall(SYS_clone, SIGCHLD)) + } +} + get_errno :: proc(res: int) -> i32 { if res < 0 && res > -4096 { return i32(-res) diff --git a/tests/core/Makefile b/tests/core/Makefile index 449efbb25..90b0df449 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,12 +1,8 @@ ODIN=../../odin PYTHON=$(shell which python3) -<<<<<<< HEAD -all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test os2_test -======= all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test ->>>>>>> upstream/master + math_test linalg_glsl_math_test os2_test download_test_assets: $(PYTHON) download_assets.py @@ -29,18 +25,16 @@ crypto_test: noise_test: $(ODIN) run math/noise -out=test_noise -os2_test: - $(ODIN) run os2/test_os2.odin -out=test_os2 - encoding_test: $(ODIN) run encoding/json -out=test_json $(ODIN) run encoding/varint -out=test_varint -<<<<<<< HEAD -======= math_test: $(ODIN) run math/test_core_math.odin -out=test_core_math -collection:tests=.. linalg_glsl_math_test: $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -out=test_linalg_glsl_math -collection:tests=.. ->>>>>>> upstream/master + +os2_test: + $(ODIN) run os2/test_os2.odin -out=test_os2 + diff --git a/tests/core/os2/test_os2.odin b/tests/core/os2/test_os2.odin index a629063bd..0e0d3dcb5 100644 --- a/tests/core/os2/test_os2.odin +++ b/tests/core/os2/test_os2.odin @@ -15,8 +15,9 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect_value :: testing.expect_value + expect :: testing.expect + log :: testing.log } else { expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) where intrinsics.type_is_comparable(T) { fmt.printf("[%v] ", loc) @@ -170,7 +171,7 @@ file_test :: proc(t: ^testing.T) { _expect_no_error(t, os2.close(fd)) _expect_no_error(t, os2.remove("file.txt")) - _expect_no_error(t, os2.mkdir("empty dir", 0)) + _expect_no_error(t, os2.mkdir("empty dir", 0o755)) _expect_no_error(t, os2.remove("empty dir")) } @@ -182,7 +183,7 @@ path_test :: proc(t: ^testing.T) { _expect_no_error(t, err) } - err = os2.mkdir_all("a/b/c/d", 0) + err = os2.mkdir_all("a/b/c/d", 0o755) _expect_no_error(t, err) expect(t, os2.exists("a"), "directory does not exist") From 4b1822ade8eda7cda798dc0d0b22e1f1d7040a8f Mon Sep 17 00:00:00 2001 From: CiD- Date: Mon, 14 Mar 2022 15:48:47 -0400 Subject: [PATCH 0402/1052] mkdir_all: close last open file --- core/os/os2/path_linux.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index e47bd36b0..fa47f1883 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -35,7 +35,7 @@ _mkdir :: proc(path: string, perm: File_Mode) -> Error { _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { _mkdirat :: proc(dfd: Handle, path: []u8, perm: int, has_created: ^bool) -> Error { if len(path) == 0 { - return nil + return _ok_or_error(unix.sys_close(int(dfd))) } i: int for /**/; i < len(path) - 1 && path[i] != '/'; i += 1 {} @@ -43,18 +43,18 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { new_dfd := unix.sys_openat(int(dfd), cstring(&path[0]), _OPENDIR_FLAGS) switch new_dfd { case -ENOENT: - res := unix.sys_mkdirat(int(dfd), cstring(&path[0]), perm) - if res < 0 { + if res := unix.sys_mkdirat(int(dfd), cstring(&path[0]), perm); res < 0 { return _get_platform_error(res) } has_created^ = true - new_dfd = unix.sys_openat(int(dfd), cstring(&path[0]), _OPENDIR_FLAGS) - if new_dfd < 0 { + if new_dfd = unix.sys_openat(int(dfd), cstring(&path[0]), _OPENDIR_FLAGS); new_dfd < 0 { return _get_platform_error(new_dfd) } fallthrough case 0: - unix.sys_close(int(dfd)) + if res := unix.sys_close(int(dfd)) < 0; res < 0 { + return _get_platform_error(res) + } // skip consecutive '/' for i += 1; i < len(path) && path[i] == '/'; i += 1 {} return _mkdirat(Handle(new_dfd), path[i:], perm, has_created) From 6d6e840bc26a92bee1eb257d081bbc3695d741a4 Mon Sep 17 00:00:00 2001 From: CiD- Date: Mon, 14 Mar 2022 15:56:41 -0400 Subject: [PATCH 0403/1052] mkdir_all: WHOOPS --- core/os/os2/path_linux.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index fa47f1883..85c39916f 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -52,7 +52,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { } fallthrough case 0: - if res := unix.sys_close(int(dfd)) < 0; res < 0 { + if res := unix.sys_close(int(dfd)); res < 0 { return _get_platform_error(res) } // skip consecutive '/' From 36c22393a4e3026bc84a5ee8d2230d1f6f78b83c Mon Sep 17 00:00:00 2001 From: CiD- Date: Tue, 15 Mar 2022 11:47:35 -0400 Subject: [PATCH 0404/1052] fix memory leak --- core/os/os2/path_linux.odin | 3 ++- tests/core/os2/test_os2.odin | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 85c39916f..889f7e447 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -112,7 +112,8 @@ _remove_all :: proc(path: string) -> Error { loop: for { res := unix.sys_getdents64(int(dfd), &buf[0], n) switch res { - case -22: //-EINVAL + case -EINVAL: + delete(buf) n *= 2 buf = make([]u8, n) continue loop diff --git a/tests/core/os2/test_os2.odin b/tests/core/os2/test_os2.odin index 0e0d3dcb5..e52351f03 100644 --- a/tests/core/os2/test_os2.odin +++ b/tests/core/os2/test_os2.odin @@ -2,6 +2,7 @@ package test_os2 import "core:os" import "core:fmt" +import "core:mem" import "core:os/os2" import "core:testing" import "core:intrinsics" @@ -49,10 +50,22 @@ when ODIN_TEST { main :: proc() { + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + t: testing.T file_test(&t) path_test(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + + for _, leak in track.allocation_map { + fmt.printf("%v leaked %v bytes\n", leak.location, leak.size) + } + for bad_free in track.bad_free_array { + fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory) + } + os.exit(TEST_fail > 0 ? 1 : 0) } @@ -215,6 +228,7 @@ path_test :: proc(t: ^testing.T) { symlink, err = os2.read_link("a/symlink_to_d") _expect_no_error(t, err) expect_value(t, symlink, "b/c/d") + delete(symlink) fd, err = os2.create("a/symlink_to_d/shnt.txt", 0o744) _expect_no_error(t, err) From a932168f505201d528dcd2d43355c3708e68e26a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 15 Mar 2022 19:35:00 +0100 Subject: [PATCH 0405/1052] [runtime] fix `insert_at` procedure group. --- core/runtime/core_builtin.odin | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 3bafc0b1d..dd4960147 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -386,12 +386,13 @@ insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle if array == nil { return } - n := len(array) + n := max(len(array), index) m :: 1 - resize(array, n+m, loc) - if n+m <= len(array) { + new_size := n + m + + if resize(array, new_size, loc) { when size_of(E) != 0 { - copy(array[index+m:], array[index:]) + copy(array[index + m:], array[index:]) array[index] = arg } ok = true @@ -409,12 +410,13 @@ insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c return } - n := len(array) + n := max(len(array), index) m := len(args) - resize(array, n+m, loc) - if n+m <= len(array) { + new_size := n + m + + if resize(array, new_size, loc) { when size_of(E) != 0 { - copy(array[index+m:], array[index:]) + copy(array[index + m:], array[index:]) copy(array[index:], args) } ok = true @@ -423,21 +425,22 @@ insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c } @builtin -insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check { +insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) { if array == nil { return } - if len(args) == 0 { + if len(arg) == 0 { ok = true return } - n := len(array) - m := len(args) - resize(array, n+m, loc) - if n+m <= len(array) { + n := max(len(array), index) + m := len(arg) + new_size := n + m + + if resize(array, new_size, loc) { copy(array[index+m:], array[index:]) - copy(array[index:], args) + copy(array[index:], arg) ok = true } return From 19dc84e300386b3f3262c78371c085a005045566 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 15 Mar 2022 19:37:04 +0100 Subject: [PATCH 0406/1052] Reinstate NBC. --- core/runtime/core_builtin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index dd4960147..67b1bd37b 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -425,7 +425,7 @@ insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c } @builtin -insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) { +insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check { if array == nil { return } From d9ca4eb4d655f31f3bf672a56c4390190d85d841 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 16 Mar 2022 11:59:28 +0000 Subject: [PATCH 0407/1052] Add nil check on ast.walk --- core/odin/ast/walk.odin | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index 7241d283f..b4eaf8140 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -52,8 +52,11 @@ walk :: proc(v: ^Visitor, node: ^Node) { } } - v := v + if v == nil || node == nil { + return + } + if v = v->visit(node); v == nil { return } From 4f5203e661928cb5b69d07a27646f9b4a57b4a0a Mon Sep 17 00:00:00 2001 From: gitlost Date: Wed, 16 Mar 2022 19:12:00 +0000 Subject: [PATCH 0408/1052] Fix some core:encoding/hxa stuff (error handling, header, max -> min) Also add missing f16 case to core:reflect as_u64 & as_f64 Add tests for above & add previous tests missing from test/core/build.bat --- core/encoding/hxa/read.odin | 29 ++- core/encoding/hxa/write.odin | 6 +- core/reflect/reflect.odin | 2 + tests/common/common.odin | 35 +++ tests/core/Makefile | 6 +- tests/core/assets/HXA/teapot.hxa | Bin 0 -> 21867 bytes tests/core/build.bat | 20 +- tests/core/encoding/hxa/test_core_hxa.odin | 232 +++++++++++++++++ tests/core/reflect/test_core_reflect.odin | 288 +++++++++++++++++++++ 9 files changed, 608 insertions(+), 10 deletions(-) create mode 100644 tests/core/assets/HXA/teapot.hxa create mode 100644 tests/core/encoding/hxa/test_core_hxa.odin create mode 100644 tests/core/reflect/test_core_reflect.odin diff --git a/core/encoding/hxa/read.odin b/core/encoding/hxa/read.odin index ef7edc8b7..abe295530 100644 --- a/core/encoding/hxa/read.odin +++ b/core/encoding/hxa/read.odin @@ -39,6 +39,9 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato read_value :: proc(r: ^Reader, $T: typeid) -> (value: T, err: Read_Error) { remaining := len(r.data) - r.offset if remaining < size_of(T) { + if r.print_error { + fmt.eprintf("file '%s' failed to read value at offset %v\n", r.filename, r.offset) + } err = .Short_Read return } @@ -51,6 +54,10 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato read_array :: proc(r: ^Reader, $T: typeid, count: int) -> (value: []T, err: Read_Error) { remaining := len(r.data) - r.offset if remaining < size_of(T)*count { + if r.print_error { + fmt.eprintf("file '%s' failed to read array of %d elements at offset %v\n", + r.filename, count, r.offset) + } err = .Short_Read return } @@ -82,7 +89,8 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato type := read_value(r, Meta_Value_Type) or_return if type > max(Meta_Value_Type) { if r.print_error { - fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type))) + fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is %d\n", + r.filename, u8(type), u8(max(Meta_Value_Type))) } err = .Invalid_Data return @@ -114,7 +122,8 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato type := read_value(r, Layer_Data_Type) or_return if type > max(type) { if r.print_error { - fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type))) + fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is %d\n", + r.filename, u8(type), u8(max(Layer_Data_Type))) } err = .Invalid_Data return @@ -134,13 +143,23 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato } if len(data) < size_of(Header) { + if print_error { + fmt.eprintf("HxA Error: file '%s' has no header\n", filename) + } + err = .Short_Read return } context.allocator = allocator header := cast(^Header)raw_data(data) - assert(header.magic_number == MAGIC_NUMBER) + if (header.magic_number != MAGIC_NUMBER) { + if print_error { + fmt.eprintf("HxA Error: file '%s' has invalid magic number 0x%x\n", filename, header.magic_number) + } + err = .Invalid_Data + return + } r := &Reader{ filename = filename, @@ -150,6 +169,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato } node_count := 0 + file.header = header^ file.nodes = make([]Node, header.internal_node_count) defer if err != nil { nodes_destroy(file.nodes) @@ -162,7 +182,8 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato type := read_value(r, Node_Type) or_return if type > max(Node_Type) { if r.print_error { - fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type))) + fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is %d\n", + r.filename, u8(type), u8(max(Node_Type))) } err = .Invalid_Data return diff --git a/core/encoding/hxa/write.odin b/core/encoding/hxa/write.odin index e774018b2..5bb950e81 100644 --- a/core/encoding/hxa/write.odin +++ b/core/encoding/hxa/write.odin @@ -84,7 +84,7 @@ write_internal :: proc(w: ^Writer, file: File) { write_metadata :: proc(w: ^Writer, meta_data: []Meta) { for m in meta_data { - name_len := max(len(m.name), 255) + name_len := min(len(m.name), 255) write_value(w, u8(name_len)) write_string(w, m.name[:name_len]) @@ -127,7 +127,7 @@ write_internal :: proc(w: ^Writer, file: File) { write_layer_stack :: proc(w: ^Writer, layers: Layer_Stack) { write_value(w, u32(len(layers))) for layer in layers { - name_len := max(len(layer.name), 255) + name_len := min(len(layer.name), 255) write_value(w, u8(name_len)) write_string(w, layer .name[:name_len]) @@ -152,7 +152,7 @@ write_internal :: proc(w: ^Writer, file: File) { return } - write_value(w, &Header{ + write_value(w, Header{ magic_number = MAGIC_NUMBER, version = LATEST_VERSION, internal_node_count = u32le(len(file.nodes)), diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index d05026532..49d7ef9b5 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -1054,6 +1054,7 @@ as_u64 :: proc(a: any) -> (value: u64, valid: bool) { case Type_Info_Float: valid = true switch v in a { + case f16: value = u64(v) case f32: value = u64(v) case f64: value = u64(v) case f32le: value = u64(v) @@ -1159,6 +1160,7 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) { case Type_Info_Float: valid = true switch v in a { + case f16: value = f64(v) case f32: value = f64(v) case f64: value = (v) case f32le: value = f64(v) diff --git a/tests/common/common.odin b/tests/common/common.odin index 9a715d38e..07b6afef9 100644 --- a/tests/common/common.odin +++ b/tests/common/common.odin @@ -4,6 +4,7 @@ package common import "core:testing" import "core:fmt" import "core:os" +import "core:strings" TEST_count := 0 TEST_fail := 0 @@ -38,3 +39,37 @@ report :: proc(t: ^testing.T) { fmt.printf("%v/%v tests successful.\n", TEST_count, TEST_count) } } + +// Returns absolute path to `sub_path` where `sub_path` is within the "tests/" sub-directory of the Odin project root +// and we're being run from the Odin project root or from a sub-directory of "tests/" +// e.g. get_data_path("assets/blah") will return "/Odin_root/tests/assets/blah" if run within "/Odin_root", +// "/Odin_root/tests" or "/Odin_root/tests/subdir" etc +get_data_path :: proc(t: ^testing.T, sub_path: string) -> (data_path: string) { + + cwd := os.get_current_directory() + defer delete(cwd) + + when ODIN_OS == .Windows { + norm, was_allocation := strings.replace_all(cwd, "\\", "/") + if !was_allocation { + norm = strings.clone(norm) + } + defer delete(norm) + } else { + norm := cwd + } + + last_index := strings.last_index(norm, "/tests/") + if last_index == -1 { + len := len(norm) + if len >= 6 && norm[len-6:] == "/tests" { + data_path = fmt.tprintf("%s/%s", norm, sub_path) + } else { + data_path = fmt.tprintf("%s/tests/%s", norm, sub_path) + } + } else { + data_path = fmt.tprintf("%s/tests/%s", norm[:last_index], sub_path) + } + + return data_path +} diff --git a/tests/core/Makefile b/tests/core/Makefile index 1158434bf..a990c5833 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -2,7 +2,7 @@ ODIN=../../odin PYTHON=$(shell which python3) all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test + math_test linalg_glsl_math_test reflect_test download_test_assets: $(PYTHON) download_assets.py @@ -26,6 +26,7 @@ noise_test: $(ODIN) run math/noise -out=test_noise encoding_test: + $(ODIN) run encoding/hxa -out=test_hxa -collection:tests=.. $(ODIN) run encoding/json -out=test_json $(ODIN) run encoding/varint -out=test_varint @@ -34,3 +35,6 @@ math_test: linalg_glsl_math_test: $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -out=test_linalg_glsl_math -collection:tests=.. + +reflect_test: + $(ODIN) run reflect/test_core_reflect.odin -out=test_core_reflect -collection:tests=.. diff --git a/tests/core/assets/HXA/teapot.hxa b/tests/core/assets/HXA/teapot.hxa new file mode 100644 index 0000000000000000000000000000000000000000..954ab5a1012cee96592adde842c6e88f8783aab7 GIT binary patch literal 21867 zcmZ{L2UHZv_ca*=Bx4509MqklEbAvz5Rjf{+l3<>@p zef;Z%2lWgKG1QA47!nye0A{d?2_F&}G;m;Oc%NS;n7eh%K%88ZVQ^4bXmAkE&=5lB zUk_{FDkdoSr(|uOu1mX+$moz*L;H}h;9t(evwm1mw4rrG?`T6*Ol0q%ULn7HY+olL z+?*w0i{W zdoioOo`p}n*yzY0LqsGlbx`C`!@!8paPz^^s_udqeD>g@{}rw zi-mFv3jbLOX35I7PR!4<5>s}>6%E1l`}KIucu9Yeas>uO;V_}YejZX;ewx|et7TBH z{>X|!nUZ;RS~<1*S=7H?Z!eplE8GFg4Fzm#d)l-A#}b-{R^UuPwu)OEw23+Eu3p>q zkg4IfM!Q=$dT6`0uk-uS$w}&?{Hpe;+sH#JHtB%7mSEA_Et)ef{PKVMS8SO(vvx1f z|M>Ux=umB!lbh5_rfqflQRS=g#l4p0FD=h5kK6uLu9=4)r5Nir{j2b>+-~x?rO$=U zY*hcNaoVj`H|;##W&cru@2-E$m1=wzlQHh0hvmFB^c%N6&FY&m_4M$Y=juAj<1W2@ zr^v>=_S(djYkIqXc91?H$I5>B)Z1Rm{j5XIy{#POarKY8`^-CGuRVXp~l+ngfdvgDCA7kKmqsX(9VfSCNhr4R7XS#j(k^0Rj z@;o_V%h)Ymu3G%Y9Umt5_-+(=PVD?Ly5m$=?P&O&J;f`g$^I2yZY}bBe0HsSlQWLB z@}^7w(6sirByQST&x&a^>+hC&*xVk2s(!NQ;<(|#{@=!rwdmrwD;i()?`!WaeMJ9~ z1&^0}2?HK72Ka zEuZ!b~>s$6@ z+mOe;4!St5xV|+uE;1w>aghDR^|g!ooO*bgqx2Wow^r{J6@Fy6N?p|Rm4f%bjq2wr zeMCLmT|PXq$t72LTv5+9lDLtM`iyDXp{>g;*LPdqJ*Cf;a@5}(I#s4s zhP^!BKemKE8Z_BaPt0e#y78Tj*0mCtbb1MXmewyPGGQK62KTc~Kj_%6guP za*YUZ(>IQ+?q9LxS6R<)YlBiJ-N~+x=`r2kwAWJ4;W-y2{vPP2UwQ4;v(IEpJ?~!G zbBU>uyRO#r;QMhetC#lB)%DwD$fq_FyI6El&kws@%eAGDMHlt#JzhVzGQ^^b{%!wHS{)Ybh;oUgiHiSt$WD{;Q+ekIOV-LJ&?s{6CJzUuxguCKa3i|ecI z&*J*3`?I*d>fa+#&+6YJQP1k%BT>)l-y>1a>fa+#&o13Q`>r19t<7v5U3mWJG^1FL zg?ctFe6@+M_MuCzH}&4dOZ{-*yaLnb=FqA>Xb|4)zySOe`+<-2?;DX6cXp1I zHa-2Q9@WBE`g>lu8vixLO53|DkJr~bF4Di-i6K32HF4H#LRxQ43U`zK>!P>+xct;r z%QI!|&e;V#q`&8++h1JvxM|tSw7bz`n1}RFzF4`++CJ`Dt^zghRqdH+6!{rjdseYV zRXnwq&L1K@^IJ>*dy!>MwteBHo#;NhQbGY6>5pA)&3IoQt>2;O*|{dzNdM859GzZH z@{xbPg#W`A1&?^|^pd*Bf6ANK3tF6|zsNtg>x@gjvcJgxrSyJo9!+y-B^F1<4cVV= z68>WTcW3y_3Ywc~68>WTv#VP-n{d%e7ye@Y)#pFkxTCDKF8sy(kMMqEg0n9CMgFfE zkDi>IC%Z2EMgD8FetqcFdpGGX@}F;EgC9LsxJ!SL|D3CHPg&dAQ~Hbg8Hn4Eoz~vc zU)0Z&Psg2}miLkVqJF#=&*)!gjgRyf^%L1-Q-ML3y`;aW=XF-OF0WYWBmIS5RBKkc zbE2>G7kba0p9T%+n?w2wU7i1f;rpKNyPj!M=kI{B=rS-N{B*=RbR5 zT&L@YY;-mMPe%WC_g_y}UCn>Va=|g1*173w{c3Uhzy?<@bli27M^e8f=edEQbN^|Sx< zwTWf=TKbFn4BY1*m-ufE*Te~S9C_TCp$rECt(o`1kg+vuWhohIk+^}f1~ zws>#4=5*Gk=)go*>Ho6&v|VkwxoCg>8)tAV;w=4x3wdlyobM!`n}ol(ubx&RZ}8t& zt)>66;qLSE?e*4@OmpAfX=o+=izgR;v*?Yd#@qJVV={~)KXdjLT9PB5hkQN~{^EH- z++T_OCpF19w4twMKNtB=Jr=yNN3^%x=Y@a#q}{1LV?3oU{Ka$7oQOU9%a63ug}Oj=1hE{YCv8YQLpvs=b%=7xh!ZZ*yi;RS)Se>POtq z3x82Rajb_pU+FLEe_HW(*^kWhmi|JYySz^C@$7g1fHfzx*6L=oHSbtNGtHV&1ExU7h7~ zhwvBorE2|TO@EP(o}|eb$*C^7%sei~DW0{&$vWA3MK^Wj`17 zv+TpVQ%&0Y$bDYa&)VMZyKH)SNnQAh=LmKE%K0nnSIl2szheI4c|rJ#`K$Yn$iKS( zi2SSjkI27xE)f1A|LXoJ>POu_Mg6Gzr>Gxs|1bPS{S1mU)oEpg_hZ8kr^VyBU({{% zfl@^)KhCas^}hFG?oBtT*NIwMztcurt*fa=m9WL`QWw{;@rS(KhrhJwSCVV)tI^+G z`rqx;z3{G(RAU0}BJ{;B(tm8W2L~1x`(hlJ9XAZ+ZKVHQV+&h{MhV8lQ+w`T(-!Zw z%=29G<86bgg{r>U(DytxbO3-`PpctK91Q@;&!S@_=x%NwUg(G0Gap##Vm{(}efGdk(+=-#l)4)66)!+1yGkEXZ%wvWUGlB1jr0+^ zI-jii_?Tu==YzY?^?^H6P3nB`_T_M;?MWszKd;(H;T4IKuI7i^)pESYQS&p%scpX$ zJ>8^UuhhfMMyITD*VXIgv$es~VK-cK^?EJ1Gonl0el~Ky68S0gSGW5A=JS-gxL!-+ zYQ0O!=_YlN=djvav-`%|>S{fU`Ka|Q=A+iLn2)-?M1IuuCGw-LFOeU0y^HImu6J?0 z)b%c|m&1rrxe7e+)aSY3!Ki7veE(4B*0a`DrE=aP#7t!iTQl~t7fAE4!QKHy#H-w(eW+CE}KGrdhtA8twdA4th50#qEVmq2_>23c9Jp-X>ey;xy;qNUv9o5`TzZkLjnJawDfr&H@qW5v z@U|hN)2(IyVaL4Oi+482>m__9m02ILFy3-pp{wV6#`@r*nlGN2)bka(dcHze&sXT` z`3haVzJ10Hp6Fxy+N54zp{v(d=<4+qx_W(uuGX`dk6O<{SL<2mYCQ{Gt!JS-UN1MI z?pr_otACkl@8>*~>+9a+jF7Jr^63{H?W)hNeB30i3;xWbwOrT+hW zuYz4VfBnAxdTwjq>4v$F<@&-)k$9hn`E=us{r#2|x?~ddcG;);wts)iqmQb#v+K$k z@1-8_w&}`G)pO{4P4^`;Rq9DCeO`MH&95I^mHDF6uG?}Q%{u%j z=YNtfo_hG}bvsNevUys(oDbfj*W0r*kN$JtOp$uUCN?*2MEdIS)_CDr&RQ4eiyiP= z@;HO;>|KB7j*(|%{_F9-T0cTp z>qqFk4eq_cTYFgGq}5+Vx6Ay`p0yL-Xy?}2R>?W~zV{ueXT7f*mRD2%9(kNTuy5L_ zd|F>)VBJ64TFHHn+j$A6{F?aQM64rm+|DjLuUrbfZb~|_IcJ?}?~T3Qclx9Dq}-ZY z+~r$Gj~+0d+tO%nk>mtpm>r%BZ1QOxzs`tz?eW1lkMAoE#T$)y&3!w}Ps{9lcKS3u z(|CMbnzg&@U1QdBlB+=;w^7&-_bVf>8O3o=#n~3{+dHvz{2{ougddX71O3tKw*Pc@;o!1CeQcC@;qf91{ajaRnJ#l z7d-64(|NT5Hf}2$U;HB15r58bI^JIkZMVmL==sC)x;LnpqgkIJ2JKZme|Yd+>K9$M z&uIS6a$NQLit`yu6D`SLdVoZUy0dcHl*wkv0Q z{`9-~E!sUXsn@q|))xt>CiVJeJqP7ZG5zQIUYzzOTa%9__4>|T(5J|j)Ym5U`qumX z!1y~0pUdNldKTxa*0VTYwVuWKs`V_+SFLApzOG1r*Sq<(mX9l}JO7WPTz4bhEi7VP z-JpFPcy`db&lWxFeNjupfBN?s>i=M=uVuZ6>o}u#sYRDY8MLhT@mn3WUA2ZCANl-> zk>ybAxIuIO^uqp*qmwq_Xr&>aP3MgF^Nt9raMGahc5K#8N3C9!G}{+@jvG(q7?*F( zK#PCgdsboE1l>5pAt^^gy?|Da*XgXIcGj)rAiwxK#*O9ncsx%kpdH^+Z(;TdPTKvy z+j@pqxMB234!GR=WC87F9VXsUyIb0(*GSvT|5#)|9H##WMdR5y;%hf?6%-+p7j<{6F*O-#aTyos0QreV;SCkj8JXCVjBv z`Bv1mv{UN}X*2kJV1(uOKhC{e0^F(>(mJfKbg_n;MK4@0xWmcL7Jrd{b^eWm9>q8H zer!_b-@%SM;C+)i|7xb7e*&EEm`*A4Uo|th-G_m*-qQ6={a{fyFi1~~6Iotj?*J9&CZ(0AXR{9o*Sabhc?Su4>s(Yl#h9*~y9tj2Gb|k%%{z!6--%DLFVs-7lUnXAq z_x@hw*_KZSjqcZ4Kld0EFZ~1VlxUaz*dgPdo0}^h+4frcuYbPePMzV;jEi^Hez9Ql zE9pPwSeeQGu}_V|SB`ntWTg~u#DIVJ9>N%)KTdqpfAeems3lkgYw z53x68FW)U*`iuNGjBjaj>HJLki~QfRTC=i#fg93aLmHuKssd#>w zUFBB^(qHK5n=7>LH2RVB7kcTe0(~s~g|5!uxo^R+*kO-N>ipkj-IzZzsq-)Q&$|T& ze!FQ>=f7^@`i#40ukN3se$@R_)Q`G8P?T-}i9B>iiy2*Xbdla2hj!1@m^ z^1eOm_ni@6j2pB4^WN4YN&1&7(>8QU;v3_btS{u!jAH&jeNv5I9J()P+SXS3-;8}z zwEP)s?Ni5PjziYjOaJ-&LNt$^miGF_+{?+&q(8r2Sk~>MG3#f4Zb{PLvDV_Y%llht zeEr`(^@~yDrvqP0cXQN&!tiAGSE~Ho?7F&Mctz_hzef=HuiI|#u;$;BjbdGh`TNxx z6> z;V<%k?047vo~`Y4F@KT&w&hB0@V@d<`iuH0@3c8zr`1-vn7^o>tjC!7j?!P$&t>;Q z6B;abmj0rC@U6eoiT@;16!KdUY{ zEDSE3O;_vZTe~S7^aQyinII=~C^bUy(3GWqRZS4Rvd-Hz_`H`8Ki7r;u_}{rQz@329@P9w7 z(!sL0Xzqg8a>{F=LAxt$2;&`Kx*`O3!Vp<8$pi*@Vr23^mqfF z4@iw3ufhF*)adaFya3REV4ryKf#rUIJJgL67_3C4toFaS!}AAT@g21uq4pMvpt-Wq_p-^tc6H7D$aAH^IvRsnO#G zczGZ-dRzyu2;~1%qQ_P6-+|QVaRs~*kQzNMgI5MpqsJxis=z7;dRzdn2Bb!h^WfEi z)aY>zyatdOJhz2Bb!h6X1UU0}%8$23`k9jUGqA z>jJ6KLkF)1q(%=DcmrU41U(LeHw03n$06`WKx*_j2;LY-jUETUn*y64=&=vH8IT%1 z_JTJDQlrNn@D@O7^w;$&~QlrNXa9bcXdi)D+2c$-i?ci;I*$~vXfwu)x zYl+wj-VR8u6=Dl`dmyzy#AfggKsN+EHi35pQlrO4@J>K#^w%qGKxn}9H z4!kRn8a>v6cLP$R#~SeNKx*_@4c-Ho3qg-n;6cD12zvYj-V;cT9xK6n0jber1$Z#f z4?&OR;2}V2JrK*ldjqM_V<~taAT@d{0q+Yeh@i(}@K7K%dMpC(2c$-ih2Z^x)abDQ zJPcS2L67<11Ax@%F%LW(NR1wI!6Sgw=rIR;Ag~mI9<#v*0jbgBZ}3PUHG0efj{;Jo z$4u~OAlEcKW`M^4snKIP_+TJ4dQ1Z!0;EQdso=4|$_RQ)0UrvaMvuwh!+_N2@fY}T zAT@eS0v`e7nx@A@@R2}j^!O8e6p$J{;=o4(snKHs_!yvupvQRdvA{71dW-`f2c$-i zvEbvWBj_;(d;*YbT0@Kmj{{O0gBS(=Cy-i}2lzy^snKHu_#`0LG(Coc{{^H*k73}G zfz;?R6nqMh8a-mcrvkaA=`jR+8ju=227^xrQlm!<_zWO5dPIYBo!TMj5e41~NR1wm z;9RHF=rIVqHIN!T27=E4a!pf@0G|t_HWLvJJ`YH37GePSd?2;I5nnx;oD z@Rh(72zvAc{|88o9zo!%fYj*G1AH}*YdXsVd=1*vRv@~8uLV-0M_2H5Kx*{p0=^!| zHBFDs;2VI{=+Oy$Baj+BI)ZNkQlm!)@XbK3X?nB=-vXpYk9Oc&fz;^H7JM6!8a>*8 zZwGQs)1x)`zd&mA2n62&q(+Zc;5&iT=+P2<7m#b39xcFk1F6xYIrttRHF`7y-wUKh zkEY=JfWr~=Xac?;NR1wi!4Ckb(W4RgK_E4HGz32cM3z#jpraeQI$$3SWvU&uU`8rx5R>ku4Y5d10d34-GbfIkCL z<9LI4EH$>{ftwH%xTUk-#cpLERKx%Art<6Soyfrx2 z8a0l$0>1{J#_^dyevYNawj(?o5Y~tca3>%&8$>#IHXt=yL>jm=keVIhJGd**1woHg zaCe{^f_=V#djdTW?DGlS2k4DppCs@cKwkv=ya&$-q{eaYz;gkqc_H3{=LS-vM*cL-hk%=QlrOfa6ce5db|Sn2U4TQOK<})KY||5!3zNkBG~6CcoAS>1p7P&FAgk* zV4nxz%oB6RKKH4y49DXTfU# zsd3yH@R~qsRS>7aYXO;4dYl5U4Wveoli)@mHF}%?*MQXMaU47V$eh#T82BGRYV*5hG3uh;EjPiH)?-_^E`NN z;fR^w&4AP*5HrAs00$!?5mUiO14kj^&>jXHju?aXc;Gn1ShV>$`;9<*BJfYdNVNGm z`^BO?1vnWo6m5Rae$i;p08U55pv}+OZy?%HK+b`mk1bGke)j(<--yM7nkQ&E#GmmBej%cp~u0@b{0bdWK#_^rO zHvp+|d?)i*_HT>!Cg4T{c?a;#Kx!P{9()Us8ppRYk7fT>Xm0~AJd^eC9$2T{RW&cKK?*;BbkT(V22c*XFO~Cg9 zsd0Q`^H}z;hxS3>0R(wN@Iydq9Nz%^FpwI@*Ef%4{{Xa2z#|Cqy5KsH8pqcGKMJJA z@qd`dvVSeKj{}b($Tjd2Kx!Os1V0I+#__eyW7)qN+NXi15acz%&j6`$d=2okKx!Oc z-8`24E1`WJcn(2c75oB_8pl@wzX+tp@s-VE*}pv6mw}fMyf-1IM*6AjxP&77f6lc%Yfeka$Qm{4SpL)?HZyK_#Gg%>xkdL?*gga zK$HZ(2jtqMM+xxzKx*_T4*md0jUL6o9|Eb-qbT?zAlD~7ihw@`Qlm#<@FzfO^e6=W z6iAI81;L*Ixkl+x06ZQ@jUEQ@=Rj)o$PfMkNR1x;;4gt(r}Xdxe+8sQk9^>-fz;@c z7yJ#78a?uWCjhxt>5&^e5lD?5xxn87snH`R_&XpqdgK6q59E5KhcEaCAT@gUfF}W| z(Zd`3Baj+Byug!zT(k7>1pfr2Mh_40&p>MQa0mYaq(%=n@Dw1|Ej_Y>e+5#bhbwq0 zkQzN)z`p^h(Zd=1JCJLa9@)UtfYj*W1fCA0Mh{2u3?ManIDr2Ea{bc79y}9BjUIO3 zRyMdFMw=eC;MU;O=wSnHgErSNJ*>fP!Ku;13fvBDYV^p=z$4b|5u+q=35txt{6q z1>7B+8a+OPdjP4?;}f_ikQzOb!MRSkcIojEoa>YtJ(9q=PN~u31Ncp}snO#-cmcEx zh`fk+hzsDD6s20Rql7tsr`7@R)j)aln7*dNgk!TZ1nbDP=> z^LTzno&AG=JrJD{tH49doccoW_P}_<+W{n_T+S|YZBcQSM8tHGxM2O*jv zc>G8+&(h7G{{?L_b#Ts;oS(CQoS9SSeAthlQy*&nd@S1I%$)Nk=jZIt_DIAiB6t@w zr@joFpAAI}LyQIId684+`LP{?7>tMm4>WV?>%n<${G9p@aP}joJ`Fq?7>gK!m~yBh1qR#p9*!-M) b61V|dQGP@o#B*$a{=nR3{sf%+761Jo9F4Mr literal 0 HcmV?d00001 diff --git a/tests/core/build.bat b/tests/core/build.bat index 0227ac6bb..c94aac10a 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,5 +1,5 @@ @echo off -set COMMON=-show-timings -no-bounds-check -vet -strict-style +set COMMON=-show-timings -no-bounds-check -vet -strict-style -collection:tests=.. set PATH_TO_ODIN==..\..\odin python3 download_assets.py echo --- @@ -35,10 +35,26 @@ echo --- echo --- echo Running core:encoding tests echo --- +%PATH_TO_ODIN% run encoding/hxa %COMMON% %PATH_TO_ODIN% run encoding/json %COMMON% %PATH_TO_ODIN% run encoding/varint %COMMON% echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% \ No newline at end of file +%PATH_TO_ODIN% run math/noise %COMMON% + +echo --- +echo Running core:math tests +echo --- +%PATH_TO_ODIN% run math %COMMON% + +echo --- +echo Running core:math/linalg/glsl tests +echo --- +%PATH_TO_ODIN% run math/linalg/glsl %COMMON% + +echo --- +echo Running core:reflect tests +echo --- +%PATH_TO_ODIN% run reflect %COMMON% diff --git a/tests/core/encoding/hxa/test_core_hxa.odin b/tests/core/encoding/hxa/test_core_hxa.odin new file mode 100644 index 000000000..b93562fd5 --- /dev/null +++ b/tests/core/encoding/hxa/test_core_hxa.odin @@ -0,0 +1,232 @@ +// Tests "core:encoding:hxa". +// Must be run with `-collection:tests=` flag, e.g. +// ./odin run tests/core/encoding/hxa/test_core_hxa.odin -out=tests/core/test_core_hxa -collection:tests=./tests +package test_core_hxa + +import "core:encoding/hxa" +import "core:fmt" +import "core:testing" +import tc "tests:common" + +TEAPOT_PATH :: "core/assets/HXA/teapot.hxa" + +main :: proc() { + t := testing.T{} + + test_read(&t) + test_write(&t) + + tc.report(&t) +} + +@test +test_read :: proc(t: ^testing.T) { + + using hxa + + filename := tc.get_data_path(t, TEAPOT_PATH) + defer delete(filename) + + file, err := read_from_file(filename) + e :: hxa.Read_Error.None + tc.expect(t, err == e, fmt.tprintf("%v: read_from_file(%v) -> %v != %v", #procedure, filename, err, e)) + defer file_destroy(file) + + /* Header */ + tc.expect(t, file.magic_number == 0x417848, fmt.tprintf("%v: file.magic_number %v != %v", + #procedure, file.magic_number, 0x417848)) + tc.expect(t, file.version == 1, fmt.tprintf("%v: file.version %v != %v", + #procedure, file.version, 1)) + tc.expect(t, file.internal_node_count == 1, fmt.tprintf("%v: file.internal_node_count %v != %v", + #procedure, file.internal_node_count, 1)) + + /* Nodes (only one) */ + tc.expect(t, len(file.nodes) == 1, fmt.tprintf("%v: len(file.nodes) %v != %v", #procedure, len(file.nodes), 1)) + + m := &file.nodes[0].meta_data + tc.expect(t, len(m^) == 38, fmt.tprintf("%v: len(m^) %v != %v", #procedure, len(m^), 38)) + { + e :: "Texture resolution" + tc.expect(t, m[0].name == e, fmt.tprintf("%v: m[0].name %v != %v", #procedure, m[0].name, e)) + + m_v, m_v_ok := m[0].value.([]i64le) + tc.expect(t, m_v_ok, fmt.tprintf("%v: m_v_ok %v != %v", #procedure, m_v_ok, true)) + tc.expect(t, len(m_v) == 1, fmt.tprintf("%v: len(m_v) %v != %v", #procedure, len(m_v), 1)) + tc.expect(t, m_v[0] == 1024, fmt.tprintf("%v: m_v[0] %v != %v", #procedure, len(m_v), 1024)) + } + { + e :: "Validate" + tc.expect(t, m[37].name == e, fmt.tprintf("%v: m[37].name %v != %v", #procedure, m[37].name, e)) + + m_v, m_v_ok := m[37].value.([]i64le) + tc.expect(t, m_v_ok, fmt.tprintf("%v: m_v_ok %v != %v", #procedure, m_v_ok, true)) + tc.expect(t, len(m_v) == 1, fmt.tprintf("%v: len(m_v) %v != %v", #procedure, len(m_v), 1)) + tc.expect(t, m_v[0] == -2054847231, fmt.tprintf("%v: m_v[0] %v != %v", #procedure, len(m_v), -2054847231)) + } + + /* Node content */ + v, v_ok := file.nodes[0].content.(hxa.Node_Geometry) + tc.expect(t, v_ok, fmt.tprintf("%v: v_ok %v != %v", #procedure, v_ok, true)) + + tc.expect(t, v.vertex_count == 530, fmt.tprintf("%v: v.vertex_count %v != %v", #procedure, v.vertex_count, 530)) + tc.expect(t, v.edge_corner_count == 2026, fmt.tprintf("%v: v.edge_corner_count %v != %v", + #procedure, v.edge_corner_count, 2026)) + tc.expect(t, v.face_count == 517, fmt.tprintf("%v: v.face_count %v != %v", #procedure, v.face_count, 517)) + + /* Vertex stack */ + tc.expect(t, len(v.vertex_stack) == 1, fmt.tprintf("%v: len(v.vertex_stack) %v != %v", + #procedure, len(v.vertex_stack), 1)) + { + e := "vertex" + tc.expect(t, v.vertex_stack[0].name == e, fmt.tprintf("%v: v.vertex_stack[0].name %v != %v", + #procedure, v.vertex_stack[0].name, e)) + } + tc.expect(t, v.vertex_stack[0].components == 3, fmt.tprintf("%v: v.vertex_stack[0].components %v != %v", + #procedure, v.vertex_stack[0].components, 3)) + + /* Vertex stack data */ + vs_d, vs_d_ok := v.vertex_stack[0].data.([]f64le) + tc.expect(t, vs_d_ok, fmt.tprintf("%v: vs_d_ok %v != %v", #procedure, vs_d_ok, true)) + tc.expect(t, len(vs_d) == 1590, fmt.tprintf("%v: len(vs_d) %v != %v", #procedure, len(vs_d), 1590)) + + tc.expect(t, vs_d[0] == 4.06266, fmt.tprintf("%v: vs_d[0] %v (%h) != %v (%h)", + #procedure, vs_d[0], vs_d[0], 4.06266, 4.06266)) + tc.expect(t, vs_d[1] == 2.83457, fmt.tprintf("%v: vs_d[1] %v (%h) != %v (%h)", + #procedure, vs_d[1], vs_d[1], 2.83457, 2.83457)) + tc.expect(t, vs_d[2] == 0hbfbc5da6a4441787, fmt.tprintf("%v: vs_d[2] %v (%h) != %v (%h)", + #procedure, vs_d[2], vs_d[2], + 0hbfbc5da6a4441787, 0hbfbc5da6a4441787)) + tc.expect(t, vs_d[3] == 0h4010074fb549f948, fmt.tprintf("%v: vs_d[3] %v (%h) != %v (%h)", + #procedure, vs_d[3], vs_d[3], + 0h4010074fb549f948, 0h4010074fb549f948)) + tc.expect(t, vs_d[1587] == 0h400befa82e87d2c7, fmt.tprintf("%v: vs_d[1587] %v (%h) != %v (%h)", + #procedure, vs_d[1587], vs_d[1587], + 0h400befa82e87d2c7, 0h400befa82e87d2c7)) + tc.expect(t, vs_d[1588] == 2.83457, fmt.tprintf("%v: vs_d[1588] %v (%h) != %v (%h)", + #procedure, vs_d[1588], vs_d[1588], 2.83457, 2.83457)) + tc.expect(t, vs_d[1589] == -1.56121, fmt.tprintf("%v: vs_d[1589] %v (%h) != %v (%h)", + #procedure, vs_d[1589], vs_d[1589], -1.56121, -1.56121)) + + /* Corner stack */ + tc.expect(t, len(v.corner_stack) == 1, + fmt.tprintf("%v: len(v.corner_stack) %v != %v", #procedure, len(v.corner_stack), 1)) + { + e := "reference" + tc.expect(t, v.corner_stack[0].name == e, fmt.tprintf("%v: v.corner_stack[0].name %v != %v", + #procedure, v.corner_stack[0].name, e)) + } + tc.expect(t, v.corner_stack[0].components == 1, fmt.tprintf("%v: v.corner_stack[0].components %v != %v", + #procedure, v.corner_stack[0].components, 1)) + + /* Corner stack data */ + cs_d, cs_d_ok := v.corner_stack[0].data.([]i32le) + tc.expect(t, cs_d_ok, fmt.tprintf("%v: cs_d_ok %v != %v", #procedure, cs_d_ok, true)) + tc.expect(t, len(cs_d) == 2026, fmt.tprintf("%v: len(cs_d) %v != %v", #procedure, len(cs_d), 2026)) + tc.expect(t, cs_d[0] == 6, fmt.tprintf("%v: cs_d[0] %v != %v", #procedure, cs_d[0], 6)) + tc.expect(t, cs_d[2025] == -32, fmt.tprintf("%v: cs_d[2025] %v != %v", #procedure, cs_d[2025], -32)) + + /* Edge and face stacks (empty) */ + tc.expect(t, len(v.edge_stack) == 0, fmt.tprintf("%v: len(v.edge_stack) %v != %v", + #procedure, len(v.edge_stack), 0)) + tc.expect(t, len(v.face_stack) == 0, fmt.tprintf("%v: len(v.face_stack) %v != %v", + #procedure, len(v.face_stack), 0)) +} + +@test +test_write :: proc(t: ^testing.T) { + + using hxa + + n1 :Node + + n1_m1_value := []f64le{0.4, -1.23, 2341.6, -333.333} + n1_m1 := Meta{"m1", n1_m1_value} + + n1.meta_data = []Meta{n1_m1} + + n1_l1 := Layer{"l1", 2, []f32le{32.1, -41.3}} + n1_l2 := Layer{"l2", 3, []f64le{0.64, 1.64, -2.64}} + + n1_content := Node_Image{Image_Type.Image_1D, [3]u32le{1, 1, 2}, Layer_Stack{n1_l1, n1_l2}} + + n1.content = n1_content + + w_file :File + w_file.nodes = []Node{n1} + + required_size := required_write_size(w_file) + buf := make([]u8, required_size) + + n, write_err := write(buf, w_file) + write_e :: hxa.Write_Error.None + tc.expect(t, write_err == write_e, fmt.tprintf("%v: write_err %v != %v", #procedure, write_err, write_e)) + tc.expect(t, n == required_size, fmt.tprintf("%v: n %v != %v", #procedure, n, required_size)) + + file, read_err := read(buf) + read_e :: hxa.Read_Error.None + tc.expect(t, read_err == read_e, fmt.tprintf("%v: read_err %v != %v", #procedure, read_err, read_e)) + defer file_destroy(file) + + delete(buf) + + tc.expect(t, file.magic_number == 0x417848, fmt.tprintf("%v: file.magic_number %v != %v", + #procedure, file.magic_number, 0x417848)) + tc.expect(t, file.version == 3, fmt.tprintf("%v: file.version %v != %v", #procedure, file.version, 3)) + tc.expect(t, file.internal_node_count == 1, fmt.tprintf("%v: file.internal_node_count %v != %v", + #procedure, file.internal_node_count, 1)) + + tc.expect(t, len(file.nodes) == len(w_file.nodes), fmt.tprintf("%v: len(file.nodes) %v != %v", + #procedure, len(file.nodes), len(w_file.nodes))) + + m := &file.nodes[0].meta_data + w_m := &w_file.nodes[0].meta_data + tc.expect(t, len(m^) == len(w_m^), fmt.tprintf("%v: len(m^) %v != %v", #procedure, len(m^), len(w_m^))) + tc.expect(t, m[0].name == w_m[0].name, fmt.tprintf("%v: m[0].name %v != %v", #procedure, m[0].name, w_m[0].name)) + + m_v, m_v_ok := m[0].value.([]f64le) + tc.expect(t, m_v_ok, fmt.tprintf("%v: m_v_ok %v != %v", #procedure, m_v_ok, true)) + tc.expect(t, len(m_v) == len(n1_m1_value), fmt.tprintf("%v: %v != len(m_v) %v", + #procedure, len(m_v), len(n1_m1_value))) + for i := 0; i < len(m_v); i += 1 { + tc.expect(t, m_v[i] == n1_m1_value[i], fmt.tprintf("%v: m_v[%d] %v != %v", + #procedure, i, m_v[i], n1_m1_value[i])) + } + + v, v_ok := file.nodes[0].content.(hxa.Node_Image) + tc.expect(t, v_ok, fmt.tprintf("%v: v_ok %v != %v", #procedure, v_ok, true)) + tc.expect(t, v.type == n1_content.type, fmt.tprintf("%v: v.type %v != %v", #procedure, v.type, n1_content.type)) + tc.expect(t, len(v.resolution) == 3, fmt.tprintf("%v: len(v.resolution) %v != %v", + #procedure, len(v.resolution), 3)) + tc.expect(t, len(v.image_stack) == len(n1_content.image_stack), fmt.tprintf("%v: len(v.image_stack) %v != %v", + #procedure, len(v.image_stack), len(n1_content.image_stack))) + for i := 0; i < len(v.image_stack); i += 1 { + tc.expect(t, v.image_stack[i].name == n1_content.image_stack[i].name, + fmt.tprintf("%v: v.image_stack[%d].name %v != %v", + #procedure, i, v.image_stack[i].name, n1_content.image_stack[i].name)) + tc.expect(t, v.image_stack[i].components == n1_content.image_stack[i].components, + fmt.tprintf("%v: v.image_stack[%d].components %v != %v", + #procedure, i, v.image_stack[i].components, n1_content.image_stack[i].components)) + + switch n1_t in n1_content.image_stack[i].data { + case []u8: + tc.expect(t, false, fmt.tprintf("%v: n1_content.image_stack[i].data []u8", #procedure)) + case []i32le: + tc.expect(t, false, fmt.tprintf("%v: n1_content.image_stack[i].data []i32le", #procedure)) + case []f32le: + l, l_ok := v.image_stack[i].data.([]f32le) + tc.expect(t, l_ok, fmt.tprintf("%v: l_ok %v != %v", #procedure, l_ok, true)) + tc.expect(t, len(l) == len(n1_t), fmt.tprintf("%v: len(l) %v != %v", #procedure, len(l), len(n1_t))) + for j := 0; j < len(l); j += 1 { + tc.expect(t, l[j] == n1_t[j], fmt.tprintf("%v: l[%d] %v (%h) != %v (%h)", + #procedure, j, l[j], l[j], n1_t[j], n1_t[j])) + } + case []f64le: + l, l_ok := v.image_stack[i].data.([]f64le) + tc.expect(t, l_ok, fmt.tprintf("%v: l_ok %v != %v", #procedure, l_ok, true)) + tc.expect(t, len(l) == len(n1_t), fmt.tprintf("%v: len(l) %v != %v", #procedure, len(l), len(n1_t))) + for j := 0; j < len(l); j += 1 { + tc.expect(t, l[j] == n1_t[j], fmt.tprintf("%v: l[%d] %v != %v", #procedure, j, l[j], n1_t[j])) + } + } + } +} diff --git a/tests/core/reflect/test_core_reflect.odin b/tests/core/reflect/test_core_reflect.odin new file mode 100644 index 000000000..039501735 --- /dev/null +++ b/tests/core/reflect/test_core_reflect.odin @@ -0,0 +1,288 @@ +// Tests "core:reflect/reflect". +// Must be run with `-collection:tests=` flag, e.g. +// ./odin run tests/core/reflect/test_core_reflect.odin -out=tests/core/test_core_reflect -collection:tests=./tests +package test_core_reflect + +import "core:fmt" +import "core:reflect" +import "core:testing" +import tc "tests:common" + +main :: proc() { + t := testing.T{} + + test_as_u64(&t) + test_as_f64(&t) + + tc.report(&t) +} + +@test +test_as_u64 :: proc(t: ^testing.T) { + using reflect + + { + /* i8 */ + Datum :: struct { i: int, v: i8, e: u64 } + @static data := []Datum{ + { 0, 0x7F, 0x7F }, + { 1, -1, 0xFFFF_FFFF_FFFF_FFFF }, + { 2, -0x80, 0xFFFF_FFFF_FFFF_FF80 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v (0x%X) != %v (0x%X)\n", + i, #procedure, d.v, r, r, d.e, d.e)) + } + } + { + /* i16 */ + Datum :: struct { i: int, v: i16, e: u64 } + @static data := []Datum{ + { 0, 0x7FFF, 0x7FFF }, + { 1, -1, 0xFFFF_FFFF_FFFF_FFFF }, + { 2, -0x8000, 0xFFFF_FFFF_FFFF_8000 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v (0x%X) != %v (0x%X)\n", + i, #procedure, d.v, r, r, d.e, d.e)) + } + } + { + /* i32 */ + Datum :: struct { i: int, v: i32, e: u64 } + @static data := []Datum{ + { 0, 0x7FFF_FFFF, 0x7FFF_FFFF }, + { 1, -1, 0xFFFF_FFFF_FFFF_FFFF }, + { 2, -0x8000_0000, 0xFFFF_FFFF_8000_0000 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v (0x%X) != %v (0x%X)\n", + i, #procedure, d.v, r, r, d.e, d.e)) + } + } + { + /* i64 */ + Datum :: struct { i: int, v: i64, e: u64 } + @static data := []Datum{ + { 0, 0x7FFF_FFFF_FFFF_FFFF, 0x7FFF_FFFF_FFFF_FFFF }, + { 1, -1, 0xFFFF_FFFF_FFFF_FFFF }, + { 2, -0x8000_0000_0000_0000, 0x8000_0000_0000_0000 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v (0x%X) != %v (0x%X)\n", + i, #procedure, d.v, r, r, d.e, d.e)) + } + } + { + /* i128 */ + Datum :: struct { i: int, v: i128, e: u64 } + @static data := []Datum{ + { 0, 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF }, + { 1, -1, 0xFFFF_FFFF_FFFF_FFFF }, + { 2, 0x8000_0000_0000_0000, 0x8000_0000_0000_0000 }, + { 3, -0x8000_0000_0000_0000, 0x8000_0000_0000_0000 }, + { 4, 0x0001_0000_0000_0000_0000, 0 }, + { 5, -0x8000_0000_0000_0000_0000_0000_0000_0000, 0 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (0x%X) != %v (0x%X)\n", + i, #procedure, d.v, r, r, d.e, d.e)) + } + } + { + /* f16 */ + Datum :: struct { i: int, v: f16, e: u64 } + @static data := []Datum{ + { 0, 1.2, 1 }, + { 1, 123.12, 123 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } + { + /* f32 */ + Datum :: struct { i: int, v: f32, e: u64 } + @static data := []Datum{ + { 0, 123.3415, 123 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } + { + /* f64 */ + Datum :: struct { i: int, v: f64, e: u64 } + @static data := []Datum{ + { 0, 12345345345.3415234234, 12345345345 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_u64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } +} + +@test +test_as_f64 :: proc(t: ^testing.T) { + using reflect + + { + /* i8 */ + Datum :: struct { i: int, v: i8, e: f64 } + @static data := []Datum{ + { 0, 0x7F, 0x7F }, + { 1, -1, -1 }, + { 2, -0x80, -0x80 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } + { + /* i16 */ + Datum :: struct { i: int, v: i16, e: f64 } + @static data := []Datum{ + { 0, 0x7FFF, 0x7FFF }, + { 1, -1, -1 }, + { 2, -0x8000, -0x8000 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } + { + /* i32 */ + Datum :: struct { i: int, v: i32, e: f64 } + @static data := []Datum{ + { 0, 0x7FFF_FFFF, 0x7FFF_FFFF }, + { 1, -1, -1 }, + { 2, -0x8000_0000, -0x8000_0000 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } + { + /* i64 */ + Datum :: struct { i: int, v: i64, e: f64 } + @static data := []Datum{ + { 0, 0x7FFF_FFFF_FFFF_FFFF, 0x7FFF_FFFF_FFFF_FFFF }, + { 1, -1, -1 }, + { 2, -0x8000_0000_0000_0000, -0x8000_0000_0000_0000 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } + { + /* i128 */ + Datum :: struct { i: int, v: i128, e: f64 } + @static data := []Datum{ + { 0, 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF }, + { 1, -1, -1 }, + { 2, 0x8000_0000_0000_0000_0000_0000_0000, 0x8000_0000_0000_0000_0000_0000_0000 }, + { 3, -0x8000_0000_0000_0000_0000_0000_0000_0000, -0x8000_0000_0000_0000_0000_0000_0000_0000 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (%H) != %v (%H)\n", + i, #procedure, d.v, r, r, d.e, d.e)) + } + } + { + /* f16 */ + Datum :: struct { i: int, v: f16, e: f64 } + @static data := []Datum{ + { 0, 1.2, 0h3FF3_3400_0000_0000 }, // Precision difference TODO: check + { 1, 123.12, 0h405E_C800_0000_0000 }, // Precision difference TODO: check + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v (%H)) -> %v (%H) != %v (%H)\n", + i, #procedure, d.v, d.v, r, r, d.e, d.e)) + } + } + { + /* f32 */ + Datum :: struct { i: int, v: f32, e: f64 } + @static data := []Datum{ + { 0, 123.3415, 0h405E_D5DB_2000_0000 }, // Precision difference TODO: check + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v (%H)) -> %v (%H) != %v (%H)\n", + i, #procedure, d.v, d.v, r, r, d.e, d.e)) + } + } + { + /* f64 */ + Datum :: struct { i: int, v: f64, e: f64 } + @static data := []Datum{ + { 0, 12345345345.3415234234, 12345345345.3415234234 }, + } + + for d, i in data { + assert(i == d.i) + r, valid := as_f64(d.v) + tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v)) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + } + } +} From 5e04ddd653523c26a45ec2f3aee6e0a24a869675 Mon Sep 17 00:00:00 2001 From: "Stanislav Ch. Nikolov" Date: Thu, 17 Mar 2022 04:20:24 +0200 Subject: [PATCH 0409/1052] Fix #1627: Remove wrong return type in cumsum_inplace --- core/math/math.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/math/math.odin b/core/math/math.odin index afbda051d..b711c160f 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -1206,7 +1206,7 @@ prod :: proc "contextless" (x: $T/[]$E) -> (res: E) return } -cumsum_inplace :: proc "contextless" (x: $T/[]$E) -> T +cumsum_inplace :: proc "contextless" (x: $T/[]$E) where intrinsics.type_is_numeric(E) { for i in 1.. Date: Fri, 18 Mar 2022 19:35:36 +1100 Subject: [PATCH 0410/1052] Add unregister_class_a and unregister_class_w for windows bindings --- core/sys/win32/user32.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/sys/win32/user32.odin b/core/sys/win32/user32.odin index fdf6a91f6..44d1f7004 100644 --- a/core/sys/win32/user32.odin +++ b/core/sys/win32/user32.odin @@ -111,6 +111,8 @@ foreign user32 { @(link_name="SetWindowTextW") set_window_text_w :: proc(hwnd: Hwnd, c_string: Wstring) -> Bool --- @(link_name="RegisterClassA") register_class_a :: proc(wc: ^Wnd_Class_A) -> i16 --- @(link_name="RegisterClassW") register_class_w :: proc(wc: ^Wnd_Class_W) -> i16 --- + @(link_name="UnregisterClassA") unregister_class_a :: proc(class_name: cstring, instance: Hinstance) -> Bool --- + @(link_name="UnregisterClassW") unregister_class_w :: proc(class_name: Wstring, instance: Hinstance) -> Bool --- @(link_name="RegisterClassExA") register_class_ex_a :: proc(wc: ^Wnd_Class_Ex_A) -> i16 --- @(link_name="RegisterClassExW") register_class_ex_w :: proc(wc: ^Wnd_Class_Ex_W) -> i16 --- From 4f9df50dc1a5f7a3fd2cc97cfbda4e57e48e905f Mon Sep 17 00:00:00 2001 From: Tetralux Date: Fri, 18 Mar 2022 11:42:25 +0000 Subject: [PATCH 0411/1052] Remove incorrect #packed from sys/windows.STARTUPINFO --- core/sys/windows/types.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 1407201d6..1ead165b4 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -578,7 +578,7 @@ PROCESS_INFORMATION :: struct { } // FYI: This is STARTUPINFOW, not STARTUPINFOA -STARTUPINFO :: struct #packed { +STARTUPINFO :: struct { cb: DWORD, lpReserved: LPWSTR, lpDesktop: LPWSTR, From fdbbf242718746ad71cb410162c6d0b8c68c5af0 Mon Sep 17 00:00:00 2001 From: gitlost Date: Fri, 18 Mar 2022 13:57:22 +0000 Subject: [PATCH 0412/1052] Fix issue #1592 "LLVM code gen error when using a constant in an if" Changes lb_build_if_stmt() to return null lbValue if condition is cmpAnd, cmpOr or non-const neg and check in lb_build_if_stmt() to avoid short circuiting if that's the case Adds test to "tests/issues" and adds step in CI to check this dir --- .github/workflows/ci.yml | 12 + src/llvm_backend_expr.cpp | 4 +- src/llvm_backend_general.cpp | 15 +- src/llvm_backend_stmt.cpp | 5 +- tests/issues/test_issue_1592.odin | 489 ++++++++++++++++++++++++++++++ 5 files changed, 519 insertions(+), 6 deletions(-) create mode 100644 tests/issues/test_issue_1592.odin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bd3ca9ad..a3b1d8058 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,9 @@ jobs: cd tests/vendor make timeout-minutes: 10 + - name: Odin issues tests + run: ./odin run tests/issues -collection:tests=tests + timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 timeout-minutes: 10 @@ -87,6 +90,9 @@ jobs: cd tests/vendor make timeout-minutes: 10 + - name: Odin issues tests + run: ./odin run tests/issues -collection:tests=tests + timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 timeout-minutes: 10 @@ -153,6 +159,12 @@ jobs: cd tests\core\math\big call build.bat timeout-minutes: 10 + - name: Odin issues tests + shell: cmd + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat + odin run tests\issues -collection:tests=tests + timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd run: | diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 4294747b9..133df4d41 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3028,7 +3028,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { lbBlock *done = lb_create_block(p, "if.done"); // NOTE(bill): Append later lbBlock *else_ = lb_create_block(p, "if.else"); - lbValue cond = lb_build_cond(p, te->cond, then, else_); + lb_build_cond(p, te->cond, then, else_); lb_start_block(p, then); Type *type = default_type(type_of_expr(expr)); @@ -4646,7 +4646,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { lbBlock *done = lb_create_block(p, "if.done"); // NOTE(bill): Append later lbBlock *else_ = lb_create_block(p, "if.else"); - lbValue cond = lb_build_cond(p, te->cond, then, else_); + lb_build_cond(p, te->cond, then, else_); lb_start_block(p, then); Type *ptr_type = alloc_type_pointer(default_type(type_of_expr(expr))); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 1c98aa77f..dd1555193 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2602,6 +2602,9 @@ lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *f GB_ASSERT(true_block != nullptr); GB_ASSERT(false_block != nullptr); + // Use to signal not to do compile time short circuit for consts + lbValue no_comptime_short_circuit = {}; + switch (cond->kind) { case_ast_node(pe, ParenExpr, cond); return lb_build_cond(p, pe->expr, true_block, false_block); @@ -2609,7 +2612,11 @@ lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *f case_ast_node(ue, UnaryExpr, cond); if (ue->op.kind == Token_Not) { - return lb_build_cond(p, ue->expr, false_block, true_block); + lbValue cond_val = lb_build_cond(p, ue->expr, false_block, true_block); + if (cond_val.value && LLVMIsConstant(cond_val.value)) { + return lb_const_bool(p->module, cond_val.type, LLVMConstIntGetZExtValue(cond_val.value) == 0); + } + return no_comptime_short_circuit; } case_end; @@ -2618,12 +2625,14 @@ lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *f lbBlock *block = lb_create_block(p, "cmp.and"); lb_build_cond(p, be->left, block, false_block); lb_start_block(p, block); - return lb_build_cond(p, be->right, true_block, false_block); + lb_build_cond(p, be->right, true_block, false_block); + return no_comptime_short_circuit; } else if (be->op.kind == Token_CmpOr) { lbBlock *block = lb_create_block(p, "cmp.or"); lb_build_cond(p, be->left, true_block, block); lb_start_block(p, block); - return lb_build_cond(p, be->right, true_block, false_block); + lb_build_cond(p, be->right, true_block, false_block); + return no_comptime_short_circuit; } case_end; } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 916c0433e..2afb5300b 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1652,13 +1652,16 @@ void lb_build_if_stmt(lbProcedure *p, Ast *node) { } lbValue cond = lb_build_cond(p, is->cond, then, else_); + // Note `cond.value` only set for non-and/or conditions and const negs so that the `LLVMIsConstant()` + // and `LLVMConstIntGetZExtValue()` calls below will be valid and `LLVMInstructionEraseFromParent()` + // will target the correct (& only) branch statement if (is->label != nullptr) { lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr); tl->is_block = true; } - if (LLVMIsConstant(cond.value)) { + if (cond.value && LLVMIsConstant(cond.value)) { // NOTE(bill): Do a compile time short circuit for when the condition is constantly known. // This done manually rather than relying on the SSA passes because sometimes the SSA passes // miss some even if they are constantly known, especially with few optimization passes. diff --git a/tests/issues/test_issue_1592.odin b/tests/issues/test_issue_1592.odin new file mode 100644 index 000000000..bb350a30b --- /dev/null +++ b/tests/issues/test_issue_1592.odin @@ -0,0 +1,489 @@ +// Tests issue #1592 https://github.com/odin-lang/Odin/issues/1592 +package test_issues + +import "core:fmt" +import "core:testing" +import tc "tests:common" + +main :: proc() { + t := testing.T{} + + /* This won't short-circuit */ + test_orig() + + /* These will short-circuit */ + test_simple_const_false(&t) + test_simple_const_true(&t) + + /* These won't short-circuit */ + test_simple_proc_false(&t) + test_simple_proc_true(&t) + + /* These won't short-circuit */ + test_const_false_const_false(&t) + test_const_false_const_true(&t) + test_const_true_const_false(&t) + test_const_true_const_true(&t) + + /* These won't short-circuit */ + test_proc_false_const_false(&t) + test_proc_false_const_true(&t) + test_proc_true_const_false(&t) + test_proc_true_const_true(&t) + + tc.report(&t) +} + +/* Original issue #1592 example */ + +// I get a LLVM code gen error when this constant is false, but it works when it is true +CONSTANT_BOOL :: false + +bool_result :: proc() -> bool { + return false +} + +@test +test_orig :: proc() { + if bool_result() || CONSTANT_BOOL { + } +} + +CONSTANT_FALSE :: false +CONSTANT_TRUE :: true + +false_result :: proc() -> bool { + return false +} +true_result :: proc() -> bool { + return true +} + +@test +test_simple_const_false :: proc(t: ^testing.T) { + if CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if (CONSTANT_FALSE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !CONSTANT_FALSE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if (!CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !(CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !!CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if CONSTANT_FALSE == true { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if CONSTANT_FALSE == false { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !(CONSTANT_FALSE == true) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !(CONSTANT_FALSE == false) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } +} + +@test +test_simple_const_true :: proc(t: ^testing.T) { + if CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if (CONSTANT_TRUE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !CONSTANT_TRUE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if (!CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if (!CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !!CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_TRUE == true { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_TRUE == false { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(CONSTANT_TRUE == true) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(CONSTANT_TRUE == false) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_simple_proc_false :: proc(t: ^testing.T) { + if false_result() { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !false_result() { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_simple_proc_true :: proc(t: ^testing.T) { + if true_result() { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !true_result() { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } +} + +@test +test_const_false_const_false :: proc(t: ^testing.T) { + if CONSTANT_FALSE || CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if CONSTANT_FALSE && CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !CONSTANT_FALSE || CONSTANT_FALSE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !CONSTANT_FALSE && CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if CONSTANT_FALSE || !CONSTANT_FALSE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_FALSE && !CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !(CONSTANT_FALSE || CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !(CONSTANT_FALSE && CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_const_false_const_true :: proc(t: ^testing.T) { + if CONSTANT_FALSE || CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_FALSE && CONSTANT_TRUE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !CONSTANT_FALSE || CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !CONSTANT_FALSE && CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + + if CONSTANT_FALSE || !CONSTANT_TRUE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if CONSTANT_FALSE && !CONSTANT_TRUE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !(CONSTANT_FALSE || CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(CONSTANT_FALSE && CONSTANT_TRUE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_const_true_const_false :: proc(t: ^testing.T) { + if CONSTANT_TRUE || CONSTANT_FALSE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_TRUE && CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !CONSTANT_TRUE || CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !CONSTANT_TRUE && CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if CONSTANT_TRUE || !CONSTANT_FALSE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_TRUE && !CONSTANT_FALSE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + + if !(CONSTANT_TRUE || CONSTANT_FALSE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(CONSTANT_TRUE && CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_const_true_const_true :: proc(t: ^testing.T) { + if CONSTANT_TRUE || CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_TRUE && CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + + if !CONSTANT_TRUE || CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !CONSTANT_TRUE && CONSTANT_TRUE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if CONSTANT_TRUE || !CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if CONSTANT_TRUE && !CONSTANT_TRUE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !(CONSTANT_TRUE || CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(CONSTANT_TRUE && CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } +} + +@test +test_proc_false_const_false :: proc(t: ^testing.T) { + if false_result() || CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if false_result() && CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !(false_result() || CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if !(false_result() && CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_proc_false_const_true :: proc(t: ^testing.T) { + if false_result() || CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if false_result() && CONSTANT_TRUE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !(false_result() || CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(false_result() && CONSTANT_TRUE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_proc_true_const_false :: proc(t: ^testing.T) { + if true_result() || CONSTANT_FALSE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if true_result() && CONSTANT_FALSE { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + + if !(true_result() || CONSTANT_FALSE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(true_result() && CONSTANT_FALSE) { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } +} + +@test +test_proc_true_const_true :: proc(t: ^testing.T) { + if true_result() || CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + if true_result() && CONSTANT_TRUE { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } else { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } + + if !(true_result() || CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } + if !(true_result() && CONSTANT_TRUE) { + tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + } else { + tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + } +} From a68f0b2d72a3883879da124321868afcdac3b9d6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Mar 2022 22:18:12 +0000 Subject: [PATCH 0413/1052] Improve procedure group selection based on the minimum number of arguments --- src/check_expr.cpp | 79 ++++++++++++++++++++++++++++++++++++---------- src/check_type.cpp | 14 -------- src/checker.cpp | 9 ++++++ src/entity.cpp | 10 ++++++ src/types.cpp | 1 - 5 files changed, 82 insertions(+), 31 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 577f3b07c..b7039fd9a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4872,25 +4872,16 @@ bool is_expr_constant_zero(Ast *expr) { return false; } - -CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { - ast_node(ce, CallExpr, call); - GB_ASSERT(is_type_proc(proc_type)); - proc_type = base_type(proc_type); - TypeProc *pt = &proc_type->Proc; - +isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_) { + GB_ASSERT(pt != nullptr); + GB_ASSERT(pt->kind == Type_Proc); isize param_count = 0; isize param_count_excluding_defaults = 0; - bool variadic = pt->variadic; - bool vari_expand = (ce->ellipsis.pos.line != 0); - i64 score = 0; - bool show_error = show_error_mode == CallArgumentMode_ShowErrors; - - + bool variadic = pt->Proc.variadic; TypeTuple *param_tuple = nullptr; - if (pt->params != nullptr) { - param_tuple = &pt->params->Tuple; + if (pt->Proc.params != nullptr) { + param_tuple = &pt->Proc.params->Tuple; param_count = param_tuple->variables.count; if (variadic) { @@ -4930,6 +4921,31 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { } } + if (param_count_) *param_count_ = param_count; + return param_count_excluding_defaults; +} + + +CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { + ast_node(ce, CallExpr, call); + GB_ASSERT(is_type_proc(proc_type)); + proc_type = base_type(proc_type); + TypeProc *pt = &proc_type->Proc; + + isize param_count = 0; + isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(proc_type, ¶m_count); + bool variadic = pt->variadic; + bool vari_expand = (ce->ellipsis.pos.line != 0); + i64 score = 0; + bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + + + TypeTuple *param_tuple = nullptr; + if (pt->params != nullptr) { + param_tuple = &pt->params->Tuple; + } + + CallArgumentError err = CallArgumentError_None; Type *final_proc_type = proc_type; Entity *gen_entity = nullptr; @@ -5602,7 +5618,37 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type if (operand->mode == Addressing_ProcGroup) { check_entity_decl(c, operand->proc_group, nullptr, nullptr); - Array procs = proc_group_entities(c, *operand); + auto procs = proc_group_entities_cloned(c, *operand); + + if (procs.count > 1) { + isize max_arg_count = args.count; + for_array(i, args) { + // NOTE(bill): The only thing that may have multiple values + // will be a call expression (assuming `or_return` and `()` will be stripped) + Ast *arg = strip_or_return_expr(args[i]); + if (arg && arg->kind == Ast_CallExpr) { + max_arg_count = ISIZE_MAX; + break; + } + } + + for (isize proc_index = 0; proc_index < procs.count; /**/) { + Entity *proc = procs[proc_index]; + Type *pt = base_type(proc->type); + if (!(pt != nullptr && is_type_proc(pt))) { + continue; + } + + isize param_count = 0; + isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(pt, ¶m_count); + + if (param_count_excluding_defaults > max_arg_count) { + array_unordered_remove(&procs, proc_index); + } else { + proc_index++; + } + } + } if (procs.count == 1) { Ast *ident = operand->expr; @@ -5632,6 +5678,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type return data; } + Entity **lhs = nullptr; isize lhs_count = -1; diff --git a/src/check_type.cpp b/src/check_type.cpp index ecb2c26ea..3c7f33a46 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1960,20 +1960,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, if (params) param_count = params ->Tuple.variables.count; if (results) result_count = results->Tuple.variables.count; - if (param_count > 0) { - for_array(i, params->Tuple.variables) { - Entity *param = params->Tuple.variables[i]; - if (param->kind == Entity_Variable) { - ParameterValue pv = param->Variable.param_value; - if (pv.kind == ParameterValue_Constant && - pv.value.kind == ExactValue_Procedure) { - type->Proc.has_proc_default_values = true; - break; - } - } - } - } - if (result_count > 0) { Entity *first = results->Tuple.variables[0]; type->Proc.has_named_results = first->token.string != ""; diff --git a/src/checker.cpp b/src/checker.cpp index ea300afd9..53bba654d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2657,6 +2657,15 @@ Array proc_group_entities(CheckerContext *c, Operand o) { return procs; } +Array proc_group_entities_cloned(CheckerContext *c, Operand o) { + auto entities = proc_group_entities(c, o); + if (entities.count == 0) { + return {}; + } + return array_clone(permanent_allocator(), entities); +} + + void init_core_type_info(Checker *c) { diff --git a/src/entity.cpp b/src/entity.cpp index f5720293f..17fa884e1 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -115,6 +115,16 @@ struct ParameterValue { }; }; +bool has_parameter_value(ParameterValue const ¶m_value) { + if (param_value.kind != ParameterValue_Invalid) { + return true; + } + if (param_value.original_ast_expr != nullptr) { + return true; + } + return false; +} + enum EntityConstantFlags : u32 { EntityConstantFlag_ImplicitEnumValue = 1<<0, }; diff --git a/src/types.cpp b/src/types.cpp index 58ccdf5b9..ef770c846 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -186,7 +186,6 @@ struct TypeProc { bool c_vararg; bool is_polymorphic; bool is_poly_specialized; - bool has_proc_default_values; bool has_named_results; bool diverging; // no return bool return_by_pointer; From ae6441182de5185812b9e5558b08ccaa3a877cdc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Mar 2022 23:32:37 +0000 Subject: [PATCH 0414/1052] Add `core:unicode/utf8/utf8string` to `examples/all` --- core/unicode/utf8/utf8string/string.odin | 120 +++++++++++------------ examples/all/all_main.odin | 2 + 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/core/unicode/utf8/utf8string/string.odin b/core/unicode/utf8/utf8string/string.odin index 23e2eefc6..86267defb 100644 --- a/core/unicode/utf8/utf8string/string.odin +++ b/core/unicode/utf8/utf8string/string.odin @@ -16,140 +16,140 @@ String :: struct { } @(private) -_len :: builtin.len; // helper procedure +_len :: builtin.len // helper procedure init :: proc(s: ^String, contents: string) -> ^String { - s.contents = contents; - s.byte_pos = 0; - s.rune_pos = 0; + s.contents = contents + s.byte_pos = 0 + s.rune_pos = 0 for i in 0..<_len(contents) { if contents[i] >= utf8.RUNE_SELF { - s.rune_count = utf8.rune_count_in_string(contents); - _, s.width = utf8.decode_rune_in_string(contents); - s.non_ascii = i; - return s; + s.rune_count = utf8.rune_count_in_string(contents) + _, s.width = utf8.decode_rune_in_string(contents) + s.non_ascii = i + return s } } - s.rune_count = _len(contents); - s.width = 0; - s.non_ascii = _len(contents); - return s; + s.rune_count = _len(contents) + s.width = 0 + s.non_ascii = _len(contents) + return s } to_string :: proc(s: ^String) -> string { - return s.contents; + return s.contents } len :: proc(s: ^String) -> int { - return s.rune_count; + return s.rune_count } is_ascii :: proc(s: ^String) -> bool { - return s.width == 0; + return s.width == 0 } at :: proc(s: ^String, i: int, loc := #caller_location) -> (r: rune) { - runtime.bounds_check_error_loc(loc, i, s.rune_count); + runtime.bounds_check_error_loc(loc, i, s.rune_count) if i < s.non_ascii { - return rune(s.contents[i]); + return rune(s.contents[i]) } switch i { case 0: - r, s.width = utf8.decode_rune_in_string(s.contents); - s.rune_pos = 0; - s.byte_pos = 0; - return; + r, s.width = utf8.decode_rune_in_string(s.contents) + s.rune_pos = 0 + s.byte_pos = 0 + return case s.rune_count-1: - r, s.width = utf8.decode_rune_in_string(s.contents); - s.rune_pos = i; - s.byte_pos = _len(s.contents) - s.width; - return; + r, s.width = utf8.decode_rune_in_string(s.contents) + s.rune_pos = i + s.byte_pos = _len(s.contents) - s.width + return case s.rune_pos-1: - r, s.width = utf8.decode_rune_in_string(s.contents[0:s.byte_pos]); - s.rune_pos = i; - s.byte_pos -= s.width; - return; + r, s.width = utf8.decode_rune_in_string(s.contents[0:s.byte_pos]) + s.rune_pos = i + s.byte_pos -= s.width + return case s.rune_pos+1: - s.rune_pos = i; - s.byte_pos += s.width; - fallthrough; + s.rune_pos = i + s.byte_pos += s.width + fallthrough case s.rune_pos: - r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]); - return; + r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]) + return } // Linear scan - scan_forward := true; + scan_forward := true if i < s.rune_pos { if i < (s.rune_pos-s.non_ascii)/2 { - s.byte_pos, s.rune_pos = s.non_ascii, s.non_ascii; + s.byte_pos, s.rune_pos = s.non_ascii, s.non_ascii } else { - scan_forward = false; + scan_forward = false } } else if i-s.rune_pos < (s.rune_count-s.rune_pos)/2 { - // scan_forward = true; + // scan_forward = true } else { - s.byte_pos, s.rune_pos = _len(s.contents), s.rune_count; - scan_forward = false; + s.byte_pos, s.rune_pos = _len(s.contents), s.rune_count + scan_forward = false } if scan_forward { for { - r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]); + r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]) if s.rune_pos == i { - return; + return } - s.rune_pos += 1; - s.byte_pos += s.width; + s.rune_pos += 1 + s.byte_pos += s.width } } else { for { - r, s.width = utf8.decode_last_rune_in_string(s.contents[:s.byte_pos]); - s.rune_pos -= 1; - s.byte_pos -= s.width; + r, s.width = utf8.decode_last_rune_in_string(s.contents[:s.byte_pos]) + s.rune_pos -= 1 + s.byte_pos -= s.width if s.rune_pos == i { - return; + return } } } } slice :: proc(s: ^String, i, j: int, loc := #caller_location) -> string { - runtime.slice_expr_error_lo_hi_loc(loc, i, j, s.rune_count); + runtime.slice_expr_error_lo_hi_loc(loc, i, j, s.rune_count) if j < s.non_ascii { - return s.contents[i:j]; + return s.contents[i:j] } if i == j { - return ""; + return "" } - lo, hi: int; + lo, hi: int if i < s.non_ascii { - lo = i; + lo = i } else if i == s.rune_count { - lo = _len(s.contents); + lo = _len(s.contents) } else { - at(s, i, loc); - lo = s.byte_pos; + at(s, i, loc) + lo = s.byte_pos } if j == s.rune_count { - hi = _len(s.contents); + hi = _len(s.contents) } else { - at(s, j, loc); - hi = s.byte_pos; + at(s, j, loc) + hi = s.byte_pos } - return s.contents[lo:hi]; + return s.contents[lo:hi] } diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 7d2082250..dafd29ab3 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -104,6 +104,7 @@ import time "core:time" import unicode "core:unicode" import utf8 "core:unicode/utf8" +import utf8string "core:unicode/utf8/utf8string" import utf16 "core:unicode/utf16" main :: proc(){} @@ -193,4 +194,5 @@ _ :: thread _ :: time _ :: unicode _ :: utf8 +_ :: utf8string _ :: utf16 \ No newline at end of file From 6d354524e28ffe69f0ce769a4d031035784d8b47 Mon Sep 17 00:00:00 2001 From: Lucas Perlind Date: Mon, 21 Mar 2022 21:17:49 +1100 Subject: [PATCH 0415/1052] * Add split_by_byte_iterator. It functions exactly like split_iterator but takes in a byte seperator rather than a string seperator. The intention is to provide a faster split parsing if the seperator is known to be byte size. --- core/strings/strings.odin | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 670da166b..fe25ad3bf 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -339,6 +339,25 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, return } +@private +_split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) { + m := index_byte(s^, sep) + if m < 0 { + // not found + res = s[:] + ok = res != "" + s^ = {} + } else { + res = s[:m] + ok = true + s^ = s[m+1:] + } + return +} + +split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (string, bool) { + return _split_by_byte_iterator(s, sep) +} split_iterator :: proc(s: ^string, sep: string) -> (string, bool) { return _split_iterator(s, sep, 0) From 47e9857eb7efad86b5f300ae3a3d1218a02342cc Mon Sep 17 00:00:00 2001 From: Holger Lindner Date: Mon, 21 Mar 2022 17:20:19 +0100 Subject: [PATCH 0416/1052] Add user32.odin with most basic procedures to core:sys/windows --- core/sys/windows/types.odin | 8 + core/sys/windows/user32.odin | 280 +++++++ core/sys/windows/window_messages.odin | 1047 +++++++++++++++++++++++++ 3 files changed, 1335 insertions(+) create mode 100644 core/sys/windows/user32.odin create mode 100644 core/sys/windows/window_messages.odin diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 1ead165b4..1e6645f0d 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -22,6 +22,10 @@ HMODULE :: distinct HINSTANCE HRESULT :: distinct LONG HWND :: distinct HANDLE HMONITOR :: distinct HANDLE +HICON :: distinct HANDLE +HCURSOR :: distinct HANDLE +HMENU :: distinct HANDLE +HBRUSH :: distinct HANDLE BOOL :: distinct b32 BYTE :: distinct u8 BOOLEAN :: distinct b8 @@ -37,6 +41,7 @@ SIZE_T :: uint PSIZE_T :: ^SIZE_T WORD :: u16 CHAR :: c_char +UINT_PTR :: uint ULONG_PTR :: uint PULONG_PTR :: ^ULONG_PTR LPULONG_PTR :: ^ULONG_PTR @@ -45,6 +50,9 @@ LONG_PTR :: int ULONG :: c_ulong UCHAR :: BYTE NTSTATUS :: c.long +LPARAM :: LONG_PTR +WPARAM :: UINT_PTR +LRESULT :: LONG_PTR UINT8 :: u8 UINT16 :: u16 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin new file mode 100644 index 000000000..1a92002b6 --- /dev/null +++ b/core/sys/windows/user32.odin @@ -0,0 +1,280 @@ +// +build windows +package sys_windows +foreign import user32 "system:User32.lib" + +WNDPROC :: proc "stdcall" (HWND, UINT, WPARAM, LPARAM) -> LRESULT + +CS_VREDRAW : UINT : 0x0001 +CS_HREDRAW : UINT : 0x0002 +CS_DBLCLKS : UINT : 0x0008 +CS_OWNDC : UINT : 0x0020 +CS_CLASSDC : UINT : 0x0040 +CS_PARENTDC : UINT : 0x0080 +CS_NOCLOSE : UINT : 0x0200 +CS_SAVEBITS : UINT : 0x0800 +CS_BYTEALIGNCLIENT : UINT : 0x1000 +CS_BYTEALIGNWINDOW : UINT : 0x2000 +CS_GLOBALCLASS : UINT : 0x4000 +CS_DROPSHADOW : UINT : 0x0002_0000 + +GWL_EXSTYLE : c_int : -20 +GWLP_HINSTANCE : c_int : -6 +GWLP_ID : c_int : -12 +GWL_STYLE : c_int : -16 +GWLP_USERDATA : c_int : -21 +GWLP_WNDPROC : c_int : -4 + +WS_BORDER : UINT : 0x0080_0000 +WS_CAPTION : UINT : 0x00C0_0000 +WS_CHILD : UINT : 0x4000_0000 +WS_CHILDWINDOW : UINT : WS_CHILD +WS_CLIPCHILDREN : UINT : 0x0200_0000 +WS_CLIPSIBLINGS : UINT : 0x0400_0000 +WS_DISABLED : UINT : 0x0800_0000 +WS_DLGFRAME : UINT : 0x0040_0000 +WS_GROUP : UINT : 0x0002_0000 +WS_HSCROLL : UINT : 0x0010_0000 +WS_ICONIC : UINT : 0x2000_0000 +WS_MAXIMIZE : UINT : 0x0100_0000 +WS_MAXIMIZEBOX : UINT : 0x0001_0000 +WS_MINIMIZE : UINT : 0x2000_0000 +WS_MINIMIZEBOX : UINT : 0x0002_0000 +WS_OVERLAPPED : UINT : 0x0000_0000 +WS_OVERLAPPEDWINDOW : UINT : WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX +WS_POPUP : UINT : 0x8000_0000 +WS_POPUPWINDOW : UINT : WS_POPUP | WS_BORDER | WS_SYSMENU +WS_SIZEBOX : UINT : 0x0004_0000 +WS_SYSMENU : UINT : 0x0008_0000 +WS_TABSTOP : UINT : 0x0001_0000 +WS_THICKFRAME : UINT : 0x0004_0000 +WS_TILED : UINT : 0x0000_0000 +WS_TILEDWINDOW : UINT : WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE +WS_VISIBLE : UINT : 0x1000_0000 +WS_VSCROLL : UINT : 0x0020_0000 + +QS_ALLEVENTS : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY +QS_ALLINPUT : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE +QS_ALLPOSTMESSAGE : UINT : 0x0100 +QS_HOTKEY : UINT : 0x0080 +QS_INPUT : UINT : QS_MOUSE | QS_KEY | QS_RAWINPUT +QS_KEY : UINT : 0x0001 +QS_MOUSE : UINT : QS_MOUSEMOVE | QS_MOUSEBUTTON +QS_MOUSEBUTTON : UINT : 0x0004 +QS_MOUSEMOVE : UINT : 0x0002 +QS_PAINT : UINT : 0x0020 +QS_POSTMESSAGE : UINT : 0x0008 +QS_RAWINPUT : UINT : 0x0400 +QS_SENDMESSAGE : UINT : 0x0040 +QS_TIMER : UINT : 0x0010 + +PM_NOREMOVE : UINT : 0x0000 +PM_REMOVE : UINT : 0x0001 +PM_NOYIELD : UINT : 0x0002 + +PM_QS_INPUT : UINT : QS_INPUT << 16 +PM_QS_PAINT : UINT : QS_PAINT << 16 +PM_QS_POSTMESSAGE : UINT : (QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16 +PM_QS_SENDMESSAGE : UINT : QS_SENDMESSAGE << 16 + +SW_HIDE : c_int : 0 +SW_SHOWNORMAL : c_int : SW_NORMAL +SW_NORMAL : c_int : 1 +SW_SHOWMINIMIZED : c_int : 2 +SW_SHOWMAXIMIZED : c_int : SW_MAXIMIZE +SW_MAXIMIZE : c_int : 3 +SW_SHOWNOACTIVATE : c_int : 4 +SW_SHOW : c_int : 5 +SW_MINIMIZE : c_int : 6 +SW_SHOWMINNOACTIVE : c_int : 7 +SW_SHOWNA : c_int : 8 +SW_RESTORE : c_int : 9 +SW_SHOWDEFAULT : c_int : 10 +SW_FORCEMINIMIZE : c_int : 11 + +CW_USEDEFAULT : c_int : -2147483648 + +WNDCLASSA :: struct { + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCSTR, + lpszClassName: LPCSTR, +} + +WNDCLASSW :: struct { + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCWSTR, + lpszClassName: LPCWSTR, +} + +WNDCLASSEXA :: struct { + cbSize: UINT, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCSTR, + lpszClassName: LPCSTR, + hIconSm: HICON, +} + +WNDCLASSEXW :: struct { + cbSize: UINT, + style: UINT, + lpfnWndProc: ^WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCWSTR, + lpszClassName: LPCWSTR, + hIconSm: HICON, +} + +MSG :: struct { + hwnd: HWND, + message: UINT, + wParam: WPARAM, + lParam: LPARAM, + time: DWORD, + pt: POINT, + lPrivate: DWORD, +} + +CREATESTRUCTA :: struct { + lpCreateParams: LPVOID, + hInstance: HINSTANCE, + hMenu: HMENU, + hwndParent: HWND, + cy: c_int, + cx: c_int, + y: c_int, + x: c_int, + style: LONG, + lpszName: LPCSTR, + lpszClass: LPCSTR, + dwExStyle: DWORD, +} + +CREATESTRUCTW:: struct { + lpCreateParams: LPVOID, + hInstance: HINSTANCE, + hMenu: HMENU, + hwndParent: HWND, + cy: c_int, + cx: c_int, + y: c_int, + x: c_int, + style: LONG, + lpszName: LPCWSTR, + lpszClass: LPCWSTR, + dwExStyle: DWORD, +} + +_IDC_APPSTARTING := rawptr(uintptr(32650)) +_IDC_ARROW := rawptr(uintptr(32512)) +_IDC_CROSS := rawptr(uintptr(32515)) +_IDC_HAND := rawptr(uintptr(32649)) +_IDC_HELP := rawptr(uintptr(32651)) +_IDC_IBEAM := rawptr(uintptr(32513)) +_IDC_ICON := rawptr(uintptr(32641)) +_IDC_NO := rawptr(uintptr(32648)) +_IDC_SIZE := rawptr(uintptr(32640)) +_IDC_SIZEALL := rawptr(uintptr(32646)) +_IDC_SIZENESW := rawptr(uintptr(32643)) +_IDC_SIZENS := rawptr(uintptr(32645)) +_IDC_SIZENWSE := rawptr(uintptr(32642)) +_IDC_SIZEWE := rawptr(uintptr(32644)) +_IDC_UPARROW := rawptr(uintptr(32516)) +_IDC_WAIT := rawptr(uintptr(32514)) +IDC_APPSTARTING := cstring(_IDC_APPSTARTING) +IDC_ARROW := cstring(_IDC_ARROW) +IDC_CROSS := cstring(_IDC_CROSS) +IDC_HAND := cstring(_IDC_HAND) +IDC_HELP := cstring(_IDC_HELP) +IDC_IBEAM := cstring(_IDC_IBEAM) +IDC_ICON := cstring(_IDC_ICON) +IDC_NO := cstring(_IDC_NO) +IDC_SIZE := cstring(_IDC_SIZE) +IDC_SIZEALL := cstring(_IDC_SIZEALL) +IDC_SIZENESW := cstring(_IDC_SIZENESW) +IDC_SIZENS := cstring(_IDC_SIZENS) +IDC_SIZENWSE := cstring(_IDC_SIZENWSE) +IDC_SIZEWE := cstring(_IDC_SIZEWE) +IDC_UPARROW := cstring(_IDC_UPARROW) +IDC_WAIT := cstring(_IDC_WAIT) + + +@(default_calling_convention="stdcall") +foreign user32 { + + GetClassInfoA :: proc(hInstance: HINSTANCE, lpClassNAme: LPCSTR, lpWndClass: ^WNDCLASSA) -> BOOL --- + GetClassInfoW :: proc(hInstance: HINSTANCE, lpClassNAme: LPCWSTR, lpWndClass: ^WNDCLASSW) -> BOOL --- + GetClassInfoExA :: proc(hInsatnce: HINSTANCE, lpszClass: LPCSTR, lpwcx: ^WNDCLASSEXA) -> BOOL --- + GetClassInfoExW :: proc(hInsatnce: HINSTANCE, lpszClass: LPCWSTR, lpwcx: ^WNDCLASSEXW) -> BOOL --- + GetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- + GetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- + GetClassNameA :: proc(hWnd: HWND, lpClassName: LPSTR, nMaxCount: c_int) -> c_int --- + GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int --- + GetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- + GetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- + RegisterClassA :: proc(^WNDCLASSA) -> ATOM --- + RegisterClassW :: proc(^WNDCLASSW) -> ATOM --- + RegisterClassExA :: proc(^WNDCLASSEXA) -> ATOM --- + RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- + SetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + SetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + SetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- + SetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- + UnregisterClassA :: proc(lpClassName: LPCSTR, hInstance: HINSTANCE) -> BOOL --- + UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL --- + + CreateWindowA :: proc(lpClassName: LPCSTR, lpWindowName: LPCSTR, dwStyle: DWORD, x: c_int, y: c_int, nWidth: c_int, nHeight: c_int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: LPARAM) -> HWND --- + CreateWindowW :: proc(lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, x: c_int, y: c_int, nWidth: c_int, nHeight: c_int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: LPARAM) -> HWND --- + CreateWindowExA :: proc(dwExStyle: DWORD, lpClassName: LPCSTR, lpWindowName: LPCSTR, dwStyle: DWORD, x: c_int, y: c_int, nWidth: c_int, nHeight: c_int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: LPARAM) -> HWND --- + CreateWindowExW :: proc(dwExStyle: DWORD, lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, x: c_int, y: c_int, nWidth: c_int, nHeight: c_int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: LPARAM) -> HWND --- + + DestroyWindow :: proc(hWnd: HWND) -> BOOL --- + + ShowWindow :: proc(hWnd: HWND, nCmdShow: c_int) -> BOOL --- + + GetMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- + GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- + PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- + PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- + + TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL --- + DispatchMessageA :: proc(lpMsg: ^MSG) -> LRESULT --- + DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT --- + + PostQuitMessage :: proc(nExitCode: c_int) --- + + PostMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + PostMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + + GetQueueStatus :: proc(flags: UINT) -> DWORD --- + + DefWindowProcA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParma: LPARAM) -> LRESULT --- + DefWindowProcW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParma: LPARAM) -> LRESULT --- + + LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- + LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- +} diff --git a/core/sys/windows/window_messages.odin b/core/sys/windows/window_messages.odin new file mode 100644 index 000000000..f52be9bbc --- /dev/null +++ b/core/sys/windows/window_messages.odin @@ -0,0 +1,1047 @@ +package sys_windows + +WM_NULL :: 0x0000 +WM_CREATE :: 0x0001 +WM_DESTROY :: 0x0002 +WM_MOVE :: 0x0003 +WM_SIZE :: 0x0005 +WM_ACTIVATE :: 0x0006 +WM_SETFOCUS :: 0x0007 +WM_KILLFOCUS :: 0x0008 +WM_ENABLE :: 0x000a +WM_SETREDRAW :: 0x000b +WM_SETTEXT :: 0x000c +WM_GETTEXT :: 0x000d +WM_GETTEXTLENGTH :: 0x000e +WM_PAINT :: 0x000f +WM_CLOSE :: 0x0010 +WM_QUERYENDSESSION :: 0x0011 +WM_QUIT :: 0x0012 +WM_QUERYOPEN :: 0x0013 +WM_ERASEBKGND :: 0x0014 +WM_SYSCOLORCHANGE :: 0x0015 +WM_ENDSESSION :: 0x0016 +WM_SHOWWINDOW :: 0x0018 +WM_CTLCOLOR :: 0x0019 +WM_WININICHANGE :: 0x001a +WM_DEVMODECHANGE :: 0x001b +WM_ACTIVATEAPP :: 0x001c +WM_FONTCHANGE :: 0x001d +WM_TIMECHANGE :: 0x001e +WM_CANCELMODE :: 0x001f +WM_SETCURSOR :: 0x0020 +WM_MOUSEACTIVATE :: 0x0021 +WM_CHILDACTIVATE :: 0x0022 +WM_QUEUESYNC :: 0x0023 +WM_GETMINMAXINFO :: 0x0024 +WM_PAINTICON :: 0x0026 +WM_ICONERASEBKGND :: 0x0027 +WM_NEXTDLGCTL :: 0x0028 +WM_SPOOLERSTATUS :: 0x002a +WM_DRAWITEM :: 0x002b +WM_MEASUREITEM :: 0x002c +WM_DELETEITEM :: 0x002d +WM_VKEYTOITEM :: 0x002e +WM_CHARTOITEM :: 0x002f +WM_SETFONT :: 0x0030 +WM_GETFONT :: 0x0031 +WM_SETHOTKEY :: 0x0032 +WM_GETHOTKEY :: 0x0033 +WM_QUERYDRAGICON :: 0x0037 +WM_COMPAREITEM :: 0x0039 +WM_GETOBJECT :: 0x003d +WM_COMPACTING :: 0x0041 +WM_COMMNOTIFY :: 0x0044 +WM_WINDOWPOSCHANGING :: 0x0046 +WM_WINDOWPOSCHANGED :: 0x0047 +WM_POWER :: 0x0048 +WM_COPYGLOBALDATA :: 0x0049 +WM_COPYDATA :: 0x004a +WM_CANCELJOURNAL :: 0x004b +WM_NOTIFY :: 0x004e +WM_INPUTLANGCHANGEREQUEST :: 0x0050 +WM_INPUTLANGCHANGE :: 0x0051 +WM_TCARD :: 0x0052 +WM_HELP :: 0x0053 +WM_USERCHANGED :: 0x0054 +WM_NOTIFYFORMAT :: 0x0055 +WM_CONTEXTMENU :: 0x007b +WM_STYLECHANGING :: 0x007c +WM_STYLECHANGED :: 0x007d +WM_DISPLAYCHANGE :: 0x007e +WM_GETICON :: 0x007f +WM_SETICON :: 0x0080 +WM_NCCREATE :: 0x0081 +WM_NCDESTROY :: 0x0082 +WM_NCCALCSIZE :: 0x0083 +WM_NCHITTEST :: 0x0084 +WM_NCPAINT :: 0x0085 +WM_NCACTIVATE :: 0x0086 +WM_GETDLGCODE :: 0x0087 +WM_SYNCPAINT :: 0x0088 +WM_NCMOUSEMOVE :: 0x00a0 +WM_NCLBUTTONDOWN :: 0x00a1 +WM_NCLBUTTONUP :: 0x00a2 +WM_NCLBUTTONDBLCLK :: 0x00a3 +WM_NCRBUTTONDOWN :: 0x00a4 +WM_NCRBUTTONUP :: 0x00a5 +WM_NCRBUTTONDBLCLK :: 0x00a6 +WM_NCMBUTTONDOWN :: 0x00a7 +WM_NCMBUTTONUP :: 0x00a8 +WM_NCMBUTTONDBLCLK :: 0x00a9 +WM_NCXBUTTONDOWN :: 0x00ab +WM_NCXBUTTONUP :: 0x00ac +WM_NCXBUTTONDBLCLK :: 0x00ad +EM_GETSEL :: 0x00b0 +EM_SETSEL :: 0x00b1 +EM_GETRECT :: 0x00b2 +EM_SETRECT :: 0x00b3 +EM_SETRECTNP :: 0x00b4 +EM_SCROLL :: 0x00b5 +EM_LINESCROLL :: 0x00b6 +EM_SCROLLCARET :: 0x00b7 +EM_GETMODIFY :: 0x00b8 +EM_SETMODIFY :: 0x00b9 +EM_GETLINECOUNT :: 0x00ba +EM_LINEINDEX :: 0x00bb +EM_SETHANDLE :: 0x00bc +EM_GETHANDLE :: 0x00bd +EM_GETTHUMB :: 0x00be +EM_LINELENGTH :: 0x00c1 +EM_REPLACESEL :: 0x00c2 +EM_SETFONT :: 0x00c3 +EM_GETLINE :: 0x00c4 +EM_LIMITTEXT :: 0x00c5 +EM_SETLIMITTEXT :: 0x00c5 +EM_CANUNDO :: 0x00c6 +EM_UNDO :: 0x00c7 +EM_FMTLINES :: 0x00c8 +EM_LINEFROMCHAR :: 0x00c9 +EM_SETWORDBREAK :: 0x00ca +EM_SETTABSTOPS :: 0x00cb +EM_SETPASSWORDCHAR :: 0x00cc +EM_EMPTYUNDOBUFFER :: 0x00cd +EM_GETFIRSTVISIBLELINE :: 0x00ce +EM_SETREADONLY :: 0x00cf +EM_SETWORDBREAKPROC :: 0x00d0 +EM_GETWORDBREAKPROC :: 0x00d1 +EM_GETPASSWORDCHAR :: 0x00d2 +EM_SETMARGINS :: 0x00d3 +EM_GETMARGINS :: 0x00d4 +EM_GETLIMITTEXT :: 0x00d5 +EM_POSFROMCHAR :: 0x00d6 +EM_CHARFROMPOS :: 0x00d7 +EM_SETIMESTATUS :: 0x00d8 +EM_GETIMESTATUS :: 0x00d9 +SBM_SETPOS :: 0x00e0 +SBM_GETPOS :: 0x00e1 +SBM_SETRANGE :: 0x00e2 +SBM_GETRANGE :: 0x00e3 +SBM_ENABLE_ARROWS :: 0x00e4 +SBM_SETRANGEREDRAW :: 0x00e6 +SBM_SETSCROLLINFO :: 0x00e9 +SBM_GETSCROLLINFO :: 0x00ea +SBM_GETSCROLLBARINFO :: 0x00eb +BM_GETCHECK :: 0x00f0 +BM_SETCHECK :: 0x00f1 +BM_GETSTATE :: 0x00f2 +BM_SETSTATE :: 0x00f3 +BM_SETSTYLE :: 0x00f4 +BM_CLICK :: 0x00f5 +BM_GETIMAGE :: 0x00f6 +BM_SETIMAGE :: 0x00f7 +BM_SETDONTCLICK :: 0x00f8 +WM_INPUT :: 0x00ff +WM_KEYDOWN :: 0x0100 +WM_KEYFIRST :: 0x0100 +WM_KEYUP :: 0x0101 +WM_CHAR :: 0x0102 +WM_DEADCHAR :: 0x0103 +WM_SYSKEYDOWN :: 0x0104 +WM_SYSKEYUP :: 0x0105 +WM_SYSCHAR :: 0x0106 +WM_SYSDEADCHAR :: 0x0107 +WM_UNICHAR :: 0x0109 +WM_KEYLAST :: 0x0109 +WM_WNT_CONVERTREQUESTEX :: 0x0109 +WM_CONVERTREQUEST :: 0x010a +WM_CONVERTRESULT :: 0x010b +WM_INTERIM :: 0x010c +WM_IME_STARTCOMPOSITION :: 0x010d +WM_IME_ENDCOMPOSITION :: 0x010e +WM_IME_COMPOSITION :: 0x010f +WM_IME_KEYLAST :: 0x010f +WM_INITDIALOG :: 0x0110 +WM_COMMAND :: 0x0111 +WM_SYSCOMMAND :: 0x0112 +WM_TIMER :: 0x0113 +WM_HSCROLL :: 0x0114 +WM_VSCROLL :: 0x0115 +WM_INITMENU :: 0x0116 +WM_INITMENUPOPUP :: 0x0117 +WM_SYSTIMER :: 0x0118 +WM_MENUSELECT :: 0x011f +WM_MENUCHAR :: 0x0120 +WM_ENTERIDLE :: 0x0121 +WM_MENURBUTTONUP :: 0x0122 +WM_MENUDRAG :: 0x0123 +WM_MENUGETOBJECT :: 0x0124 +WM_UNINITMENUPOPUP :: 0x0125 +WM_MENUCOMMAND :: 0x0126 +WM_CHANGEUISTATE :: 0x0127 +WM_UPDATEUISTATE :: 0x0128 +WM_QUERYUISTATE :: 0x0129 +WM_LBTRACKPOINT :: 0x0131 +WM_CTLCOLORMSGBOX :: 0x0132 +WM_CTLCOLOREDIT :: 0x0133 +WM_CTLCOLORLISTBOX :: 0x0134 +WM_CTLCOLORBTN :: 0x0135 +WM_CTLCOLORDLG :: 0x0136 +WM_CTLCOLORSCROLLBAR :: 0x0137 +WM_CTLCOLORSTATIC :: 0x0138 +CB_GETEDITSEL :: 0x0140 +CB_LIMITTEXT :: 0x0141 +CB_SETEDITSEL :: 0x0142 +CB_ADDSTRING :: 0x0143 +CB_DELETESTRING :: 0x0144 +CB_DIR :: 0x0145 +CB_GETCOUNT :: 0x0146 +CB_GETCURSEL :: 0x0147 +CB_GETLBTEXT :: 0x0148 +CB_GETLBTEXTLEN :: 0x0149 +CB_INSERTSTRING :: 0x014a +CB_RESETCONTENT :: 0x014b +CB_FINDSTRING :: 0x014c +CB_SELECTSTRING :: 0x014d +CB_SETCURSEL :: 0x014e +CB_SHOWDROPDOWN :: 0x014f +CB_GETITEMDATA :: 0x0150 +CB_SETITEMDATA :: 0x0151 +CB_GETDROPPEDCONTROLRECT :: 0x0152 +CB_SETITEMHEIGHT :: 0x0153 +CB_GETITEMHEIGHT :: 0x0154 +CB_SETEXTENDEDUI :: 0x0155 +CB_GETEXTENDEDUI :: 0x0156 +CB_GETDROPPEDSTATE :: 0x0157 +CB_FINDSTRINGEXACT :: 0x0158 +CB_SETLOCALE :: 0x0159 +CB_GETLOCALE :: 0x015a +CB_GETTOPINDEX :: 0x015b +CB_SETTOPINDEX :: 0x015c +CB_GETHORIZONTALEXTENT :: 0x015d +CB_SETHORIZONTALEXTENT :: 0x015e +CB_GETDROPPEDWIDTH :: 0x015f +CB_SETDROPPEDWIDTH :: 0x0160 +CB_INITSTORAGE :: 0x0161 +CB_MULTIPLEADDSTRING :: 0x0163 +CB_GETCOMBOBOXINFO :: 0x0164 +CB_MSGMAX :: 0x0165 +WM_MOUSEFIRST :: 0x0200 +WM_MOUSEMOVE :: 0x0200 +WM_LBUTTONDOWN :: 0x0201 +WM_LBUTTONUP :: 0x0202 +WM_LBUTTONDBLCLK :: 0x0203 +WM_RBUTTONDOWN :: 0x0204 +WM_RBUTTONUP :: 0x0205 +WM_RBUTTONDBLCLK :: 0x0206 +WM_MBUTTONDOWN :: 0x0207 +WM_MBUTTONUP :: 0x0208 +WM_MBUTTONDBLCLK :: 0x0209 +WM_MOUSELAST :: 0x0209 +WM_MOUSEWHEEL :: 0x020a +WM_XBUTTONDOWN :: 0x020b +WM_XBUTTONUP :: 0x020c +WM_XBUTTONDBLCLK :: 0x020d +WM_MOUSEHWHEEL :: 0x020e +WM_PARENTNOTIFY :: 0x0210 +WM_ENTERMENULOOP :: 0x0211 +WM_EXITMENULOOP :: 0x0212 +WM_NEXTMENU :: 0x0213 +WM_SIZING :: 0x0214 +WM_CAPTURECHANGED :: 0x0215 +WM_MOVING :: 0x0216 +WM_POWERBROADCAST :: 0x0218 +WM_DEVICECHANGE :: 0x0219 +WM_MDICREATE :: 0x0220 +WM_MDIDESTROY :: 0x0221 +WM_MDIACTIVATE :: 0x0222 +WM_MDIRESTORE :: 0x0223 +WM_MDINEXT :: 0x0224 +WM_MDIMAXIMIZE :: 0x0225 +WM_MDITILE :: 0x0226 +WM_MDICASCADE :: 0x0227 +WM_MDIICONARRANGE :: 0x0228 +WM_MDIGETACTIVE :: 0x0229 +WM_MDISETMENU :: 0x0230 +WM_ENTERSIZEMOVE :: 0x0231 +WM_EXITSIZEMOVE :: 0x0232 +WM_DROPFILES :: 0x0233 +WM_MDIREFRESHMENU :: 0x0234 +WM_IME_REPORT :: 0x0280 +WM_IME_SETCONTEXT :: 0x0281 +WM_IME_NOTIFY :: 0x0282 +WM_IME_CONTROL :: 0x0283 +WM_IME_COMPOSITIONFULL :: 0x0284 +WM_IME_SELECT :: 0x0285 +WM_IME_CHAR :: 0x0286 +WM_IME_REQUEST :: 0x0288 +WM_IMEKEYDOWN :: 0x0290 +WM_IME_KEYDOWN :: 0x0290 +WM_IMEKEYUP :: 0x0291 +WM_IME_KEYUP :: 0x0291 +WM_NCMOUSEHOVER :: 0x02a0 +WM_MOUSEHOVER :: 0x02a1 +WM_NCMOUSELEAVE :: 0x02a2 +WM_MOUSELEAVE :: 0x02a3 +WM_CUT :: 0x0300 +WM_COPY :: 0x0301 +WM_PASTE :: 0x0302 +WM_CLEAR :: 0x0303 +WM_UNDO :: 0x0304 +WM_RENDERFORMAT :: 0x0305 +WM_RENDERALLFORMATS :: 0x0306 +WM_DESTROYCLIPBOARD :: 0x0307 +WM_DRAWCLIPBOARD :: 0x0308 +WM_PAINTCLIPBOARD :: 0x0309 +WM_VSCROLLCLIPBOARD :: 0x030a +WM_SIZECLIPBOARD :: 0x030b +WM_ASKCBFORMATNAME :: 0x030c +WM_CHANGECBCHAIN :: 0x030d +WM_HSCROLLCLIPBOARD :: 0x030e +WM_QUERYNEWPALETTE :: 0x030f +WM_PALETTEISCHANGING :: 0x0310 +WM_PALETTECHANGED :: 0x0311 +WM_HOTKEY :: 0x0312 +WM_PRINT :: 0x0317 +WM_PRINTCLIENT :: 0x0318 +WM_APPCOMMAND :: 0x0319 +WM_HANDHELDFIRST :: 0x0358 +WM_HANDHELDLAST :: 0x035f +WM_AFXFIRST :: 0x0360 +WM_AFXLAST :: 0x037f +WM_PENWINFIRST :: 0x0380 +WM_RCRESULT :: 0x0381 +WM_HOOKRCRESULT :: 0x0382 +WM_GLOBALRCCHANGE :: 0x0383 +WM_PENMISCINFO :: 0x0383 +WM_SKB :: 0x0384 +WM_HEDITCTL :: 0x0385 +WM_PENCTL :: 0x0385 +WM_PENMISC :: 0x0386 +WM_CTLINIT :: 0x0387 +WM_PENEVENT :: 0x0388 +WM_PENWINLAST :: 0x038f +DDM_SETFMT :: 0x0400 +DM_GETDEFID :: 0x0400 +NIN_SELECT :: 0x0400 +TBM_GETPOS :: 0x0400 +WM_PSD_PAGESETUPDLG :: 0x0400 +WM_USER :: 0x0400 +CBEM_INSERTITEMA :: 0x0401 +DDM_DRAW :: 0x0401 +DM_SETDEFID :: 0x0401 +HKM_SETHOTKEY :: 0x0401 +PBM_SETRANGE :: 0x0401 +RB_INSERTBANDA :: 0x0401 +SB_SETTEXTA :: 0x0401 +TB_ENABLEBUTTON :: 0x0401 +TBM_GETRANGEMIN :: 0x0401 +TTM_ACTIVATE :: 0x0401 +WM_CHOOSEFONT_GETLOGFONT :: 0x0401 +WM_PSD_FULLPAGERECT :: 0x0401 +CBEM_SETIMAGELIST :: 0x0402 +DDM_CLOSE :: 0x0402 +DM_REPOSITION :: 0x0402 +HKM_GETHOTKEY :: 0x0402 +PBM_SETPOS :: 0x0402 +RB_DELETEBAND :: 0x0402 +SB_GETTEXTA :: 0x0402 +TB_CHECKBUTTON :: 0x0402 +TBM_GETRANGEMAX :: 0x0402 +WM_PSD_MINMARGINRECT :: 0x0402 +CBEM_GETIMAGELIST :: 0x0403 +DDM_BEGIN :: 0x0403 +HKM_SETRULES :: 0x0403 +PBM_DELTAPOS :: 0x0403 +RB_GETBARINFO :: 0x0403 +SB_GETTEXTLENGTHA :: 0x0403 +TBM_GETTIC :: 0x0403 +TB_PRESSBUTTON :: 0x0403 +TTM_SETDELAYTIME :: 0x0403 +WM_PSD_MARGINRECT :: 0x0403 +CBEM_GETITEMA :: 0x0404 +DDM_END :: 0x0404 +PBM_SETSTEP :: 0x0404 +RB_SETBARINFO :: 0x0404 +SB_SETPARTS :: 0x0404 +TB_HIDEBUTTON :: 0x0404 +TBM_SETTIC :: 0x0404 +TTM_ADDTOOLA :: 0x0404 +WM_PSD_GREEKTEXTRECT :: 0x0404 +CBEM_SETITEMA :: 0x0405 +PBM_STEPIT :: 0x0405 +TB_INDETERMINATE :: 0x0405 +TBM_SETPOS :: 0x0405 +TTM_DELTOOLA :: 0x0405 +WM_PSD_ENVSTAMPRECT :: 0x0405 +CBEM_GETCOMBOCONTROL :: 0x0406 +PBM_SETRANGE32 :: 0x0406 +RB_SETBANDINFOA :: 0x0406 +SB_GETPARTS :: 0x0406 +TB_MARKBUTTON :: 0x0406 +TBM_SETRANGE :: 0x0406 +TTM_NEWTOOLRECTA :: 0x0406 +WM_PSD_YAFULLPAGERECT :: 0x0406 +CBEM_GETEDITCONTROL :: 0x0407 +PBM_GETRANGE :: 0x0407 +RB_SETPARENT :: 0x0407 +SB_GETBORDERS :: 0x0407 +TBM_SETRANGEMIN :: 0x0407 +TTM_RELAYEVENT :: 0x0407 +CBEM_SETEXSTYLE :: 0x0408 +PBM_GETPOS :: 0x0408 +RB_HITTEST :: 0x0408 +SB_SETMINHEIGHT :: 0x0408 +TBM_SETRANGEMAX :: 0x0408 +TTM_GETTOOLINFOA :: 0x0408 +CBEM_GETEXSTYLE :: 0x0409 +CBEM_GETEXTENDEDSTYLE :: 0x0409 +PBM_SETBARCOLOR :: 0x0409 +RB_GETRECT :: 0x0409 +SB_SIMPLE :: 0x0409 +TB_ISBUTTONENABLED :: 0x0409 +TBM_CLEARTICS :: 0x0409 +TTM_SETTOOLINFOA :: 0x0409 +CBEM_HASEDITCHANGED :: 0x040a +RB_INSERTBANDW :: 0x040a +SB_GETRECT :: 0x040a +TB_ISBUTTONCHECKED :: 0x040a +TBM_SETSEL :: 0x040a +TTM_HITTESTA :: 0x040a +WIZ_QUERYNUMPAGES :: 0x040a +CBEM_INSERTITEMW :: 0x040b +RB_SETBANDINFOW :: 0x040b +SB_SETTEXTW :: 0x040b +TB_ISBUTTONPRESSED :: 0x040b +TBM_SETSELSTART :: 0x040b +TTM_GETTEXTA :: 0x040b +WIZ_NEXT :: 0x040b +CBEM_SETITEMW :: 0x040c +RB_GETBANDCOUNT :: 0x040c +SB_GETTEXTLENGTHW :: 0x040c +TB_ISBUTTONHIDDEN :: 0x040c +TBM_SETSELEND :: 0x040c +TTM_UPDATETIPTEXTA :: 0x040c +WIZ_PREV :: 0x040c +CBEM_GETITEMW :: 0x040d +RB_GETROWCOUNT :: 0x040d +SB_GETTEXTW :: 0x040d +TB_ISBUTTONINDETERMINATE :: 0x040d +TTM_GETTOOLCOUNT :: 0x040d +CBEM_SETEXTENDEDSTYLE :: 0x040e +RB_GETROWHEIGHT :: 0x040e +SB_ISSIMPLE :: 0x040e +TB_ISBUTTONHIGHLIGHTED :: 0x040e +TBM_GETPTICS :: 0x040e +TTM_ENUMTOOLSA :: 0x040e +SB_SETICON :: 0x040f +TBM_GETTICPOS :: 0x040f +TTM_GETCURRENTTOOLA :: 0x040f +RB_IDTOINDEX :: 0x0410 +SB_SETTIPTEXTA :: 0x0410 +TBM_GETNUMTICS :: 0x0410 +TTM_WINDOWFROMPOINT :: 0x0410 +RB_GETTOOLTIPS :: 0x0411 +SB_SETTIPTEXTW :: 0x0411 +TBM_GETSELSTART :: 0x0411 +TB_SETSTATE :: 0x0411 +TTM_TRACKACTIVATE :: 0x0411 +RB_SETTOOLTIPS :: 0x0412 +SB_GETTIPTEXTA :: 0x0412 +TB_GETSTATE :: 0x0412 +TBM_GETSELEND :: 0x0412 +TTM_TRACKPOSITION :: 0x0412 +RB_SETBKCOLOR :: 0x0413 +SB_GETTIPTEXTW :: 0x0413 +TB_ADDBITMAP :: 0x0413 +TBM_CLEARSEL :: 0x0413 +TTM_SETTIPBKCOLOR :: 0x0413 +RB_GETBKCOLOR :: 0x0414 +SB_GETICON :: 0x0414 +TB_ADDBUTTONSA :: 0x0414 +TBM_SETTICFREQ :: 0x0414 +TTM_SETTIPTEXTCOLOR :: 0x0414 +RB_SETTEXTCOLOR :: 0x0415 +TB_INSERTBUTTONA :: 0x0415 +TBM_SETPAGESIZE :: 0x0415 +TTM_GETDELAYTIME :: 0x0415 +RB_GETTEXTCOLOR :: 0x0416 +TB_DELETEBUTTON :: 0x0416 +TBM_GETPAGESIZE :: 0x0416 +TTM_GETTIPBKCOLOR :: 0x0416 +RB_SIZETORECT :: 0x0417 +TB_GETBUTTON :: 0x0417 +TBM_SETLINESIZE :: 0x0417 +TTM_GETTIPTEXTCOLOR :: 0x0417 +RB_BEGINDRAG :: 0x0418 +TB_BUTTONCOUNT :: 0x0418 +TBM_GETLINESIZE :: 0x0418 +TTM_SETMAXTIPWIDTH :: 0x0418 +RB_ENDDRAG :: 0x0419 +TB_COMMANDTOINDEX :: 0x0419 +TBM_GETTHUMBRECT :: 0x0419 +TTM_GETMAXTIPWIDTH :: 0x0419 +RB_DRAGMOVE :: 0x041a +TBM_GETCHANNELRECT :: 0x041a +TB_SAVERESTOREA :: 0x041a +TTM_SETMARGIN :: 0x041a +RB_GETBARHEIGHT :: 0x041b +TB_CUSTOMIZE :: 0x041b +TBM_SETTHUMBLENGTH :: 0x041b +TTM_GETMARGIN :: 0x041b +RB_GETBANDINFOW :: 0x041c +TB_ADDSTRINGA :: 0x041c +TBM_GETTHUMBLENGTH :: 0x041c +TTM_POP :: 0x041c +RB_GETBANDINFOA :: 0x041d +TB_GETITEMRECT :: 0x041d +TBM_SETTOOLTIPS :: 0x041d +TTM_UPDATE :: 0x041d +RB_MINIMIZEBAND :: 0x041e +TB_BUTTONSTRUCTSIZE :: 0x041e +TBM_GETTOOLTIPS :: 0x041e +TTM_GETBUBBLESIZE :: 0x041e +RB_MAXIMIZEBAND :: 0x041f +TBM_SETTIPSIDE :: 0x041f +TB_SETBUTTONSIZE :: 0x041f +TTM_ADJUSTRECT :: 0x041f +TBM_SETBUDDY :: 0x0420 +TB_SETBITMAPSIZE :: 0x0420 +TTM_SETTITLEA :: 0x0420 +MSG_FTS_JUMP_VA :: 0x0421 +TB_AUTOSIZE :: 0x0421 +TBM_GETBUDDY :: 0x0421 +TTM_SETTITLEW :: 0x0421 +RB_GETBANDBORDERS :: 0x0422 +MSG_FTS_JUMP_QWORD :: 0x0423 +RB_SHOWBAND :: 0x0423 +TB_GETTOOLTIPS :: 0x0423 +MSG_REINDEX_REQUEST :: 0x0424 +TB_SETTOOLTIPS :: 0x0424 +MSG_FTS_WHERE_IS_IT :: 0x0425 +RB_SETPALETTE :: 0x0425 +TB_SETPARENT :: 0x0425 +RB_GETPALETTE :: 0x0426 +RB_MOVEBAND :: 0x0427 +TB_SETROWS :: 0x0427 +TB_GETROWS :: 0x0428 +TB_GETBITMAPFLAGS :: 0x0429 +TB_SETCMDID :: 0x042a +RB_PUSHCHEVRON :: 0x042b +TB_CHANGEBITMAP :: 0x042b +TB_GETBITMAP :: 0x042c +MSG_GET_DEFFONT :: 0x042d +TB_GETBUTTONTEXTA :: 0x042d +TB_REPLACEBITMAP :: 0x042e +TB_SETINDENT :: 0x042f +TB_SETIMAGELIST :: 0x0430 +TB_GETIMAGELIST :: 0x0431 +TB_LOADIMAGES :: 0x0432 +EM_CANPASTE :: 0x0432 +TTM_ADDTOOLW :: 0x0432 +EM_DISPLAYBAND :: 0x0433 +TB_GETRECT :: 0x0433 +TTM_DELTOOLW :: 0x0433 +EM_EXGETSEL :: 0x0434 +TB_SETHOTIMAGELIST :: 0x0434 +TTM_NEWTOOLRECTW :: 0x0434 +EM_EXLIMITTEXT :: 0x0435 +TB_GETHOTIMAGELIST :: 0x0435 +TTM_GETTOOLINFOW :: 0x0435 +EM_EXLINEFROMCHAR :: 0x0436 +TB_SETDISABLEDIMAGELIST :: 0x0436 +TTM_SETTOOLINFOW :: 0x0436 +EM_EXSETSEL :: 0x0437 +TB_GETDISABLEDIMAGELIST :: 0x0437 +TTM_HITTESTW :: 0x0437 +EM_FINDTEXT :: 0x0438 +TB_SETSTYLE :: 0x0438 +TTM_GETTEXTW :: 0x0438 +EM_FORMATRANGE :: 0x0439 +TB_GETSTYLE :: 0x0439 +TTM_UPDATETIPTEXTW :: 0x0439 +EM_GETCHARFORMAT :: 0x043a +TB_GETBUTTONSIZE :: 0x043a +TTM_ENUMTOOLSW :: 0x043a +EM_GETEVENTMASK :: 0x043b +TB_SETBUTTONWIDTH :: 0x043b +TTM_GETCURRENTTOOLW :: 0x043b +EM_GETOLEINTERFACE :: 0x043c +TB_SETMAXTEXTROWS :: 0x043c +EM_GETPARAFORMAT :: 0x043d +TB_GETTEXTROWS :: 0x043d +EM_GETSELTEXT :: 0x043e +TB_GETOBJECT :: 0x043e +EM_HIDESELECTION :: 0x043f +TB_GETBUTTONINFOW :: 0x043f +EM_PASTESPECIAL :: 0x0440 +TB_SETBUTTONINFOW :: 0x0440 +EM_REQUESTRESIZE :: 0x0441 +TB_GETBUTTONINFOA :: 0x0441 +EM_SELECTIONTYPE :: 0x0442 +TB_SETBUTTONINFOA :: 0x0442 +EM_SETBKGNDCOLOR :: 0x0443 +TB_INSERTBUTTONW :: 0x0443 +EM_SETCHARFORMAT :: 0x0444 +TB_ADDBUTTONSW :: 0x0444 +EM_SETEVENTMASK :: 0x0445 +TB_HITTEST :: 0x0445 +EM_SETOLECALLBACK :: 0x0446 +TB_SETDRAWTEXTFLAGS :: 0x0446 +EM_SETPARAFORMAT :: 0x0447 +TB_GETHOTITEM :: 0x0447 +EM_SETTARGETDEVICE :: 0x0448 +TB_SETHOTITEM :: 0x0448 +EM_STREAMIN :: 0x0449 +TB_SETANCHORHIGHLIGHT :: 0x0449 +EM_STREAMOUT :: 0x044a +TB_GETANCHORHIGHLIGHT :: 0x044a +EM_GETTEXTRANGE :: 0x044b +TB_GETBUTTONTEXTW :: 0x044b +EM_FINDWORDBREAK :: 0x044c +TB_SAVERESTOREW :: 0x044c +EM_SETOPTIONS :: 0x044d +TB_ADDSTRINGW :: 0x044d +EM_GETOPTIONS :: 0x044e +TB_MAPACCELERATORA :: 0x044e +EM_FINDTEXTEX :: 0x044f +TB_GETINSERTMARK :: 0x044f +EM_GETWORDBREAKPROCEX :: 0x0450 +TB_SETINSERTMARK :: 0x0450 +EM_SETWORDBREAKPROCEX :: 0x0451 +TB_INSERTMARKHITTEST :: 0x0451 +EM_SETUNDOLIMIT :: 0x0452 +TB_MOVEBUTTON :: 0x0452 +TB_GETMAXSIZE :: 0x0453 +EM_REDO :: 0x0454 +TB_SETEXTENDEDSTYLE :: 0x0454 +EM_CANREDO :: 0x0455 +TB_GETEXTENDEDSTYLE :: 0x0455 +EM_GETUNDONAME :: 0x0456 +TB_GETPADDING :: 0x0456 +EM_GETREDONAME :: 0x0457 +TB_SETPADDING :: 0x0457 +EM_STOPGROUPTYPING :: 0x0458 +TB_SETINSERTMARKCOLOR :: 0x0458 +EM_SETTEXTMODE :: 0x0459 +TB_GETINSERTMARKCOLOR :: 0x0459 +EM_GETTEXTMODE :: 0x045a +TB_MAPACCELERATORW :: 0x045a +EM_AUTOURLDETECT :: 0x045b +TB_GETSTRINGW :: 0x045b +EM_GETAUTOURLDETECT :: 0x045c +TB_GETSTRINGA :: 0x045c +EM_SETPALETTE :: 0x045d +EM_GETTEXTEX :: 0x045e +EM_GETTEXTLENGTHEX :: 0x045f +EM_SHOWSCROLLBAR :: 0x0460 +EM_SETTEXTEX :: 0x0461 +TAPI_REPLY :: 0x0463 +ACM_OPENA :: 0x0464 +BFFM_SETSTATUSTEXTA :: 0x0464 +CDM_FIRST :: 0x0464 +CDM_GETSPEC :: 0x0464 +EM_SETPUNCTUATION :: 0x0464 +IPM_CLEARADDRESS :: 0x0464 +WM_CAP_UNICODE_START :: 0x0464 +ACM_PLAY :: 0x0465 +BFFM_ENABLEOK :: 0x0465 +CDM_GETFILEPATH :: 0x0465 +EM_GETPUNCTUATION :: 0x0465 +IPM_SETADDRESS :: 0x0465 +PSM_SETCURSEL :: 0x0465 +UDM_SETRANGE :: 0x0465 +WM_CHOOSEFONT_SETLOGFONT :: 0x0465 +ACM_STOP :: 0x0466 +BFFM_SETSELECTIONA :: 0x0466 +CDM_GETFOLDERPATH :: 0x0466 +EM_SETWORDWRAPMODE :: 0x0466 +IPM_GETADDRESS :: 0x0466 +PSM_REMOVEPAGE :: 0x0466 +UDM_GETRANGE :: 0x0466 +WM_CAP_SET_CALLBACK_ERRORW :: 0x0466 +WM_CHOOSEFONT_SETFLAGS :: 0x0466 +ACM_OPENW :: 0x0467 +BFFM_SETSELECTIONW :: 0x0467 +CDM_GETFOLDERIDLIST :: 0x0467 +EM_GETWORDWRAPMODE :: 0x0467 +IPM_SETRANGE :: 0x0467 +PSM_ADDPAGE :: 0x0467 +UDM_SETPOS :: 0x0467 +WM_CAP_SET_CALLBACK_STATUSW :: 0x0467 +BFFM_SETSTATUSTEXTW :: 0x0468 +CDM_SETCONTROLTEXT :: 0x0468 +EM_SETIMECOLOR :: 0x0468 +IPM_SETFOCUS :: 0x0468 +PSM_CHANGED :: 0x0468 +UDM_GETPOS :: 0x0468 +CDM_HIDECONTROL :: 0x0469 +EM_GETIMECOLOR :: 0x0469 +IPM_ISBLANK :: 0x0469 +PSM_RESTARTWINDOWS :: 0x0469 +UDM_SETBUDDY :: 0x0469 +CDM_SETDEFEXT :: 0x046a +EM_SETIMEOPTIONS :: 0x046a +PSM_REBOOTSYSTEM :: 0x046a +UDM_GETBUDDY :: 0x046a +EM_GETIMEOPTIONS :: 0x046b +PSM_CANCELTOCLOSE :: 0x046b +UDM_SETACCEL :: 0x046b +EM_CONVPOSITION :: 0x046c +PSM_QUERYSIBLINGS :: 0x046c +UDM_GETACCEL :: 0x046c +MCIWNDM_GETZOOM :: 0x046d +PSM_UNCHANGED :: 0x046d +UDM_SETBASE :: 0x046d +PSM_APPLY :: 0x046e +UDM_GETBASE :: 0x046e +PSM_SETTITLEA :: 0x046f +UDM_SETRANGE32 :: 0x046f +PSM_SETWIZBUTTONS :: 0x0470 +UDM_GETRANGE32 :: 0x0470 +WM_CAP_DRIVER_GET_NAMEW :: 0x0470 +PSM_PRESSBUTTON :: 0x0471 +UDM_SETPOS32 :: 0x0471 +WM_CAP_DRIVER_GET_VERSIONW :: 0x0471 +PSM_SETCURSELID :: 0x0472 +UDM_GETPOS32 :: 0x0472 +PSM_SETFINISHTEXTA :: 0x0473 +PSM_GETTABCONTROL :: 0x0474 +PSM_ISDIALOGMESSAGE :: 0x0475 +MCIWNDM_REALIZE :: 0x0476 +PSM_GETCURRENTPAGEHWND :: 0x0476 +MCIWNDM_SETTIMEFORMATA :: 0x0477 +PSM_INSERTPAGE :: 0x0477 +EM_SETLANGOPTIONS :: 0x0478 +MCIWNDM_GETTIMEFORMATA :: 0x0478 +PSM_SETTITLEW :: 0x0478 +WM_CAP_FILE_SET_CAPTURE_FILEW :: 0x0478 +EM_GETLANGOPTIONS :: 0x0479 +MCIWNDM_VALIDATEMEDIA :: 0x0479 +PSM_SETFINISHTEXTW :: 0x0479 +WM_CAP_FILE_GET_CAPTURE_FILEW :: 0x0479 +EM_GETIMECOMPMODE :: 0x047a +EM_FINDTEXTW :: 0x047b +MCIWNDM_PLAYTO :: 0x047b +WM_CAP_FILE_SAVEASW :: 0x047b +EM_FINDTEXTEXW :: 0x047c +MCIWNDM_GETFILENAMEA :: 0x047c +EM_RECONVERSION :: 0x047d +MCIWNDM_GETDEVICEA :: 0x047d +PSM_SETHEADERTITLEA :: 0x047d +WM_CAP_FILE_SAVEDIBW :: 0x047d +EM_SETIMEMODEBIAS :: 0x047e +MCIWNDM_GETPALETTE :: 0x047e +PSM_SETHEADERTITLEW :: 0x047e +EM_GETIMEMODEBIAS :: 0x047f +MCIWNDM_SETPALETTE :: 0x047f +PSM_SETHEADERSUBTITLEA :: 0x047f +MCIWNDM_GETERRORA :: 0x0480 +PSM_SETHEADERSUBTITLEW :: 0x0480 +PSM_HWNDTOINDEX :: 0x0481 +PSM_INDEXTOHWND :: 0x0482 +MCIWNDM_SETINACTIVETIMER :: 0x0483 +PSM_PAGETOINDEX :: 0x0483 +PSM_INDEXTOPAGE :: 0x0484 +DL_BEGINDRAG :: 0x0485 +MCIWNDM_GETINACTIVETIMER :: 0x0485 +PSM_IDTOINDEX :: 0x0485 +DL_DRAGGING :: 0x0486 +PSM_INDEXTOID :: 0x0486 +DL_DROPPED :: 0x0487 +PSM_GETRESULT :: 0x0487 +DL_CANCELDRAG :: 0x0488 +PSM_RECALCPAGESIZES :: 0x0488 +MCIWNDM_GET_SOURCE :: 0x048c +MCIWNDM_PUT_SOURCE :: 0x048d +MCIWNDM_GET_DEST :: 0x048e +MCIWNDM_PUT_DEST :: 0x048f +MCIWNDM_CAN_PLAY :: 0x0490 +MCIWNDM_CAN_WINDOW :: 0x0491 +MCIWNDM_CAN_RECORD :: 0x0492 +MCIWNDM_CAN_SAVE :: 0x0493 +MCIWNDM_CAN_EJECT :: 0x0494 +MCIWNDM_CAN_CONFIG :: 0x0495 +IE_GETINK :: 0x0496 +IE_MSGFIRST :: 0x0496 +MCIWNDM_PALETTEKICK :: 0x0496 +IE_SETINK :: 0x0497 +IE_GETPENTIP :: 0x0498 +IE_SETPENTIP :: 0x0499 +IE_GETERASERTIP :: 0x049a +IE_SETERASERTIP :: 0x049b +IE_GETBKGND :: 0x049c +IE_SETBKGND :: 0x049d +IE_GETGRIDORIGIN :: 0x049e +IE_SETGRIDORIGIN :: 0x049f +IE_GETGRIDPEN :: 0x04a0 +IE_SETGRIDPEN :: 0x04a1 +IE_GETGRIDSIZE :: 0x04a2 +IE_SETGRIDSIZE :: 0x04a3 +IE_GETMODE :: 0x04a4 +IE_SETMODE :: 0x04a5 +IE_GETINKRECT :: 0x04a6 +WM_CAP_SET_MCI_DEVICEW :: 0x04a6 +WM_CAP_GET_MCI_DEVICEW :: 0x04a7 +WM_CAP_PAL_OPENW :: 0x04b4 +WM_CAP_PAL_SAVEW :: 0x04b5 +IE_GETAPPDATA :: 0x04b8 +IE_SETAPPDATA :: 0x04b9 +IE_GETDRAWOPTS :: 0x04ba +IE_SETDRAWOPTS :: 0x04bb +IE_GETFORMAT :: 0x04bc +IE_SETFORMAT :: 0x04bd +IE_GETINKINPUT :: 0x04be +IE_SETINKINPUT :: 0x04bf +IE_GETNOTIFY :: 0x04c0 +IE_SETNOTIFY :: 0x04c1 +IE_GETRECOG :: 0x04c2 +IE_SETRECOG :: 0x04c3 +IE_GETSECURITY :: 0x04c4 +IE_SETSECURITY :: 0x04c5 +IE_GETSEL :: 0x04c6 +IE_SETSEL :: 0x04c7 +CDM_LAST :: 0x04c8 +EM_SETBIDIOPTIONS :: 0x04c8 +IE_DOCOMMAND :: 0x04c8 +MCIWNDM_NOTIFYMODE :: 0x04c8 +EM_GETBIDIOPTIONS :: 0x04c9 +IE_GETCOMMAND :: 0x04c9 +EM_SETTYPOGRAPHYOPTIONS :: 0x04ca +IE_GETCOUNT :: 0x04ca +EM_GETTYPOGRAPHYOPTIONS :: 0x04cb +IE_GETGESTURE :: 0x04cb +MCIWNDM_NOTIFYMEDIA :: 0x04cb +EM_SETEDITSTYLE :: 0x04cc +IE_GETMENU :: 0x04cc +EM_GETEDITSTYLE :: 0x04cd +IE_GETPAINTDC :: 0x04cd +MCIWNDM_NOTIFYERROR :: 0x04cd +IE_GETPDEVENT :: 0x04ce +IE_GETSELCOUNT :: 0x04cf +IE_GETSELITEMS :: 0x04d0 +IE_GETSTYLE :: 0x04d1 +MCIWNDM_SETTIMEFORMATW :: 0x04db +EM_OUTLINE :: 0x04dc +MCIWNDM_GETTIMEFORMATW :: 0x04dc +EM_GETSCROLLPOS :: 0x04dd +EM_SETSCROLLPOS :: 0x04de +EM_SETFONTSIZE :: 0x04df +EM_GETZOOM :: 0x04e0 +MCIWNDM_GETFILENAMEW :: 0x04e0 +EM_SETZOOM :: 0x04e1 +MCIWNDM_GETDEVICEW :: 0x04e1 +EM_GETVIEWKIND :: 0x04e2 +EM_SETVIEWKIND :: 0x04e3 +EM_GETPAGE :: 0x04e4 +MCIWNDM_GETERRORW :: 0x04e4 +EM_SETPAGE :: 0x04e5 +EM_GETHYPHENATEINFO :: 0x04e6 +EM_SETHYPHENATEINFO :: 0x04e7 +EM_GETPAGEROTATE :: 0x04eb +EM_SETPAGEROTATE :: 0x04ec +EM_GETCTFMODEBIAS :: 0x04ed +EM_SETCTFMODEBIAS :: 0x04ee +EM_GETCTFOPENSTATUS :: 0x04f0 +EM_SETCTFOPENSTATUS :: 0x04f1 +EM_GETIMECOMPTEXT :: 0x04f2 +EM_ISIME :: 0x04f3 +EM_GETIMEPROPERTY :: 0x04f4 +EM_GETQUERYRTFOBJ :: 0x050d +EM_SETQUERYRTFOBJ :: 0x050e +FM_GETFOCUS :: 0x0600 +FM_GETDRIVEINFOA :: 0x0601 +FM_GETSELCOUNT :: 0x0602 +FM_GETSELCOUNTLFN :: 0x0603 +FM_GETFILESELA :: 0x0604 +FM_GETFILESELLFNA :: 0x0605 +FM_REFRESH_WINDOWS :: 0x0606 +FM_RELOAD_EXTENSIONS :: 0x0607 +FM_GETDRIVEINFOW :: 0x0611 +FM_GETFILESELW :: 0x0614 +FM_GETFILESELLFNW :: 0x0615 +WLX_WM_SAS :: 0x0659 +SM_GETSELCOUNT :: 0x07e8 +UM_GETSELCOUNT :: 0x07e8 +WM_CPL_LAUNCH :: 0x07e8 +SM_GETSERVERSELA :: 0x07e9 +UM_GETUSERSELA :: 0x07e9 +WM_CPL_LAUNCHED :: 0x07e9 +SM_GETSERVERSELW :: 0x07ea +UM_GETUSERSELW :: 0x07ea +SM_GETCURFOCUSA :: 0x07eb +UM_GETGROUPSELA :: 0x07eb +SM_GETCURFOCUSW :: 0x07ec +UM_GETGROUPSELW :: 0x07ec +SM_GETOPTIONS :: 0x07ed +UM_GETCURFOCUSA :: 0x07ed +UM_GETCURFOCUSW :: 0x07ee +UM_GETOPTIONS :: 0x07ef +UM_GETOPTIONS2 :: 0x07f0 +LVM_FIRST :: 0x1000 +LVM_GETBKCOLOR :: 0x1000 +LVM_SETBKCOLOR :: 0x1001 +LVM_GETIMAGELIST :: 0x1002 +LVM_SETIMAGELIST :: 0x1003 +LVM_GETITEMCOUNT :: 0x1004 +LVM_GETITEMA :: 0x1005 +LVM_SETITEMA :: 0x1006 +LVM_INSERTITEMA :: 0x1007 +LVM_DELETEITEM :: 0x1008 +LVM_DELETEALLITEMS :: 0x1009 +LVM_GETCALLBACKMASK :: 0x100a +LVM_SETCALLBACKMASK :: 0x100b +LVM_GETNEXTITEM :: 0x100c +LVM_FINDITEMA :: 0x100d +LVM_GETITEMRECT :: 0x100e +LVM_SETITEMPOSITION :: 0x100f +LVM_GETITEMPOSITION :: 0x1010 +LVM_GETSTRINGWIDTHA :: 0x1011 +LVM_HITTEST :: 0x1012 +LVM_ENSUREVISIBLE :: 0x1013 +LVM_SCROLL :: 0x1014 +LVM_REDRAWITEMS :: 0x1015 +LVM_ARRANGE :: 0x1016 +LVM_EDITLABELA :: 0x1017 +LVM_GETEDITCONTROL :: 0x1018 +LVM_GETCOLUMNA :: 0x1019 +LVM_SETCOLUMNA :: 0x101a +LVM_INSERTCOLUMNA :: 0x101b +LVM_DELETECOLUMN :: 0x101c +LVM_GETCOLUMNWIDTH :: 0x101d +LVM_SETCOLUMNWIDTH :: 0x101e +LVM_GETHEADER :: 0x101f +LVM_CREATEDRAGIMAGE :: 0x1021 +LVM_GETVIEWRECT :: 0x1022 +LVM_GETTEXTCOLOR :: 0x1023 +LVM_SETTEXTCOLOR :: 0x1024 +LVM_GETTEXTBKCOLOR :: 0x1025 +LVM_SETTEXTBKCOLOR :: 0x1026 +LVM_GETTOPINDEX :: 0x1027 +LVM_GETCOUNTPERPAGE :: 0x1028 +LVM_GETORIGIN :: 0x1029 +LVM_UPDATE :: 0x102a +LVM_SETITEMSTATE :: 0x102b +LVM_GETITEMSTATE :: 0x102c +LVM_GETITEMTEXTA :: 0x102d +LVM_SETITEMTEXTA :: 0x102e +LVM_SETITEMCOUNT :: 0x102f +LVM_SORTITEMS :: 0x1030 +LVM_SETITEMPOSITION32 :: 0x1031 +LVM_GETSELECTEDCOUNT :: 0x1032 +LVM_GETITEMSPACING :: 0x1033 +LVM_GETISEARCHSTRINGA :: 0x1034 +LVM_SETICONSPACING :: 0x1035 +LVM_SETEXTENDEDLISTVIEWSTYLE :: 0x1036 +LVM_GETEXTENDEDLISTVIEWSTYLE :: 0x1037 +LVM_GETSUBITEMRECT :: 0x1038 +LVM_SUBITEMHITTEST :: 0x1039 +LVM_SETCOLUMNORDERARRAY :: 0x103a +LVM_GETCOLUMNORDERARRAY :: 0x103b +LVM_SETHOTITEM :: 0x103c +LVM_GETHOTITEM :: 0x103d +LVM_SETHOTCURSOR :: 0x103e +LVM_GETHOTCURSOR :: 0x103f +LVM_APPROXIMATEVIEWRECT :: 0x1040 +LVM_SETWORKAREAS :: 0x1041 +LVM_GETSELECTIONMARK :: 0x1042 +LVM_SETSELECTIONMARK :: 0x1043 +LVM_SETBKIMAGEA :: 0x1044 +LVM_GETBKIMAGEA :: 0x1045 +LVM_GETWORKAREAS :: 0x1046 +LVM_SETHOVERTIME :: 0x1047 +LVM_GETHOVERTIME :: 0x1048 +LVM_GETNUMBEROFWORKAREAS :: 0x1049 +LVM_SETTOOLTIPS :: 0x104a +LVM_GETITEMW :: 0x104b +LVM_SETITEMW :: 0x104c +LVM_INSERTITEMW :: 0x104d +LVM_GETTOOLTIPS :: 0x104e +LVM_FINDITEMW :: 0x1053 +LVM_GETSTRINGWIDTHW :: 0x1057 +LVM_GETCOLUMNW :: 0x105f +LVM_SETCOLUMNW :: 0x1060 +LVM_INSERTCOLUMNW :: 0x1061 +LVM_GETITEMTEXTW :: 0x1073 +LVM_SETITEMTEXTW :: 0x1074 +LVM_GETISEARCHSTRINGW :: 0x1075 +LVM_EDITLABELW :: 0x1076 +LVM_GETBKIMAGEW :: 0x108b +LVM_SETSELECTEDCOLUMN :: 0x108c +LVM_SETTILEWIDTH :: 0x108d +LVM_SETVIEW :: 0x108e +LVM_GETVIEW :: 0x108f +LVM_INSERTGROUP :: 0x1091 +LVM_SETGROUPINFO :: 0x1093 +LVM_GETGROUPINFO :: 0x1095 +LVM_REMOVEGROUP :: 0x1096 +LVM_MOVEGROUP :: 0x1097 +LVM_MOVEITEMTOGROUP :: 0x109a +LVM_SETGROUPMETRICS :: 0x109b +LVM_GETGROUPMETRICS :: 0x109c +LVM_ENABLEGROUPVIEW :: 0x109d +LVM_SORTGROUPS :: 0x109e +LVM_INSERTGROUPSORTED :: 0x109f +LVM_REMOVEALLGROUPS :: 0x10a0 +LVM_HASGROUP :: 0x10a1 +LVM_SETTILEVIEWINFO :: 0x10a2 +LVM_GETTILEVIEWINFO :: 0x10a3 +LVM_SETTILEINFO :: 0x10a4 +LVM_GETTILEINFO :: 0x10a5 +LVM_SETINSERTMARK :: 0x10a6 +LVM_GETINSERTMARK :: 0x10a7 +LVM_INSERTMARKHITTEST :: 0x10a8 +LVM_GETINSERTMARKRECT :: 0x10a9 +LVM_SETINSERTMARKCOLOR :: 0x10aa +LVM_GETINSERTMARKCOLOR :: 0x10ab +LVM_SETINFOTIP :: 0x10ad +LVM_GETSELECTEDCOLUMN :: 0x10ae +LVM_ISGROUPVIEWENABLED :: 0x10af +LVM_GETOUTLINECOLOR :: 0x10b0 +LVM_SETOUTLINECOLOR :: 0x10b1 +LVM_CANCELEDITLABEL :: 0x10b3 +LVM_MAPINDEXTOID :: 0x10b4 +LVM_MAPIDTOINDEX :: 0x10b5 +LVM_ISITEMVISIBLE :: 0x10b6 +LVM_GETEMPTYTEXT :: 0x10cc +LVM_GETFOOTERRECT :: 0x10cd +LVM_GETFOOTERINFO :: 0x10ce +LVM_GETFOOTERITEMRECT :: 0x10cf +LVM_GETFOOTERITEM :: 0x10d0 +LVM_GETITEMINDEXRECT :: 0x10d1 +LVM_SETITEMINDEXSTATE :: 0x10d2 +LVM_GETNEXTITEMINDEX :: 0x10d3 +OCM__BASE :: 0x2000 +LVM_SETUNICODEFORMAT :: 0x2005 +LVM_GETUNICODEFORMAT :: 0x2006 +OCM_CTLCOLOR :: 0x2019 +OCM_DRAWITEM :: 0x202b +OCM_MEASUREITEM :: 0x202c +OCM_DELETEITEM :: 0x202d +OCM_VKEYTOITEM :: 0x202e +OCM_CHARTOITEM :: 0x202f +OCM_COMPAREITEM :: 0x2039 +OCM_NOTIFY :: 0x204e +OCM_COMMAND :: 0x2111 +OCM_HSCROLL :: 0x2114 +OCM_VSCROLL :: 0x2115 +OCM_CTLCOLORMSGBOX :: 0x2132 +OCM_CTLCOLOREDIT :: 0x2133 +OCM_CTLCOLORLISTBOX :: 0x2134 +OCM_CTLCOLORBTN :: 0x2135 +OCM_CTLCOLORDLG :: 0x2136 +OCM_CTLCOLORSCROLLBAR :: 0x2137 +OCM_CTLCOLORSTATIC :: 0x2138 +OCM_PARENTNOTIFY :: 0x2210 +WM_APP :: 0x8000 +WM_RASDIALEVENT :: 0xcccd \ No newline at end of file From e48c0eee74b477d64d4c759f800906b95a6fc8f3 Mon Sep 17 00:00:00 2001 From: hikari Date: Mon, 21 Mar 2022 18:38:52 +0200 Subject: [PATCH 0417/1052] sys/windows: added rudimentary User32.lib bindings --- core/sys/windows/types.odin | 146 ++++++++++++++++++++++++++++------- core/sys/windows/user32.odin | 82 ++++++++++++++++++++ 2 files changed, 198 insertions(+), 30 deletions(-) create mode 100644 core/sys/windows/user32.odin diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 1ead165b4..ca740b4b9 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -21,7 +21,15 @@ HINSTANCE :: HANDLE HMODULE :: distinct HINSTANCE HRESULT :: distinct LONG HWND :: distinct HANDLE +HDC :: distinct HANDLE HMONITOR :: distinct HANDLE +HICON :: distinct HANDLE +HCURSOR :: distinct HANDLE +HMENU :: distinct HANDLE +HBRUSH :: distinct HANDLE +WPARAM :: distinct UINT_PTR +LPARAM :: distinct LONG_PTR +LRESULT :: distinct LONG_PTR BOOL :: distinct b32 BYTE :: distinct u8 BOOLEAN :: distinct b8 @@ -42,6 +50,7 @@ PULONG_PTR :: ^ULONG_PTR LPULONG_PTR :: ^ULONG_PTR DWORD_PTR :: ULONG_PTR LONG_PTR :: int +UINT_PTR :: uintptr ULONG :: c_ulong UCHAR :: BYTE NTSTATUS :: c.long @@ -178,6 +187,83 @@ GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0 GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1 +WNDPROC :: #type proc "stdcall" (HWND, UINT, WPARAM, LPARAM) -> LRESULT + +WNDCLASSA :: struct { + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCSTR, + lpszClassName: LPCSTR, +} + +WNDCLASSW :: struct { + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCWSTR, + lpszClassName: LPCWSTR, +} + +WNDCLASSEXA :: struct { + cbSize: UINT, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCSTR, + lpszClassName: LPCSTR, + hIconSm: HICON, +} + +WNDCLASSEXW :: struct { + cbSize: UINT, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCWSTR, + lpszClassName: LPCWSTR, + hIconSm: HICON, +} + +MSG :: struct { + hwnd: HWND, + message: UINT, + wParam: WPARAM, + lParam: LPARAM, + time: DWORD, + pt: POINT, +} + +PAINTSTRUCT :: struct { + hdc: HDC, + fErase: BOOL, + rcPaint: RECT, + fRestore: BOOL, + fIncUpdate: BOOL, + rgbReserved: [32]BYTE, +} + + WIN32_FIND_DATAW :: struct { dwFileAttributes: DWORD, ftCreationTime: FILETIME, @@ -784,17 +870,17 @@ SYSTEM_INFO :: struct { // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw OSVERSIONINFOEXW :: struct { - dwOSVersionInfoSize: ULONG, - dwMajorVersion: ULONG, - dwMinorVersion: ULONG, - dwBuildNumber: ULONG, - dwPlatformId: ULONG, - szCSDVersion: [128]WCHAR, - wServicePackMajor: USHORT, - wServicePackMinor: USHORT, - wSuiteMask: USHORT, - wProductType: UCHAR, - wReserved: UCHAR, + dwOSVersionInfoSize: ULONG, + dwMajorVersion: ULONG, + dwMinorVersion: ULONG, + dwBuildNumber: ULONG, + dwPlatformId: ULONG, + szCSDVersion: [128]WCHAR, + wServicePackMajor: USHORT, + wServicePackMinor: USHORT, + wSuiteMask: USHORT, + wProductType: UCHAR, + wReserved: UCHAR, } // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-quota_limits @@ -837,24 +923,24 @@ PROFILEINFOW :: struct { lpDefaultPath: LPWSTR, lpServerName: LPWSTR, lpPolicyPath: LPWSTR, - hProfile: HANDLE, + hProfile: HANDLE, } // Used in LookupAccountNameW SID_NAME_USE :: distinct DWORD SID_TYPE :: enum SID_NAME_USE { - User = 1, - Group, - Domain, - Alias, - WellKnownGroup, - DeletedAccount, - Invalid, - Unknown, - Computer, - Label, - LogonSession, + User = 1, + Group, + Domain, + Alias, + WellKnownGroup, + DeletedAccount, + Invalid, + Unknown, + Computer, + Label, + LogonSession, } SECURITY_MAX_SID_SIZE :: 68 @@ -869,7 +955,7 @@ SID :: struct #packed { #assert(size_of(SID) == SECURITY_MAX_SID_SIZE) SID_IDENTIFIER_AUTHORITY :: struct #packed { - Value: [6]u8, + Value: [6]u8, } // For NetAPI32 @@ -901,11 +987,11 @@ USER_INFO_FLAG :: enum DWORD { Passwd_Cant_Change = 6, // 1 << 6: 0x0040, Encrypted_Text_Password_Allowed = 7, // 1 << 7: 0x0080, - Temp_Duplicate_Account = 8, // 1 << 8: 0x0100, - Normal_Account = 9, // 1 << 9: 0x0200, - InterDomain_Trust_Account = 11, // 1 << 11: 0x0800, - Workstation_Trust_Account = 12, // 1 << 12: 0x1000, - Server_Trust_Account = 13, // 1 << 13: 0x2000, + Temp_Duplicate_Account = 8, // 1 << 8: 0x0100, + Normal_Account = 9, // 1 << 9: 0x0200, + InterDomain_Trust_Account = 11, // 1 << 11: 0x0800, + Workstation_Trust_Account = 12, // 1 << 12: 0x1000, + Server_Trust_Account = 13, // 1 << 13: 0x2000, } USER_INFO_FLAGS :: distinct bit_set[USER_INFO_FLAG] @@ -1252,4 +1338,4 @@ SYSTEMTIME :: struct { minute: WORD, second: WORD, milliseconds: WORD, -} \ No newline at end of file +} diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin new file mode 100644 index 000000000..b6fef5444 --- /dev/null +++ b/core/sys/windows/user32.odin @@ -0,0 +1,82 @@ +// +build windows +package sys_windows + +foreign import user32 "system:User32.lib" + +@(default_calling_convention="stdcall") +foreign user32 { + RegisterClassA :: proc(lpWndClass: ^WNDCLASSA) -> ATOM --- + RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- + RegisterClassExA :: proc(^WNDCLASSEXA) -> ATOM --- + RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- + + CreateWindowExA :: proc( + dwExStyle: DWORD, + lpClassName: LPCSTR, + lpWindowName: LPCSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, + ) -> HWND --- + CreateWindowExW :: proc( + dwExStyle: DWORD, + lpClassName: LPCWSTR, + lpWindowName: LPCWSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, + ) -> HWND --- + + DestroyWindow :: proc(hWnd: HWND) -> BOOL --- + ShowWindow :: proc(hWnd: HWND, nCmdShow: c_int) -> BOOL --- + + GetMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- + GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- + + TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL --- + DispatchMessageA :: proc(lpMsg: ^MSG) -> LRESULT --- + DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT --- + + PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- + PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- + + PostMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + PostMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + SendMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + SendMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + + PostThreadMessageA :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + PostThreadMessageW :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + + DefWindowProcA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + DefWindowProcW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + + FindWindowExA :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCSTR, lpszWindow: LPCSTR) -> HWND --- + FindWindowExW :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCWSTR, lpszWindow: LPCWSTR) -> HWND --- + + LoadIconA :: proc(hInstance: HINSTANCE, lpIconName: LPCSTR) -> HICON --- + LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON --- + LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- + LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- + + GetClientRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- + + GetWindowDC :: proc(hWnd: HWND) -> HDC --- + GetDC :: proc(hWnd: HWND) -> HDC --- + ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> c_int --- + + BeginPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> HDC --- + EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- +} From bae13b63871c3973b4274e94a3041be7665b1781 Mon Sep 17 00:00:00 2001 From: Holger Lindner Date: Mon, 21 Mar 2022 20:06:50 +0100 Subject: [PATCH 0418/1052] Fix incorrect type for wndproc callback procedure --- core/sys/windows/user32.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 1a92002b6..c9d4bdba1 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -137,7 +137,7 @@ WNDCLASSEXA :: struct { WNDCLASSEXW :: struct { cbSize: UINT, style: UINT, - lpfnWndProc: ^WNDPROC, + lpfnWndProc: WNDPROC, cbClsExtra: c_int, cbWndExtra: c_int, hInstance: HINSTANCE, From 43640a8b5989909386cd0492d36ca2daa42abe50 Mon Sep 17 00:00:00 2001 From: Holger Lindner Date: Tue, 22 Mar 2022 16:23:38 +0100 Subject: [PATCH 0419/1052] Add SendMessageA/W to sys/windows/user32.odin --- core/sys/windows/user32.odin | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index c9d4bdba1..5e374d1e5 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -270,6 +270,9 @@ foreign user32 { PostMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- PostMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + SendMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + SendMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + GetQueueStatus :: proc(flags: UINT) -> DWORD --- DefWindowProcA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParma: LPARAM) -> LRESULT --- From edce27812f191f23846f55cc6359f30e3be45c82 Mon Sep 17 00:00:00 2001 From: Holger Lindner Date: Tue, 22 Mar 2022 16:41:07 +0100 Subject: [PATCH 0420/1052] Nixify line endings --- core/sys/windows/user32.odin | 258 +-- core/sys/windows/window_messages.odin | 2092 ++++++++++++------------- 2 files changed, 1175 insertions(+), 1175 deletions(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 588a618b8..ce88b25ce 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -1,129 +1,129 @@ -// +build windows -package sys_windows - -foreign import user32 "system:User32.lib" - -@(default_calling_convention="stdcall") -foreign user32 { - GetClassInfoA :: proc(hInstance: HINSTANCE, lpClassNAme: LPCSTR, lpWndClass: ^WNDCLASSA) -> BOOL --- - GetClassInfoW :: proc(hInstance: HINSTANCE, lpClassNAme: LPCWSTR, lpWndClass: ^WNDCLASSW) -> BOOL --- - GetClassInfoExA :: proc(hInsatnce: HINSTANCE, lpszClass: LPCSTR, lpwcx: ^WNDCLASSEXA) -> BOOL --- - GetClassInfoExW :: proc(hInsatnce: HINSTANCE, lpszClass: LPCWSTR, lpwcx: ^WNDCLASSEXW) -> BOOL --- - - GetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- - GetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- - SetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- - SetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- - - GetClassNameA :: proc(hWnd: HWND, lpClassName: LPSTR, nMaxCount: c_int) -> c_int --- - GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int --- - - GetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- - GetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- - SetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- - SetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- - - RegisterClassA :: proc(lpWndClass: ^WNDCLASSA) -> ATOM --- - RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- - RegisterClassExA :: proc(^WNDCLASSEXA) -> ATOM --- - RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- - - CreateWindowA :: proc( - lpClassName: LPCSTR, - lpWindowName: LPCSTR, - dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPARAM) -> HWND --- - CreateWindowW :: proc( - lpClassName: LPCWSTR, - lpWindowName: LPCWSTR, - dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPARAM) -> HWND --- - CreateWindowExA :: proc( - dwExStyle: DWORD, - lpClassName: LPCSTR, - lpWindowName: LPCSTR, - dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPVOID, - ) -> HWND --- - CreateWindowExW :: proc( - dwExStyle: DWORD, - lpClassName: LPCWSTR, - lpWindowName: LPCWSTR, - dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPVOID, - ) -> HWND --- - - DestroyWindow :: proc(hWnd: HWND) -> BOOL --- - - ShowWindow :: proc(hWnd: HWND, nCmdShow: c_int) -> BOOL --- - - GetMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- - GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- - - TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL --- - DispatchMessageA :: proc(lpMsg: ^MSG) -> LRESULT --- - DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT --- - - PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- - PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- - - PostMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- - PostMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- - SendMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- - SendMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- - - PostThreadMessageA :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- - PostThreadMessageW :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- - - PostQuitMessage :: proc(nExitCode: c_int) --- - - GetQueueStatus :: proc(flags: UINT) -> DWORD --- - - DefWindowProcA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- - DefWindowProcW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- - - FindWindowExA :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCSTR, lpszWindow: LPCSTR) -> HWND --- - FindWindowExW :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCWSTR, lpszWindow: LPCWSTR) -> HWND --- - - LoadIconA :: proc(hInstance: HINSTANCE, lpIconName: LPCSTR) -> HICON --- - LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON --- - LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- - LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- - - GetClientRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- - - GetWindowDC :: proc(hWnd: HWND) -> HDC --- - GetDC :: proc(hWnd: HWND) -> HDC --- - ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> c_int --- - - BeginPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> HDC --- - EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- -} +// +build windows +package sys_windows + +foreign import user32 "system:User32.lib" + +@(default_calling_convention="stdcall") +foreign user32 { + GetClassInfoA :: proc(hInstance: HINSTANCE, lpClassNAme: LPCSTR, lpWndClass: ^WNDCLASSA) -> BOOL --- + GetClassInfoW :: proc(hInstance: HINSTANCE, lpClassNAme: LPCWSTR, lpWndClass: ^WNDCLASSW) -> BOOL --- + GetClassInfoExA :: proc(hInsatnce: HINSTANCE, lpszClass: LPCSTR, lpwcx: ^WNDCLASSEXA) -> BOOL --- + GetClassInfoExW :: proc(hInsatnce: HINSTANCE, lpszClass: LPCWSTR, lpwcx: ^WNDCLASSEXW) -> BOOL --- + + GetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- + GetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- + SetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + SetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + + GetClassNameA :: proc(hWnd: HWND, lpClassName: LPSTR, nMaxCount: c_int) -> c_int --- + GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int --- + + GetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- + GetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- + SetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- + SetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- + + RegisterClassA :: proc(lpWndClass: ^WNDCLASSA) -> ATOM --- + RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- + RegisterClassExA :: proc(^WNDCLASSEXA) -> ATOM --- + RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- + + CreateWindowA :: proc( + lpClassName: LPCSTR, + lpWindowName: LPCSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPARAM) -> HWND --- + CreateWindowW :: proc( + lpClassName: LPCWSTR, + lpWindowName: LPCWSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPARAM) -> HWND --- + CreateWindowExA :: proc( + dwExStyle: DWORD, + lpClassName: LPCSTR, + lpWindowName: LPCSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, + ) -> HWND --- + CreateWindowExW :: proc( + dwExStyle: DWORD, + lpClassName: LPCWSTR, + lpWindowName: LPCWSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, + ) -> HWND --- + + DestroyWindow :: proc(hWnd: HWND) -> BOOL --- + + ShowWindow :: proc(hWnd: HWND, nCmdShow: c_int) -> BOOL --- + + GetMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- + GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL --- + + TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL --- + DispatchMessageA :: proc(lpMsg: ^MSG) -> LRESULT --- + DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT --- + + PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- + PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- + + PostMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + PostMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + SendMessageA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + SendMessageW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + + PostThreadMessageA :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + PostThreadMessageW :: proc(idThread: DWORD, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> BOOL --- + + PostQuitMessage :: proc(nExitCode: c_int) --- + + GetQueueStatus :: proc(flags: UINT) -> DWORD --- + + DefWindowProcA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + DefWindowProcW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + + FindWindowExA :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCSTR, lpszWindow: LPCSTR) -> HWND --- + FindWindowExW :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCWSTR, lpszWindow: LPCWSTR) -> HWND --- + + LoadIconA :: proc(hInstance: HINSTANCE, lpIconName: LPCSTR) -> HICON --- + LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON --- + LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- + LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- + + GetClientRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- + + GetWindowDC :: proc(hWnd: HWND) -> HDC --- + GetDC :: proc(hWnd: HWND) -> HDC --- + ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> c_int --- + + BeginPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> HDC --- + EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- +} diff --git a/core/sys/windows/window_messages.odin b/core/sys/windows/window_messages.odin index f52be9bbc..f0aa76daa 100644 --- a/core/sys/windows/window_messages.odin +++ b/core/sys/windows/window_messages.odin @@ -1,1047 +1,1047 @@ -package sys_windows - -WM_NULL :: 0x0000 -WM_CREATE :: 0x0001 -WM_DESTROY :: 0x0002 -WM_MOVE :: 0x0003 -WM_SIZE :: 0x0005 -WM_ACTIVATE :: 0x0006 -WM_SETFOCUS :: 0x0007 -WM_KILLFOCUS :: 0x0008 -WM_ENABLE :: 0x000a -WM_SETREDRAW :: 0x000b -WM_SETTEXT :: 0x000c -WM_GETTEXT :: 0x000d -WM_GETTEXTLENGTH :: 0x000e -WM_PAINT :: 0x000f -WM_CLOSE :: 0x0010 -WM_QUERYENDSESSION :: 0x0011 -WM_QUIT :: 0x0012 -WM_QUERYOPEN :: 0x0013 -WM_ERASEBKGND :: 0x0014 -WM_SYSCOLORCHANGE :: 0x0015 -WM_ENDSESSION :: 0x0016 -WM_SHOWWINDOW :: 0x0018 -WM_CTLCOLOR :: 0x0019 -WM_WININICHANGE :: 0x001a -WM_DEVMODECHANGE :: 0x001b -WM_ACTIVATEAPP :: 0x001c -WM_FONTCHANGE :: 0x001d -WM_TIMECHANGE :: 0x001e -WM_CANCELMODE :: 0x001f -WM_SETCURSOR :: 0x0020 -WM_MOUSEACTIVATE :: 0x0021 -WM_CHILDACTIVATE :: 0x0022 -WM_QUEUESYNC :: 0x0023 -WM_GETMINMAXINFO :: 0x0024 -WM_PAINTICON :: 0x0026 -WM_ICONERASEBKGND :: 0x0027 -WM_NEXTDLGCTL :: 0x0028 -WM_SPOOLERSTATUS :: 0x002a -WM_DRAWITEM :: 0x002b -WM_MEASUREITEM :: 0x002c -WM_DELETEITEM :: 0x002d -WM_VKEYTOITEM :: 0x002e -WM_CHARTOITEM :: 0x002f -WM_SETFONT :: 0x0030 -WM_GETFONT :: 0x0031 -WM_SETHOTKEY :: 0x0032 -WM_GETHOTKEY :: 0x0033 -WM_QUERYDRAGICON :: 0x0037 -WM_COMPAREITEM :: 0x0039 -WM_GETOBJECT :: 0x003d -WM_COMPACTING :: 0x0041 -WM_COMMNOTIFY :: 0x0044 -WM_WINDOWPOSCHANGING :: 0x0046 -WM_WINDOWPOSCHANGED :: 0x0047 -WM_POWER :: 0x0048 -WM_COPYGLOBALDATA :: 0x0049 -WM_COPYDATA :: 0x004a -WM_CANCELJOURNAL :: 0x004b -WM_NOTIFY :: 0x004e -WM_INPUTLANGCHANGEREQUEST :: 0x0050 -WM_INPUTLANGCHANGE :: 0x0051 -WM_TCARD :: 0x0052 -WM_HELP :: 0x0053 -WM_USERCHANGED :: 0x0054 -WM_NOTIFYFORMAT :: 0x0055 -WM_CONTEXTMENU :: 0x007b -WM_STYLECHANGING :: 0x007c -WM_STYLECHANGED :: 0x007d -WM_DISPLAYCHANGE :: 0x007e -WM_GETICON :: 0x007f -WM_SETICON :: 0x0080 -WM_NCCREATE :: 0x0081 -WM_NCDESTROY :: 0x0082 -WM_NCCALCSIZE :: 0x0083 -WM_NCHITTEST :: 0x0084 -WM_NCPAINT :: 0x0085 -WM_NCACTIVATE :: 0x0086 -WM_GETDLGCODE :: 0x0087 -WM_SYNCPAINT :: 0x0088 -WM_NCMOUSEMOVE :: 0x00a0 -WM_NCLBUTTONDOWN :: 0x00a1 -WM_NCLBUTTONUP :: 0x00a2 -WM_NCLBUTTONDBLCLK :: 0x00a3 -WM_NCRBUTTONDOWN :: 0x00a4 -WM_NCRBUTTONUP :: 0x00a5 -WM_NCRBUTTONDBLCLK :: 0x00a6 -WM_NCMBUTTONDOWN :: 0x00a7 -WM_NCMBUTTONUP :: 0x00a8 -WM_NCMBUTTONDBLCLK :: 0x00a9 -WM_NCXBUTTONDOWN :: 0x00ab -WM_NCXBUTTONUP :: 0x00ac -WM_NCXBUTTONDBLCLK :: 0x00ad -EM_GETSEL :: 0x00b0 -EM_SETSEL :: 0x00b1 -EM_GETRECT :: 0x00b2 -EM_SETRECT :: 0x00b3 -EM_SETRECTNP :: 0x00b4 -EM_SCROLL :: 0x00b5 -EM_LINESCROLL :: 0x00b6 -EM_SCROLLCARET :: 0x00b7 -EM_GETMODIFY :: 0x00b8 -EM_SETMODIFY :: 0x00b9 -EM_GETLINECOUNT :: 0x00ba -EM_LINEINDEX :: 0x00bb -EM_SETHANDLE :: 0x00bc -EM_GETHANDLE :: 0x00bd -EM_GETTHUMB :: 0x00be -EM_LINELENGTH :: 0x00c1 -EM_REPLACESEL :: 0x00c2 -EM_SETFONT :: 0x00c3 -EM_GETLINE :: 0x00c4 -EM_LIMITTEXT :: 0x00c5 -EM_SETLIMITTEXT :: 0x00c5 -EM_CANUNDO :: 0x00c6 -EM_UNDO :: 0x00c7 -EM_FMTLINES :: 0x00c8 -EM_LINEFROMCHAR :: 0x00c9 -EM_SETWORDBREAK :: 0x00ca -EM_SETTABSTOPS :: 0x00cb -EM_SETPASSWORDCHAR :: 0x00cc -EM_EMPTYUNDOBUFFER :: 0x00cd -EM_GETFIRSTVISIBLELINE :: 0x00ce -EM_SETREADONLY :: 0x00cf -EM_SETWORDBREAKPROC :: 0x00d0 -EM_GETWORDBREAKPROC :: 0x00d1 -EM_GETPASSWORDCHAR :: 0x00d2 -EM_SETMARGINS :: 0x00d3 -EM_GETMARGINS :: 0x00d4 -EM_GETLIMITTEXT :: 0x00d5 -EM_POSFROMCHAR :: 0x00d6 -EM_CHARFROMPOS :: 0x00d7 -EM_SETIMESTATUS :: 0x00d8 -EM_GETIMESTATUS :: 0x00d9 -SBM_SETPOS :: 0x00e0 -SBM_GETPOS :: 0x00e1 -SBM_SETRANGE :: 0x00e2 -SBM_GETRANGE :: 0x00e3 -SBM_ENABLE_ARROWS :: 0x00e4 -SBM_SETRANGEREDRAW :: 0x00e6 -SBM_SETSCROLLINFO :: 0x00e9 -SBM_GETSCROLLINFO :: 0x00ea -SBM_GETSCROLLBARINFO :: 0x00eb -BM_GETCHECK :: 0x00f0 -BM_SETCHECK :: 0x00f1 -BM_GETSTATE :: 0x00f2 -BM_SETSTATE :: 0x00f3 -BM_SETSTYLE :: 0x00f4 -BM_CLICK :: 0x00f5 -BM_GETIMAGE :: 0x00f6 -BM_SETIMAGE :: 0x00f7 -BM_SETDONTCLICK :: 0x00f8 -WM_INPUT :: 0x00ff -WM_KEYDOWN :: 0x0100 -WM_KEYFIRST :: 0x0100 -WM_KEYUP :: 0x0101 -WM_CHAR :: 0x0102 -WM_DEADCHAR :: 0x0103 -WM_SYSKEYDOWN :: 0x0104 -WM_SYSKEYUP :: 0x0105 -WM_SYSCHAR :: 0x0106 -WM_SYSDEADCHAR :: 0x0107 -WM_UNICHAR :: 0x0109 -WM_KEYLAST :: 0x0109 -WM_WNT_CONVERTREQUESTEX :: 0x0109 -WM_CONVERTREQUEST :: 0x010a -WM_CONVERTRESULT :: 0x010b -WM_INTERIM :: 0x010c -WM_IME_STARTCOMPOSITION :: 0x010d -WM_IME_ENDCOMPOSITION :: 0x010e -WM_IME_COMPOSITION :: 0x010f -WM_IME_KEYLAST :: 0x010f -WM_INITDIALOG :: 0x0110 -WM_COMMAND :: 0x0111 -WM_SYSCOMMAND :: 0x0112 -WM_TIMER :: 0x0113 -WM_HSCROLL :: 0x0114 -WM_VSCROLL :: 0x0115 -WM_INITMENU :: 0x0116 -WM_INITMENUPOPUP :: 0x0117 -WM_SYSTIMER :: 0x0118 -WM_MENUSELECT :: 0x011f -WM_MENUCHAR :: 0x0120 -WM_ENTERIDLE :: 0x0121 -WM_MENURBUTTONUP :: 0x0122 -WM_MENUDRAG :: 0x0123 -WM_MENUGETOBJECT :: 0x0124 -WM_UNINITMENUPOPUP :: 0x0125 -WM_MENUCOMMAND :: 0x0126 -WM_CHANGEUISTATE :: 0x0127 -WM_UPDATEUISTATE :: 0x0128 -WM_QUERYUISTATE :: 0x0129 -WM_LBTRACKPOINT :: 0x0131 -WM_CTLCOLORMSGBOX :: 0x0132 -WM_CTLCOLOREDIT :: 0x0133 -WM_CTLCOLORLISTBOX :: 0x0134 -WM_CTLCOLORBTN :: 0x0135 -WM_CTLCOLORDLG :: 0x0136 -WM_CTLCOLORSCROLLBAR :: 0x0137 -WM_CTLCOLORSTATIC :: 0x0138 -CB_GETEDITSEL :: 0x0140 -CB_LIMITTEXT :: 0x0141 -CB_SETEDITSEL :: 0x0142 -CB_ADDSTRING :: 0x0143 -CB_DELETESTRING :: 0x0144 -CB_DIR :: 0x0145 -CB_GETCOUNT :: 0x0146 -CB_GETCURSEL :: 0x0147 -CB_GETLBTEXT :: 0x0148 -CB_GETLBTEXTLEN :: 0x0149 -CB_INSERTSTRING :: 0x014a -CB_RESETCONTENT :: 0x014b -CB_FINDSTRING :: 0x014c -CB_SELECTSTRING :: 0x014d -CB_SETCURSEL :: 0x014e -CB_SHOWDROPDOWN :: 0x014f -CB_GETITEMDATA :: 0x0150 -CB_SETITEMDATA :: 0x0151 -CB_GETDROPPEDCONTROLRECT :: 0x0152 -CB_SETITEMHEIGHT :: 0x0153 -CB_GETITEMHEIGHT :: 0x0154 -CB_SETEXTENDEDUI :: 0x0155 -CB_GETEXTENDEDUI :: 0x0156 -CB_GETDROPPEDSTATE :: 0x0157 -CB_FINDSTRINGEXACT :: 0x0158 -CB_SETLOCALE :: 0x0159 -CB_GETLOCALE :: 0x015a -CB_GETTOPINDEX :: 0x015b -CB_SETTOPINDEX :: 0x015c -CB_GETHORIZONTALEXTENT :: 0x015d -CB_SETHORIZONTALEXTENT :: 0x015e -CB_GETDROPPEDWIDTH :: 0x015f -CB_SETDROPPEDWIDTH :: 0x0160 -CB_INITSTORAGE :: 0x0161 -CB_MULTIPLEADDSTRING :: 0x0163 -CB_GETCOMBOBOXINFO :: 0x0164 -CB_MSGMAX :: 0x0165 -WM_MOUSEFIRST :: 0x0200 -WM_MOUSEMOVE :: 0x0200 -WM_LBUTTONDOWN :: 0x0201 -WM_LBUTTONUP :: 0x0202 -WM_LBUTTONDBLCLK :: 0x0203 -WM_RBUTTONDOWN :: 0x0204 -WM_RBUTTONUP :: 0x0205 -WM_RBUTTONDBLCLK :: 0x0206 -WM_MBUTTONDOWN :: 0x0207 -WM_MBUTTONUP :: 0x0208 -WM_MBUTTONDBLCLK :: 0x0209 -WM_MOUSELAST :: 0x0209 -WM_MOUSEWHEEL :: 0x020a -WM_XBUTTONDOWN :: 0x020b -WM_XBUTTONUP :: 0x020c -WM_XBUTTONDBLCLK :: 0x020d -WM_MOUSEHWHEEL :: 0x020e -WM_PARENTNOTIFY :: 0x0210 -WM_ENTERMENULOOP :: 0x0211 -WM_EXITMENULOOP :: 0x0212 -WM_NEXTMENU :: 0x0213 -WM_SIZING :: 0x0214 -WM_CAPTURECHANGED :: 0x0215 -WM_MOVING :: 0x0216 -WM_POWERBROADCAST :: 0x0218 -WM_DEVICECHANGE :: 0x0219 -WM_MDICREATE :: 0x0220 -WM_MDIDESTROY :: 0x0221 -WM_MDIACTIVATE :: 0x0222 -WM_MDIRESTORE :: 0x0223 -WM_MDINEXT :: 0x0224 -WM_MDIMAXIMIZE :: 0x0225 -WM_MDITILE :: 0x0226 -WM_MDICASCADE :: 0x0227 -WM_MDIICONARRANGE :: 0x0228 -WM_MDIGETACTIVE :: 0x0229 -WM_MDISETMENU :: 0x0230 -WM_ENTERSIZEMOVE :: 0x0231 -WM_EXITSIZEMOVE :: 0x0232 -WM_DROPFILES :: 0x0233 -WM_MDIREFRESHMENU :: 0x0234 -WM_IME_REPORT :: 0x0280 -WM_IME_SETCONTEXT :: 0x0281 -WM_IME_NOTIFY :: 0x0282 -WM_IME_CONTROL :: 0x0283 -WM_IME_COMPOSITIONFULL :: 0x0284 -WM_IME_SELECT :: 0x0285 -WM_IME_CHAR :: 0x0286 -WM_IME_REQUEST :: 0x0288 -WM_IMEKEYDOWN :: 0x0290 -WM_IME_KEYDOWN :: 0x0290 -WM_IMEKEYUP :: 0x0291 -WM_IME_KEYUP :: 0x0291 -WM_NCMOUSEHOVER :: 0x02a0 -WM_MOUSEHOVER :: 0x02a1 -WM_NCMOUSELEAVE :: 0x02a2 -WM_MOUSELEAVE :: 0x02a3 -WM_CUT :: 0x0300 -WM_COPY :: 0x0301 -WM_PASTE :: 0x0302 -WM_CLEAR :: 0x0303 -WM_UNDO :: 0x0304 -WM_RENDERFORMAT :: 0x0305 -WM_RENDERALLFORMATS :: 0x0306 -WM_DESTROYCLIPBOARD :: 0x0307 -WM_DRAWCLIPBOARD :: 0x0308 -WM_PAINTCLIPBOARD :: 0x0309 -WM_VSCROLLCLIPBOARD :: 0x030a -WM_SIZECLIPBOARD :: 0x030b -WM_ASKCBFORMATNAME :: 0x030c -WM_CHANGECBCHAIN :: 0x030d -WM_HSCROLLCLIPBOARD :: 0x030e -WM_QUERYNEWPALETTE :: 0x030f -WM_PALETTEISCHANGING :: 0x0310 -WM_PALETTECHANGED :: 0x0311 -WM_HOTKEY :: 0x0312 -WM_PRINT :: 0x0317 -WM_PRINTCLIENT :: 0x0318 -WM_APPCOMMAND :: 0x0319 -WM_HANDHELDFIRST :: 0x0358 -WM_HANDHELDLAST :: 0x035f -WM_AFXFIRST :: 0x0360 -WM_AFXLAST :: 0x037f -WM_PENWINFIRST :: 0x0380 -WM_RCRESULT :: 0x0381 -WM_HOOKRCRESULT :: 0x0382 -WM_GLOBALRCCHANGE :: 0x0383 -WM_PENMISCINFO :: 0x0383 -WM_SKB :: 0x0384 -WM_HEDITCTL :: 0x0385 -WM_PENCTL :: 0x0385 -WM_PENMISC :: 0x0386 -WM_CTLINIT :: 0x0387 -WM_PENEVENT :: 0x0388 -WM_PENWINLAST :: 0x038f -DDM_SETFMT :: 0x0400 -DM_GETDEFID :: 0x0400 -NIN_SELECT :: 0x0400 -TBM_GETPOS :: 0x0400 -WM_PSD_PAGESETUPDLG :: 0x0400 -WM_USER :: 0x0400 -CBEM_INSERTITEMA :: 0x0401 -DDM_DRAW :: 0x0401 -DM_SETDEFID :: 0x0401 -HKM_SETHOTKEY :: 0x0401 -PBM_SETRANGE :: 0x0401 -RB_INSERTBANDA :: 0x0401 -SB_SETTEXTA :: 0x0401 -TB_ENABLEBUTTON :: 0x0401 -TBM_GETRANGEMIN :: 0x0401 -TTM_ACTIVATE :: 0x0401 -WM_CHOOSEFONT_GETLOGFONT :: 0x0401 -WM_PSD_FULLPAGERECT :: 0x0401 -CBEM_SETIMAGELIST :: 0x0402 -DDM_CLOSE :: 0x0402 -DM_REPOSITION :: 0x0402 -HKM_GETHOTKEY :: 0x0402 -PBM_SETPOS :: 0x0402 -RB_DELETEBAND :: 0x0402 -SB_GETTEXTA :: 0x0402 -TB_CHECKBUTTON :: 0x0402 -TBM_GETRANGEMAX :: 0x0402 -WM_PSD_MINMARGINRECT :: 0x0402 -CBEM_GETIMAGELIST :: 0x0403 -DDM_BEGIN :: 0x0403 -HKM_SETRULES :: 0x0403 -PBM_DELTAPOS :: 0x0403 -RB_GETBARINFO :: 0x0403 -SB_GETTEXTLENGTHA :: 0x0403 -TBM_GETTIC :: 0x0403 -TB_PRESSBUTTON :: 0x0403 -TTM_SETDELAYTIME :: 0x0403 -WM_PSD_MARGINRECT :: 0x0403 -CBEM_GETITEMA :: 0x0404 -DDM_END :: 0x0404 -PBM_SETSTEP :: 0x0404 -RB_SETBARINFO :: 0x0404 -SB_SETPARTS :: 0x0404 -TB_HIDEBUTTON :: 0x0404 -TBM_SETTIC :: 0x0404 -TTM_ADDTOOLA :: 0x0404 -WM_PSD_GREEKTEXTRECT :: 0x0404 -CBEM_SETITEMA :: 0x0405 -PBM_STEPIT :: 0x0405 -TB_INDETERMINATE :: 0x0405 -TBM_SETPOS :: 0x0405 -TTM_DELTOOLA :: 0x0405 -WM_PSD_ENVSTAMPRECT :: 0x0405 -CBEM_GETCOMBOCONTROL :: 0x0406 -PBM_SETRANGE32 :: 0x0406 -RB_SETBANDINFOA :: 0x0406 -SB_GETPARTS :: 0x0406 -TB_MARKBUTTON :: 0x0406 -TBM_SETRANGE :: 0x0406 -TTM_NEWTOOLRECTA :: 0x0406 -WM_PSD_YAFULLPAGERECT :: 0x0406 -CBEM_GETEDITCONTROL :: 0x0407 -PBM_GETRANGE :: 0x0407 -RB_SETPARENT :: 0x0407 -SB_GETBORDERS :: 0x0407 -TBM_SETRANGEMIN :: 0x0407 -TTM_RELAYEVENT :: 0x0407 -CBEM_SETEXSTYLE :: 0x0408 -PBM_GETPOS :: 0x0408 -RB_HITTEST :: 0x0408 -SB_SETMINHEIGHT :: 0x0408 -TBM_SETRANGEMAX :: 0x0408 -TTM_GETTOOLINFOA :: 0x0408 -CBEM_GETEXSTYLE :: 0x0409 -CBEM_GETEXTENDEDSTYLE :: 0x0409 -PBM_SETBARCOLOR :: 0x0409 -RB_GETRECT :: 0x0409 -SB_SIMPLE :: 0x0409 -TB_ISBUTTONENABLED :: 0x0409 -TBM_CLEARTICS :: 0x0409 -TTM_SETTOOLINFOA :: 0x0409 -CBEM_HASEDITCHANGED :: 0x040a -RB_INSERTBANDW :: 0x040a -SB_GETRECT :: 0x040a -TB_ISBUTTONCHECKED :: 0x040a -TBM_SETSEL :: 0x040a -TTM_HITTESTA :: 0x040a -WIZ_QUERYNUMPAGES :: 0x040a -CBEM_INSERTITEMW :: 0x040b -RB_SETBANDINFOW :: 0x040b -SB_SETTEXTW :: 0x040b -TB_ISBUTTONPRESSED :: 0x040b -TBM_SETSELSTART :: 0x040b -TTM_GETTEXTA :: 0x040b -WIZ_NEXT :: 0x040b -CBEM_SETITEMW :: 0x040c -RB_GETBANDCOUNT :: 0x040c -SB_GETTEXTLENGTHW :: 0x040c -TB_ISBUTTONHIDDEN :: 0x040c -TBM_SETSELEND :: 0x040c -TTM_UPDATETIPTEXTA :: 0x040c -WIZ_PREV :: 0x040c -CBEM_GETITEMW :: 0x040d -RB_GETROWCOUNT :: 0x040d -SB_GETTEXTW :: 0x040d -TB_ISBUTTONINDETERMINATE :: 0x040d -TTM_GETTOOLCOUNT :: 0x040d -CBEM_SETEXTENDEDSTYLE :: 0x040e -RB_GETROWHEIGHT :: 0x040e -SB_ISSIMPLE :: 0x040e -TB_ISBUTTONHIGHLIGHTED :: 0x040e -TBM_GETPTICS :: 0x040e -TTM_ENUMTOOLSA :: 0x040e -SB_SETICON :: 0x040f -TBM_GETTICPOS :: 0x040f -TTM_GETCURRENTTOOLA :: 0x040f -RB_IDTOINDEX :: 0x0410 -SB_SETTIPTEXTA :: 0x0410 -TBM_GETNUMTICS :: 0x0410 -TTM_WINDOWFROMPOINT :: 0x0410 -RB_GETTOOLTIPS :: 0x0411 -SB_SETTIPTEXTW :: 0x0411 -TBM_GETSELSTART :: 0x0411 -TB_SETSTATE :: 0x0411 -TTM_TRACKACTIVATE :: 0x0411 -RB_SETTOOLTIPS :: 0x0412 -SB_GETTIPTEXTA :: 0x0412 -TB_GETSTATE :: 0x0412 -TBM_GETSELEND :: 0x0412 -TTM_TRACKPOSITION :: 0x0412 -RB_SETBKCOLOR :: 0x0413 -SB_GETTIPTEXTW :: 0x0413 -TB_ADDBITMAP :: 0x0413 -TBM_CLEARSEL :: 0x0413 -TTM_SETTIPBKCOLOR :: 0x0413 -RB_GETBKCOLOR :: 0x0414 -SB_GETICON :: 0x0414 -TB_ADDBUTTONSA :: 0x0414 -TBM_SETTICFREQ :: 0x0414 -TTM_SETTIPTEXTCOLOR :: 0x0414 -RB_SETTEXTCOLOR :: 0x0415 -TB_INSERTBUTTONA :: 0x0415 -TBM_SETPAGESIZE :: 0x0415 -TTM_GETDELAYTIME :: 0x0415 -RB_GETTEXTCOLOR :: 0x0416 -TB_DELETEBUTTON :: 0x0416 -TBM_GETPAGESIZE :: 0x0416 -TTM_GETTIPBKCOLOR :: 0x0416 -RB_SIZETORECT :: 0x0417 -TB_GETBUTTON :: 0x0417 -TBM_SETLINESIZE :: 0x0417 -TTM_GETTIPTEXTCOLOR :: 0x0417 -RB_BEGINDRAG :: 0x0418 -TB_BUTTONCOUNT :: 0x0418 -TBM_GETLINESIZE :: 0x0418 -TTM_SETMAXTIPWIDTH :: 0x0418 -RB_ENDDRAG :: 0x0419 -TB_COMMANDTOINDEX :: 0x0419 -TBM_GETTHUMBRECT :: 0x0419 -TTM_GETMAXTIPWIDTH :: 0x0419 -RB_DRAGMOVE :: 0x041a -TBM_GETCHANNELRECT :: 0x041a -TB_SAVERESTOREA :: 0x041a -TTM_SETMARGIN :: 0x041a -RB_GETBARHEIGHT :: 0x041b -TB_CUSTOMIZE :: 0x041b -TBM_SETTHUMBLENGTH :: 0x041b -TTM_GETMARGIN :: 0x041b -RB_GETBANDINFOW :: 0x041c -TB_ADDSTRINGA :: 0x041c -TBM_GETTHUMBLENGTH :: 0x041c -TTM_POP :: 0x041c -RB_GETBANDINFOA :: 0x041d -TB_GETITEMRECT :: 0x041d -TBM_SETTOOLTIPS :: 0x041d -TTM_UPDATE :: 0x041d -RB_MINIMIZEBAND :: 0x041e -TB_BUTTONSTRUCTSIZE :: 0x041e -TBM_GETTOOLTIPS :: 0x041e -TTM_GETBUBBLESIZE :: 0x041e -RB_MAXIMIZEBAND :: 0x041f -TBM_SETTIPSIDE :: 0x041f -TB_SETBUTTONSIZE :: 0x041f -TTM_ADJUSTRECT :: 0x041f -TBM_SETBUDDY :: 0x0420 -TB_SETBITMAPSIZE :: 0x0420 -TTM_SETTITLEA :: 0x0420 -MSG_FTS_JUMP_VA :: 0x0421 -TB_AUTOSIZE :: 0x0421 -TBM_GETBUDDY :: 0x0421 -TTM_SETTITLEW :: 0x0421 -RB_GETBANDBORDERS :: 0x0422 -MSG_FTS_JUMP_QWORD :: 0x0423 -RB_SHOWBAND :: 0x0423 -TB_GETTOOLTIPS :: 0x0423 -MSG_REINDEX_REQUEST :: 0x0424 -TB_SETTOOLTIPS :: 0x0424 -MSG_FTS_WHERE_IS_IT :: 0x0425 -RB_SETPALETTE :: 0x0425 -TB_SETPARENT :: 0x0425 -RB_GETPALETTE :: 0x0426 -RB_MOVEBAND :: 0x0427 -TB_SETROWS :: 0x0427 -TB_GETROWS :: 0x0428 -TB_GETBITMAPFLAGS :: 0x0429 -TB_SETCMDID :: 0x042a -RB_PUSHCHEVRON :: 0x042b -TB_CHANGEBITMAP :: 0x042b -TB_GETBITMAP :: 0x042c -MSG_GET_DEFFONT :: 0x042d -TB_GETBUTTONTEXTA :: 0x042d -TB_REPLACEBITMAP :: 0x042e -TB_SETINDENT :: 0x042f -TB_SETIMAGELIST :: 0x0430 -TB_GETIMAGELIST :: 0x0431 -TB_LOADIMAGES :: 0x0432 -EM_CANPASTE :: 0x0432 -TTM_ADDTOOLW :: 0x0432 -EM_DISPLAYBAND :: 0x0433 -TB_GETRECT :: 0x0433 -TTM_DELTOOLW :: 0x0433 -EM_EXGETSEL :: 0x0434 -TB_SETHOTIMAGELIST :: 0x0434 -TTM_NEWTOOLRECTW :: 0x0434 -EM_EXLIMITTEXT :: 0x0435 -TB_GETHOTIMAGELIST :: 0x0435 -TTM_GETTOOLINFOW :: 0x0435 -EM_EXLINEFROMCHAR :: 0x0436 -TB_SETDISABLEDIMAGELIST :: 0x0436 -TTM_SETTOOLINFOW :: 0x0436 -EM_EXSETSEL :: 0x0437 -TB_GETDISABLEDIMAGELIST :: 0x0437 -TTM_HITTESTW :: 0x0437 -EM_FINDTEXT :: 0x0438 -TB_SETSTYLE :: 0x0438 -TTM_GETTEXTW :: 0x0438 -EM_FORMATRANGE :: 0x0439 -TB_GETSTYLE :: 0x0439 -TTM_UPDATETIPTEXTW :: 0x0439 -EM_GETCHARFORMAT :: 0x043a -TB_GETBUTTONSIZE :: 0x043a -TTM_ENUMTOOLSW :: 0x043a -EM_GETEVENTMASK :: 0x043b -TB_SETBUTTONWIDTH :: 0x043b -TTM_GETCURRENTTOOLW :: 0x043b -EM_GETOLEINTERFACE :: 0x043c -TB_SETMAXTEXTROWS :: 0x043c -EM_GETPARAFORMAT :: 0x043d -TB_GETTEXTROWS :: 0x043d -EM_GETSELTEXT :: 0x043e -TB_GETOBJECT :: 0x043e -EM_HIDESELECTION :: 0x043f -TB_GETBUTTONINFOW :: 0x043f -EM_PASTESPECIAL :: 0x0440 -TB_SETBUTTONINFOW :: 0x0440 -EM_REQUESTRESIZE :: 0x0441 -TB_GETBUTTONINFOA :: 0x0441 -EM_SELECTIONTYPE :: 0x0442 -TB_SETBUTTONINFOA :: 0x0442 -EM_SETBKGNDCOLOR :: 0x0443 -TB_INSERTBUTTONW :: 0x0443 -EM_SETCHARFORMAT :: 0x0444 -TB_ADDBUTTONSW :: 0x0444 -EM_SETEVENTMASK :: 0x0445 -TB_HITTEST :: 0x0445 -EM_SETOLECALLBACK :: 0x0446 -TB_SETDRAWTEXTFLAGS :: 0x0446 -EM_SETPARAFORMAT :: 0x0447 -TB_GETHOTITEM :: 0x0447 -EM_SETTARGETDEVICE :: 0x0448 -TB_SETHOTITEM :: 0x0448 -EM_STREAMIN :: 0x0449 -TB_SETANCHORHIGHLIGHT :: 0x0449 -EM_STREAMOUT :: 0x044a -TB_GETANCHORHIGHLIGHT :: 0x044a -EM_GETTEXTRANGE :: 0x044b -TB_GETBUTTONTEXTW :: 0x044b -EM_FINDWORDBREAK :: 0x044c -TB_SAVERESTOREW :: 0x044c -EM_SETOPTIONS :: 0x044d -TB_ADDSTRINGW :: 0x044d -EM_GETOPTIONS :: 0x044e -TB_MAPACCELERATORA :: 0x044e -EM_FINDTEXTEX :: 0x044f -TB_GETINSERTMARK :: 0x044f -EM_GETWORDBREAKPROCEX :: 0x0450 -TB_SETINSERTMARK :: 0x0450 -EM_SETWORDBREAKPROCEX :: 0x0451 -TB_INSERTMARKHITTEST :: 0x0451 -EM_SETUNDOLIMIT :: 0x0452 -TB_MOVEBUTTON :: 0x0452 -TB_GETMAXSIZE :: 0x0453 -EM_REDO :: 0x0454 -TB_SETEXTENDEDSTYLE :: 0x0454 -EM_CANREDO :: 0x0455 -TB_GETEXTENDEDSTYLE :: 0x0455 -EM_GETUNDONAME :: 0x0456 -TB_GETPADDING :: 0x0456 -EM_GETREDONAME :: 0x0457 -TB_SETPADDING :: 0x0457 -EM_STOPGROUPTYPING :: 0x0458 -TB_SETINSERTMARKCOLOR :: 0x0458 -EM_SETTEXTMODE :: 0x0459 -TB_GETINSERTMARKCOLOR :: 0x0459 -EM_GETTEXTMODE :: 0x045a -TB_MAPACCELERATORW :: 0x045a -EM_AUTOURLDETECT :: 0x045b -TB_GETSTRINGW :: 0x045b -EM_GETAUTOURLDETECT :: 0x045c -TB_GETSTRINGA :: 0x045c -EM_SETPALETTE :: 0x045d -EM_GETTEXTEX :: 0x045e -EM_GETTEXTLENGTHEX :: 0x045f -EM_SHOWSCROLLBAR :: 0x0460 -EM_SETTEXTEX :: 0x0461 -TAPI_REPLY :: 0x0463 -ACM_OPENA :: 0x0464 -BFFM_SETSTATUSTEXTA :: 0x0464 -CDM_FIRST :: 0x0464 -CDM_GETSPEC :: 0x0464 -EM_SETPUNCTUATION :: 0x0464 -IPM_CLEARADDRESS :: 0x0464 -WM_CAP_UNICODE_START :: 0x0464 -ACM_PLAY :: 0x0465 -BFFM_ENABLEOK :: 0x0465 -CDM_GETFILEPATH :: 0x0465 -EM_GETPUNCTUATION :: 0x0465 -IPM_SETADDRESS :: 0x0465 -PSM_SETCURSEL :: 0x0465 -UDM_SETRANGE :: 0x0465 -WM_CHOOSEFONT_SETLOGFONT :: 0x0465 -ACM_STOP :: 0x0466 -BFFM_SETSELECTIONA :: 0x0466 -CDM_GETFOLDERPATH :: 0x0466 -EM_SETWORDWRAPMODE :: 0x0466 -IPM_GETADDRESS :: 0x0466 -PSM_REMOVEPAGE :: 0x0466 -UDM_GETRANGE :: 0x0466 -WM_CAP_SET_CALLBACK_ERRORW :: 0x0466 -WM_CHOOSEFONT_SETFLAGS :: 0x0466 -ACM_OPENW :: 0x0467 -BFFM_SETSELECTIONW :: 0x0467 -CDM_GETFOLDERIDLIST :: 0x0467 -EM_GETWORDWRAPMODE :: 0x0467 -IPM_SETRANGE :: 0x0467 -PSM_ADDPAGE :: 0x0467 -UDM_SETPOS :: 0x0467 -WM_CAP_SET_CALLBACK_STATUSW :: 0x0467 -BFFM_SETSTATUSTEXTW :: 0x0468 -CDM_SETCONTROLTEXT :: 0x0468 -EM_SETIMECOLOR :: 0x0468 -IPM_SETFOCUS :: 0x0468 -PSM_CHANGED :: 0x0468 -UDM_GETPOS :: 0x0468 -CDM_HIDECONTROL :: 0x0469 -EM_GETIMECOLOR :: 0x0469 -IPM_ISBLANK :: 0x0469 -PSM_RESTARTWINDOWS :: 0x0469 -UDM_SETBUDDY :: 0x0469 -CDM_SETDEFEXT :: 0x046a -EM_SETIMEOPTIONS :: 0x046a -PSM_REBOOTSYSTEM :: 0x046a -UDM_GETBUDDY :: 0x046a -EM_GETIMEOPTIONS :: 0x046b -PSM_CANCELTOCLOSE :: 0x046b -UDM_SETACCEL :: 0x046b -EM_CONVPOSITION :: 0x046c -PSM_QUERYSIBLINGS :: 0x046c -UDM_GETACCEL :: 0x046c -MCIWNDM_GETZOOM :: 0x046d -PSM_UNCHANGED :: 0x046d -UDM_SETBASE :: 0x046d -PSM_APPLY :: 0x046e -UDM_GETBASE :: 0x046e -PSM_SETTITLEA :: 0x046f -UDM_SETRANGE32 :: 0x046f -PSM_SETWIZBUTTONS :: 0x0470 -UDM_GETRANGE32 :: 0x0470 -WM_CAP_DRIVER_GET_NAMEW :: 0x0470 -PSM_PRESSBUTTON :: 0x0471 -UDM_SETPOS32 :: 0x0471 -WM_CAP_DRIVER_GET_VERSIONW :: 0x0471 -PSM_SETCURSELID :: 0x0472 -UDM_GETPOS32 :: 0x0472 -PSM_SETFINISHTEXTA :: 0x0473 -PSM_GETTABCONTROL :: 0x0474 -PSM_ISDIALOGMESSAGE :: 0x0475 -MCIWNDM_REALIZE :: 0x0476 -PSM_GETCURRENTPAGEHWND :: 0x0476 -MCIWNDM_SETTIMEFORMATA :: 0x0477 -PSM_INSERTPAGE :: 0x0477 -EM_SETLANGOPTIONS :: 0x0478 -MCIWNDM_GETTIMEFORMATA :: 0x0478 -PSM_SETTITLEW :: 0x0478 -WM_CAP_FILE_SET_CAPTURE_FILEW :: 0x0478 -EM_GETLANGOPTIONS :: 0x0479 -MCIWNDM_VALIDATEMEDIA :: 0x0479 -PSM_SETFINISHTEXTW :: 0x0479 -WM_CAP_FILE_GET_CAPTURE_FILEW :: 0x0479 -EM_GETIMECOMPMODE :: 0x047a -EM_FINDTEXTW :: 0x047b -MCIWNDM_PLAYTO :: 0x047b -WM_CAP_FILE_SAVEASW :: 0x047b -EM_FINDTEXTEXW :: 0x047c -MCIWNDM_GETFILENAMEA :: 0x047c -EM_RECONVERSION :: 0x047d -MCIWNDM_GETDEVICEA :: 0x047d -PSM_SETHEADERTITLEA :: 0x047d -WM_CAP_FILE_SAVEDIBW :: 0x047d -EM_SETIMEMODEBIAS :: 0x047e -MCIWNDM_GETPALETTE :: 0x047e -PSM_SETHEADERTITLEW :: 0x047e -EM_GETIMEMODEBIAS :: 0x047f -MCIWNDM_SETPALETTE :: 0x047f -PSM_SETHEADERSUBTITLEA :: 0x047f -MCIWNDM_GETERRORA :: 0x0480 -PSM_SETHEADERSUBTITLEW :: 0x0480 -PSM_HWNDTOINDEX :: 0x0481 -PSM_INDEXTOHWND :: 0x0482 -MCIWNDM_SETINACTIVETIMER :: 0x0483 -PSM_PAGETOINDEX :: 0x0483 -PSM_INDEXTOPAGE :: 0x0484 -DL_BEGINDRAG :: 0x0485 -MCIWNDM_GETINACTIVETIMER :: 0x0485 -PSM_IDTOINDEX :: 0x0485 -DL_DRAGGING :: 0x0486 -PSM_INDEXTOID :: 0x0486 -DL_DROPPED :: 0x0487 -PSM_GETRESULT :: 0x0487 -DL_CANCELDRAG :: 0x0488 -PSM_RECALCPAGESIZES :: 0x0488 -MCIWNDM_GET_SOURCE :: 0x048c -MCIWNDM_PUT_SOURCE :: 0x048d -MCIWNDM_GET_DEST :: 0x048e -MCIWNDM_PUT_DEST :: 0x048f -MCIWNDM_CAN_PLAY :: 0x0490 -MCIWNDM_CAN_WINDOW :: 0x0491 -MCIWNDM_CAN_RECORD :: 0x0492 -MCIWNDM_CAN_SAVE :: 0x0493 -MCIWNDM_CAN_EJECT :: 0x0494 -MCIWNDM_CAN_CONFIG :: 0x0495 -IE_GETINK :: 0x0496 -IE_MSGFIRST :: 0x0496 -MCIWNDM_PALETTEKICK :: 0x0496 -IE_SETINK :: 0x0497 -IE_GETPENTIP :: 0x0498 -IE_SETPENTIP :: 0x0499 -IE_GETERASERTIP :: 0x049a -IE_SETERASERTIP :: 0x049b -IE_GETBKGND :: 0x049c -IE_SETBKGND :: 0x049d -IE_GETGRIDORIGIN :: 0x049e -IE_SETGRIDORIGIN :: 0x049f -IE_GETGRIDPEN :: 0x04a0 -IE_SETGRIDPEN :: 0x04a1 -IE_GETGRIDSIZE :: 0x04a2 -IE_SETGRIDSIZE :: 0x04a3 -IE_GETMODE :: 0x04a4 -IE_SETMODE :: 0x04a5 -IE_GETINKRECT :: 0x04a6 -WM_CAP_SET_MCI_DEVICEW :: 0x04a6 -WM_CAP_GET_MCI_DEVICEW :: 0x04a7 -WM_CAP_PAL_OPENW :: 0x04b4 -WM_CAP_PAL_SAVEW :: 0x04b5 -IE_GETAPPDATA :: 0x04b8 -IE_SETAPPDATA :: 0x04b9 -IE_GETDRAWOPTS :: 0x04ba -IE_SETDRAWOPTS :: 0x04bb -IE_GETFORMAT :: 0x04bc -IE_SETFORMAT :: 0x04bd -IE_GETINKINPUT :: 0x04be -IE_SETINKINPUT :: 0x04bf -IE_GETNOTIFY :: 0x04c0 -IE_SETNOTIFY :: 0x04c1 -IE_GETRECOG :: 0x04c2 -IE_SETRECOG :: 0x04c3 -IE_GETSECURITY :: 0x04c4 -IE_SETSECURITY :: 0x04c5 -IE_GETSEL :: 0x04c6 -IE_SETSEL :: 0x04c7 -CDM_LAST :: 0x04c8 -EM_SETBIDIOPTIONS :: 0x04c8 -IE_DOCOMMAND :: 0x04c8 -MCIWNDM_NOTIFYMODE :: 0x04c8 -EM_GETBIDIOPTIONS :: 0x04c9 -IE_GETCOMMAND :: 0x04c9 -EM_SETTYPOGRAPHYOPTIONS :: 0x04ca -IE_GETCOUNT :: 0x04ca -EM_GETTYPOGRAPHYOPTIONS :: 0x04cb -IE_GETGESTURE :: 0x04cb -MCIWNDM_NOTIFYMEDIA :: 0x04cb -EM_SETEDITSTYLE :: 0x04cc -IE_GETMENU :: 0x04cc -EM_GETEDITSTYLE :: 0x04cd -IE_GETPAINTDC :: 0x04cd -MCIWNDM_NOTIFYERROR :: 0x04cd -IE_GETPDEVENT :: 0x04ce -IE_GETSELCOUNT :: 0x04cf -IE_GETSELITEMS :: 0x04d0 -IE_GETSTYLE :: 0x04d1 -MCIWNDM_SETTIMEFORMATW :: 0x04db -EM_OUTLINE :: 0x04dc -MCIWNDM_GETTIMEFORMATW :: 0x04dc -EM_GETSCROLLPOS :: 0x04dd -EM_SETSCROLLPOS :: 0x04de -EM_SETFONTSIZE :: 0x04df -EM_GETZOOM :: 0x04e0 -MCIWNDM_GETFILENAMEW :: 0x04e0 -EM_SETZOOM :: 0x04e1 -MCIWNDM_GETDEVICEW :: 0x04e1 -EM_GETVIEWKIND :: 0x04e2 -EM_SETVIEWKIND :: 0x04e3 -EM_GETPAGE :: 0x04e4 -MCIWNDM_GETERRORW :: 0x04e4 -EM_SETPAGE :: 0x04e5 -EM_GETHYPHENATEINFO :: 0x04e6 -EM_SETHYPHENATEINFO :: 0x04e7 -EM_GETPAGEROTATE :: 0x04eb -EM_SETPAGEROTATE :: 0x04ec -EM_GETCTFMODEBIAS :: 0x04ed -EM_SETCTFMODEBIAS :: 0x04ee -EM_GETCTFOPENSTATUS :: 0x04f0 -EM_SETCTFOPENSTATUS :: 0x04f1 -EM_GETIMECOMPTEXT :: 0x04f2 -EM_ISIME :: 0x04f3 -EM_GETIMEPROPERTY :: 0x04f4 -EM_GETQUERYRTFOBJ :: 0x050d -EM_SETQUERYRTFOBJ :: 0x050e -FM_GETFOCUS :: 0x0600 -FM_GETDRIVEINFOA :: 0x0601 -FM_GETSELCOUNT :: 0x0602 -FM_GETSELCOUNTLFN :: 0x0603 -FM_GETFILESELA :: 0x0604 -FM_GETFILESELLFNA :: 0x0605 -FM_REFRESH_WINDOWS :: 0x0606 -FM_RELOAD_EXTENSIONS :: 0x0607 -FM_GETDRIVEINFOW :: 0x0611 -FM_GETFILESELW :: 0x0614 -FM_GETFILESELLFNW :: 0x0615 -WLX_WM_SAS :: 0x0659 -SM_GETSELCOUNT :: 0x07e8 -UM_GETSELCOUNT :: 0x07e8 -WM_CPL_LAUNCH :: 0x07e8 -SM_GETSERVERSELA :: 0x07e9 -UM_GETUSERSELA :: 0x07e9 -WM_CPL_LAUNCHED :: 0x07e9 -SM_GETSERVERSELW :: 0x07ea -UM_GETUSERSELW :: 0x07ea -SM_GETCURFOCUSA :: 0x07eb -UM_GETGROUPSELA :: 0x07eb -SM_GETCURFOCUSW :: 0x07ec -UM_GETGROUPSELW :: 0x07ec -SM_GETOPTIONS :: 0x07ed -UM_GETCURFOCUSA :: 0x07ed -UM_GETCURFOCUSW :: 0x07ee -UM_GETOPTIONS :: 0x07ef -UM_GETOPTIONS2 :: 0x07f0 -LVM_FIRST :: 0x1000 -LVM_GETBKCOLOR :: 0x1000 -LVM_SETBKCOLOR :: 0x1001 -LVM_GETIMAGELIST :: 0x1002 -LVM_SETIMAGELIST :: 0x1003 -LVM_GETITEMCOUNT :: 0x1004 -LVM_GETITEMA :: 0x1005 -LVM_SETITEMA :: 0x1006 -LVM_INSERTITEMA :: 0x1007 -LVM_DELETEITEM :: 0x1008 -LVM_DELETEALLITEMS :: 0x1009 -LVM_GETCALLBACKMASK :: 0x100a -LVM_SETCALLBACKMASK :: 0x100b -LVM_GETNEXTITEM :: 0x100c -LVM_FINDITEMA :: 0x100d -LVM_GETITEMRECT :: 0x100e -LVM_SETITEMPOSITION :: 0x100f -LVM_GETITEMPOSITION :: 0x1010 -LVM_GETSTRINGWIDTHA :: 0x1011 -LVM_HITTEST :: 0x1012 -LVM_ENSUREVISIBLE :: 0x1013 -LVM_SCROLL :: 0x1014 -LVM_REDRAWITEMS :: 0x1015 -LVM_ARRANGE :: 0x1016 -LVM_EDITLABELA :: 0x1017 -LVM_GETEDITCONTROL :: 0x1018 -LVM_GETCOLUMNA :: 0x1019 -LVM_SETCOLUMNA :: 0x101a -LVM_INSERTCOLUMNA :: 0x101b -LVM_DELETECOLUMN :: 0x101c -LVM_GETCOLUMNWIDTH :: 0x101d -LVM_SETCOLUMNWIDTH :: 0x101e -LVM_GETHEADER :: 0x101f -LVM_CREATEDRAGIMAGE :: 0x1021 -LVM_GETVIEWRECT :: 0x1022 -LVM_GETTEXTCOLOR :: 0x1023 -LVM_SETTEXTCOLOR :: 0x1024 -LVM_GETTEXTBKCOLOR :: 0x1025 -LVM_SETTEXTBKCOLOR :: 0x1026 -LVM_GETTOPINDEX :: 0x1027 -LVM_GETCOUNTPERPAGE :: 0x1028 -LVM_GETORIGIN :: 0x1029 -LVM_UPDATE :: 0x102a -LVM_SETITEMSTATE :: 0x102b -LVM_GETITEMSTATE :: 0x102c -LVM_GETITEMTEXTA :: 0x102d -LVM_SETITEMTEXTA :: 0x102e -LVM_SETITEMCOUNT :: 0x102f -LVM_SORTITEMS :: 0x1030 -LVM_SETITEMPOSITION32 :: 0x1031 -LVM_GETSELECTEDCOUNT :: 0x1032 -LVM_GETITEMSPACING :: 0x1033 -LVM_GETISEARCHSTRINGA :: 0x1034 -LVM_SETICONSPACING :: 0x1035 -LVM_SETEXTENDEDLISTVIEWSTYLE :: 0x1036 -LVM_GETEXTENDEDLISTVIEWSTYLE :: 0x1037 -LVM_GETSUBITEMRECT :: 0x1038 -LVM_SUBITEMHITTEST :: 0x1039 -LVM_SETCOLUMNORDERARRAY :: 0x103a -LVM_GETCOLUMNORDERARRAY :: 0x103b -LVM_SETHOTITEM :: 0x103c -LVM_GETHOTITEM :: 0x103d -LVM_SETHOTCURSOR :: 0x103e -LVM_GETHOTCURSOR :: 0x103f -LVM_APPROXIMATEVIEWRECT :: 0x1040 -LVM_SETWORKAREAS :: 0x1041 -LVM_GETSELECTIONMARK :: 0x1042 -LVM_SETSELECTIONMARK :: 0x1043 -LVM_SETBKIMAGEA :: 0x1044 -LVM_GETBKIMAGEA :: 0x1045 -LVM_GETWORKAREAS :: 0x1046 -LVM_SETHOVERTIME :: 0x1047 -LVM_GETHOVERTIME :: 0x1048 -LVM_GETNUMBEROFWORKAREAS :: 0x1049 -LVM_SETTOOLTIPS :: 0x104a -LVM_GETITEMW :: 0x104b -LVM_SETITEMW :: 0x104c -LVM_INSERTITEMW :: 0x104d -LVM_GETTOOLTIPS :: 0x104e -LVM_FINDITEMW :: 0x1053 -LVM_GETSTRINGWIDTHW :: 0x1057 -LVM_GETCOLUMNW :: 0x105f -LVM_SETCOLUMNW :: 0x1060 -LVM_INSERTCOLUMNW :: 0x1061 -LVM_GETITEMTEXTW :: 0x1073 -LVM_SETITEMTEXTW :: 0x1074 -LVM_GETISEARCHSTRINGW :: 0x1075 -LVM_EDITLABELW :: 0x1076 -LVM_GETBKIMAGEW :: 0x108b -LVM_SETSELECTEDCOLUMN :: 0x108c -LVM_SETTILEWIDTH :: 0x108d -LVM_SETVIEW :: 0x108e -LVM_GETVIEW :: 0x108f -LVM_INSERTGROUP :: 0x1091 -LVM_SETGROUPINFO :: 0x1093 -LVM_GETGROUPINFO :: 0x1095 -LVM_REMOVEGROUP :: 0x1096 -LVM_MOVEGROUP :: 0x1097 -LVM_MOVEITEMTOGROUP :: 0x109a -LVM_SETGROUPMETRICS :: 0x109b -LVM_GETGROUPMETRICS :: 0x109c -LVM_ENABLEGROUPVIEW :: 0x109d -LVM_SORTGROUPS :: 0x109e -LVM_INSERTGROUPSORTED :: 0x109f -LVM_REMOVEALLGROUPS :: 0x10a0 -LVM_HASGROUP :: 0x10a1 -LVM_SETTILEVIEWINFO :: 0x10a2 -LVM_GETTILEVIEWINFO :: 0x10a3 -LVM_SETTILEINFO :: 0x10a4 -LVM_GETTILEINFO :: 0x10a5 -LVM_SETINSERTMARK :: 0x10a6 -LVM_GETINSERTMARK :: 0x10a7 -LVM_INSERTMARKHITTEST :: 0x10a8 -LVM_GETINSERTMARKRECT :: 0x10a9 -LVM_SETINSERTMARKCOLOR :: 0x10aa -LVM_GETINSERTMARKCOLOR :: 0x10ab -LVM_SETINFOTIP :: 0x10ad -LVM_GETSELECTEDCOLUMN :: 0x10ae -LVM_ISGROUPVIEWENABLED :: 0x10af -LVM_GETOUTLINECOLOR :: 0x10b0 -LVM_SETOUTLINECOLOR :: 0x10b1 -LVM_CANCELEDITLABEL :: 0x10b3 -LVM_MAPINDEXTOID :: 0x10b4 -LVM_MAPIDTOINDEX :: 0x10b5 -LVM_ISITEMVISIBLE :: 0x10b6 -LVM_GETEMPTYTEXT :: 0x10cc -LVM_GETFOOTERRECT :: 0x10cd -LVM_GETFOOTERINFO :: 0x10ce -LVM_GETFOOTERITEMRECT :: 0x10cf -LVM_GETFOOTERITEM :: 0x10d0 -LVM_GETITEMINDEXRECT :: 0x10d1 -LVM_SETITEMINDEXSTATE :: 0x10d2 -LVM_GETNEXTITEMINDEX :: 0x10d3 -OCM__BASE :: 0x2000 -LVM_SETUNICODEFORMAT :: 0x2005 -LVM_GETUNICODEFORMAT :: 0x2006 -OCM_CTLCOLOR :: 0x2019 -OCM_DRAWITEM :: 0x202b -OCM_MEASUREITEM :: 0x202c -OCM_DELETEITEM :: 0x202d -OCM_VKEYTOITEM :: 0x202e -OCM_CHARTOITEM :: 0x202f -OCM_COMPAREITEM :: 0x2039 -OCM_NOTIFY :: 0x204e -OCM_COMMAND :: 0x2111 -OCM_HSCROLL :: 0x2114 -OCM_VSCROLL :: 0x2115 -OCM_CTLCOLORMSGBOX :: 0x2132 -OCM_CTLCOLOREDIT :: 0x2133 -OCM_CTLCOLORLISTBOX :: 0x2134 -OCM_CTLCOLORBTN :: 0x2135 -OCM_CTLCOLORDLG :: 0x2136 -OCM_CTLCOLORSCROLLBAR :: 0x2137 -OCM_CTLCOLORSTATIC :: 0x2138 -OCM_PARENTNOTIFY :: 0x2210 -WM_APP :: 0x8000 +package sys_windows + +WM_NULL :: 0x0000 +WM_CREATE :: 0x0001 +WM_DESTROY :: 0x0002 +WM_MOVE :: 0x0003 +WM_SIZE :: 0x0005 +WM_ACTIVATE :: 0x0006 +WM_SETFOCUS :: 0x0007 +WM_KILLFOCUS :: 0x0008 +WM_ENABLE :: 0x000a +WM_SETREDRAW :: 0x000b +WM_SETTEXT :: 0x000c +WM_GETTEXT :: 0x000d +WM_GETTEXTLENGTH :: 0x000e +WM_PAINT :: 0x000f +WM_CLOSE :: 0x0010 +WM_QUERYENDSESSION :: 0x0011 +WM_QUIT :: 0x0012 +WM_QUERYOPEN :: 0x0013 +WM_ERASEBKGND :: 0x0014 +WM_SYSCOLORCHANGE :: 0x0015 +WM_ENDSESSION :: 0x0016 +WM_SHOWWINDOW :: 0x0018 +WM_CTLCOLOR :: 0x0019 +WM_WININICHANGE :: 0x001a +WM_DEVMODECHANGE :: 0x001b +WM_ACTIVATEAPP :: 0x001c +WM_FONTCHANGE :: 0x001d +WM_TIMECHANGE :: 0x001e +WM_CANCELMODE :: 0x001f +WM_SETCURSOR :: 0x0020 +WM_MOUSEACTIVATE :: 0x0021 +WM_CHILDACTIVATE :: 0x0022 +WM_QUEUESYNC :: 0x0023 +WM_GETMINMAXINFO :: 0x0024 +WM_PAINTICON :: 0x0026 +WM_ICONERASEBKGND :: 0x0027 +WM_NEXTDLGCTL :: 0x0028 +WM_SPOOLERSTATUS :: 0x002a +WM_DRAWITEM :: 0x002b +WM_MEASUREITEM :: 0x002c +WM_DELETEITEM :: 0x002d +WM_VKEYTOITEM :: 0x002e +WM_CHARTOITEM :: 0x002f +WM_SETFONT :: 0x0030 +WM_GETFONT :: 0x0031 +WM_SETHOTKEY :: 0x0032 +WM_GETHOTKEY :: 0x0033 +WM_QUERYDRAGICON :: 0x0037 +WM_COMPAREITEM :: 0x0039 +WM_GETOBJECT :: 0x003d +WM_COMPACTING :: 0x0041 +WM_COMMNOTIFY :: 0x0044 +WM_WINDOWPOSCHANGING :: 0x0046 +WM_WINDOWPOSCHANGED :: 0x0047 +WM_POWER :: 0x0048 +WM_COPYGLOBALDATA :: 0x0049 +WM_COPYDATA :: 0x004a +WM_CANCELJOURNAL :: 0x004b +WM_NOTIFY :: 0x004e +WM_INPUTLANGCHANGEREQUEST :: 0x0050 +WM_INPUTLANGCHANGE :: 0x0051 +WM_TCARD :: 0x0052 +WM_HELP :: 0x0053 +WM_USERCHANGED :: 0x0054 +WM_NOTIFYFORMAT :: 0x0055 +WM_CONTEXTMENU :: 0x007b +WM_STYLECHANGING :: 0x007c +WM_STYLECHANGED :: 0x007d +WM_DISPLAYCHANGE :: 0x007e +WM_GETICON :: 0x007f +WM_SETICON :: 0x0080 +WM_NCCREATE :: 0x0081 +WM_NCDESTROY :: 0x0082 +WM_NCCALCSIZE :: 0x0083 +WM_NCHITTEST :: 0x0084 +WM_NCPAINT :: 0x0085 +WM_NCACTIVATE :: 0x0086 +WM_GETDLGCODE :: 0x0087 +WM_SYNCPAINT :: 0x0088 +WM_NCMOUSEMOVE :: 0x00a0 +WM_NCLBUTTONDOWN :: 0x00a1 +WM_NCLBUTTONUP :: 0x00a2 +WM_NCLBUTTONDBLCLK :: 0x00a3 +WM_NCRBUTTONDOWN :: 0x00a4 +WM_NCRBUTTONUP :: 0x00a5 +WM_NCRBUTTONDBLCLK :: 0x00a6 +WM_NCMBUTTONDOWN :: 0x00a7 +WM_NCMBUTTONUP :: 0x00a8 +WM_NCMBUTTONDBLCLK :: 0x00a9 +WM_NCXBUTTONDOWN :: 0x00ab +WM_NCXBUTTONUP :: 0x00ac +WM_NCXBUTTONDBLCLK :: 0x00ad +EM_GETSEL :: 0x00b0 +EM_SETSEL :: 0x00b1 +EM_GETRECT :: 0x00b2 +EM_SETRECT :: 0x00b3 +EM_SETRECTNP :: 0x00b4 +EM_SCROLL :: 0x00b5 +EM_LINESCROLL :: 0x00b6 +EM_SCROLLCARET :: 0x00b7 +EM_GETMODIFY :: 0x00b8 +EM_SETMODIFY :: 0x00b9 +EM_GETLINECOUNT :: 0x00ba +EM_LINEINDEX :: 0x00bb +EM_SETHANDLE :: 0x00bc +EM_GETHANDLE :: 0x00bd +EM_GETTHUMB :: 0x00be +EM_LINELENGTH :: 0x00c1 +EM_REPLACESEL :: 0x00c2 +EM_SETFONT :: 0x00c3 +EM_GETLINE :: 0x00c4 +EM_LIMITTEXT :: 0x00c5 +EM_SETLIMITTEXT :: 0x00c5 +EM_CANUNDO :: 0x00c6 +EM_UNDO :: 0x00c7 +EM_FMTLINES :: 0x00c8 +EM_LINEFROMCHAR :: 0x00c9 +EM_SETWORDBREAK :: 0x00ca +EM_SETTABSTOPS :: 0x00cb +EM_SETPASSWORDCHAR :: 0x00cc +EM_EMPTYUNDOBUFFER :: 0x00cd +EM_GETFIRSTVISIBLELINE :: 0x00ce +EM_SETREADONLY :: 0x00cf +EM_SETWORDBREAKPROC :: 0x00d0 +EM_GETWORDBREAKPROC :: 0x00d1 +EM_GETPASSWORDCHAR :: 0x00d2 +EM_SETMARGINS :: 0x00d3 +EM_GETMARGINS :: 0x00d4 +EM_GETLIMITTEXT :: 0x00d5 +EM_POSFROMCHAR :: 0x00d6 +EM_CHARFROMPOS :: 0x00d7 +EM_SETIMESTATUS :: 0x00d8 +EM_GETIMESTATUS :: 0x00d9 +SBM_SETPOS :: 0x00e0 +SBM_GETPOS :: 0x00e1 +SBM_SETRANGE :: 0x00e2 +SBM_GETRANGE :: 0x00e3 +SBM_ENABLE_ARROWS :: 0x00e4 +SBM_SETRANGEREDRAW :: 0x00e6 +SBM_SETSCROLLINFO :: 0x00e9 +SBM_GETSCROLLINFO :: 0x00ea +SBM_GETSCROLLBARINFO :: 0x00eb +BM_GETCHECK :: 0x00f0 +BM_SETCHECK :: 0x00f1 +BM_GETSTATE :: 0x00f2 +BM_SETSTATE :: 0x00f3 +BM_SETSTYLE :: 0x00f4 +BM_CLICK :: 0x00f5 +BM_GETIMAGE :: 0x00f6 +BM_SETIMAGE :: 0x00f7 +BM_SETDONTCLICK :: 0x00f8 +WM_INPUT :: 0x00ff +WM_KEYDOWN :: 0x0100 +WM_KEYFIRST :: 0x0100 +WM_KEYUP :: 0x0101 +WM_CHAR :: 0x0102 +WM_DEADCHAR :: 0x0103 +WM_SYSKEYDOWN :: 0x0104 +WM_SYSKEYUP :: 0x0105 +WM_SYSCHAR :: 0x0106 +WM_SYSDEADCHAR :: 0x0107 +WM_UNICHAR :: 0x0109 +WM_KEYLAST :: 0x0109 +WM_WNT_CONVERTREQUESTEX :: 0x0109 +WM_CONVERTREQUEST :: 0x010a +WM_CONVERTRESULT :: 0x010b +WM_INTERIM :: 0x010c +WM_IME_STARTCOMPOSITION :: 0x010d +WM_IME_ENDCOMPOSITION :: 0x010e +WM_IME_COMPOSITION :: 0x010f +WM_IME_KEYLAST :: 0x010f +WM_INITDIALOG :: 0x0110 +WM_COMMAND :: 0x0111 +WM_SYSCOMMAND :: 0x0112 +WM_TIMER :: 0x0113 +WM_HSCROLL :: 0x0114 +WM_VSCROLL :: 0x0115 +WM_INITMENU :: 0x0116 +WM_INITMENUPOPUP :: 0x0117 +WM_SYSTIMER :: 0x0118 +WM_MENUSELECT :: 0x011f +WM_MENUCHAR :: 0x0120 +WM_ENTERIDLE :: 0x0121 +WM_MENURBUTTONUP :: 0x0122 +WM_MENUDRAG :: 0x0123 +WM_MENUGETOBJECT :: 0x0124 +WM_UNINITMENUPOPUP :: 0x0125 +WM_MENUCOMMAND :: 0x0126 +WM_CHANGEUISTATE :: 0x0127 +WM_UPDATEUISTATE :: 0x0128 +WM_QUERYUISTATE :: 0x0129 +WM_LBTRACKPOINT :: 0x0131 +WM_CTLCOLORMSGBOX :: 0x0132 +WM_CTLCOLOREDIT :: 0x0133 +WM_CTLCOLORLISTBOX :: 0x0134 +WM_CTLCOLORBTN :: 0x0135 +WM_CTLCOLORDLG :: 0x0136 +WM_CTLCOLORSCROLLBAR :: 0x0137 +WM_CTLCOLORSTATIC :: 0x0138 +CB_GETEDITSEL :: 0x0140 +CB_LIMITTEXT :: 0x0141 +CB_SETEDITSEL :: 0x0142 +CB_ADDSTRING :: 0x0143 +CB_DELETESTRING :: 0x0144 +CB_DIR :: 0x0145 +CB_GETCOUNT :: 0x0146 +CB_GETCURSEL :: 0x0147 +CB_GETLBTEXT :: 0x0148 +CB_GETLBTEXTLEN :: 0x0149 +CB_INSERTSTRING :: 0x014a +CB_RESETCONTENT :: 0x014b +CB_FINDSTRING :: 0x014c +CB_SELECTSTRING :: 0x014d +CB_SETCURSEL :: 0x014e +CB_SHOWDROPDOWN :: 0x014f +CB_GETITEMDATA :: 0x0150 +CB_SETITEMDATA :: 0x0151 +CB_GETDROPPEDCONTROLRECT :: 0x0152 +CB_SETITEMHEIGHT :: 0x0153 +CB_GETITEMHEIGHT :: 0x0154 +CB_SETEXTENDEDUI :: 0x0155 +CB_GETEXTENDEDUI :: 0x0156 +CB_GETDROPPEDSTATE :: 0x0157 +CB_FINDSTRINGEXACT :: 0x0158 +CB_SETLOCALE :: 0x0159 +CB_GETLOCALE :: 0x015a +CB_GETTOPINDEX :: 0x015b +CB_SETTOPINDEX :: 0x015c +CB_GETHORIZONTALEXTENT :: 0x015d +CB_SETHORIZONTALEXTENT :: 0x015e +CB_GETDROPPEDWIDTH :: 0x015f +CB_SETDROPPEDWIDTH :: 0x0160 +CB_INITSTORAGE :: 0x0161 +CB_MULTIPLEADDSTRING :: 0x0163 +CB_GETCOMBOBOXINFO :: 0x0164 +CB_MSGMAX :: 0x0165 +WM_MOUSEFIRST :: 0x0200 +WM_MOUSEMOVE :: 0x0200 +WM_LBUTTONDOWN :: 0x0201 +WM_LBUTTONUP :: 0x0202 +WM_LBUTTONDBLCLK :: 0x0203 +WM_RBUTTONDOWN :: 0x0204 +WM_RBUTTONUP :: 0x0205 +WM_RBUTTONDBLCLK :: 0x0206 +WM_MBUTTONDOWN :: 0x0207 +WM_MBUTTONUP :: 0x0208 +WM_MBUTTONDBLCLK :: 0x0209 +WM_MOUSELAST :: 0x0209 +WM_MOUSEWHEEL :: 0x020a +WM_XBUTTONDOWN :: 0x020b +WM_XBUTTONUP :: 0x020c +WM_XBUTTONDBLCLK :: 0x020d +WM_MOUSEHWHEEL :: 0x020e +WM_PARENTNOTIFY :: 0x0210 +WM_ENTERMENULOOP :: 0x0211 +WM_EXITMENULOOP :: 0x0212 +WM_NEXTMENU :: 0x0213 +WM_SIZING :: 0x0214 +WM_CAPTURECHANGED :: 0x0215 +WM_MOVING :: 0x0216 +WM_POWERBROADCAST :: 0x0218 +WM_DEVICECHANGE :: 0x0219 +WM_MDICREATE :: 0x0220 +WM_MDIDESTROY :: 0x0221 +WM_MDIACTIVATE :: 0x0222 +WM_MDIRESTORE :: 0x0223 +WM_MDINEXT :: 0x0224 +WM_MDIMAXIMIZE :: 0x0225 +WM_MDITILE :: 0x0226 +WM_MDICASCADE :: 0x0227 +WM_MDIICONARRANGE :: 0x0228 +WM_MDIGETACTIVE :: 0x0229 +WM_MDISETMENU :: 0x0230 +WM_ENTERSIZEMOVE :: 0x0231 +WM_EXITSIZEMOVE :: 0x0232 +WM_DROPFILES :: 0x0233 +WM_MDIREFRESHMENU :: 0x0234 +WM_IME_REPORT :: 0x0280 +WM_IME_SETCONTEXT :: 0x0281 +WM_IME_NOTIFY :: 0x0282 +WM_IME_CONTROL :: 0x0283 +WM_IME_COMPOSITIONFULL :: 0x0284 +WM_IME_SELECT :: 0x0285 +WM_IME_CHAR :: 0x0286 +WM_IME_REQUEST :: 0x0288 +WM_IMEKEYDOWN :: 0x0290 +WM_IME_KEYDOWN :: 0x0290 +WM_IMEKEYUP :: 0x0291 +WM_IME_KEYUP :: 0x0291 +WM_NCMOUSEHOVER :: 0x02a0 +WM_MOUSEHOVER :: 0x02a1 +WM_NCMOUSELEAVE :: 0x02a2 +WM_MOUSELEAVE :: 0x02a3 +WM_CUT :: 0x0300 +WM_COPY :: 0x0301 +WM_PASTE :: 0x0302 +WM_CLEAR :: 0x0303 +WM_UNDO :: 0x0304 +WM_RENDERFORMAT :: 0x0305 +WM_RENDERALLFORMATS :: 0x0306 +WM_DESTROYCLIPBOARD :: 0x0307 +WM_DRAWCLIPBOARD :: 0x0308 +WM_PAINTCLIPBOARD :: 0x0309 +WM_VSCROLLCLIPBOARD :: 0x030a +WM_SIZECLIPBOARD :: 0x030b +WM_ASKCBFORMATNAME :: 0x030c +WM_CHANGECBCHAIN :: 0x030d +WM_HSCROLLCLIPBOARD :: 0x030e +WM_QUERYNEWPALETTE :: 0x030f +WM_PALETTEISCHANGING :: 0x0310 +WM_PALETTECHANGED :: 0x0311 +WM_HOTKEY :: 0x0312 +WM_PRINT :: 0x0317 +WM_PRINTCLIENT :: 0x0318 +WM_APPCOMMAND :: 0x0319 +WM_HANDHELDFIRST :: 0x0358 +WM_HANDHELDLAST :: 0x035f +WM_AFXFIRST :: 0x0360 +WM_AFXLAST :: 0x037f +WM_PENWINFIRST :: 0x0380 +WM_RCRESULT :: 0x0381 +WM_HOOKRCRESULT :: 0x0382 +WM_GLOBALRCCHANGE :: 0x0383 +WM_PENMISCINFO :: 0x0383 +WM_SKB :: 0x0384 +WM_HEDITCTL :: 0x0385 +WM_PENCTL :: 0x0385 +WM_PENMISC :: 0x0386 +WM_CTLINIT :: 0x0387 +WM_PENEVENT :: 0x0388 +WM_PENWINLAST :: 0x038f +DDM_SETFMT :: 0x0400 +DM_GETDEFID :: 0x0400 +NIN_SELECT :: 0x0400 +TBM_GETPOS :: 0x0400 +WM_PSD_PAGESETUPDLG :: 0x0400 +WM_USER :: 0x0400 +CBEM_INSERTITEMA :: 0x0401 +DDM_DRAW :: 0x0401 +DM_SETDEFID :: 0x0401 +HKM_SETHOTKEY :: 0x0401 +PBM_SETRANGE :: 0x0401 +RB_INSERTBANDA :: 0x0401 +SB_SETTEXTA :: 0x0401 +TB_ENABLEBUTTON :: 0x0401 +TBM_GETRANGEMIN :: 0x0401 +TTM_ACTIVATE :: 0x0401 +WM_CHOOSEFONT_GETLOGFONT :: 0x0401 +WM_PSD_FULLPAGERECT :: 0x0401 +CBEM_SETIMAGELIST :: 0x0402 +DDM_CLOSE :: 0x0402 +DM_REPOSITION :: 0x0402 +HKM_GETHOTKEY :: 0x0402 +PBM_SETPOS :: 0x0402 +RB_DELETEBAND :: 0x0402 +SB_GETTEXTA :: 0x0402 +TB_CHECKBUTTON :: 0x0402 +TBM_GETRANGEMAX :: 0x0402 +WM_PSD_MINMARGINRECT :: 0x0402 +CBEM_GETIMAGELIST :: 0x0403 +DDM_BEGIN :: 0x0403 +HKM_SETRULES :: 0x0403 +PBM_DELTAPOS :: 0x0403 +RB_GETBARINFO :: 0x0403 +SB_GETTEXTLENGTHA :: 0x0403 +TBM_GETTIC :: 0x0403 +TB_PRESSBUTTON :: 0x0403 +TTM_SETDELAYTIME :: 0x0403 +WM_PSD_MARGINRECT :: 0x0403 +CBEM_GETITEMA :: 0x0404 +DDM_END :: 0x0404 +PBM_SETSTEP :: 0x0404 +RB_SETBARINFO :: 0x0404 +SB_SETPARTS :: 0x0404 +TB_HIDEBUTTON :: 0x0404 +TBM_SETTIC :: 0x0404 +TTM_ADDTOOLA :: 0x0404 +WM_PSD_GREEKTEXTRECT :: 0x0404 +CBEM_SETITEMA :: 0x0405 +PBM_STEPIT :: 0x0405 +TB_INDETERMINATE :: 0x0405 +TBM_SETPOS :: 0x0405 +TTM_DELTOOLA :: 0x0405 +WM_PSD_ENVSTAMPRECT :: 0x0405 +CBEM_GETCOMBOCONTROL :: 0x0406 +PBM_SETRANGE32 :: 0x0406 +RB_SETBANDINFOA :: 0x0406 +SB_GETPARTS :: 0x0406 +TB_MARKBUTTON :: 0x0406 +TBM_SETRANGE :: 0x0406 +TTM_NEWTOOLRECTA :: 0x0406 +WM_PSD_YAFULLPAGERECT :: 0x0406 +CBEM_GETEDITCONTROL :: 0x0407 +PBM_GETRANGE :: 0x0407 +RB_SETPARENT :: 0x0407 +SB_GETBORDERS :: 0x0407 +TBM_SETRANGEMIN :: 0x0407 +TTM_RELAYEVENT :: 0x0407 +CBEM_SETEXSTYLE :: 0x0408 +PBM_GETPOS :: 0x0408 +RB_HITTEST :: 0x0408 +SB_SETMINHEIGHT :: 0x0408 +TBM_SETRANGEMAX :: 0x0408 +TTM_GETTOOLINFOA :: 0x0408 +CBEM_GETEXSTYLE :: 0x0409 +CBEM_GETEXTENDEDSTYLE :: 0x0409 +PBM_SETBARCOLOR :: 0x0409 +RB_GETRECT :: 0x0409 +SB_SIMPLE :: 0x0409 +TB_ISBUTTONENABLED :: 0x0409 +TBM_CLEARTICS :: 0x0409 +TTM_SETTOOLINFOA :: 0x0409 +CBEM_HASEDITCHANGED :: 0x040a +RB_INSERTBANDW :: 0x040a +SB_GETRECT :: 0x040a +TB_ISBUTTONCHECKED :: 0x040a +TBM_SETSEL :: 0x040a +TTM_HITTESTA :: 0x040a +WIZ_QUERYNUMPAGES :: 0x040a +CBEM_INSERTITEMW :: 0x040b +RB_SETBANDINFOW :: 0x040b +SB_SETTEXTW :: 0x040b +TB_ISBUTTONPRESSED :: 0x040b +TBM_SETSELSTART :: 0x040b +TTM_GETTEXTA :: 0x040b +WIZ_NEXT :: 0x040b +CBEM_SETITEMW :: 0x040c +RB_GETBANDCOUNT :: 0x040c +SB_GETTEXTLENGTHW :: 0x040c +TB_ISBUTTONHIDDEN :: 0x040c +TBM_SETSELEND :: 0x040c +TTM_UPDATETIPTEXTA :: 0x040c +WIZ_PREV :: 0x040c +CBEM_GETITEMW :: 0x040d +RB_GETROWCOUNT :: 0x040d +SB_GETTEXTW :: 0x040d +TB_ISBUTTONINDETERMINATE :: 0x040d +TTM_GETTOOLCOUNT :: 0x040d +CBEM_SETEXTENDEDSTYLE :: 0x040e +RB_GETROWHEIGHT :: 0x040e +SB_ISSIMPLE :: 0x040e +TB_ISBUTTONHIGHLIGHTED :: 0x040e +TBM_GETPTICS :: 0x040e +TTM_ENUMTOOLSA :: 0x040e +SB_SETICON :: 0x040f +TBM_GETTICPOS :: 0x040f +TTM_GETCURRENTTOOLA :: 0x040f +RB_IDTOINDEX :: 0x0410 +SB_SETTIPTEXTA :: 0x0410 +TBM_GETNUMTICS :: 0x0410 +TTM_WINDOWFROMPOINT :: 0x0410 +RB_GETTOOLTIPS :: 0x0411 +SB_SETTIPTEXTW :: 0x0411 +TBM_GETSELSTART :: 0x0411 +TB_SETSTATE :: 0x0411 +TTM_TRACKACTIVATE :: 0x0411 +RB_SETTOOLTIPS :: 0x0412 +SB_GETTIPTEXTA :: 0x0412 +TB_GETSTATE :: 0x0412 +TBM_GETSELEND :: 0x0412 +TTM_TRACKPOSITION :: 0x0412 +RB_SETBKCOLOR :: 0x0413 +SB_GETTIPTEXTW :: 0x0413 +TB_ADDBITMAP :: 0x0413 +TBM_CLEARSEL :: 0x0413 +TTM_SETTIPBKCOLOR :: 0x0413 +RB_GETBKCOLOR :: 0x0414 +SB_GETICON :: 0x0414 +TB_ADDBUTTONSA :: 0x0414 +TBM_SETTICFREQ :: 0x0414 +TTM_SETTIPTEXTCOLOR :: 0x0414 +RB_SETTEXTCOLOR :: 0x0415 +TB_INSERTBUTTONA :: 0x0415 +TBM_SETPAGESIZE :: 0x0415 +TTM_GETDELAYTIME :: 0x0415 +RB_GETTEXTCOLOR :: 0x0416 +TB_DELETEBUTTON :: 0x0416 +TBM_GETPAGESIZE :: 0x0416 +TTM_GETTIPBKCOLOR :: 0x0416 +RB_SIZETORECT :: 0x0417 +TB_GETBUTTON :: 0x0417 +TBM_SETLINESIZE :: 0x0417 +TTM_GETTIPTEXTCOLOR :: 0x0417 +RB_BEGINDRAG :: 0x0418 +TB_BUTTONCOUNT :: 0x0418 +TBM_GETLINESIZE :: 0x0418 +TTM_SETMAXTIPWIDTH :: 0x0418 +RB_ENDDRAG :: 0x0419 +TB_COMMANDTOINDEX :: 0x0419 +TBM_GETTHUMBRECT :: 0x0419 +TTM_GETMAXTIPWIDTH :: 0x0419 +RB_DRAGMOVE :: 0x041a +TBM_GETCHANNELRECT :: 0x041a +TB_SAVERESTOREA :: 0x041a +TTM_SETMARGIN :: 0x041a +RB_GETBARHEIGHT :: 0x041b +TB_CUSTOMIZE :: 0x041b +TBM_SETTHUMBLENGTH :: 0x041b +TTM_GETMARGIN :: 0x041b +RB_GETBANDINFOW :: 0x041c +TB_ADDSTRINGA :: 0x041c +TBM_GETTHUMBLENGTH :: 0x041c +TTM_POP :: 0x041c +RB_GETBANDINFOA :: 0x041d +TB_GETITEMRECT :: 0x041d +TBM_SETTOOLTIPS :: 0x041d +TTM_UPDATE :: 0x041d +RB_MINIMIZEBAND :: 0x041e +TB_BUTTONSTRUCTSIZE :: 0x041e +TBM_GETTOOLTIPS :: 0x041e +TTM_GETBUBBLESIZE :: 0x041e +RB_MAXIMIZEBAND :: 0x041f +TBM_SETTIPSIDE :: 0x041f +TB_SETBUTTONSIZE :: 0x041f +TTM_ADJUSTRECT :: 0x041f +TBM_SETBUDDY :: 0x0420 +TB_SETBITMAPSIZE :: 0x0420 +TTM_SETTITLEA :: 0x0420 +MSG_FTS_JUMP_VA :: 0x0421 +TB_AUTOSIZE :: 0x0421 +TBM_GETBUDDY :: 0x0421 +TTM_SETTITLEW :: 0x0421 +RB_GETBANDBORDERS :: 0x0422 +MSG_FTS_JUMP_QWORD :: 0x0423 +RB_SHOWBAND :: 0x0423 +TB_GETTOOLTIPS :: 0x0423 +MSG_REINDEX_REQUEST :: 0x0424 +TB_SETTOOLTIPS :: 0x0424 +MSG_FTS_WHERE_IS_IT :: 0x0425 +RB_SETPALETTE :: 0x0425 +TB_SETPARENT :: 0x0425 +RB_GETPALETTE :: 0x0426 +RB_MOVEBAND :: 0x0427 +TB_SETROWS :: 0x0427 +TB_GETROWS :: 0x0428 +TB_GETBITMAPFLAGS :: 0x0429 +TB_SETCMDID :: 0x042a +RB_PUSHCHEVRON :: 0x042b +TB_CHANGEBITMAP :: 0x042b +TB_GETBITMAP :: 0x042c +MSG_GET_DEFFONT :: 0x042d +TB_GETBUTTONTEXTA :: 0x042d +TB_REPLACEBITMAP :: 0x042e +TB_SETINDENT :: 0x042f +TB_SETIMAGELIST :: 0x0430 +TB_GETIMAGELIST :: 0x0431 +TB_LOADIMAGES :: 0x0432 +EM_CANPASTE :: 0x0432 +TTM_ADDTOOLW :: 0x0432 +EM_DISPLAYBAND :: 0x0433 +TB_GETRECT :: 0x0433 +TTM_DELTOOLW :: 0x0433 +EM_EXGETSEL :: 0x0434 +TB_SETHOTIMAGELIST :: 0x0434 +TTM_NEWTOOLRECTW :: 0x0434 +EM_EXLIMITTEXT :: 0x0435 +TB_GETHOTIMAGELIST :: 0x0435 +TTM_GETTOOLINFOW :: 0x0435 +EM_EXLINEFROMCHAR :: 0x0436 +TB_SETDISABLEDIMAGELIST :: 0x0436 +TTM_SETTOOLINFOW :: 0x0436 +EM_EXSETSEL :: 0x0437 +TB_GETDISABLEDIMAGELIST :: 0x0437 +TTM_HITTESTW :: 0x0437 +EM_FINDTEXT :: 0x0438 +TB_SETSTYLE :: 0x0438 +TTM_GETTEXTW :: 0x0438 +EM_FORMATRANGE :: 0x0439 +TB_GETSTYLE :: 0x0439 +TTM_UPDATETIPTEXTW :: 0x0439 +EM_GETCHARFORMAT :: 0x043a +TB_GETBUTTONSIZE :: 0x043a +TTM_ENUMTOOLSW :: 0x043a +EM_GETEVENTMASK :: 0x043b +TB_SETBUTTONWIDTH :: 0x043b +TTM_GETCURRENTTOOLW :: 0x043b +EM_GETOLEINTERFACE :: 0x043c +TB_SETMAXTEXTROWS :: 0x043c +EM_GETPARAFORMAT :: 0x043d +TB_GETTEXTROWS :: 0x043d +EM_GETSELTEXT :: 0x043e +TB_GETOBJECT :: 0x043e +EM_HIDESELECTION :: 0x043f +TB_GETBUTTONINFOW :: 0x043f +EM_PASTESPECIAL :: 0x0440 +TB_SETBUTTONINFOW :: 0x0440 +EM_REQUESTRESIZE :: 0x0441 +TB_GETBUTTONINFOA :: 0x0441 +EM_SELECTIONTYPE :: 0x0442 +TB_SETBUTTONINFOA :: 0x0442 +EM_SETBKGNDCOLOR :: 0x0443 +TB_INSERTBUTTONW :: 0x0443 +EM_SETCHARFORMAT :: 0x0444 +TB_ADDBUTTONSW :: 0x0444 +EM_SETEVENTMASK :: 0x0445 +TB_HITTEST :: 0x0445 +EM_SETOLECALLBACK :: 0x0446 +TB_SETDRAWTEXTFLAGS :: 0x0446 +EM_SETPARAFORMAT :: 0x0447 +TB_GETHOTITEM :: 0x0447 +EM_SETTARGETDEVICE :: 0x0448 +TB_SETHOTITEM :: 0x0448 +EM_STREAMIN :: 0x0449 +TB_SETANCHORHIGHLIGHT :: 0x0449 +EM_STREAMOUT :: 0x044a +TB_GETANCHORHIGHLIGHT :: 0x044a +EM_GETTEXTRANGE :: 0x044b +TB_GETBUTTONTEXTW :: 0x044b +EM_FINDWORDBREAK :: 0x044c +TB_SAVERESTOREW :: 0x044c +EM_SETOPTIONS :: 0x044d +TB_ADDSTRINGW :: 0x044d +EM_GETOPTIONS :: 0x044e +TB_MAPACCELERATORA :: 0x044e +EM_FINDTEXTEX :: 0x044f +TB_GETINSERTMARK :: 0x044f +EM_GETWORDBREAKPROCEX :: 0x0450 +TB_SETINSERTMARK :: 0x0450 +EM_SETWORDBREAKPROCEX :: 0x0451 +TB_INSERTMARKHITTEST :: 0x0451 +EM_SETUNDOLIMIT :: 0x0452 +TB_MOVEBUTTON :: 0x0452 +TB_GETMAXSIZE :: 0x0453 +EM_REDO :: 0x0454 +TB_SETEXTENDEDSTYLE :: 0x0454 +EM_CANREDO :: 0x0455 +TB_GETEXTENDEDSTYLE :: 0x0455 +EM_GETUNDONAME :: 0x0456 +TB_GETPADDING :: 0x0456 +EM_GETREDONAME :: 0x0457 +TB_SETPADDING :: 0x0457 +EM_STOPGROUPTYPING :: 0x0458 +TB_SETINSERTMARKCOLOR :: 0x0458 +EM_SETTEXTMODE :: 0x0459 +TB_GETINSERTMARKCOLOR :: 0x0459 +EM_GETTEXTMODE :: 0x045a +TB_MAPACCELERATORW :: 0x045a +EM_AUTOURLDETECT :: 0x045b +TB_GETSTRINGW :: 0x045b +EM_GETAUTOURLDETECT :: 0x045c +TB_GETSTRINGA :: 0x045c +EM_SETPALETTE :: 0x045d +EM_GETTEXTEX :: 0x045e +EM_GETTEXTLENGTHEX :: 0x045f +EM_SHOWSCROLLBAR :: 0x0460 +EM_SETTEXTEX :: 0x0461 +TAPI_REPLY :: 0x0463 +ACM_OPENA :: 0x0464 +BFFM_SETSTATUSTEXTA :: 0x0464 +CDM_FIRST :: 0x0464 +CDM_GETSPEC :: 0x0464 +EM_SETPUNCTUATION :: 0x0464 +IPM_CLEARADDRESS :: 0x0464 +WM_CAP_UNICODE_START :: 0x0464 +ACM_PLAY :: 0x0465 +BFFM_ENABLEOK :: 0x0465 +CDM_GETFILEPATH :: 0x0465 +EM_GETPUNCTUATION :: 0x0465 +IPM_SETADDRESS :: 0x0465 +PSM_SETCURSEL :: 0x0465 +UDM_SETRANGE :: 0x0465 +WM_CHOOSEFONT_SETLOGFONT :: 0x0465 +ACM_STOP :: 0x0466 +BFFM_SETSELECTIONA :: 0x0466 +CDM_GETFOLDERPATH :: 0x0466 +EM_SETWORDWRAPMODE :: 0x0466 +IPM_GETADDRESS :: 0x0466 +PSM_REMOVEPAGE :: 0x0466 +UDM_GETRANGE :: 0x0466 +WM_CAP_SET_CALLBACK_ERRORW :: 0x0466 +WM_CHOOSEFONT_SETFLAGS :: 0x0466 +ACM_OPENW :: 0x0467 +BFFM_SETSELECTIONW :: 0x0467 +CDM_GETFOLDERIDLIST :: 0x0467 +EM_GETWORDWRAPMODE :: 0x0467 +IPM_SETRANGE :: 0x0467 +PSM_ADDPAGE :: 0x0467 +UDM_SETPOS :: 0x0467 +WM_CAP_SET_CALLBACK_STATUSW :: 0x0467 +BFFM_SETSTATUSTEXTW :: 0x0468 +CDM_SETCONTROLTEXT :: 0x0468 +EM_SETIMECOLOR :: 0x0468 +IPM_SETFOCUS :: 0x0468 +PSM_CHANGED :: 0x0468 +UDM_GETPOS :: 0x0468 +CDM_HIDECONTROL :: 0x0469 +EM_GETIMECOLOR :: 0x0469 +IPM_ISBLANK :: 0x0469 +PSM_RESTARTWINDOWS :: 0x0469 +UDM_SETBUDDY :: 0x0469 +CDM_SETDEFEXT :: 0x046a +EM_SETIMEOPTIONS :: 0x046a +PSM_REBOOTSYSTEM :: 0x046a +UDM_GETBUDDY :: 0x046a +EM_GETIMEOPTIONS :: 0x046b +PSM_CANCELTOCLOSE :: 0x046b +UDM_SETACCEL :: 0x046b +EM_CONVPOSITION :: 0x046c +PSM_QUERYSIBLINGS :: 0x046c +UDM_GETACCEL :: 0x046c +MCIWNDM_GETZOOM :: 0x046d +PSM_UNCHANGED :: 0x046d +UDM_SETBASE :: 0x046d +PSM_APPLY :: 0x046e +UDM_GETBASE :: 0x046e +PSM_SETTITLEA :: 0x046f +UDM_SETRANGE32 :: 0x046f +PSM_SETWIZBUTTONS :: 0x0470 +UDM_GETRANGE32 :: 0x0470 +WM_CAP_DRIVER_GET_NAMEW :: 0x0470 +PSM_PRESSBUTTON :: 0x0471 +UDM_SETPOS32 :: 0x0471 +WM_CAP_DRIVER_GET_VERSIONW :: 0x0471 +PSM_SETCURSELID :: 0x0472 +UDM_GETPOS32 :: 0x0472 +PSM_SETFINISHTEXTA :: 0x0473 +PSM_GETTABCONTROL :: 0x0474 +PSM_ISDIALOGMESSAGE :: 0x0475 +MCIWNDM_REALIZE :: 0x0476 +PSM_GETCURRENTPAGEHWND :: 0x0476 +MCIWNDM_SETTIMEFORMATA :: 0x0477 +PSM_INSERTPAGE :: 0x0477 +EM_SETLANGOPTIONS :: 0x0478 +MCIWNDM_GETTIMEFORMATA :: 0x0478 +PSM_SETTITLEW :: 0x0478 +WM_CAP_FILE_SET_CAPTURE_FILEW :: 0x0478 +EM_GETLANGOPTIONS :: 0x0479 +MCIWNDM_VALIDATEMEDIA :: 0x0479 +PSM_SETFINISHTEXTW :: 0x0479 +WM_CAP_FILE_GET_CAPTURE_FILEW :: 0x0479 +EM_GETIMECOMPMODE :: 0x047a +EM_FINDTEXTW :: 0x047b +MCIWNDM_PLAYTO :: 0x047b +WM_CAP_FILE_SAVEASW :: 0x047b +EM_FINDTEXTEXW :: 0x047c +MCIWNDM_GETFILENAMEA :: 0x047c +EM_RECONVERSION :: 0x047d +MCIWNDM_GETDEVICEA :: 0x047d +PSM_SETHEADERTITLEA :: 0x047d +WM_CAP_FILE_SAVEDIBW :: 0x047d +EM_SETIMEMODEBIAS :: 0x047e +MCIWNDM_GETPALETTE :: 0x047e +PSM_SETHEADERTITLEW :: 0x047e +EM_GETIMEMODEBIAS :: 0x047f +MCIWNDM_SETPALETTE :: 0x047f +PSM_SETHEADERSUBTITLEA :: 0x047f +MCIWNDM_GETERRORA :: 0x0480 +PSM_SETHEADERSUBTITLEW :: 0x0480 +PSM_HWNDTOINDEX :: 0x0481 +PSM_INDEXTOHWND :: 0x0482 +MCIWNDM_SETINACTIVETIMER :: 0x0483 +PSM_PAGETOINDEX :: 0x0483 +PSM_INDEXTOPAGE :: 0x0484 +DL_BEGINDRAG :: 0x0485 +MCIWNDM_GETINACTIVETIMER :: 0x0485 +PSM_IDTOINDEX :: 0x0485 +DL_DRAGGING :: 0x0486 +PSM_INDEXTOID :: 0x0486 +DL_DROPPED :: 0x0487 +PSM_GETRESULT :: 0x0487 +DL_CANCELDRAG :: 0x0488 +PSM_RECALCPAGESIZES :: 0x0488 +MCIWNDM_GET_SOURCE :: 0x048c +MCIWNDM_PUT_SOURCE :: 0x048d +MCIWNDM_GET_DEST :: 0x048e +MCIWNDM_PUT_DEST :: 0x048f +MCIWNDM_CAN_PLAY :: 0x0490 +MCIWNDM_CAN_WINDOW :: 0x0491 +MCIWNDM_CAN_RECORD :: 0x0492 +MCIWNDM_CAN_SAVE :: 0x0493 +MCIWNDM_CAN_EJECT :: 0x0494 +MCIWNDM_CAN_CONFIG :: 0x0495 +IE_GETINK :: 0x0496 +IE_MSGFIRST :: 0x0496 +MCIWNDM_PALETTEKICK :: 0x0496 +IE_SETINK :: 0x0497 +IE_GETPENTIP :: 0x0498 +IE_SETPENTIP :: 0x0499 +IE_GETERASERTIP :: 0x049a +IE_SETERASERTIP :: 0x049b +IE_GETBKGND :: 0x049c +IE_SETBKGND :: 0x049d +IE_GETGRIDORIGIN :: 0x049e +IE_SETGRIDORIGIN :: 0x049f +IE_GETGRIDPEN :: 0x04a0 +IE_SETGRIDPEN :: 0x04a1 +IE_GETGRIDSIZE :: 0x04a2 +IE_SETGRIDSIZE :: 0x04a3 +IE_GETMODE :: 0x04a4 +IE_SETMODE :: 0x04a5 +IE_GETINKRECT :: 0x04a6 +WM_CAP_SET_MCI_DEVICEW :: 0x04a6 +WM_CAP_GET_MCI_DEVICEW :: 0x04a7 +WM_CAP_PAL_OPENW :: 0x04b4 +WM_CAP_PAL_SAVEW :: 0x04b5 +IE_GETAPPDATA :: 0x04b8 +IE_SETAPPDATA :: 0x04b9 +IE_GETDRAWOPTS :: 0x04ba +IE_SETDRAWOPTS :: 0x04bb +IE_GETFORMAT :: 0x04bc +IE_SETFORMAT :: 0x04bd +IE_GETINKINPUT :: 0x04be +IE_SETINKINPUT :: 0x04bf +IE_GETNOTIFY :: 0x04c0 +IE_SETNOTIFY :: 0x04c1 +IE_GETRECOG :: 0x04c2 +IE_SETRECOG :: 0x04c3 +IE_GETSECURITY :: 0x04c4 +IE_SETSECURITY :: 0x04c5 +IE_GETSEL :: 0x04c6 +IE_SETSEL :: 0x04c7 +CDM_LAST :: 0x04c8 +EM_SETBIDIOPTIONS :: 0x04c8 +IE_DOCOMMAND :: 0x04c8 +MCIWNDM_NOTIFYMODE :: 0x04c8 +EM_GETBIDIOPTIONS :: 0x04c9 +IE_GETCOMMAND :: 0x04c9 +EM_SETTYPOGRAPHYOPTIONS :: 0x04ca +IE_GETCOUNT :: 0x04ca +EM_GETTYPOGRAPHYOPTIONS :: 0x04cb +IE_GETGESTURE :: 0x04cb +MCIWNDM_NOTIFYMEDIA :: 0x04cb +EM_SETEDITSTYLE :: 0x04cc +IE_GETMENU :: 0x04cc +EM_GETEDITSTYLE :: 0x04cd +IE_GETPAINTDC :: 0x04cd +MCIWNDM_NOTIFYERROR :: 0x04cd +IE_GETPDEVENT :: 0x04ce +IE_GETSELCOUNT :: 0x04cf +IE_GETSELITEMS :: 0x04d0 +IE_GETSTYLE :: 0x04d1 +MCIWNDM_SETTIMEFORMATW :: 0x04db +EM_OUTLINE :: 0x04dc +MCIWNDM_GETTIMEFORMATW :: 0x04dc +EM_GETSCROLLPOS :: 0x04dd +EM_SETSCROLLPOS :: 0x04de +EM_SETFONTSIZE :: 0x04df +EM_GETZOOM :: 0x04e0 +MCIWNDM_GETFILENAMEW :: 0x04e0 +EM_SETZOOM :: 0x04e1 +MCIWNDM_GETDEVICEW :: 0x04e1 +EM_GETVIEWKIND :: 0x04e2 +EM_SETVIEWKIND :: 0x04e3 +EM_GETPAGE :: 0x04e4 +MCIWNDM_GETERRORW :: 0x04e4 +EM_SETPAGE :: 0x04e5 +EM_GETHYPHENATEINFO :: 0x04e6 +EM_SETHYPHENATEINFO :: 0x04e7 +EM_GETPAGEROTATE :: 0x04eb +EM_SETPAGEROTATE :: 0x04ec +EM_GETCTFMODEBIAS :: 0x04ed +EM_SETCTFMODEBIAS :: 0x04ee +EM_GETCTFOPENSTATUS :: 0x04f0 +EM_SETCTFOPENSTATUS :: 0x04f1 +EM_GETIMECOMPTEXT :: 0x04f2 +EM_ISIME :: 0x04f3 +EM_GETIMEPROPERTY :: 0x04f4 +EM_GETQUERYRTFOBJ :: 0x050d +EM_SETQUERYRTFOBJ :: 0x050e +FM_GETFOCUS :: 0x0600 +FM_GETDRIVEINFOA :: 0x0601 +FM_GETSELCOUNT :: 0x0602 +FM_GETSELCOUNTLFN :: 0x0603 +FM_GETFILESELA :: 0x0604 +FM_GETFILESELLFNA :: 0x0605 +FM_REFRESH_WINDOWS :: 0x0606 +FM_RELOAD_EXTENSIONS :: 0x0607 +FM_GETDRIVEINFOW :: 0x0611 +FM_GETFILESELW :: 0x0614 +FM_GETFILESELLFNW :: 0x0615 +WLX_WM_SAS :: 0x0659 +SM_GETSELCOUNT :: 0x07e8 +UM_GETSELCOUNT :: 0x07e8 +WM_CPL_LAUNCH :: 0x07e8 +SM_GETSERVERSELA :: 0x07e9 +UM_GETUSERSELA :: 0x07e9 +WM_CPL_LAUNCHED :: 0x07e9 +SM_GETSERVERSELW :: 0x07ea +UM_GETUSERSELW :: 0x07ea +SM_GETCURFOCUSA :: 0x07eb +UM_GETGROUPSELA :: 0x07eb +SM_GETCURFOCUSW :: 0x07ec +UM_GETGROUPSELW :: 0x07ec +SM_GETOPTIONS :: 0x07ed +UM_GETCURFOCUSA :: 0x07ed +UM_GETCURFOCUSW :: 0x07ee +UM_GETOPTIONS :: 0x07ef +UM_GETOPTIONS2 :: 0x07f0 +LVM_FIRST :: 0x1000 +LVM_GETBKCOLOR :: 0x1000 +LVM_SETBKCOLOR :: 0x1001 +LVM_GETIMAGELIST :: 0x1002 +LVM_SETIMAGELIST :: 0x1003 +LVM_GETITEMCOUNT :: 0x1004 +LVM_GETITEMA :: 0x1005 +LVM_SETITEMA :: 0x1006 +LVM_INSERTITEMA :: 0x1007 +LVM_DELETEITEM :: 0x1008 +LVM_DELETEALLITEMS :: 0x1009 +LVM_GETCALLBACKMASK :: 0x100a +LVM_SETCALLBACKMASK :: 0x100b +LVM_GETNEXTITEM :: 0x100c +LVM_FINDITEMA :: 0x100d +LVM_GETITEMRECT :: 0x100e +LVM_SETITEMPOSITION :: 0x100f +LVM_GETITEMPOSITION :: 0x1010 +LVM_GETSTRINGWIDTHA :: 0x1011 +LVM_HITTEST :: 0x1012 +LVM_ENSUREVISIBLE :: 0x1013 +LVM_SCROLL :: 0x1014 +LVM_REDRAWITEMS :: 0x1015 +LVM_ARRANGE :: 0x1016 +LVM_EDITLABELA :: 0x1017 +LVM_GETEDITCONTROL :: 0x1018 +LVM_GETCOLUMNA :: 0x1019 +LVM_SETCOLUMNA :: 0x101a +LVM_INSERTCOLUMNA :: 0x101b +LVM_DELETECOLUMN :: 0x101c +LVM_GETCOLUMNWIDTH :: 0x101d +LVM_SETCOLUMNWIDTH :: 0x101e +LVM_GETHEADER :: 0x101f +LVM_CREATEDRAGIMAGE :: 0x1021 +LVM_GETVIEWRECT :: 0x1022 +LVM_GETTEXTCOLOR :: 0x1023 +LVM_SETTEXTCOLOR :: 0x1024 +LVM_GETTEXTBKCOLOR :: 0x1025 +LVM_SETTEXTBKCOLOR :: 0x1026 +LVM_GETTOPINDEX :: 0x1027 +LVM_GETCOUNTPERPAGE :: 0x1028 +LVM_GETORIGIN :: 0x1029 +LVM_UPDATE :: 0x102a +LVM_SETITEMSTATE :: 0x102b +LVM_GETITEMSTATE :: 0x102c +LVM_GETITEMTEXTA :: 0x102d +LVM_SETITEMTEXTA :: 0x102e +LVM_SETITEMCOUNT :: 0x102f +LVM_SORTITEMS :: 0x1030 +LVM_SETITEMPOSITION32 :: 0x1031 +LVM_GETSELECTEDCOUNT :: 0x1032 +LVM_GETITEMSPACING :: 0x1033 +LVM_GETISEARCHSTRINGA :: 0x1034 +LVM_SETICONSPACING :: 0x1035 +LVM_SETEXTENDEDLISTVIEWSTYLE :: 0x1036 +LVM_GETEXTENDEDLISTVIEWSTYLE :: 0x1037 +LVM_GETSUBITEMRECT :: 0x1038 +LVM_SUBITEMHITTEST :: 0x1039 +LVM_SETCOLUMNORDERARRAY :: 0x103a +LVM_GETCOLUMNORDERARRAY :: 0x103b +LVM_SETHOTITEM :: 0x103c +LVM_GETHOTITEM :: 0x103d +LVM_SETHOTCURSOR :: 0x103e +LVM_GETHOTCURSOR :: 0x103f +LVM_APPROXIMATEVIEWRECT :: 0x1040 +LVM_SETWORKAREAS :: 0x1041 +LVM_GETSELECTIONMARK :: 0x1042 +LVM_SETSELECTIONMARK :: 0x1043 +LVM_SETBKIMAGEA :: 0x1044 +LVM_GETBKIMAGEA :: 0x1045 +LVM_GETWORKAREAS :: 0x1046 +LVM_SETHOVERTIME :: 0x1047 +LVM_GETHOVERTIME :: 0x1048 +LVM_GETNUMBEROFWORKAREAS :: 0x1049 +LVM_SETTOOLTIPS :: 0x104a +LVM_GETITEMW :: 0x104b +LVM_SETITEMW :: 0x104c +LVM_INSERTITEMW :: 0x104d +LVM_GETTOOLTIPS :: 0x104e +LVM_FINDITEMW :: 0x1053 +LVM_GETSTRINGWIDTHW :: 0x1057 +LVM_GETCOLUMNW :: 0x105f +LVM_SETCOLUMNW :: 0x1060 +LVM_INSERTCOLUMNW :: 0x1061 +LVM_GETITEMTEXTW :: 0x1073 +LVM_SETITEMTEXTW :: 0x1074 +LVM_GETISEARCHSTRINGW :: 0x1075 +LVM_EDITLABELW :: 0x1076 +LVM_GETBKIMAGEW :: 0x108b +LVM_SETSELECTEDCOLUMN :: 0x108c +LVM_SETTILEWIDTH :: 0x108d +LVM_SETVIEW :: 0x108e +LVM_GETVIEW :: 0x108f +LVM_INSERTGROUP :: 0x1091 +LVM_SETGROUPINFO :: 0x1093 +LVM_GETGROUPINFO :: 0x1095 +LVM_REMOVEGROUP :: 0x1096 +LVM_MOVEGROUP :: 0x1097 +LVM_MOVEITEMTOGROUP :: 0x109a +LVM_SETGROUPMETRICS :: 0x109b +LVM_GETGROUPMETRICS :: 0x109c +LVM_ENABLEGROUPVIEW :: 0x109d +LVM_SORTGROUPS :: 0x109e +LVM_INSERTGROUPSORTED :: 0x109f +LVM_REMOVEALLGROUPS :: 0x10a0 +LVM_HASGROUP :: 0x10a1 +LVM_SETTILEVIEWINFO :: 0x10a2 +LVM_GETTILEVIEWINFO :: 0x10a3 +LVM_SETTILEINFO :: 0x10a4 +LVM_GETTILEINFO :: 0x10a5 +LVM_SETINSERTMARK :: 0x10a6 +LVM_GETINSERTMARK :: 0x10a7 +LVM_INSERTMARKHITTEST :: 0x10a8 +LVM_GETINSERTMARKRECT :: 0x10a9 +LVM_SETINSERTMARKCOLOR :: 0x10aa +LVM_GETINSERTMARKCOLOR :: 0x10ab +LVM_SETINFOTIP :: 0x10ad +LVM_GETSELECTEDCOLUMN :: 0x10ae +LVM_ISGROUPVIEWENABLED :: 0x10af +LVM_GETOUTLINECOLOR :: 0x10b0 +LVM_SETOUTLINECOLOR :: 0x10b1 +LVM_CANCELEDITLABEL :: 0x10b3 +LVM_MAPINDEXTOID :: 0x10b4 +LVM_MAPIDTOINDEX :: 0x10b5 +LVM_ISITEMVISIBLE :: 0x10b6 +LVM_GETEMPTYTEXT :: 0x10cc +LVM_GETFOOTERRECT :: 0x10cd +LVM_GETFOOTERINFO :: 0x10ce +LVM_GETFOOTERITEMRECT :: 0x10cf +LVM_GETFOOTERITEM :: 0x10d0 +LVM_GETITEMINDEXRECT :: 0x10d1 +LVM_SETITEMINDEXSTATE :: 0x10d2 +LVM_GETNEXTITEMINDEX :: 0x10d3 +OCM__BASE :: 0x2000 +LVM_SETUNICODEFORMAT :: 0x2005 +LVM_GETUNICODEFORMAT :: 0x2006 +OCM_CTLCOLOR :: 0x2019 +OCM_DRAWITEM :: 0x202b +OCM_MEASUREITEM :: 0x202c +OCM_DELETEITEM :: 0x202d +OCM_VKEYTOITEM :: 0x202e +OCM_CHARTOITEM :: 0x202f +OCM_COMPAREITEM :: 0x2039 +OCM_NOTIFY :: 0x204e +OCM_COMMAND :: 0x2111 +OCM_HSCROLL :: 0x2114 +OCM_VSCROLL :: 0x2115 +OCM_CTLCOLORMSGBOX :: 0x2132 +OCM_CTLCOLOREDIT :: 0x2133 +OCM_CTLCOLORLISTBOX :: 0x2134 +OCM_CTLCOLORBTN :: 0x2135 +OCM_CTLCOLORDLG :: 0x2136 +OCM_CTLCOLORSCROLLBAR :: 0x2137 +OCM_CTLCOLORSTATIC :: 0x2138 +OCM_PARENTNOTIFY :: 0x2210 +WM_APP :: 0x8000 WM_RASDIALEVENT :: 0xcccd \ No newline at end of file From f89ebce807b8f890a27de3f58dc77f3286735829 Mon Sep 17 00:00:00 2001 From: Wes Hardee Date: Tue, 22 Mar 2022 15:55:37 -0500 Subject: [PATCH 0421/1052] Add foreign imports for Darwin to vendor:stb --- vendor/stb/image/stb_image.odin | 1 + vendor/stb/image/stb_image_resize.odin | 1 + vendor/stb/image/stb_image_write.odin | 1 + vendor/stb/rect_pack/stb_rect_pack.odin | 1 + vendor/stb/truetype/stb_truetype.odin | 1 + vendor/stb/vorbis/stb_vorbis.odin | 1 + 6 files changed, 6 insertions(+) diff --git a/vendor/stb/image/stb_image.odin b/vendor/stb/image/stb_image.odin index 4f7e43171..eedce5f04 100644 --- a/vendor/stb/image/stb_image.odin +++ b/vendor/stb/image/stb_image.odin @@ -6,6 +6,7 @@ import c "core:c/libc" when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib" } when ODIN_OS == .Linux { foreign import stbi "../lib/stb_image.a" } +when ODIN_OS == .Darwin { foreign import stbi "../lib/stb_image.a" } #assert(size_of(b32) == size_of(c.int)) diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin index 65bf3e4a9..362ec9315 100644 --- a/vendor/stb/image/stb_image_resize.odin +++ b/vendor/stb/image/stb_image_resize.odin @@ -4,6 +4,7 @@ import c "core:c/libc" when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib" } when ODIN_OS == .Linux { foreign import lib "../lib/stb_image_resize.a" } +when ODIN_OS == .Darwin { foreign import lib "../lib/stb_image_resize.a" } ////////////////////////////////////////////////////////////////////////////// // diff --git a/vendor/stb/image/stb_image_write.odin b/vendor/stb/image/stb_image_write.odin index 67f4299fa..b9433e821 100644 --- a/vendor/stb/image/stb_image_write.odin +++ b/vendor/stb/image/stb_image_write.odin @@ -4,6 +4,7 @@ import c "core:c/libc" when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" } when ODIN_OS == .Linux { foreign import stbiw "../lib/stb_image_write.a" } +when ODIN_OS == .Darwin { foreign import stbiw "../lib/stb_image_write.a" } write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int) diff --git a/vendor/stb/rect_pack/stb_rect_pack.odin b/vendor/stb/rect_pack/stb_rect_pack.odin index f84f1cedc..c9f999bf7 100644 --- a/vendor/stb/rect_pack/stb_rect_pack.odin +++ b/vendor/stb/rect_pack/stb_rect_pack.odin @@ -6,6 +6,7 @@ import c "core:c/libc" when ODIN_OS == .Windows { foreign import lib "../lib/stb_rect_pack.lib" } when ODIN_OS == .Linux { foreign import lib "../lib/stb_rect_pack.a" } +when ODIN_OS == .Darwin { foreign import lib "../lib/stb_rect_pack.a" } Coord :: distinct c.int _MAXVAL :: max(Coord) diff --git a/vendor/stb/truetype/stb_truetype.odin b/vendor/stb/truetype/stb_truetype.odin index cf4af15e9..b51cb037f 100644 --- a/vendor/stb/truetype/stb_truetype.odin +++ b/vendor/stb/truetype/stb_truetype.odin @@ -5,6 +5,7 @@ import stbrp "vendor:stb/rect_pack" when ODIN_OS == .Windows { foreign import stbtt "../lib/stb_truetype.lib" } when ODIN_OS == .Linux { foreign import stbtt "../lib/stb_truetype.a" } +when ODIN_OS == .Darwin { foreign import stbtt "../lib/stb_truetype.a" } /////////////////////////////////////////////////////////////////////////////// diff --git a/vendor/stb/vorbis/stb_vorbis.odin b/vendor/stb/vorbis/stb_vorbis.odin index f35b58e04..43b9bc715 100644 --- a/vendor/stb/vorbis/stb_vorbis.odin +++ b/vendor/stb/vorbis/stb_vorbis.odin @@ -5,6 +5,7 @@ import c "core:c/libc" when ODIN_OS == .Windows { foreign import lib "../lib/stb_vorbis.lib" } when ODIN_OS == .Linux { foreign import lib "../lib/stb_vorbis.a" } +when ODIN_OS == .Darwin { foreign import lib "../lib/stb_vorbis.a" } From 10c58257159f8c8d046dd3cb93dde6b404414169 Mon Sep 17 00:00:00 2001 From: gitlost Date: Wed, 23 Mar 2022 12:56:37 +0000 Subject: [PATCH 0422/1052] Fix issue #829 "Compiler crashes when declaring maps with procedure" Inits `o->value` in `check_expr_base_internal()` so doesn't accidentally use last (the proc lit was being set to that of previous string) Adds test to "tests/issues" and changes CI to use new "run" shells --- .github/workflows/ci.yml | 6 +++--- src/check_expr.cpp | 1 + tests/issues/run.bat | 17 ++++++++++++++++ tests/issues/run.sh | 18 +++++++++++++++++ tests/issues/test_issue_829.odin | 33 ++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 tests/issues/run.bat create mode 100755 tests/issues/run.sh create mode 100644 tests/issues/test_issue_829.odin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3b1d8058..3cc4283b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: ./odin run tests/issues -collection:tests=tests + run: tests/issues/run.sh timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 @@ -91,7 +91,7 @@ jobs: make timeout-minutes: 10 - name: Odin issues tests - run: ./odin run tests/issues -collection:tests=tests + run: tests/issues/run.sh timeout-minutes: 10 - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 @@ -163,7 +163,7 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin run tests\issues -collection:tests=tests + call tests\issues\run.bat timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b7039fd9a..66bf8bbd7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9000,6 +9000,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type o->mode = Addressing_Invalid; o->type = t_invalid; + o->value = {ExactValue_Invalid}; switch (node->kind) { default: diff --git a/tests/issues/run.bat b/tests/issues/run.bat new file mode 100644 index 000000000..b145dda48 --- /dev/null +++ b/tests/issues/run.bat @@ -0,0 +1,17 @@ +@echo off + +if not exist "tests\issues\build\" mkdir tests\issues\build + +set COMMON=-collection:tests=tests -out:tests\issues\build\test_issue + +@echo on + +.\odin build tests\issues\test_issue_829.odin %COMMON% +tests\issues\build\test_issue + +.\odin build tests\issues\test_issue_1592.odin %COMMON% +tests\issues\build\test_issue + +@echo off + +rmdir /S /Q tests\issues\build diff --git a/tests/issues/run.sh b/tests/issues/run.sh new file mode 100755 index 000000000..c4f978771 --- /dev/null +++ b/tests/issues/run.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -eu + +mkdir -p tests/issues/build + +COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" + +set -x + +./odin build tests/issues/test_issue_829.odin $COMMON +tests/issues/build/test_issue + +./odin build tests/issues/test_issue_1592.odin $COMMON +tests/issues/build/test_issue + +set +x + +rm -rf tests/issues/build diff --git a/tests/issues/test_issue_829.odin b/tests/issues/test_issue_829.odin new file mode 100644 index 000000000..4ff3d71f1 --- /dev/null +++ b/tests/issues/test_issue_829.odin @@ -0,0 +1,33 @@ +// Tests issue #829 https://github.com/odin-lang/Odin/issues/829 +package test_issues + +import "core:fmt" +import "core:testing" +import tc "tests:common" + +/* Original issue #829 example */ + +env : map[string]proc(a, b : int) -> int = { + "+" = proc(a, b : int) -> int { + return a + b + }, +} + +test_orig :: proc() { + fmt.println(env["+"](1, 2)) +} + +main :: proc() { + t := testing.T{} + + test_orig() + + test_orig_ret(&t) + + tc.report(&t) +} + +test_orig_ret :: proc(t: ^testing.T) { + r := fmt.tprint(env["+"](1, 2)) + tc.expect(t, r == "3", fmt.tprintf("%s: \"%s\" != \"3\"\n", #procedure, r)) +} From 3d389ee028b192a570008c5f5f89002e99a67c2d Mon Sep 17 00:00:00 2001 From: Holger Lindner Date: Wed, 23 Mar 2022 15:01:06 +0100 Subject: [PATCH 0423/1052] sys/windows: Add icon resource constants --- core/sys/windows/types.odin | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 23c74d1ed..302857e7e 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -395,6 +395,7 @@ SW_FORCEMINIMIZE : c_int : 11 CW_USEDEFAULT : c_int : -2147483648 + _IDC_APPSTARTING := rawptr(uintptr(32650)) _IDC_ARROW := rawptr(uintptr(32512)) _IDC_CROSS := rawptr(uintptr(32515)) @@ -411,6 +412,7 @@ _IDC_SIZENWSE := rawptr(uintptr(32642)) _IDC_SIZEWE := rawptr(uintptr(32644)) _IDC_UPARROW := rawptr(uintptr(32516)) _IDC_WAIT := rawptr(uintptr(32514)) + IDC_APPSTARTING := cstring(_IDC_APPSTARTING) IDC_ARROW := cstring(_IDC_ARROW) IDC_CROSS := cstring(_IDC_CROSS) @@ -428,6 +430,31 @@ IDC_SIZEWE := cstring(_IDC_SIZEWE) IDC_UPARROW := cstring(_IDC_UPARROW) IDC_WAIT := cstring(_IDC_WAIT) + +_IDI_APPLICATION := rawptr(uintptr(32512)) +_IDI_HAND := rawptr(uintptr(32513)) +_IDI_QUESTION := rawptr(uintptr(32514)) +_IDI_EXCLAMATION := rawptr(uintptr(32515)) +_IDI_ASTERISK := rawptr(uintptr(32516)) +_IDI_WINLOGO := rawptr(uintptr(32517)) +_IDI_SHIELD := rawptr(uintptr(32518)) + +IDI_APPLICATION := cstring(_IDI_APPLICATION) +IDI_HAND := cstring(_IDI_HAND) +IDI_QUESTION := cstring(_IDI_QUESTION) +IDI_EXCLAMATION := cstring(_IDI_EXCLAMATION) +IDI_ASTERISK := cstring(_IDI_ASTERISK) + +// if WINVER >= _WIN32_WINNT_NT4 +IDI_WINLOGO := cstring(_IDI_WINLOGO) +IDI_WARNING := IDI_EXCLAMATION +IDI_ERROR := IDI_HAND +IDI_INFORMATION := IDI_ASTERISK + +// if WINVER >= _WIN32_WINNT_VISTA +IDI_SHIELD := cstring(_IDI_SHIELD) + + WSA_FLAG_OVERLAPPED: DWORD : 0x01 WSA_FLAG_NO_HANDLE_INHERIT: DWORD : 0x80 From b9efd09d17bf21ed79338905ca84b59bb0bdb27a Mon Sep 17 00:00:00 2001 From: hikari Date: Wed, 23 Mar 2022 17:37:38 +0200 Subject: [PATCH 0424/1052] sys/windows: fixed calling conventions, added several bindings --- core/sys/windows/kernel32.odin | 11 ++++- core/sys/windows/types.odin | 27 +++++------ core/sys/windows/user32.odin | 88 ++++++++++++++++++++++++---------- 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 8c58fbd52..f81c51311 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -341,6 +341,7 @@ MEM_TOP_DOWN :: 0x100000 MEM_LARGE_PAGES :: 0x20000000 MEM_4MB_PAGES :: 0x80000000 +@(default_calling_convention="stdcall") foreign kernel32 { VirtualAlloc :: proc( lpAddress: LPVOID, @@ -483,6 +484,7 @@ LowMemoryResourceNotification :: MEMORY_RESOURCE_NOTIFICATION_TYPE.LowMemoryRes HighMemoryResourceNotification :: MEMORY_RESOURCE_NOTIFICATION_TYPE.HighMemoryResourceNotification +@(default_calling_convention="stdcall") foreign kernel32 { CreateMemoryResourceNotification :: proc( NotificationType: MEMORY_RESOURCE_NOTIFICATION_TYPE, @@ -498,6 +500,7 @@ FILE_CACHE_MAX_HARD_DISABLE :: DWORD(0x00000002) FILE_CACHE_MIN_HARD_ENABLE :: DWORD(0x00000004) FILE_CACHE_MIN_HARD_DISABLE :: DWORD(0x00000008) +@(default_calling_convention="stdcall") foreign kernel32 { GetSystemFileCacheSize :: proc( lpMinimumFileCacheSize: PSIZE_T, @@ -527,6 +530,7 @@ WIN32_MEMORY_RANGE_ENTRY :: struct { PWIN32_MEMORY_RANGE_ENTRY :: ^WIN32_MEMORY_RANGE_ENTRY +@(default_calling_convention="stdcall") foreign kernel32 { PrefetchVirtualMemory :: proc( hProcess: HANDLE, @@ -584,6 +588,7 @@ foreign kernel32 { MEHC_PATROL_SCRUBBER_PRESENT :: ULONG(0x1) +@(default_calling_convention="stdcall") foreign kernel32 { GetMemoryErrorHandlingCapabilities :: proc( Capabilities: PULONG, @@ -592,6 +597,7 @@ foreign kernel32 { PBAD_MEMORY_CALLBACK_ROUTINE :: #type proc "stdcall" () +@(default_calling_convention="stdcall") foreign kernel32 { RegisterBadMemoryNotification :: proc( Callback: PBAD_MEMORY_CALLBACK_ROUTINE, @@ -612,6 +618,7 @@ VmOfferPriorityLow :: OFFER_PRIORITY.VmOfferPriorityLow VmOfferPriorityBelowNormal :: OFFER_PRIORITY.VmOfferPriorityBelowNormal VmOfferPriorityNormal :: OFFER_PRIORITY.VmOfferPriorityNormal +@(default_calling_convention="stdcall") foreign kernel32 { OfferVirtualMemory :: proc( VirtualAddress: PVOID, @@ -676,6 +683,7 @@ WIN32_MEMORY_REGION_INFORMATION_u_s_Bitfield :: distinct ULONG Reserved : 32-6, }*/ +@(default_calling_convention="stdcall") foreign kernel32 { QueryVirtualMemoryInformation :: proc( Process: HANDLE, @@ -700,7 +708,7 @@ foreign kernel32 { NUMA_NO_PREFERRED_NODE :: 0xffffffff -MapViewOfFile2 :: #force_inline proc( +MapViewOfFile2 :: #force_inline proc "stdcall" ( FileMappingHandle: HANDLE, ProcessHandle: HANDLE, Offset: ULONG64, @@ -721,6 +729,7 @@ MapViewOfFile2 :: #force_inline proc( ) } +@(default_calling_convention="stdcall") foreign kernel32 { UnmapViewOfFile2 :: proc( ProcessHandle: HANDLE, diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 302857e7e..d34231ce6 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -54,6 +54,7 @@ NTSTATUS :: c.long LPARAM :: LONG_PTR WPARAM :: UINT_PTR LRESULT :: LONG_PTR +LPRECT :: ^RECT UINT8 :: u8 UINT16 :: u16 @@ -80,6 +81,7 @@ PBOOL :: ^BOOL LPBOOL :: ^BOOL LPCSTR :: cstring LPCWSTR :: wstring +LPCTSTR :: wstring LPDWORD :: ^DWORD PCSTR :: cstring PCWSTR :: wstring @@ -438,21 +440,16 @@ _IDI_EXCLAMATION := rawptr(uintptr(32515)) _IDI_ASTERISK := rawptr(uintptr(32516)) _IDI_WINLOGO := rawptr(uintptr(32517)) _IDI_SHIELD := rawptr(uintptr(32518)) - -IDI_APPLICATION := cstring(_IDI_APPLICATION) -IDI_HAND := cstring(_IDI_HAND) -IDI_QUESTION := cstring(_IDI_QUESTION) -IDI_EXCLAMATION := cstring(_IDI_EXCLAMATION) -IDI_ASTERISK := cstring(_IDI_ASTERISK) - -// if WINVER >= _WIN32_WINNT_NT4 -IDI_WINLOGO := cstring(_IDI_WINLOGO) -IDI_WARNING := IDI_EXCLAMATION -IDI_ERROR := IDI_HAND -IDI_INFORMATION := IDI_ASTERISK - -// if WINVER >= _WIN32_WINNT_VISTA -IDI_SHIELD := cstring(_IDI_SHIELD) +IDI_APPLICATION := cstring(_IDI_APPLICATION) +IDI_HAND := cstring(_IDI_HAND) +IDI_QUESTION := cstring(_IDI_QUESTION) +IDI_EXCLAMATION := cstring(_IDI_EXCLAMATION) +IDI_ASTERISK := cstring(_IDI_ASTERISK) +IDI_WINLOGO := cstring(_IDI_WINLOGO) +IDI_SHIELD := cstring(_IDI_SHIELD) +IDI_WARNING := IDI_EXCLAMATION +IDI_ERROR := IDI_HAND +IDI_INFORMATION := IDI_ASTERISK WSA_FLAG_OVERLAPPED: DWORD : 0x01 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index ce88b25ce..705b9253a 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -28,30 +28,6 @@ foreign user32 { RegisterClassExA :: proc(^WNDCLASSEXA) -> ATOM --- RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- - CreateWindowA :: proc( - lpClassName: LPCSTR, - lpWindowName: LPCSTR, - dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPARAM) -> HWND --- - CreateWindowW :: proc( - lpClassName: LPCWSTR, - lpWindowName: LPCWSTR, - dwStyle: DWORD, - X: c_int, - Y: c_int, - nWidth: c_int, - nHeight: c_int, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPARAM) -> HWND --- CreateWindowExA :: proc( dwExStyle: DWORD, lpClassName: LPCSTR, @@ -110,6 +86,8 @@ foreign user32 { DefWindowProcA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- DefWindowProcW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + FindWindowA :: proc(lpClassName: LPCSTR, lpWindowName: LPCSTR) -> HWND --- + FindWindowW :: proc(lpClassName: LPCWSTR, lpWindowName: LPCWSTR) -> HWND --- FindWindowExA :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCSTR, lpszWindow: LPCSTR) -> HWND --- FindWindowExW :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCWSTR, lpszWindow: LPCWSTR) -> HWND --- @@ -124,6 +102,68 @@ foreign user32 { GetDC :: proc(hWnd: HWND) -> HDC --- ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> c_int --- + GetUpdateRect :: proc(hWnd: HWND, lpRect: LPRECT, bErase: BOOL) -> BOOL --- + ValidateRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- + InvalidateRect :: proc(hWnd: HWND, lpRect: ^RECT, bErase: BOOL) -> BOOL --- + BeginPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> HDC --- EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- } + +CreateWindowA :: #force_inline proc "stdcall" ( + lpClassName: LPCSTR, + lpWindowName: LPCSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, +) -> HWND { + return CreateWindowExA( + 0, + lpClassName, + lpWindowName, + dwStyle, + X, + Y, + nWidth, + nHeight, + hWndParent, + hMenu, + hInstance, + lpParam, + ) +} + +CreateWindowW :: #force_inline proc "stdcall" ( + lpClassName: LPCTSTR, + lpWindowName: LPCTSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, +) -> HWND { + return CreateWindowExW( + 0, + lpClassName, + lpWindowName, + dwStyle, + X, + Y, + nWidth, + nHeight, + hWndParent, + hMenu, + hInstance, + lpParam, + ) +} From e252d3bedf28e603ee3c33a4aebcfefbb5cfb66c Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 23 Mar 2022 11:49:19 -0400 Subject: [PATCH 0425/1052] add os2.name --- core/os/os2/file_linux.odin | 27 +++++++++++++++++++++------ tests/core/os2/test_os2.odin | 25 ++++++++++++++++++++----- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 9030d265d..7040d0ed3 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -4,6 +4,7 @@ package os2 import "core:io" import "core:time" import "core:strings" +import "core:strconv" import "core:sys/unix" @@ -55,8 +56,20 @@ _close :: proc(fd: Handle) -> Error { } _name :: proc(fd: Handle, allocator := context.allocator) -> string { - //TODO - return "" + // NOTE: Not sure how portable this really is + PROC_FD_PATH :: "/proc/self/fd/" + + buf: [32]u8 + copy(buf[:], PROC_FD_PATH) + + strconv.itoa(buf[len(PROC_FD_PATH):], int(fd)) + + realpath: string + err: Error + if realpath, err = _read_link_cstr(cstring(&buf[0])); err != nil || realpath[0] != '/' { + return "" + } + return realpath } _seek :: proc(fd: Handle, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) { @@ -189,10 +202,7 @@ _symlink :: proc(old_name, new_name: string) -> Error { return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr)) } -_read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) { - name_cstr := strings.clone_to_cstring(name) - defer delete(name_cstr) - +_read_link_cstr :: proc(name_cstr: cstring, allocator := context.allocator) -> (string, Error) { bufsz : uint = 256 buf := make([]byte, bufsz, allocator) for { @@ -210,6 +220,11 @@ _read_link :: proc(name: string, allocator := context.allocator) -> (string, Err } } +_read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) { + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return _read_link_cstr(name_cstr, allocator) +} + _unlink :: proc(name: string) -> Error { name_cstr := strings.clone_to_cstring(name, context.temp_allocator) return _ok_or_error(unix.sys_unlink(name_cstr)) diff --git a/tests/core/os2/test_os2.odin b/tests/core/os2/test_os2.odin index e52351f03..c588e532e 100644 --- a/tests/core/os2/test_os2.odin +++ b/tests/core/os2/test_os2.odin @@ -1,9 +1,11 @@ package test_os2 +import "core:os/os2" + import "core:os" import "core:fmt" import "core:mem" -import "core:os/os2" +import "core:strings" import "core:testing" import "core:intrinsics" @@ -116,7 +118,7 @@ file_test :: proc(t: ^testing.T) { _expect_no_error(t, err) expect_value(t, n, 10) - // seek to the "ll" in "hello" + // seek FROM BEGINNING to the "ll" in "hello" n64: i64 n64, err = os2.seek(fd, 12, .Start) _expect_no_error(t, err) @@ -127,7 +129,7 @@ file_test :: proc(t: ^testing.T) { _expect_no_error(t, err) expect_value(t, n, 2) - // seek to the "e" in "he11o" + // seek BACK to the "e" in "he11o" n64, err = os2.seek(fd, -3, .Current) _expect_no_error(t, err) expect_value(t, n64, 11) @@ -137,7 +139,7 @@ file_test :: proc(t: ^testing.T) { _expect_no_error(t, err) expect_value(t, n, 1) - // seek to the "o" in "h311o" + // seek FROM THE END the "o" in "h311o" n64, err = os2.seek(fd, -1, .End) _expect_no_error(t, err) expect_value(t, n64, 14) @@ -157,11 +159,24 @@ file_test :: proc(t: ^testing.T) { expect(t, unix.sys_access("file.txt", X_OK) == 0, "expected exec permission") } + /* Build expected full path via cwd and known file name */ + parts: [2]string + parts[0], err = os2.getwd() + defer delete(parts[0]) + _expect_no_error(t, err) + + parts[1] = "/file.txt" + expected_full_path := strings.concatenate(parts[:]) + defer delete(expected_full_path) + + full_path := os2.name(fd) + defer delete(full_path) + expect_value(t, full_path, expected_full_path) + // NOTE: chown not possible without root user //_expect_no_error(t, os2.chown(fd, 0, 0)) _expect_no_error(t, os2.close(fd)) - fd, err = os2.open("file.txt") _expect_no_error(t, err) From 374e71e9b0bcfa5791f61945cfd9163dcaaa2537 Mon Sep 17 00:00:00 2001 From: gitlost Date: Wed, 23 Mar 2022 17:44:35 +0000 Subject: [PATCH 0426/1052] Fix issue #1537 "filepath.split_list requires a trailing separator" Does `make()` with `count + 1` and appends final component (note a trailing separator will now result in an empty final component) Adds test "tests/core/path/filepath/test_core_filepath.odin" --- core/path/filepath/path.odin | 10 +- tests/core/Makefile | 5 +- tests/core/build.bat | 5 + .../path/filepath/test_core_filepath.odin | 123 ++++++++++++++++++ 4 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 tests/core/path/filepath/test_core_filepath.odin diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin index ba6e11044..c04bd5a11 100644 --- a/core/path/filepath/path.odin +++ b/core/path/filepath/path.odin @@ -1,5 +1,5 @@ // The path/filepath package uses either forward slashes or backslashes depending on the operating system -// To process paths usch as URLs that depend on forward slashes regardless of the OS, use the path package +// To process paths such as URLs that depend on forward slashes regardless of the OS, use the path package package filepath import "core:strings" @@ -300,6 +300,11 @@ dir :: proc(path: string, allocator := context.allocator) -> string { +// Splits the PATH-like `path` string, returning an array of its separated components (delete after use). +// For Windows the separator is `;`, for Unix it's `:`. +// An empty string returns nil. A non-empty string with no separators returns a 1-element array. +// Any empty components will be included, e.g. `a::b` will return a 3-element array, as will `::`. +// Separators within pairs of double-quotes will be ignored and stripped, e.g. `"a:b"c:d` will return []{`a:bc`, `d`}. split_list :: proc(path: string, allocator := context.allocator) -> []string { if path == "" { return nil @@ -322,7 +327,7 @@ split_list :: proc(path: string, allocator := context.allocator) -> []string { } start, quote = 0, false - list := make([]string, count, allocator) + list := make([]string, count + 1, allocator) index := 0 for i := 0; i < len(path); i += 1 { c := path[i] @@ -336,6 +341,7 @@ split_list :: proc(path: string, allocator := context.allocator) -> []string { } } assert(index == count) + list[index] = path[start:] for s0, i in list { s, new := strings.replace_all(s0, `"`, ``, allocator) diff --git a/tests/core/Makefile b/tests/core/Makefile index a990c5833..4160690f9 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -2,7 +2,7 @@ ODIN=../../odin PYTHON=$(shell which python3) all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test reflect_test + math_test linalg_glsl_math_test filepath_test reflect_test download_test_assets: $(PYTHON) download_assets.py @@ -36,5 +36,8 @@ math_test: linalg_glsl_math_test: $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -out=test_linalg_glsl_math -collection:tests=.. +filepath_test: + $(ODIN) run path/filepath/test_core_filepath.odin -out=test_core_filepath -collection:tests=.. + reflect_test: $(ODIN) run reflect/test_core_reflect.odin -out=test_core_reflect -collection:tests=.. diff --git a/tests/core/build.bat b/tests/core/build.bat index c94aac10a..2f9ba672e 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -54,6 +54,11 @@ echo Running core:math/linalg/glsl tests echo --- %PATH_TO_ODIN% run math/linalg/glsl %COMMON% +echo --- +echo Running core:path/filepath tests +echo --- +%PATH_TO_ODIN% run path/filepath %COMMON% + echo --- echo Running core:reflect tests echo --- diff --git a/tests/core/path/filepath/test_core_filepath.odin b/tests/core/path/filepath/test_core_filepath.odin new file mode 100644 index 000000000..0268fb62c --- /dev/null +++ b/tests/core/path/filepath/test_core_filepath.odin @@ -0,0 +1,123 @@ +// Tests "path.odin" in "core:path/filepath". +// Must be run with `-collection:tests=` flag, e.g. +// ./odin run tests/core/path/filepath/test_core_filepath.odin -collection:tests=tests +package test_core_filepath + +import "core:fmt" +import "core:path/filepath" +import "core:testing" +import tc "tests:common" + +main :: proc() { + t := testing.T{} + + when ODIN_OS == .Windows { + test_split_list_windows(&t) + } else { + test_split_list_unix(&t) + } + + tc.report(&t) +} + +@test +test_split_list_windows :: proc(t: ^testing.T) { + + using filepath + + Datum :: struct { + i: int, + v: string, + e: [3]string, + } + @static data := []Datum{ + { 0, "C:\\Odin;C:\\Visual Studio;\"C:\\Some Other\"", + [3]string{"C:\\Odin", "C:\\Visual Studio", "C:\\Some Other"} }, // Issue #1537 + { 1, "a;;b", [3]string{"a", "", "b"} }, + { 2, "a;b;", [3]string{"a", "b", ""} }, + { 3, ";a;b", [3]string{"", "a", "b"} }, + { 4, ";;", [3]string{"", "", ""} }, + { 5, "\"a;b\"c;d;\"f\"", [3]string{"a;bc", "d", "f"} }, + { 6, "\"a;b;c\";d\";e\";f", [3]string{"a;b;c", "d;e", "f"} }, + } + + for d, i in data { + assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) + r := split_list(d.v) + defer delete(r) + tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", + i, #procedure, d.v, len(r), len(d.e))) + if len(r) == len(d.e) { + for _, j in r { + tc.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", + i, #procedure, d.v, r[j], j, d.e[j])) + } + } + } + + { + v := "" + r := split_list(v) + tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) + } + { + v := "a" + r := split_list(v) + defer delete(r) + tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) + if len(r) == 1 { + tc.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) + } + } +} + +@test +test_split_list_unix :: proc(t: ^testing.T) { + + using filepath + + Datum :: struct { + i: int, + v: string, + e: [3]string, + } + @static data := []Datum{ + { 0, "/opt/butler:/home/fancykillerpanda/Projects/Odin/Odin:/usr/local/sbin", + [3]string{"/opt/butler", "/home/fancykillerpanda/Projects/Odin/Odin", "/usr/local/sbin"} }, // Issue #1537 + { 1, "a::b", [3]string{"a", "", "b"} }, + { 2, "a:b:", [3]string{"a", "b", ""} }, + { 3, ":a:b", [3]string{"", "a", "b"} }, + { 4, "::", [3]string{"", "", ""} }, + { 5, "\"a:b\"c:d:\"f\"", [3]string{"a:bc", "d", "f"} }, + { 6, "\"a:b:c\":d\":e\":f", [3]string{"a:b:c", "d:e", "f"} }, + } + + for d, i in data { + assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) + r := split_list(d.v) + defer delete(r) + tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", + i, #procedure, d.v, len(r), len(d.e))) + if len(r) == len(d.e) { + for _, j in r { + tc.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", + i, #procedure, d.v, r[j], j, d.e[j])) + } + } + } + + { + v := "" + r := split_list(v) + tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) + } + { + v := "a" + r := split_list(v) + defer delete(r) + tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) + if len(r) == 1 { + tc.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) + } + } +} From 4bd5de34eabf3c5431117caf96bb0bf51ad49678 Mon Sep 17 00:00:00 2001 From: hikari Date: Wed, 23 Mar 2022 22:50:27 +0200 Subject: [PATCH 0427/1052] sys/windows: add several of constants --- core/sys/windows/types.odin | 14 ++++++++++++++ core/sys/windows/window_messages.odin | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index d34231ce6..780d9b634 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -397,6 +397,20 @@ SW_FORCEMINIMIZE : c_int : 11 CW_USEDEFAULT : c_int : -2147483648 +SIZE_RESTORED :: 0 +SIZE_MINIMIZED :: 1 +SIZE_MAXIMIZED :: 2 +SIZE_MAXSHOW :: 3 +SIZE_MAXHIDE :: 4 + +WMSZ_LEFT :: 1 +WMSZ_RIGHT :: 2 +WMSZ_TOP :: 3 +WMSZ_TOPLEFT :: 4 +WMSZ_TOPRIGHT :: 5 +WMSZ_BOTTOM :: 6 +WMSZ_BOTTOMLEFT :: 7 +WMSZ_BOTTOMRIGHT :: 8 _IDC_APPSTARTING := rawptr(uintptr(32650)) _IDC_ARROW := rawptr(uintptr(32512)) diff --git a/core/sys/windows/window_messages.odin b/core/sys/windows/window_messages.odin index f0aa76daa..9c3a30088 100644 --- a/core/sys/windows/window_messages.odin +++ b/core/sys/windows/window_messages.odin @@ -1,3 +1,4 @@ +// +build windows package sys_windows WM_NULL :: 0x0000 @@ -1044,4 +1045,4 @@ OCM_CTLCOLORSCROLLBAR :: 0x2137 OCM_CTLCOLORSTATIC :: 0x2138 OCM_PARENTNOTIFY :: 0x2210 WM_APP :: 0x8000 -WM_RASDIALEVENT :: 0xcccd \ No newline at end of file +WM_RASDIALEVENT :: 0xcccd From 2ccfaa7d4e1bf03d164b4673ee7eef8e9c4eb168 Mon Sep 17 00:00:00 2001 From: hikari Date: Wed, 23 Mar 2022 23:38:53 +0200 Subject: [PATCH 0428/1052] sys/windows: add virtual keycodes --- core/sys/windows/key_codes.odin | 252 ++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 core/sys/windows/key_codes.odin diff --git a/core/sys/windows/key_codes.odin b/core/sys/windows/key_codes.odin new file mode 100644 index 000000000..2f6e01116 --- /dev/null +++ b/core/sys/windows/key_codes.odin @@ -0,0 +1,252 @@ +// +build windows +package sys_windows + +// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +// Virtual Keys, Standard Set +VK_LBUTTON :: 0x01 +VK_RBUTTON :: 0x02 +VK_CANCEL :: 0x03 +VK_MBUTTON :: 0x04 // NOT contiguous with L & RBUTTON +VK_XBUTTON1 :: 0x05 // NOT contiguous with L & RBUTTON +VK_XBUTTON2 :: 0x06 // NOT contiguous with L & RBUTTON + +// 0x07 : reserved + +VK_BACK :: 0x08 +VK_TAB :: 0x09 + +// 0x0A - 0x0B : reserved + +VK_CLEAR :: 0x0C +VK_RETURN :: 0x0D + +// 0x0E - 0x0F : unassigned + +VK_SHIFT :: 0x10 +VK_CONTROL :: 0x11 +VK_MENU :: 0x12 +VK_PAUSE :: 0x13 +VK_CAPITAL :: 0x14 +VK_KANA :: 0x15 +VK_HANGEUL :: 0x15 // old name - should be here for compatibility +VK_HANGUL :: 0x15 +VK_IME_ON :: 0x16 +VK_JUNJA :: 0x17 +VK_FINAL :: 0x18 +VK_HANJA :: 0x19 +VK_KANJI :: 0x19 +VK_IME_OFF :: 0x1A +VK_ESCAPE :: 0x1B +VK_CONVERT :: 0x1C +VK_NONCONVERT :: 0x1D +VK_ACCEPT :: 0x1E +VK_MODECHANGE :: 0x1F +VK_SPACE :: 0x20 +VK_PRIOR :: 0x21 +VK_NEXT :: 0x22 +VK_END :: 0x23 +VK_HOME :: 0x24 +VK_LEFT :: 0x25 +VK_UP :: 0x26 +VK_RIGHT :: 0x27 +VK_DOWN :: 0x28 +VK_SELECT :: 0x29 +VK_PRINT :: 0x2A +VK_EXECUTE :: 0x2B +VK_SNAPSHOT :: 0x2C +VK_INSERT :: 0x2D +VK_DELETE :: 0x2E +VK_HELP :: 0x2F + +VK_0 :: '0' +VK_1 :: '1' +VK_2 :: '2' +VK_3 :: '3' +VK_4 :: '4' +VK_5 :: '5' +VK_6 :: '6' +VK_7 :: '7' +VK_8 :: '8' +VK_9 :: '9' + +// 0x3A - 0x40 : unassigned + +VK_A :: 'A' +VK_B :: 'B' +VK_C :: 'C' +VK_D :: 'D' +VK_E :: 'E' +VK_F :: 'F' +VK_G :: 'G' +VK_H :: 'H' +VK_I :: 'I' +VK_J :: 'J' +VK_K :: 'K' +VK_L :: 'L' +VK_M :: 'M' +VK_N :: 'N' +VK_O :: 'O' +VK_P :: 'P' +VK_Q :: 'Q' +VK_R :: 'R' +VK_S :: 'S' +VK_T :: 'T' +VK_U :: 'U' +VK_V :: 'V' +VK_W :: 'W' +VK_X :: 'X' +VK_Y :: 'Y' +VK_Z :: 'Z' + +VK_LWIN :: 0x5B +VK_RWIN :: 0x5C +VK_APPS :: 0x5D + +// 0x5E : reserved + +VK_SLEEP :: 0x5F +VK_NUMPAD0 :: 0x60 +VK_NUMPAD1 :: 0x61 +VK_NUMPAD2 :: 0x62 +VK_NUMPAD3 :: 0x63 +VK_NUMPAD4 :: 0x64 +VK_NUMPAD5 :: 0x65 +VK_NUMPAD6 :: 0x66 +VK_NUMPAD7 :: 0x67 +VK_NUMPAD8 :: 0x68 +VK_NUMPAD9 :: 0x69 +VK_MULTIPLY :: 0x6A +VK_ADD :: 0x6B +VK_SEPARATOR :: 0x6C +VK_SUBTRACT :: 0x6D +VK_DECIMAL :: 0x6E +VK_DIVIDE :: 0x6F +VK_F1 :: 0x70 +VK_F2 :: 0x71 +VK_F3 :: 0x72 +VK_F4 :: 0x73 +VK_F5 :: 0x74 +VK_F6 :: 0x75 +VK_F7 :: 0x76 +VK_F8 :: 0x77 +VK_F9 :: 0x78 +VK_F10 :: 0x79 +VK_F11 :: 0x7A +VK_F12 :: 0x7B +VK_F13 :: 0x7C +VK_F14 :: 0x7D +VK_F15 :: 0x7E +VK_F16 :: 0x7F +VK_F17 :: 0x80 +VK_F18 :: 0x81 +VK_F19 :: 0x82 +VK_F20 :: 0x83 +VK_F21 :: 0x84 +VK_F22 :: 0x85 +VK_F23 :: 0x86 +VK_F24 :: 0x87 + +// 0x88 - 0x8F : reserved + +VK_NUMLOCK :: 0x90 +VK_SCROLL :: 0x91 + +// NEC PC-9800 kbd definitions +VK_OEM_NEC_EQUAL :: 0x92 // '=' key on numpad + +// Fujitsu/OASYS kbd definitions +VK_OEM_FJ_JISHO :: 0x92 // 'Dictionary' key +VK_OEM_FJ_MASSHOU :: 0x93 // 'Unregister word' key +VK_OEM_FJ_TOUROKU :: 0x94 // 'Register word' key +VK_OEM_FJ_LOYA :: 0x95 // 'Left OYAYUBI' key +VK_OEM_FJ_ROYA :: 0x96 // 'Right OYAYUBI' key + +// 0x97 - 0x9F : unassigned + +// VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys. +// Used only as parameters to GetAsyncKeyState() and GetKeyState(). +// No other API or message will distinguish left and right keys in this way. +VK_LSHIFT :: 0xA0 +VK_RSHIFT :: 0xA1 +VK_LCONTROL :: 0xA2 +VK_RCONTROL :: 0xA3 +VK_LMENU :: 0xA4 +VK_RMENU :: 0xA5 + +VK_BROWSER_BACK :: 0xA6 +VK_BROWSER_FORWARD :: 0xA7 +VK_BROWSER_REFRESH :: 0xA8 +VK_BROWSER_STOP :: 0xA9 +VK_BROWSER_SEARCH :: 0xAA +VK_BROWSER_FAVORITES :: 0xAB +VK_BROWSER_HOME :: 0xAC +VK_VOLUME_MUTE :: 0xAD +VK_VOLUME_DOWN :: 0xAE +VK_VOLUME_UP :: 0xAF +VK_MEDIA_NEXT_TRACK :: 0xB0 +VK_MEDIA_PREV_TRACK :: 0xB1 +VK_MEDIA_STOP :: 0xB2 +VK_MEDIA_PLAY_PAUSE :: 0xB3 +VK_LAUNCH_MAIL :: 0xB4 +VK_LAUNCH_MEDIA_SELECT :: 0xB5 +VK_LAUNCH_APP1 :: 0xB6 +VK_LAUNCH_APP2 :: 0xB7 + +// 0xB8 - 0xB9 : reserved + +VK_OEM_1 :: 0xBA // ';:' for US +VK_OEM_PLUS :: 0xBB // '+' any country +VK_OEM_COMMA :: 0xBC // ',' any country +VK_OEM_MINUS :: 0xBD // '-' any country +VK_OEM_PERIOD :: 0xBE // '.' any country +VK_OEM_2 :: 0xBF // '/?' for US +VK_OEM_3 :: 0xC0 // '`~' for US + +// 0xC1 - 0xDA : reserved + +VK_OEM_4 :: 0xDB // '[{' for US +VK_OEM_5 :: 0xDC // '\|' for US +VK_OEM_6 :: 0xDD // ']}' for US +VK_OEM_7 :: 0xDE // ''"' for US +VK_OEM_8 :: 0xDF + +// 0xE0 : reserved + +// Various extended or enhanced keyboards +VK_OEM_AX :: 0xE1 // 'AX' key on Japanese AX kbd +VK_OEM_102 :: 0xE2 // "<>" or "\|" on RT 102-key kbd. +VK_ICO_HELP :: 0xE3 // Help key on ICO +VK_ICO_00 :: 0xE4 // 00 key on ICO + +VK_PROCESSKEY :: 0xE5 +VK_ICO_CLEAR :: 0xE6 +VK_PACKET :: 0xE7 + +// 0xE8 : unassigned + +// Nokia/Ericsson definitions +VK_OEM_RESET :: 0xE9 +VK_OEM_JUMP :: 0xEA +VK_OEM_PA1 :: 0xEB +VK_OEM_PA2 :: 0xEC +VK_OEM_PA3 :: 0xED +VK_OEM_WSCTRL :: 0xEE +VK_OEM_CUSEL :: 0xEF +VK_OEM_ATTN :: 0xF0 +VK_OEM_FINISH :: 0xF1 +VK_OEM_COPY :: 0xF2 +VK_OEM_AUTO :: 0xF3 +VK_OEM_ENLW :: 0xF4 +VK_OEM_BACKTAB :: 0xF5 + +VK_ATTN :: 0xF6 +VK_CRSEL :: 0xF7 +VK_EXSEL :: 0xF8 +VK_EREOF :: 0xF9 +VK_PLAY :: 0xFA +VK_ZOOM :: 0xFB +VK_NONAME :: 0xFC +VK_PA1 :: 0xFD +VK_OEM_CLEAR :: 0xFE + +// 0xFF : reserved From 3f935bea2505b3ee7e169a29b7aed50c0e5614b7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 24 Mar 2022 11:55:03 +0000 Subject: [PATCH 0429/1052] `union #shared_nil` This adds a feature to `union` which requires all the variants to have a `nil` value and on assign to the union, checks whether that value is `nil` or not. If the value is `nil`, the union will be `nil` (thus sharing the `nil` value) --- core/runtime/core.odin | 1 + src/check_expr.cpp | 7 +++++-- src/check_type.cpp | 19 ++++++++++++++----- src/docs_format.cpp | 1 + src/docs_writer.cpp | 8 +++++--- src/llvm_backend_general.cpp | 31 ++++++++++++++++++++++++++++--- src/llvm_backend_type.cpp | 7 ++++--- src/parser.cpp | 30 ++++++++++++++++++++++++++---- src/parser.hpp | 10 ++++++++-- src/types.cpp | 22 ++++++++++++---------- 10 files changed, 104 insertions(+), 32 deletions(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 8c95a234f..a5a190a9c 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -136,6 +136,7 @@ Type_Info_Union :: struct { custom_align: bool, no_nil: bool, maybe: bool, + shared_nil: bool, } Type_Info_Enum :: struct { base: ^Type_Info, diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 66bf8bbd7..dcf17af39 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10047,8 +10047,11 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { str = write_expr_to_string(str, st->polymorphic_params, shorthand); str = gb_string_appendc(str, ") "); } - if (st->no_nil) str = gb_string_appendc(str, "#no_nil "); - if (st->maybe) str = gb_string_appendc(str, "#maybe "); + switch (st->kind) { + case UnionType_maybe: str = gb_string_appendc(str, "#maybe "); break; + case UnionType_no_nil: str = gb_string_appendc(str, "#no_nil "); break; + case UnionType_shared_nil: str = gb_string_appendc(str, "#shared_nil "); break; + } if (st->align) { str = gb_string_appendc(str, "#align "); str = write_expr_to_string(str, st->align, shorthand); diff --git a/src/check_type.cpp b/src/check_type.cpp index 3c7f33a46..51f472961 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -675,22 +675,31 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Arraykind == UnionType_shared_nil) { + if (!type_has_nil(t)) { + gbString s = type_to_string(t); + error(node, "Each variant of a union with #shared_nil must have a 'nil' value, got %s", s); + gb_string_free(s); + } + } } } } union_type->Union.variants = slice_from_array(variants); - union_type->Union.no_nil = ut->no_nil; - union_type->Union.maybe = ut->maybe; - if (union_type->Union.no_nil) { + union_type->Union.kind = ut->kind; + switch (ut->kind) { + case UnionType_no_nil: if (variants.count < 2) { error(ut->align, "A union with #no_nil must have at least 2 variants"); } - } - if (union_type->Union.maybe) { + break; + case UnionType_maybe: if (variants.count != 1) { error(ut->align, "A union with #maybe must have at 1 variant, got %lld", cast(long long)variants.count); } + break; } if (ut->align != nullptr) { diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 7ce93d2bf..ee32d0e05 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -99,6 +99,7 @@ enum OdinDocTypeFlag_Union : u32 { OdinDocTypeFlag_Union_polymorphic = 1<<0, OdinDocTypeFlag_Union_no_nil = 1<<1, OdinDocTypeFlag_Union_maybe = 1<<2, + OdinDocTypeFlag_Union_shared_nil = 1<<3, }; enum OdinDocTypeFlag_Proc : u32 { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 2c5186c39..0ad10ac49 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -619,9 +619,11 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { case Type_Union: doc_type.kind = OdinDocType_Union; if (type->Union.is_polymorphic) { doc_type.flags |= OdinDocTypeFlag_Union_polymorphic; } - if (type->Union.no_nil) { doc_type.flags |= OdinDocTypeFlag_Union_no_nil; } - if (type->Union.maybe) { doc_type.flags |= OdinDocTypeFlag_Union_maybe; } - + switch (type->Union.kind) { + case UnionType_maybe: doc_type.flags |= OdinDocTypeFlag_Union_maybe; break; + case UnionType_no_nil: doc_type.flags |= OdinDocTypeFlag_Union_no_nil; break; + case UnionType_shared_nil: doc_type.flags |= OdinDocTypeFlag_Union_shared_nil; break; + } { auto variants = array_make(heap_allocator(), type->Union.variants.count); defer (array_free(&variants)); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index dd1555193..f6dd97966 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1176,10 +1176,35 @@ void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, Type *varia } void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) { - lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); + Type *pt = base_type(type_deref(parent.type)); + GB_ASSERT(pt->kind == Type_Union); + if (pt->Union.kind == UnionType_shared_nil) { + lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil"); + lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil"); + lbBlock *done = lb_create_block(p, "shared_nil.done"); - lb_emit_store(p, underlying, variant); - lb_emit_store_union_variant_tag(p, parent, variant_type); + lbValue cond_is_nil = lb_emit_comp_against_nil(p, Token_CmpEq, variant); + lb_emit_if(p, cond_is_nil, if_nil, if_not_nil); + + lb_start_block(p, if_nil); + lb_emit_store(p, parent, lb_const_nil(p->module, type_deref(parent.type))); + lb_emit_jump(p, done); + + lb_start_block(p, if_not_nil); + lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); + lb_emit_store(p, underlying, variant); + lb_emit_store_union_variant_tag(p, parent, variant_type); + lb_emit_jump(p, done); + + lb_start_block(p, done); + + + } else { + lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); + + lb_emit_store(p, underlying, variant); + lb_emit_store_union_variant_tag(p, parent, variant_type); + } } diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index e245a8b40..7d73956e8 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -641,7 +641,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_union_ptr); { - LLVMValueRef vals[7] = {}; + LLVMValueRef vals[8] = {}; isize variant_count = gb_max(0, t->Union.variants.count); lbValue memory_types = lb_type_info_member_types_offset(p, variant_count); @@ -675,8 +675,9 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da } vals[4] = lb_const_bool(m, t_bool, t->Union.custom_align != 0).value; - vals[5] = lb_const_bool(m, t_bool, t->Union.no_nil).value; - vals[6] = lb_const_bool(m, t_bool, t->Union.maybe).value; + vals[5] = lb_const_bool(m, t_bool, t->Union.kind == UnionType_no_nil).value; + vals[6] = lb_const_bool(m, t_bool, t->Union.kind == UnionType_maybe).value; + vals[7] = lb_const_bool(m, t_bool, t->Union.kind == UnionType_shared_nil).value; for (isize i = 0; i < gb_count_of(vals); i++) { if (vals[i] == nullptr) { diff --git a/src/parser.cpp b/src/parser.cpp index a435d1317..767119aa8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1071,15 +1071,14 @@ Ast *ast_struct_type(AstFile *f, Token token, Slice fields, isize field_c } -Ast *ast_union_type(AstFile *f, Token token, Array const &variants, Ast *polymorphic_params, Ast *align, bool no_nil, bool maybe, +Ast *ast_union_type(AstFile *f, Token token, Array const &variants, Ast *polymorphic_params, Ast *align, UnionTypeKind kind, Token where_token, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_UnionType); result->UnionType.token = token; result->UnionType.variants = slice_from_array(variants); result->UnionType.polymorphic_params = polymorphic_params; result->UnionType.align = align; - result->UnionType.no_nil = no_nil; - result->UnionType.maybe = maybe; + result->UnionType.kind = kind; result->UnionType.where_token = where_token; result->UnionType.where_clauses = slice_from_array(where_clauses); return result; @@ -2475,6 +2474,9 @@ Ast *parse_operand(AstFile *f, bool lhs) { Ast *align = nullptr; bool no_nil = false; bool maybe = false; + bool shared_nil = false; + + UnionTypeKind union_kind = UnionType_Normal; Token start_token = f->curr_token; @@ -2501,6 +2503,11 @@ Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "Duplicate union tag '#%.*s'", LIT(tag.string)); } no_nil = true; + } else if (tag.string == "shared_nil") { + if (shared_nil) { + syntax_error(tag, "Duplicate union tag '#%.*s'", LIT(tag.string)); + } + shared_nil = true; } else if (tag.string == "maybe") { if (maybe) { syntax_error(tag, "Duplicate union tag '#%.*s'", LIT(tag.string)); @@ -2513,6 +2520,21 @@ Ast *parse_operand(AstFile *f, bool lhs) { if (no_nil && maybe) { syntax_error(f->curr_token, "#maybe and #no_nil cannot be applied together"); } + if (no_nil && shared_nil) { + syntax_error(f->curr_token, "#shared_nil and #no_nil cannot be applied together"); + } + if (shared_nil && maybe) { + syntax_error(f->curr_token, "#maybe and #shared_nil cannot be applied together"); + } + + + if (maybe) { + union_kind = UnionType_maybe; + } else if (no_nil) { + union_kind = UnionType_no_nil; + } else if (shared_nil) { + union_kind = UnionType_shared_nil; + } skip_possible_newline_for_literal(f); @@ -2544,7 +2566,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { Token close = expect_closing_brace_of_field_list(f); - return ast_union_type(f, token, variants, polymorphic_params, align, no_nil, maybe, where_token, where_clauses); + return ast_union_type(f, token, variants, polymorphic_params, align, union_kind, where_token, where_clauses); } break; case Token_enum: { diff --git a/src/parser.hpp b/src/parser.hpp index c33d1520b..c7b4fd0d8 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -330,6 +330,13 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = { "intel", }; +enum UnionTypeKind : u8 { + UnionType_Normal = 0, + UnionType_maybe = 1, + UnionType_no_nil = 2, + UnionType_shared_nil = 3, +}; + #define AST_KINDS \ AST_KIND(Ident, "identifier", struct { \ Token token; \ @@ -678,8 +685,7 @@ AST_KIND(_TypeBegin, "", bool) \ Slice variants; \ Ast *polymorphic_params; \ Ast * align; \ - bool maybe; \ - bool no_nil; \ + UnionTypeKind kind; \ Token where_token; \ Slice where_clauses; \ }) \ diff --git a/src/types.cpp b/src/types.cpp index ef770c846..b231218a2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -165,9 +165,8 @@ struct TypeUnion { i16 tag_size; bool is_polymorphic; - bool is_poly_specialized : 1; - bool no_nil : 1; - bool maybe : 1; + bool is_poly_specialized; + UnionTypeKind kind; }; struct TypeProc { @@ -1664,7 +1663,7 @@ bool is_type_map(Type *t) { bool is_type_union_maybe_pointer(Type *t) { t = base_type(t); - if (t->kind == Type_Union && t->Union.maybe) { + if (t->kind == Type_Union && t->Union.kind == UnionType_maybe) { if (t->Union.variants.count == 1) { Type *v = t->Union.variants[0]; return is_type_pointer(v) || is_type_multi_pointer(v); @@ -1676,7 +1675,7 @@ bool is_type_union_maybe_pointer(Type *t) { bool is_type_union_maybe_pointer_original_alignment(Type *t) { t = base_type(t); - if (t->kind == Type_Union && t->Union.maybe) { + if (t->kind == Type_Union && t->Union.kind == UnionType_maybe) { if (t->Union.variants.count == 1) { Type *v = t->Union.variants[0]; if (is_type_pointer(v) || is_type_multi_pointer(v)) { @@ -2168,7 +2167,7 @@ bool type_has_nil(Type *t) { case Type_Map: return true; case Type_Union: - return !t->Union.no_nil; + return t->Union.kind != UnionType_no_nil; case Type_Struct: if (is_type_soa_struct(t)) { switch (t->Struct.soa_kind) { @@ -2454,7 +2453,7 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) { if (y->kind == Type_Union) { if (x->Union.variants.count == y->Union.variants.count && x->Union.custom_align == y->Union.custom_align && - x->Union.no_nil == y->Union.no_nil) { + x->Union.kind == y->Union.kind) { // NOTE(bill): zeroth variant is nullptr for_array(i, x->Union.variants) { if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) { @@ -2598,7 +2597,7 @@ i64 union_variant_index(Type *u, Type *v) { for_array(i, u->Union.variants) { Type *vt = u->Union.variants[i]; if (are_types_identical(v, vt)) { - if (u->Union.no_nil) { + if (u->Union.kind == UnionType_no_nil) { return cast(i64)(i+0); } else { return cast(i64)(i+1); @@ -4021,8 +4020,11 @@ gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { case Type_Union: str = gb_string_appendc(str, "union"); - if (type->Union.no_nil != 0) str = gb_string_appendc(str, " #no_nil"); - if (type->Union.maybe != 0) str = gb_string_appendc(str, " #maybe"); + switch (type->Union.kind) { + case UnionType_maybe: str = gb_string_appendc(str, " #maybe"); break; + case UnionType_no_nil: str = gb_string_appendc(str, " #no_nil"); break; + case UnionType_shared_nil: str = gb_string_appendc(str, " #shared_nil"); break; + } if (type->Union.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Union.custom_align); str = gb_string_appendc(str, " {"); for_array(i, type->Union.variants) { From 13cb894b309faa2dc66b77f1aa4e89fdffba9512 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 24 Mar 2022 12:00:27 +0000 Subject: [PATCH 0430/1052] Update `core:odin` for `union #shared_nil` --- core/odin/ast/ast.odin | 10 ++++++++-- core/odin/parser/parser.odin | 32 ++++++++++++++++++++++++++++---- core/odin/printer/visit.odin | 7 +++++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 740299539..f4aa67446 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -708,13 +708,19 @@ Struct_Type :: struct { name_count: int, } +Union_Type_Kind :: enum u8 { + Normal, + maybe, + no_nil, + shared_nil, +} + Union_Type :: struct { using node: Expr, tok_pos: tokenizer.Pos, poly_params: ^Field_List, align: ^Expr, - is_maybe: bool, - is_no_nil: bool, + kind: Union_Type_Kind, where_token: tokenizer.Token, where_clauses: []^Expr, variants: []^Expr, diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 1546dce2d..4be14f2cf 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2630,8 +2630,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tok := expect_token(p, .Union) poly_params: ^ast.Field_List align: ^ast.Expr - is_maybe: bool - is_no_nil: bool + is_maybe: bool + is_no_nil: bool + is_shared_nil: bool if allow_token(p, .Open_Paren) { param_count: int @@ -2663,12 +2664,34 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, tag.pos, "duplicate union tag '#%s'", tag.text) } is_no_nil = true + case "shared_nil": + if is_shared_nil { + error(p, tag.pos, "duplicate union tag '#%s'", tag.text) + } + is_shared_nil = true case: error(p, tag.pos, "invalid union tag '#%s", tag.text) } } p.expr_level = prev_level + if is_no_nil && is_maybe { + error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together"); + } + if is_no_nil && is_shared_nil { + error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together"); + } + if is_shared_nil && is_maybe { + error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together"); + } + + union_kind := ast.Union_Type_Kind.Normal + switch { + case is_maybe: union_kind = .maybe + case is_no_nil: union_kind = .no_nil + case is_shared_nil: union_kind = .shared_nil + } + where_token: tokenizer.Token where_clauses: []^ast.Expr @@ -2699,14 +2722,15 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { close := expect_closing_brace_of_field_list(p) + + ut := ast.new(ast.Union_Type, tok.pos, end_pos(close)) ut.poly_params = poly_params ut.variants = variants[:] ut.align = align ut.where_token = where_token ut.where_clauses = where_clauses - ut.is_maybe = is_maybe - ut.is_no_nil = is_no_nil + ut.kind = union_kind return ut diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 9eba29987..70140f180 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -1046,8 +1046,11 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_poly_params(p, v.poly_params) - if v.is_maybe { - push_ident_token(p, "#maybe", 1) + switch v.kind { + case .Normal: + case .maybe: push_ident_token(p, "#maybe", 1) + case .no_nil: push_ident_token(p, "#no_nil", 1) + case .shared_nil: push_ident_token(p, "#shared_nil", 1) } push_where_clauses(p, v.where_clauses) From b6b33777865239794a1f50e64659343e397ea289 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 24 Mar 2022 12:02:50 +0000 Subject: [PATCH 0431/1052] Remove unneeded semicolons --- core/odin/parser/parser.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 4be14f2cf..25eda6bed 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2676,13 +2676,13 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { p.expr_level = prev_level if is_no_nil && is_maybe { - error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together"); + error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together") } if is_no_nil && is_shared_nil { - error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together"); + error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together") } if is_shared_nil && is_maybe { - error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together"); + error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together") } union_kind := ast.Union_Type_Kind.Normal From 17e36bd5e1478022b3206814fe09916400cdda78 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 24 Mar 2022 12:06:18 +0000 Subject: [PATCH 0432/1052] Utilize `union #shared_nil` to `core:image` `Error` --- core/compress/common.odin | 7 ++++- core/compress/zlib/zlib.odin | 56 ++++++++++++++++++------------------ core/image/common.odin | 3 +- core/image/png/helpers.odin | 6 ++-- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/core/compress/common.odin b/core/compress/common.odin index fb0f74e95..58aeac25b 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -47,7 +47,7 @@ when size_of(uintptr) == 8 { } -Error :: union { +Error :: union #shared_nil { General_Error, Deflate_Error, ZLIB_Error, @@ -58,6 +58,7 @@ Error :: union { } General_Error :: enum { + None = 0, File_Not_Found, Cannot_Open_File, File_Too_Short, @@ -76,6 +77,7 @@ General_Error :: enum { } GZIP_Error :: enum { + None = 0, Invalid_GZIP_Signature, Reserved_Flag_Set, Invalid_Extra_Data, @@ -100,6 +102,7 @@ GZIP_Error :: enum { } ZIP_Error :: enum { + None = 0, Invalid_ZIP_File_Signature, Unexpected_Signature, Insert_Next_Disk, @@ -107,6 +110,7 @@ ZIP_Error :: enum { } ZLIB_Error :: enum { + None = 0, Unsupported_Window_Size, FDICT_Unsupported, Unsupported_Compression_Level, @@ -114,6 +118,7 @@ ZLIB_Error :: enum { } Deflate_Error :: enum { + None = 0, Huffman_Bad_Sizes, Huffman_Bad_Code_Lengths, Inflate_Error, diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index d4b770929..d76f0f9aa 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -48,9 +48,9 @@ Options :: struct { } Error :: compress.Error -E_General :: compress.General_Error -E_ZLIB :: compress.ZLIB_Error -E_Deflate :: compress.Deflate_Error +General_Error :: compress.General_Error +ZLIB_Error :: compress.ZLIB_Error +Deflate_Error :: compress.Deflate_Error DEFLATE_MAX_CHUNK_SIZE :: 65535 DEFLATE_MAX_LITERAL_SIZE :: 65535 @@ -258,7 +258,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) { for i in 1 ..< HUFFMAN_MAX_BITS { if sizes[i] > (1 << uint(i)) { - return E_Deflate.Huffman_Bad_Sizes + return .Huffman_Bad_Sizes } } code := int(0) @@ -270,7 +270,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) { code = code + sizes[i] if sizes[i] != 0 { if code - 1 >= (1 << u16(i)) { - return E_Deflate.Huffman_Bad_Code_Lengths + return .Huffman_Bad_Code_Lengths } } z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i)) @@ -314,15 +314,15 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro s += 1 } if s >= 16 { - return 0, E_Deflate.Bad_Huffman_Code + return 0, .Bad_Huffman_Code } // code size is s, so: b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s]) if b >= size_of(t.size) { - return 0, E_Deflate.Bad_Huffman_Code + return 0, .Bad_Huffman_Code } if t.size[b] != s { - return 0, E_Deflate.Bad_Huffman_Code + return 0, .Bad_Huffman_Code } compress.consume_bits_lsb(z, s) @@ -335,11 +335,11 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check { if z.num_bits < 16 { if z.num_bits > 63 { - return 0, E_ZLIB.Code_Buffer_Malformed + return 0, .Code_Buffer_Malformed } compress.refill_lsb(z) if z.num_bits > 63 { - return 0, E_General.Stream_Too_Short + return 0, .Stream_Too_Short } } #no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK] @@ -361,7 +361,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: if value < 256 { e := write_byte(z, u8(value)) if e != .None { - return E_General.Output_Too_Short + return .Output_Too_Short } } else { if value == 256 { @@ -377,7 +377,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: value, e = decode_huffman(z, z_offset) if e != nil { - return E_Deflate.Bad_Huffman_Code + return .Bad_Huffman_Code } distance := Z_DIST_BASE[value] @@ -387,7 +387,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: if z.bytes_written < i64(distance) { // Distance is longer than we've decoded so far. - return E_Deflate.Bad_Distance + return .Bad_Distance } /* @@ -405,14 +405,14 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: c := z.output.buf[z.bytes_written - i64(distance)] e := repl_byte(z, length, c) if e != .None { - return E_General.Output_Too_Short + return .Output_Too_Short } } } else { if length > 0 { e := repl_bytes(z, length, distance) if e != .None { - return E_General.Output_Too_Short + return .Output_Too_Short } } } @@ -432,25 +432,25 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f if !raw { size, size_err := compress.input_size(ctx) if size < 6 || size_err != nil { - return E_General.Stream_Too_Short + return .Stream_Too_Short } cmf, _ := compress.read_u8(ctx) method := Compression_Method(cmf & 0xf) if method != .DEFLATE { - return E_General.Unknown_Compression_Method + return .Unknown_Compression_Method } if cinfo := (cmf >> 4) & 0xf; cinfo > 7 { - return E_ZLIB.Unsupported_Window_Size + return .Unsupported_Window_Size } flg, _ := compress.read_u8(ctx) fcheck := flg & 0x1f fcheck_computed := (cmf << 8 | flg) & 0x1f if fcheck != fcheck_computed { - return E_General.Checksum_Failed + return .Checksum_Failed } /* @@ -458,7 +458,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f They're application specific and PNG doesn't use them. */ if fdict := (flg >> 5) & 1; fdict != 0 { - return E_ZLIB.FDICT_Unsupported + return .FDICT_Unsupported } // flevel := Compression_Level((flg >> 6) & 3); @@ -485,7 +485,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f output_hash := hash.adler32(ctx.output.buf[:]) if output_hash != u32(adler) { - return E_General.Checksum_Failed + return .Checksum_Failed } } return nil @@ -555,7 +555,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all if ~uncompressed_len != length_check { - return E_Deflate.Len_Nlen_Mismatch + return .Len_Nlen_Mismatch } /* @@ -571,7 +571,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all assert(uncompressed_len == 0) case 3: - return E_Deflate.BType_3 + return .BType_3 case: // fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type) if type == 1 { @@ -604,7 +604,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all c = decode_huffman(z, codelength_ht) or_return if c < 0 || c >= 19 { - return E_Deflate.Huffman_Bad_Code_Lengths + return .Huffman_Bad_Code_Lengths } if c < 16 { lencodes[n] = u8(c) @@ -616,7 +616,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all case 16: c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3) if n == 0 { - return E_Deflate.Huffman_Bad_Code_Lengths + return .Huffman_Bad_Code_Lengths } fill = lencodes[n - 1] case 17: @@ -624,11 +624,11 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all case 18: c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11) case: - return E_Deflate.Huffman_Bad_Code_Lengths + return .Huffman_Bad_Code_Lengths } if ntot - n < u32(c) { - return E_Deflate.Huffman_Bad_Code_Lengths + return .Huffman_Bad_Code_Lengths } nc := n + u32(c) @@ -639,7 +639,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all } if n != ntot { - return E_Deflate.Huffman_Bad_Code_Lengths + return .Huffman_Bad_Code_Lengths } build_huffman(z_repeat, lencodes[:hlit]) or_return diff --git a/core/image/common.odin b/core/image/common.odin index d72b770d5..adaa094d8 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -118,7 +118,7 @@ Option :: enum { } Options :: distinct bit_set[Option] -Error :: union { +Error :: union #shared_nil { General_Image_Error, PNG_Error, @@ -137,6 +137,7 @@ General_Image_Error :: enum { } PNG_Error :: enum { + None = 0, Invalid_PNG_Signature, IHDR_Not_First_Chunk, IHDR_Corrupt, diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index 6ec674544..c64e6f471 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -439,7 +439,7 @@ when false { flags: int = O_WRONLY|O_CREATE|O_TRUNC if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) { - return E_PNG.Invalid_Image_Dimensions + return .Invalid_Image_Dimensions } mode: int = 0 @@ -450,7 +450,7 @@ when false { fd, fderr := open(filename, flags, mode) if fderr != 0 { - return E_General.Cannot_Open_File + return .Cannot_Open_File } defer close(fd) @@ -473,7 +473,7 @@ when false { case 3: ihdr.color_type = Color_Type{.Color} case 4: ihdr.color_type = Color_Type{.Color, .Alpha} case:// Unhandled - return E_PNG.Unknown_Color_Type + return .Unknown_Color_Type } h := make_chunk(ihdr, .IHDR) write_chunk(fd, h) From 1baeb9406f5deb309a87e10b848567fc1b30a695 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 24 Mar 2022 12:11:31 +0000 Subject: [PATCH 0433/1052] Utilize `union #shared_nil` in more places --- core/bufio/scanner.odin | 9 +++------ core/compress/zlib/zlib.odin | 2 +- core/encoding/json/marshal.odin | 7 ++++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/core/bufio/scanner.odin b/core/bufio/scanner.odin index cc3b4533a..86e6d8eb0 100644 --- a/core/bufio/scanner.odin +++ b/core/bufio/scanner.odin @@ -8,6 +8,7 @@ import "core:intrinsics" // Extra errors returns by scanning procedures Scanner_Extra_Error :: enum i32 { + None, Negative_Advance, Advanced_Too_Far, Bad_Read_Count, @@ -15,7 +16,7 @@ Scanner_Extra_Error :: enum i32 { Too_Short, } -Scanner_Error :: union { +Scanner_Error :: union #shared_nil { io.Error, Scanner_Extra_Error, } @@ -68,7 +69,7 @@ scanner_destroy :: proc(s: ^Scanner) { // Returns the first non-EOF error that was encounted by the scanner scanner_error :: proc(s: ^Scanner) -> Scanner_Error { switch s._err { - case .EOF, .None: + case .EOF, nil: return nil } return s._err @@ -93,10 +94,6 @@ scanner_text :: proc(s: ^Scanner) -> string { // scanner_scan advances the scanner scanner_scan :: proc(s: ^Scanner) -> bool { set_err :: proc(s: ^Scanner, err: Scanner_Error) { - err := err - if err == .None { - err = nil - } switch s._err { case nil, .EOF: s._err = err diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index d76f0f9aa..855eef7a8 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -47,7 +47,7 @@ Options :: struct { level: u8, } -Error :: compress.Error +Error :: compress.Error General_Error :: compress.General_Error ZLIB_Error :: compress.ZLIB_Error Deflate_Error :: compress.Deflate_Error diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index aa1c1559c..9c54f35f0 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -8,17 +8,18 @@ import "core:strings" import "core:io" Marshal_Data_Error :: enum { + None, Unsupported_Type, } -Marshal_Error :: union { +Marshal_Error :: union #shared_nil { Marshal_Data_Error, io.Error, } marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) { b := strings.make_builder(allocator) - defer if err != .None { + defer if err != nil { strings.destroy_builder(&b) } @@ -27,7 +28,7 @@ marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: M if len(b.buf) != 0 { data = b.buf[:] } - return data, .None + return data, nil } marshal_to_builder :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { From 7203560b06c1e70dcc91d39a5ee562038ac76281 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 24 Mar 2022 12:15:03 +0000 Subject: [PATCH 0434/1052] Fix test --- tests/core/encoding/json/test_core_json.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin index 60e71bf72..285cc04a1 100644 --- a/tests/core/encoding/json/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -88,5 +88,5 @@ marshal_json :: proc(t: ^testing.T) { _, err := json.marshal(my_struct) - expect(t, err == .None, "expected json error to be none") + expect(t, err == nil, "expected json error to be none") } From f702c782f15994cfab165c58a8415d122f7c9d0d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 24 Mar 2022 12:18:17 +0000 Subject: [PATCH 0435/1052] Make constant string backing structures use PrivateLinkage compared to InternalLinkage --- src/llvm_backend_general.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index f6dd97966..330059622 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2337,7 +2337,7 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); LLVMSetInitializer(global_data, data); - LLVMSetLinkage(global_data, LLVMInternalLinkage); + LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); string_map_set(&m->const_strings, key, ptr); @@ -2379,7 +2379,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) } LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); LLVMSetInitializer(global_data, data); - LLVMSetLinkage(global_data, LLVMInternalLinkage); + LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMValueRef ptr = nullptr; if (str.len != 0) { @@ -2615,7 +2615,7 @@ lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String g.value = LLVMAddGlobal(m->mod, lb_type(m, t), text); g.type = alloc_type_pointer(t); LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g.value, LLVMInternalLinkage); + LLVMSetLinkage(g.value, LLVMPrivateLinkage); string_map_set(&m->members, s, g); return g; } From 01181517dc8c3b0970f01f9368ba952e8d21822a Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 24 Mar 2022 16:04:27 +0200 Subject: [PATCH 0436/1052] sys/windows: add GetKeyState functions --- core/sys/windows/user32.odin | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 705b9253a..fc001f26b 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -108,6 +108,9 @@ foreign user32 { BeginPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> HDC --- EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- + + GetKeyState :: proc(nVirtKey: c_int) -> SHORT --- + GetAsyncKeyState :: proc(vKey: c_int) -> SHORT --- } CreateWindowA :: #force_inline proc "stdcall" ( From a3b1ac3133292e984b99b106d14959db1662874f Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 24 Mar 2022 17:27:05 +0200 Subject: [PATCH 0437/1052] sys/windows: add basic Gdi32.lib support --- core/sys/windows/gdi32.odin | 66 +++++++++++++ core/sys/windows/types.odin | 185 +++++++++++++++++++++++++++++++++++- 2 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 core/sys/windows/gdi32.odin diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin new file mode 100644 index 000000000..2caf42753 --- /dev/null +++ b/core/sys/windows/gdi32.odin @@ -0,0 +1,66 @@ +// +build windows +package sys_windows + +foreign import gdi32 "system:Gdi32.lib" + +@(default_calling_convention="stdcall") +foreign gdi32 { + GetStockObject :: proc(i: c_int) -> HGDIOBJ --- + SelectObject :: proc(hdc: HDC, h: HGDIOBJ) -> HGDIOBJ --- + + CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- + + CreateDIBitmap :: proc( + hdc: HDC, + pbmih: ^BITMAPINFOHEADER, + flInit: DWORD, + pjBits: ^VOID, + pbmi: ^BITMAPINFO, + iUsage: UINT, + ) -> HBITMAP --- + + CreateDIBSection :: proc( + hdc: HDC, + pbmi: ^BITMAPINFO, + usage: UINT, + ppvBits: ^^VOID, + hSection: HANDLE, + offset: DWORD, + ) -> HBITMAP --- + + StretchDIBits :: proc( + hdc: HDC, + xDest: c_int, + yDest: c_int, + DestWidth: c_int, + DestHeight: c_int, + xSrc: c_int, + ySrc: c_int, + SrcWidth: c_int, + SrcHeight: c_int, + lpBits: ^VOID, + lpbmi: ^BITMAPINFO, + iUsage: UINT, + rop: DWORD, + ) -> c_int --- + + StretchBlt :: proc( + hdcDest: HDC, + xDest: c_int, + yDest: c_int, + wDest: c_int, + hDest: c_int, + hdcSrc: HDC, + xSrc: c_int, + ySrc: c_int, + wSrc: c_int, + hSrc: c_int, + rop: DWORD, + ) -> BOOL --- + + SetPixelFormat :: proc(hdc: HDC, format: c_int, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL --- + ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int --- + SwapBuffers :: proc(HDC) -> BOOL --- + + PatBlt :: proc(hdc: HDC, x, y, w, h: c_int, rop: DWORD) -> BOOL --- +} diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 780d9b634..9a4a1ab5e 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -27,6 +27,9 @@ HICON :: distinct HANDLE HCURSOR :: distinct HANDLE HMENU :: distinct HANDLE HBRUSH :: distinct HANDLE +HGDIOBJ :: distinct HANDLE +HBITMAP :: distinct HANDLE +HGLOBAL :: distinct HANDLE BOOL :: distinct b32 BYTE :: distinct u8 BOOLEAN :: distinct b8 @@ -92,7 +95,8 @@ LPPROCESS_INFORMATION :: ^PROCESS_INFORMATION PSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES LPSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES LPSTARTUPINFO :: ^STARTUPINFO -PVOID :: rawptr +VOID :: rawptr +PVOID :: rawptr LPVOID :: rawptr PINT :: ^INT LPINT :: ^INT @@ -466,6 +470,185 @@ IDI_ERROR := IDI_HAND IDI_INFORMATION := IDI_ASTERISK +// DIB color table identifiers +DIB_RGB_COLORS :: 0 +DIB_PAL_COLORS :: 1 + +// constants for CreateDIBitmap +CBM_INIT :: 0x04 // initialize bitmap + +// Region Flags +ERROR :: 0 +NULLREGION :: 1 +SIMPLEREGION :: 2 +COMPLEXREGION :: 3 +RGN_ERROR :: ERROR + +// StretchBlt() Modes +BLACKONWHITE :: 1 +WHITEONBLACK :: 2 +COLORONCOLOR :: 3 +HALFTONE :: 4 +MAXSTRETCHBLTMODE :: 4 + +// Binary raster ops +R2_BLACK :: 1 // 0 +R2_NOTMERGEPEN :: 2 // DPon +R2_MASKNOTPEN :: 3 // DPna +R2_NOTCOPYPEN :: 4 // PN +R2_MASKPENNOT :: 5 // PDna +R2_NOT :: 6 // Dn +R2_XORPEN :: 7 // DPx +R2_NOTMASKPEN :: 8 // DPan +R2_MASKPEN :: 9 // DPa +R2_NOTXORPEN :: 10 // DPxn +R2_NOP :: 11 // D +R2_MERGENOTPEN :: 12 // DPno +R2_COPYPEN :: 13 // P +R2_MERGEPENNOT :: 14 // PDno +R2_MERGEPEN :: 15 // DPo +R2_WHITE :: 16 // 1 +R2_LAST :: 16 + +// Ternary raster operations +SRCCOPY : DWORD : 0x00CC0020 // dest = source +SRCPAINT : DWORD : 0x00EE0086 // dest = source OR dest +SRCAND : DWORD : 0x008800C6 // dest = source AND dest +SRCINVERT : DWORD : 0x00660046 // dest = source XOR dest +SRCERASE : DWORD : 0x00440328 // dest = source AND (NOT dest) +NOTSRCCOPY : DWORD : 0x00330008 // dest = (NOT source) +NOTSRCERASE : DWORD : 0x001100A6 // dest = (NOT src) AND (NOT dest) +MERGECOPY : DWORD : 0x00C000CA // dest = (source AND pattern +MERGEPAINT : DWORD : 0x00BB0226 // dest = (NOT source) OR dest +PATCOPY : DWORD : 0x00F00021 // dest = pattern +PATPAINT : DWORD : 0x00FB0A09 // dest = DPSnoo +PATINVERT : DWORD : 0x005A0049 // dest = pattern XOR dest +DSTINVERT : DWORD : 0x00550009 // dest = (NOT dest) +BLACKNESS : DWORD : 0x00000042 // dest = BLACK +WHITENESS : DWORD : 0x00FF0062 // dest = WHITE +NOMIRRORBITMAP : DWORD : 0x80000000 // Do not Mirror the bitmap in this call +CAPTUREBLT : DWORD : 0x40000000 // Include layered windows + +// Stock Logical Objects +WHITE_BRUSH :: 0 +LTGRAY_BRUSH :: 1 +GRAY_BRUSH :: 2 +DKGRAY_BRUSH :: 3 +BLACK_BRUSH :: 4 +NULL_BRUSH :: 5 +HOLLOW_BRUSH :: NULL_BRUSH +WHITE_PEN :: 6 +BLACK_PEN :: 7 +NULL_PEN :: 8 +OEM_FIXED_FONT :: 10 +ANSI_FIXED_FONT :: 11 +ANSI_VAR_FONT :: 12 +SYSTEM_FONT :: 13 +DEVICE_DEFAULT_FONT :: 14 +DEFAULT_PALETTE :: 15 +SYSTEM_FIXED_FONT :: 16 +DEFAULT_GUI_FONT :: 17 +DC_BRUSH :: 18 +DC_PEN :: 19 +STOCK_LAST :: 19 + +CLR_INVALID :: 0xFFFFFFFF + +RGBQUAD :: struct { + rgbBlue: BYTE, + rgbGreen: BYTE, + rgbRed: BYTE, + rgbReserved: BYTE, +} + +PIXELFORMATDESCRIPTOR :: struct { + nSize: WORD, + nVersion: WORD, + dwFlags: DWORD, + iPixelType: BYTE, + cColorBits: BYTE, + cRedBits: BYTE, + cRedShift: BYTE, + cGreenBits: BYTE, + cGreenShift: BYTE, + cBlueBits: BYTE, + cBlueShift: BYTE, + cAlphaBits: BYTE, + cAlphaShift: BYTE, + cAccumBits: BYTE, + cAccumRedBits: BYTE, + cAccumGreenBits: BYTE, + cAccumBlueBits: BYTE, + cAccumAlphaBits: BYTE, + cDepthBits: BYTE, + cStencilBits: BYTE, + cAuxBuffers: BYTE, + iLayerType: BYTE, + bReserved: BYTE, + dwLayerMask: DWORD, + dwVisibleMask: DWORD, + dwDamageMask: DWORD, +} + +BITMAPINFOHEADER :: struct { + biSize: DWORD, + biWidth: LONG, + biHeight: LONG, + biPlanes: WORD, + biBitCount: WORD, + biCompression: DWORD, + biSizeImage: DWORD, + biXPelsPerMeter: LONG, + biYPelsPerMeter: LONG, + biClrUsed: DWORD, + biClrImportant: DWORD, +} + +BITMAPINFO :: struct { + bmiHeader: BITMAPINFOHEADER, + bmiColors: [1]RGBQUAD, +} + +// pixel types +PFD_TYPE_RGBA :: 0 +PFD_TYPE_COLORINDEX :: 1 + +// layer types +PFD_MAIN_PLANE :: 0 +PFD_OVERLAY_PLANE :: 1 +PFD_UNDERLAY_PLANE :: -1 + +// PIXELFORMATDESCRIPTOR flags +PFD_DOUBLEBUFFER :: 0x00000001 +PFD_STEREO :: 0x00000002 +PFD_DRAW_TO_WINDOW :: 0x00000004 +PFD_DRAW_TO_BITMAP :: 0x00000008 +PFD_SUPPORT_GDI :: 0x00000010 +PFD_SUPPORT_OPENGL :: 0x00000020 +PFD_GENERIC_FORMAT :: 0x00000040 +PFD_NEED_PALETTE :: 0x00000080 +PFD_NEED_SYSTEM_PALETTE :: 0x00000100 +PFD_SWAP_EXCHANGE :: 0x00000200 +PFD_SWAP_COPY :: 0x00000400 +PFD_SWAP_LAYER_BUFFERS :: 0x00000800 +PFD_GENERIC_ACCELERATED :: 0x00001000 +PFD_SUPPORT_DIRECTDRAW :: 0x00002000 +PFD_DIRECT3D_ACCELERATED :: 0x00004000 +PFD_SUPPORT_COMPOSITION :: 0x00008000 + +// PIXELFORMATDESCRIPTOR flags for use in ChoosePixelFormat only +PFD_DEPTH_DONTCARE :: 0x20000000 +PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000 +PFD_STEREO_DONTCARE :: 0x80000000 + +// constants for the biCompression field +BI_RGB :: 0 +BI_RLE8 :: 1 +BI_RLE4 :: 2 +BI_BITFIELDS :: 3 +BI_JPEG :: 4 +BI_PNG :: 5 + WSA_FLAG_OVERLAPPED: DWORD : 0x01 WSA_FLAG_NO_HANDLE_INHERIT: DWORD : 0x80 From 1d8bc3e917b3cf5713e56a0f07b0a8a811d09d2b Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 24 Mar 2022 17:32:11 +0200 Subject: [PATCH 0438/1052] sys/windows: fix gdi32 raw pointer types --- core/sys/windows/gdi32.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 2caf42753..15d5567c7 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -14,7 +14,7 @@ foreign gdi32 { hdc: HDC, pbmih: ^BITMAPINFOHEADER, flInit: DWORD, - pjBits: ^VOID, + pjBits: VOID, pbmi: ^BITMAPINFO, iUsage: UINT, ) -> HBITMAP --- @@ -23,7 +23,7 @@ foreign gdi32 { hdc: HDC, pbmi: ^BITMAPINFO, usage: UINT, - ppvBits: ^^VOID, + ppvBits: VOID, hSection: HANDLE, offset: DWORD, ) -> HBITMAP --- @@ -38,7 +38,7 @@ foreign gdi32 { ySrc: c_int, SrcWidth: c_int, SrcHeight: c_int, - lpBits: ^VOID, + lpBits: VOID, lpbmi: ^BITMAPINFO, iUsage: UINT, rop: DWORD, From 5d7b92d391bcddf98cc94b99f932e391cd3cbb40 Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 24 Mar 2022 18:40:23 +0200 Subject: [PATCH 0439/1052] sys/windows: add mouse states masks --- core/sys/windows/types.odin | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 9a4a1ab5e..63e66ee83 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -416,6 +416,15 @@ WMSZ_BOTTOM :: 6 WMSZ_BOTTOMLEFT :: 7 WMSZ_BOTTOMRIGHT :: 8 +// Key State Masks for Mouse Messages +MK_LBUTTON :: 0x0001 +MK_RBUTTON :: 0x0002 +MK_SHIFT :: 0x0004 +MK_CONTROL :: 0x0008 +MK_MBUTTON :: 0x0010 +MK_XBUTTON1 :: 0x0020 +MK_XBUTTON2 :: 0x0040 + _IDC_APPSTARTING := rawptr(uintptr(32650)) _IDC_ARROW := rawptr(uintptr(32512)) _IDC_CROSS := rawptr(uintptr(32515)) From 86614575126265a17e4a232522b7c08541375b76 Mon Sep 17 00:00:00 2001 From: gitlost Date: Thu, 24 Mar 2022 19:31:46 +0000 Subject: [PATCH 0440/1052] Use `WIFEXITED()` and `WEXITSTATUS()` on Unix `system()` exit code (ensures Odin run returns correct exit code of built executable) Adds test "tests/core/os/test_core_os_exit.odin" (Unix only) --- src/main.cpp | 3 +++ tests/core/Makefile | 5 ++++- tests/core/os/test_core_os_exit.odin | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/core/os/test_core_os_exit.odin diff --git a/src/main.cpp b/src/main.cpp index 63b2c8386..905571f44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -117,6 +117,9 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { gb_printf_err("%s\n\n", cmd_line); } exit_code = system(cmd_line); + if (WIFEXITED(exit_code)) { + exit_code = WEXITSTATUS(exit_code); + } #endif if (exit_code) { diff --git a/tests/core/Makefile b/tests/core/Makefile index 4160690f9..652ebb151 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -2,7 +2,7 @@ ODIN=../../odin PYTHON=$(shell which python3) all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test filepath_test reflect_test + math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test download_test_assets: $(PYTHON) download_assets.py @@ -41,3 +41,6 @@ filepath_test: reflect_test: $(ODIN) run reflect/test_core_reflect.odin -out=test_core_reflect -collection:tests=.. + +os_exit_test: + $(ODIN) run os/test_core_os_exit.odin -out=test_core_os_exit && exit 1 || exit 0 diff --git a/tests/core/os/test_core_os_exit.odin b/tests/core/os/test_core_os_exit.odin new file mode 100644 index 000000000..2ab274f5e --- /dev/null +++ b/tests/core/os/test_core_os_exit.odin @@ -0,0 +1,10 @@ +// Tests that Odin run returns exit code of built executable on Unix +// Needs exit status to be inverted to return 0 on success, e.g. +// $(./odin run tests/core/os/test_core_os_exit.odin && exit 1 || exit 0) +package test_core_os_exit + +import "core:os" + +main :: proc() { + os.exit(1) +} From 2f9a410a45bc6f8c0610417e8406793989177a7a Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 25 Mar 2022 16:09:16 +0200 Subject: [PATCH 0441/1052] sys/windows: add SetWindowPos() --- core/sys/windows/types.odin | 33 +++++++++++++++++++++++++++++++++ core/sys/windows/user32.odin | 9 +++++++++ 2 files changed, 42 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 63e66ee83..0c6327cc2 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -399,6 +399,30 @@ SW_RESTORE : c_int : 9 SW_SHOWDEFAULT : c_int : 10 SW_FORCEMINIMIZE : c_int : 11 +// SetWindowPos Flags +SWP_NOSIZE :: 0x0001 +SWP_NOMOVE :: 0x0002 +SWP_NOZORDER :: 0x0004 +SWP_NOREDRAW :: 0x0008 +SWP_NOACTIVATE :: 0x0010 +SWP_FRAMECHANGED :: 0x0020 // The frame changed: send WM_NCCALCSIZE +SWP_SHOWWINDOW :: 0x0040 +SWP_HIDEWINDOW :: 0x0080 +SWP_NOCOPYBITS :: 0x0100 +SWP_NOOWNERZORDER :: 0x0200 // Don't do owner Z ordering +SWP_NOSENDCHANGING :: 0x0400 // Don't send WM_WINDOWPOSCHANGING + +SWP_DRAWFRAME :: SWP_FRAMECHANGED +SWP_NOREPOSITION :: SWP_NOOWNERZORDER + +SWP_DEFERERASE :: 0x2000 // same as SWP_DEFERDRAWING +SWP_ASYNCWINDOWPOS :: 0x4000 // same as SWP_CREATESPB + +HWND_TOP : HWND : 0 +HWND_BOTTOM : HWND : 1 +HWND_TOPMOST : HWND : -1 +HWND_NOTOPMOST : HWND : -2 + CW_USEDEFAULT : c_int : -2147483648 SIZE_RESTORED :: 0 @@ -846,6 +870,15 @@ FILE_TYPE_PIPE :: 0x0003 RECT :: struct {left, top, right, bottom: LONG} POINT :: struct {x, y: LONG} +WINDOWPOS :: struct { + hwnd: HWND, + hwndInsertAfter: HWND, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + flags: UINT, +} when size_of(uintptr) == 4 { WSADATA :: struct { diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index fc001f26b..6e57196ee 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -97,6 +97,15 @@ foreign user32 { LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- GetClientRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- + SetWindowPos :: proc( + hWnd: HWND, + hWndInsertAfter: HWND, + X: c_int, + Y: c_int, + cx: c_int, + cy: c_int, + uFlags: UINT, + ) -> BOOL --- GetWindowDC :: proc(hWnd: HWND) -> HDC --- GetDC :: proc(hWnd: HWND) -> HDC --- From f8d3f86d8b79cc0ee811490455452423fae0fc88 Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 25 Mar 2022 16:17:53 +0200 Subject: [PATCH 0442/1052] sys/windows: fix build --- core/sys/windows/types.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 0c6327cc2..5e1aa2503 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -418,10 +418,10 @@ SWP_NOREPOSITION :: SWP_NOOWNERZORDER SWP_DEFERERASE :: 0x2000 // same as SWP_DEFERDRAWING SWP_ASYNCWINDOWPOS :: 0x4000 // same as SWP_CREATESPB -HWND_TOP : HWND : 0 -HWND_BOTTOM : HWND : 1 -HWND_TOPMOST : HWND : -1 -HWND_NOTOPMOST : HWND : -2 +HWND_TOP :: 0 +HWND_BOTTOM :: 1 +HWND_TOPMOST :: -1 +HWND_NOTOPMOST :: -2 CW_USEDEFAULT : c_int : -2147483648 From 73b81184fa3c7f97b5b945a0d459cb09bd91aa97 Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 25 Mar 2022 20:53:17 +0200 Subject: [PATCH 0443/1052] sys/windows: add MessageBox procedures --- core/sys/windows/types.odin | 59 ++++++++++++++++++++++++++++++++++++ core/sys/windows/user32.odin | 5 +++ 2 files changed, 64 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 5e1aa2503..bd6eba24e 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -312,6 +312,65 @@ CREATESTRUCTW:: struct { dwExStyle: DWORD, } +// MessageBox() Flags +MB_OK :: 0x00000000 +MB_OKCANCEL :: 0x00000001 +MB_ABORTRETRYIGNORE :: 0x00000002 +MB_YESNOCANCEL :: 0x00000003 +MB_YESNO :: 0x00000004 +MB_RETRYCANCEL :: 0x00000005 +MB_CANCELTRYCONTINUE :: 0x00000006 + +MB_ICONHAND :: 0x00000010 +MB_ICONQUESTION :: 0x00000020 +MB_ICONEXCLAMATION :: 0x00000030 +MB_ICONASTERISK :: 0x00000040 +MB_USERICON :: 0x00000080 +MB_ICONWARNING :: MB_ICONEXCLAMATION +MB_ICONERROR :: MB_ICONHAND +MB_ICONINFORMATION :: MB_ICONASTERISK +MB_ICONSTOP :: MB_ICONHAND + +MB_DEFBUTTON1 :: 0x00000000 +MB_DEFBUTTON2 :: 0x00000100 +MB_DEFBUTTON3 :: 0x00000200 +MB_DEFBUTTON4 :: 0x00000300 + +MB_APPLMODAL :: 0x00000000 +MB_SYSTEMMODAL :: 0x00001000 +MB_TASKMODAL :: 0x00002000 +MB_HELP :: 0x00004000 // Help Button + +MB_NOFOCUS :: 0x00008000 +MB_SETFOREGROUND :: 0x00010000 +MB_DEFAULT_DESKTOP_ONLY :: 0x00020000 +MB_TOPMOST :: 0x00040000 +MB_RIGHT :: 0x00080000 +MB_RTLREADING :: 0x00100000 + +MB_SERVICE_NOTIFICATION :: 0x00200000 +MB_SERVICE_NOTIFICATION_NT3X :: 0x00040000 + +MB_TYPEMASK :: 0x0000000F +MB_ICONMASK :: 0x000000F0 +MB_DEFMASK :: 0x00000F00 +MB_MODEMASK :: 0x00003000 +MB_MISCMASK :: 0x0000C000 + +// Dialog Box Command IDs +IDOK :: 1 +IDCANCEL :: 2 +IDABORT :: 3 +IDRETRY :: 4 +IDIGNORE :: 5 +IDYES :: 6 +IDNO :: 7 +IDCLOSE :: 8 +IDHELP :: 9 +IDTRYAGAIN :: 10 +IDCONTINUE :: 11 +IDTIMEOUT :: 32000 + CS_VREDRAW : UINT : 0x0001 CS_HREDRAW : UINT : 0x0002 CS_DBLCLKS : UINT : 0x0008 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 6e57196ee..2336878ef 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -120,6 +120,11 @@ foreign user32 { GetKeyState :: proc(nVirtKey: c_int) -> SHORT --- GetAsyncKeyState :: proc(vKey: c_int) -> SHORT --- + + MessageBoxA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT) -> c_int --- + MessageBoxW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT) -> c_int --- + MessageBoxExA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT, wLanguageId: WORD) -> c_int --- + MessageBoxExW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT, wLanguageId: WORD) -> c_int --- } CreateWindowA :: #force_inline proc "stdcall" ( From 5616ff9a405a335103a3fed705e47d864fb05776 Mon Sep 17 00:00:00 2001 From: WalterPlinge <22519813+WalterPlinge@users.noreply.github.com> Date: Fri, 25 Mar 2022 20:03:39 +0000 Subject: [PATCH 0444/1052] Add fields_iterator proc Adds a `fields_iterator` proc to `core:strings` --- core/strings/strings.odin | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index fe25ad3bf..21e33f22b 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1365,3 +1365,35 @@ fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.alloc return substrings[:] } + + +// fields_iterator returns the first run of characters in s that does not contain white space, defined by unicode.is_space +// s will then start from any space after the substring, or be a nil string if the substring was the remaining characters +fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { + start, end := -1, -1 + for r, offset in s { + end = offset + if unicode.is_space(r) { + if start >= 0 { + field = s[start : end] + ok = true + s^ = s[end:] + return + } + } else { + if start < 0 { + start = end + } + } + } + + // if either of these are true, the string did not contain any characters + if end < 0 || start < 0 { + return "", false + } + + field = s[:len(s)] + ok = true + s^ = s[len(s):] + return +} From 9080fa4a9d432b172abbad83b870876631c8eb44 Mon Sep 17 00:00:00 2001 From: WalterPlinge <22519813+WalterPlinge@users.noreply.github.com> Date: Fri, 25 Mar 2022 20:51:04 +0000 Subject: [PATCH 0445/1052] Update fields_iterator comment Added ticks for identifiers --- core/strings/strings.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 21e33f22b..53d7ea647 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1367,8 +1367,8 @@ fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.alloc } -// fields_iterator returns the first run of characters in s that does not contain white space, defined by unicode.is_space -// s will then start from any space after the substring, or be a nil string if the substring was the remaining characters +// `fields_iterator` returns the first run of characters in `s` that does not contain white space, defined by `unicode.is_space` +// `s` will then start from any space after the substring, or be an empty string if the substring was the remaining characters fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { start, end := -1, -1 for r, offset in s { From 3f3cc342b4851122b8fbc6a819c10a39b5b9933b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 26 Mar 2022 18:38:10 +0100 Subject: [PATCH 0446/1052] Update strings.odin Fix from Walter. --- core/strings/strings.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 53d7ea647..e5bd60d33 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1392,7 +1392,7 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { return "", false } - field = s[:len(s)] + field = s[start:] ok = true s^ = s[len(s):] return From 86a1c34c3ad9294ea31a725407dff630888cf23d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 26 Mar 2022 19:33:53 +0100 Subject: [PATCH 0447/1052] HWND_TOPMOST, HWND_NOTOPMOST constants --- core/sys/windows/types.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index bd6eba24e..c15f18830 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -477,10 +477,10 @@ SWP_NOREPOSITION :: SWP_NOOWNERZORDER SWP_DEFERERASE :: 0x2000 // same as SWP_DEFERDRAWING SWP_ASYNCWINDOWPOS :: 0x4000 // same as SWP_CREATESPB -HWND_TOP :: 0 -HWND_BOTTOM :: 1 -HWND_TOPMOST :: -1 -HWND_NOTOPMOST :: -2 +HWND_TOP :: HWND( uintptr(0)) // 0 +HWND_BOTTOM :: HWND( uintptr(1)) // 1 +HWND_TOPMOST :: HWND(~uintptr(0)) // -1 +HWND_NOTOPMOST :: HWND(~uintptr(0) - 1) // -2 CW_USEDEFAULT : c_int : -2147483648 From f4125d2d8851f20b7ee26d93b5ff097be46bdc4a Mon Sep 17 00:00:00 2001 From: hikari Date: Sun, 27 Mar 2022 01:42:46 +0200 Subject: [PATCH 0448/1052] sys/windows: add ClientToScreen --- core/sys/windows/types.odin | 1 + core/sys/windows/user32.odin | 1 + 2 files changed, 2 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index c15f18830..447bbda11 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -58,6 +58,7 @@ LPARAM :: LONG_PTR WPARAM :: UINT_PTR LRESULT :: LONG_PTR LPRECT :: ^RECT +LPPOINT :: ^POINT UINT8 :: u8 UINT16 :: u16 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 2336878ef..c9267da76 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -97,6 +97,7 @@ foreign user32 { LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- GetClientRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- + ClientToScreen :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- SetWindowPos :: proc( hWnd: HWND, hWndInsertAfter: HWND, From 76277f83c15c1a245059139e7ca4beb4bfad6384 Mon Sep 17 00:00:00 2001 From: hikari Date: Sun, 27 Mar 2022 02:23:40 +0200 Subject: [PATCH 0449/1052] sys/windows: add GetSystemMetrics --- core/sys/windows/types.odin | 111 ++++++++++++++++++++++++++++++++++- core/sys/windows/user32.odin | 1 + 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 447bbda11..45c94e733 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -483,7 +483,116 @@ HWND_BOTTOM :: HWND( uintptr(1)) // 1 HWND_TOPMOST :: HWND(~uintptr(0)) // -1 HWND_NOTOPMOST :: HWND(~uintptr(0) - 1) // -2 -CW_USEDEFAULT : c_int : -2147483648 +// GetSystemMetrics() codes +SM_CXSCREEN :: 0 +SM_CYSCREEN :: 1 +SM_CXVSCROLL :: 2 +SM_CYHSCROLL :: 3 +SM_CYCAPTION :: 4 +SM_CXBORDER :: 5 +SM_CYBORDER :: 6 +SM_CXDLGFRAME :: 7 +SM_CYDLGFRAME :: 8 +SM_CYVTHUMB :: 9 +SM_CXHTHUMB :: 10 +SM_CXICON :: 11 +SM_CYICON :: 12 +SM_CXCURSOR :: 13 +SM_CYCURSOR :: 14 +SM_CYMENU :: 15 +SM_CXFULLSCREEN :: 16 +SM_CYFULLSCREEN :: 17 +SM_CYKANJIWINDOW :: 18 +SM_MOUSEPRESENT :: 19 +SM_CYVSCROLL :: 20 +SM_CXHSCROLL :: 21 +SM_DEBUG :: 22 +SM_SWAPBUTTON :: 23 +SM_RESERVED1 :: 24 +SM_RESERVED2 :: 25 +SM_RESERVED3 :: 26 +SM_RESERVED4 :: 27 +SM_CXMIN :: 28 +SM_CYMIN :: 29 +SM_CXSIZE :: 30 +SM_CYSIZE :: 31 +SM_CXFRAME :: 32 +SM_CYFRAME :: 33 +SM_CXMINTRACK :: 34 +SM_CYMINTRACK :: 35 +SM_CXDOUBLECLK :: 36 +SM_CYDOUBLECLK :: 37 +SM_CXICONSPACING :: 38 +SM_CYICONSPACING :: 39 +SM_MENUDROPALIGNMENT :: 40 +SM_PENWINDOWS :: 41 +SM_DBCSENABLED :: 42 +SM_CMOUSEBUTTONS :: 43 + +SM_CXFIXEDFRAME :: SM_CXDLGFRAME // ;win40 name change +SM_CYFIXEDFRAME :: SM_CYDLGFRAME // ;win40 name change +SM_CXSIZEFRAME :: SM_CXFRAME // ;win40 name change +SM_CYSIZEFRAME :: SM_CYFRAME // ;win40 name change + +SM_SECURE :: 44 +SM_CXEDGE :: 45 +SM_CYEDGE :: 46 +SM_CXMINSPACING :: 47 +SM_CYMINSPACING :: 48 +SM_CXSMICON :: 49 +SM_CYSMICON :: 50 +SM_CYSMCAPTION :: 51 +SM_CXSMSIZE :: 52 +SM_CYSMSIZE :: 53 +SM_CXMENUSIZE :: 54 +SM_CYMENUSIZE :: 55 +SM_ARRANGE :: 56 +SM_CXMINIMIZED :: 57 +SM_CYMINIMIZED :: 58 +SM_CXMAXTRACK :: 59 +SM_CYMAXTRACK :: 60 +SM_CXMAXIMIZED :: 61 +SM_CYMAXIMIZED :: 62 +SM_NETWORK :: 63 +SM_CLEANBOOT :: 67 +SM_CXDRAG :: 68 +SM_CYDRAG :: 69 + +SM_SHOWSOUNDS :: 70 +SM_CXMENUCHECK :: 71 // Use instead of GetMenuCheckMarkDimensions()! +SM_CYMENUCHECK :: 72 +SM_SLOWMACHINE :: 73 +SM_MIDEASTENABLED :: 74 +SM_MOUSEWHEELPRESENT :: 75 +SM_XVIRTUALSCREEN :: 76 +SM_YVIRTUALSCREEN :: 77 +SM_CXVIRTUALSCREEN :: 78 +SM_CYVIRTUALSCREEN :: 79 +SM_CMONITORS :: 80 +SM_SAMEDISPLAYFORMAT :: 81 +SM_IMMENABLED :: 82 +SM_CXFOCUSBORDER :: 83 +SM_CYFOCUSBORDER :: 84 +SM_TABLETPC :: 86 +SM_MEDIACENTER :: 87 +SM_STARTER :: 88 +SM_SERVERR2 :: 89 + +SM_MOUSEHORIZONTALWHEELPRESENT :: 91 + +SM_CXPADDEDBORDER :: 92 +SM_DIGITIZER :: 94 +SM_MAXIMUMTOUCHES :: 95 +SM_CMETRICS :: 97 + +SM_REMOTESESSION :: 0x1000 +SM_SHUTTINGDOWN :: 0x2000 +SM_REMOTECONTROL :: 0x2001 +SM_CARETBLINKINGENABLED :: 0x2002 +SM_CONVERTIBLESLATEMODE :: 0x2003 +SM_SYSTEMDOCKED :: 0x2004 + +CW_USEDEFAULT : c_int : -2147483648 SIZE_RESTORED :: 0 SIZE_MINIMIZED :: 1 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index c9267da76..19bbb518e 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -107,6 +107,7 @@ foreign user32 { cy: c_int, uFlags: UINT, ) -> BOOL --- + GetSystemMetrics :: proc(nIndex: c_int) -> c_int --- GetWindowDC :: proc(hWnd: HWND) -> HDC --- GetDC :: proc(hWnd: HWND) -> HDC --- From 3ce17607c621fcb61ec77dbfef3bcd4799aa960d Mon Sep 17 00:00:00 2001 From: hikari Date: Sun, 27 Mar 2022 04:17:07 +0300 Subject: [PATCH 0450/1052] sys/windows: add AdjustWindowRect and GetWindowRect --- core/sys/windows/user32.odin | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 19bbb518e..001434f80 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -96,7 +96,8 @@ foreign user32 { LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- - GetClientRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- + GetWindowRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- + GetClientRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- ClientToScreen :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- SetWindowPos :: proc( hWnd: HWND, @@ -108,6 +109,8 @@ foreign user32 { uFlags: UINT, ) -> BOOL --- GetSystemMetrics :: proc(nIndex: c_int) -> c_int --- + AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL --- + AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL --- GetWindowDC :: proc(hWnd: HWND) -> HDC --- GetDC :: proc(hWnd: HWND) -> HDC --- From d2ff6f424db9d0422fc11d0c84f5bc63fcd64962 Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Sun, 27 Mar 2022 11:32:46 +0200 Subject: [PATCH 0451/1052] add math easing package --- core/math/ease/ease.odin | 466 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100644 core/math/ease/ease.odin diff --git a/core/math/ease/ease.odin b/core/math/ease/ease.odin new file mode 100644 index 000000000..0fe59f9d2 --- /dev/null +++ b/core/math/ease/ease.odin @@ -0,0 +1,466 @@ +package ease + +import "core:math" +import "core:intrinsics" +import "core:time" + +@(private) PI_2 :: math.PI / 2 + +// converted to odin from https://github.com/warrenm/AHEasing +// with additional enum based call + +// Modeled after the parabola y = x^2 +quadratic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return p * p +} + +// Modeled after the parabola y = -x^2 + 2x +quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return -(p * (p - 2)) +} + +// Modeled after the piecewise quadratic +// y = (1/2)((2x)^2) ; [0, 0.5) +// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] +quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + return 2 * p * p; + } else { + return (-2 * p * p) + (4 * p) - 1 + } +} + +// Modeled after the cubic y = x^3 +cubic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return p * p * p +} + +// Modeled after the cubic y = (x - 1)^3 + 1 +cubic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + f := p - 1 + return f * f * f + 1 +} + +// Modeled after the piecewise cubic +// y = (1/2)((2x)^3) ; [0, 0.5) +// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] +cubic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + return 4 * p * p * p + } else { + f := (2 * p) - 2 + return 0.5 * f * f * f + 1 + } +} + +// Modeled after the quartic x^4 +quartic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return p * p * p * p +} + +// Modeled after the quartic y = 1 - (x - 1)^4 +quartic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + f := p - 1 + return f * f * f * (1 - p) + 1 +} + +// Modeled after the piecewise quartic +// y = (1/2)((2x)^4) ; [0, 0.5) +// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] +quartic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + return 8 * p * p * p * p + } else { + f := p - 1 + return -8 * f * f * f * f + 1 + } +} + +// Modeled after the quintic y = x^5 +quintic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return p * p * p * p * p +} + +// Modeled after the quintic y = (x - 1)^5 + 1 +quintic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + f := p - 1 + return f * f * f * f * f + 1 +} + +// Modeled after the piecewise quintic +// y = (1/2)((2x)^5) ; [0, 0.5) +// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] +quintic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + return 16 * p * p * p * p * p + } else { + f := (2 * p) - 2 + return 0.5 * f * f * f * f * f + 1 + } +} + +// Modeled after quarter-cycle of sine wave +sine_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return math.sin((p - 1) * PI_2) + 1 +} + +// Modeled after quarter-cycle of sine wave (different phase) +sine_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return math.sin(p * PI_2) +} + +// Modeled after half sine wave +sine_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return 0.5 * (1 - math.cos(p * math.PI)) +} + +// Modeled after shifted quadrant IV of unit circle +circular_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return 1 - math.sqrt(1 - (p * p)) +} + +// Modeled after shifted quadrant II of unit circle +circular_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return math.sqrt((2 - p) * p) +} + +// Modeled after the piecewise circular function +// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) +// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] +circular_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + return 0.5 * (1 - math.sqrt(1 - 4 * (p * p))) + } else { + return 0.5 * (math.sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1) + } +} + +// Modeled after the exponential function y = 2^(10(x - 1)) +exponential_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return p == 0.0 ? p : math.pow(2, 10 * (p - 1)) +} + +// Modeled after the exponential function y = -2^(-10x) + 1 +exponential_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return p == 1.0 ? p : 1 - math.pow(2, -10 * p) +} + +// Modeled after the piecewise exponential +// y = (1/2)2^(10(2x - 1)) ; [0,0.5) +// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] +exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p == 0.0 || p == 1.0 { + return p + } + + if p < 0.5 { + return 0.5 * math.pow(2, (20 * p) - 10) + } else { + return -0.5 * math.pow(2, (-20 * p) + 10) + 1 + } +} + +// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) +elastic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return math.sin(13 * PI_2 * p) * math.pow(2, 10 * (p - 1)) +} + +// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 +elastic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return math.sin(-13 * PI_2 * (p + 1)) * math.pow(2, -10 * p) + 1 +} + +// Modeled after the piecewise exponentially-damped sine wave: +// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) +// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] +elastic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + return 0.5 * math.sin(13 * PI_2 * (2 * p)) * math.pow(2, 10 * ((2 * p) - 1)) + } else { + return 0.5 * (math.sin(-13 * PI_2 * ((2 * p - 1) + 1)) * math.pow(2, -10 * (2 * p - 1)) + 2) + } +} + +// Modeled after the overshooting cubic y = x^3-x*sin(x*pi) +back_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return p * p * p - p * math.sin(p * math.PI) +} + +// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) +back_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + f := 1 - p + return 1 - (f * f * f - f * math.sin(f * math.PI)) +} + +// Modeled after the piecewise overshooting cubic function: +// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) +// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] +back_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + f := 2 * p + return 0.5 * (f * f * f - f * math.sin(f * math.PI)) + } else { + f := (1 - (2*p - 1)) + return 0.5 * (1 - (f * f * f - f * math.sin(f * math.PI))) + 0.5 + } +} + +bounce_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + return 1 - bounce_out(1 - p) +} + +bounce_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 4/11.0 { + return (121 * p * p)/16.0 + } else if p < 8/11.0 { + return (363/40.0 * p * p) - (99/10.0 * p) + 17/5.0 + } else if p < 9/10.0 { + return (4356/361.0 * p * p) - (35442/1805.0 * p) + 16061/1805.0 + } else { + return (54/5.0 * p * p) - (513/25.0 * p) + 268/25.0 + } +} + +bounce_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { + if p < 0.5 { + return 0.5 * bounce_in(p*2) + } else { + return 0.5 * bounce_out(p * 2 - 1) + 0.5 + } +} + +// additional enum variant + +Ease :: enum { + Linear, + + Quadratic_In, + Quadratic_Out, + Quadratic_In_Out, + + Cubic_In, + Cubic_Out, + Cubic_In_Out, + + Quartic_In, + Quartic_Out, + Quartic_In_Out, + + Quintic_In, + Quintic_Out, + Quintic_In_Out, + + Sine_In, + Sine_Out, + Sine_In_Out, + + Circular_In, + Circular_Out, + Circular_In_Out, + + Exponential_In, + Exponential_Out, + Exponential_In_Out, + + Elastic_In, + Elastic_Out, + Elastic_In_Out, + + Back_In, + Back_Out, + Back_In_Out, + + Bounce_In, + Bounce_Out, + Bounce_In_Out, +} + +ease :: proc "contextless" (type: Ease, p: $T) -> T + where intrinsics.type_is_float(T) { + switch type { + case .Linear: return p + + case .Quadratic_In: return quadratic_in(p) + case .Quadratic_Out: return quadratic_out(p) + case .Quadratic_In_Out: return quadratic_in_out(p) + + case .Cubic_In: return cubic_in(p) + case .Cubic_Out: return cubic_out(p) + case .Cubic_In_Out: return cubic_in_out(p) + + case .Quartic_In: return quartic_in(p) + case .Quartic_Out: return quartic_out(p) + case .Quartic_In_Out: return quartic_in_out(p) + + case .Quintic_In: return quintic_in(p) + case .Quintic_Out: return quintic_out(p) + case .Quintic_In_Out: return quintic_in_out(p) + + case .Sine_In: return sine_in(p) + case .Sine_Out: return sine_out(p) + case .Sine_In_Out: return sine_in_out(p) + + case .Circular_In: return circular_in(p) + case .Circular_Out: return circular_out(p) + case .Circular_In_Out: return circular_in_out(p) + + case .Exponential_In: return exponential_in(p) + case .Exponential_Out: return exponential_out(p) + case .Exponential_In_Out: return exponential_in_out(p) + + case .Elastic_In: return elastic_in(p) + case .Elastic_Out: return elastic_out(p) + case .Elastic_In_Out: return elastic_in_out(p) + + case .Back_In: return back_in(p) + case .Back_Out: return back_out(p) + case .Back_In_Out: return back_in_out(p) + + case .Bounce_In: return bounce_in(p) + case .Bounce_Out: return bounce_out(p) + case .Bounce_In_Out: return bounce_in_out(p) + } + + // in case type was invalid + return 0 +} + +Flux_Map :: struct($T: typeid) { + values: map[^T]Flux_Tween(T), +} + +Flux_Tween :: struct($T: typeid) { + value: ^T, + start: T, + diff: T, + goal: T, + + // using ticks for timing instead + delay_tick_start: time.Tick, + delay: time.Duration, + duration: time.Duration, + + progress: f64, + rate: f64, + type: Ease, + + inited: bool, + + // callbacks, data can be set, will be pushed to callback + data: rawptr, // by default gets set to value input + on_start: proc(flux: ^Flux_Map(T), data: rawptr), + on_update: proc(flux: ^Flux_Map(T), data: rawptr), + on_complete: proc(flux: ^Flux_Map(T), data: rawptr), +} + +// init flux map to a float type and a wanted cap +flux_init :: proc($T: typeid, cap := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) { + return { + make(map[^T]Flux_Tween(T), cap), + } +} + +// delete map content +flux_destroy :: proc(flux: Flux_Map($T)) where intrinsics.type_is_float(T) { + delete(flux.values) +} + +// clear map content, stops all animations +flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) { + clear(&flux.values) +} + +// append / overwrite existing tween value to parameters +// rest is initialized in flux_tween_init, inside update +// return value can be used to set callbacks +flux_to :: proc( + flux: ^Flux_Map($T), + value: ^f32, + goal: f32, + type: Ease = .Quadratic_Out, + duration: time.Duration = time.Second, + delay: time.Duration = 0, +) -> (tween: ^Flux_Tween(T)) where intrinsics.type_is_float(T) { + if res, ok := &flux.values[value]; ok { + tween = res + } else { + flux.values[value] = {} + tween = &flux.values[value] + } + + tween^ = { + value = value, + goal = goal, + duration = duration, + delay = delay, + delay_tick_start = time.tick_now(), + type = type, + data = value, + } + + return +} + +// init internal properties +flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where intrinsics.type_is_float(T) { + tween.inited = true + tween.start = tween.value^ + tween.diff = tween.goal - tween.value^ + s := time.duration_seconds(duration) + tween.rate = duration > 0 ? 1.0 / s : 0 + tween.progress = duration > 0 ? 0 : 1 +} + +// update all tweens, wait for their delay if one exists +// calls callbacks in all stages, when they're filled +// deletes tween from the map after completion +flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) { + size := len(flux.values) + now := time.tick_now() + + for key, tween in &flux.values { + if tween.delay != 0 { + diff := time.tick_diff(tween.delay_tick_start, now) + + // when diff reached delay, stop delaying + if diff > tween.delay { + tween.delay = 0 + } + } else { + if !tween.inited { + flux_tween_init(&tween, tween.duration) + + if tween.on_start != nil { + tween.on_start(flux, tween.data) + } + } + + tween.progress += tween.rate * dt + x := tween.progress >= 1 ? 1 : ease(tween.type, tween.progress) + tween.value^ = tween.start + tween.diff * T(x) + + if tween.on_update != nil { + tween.on_update(flux, tween.data) + } + + if tween.progress >= 1 { + delete_key(&flux.values, key) + + if tween.on_complete != nil { + tween.on_complete(flux, tween.data) + } + } + } + } +} + +// stop a specific key inside the map +// returns true when it successfully removed the key +flux_stop :: proc(flux: ^Flux_Map($T), key: ^f32) -> bool where intrinsics.type_is_float(T) { + if key in flux { + delete_key(flux, key) + return true + } + + return false +} \ No newline at end of file From 58f4d533b72d199848e4ebb291b7737312b4957a Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Sun, 27 Mar 2022 11:39:17 +0200 Subject: [PATCH 0452/1052] add string documentation & examples, fix & cleanup string_multi --- core/strings/strings.odin | 657 ++++++++++++++++++++++++++++++-------- 1 file changed, 524 insertions(+), 133 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index e5bd60d33..452c0ca0c 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1,16 +1,21 @@ +// simple procedures to manipulate UTF-8 encoded strings package strings import "core:io" import "core:mem" +import "core:slice" import "core:unicode" import "core:unicode/utf8" +// returns a clone of the string `s` allocated using the `allocator` clone :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> string { c := make([]byte, len(s), allocator, loc) copy(c, s) return string(c[:len(s)]) } +// returns a clone of the string `s` allocated using the `allocator` as a cstring +// a nul byte is appended to the clone, to make the cstring safe clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> cstring { c := make([]byte, len(s)+1, allocator, loc) copy(c, s) @@ -18,27 +23,35 @@ clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #call return cstring(&c[0]) } +// returns a string from a byte pointer `ptr` and byte length `len` +// the string is valid as long as the parameters stay alive string_from_ptr :: proc(ptr: ^byte, len: int) -> string { return transmute(string)mem.Raw_String{ptr, len} } +// returns a string from a byte pointer `ptr and byte length `len` +// searches for a nul byte from 0.. string { s := transmute(string)mem.Raw_String{ptr, len} s = truncate_to_byte(s, 0) return s } - +// returns the raw ^byte start of the string `str` ptr_from_string :: proc(str: string) -> ^byte { d := transmute(mem.Raw_String)str return d.data } +// returns the transmute of string `str` to a cstring +// not safe since the origin string may not contain a nul byte unsafe_string_to_cstring :: proc(str: string) -> cstring { d := transmute(mem.Raw_String)str return cstring(d.data) } +// returns a string truncated to the first time it finds the byte `b` +// uses the `len` of the string `str` when it couldn't find the input truncate_to_byte :: proc(str: string, b: byte) -> string { n := index_byte(str, b) if n < 0 { @@ -46,6 +59,9 @@ truncate_to_byte :: proc(str: string, b: byte) -> string { } return str[:n] } + +// returns a string truncated to the first time it finds the rune `r` +// uses the `len` of the string `str` when it couldn't find the input truncate_to_rune :: proc(str: string, r: rune) -> string { n := index_rune(str, r) if n < 0 { @@ -54,20 +70,28 @@ truncate_to_rune :: proc(str: string, r: rune) -> string { return str[:n] } +// returns a cloned string of the byte array `s` using the `allocator` +// appends a leading nul byte clone_from_bytes :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> string { c := make([]byte, len(s)+1, allocator, loc) copy(c, s) c[len(s)] = 0 return string(c[:len(s)]) } + +// returns a clone of the cstring `s` using the `allocator` as a string clone_from_cstring :: proc(s: cstring, allocator := context.allocator, loc := #caller_location) -> string { return clone(string(s), allocator, loc) } + +// returns a cloned string from the pointer `ptr` and a byte length `len` using the `allocator` +// same to `string_from_ptr` but allocates clone_from_ptr :: proc(ptr: ^byte, len: int, allocator := context.allocator, loc := #caller_location) -> string { s := string_from_ptr(ptr, len) return clone(s, allocator, loc) } +// overload to clone from a `string`, `[]byte`, `cstring` or a `^byte + length` to a string clone_from :: proc{ clone, clone_from_bytes, @@ -75,6 +99,8 @@ clone_from :: proc{ clone_from_ptr, } +// returns a cloned string from the cstring `ptr` and a byte length `len` using the `allocator` +// truncates till the first nul byte it finds or the byte len clone_from_cstring_bounded :: proc(ptr: cstring, len: int, allocator := context.allocator, loc := #caller_location) -> string { s := string_from_ptr((^u8)(ptr), len) s = truncate_to_byte(s, 0) @@ -82,11 +108,12 @@ clone_from_cstring_bounded :: proc(ptr: cstring, len: int, allocator := context. } // Compares two strings, returning a value representing which one comes first lexiographically. -// -1 for `a`; 1 for `b`, or 0 if they are equal. +// -1 for `lhs`; 1 for `rhs`, or 0 if they are equal. compare :: proc(lhs, rhs: string) -> int { return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs) } +// returns the byte offset of the rune `r` in the string `s`, -1 when not found contains_rune :: proc(s: string, r: rune) -> int { for c, offset in s { if c == r { @@ -96,20 +123,48 @@ contains_rune :: proc(s: string, r: rune) -> int { return -1 } +/* + returns true when the string `substr` is contained inside the string `s` + + strings.contains("testing", "test") -> true + strings.contains("testing", "ing") -> true + strings.contains("testing", "text") -> false +*/ contains :: proc(s, substr: string) -> bool { return index(s, substr) >= 0 } +/* + returns true when the string `s` contains any of the characters inside the string `chars` + + strings.contains_any("test", "test") -> true + strings.contains_any("test", "ts") -> true + strings.contains_any("test", "et") -> true + strings.contains_any("test", "a") -> false +*/ contains_any :: proc(s, chars: string) -> bool { return index_any(s, chars) >= 0 } +/* + returns the utf8 rune count of the string `s` + strings.rune_count("test") -> 4 + strings.rune_count("testö") -> 5, where len("testö") -> 6 +*/ rune_count :: proc(s: string) -> int { return utf8.rune_count_in_string(s) } +/* + returns wether the strings `u` and `v` are the same alpha characters + works with utf8 string content and ignores different casings + strings.equal_fold("test", "test") -> true + strings.equal_fold("Test", "test") -> true + strings.equal_fold("Test", "tEsT") -> true + strings.equal_fold("test", "tes") -> false +*/ equal_fold :: proc(u, v: string) -> bool { s, t := u, v loop: for s != "" && t != "" { @@ -153,15 +208,39 @@ equal_fold :: proc(u, v: string) -> bool { return s == t } +/* + return true when the string `prefix` is contained at the start of the string `s` + + strings.has_prefix("testing", "test") -> true + strings.has_prefix("testing", "te") -> true + strings.has_prefix("telephone", "te") -> true + strings.has_prefix("testing", "est") -> false +*/ has_prefix :: proc(s, prefix: string) -> bool { return len(s) >= len(prefix) && s[0:len(prefix)] == prefix } +/* + returns true when the string `suffix` is contained at the end of the string `s` + good example to use this is for file extensions + + strings.has_suffix("todo.txt", ".txt") -> true + strings.has_suffix("todo.doc", ".txt") -> false + strings.has_suffix("todo.doc.txt", ".txt") -> true +*/ has_suffix :: proc(s, suffix: string) -> bool { return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix } +/* + returns a combined string from the slice of strings `a` seperated with the `sep` string + allocates the string using the `allocator` + a := [?]string { "a", "b", "c" } + b := strings.join(a[:], " ") -> "a b c" + c := strings.join(a[:], "-") -> "a-b-c" + d := strings.join(a[:], "...") -> "a...b...c" +*/ join :: proc(a: []string, sep: string, allocator := context.allocator) -> string { if len(a) == 0 { return "" @@ -181,6 +260,14 @@ join :: proc(a: []string, sep: string, allocator := context.allocator) -> string return string(b) } +/* + returns a combined string from the slice of strings `a` without a seperator + allocates the string using the `allocator` + + + a := [?]string { "a", "b", "c" } + b := strings.concatenate(a[:]) -> "abc" +*/ concatenate :: proc(a: []string, allocator := context.allocator) -> string { if len(a) == 0 { return "" @@ -199,8 +286,13 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string { } /* + `rune_offset` and `rune_length` are in runes, not bytes. If `rune_length` <= 0, then it'll return the remainder of the string starting with `rune_offset`. + + strings.cut("some example text", 0, 4) -> "some" + strings.cut("some example text", 2, 2) -> "me" + strings.cut("some example text", 5, 7) -> "example" */ cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator) -> (res: string) { s := s; rune_length := rune_length @@ -307,17 +399,37 @@ split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> []str return _split(s, sep, 0, n, allocator) } +/* + splits the string `s` after the seperator string `sep` appears + returns the slice of split strings allocated using `allocator` + + a := "aaa.bbb.ccc.ddd.eee" + aa := strings.split_after(a, ".") + fmt.eprintln(aa) // [aaa., bbb., ccc., ddd., eee] +*/ split_after :: proc(s, sep: string, allocator := context.allocator) -> []string { return _split(s, sep, len(sep), -1, allocator) } +/* + splits the string `s` after the seperator string `sep` appears into a total of `n` parts + returns the slice of split strings allocated using `allocator` + + a := "aaa.bbb.ccc.ddd.eee" + aa := strings.split_after(a, ".") + fmt.eprintln(aa) // [aaa., bbb., ccc., ddd., eee] +*/ split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> []string { return _split(s, sep, len(sep), n, allocator) } - @private _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, ok: bool) { + // stop once the string is empty or nil + if s == nil || len(s^) == 0 { + return + } + if sep == "" { res = s[:] ok = true @@ -339,8 +451,16 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, return } -@private -_split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) { +/* + split the ^string `s` by the byte seperator `sep` in an iterator fashion + consumes the original string till the end, leaving the string `s` with len == 0 + + text := "a.b.c.d.e" + for str in strings.split_by_byte_iterator(&text, '.') { + fmt.eprintln(str) // every loop -> a b c d e + } +*/ +split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) { m := index_byte(s^, sep) if m < 0 { // not found @@ -355,14 +475,28 @@ _split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) return } -split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (string, bool) { - return _split_by_byte_iterator(s, sep) -} +/* + split the ^string `s` by the seperator string `sep` in an iterator fashion + consumes the original string till the end + text := "a.b.c.d.e" + for str in strings.split_iterator(&text, ".") { + fmt.eprintln(str) // every loop -> a b c d e + } +*/ split_iterator :: proc(s: ^string, sep: string) -> (string, bool) { return _split_iterator(s, sep, 0) } +/* + split the ^string `s` after every seperator string `sep` in an iterator fashion + consumes the original string till the end + + text := "a.b.c.d.e" + for str in strings.split_after_iterator(&text, ".") { + fmt.eprintln(str) // every loop -> a. b. c. d. e + } +*/ split_after_iterator :: proc(s: ^string, sep: string) -> (string, bool) { return _split_iterator(s, sep, len(sep)) } @@ -379,6 +513,14 @@ _trim_cr :: proc(s: string) -> string { return s } +/* + split the string `s` at every line break '\n' + return an allocated slice of strings + + a := "a\nb\nc\nd\ne" + b := strings.split_lines(a) + fmt.eprintln(b) // [a, b, c, d, e] +*/ split_lines :: proc(s: string, allocator := context.allocator) -> []string { sep :: "\n" lines := _split(s, sep, 0, -1, allocator) @@ -388,6 +530,14 @@ split_lines :: proc(s: string, allocator := context.allocator) -> []string { return lines } +/* + split the string `s` at every line break '\n' for `n` parts + return an allocated slice of strings + + a := "a\nb\nc\nd\ne" + b := strings.split_lines_n(a, 3) + fmt.eprintln(b) // [a, b, c, d\ne\n] +*/ split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> []string { sep :: "\n" lines := _split(s, sep, 0, n, allocator) @@ -397,6 +547,14 @@ split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> []st return lines } +/* + split the string `s` at every line break '\n' leaving the '\n' in the resulting strings + return an allocated slice of strings + + a := "a\nb\nc\nd\ne" + b := strings.split_lines_after(a) + fmt.eprintln(b) // [a\n, b\n, c\n, d\n, e\n] +*/ split_lines_after :: proc(s: string, allocator := context.allocator) -> []string { sep :: "\n" lines := _split(s, sep, len(sep), -1, allocator) @@ -406,6 +564,15 @@ split_lines_after :: proc(s: string, allocator := context.allocator) -> []string return lines } +/* + split the string `s` at every line break '\n' leaving the '\n' in the resulting strings + only runs for `n` parts + return an allocated slice of strings + + a := "a\nb\nc\nd\ne" + b := strings.split_lines_after_n(a, 3) + fmt.eprintln(b) // [a\n, b\n, c\n, d\ne\n] +*/ split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) -> []string { sep :: "\n" lines := _split(s, sep, len(sep), n, allocator) @@ -415,21 +582,45 @@ split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) - return lines } +/* + split the string `s` at every line break '\n' + returns the current split string every iteration till the string is consumed + + text := "a\nb\nc\nd\ne" + for str in strings.split_lines_iterator(&text) { + fmt.eprintln(text) // every loop -> a b c d e + } +*/ split_lines_iterator :: proc(s: ^string) -> (line: string, ok: bool) { sep :: "\n" line = _split_iterator(s, sep, 0) or_return return _trim_cr(line), true } +/* + split the string `s` at every line break '\n' + returns the current split string every iteration till the string is consumed + + text := "a\nb\nc\nd\ne" + for str in strings.split_lines_after_iterator(&text) { + fmt.eprintln(text) // every loop -> a\n b\n c\n d\n e\n + } +*/ split_lines_after_iterator :: proc(s: ^string) -> (line: string, ok: bool) { sep :: "\n" line = _split_iterator(s, sep, len(sep)) or_return return _trim_cr(line), true } +/* + returns the byte offset of the first byte `c` in the string `s` it finds, -1 when not found + can't find utf8 based runes - - + strings.index_byte("test", 't') -> 0 + strings.index_byte("test", 'e') -> 1 + strings.index_byte("test", 'x') -> -1 + strings.index_byte("teäst", 'ä') -> -1 +*/ index_byte :: proc(s: string, c: byte) -> int { for i := 0; i < len(s); i += 1 { if s[i] == c { @@ -439,7 +630,15 @@ index_byte :: proc(s: string, c: byte) -> int { return -1 } -// Returns -1 if c is not present +/* + returns the byte offset of the last byte `c` in the string `s` it finds, -1 when not found + can't find utf8 based runes + + strings.index_byte("test", 't') -> 3 + strings.index_byte("test", 'e') -> 1 + strings.index_byte("test", 'x') -> -1 + strings.index_byte("teäst", 'ä') -> -1 +*/ last_index_byte :: proc(s: string, c: byte) -> int { for i := len(s)-1; i >= 0; i -= 1 { if s[i] == c { @@ -450,9 +649,50 @@ last_index_byte :: proc(s: string, c: byte) -> int { } +/* + returns the byte offset of the first rune `r` in the string `s` it finds, -1 when not found + avoids invalid runes + + strings.index_rune("abcädef", 'x') -> -1 + strings.index_rune("abcädef", 'a') -> 0 + strings.index_rune("abcädef", 'b') -> 1 + strings.index_rune("abcädef", 'c') -> 2 + strings.index_rune("abcädef", 'ä') -> 3 + strings.index_rune("abcädef", 'd') -> 5 + strings.index_rune("abcädef", 'e') -> 6 + strings.index_rune("abcädef", 'f') -> 7 +*/ +index_rune :: proc(s: string, r: rune) -> int { + switch { + case 0 <= r && r < utf8.RUNE_SELF: + return index_byte(s, byte(r)) + + case r == utf8.RUNE_ERROR: + for c, i in s { + if c == utf8.RUNE_ERROR { + return i + } + } + return -1 + + case !utf8.valid_rune(r): + return -1 + } + + b, w := utf8.encode_rune(r) + return index(s, string(b[:w])) +} @private PRIME_RABIN_KARP :: 16777619 +/* + returns the byte offset of the string `substr` in the string `s`, -1 when not found + + strings.index("test", "t") -> 0 + strings.index("test", "te") -> 0 + strings.index("test", "st") -> 2 + strings.index("test", "tt") -> -1 +*/ index :: proc(s, substr: string) -> int { hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) { for i := 0; i < len(s); i += 1 { @@ -503,6 +743,14 @@ index :: proc(s, substr: string) -> int { return -1 } +/* + returns the last byte offset of the string `substr` in the string `s`, -1 when not found + + strings.index("test", "t") -> 3 + strings.index("test", "te") -> 0 + strings.index("test", "st") -> 2 + strings.index("test", "tt") -> -1 +*/ last_index :: proc(s, substr: string) -> int { hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) { for i := len(s) - 1; i >= 0; i -= 1 { @@ -551,7 +799,15 @@ last_index :: proc(s, substr: string) -> int { return -1 } -// index_any returns the index of the first char of `chars` found in `s`. -1 if not found. +/* + returns the index of any first char of `chars` found in `s`, -1 if not found + + strings.index_any("test", "s") -> 2 + strings.index_any("test", "se") -> 1 + strings.index_any("test", "et") -> 0 + strings.index_any("test", "set") -> 0 + strings.index_any("test", "x") -> -1 +*/ index_any :: proc(s, chars: string) -> int { if chars == "" { return -1 @@ -584,6 +840,16 @@ index_any :: proc(s, chars: string) -> int { return -1 } +/* + returns the index of any first char of `chars` found in `s`, -1 if not found + iterates the string in reverse + + strings.index_any("test", "s") -> 2 + strings.index_any("test", "se") -> 2 + strings.index_any("test", "et") -> 1 + strings.index_any("test", "set") -> 3 + strings.index_any("test", "x") -> -1 +*/ last_index_any :: proc(s, chars: string) -> int { if chars == "" { return -1 @@ -633,6 +899,16 @@ last_index_any :: proc(s, chars: string) -> int { return -1 } +/* + returns the count of the string `substr` found in the string `s` + returns the rune_count + 1 of the string `s` on empty `substr` + + strings.count("abbccc", "a") -> 1 + strings.count("abbccc", "b") -> 2 + strings.count("abbccc", "c") -> 3 + strings.count("abbccc", "ab") -> 1 + strings.count("abbccc", " ") -> 0 +*/ count :: proc(s, substr: string) -> int { if len(substr) == 0 { // special case return rune_count(s) + 1 @@ -668,7 +944,12 @@ count :: proc(s, substr: string) -> int { return n } +/* + repeats the string `s` multiple `count` times and returns the allocated string + panics when `count` is below 0 + strings.repeat("abc", 2) -> "abcabc" +*/ repeat :: proc(s: string, count: int, allocator := context.allocator) -> string { if count < 0 { panic("strings: negative repeat count") @@ -685,11 +966,28 @@ repeat :: proc(s: string, count: int, allocator := context.allocator) -> string return string(b) } +/* + replaces all instances of `old` in the string `s` with the `new` string + returns the `output` string and true when an a allocation through a replace happened + + strings.replace_all("xyzxyz", "xyz", "abc") -> "abcabc", true + strings.replace_all("xyzxyz", "abc", "xyz") -> "xyzxyz", false + strings.replace_all("xyzxyz", "xy", "z") -> "zzzz", true +*/ replace_all :: proc(s, old, new: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { return replace(s, old, new, -1, allocator) } -// if n < 0, no limit on the number of replacements +/* + replaces `n` instances of `old` in the string `s` with the `new` string + if n < 0, no limit on the number of replacements + returns the `output` string and true when an a allocation through a replace happened + + strings.replace("xyzxyz", "xyz", "abc", 2) -> "abcabc", true + strings.replace("xyzxyz", "xyz", "abc", 1) -> "abcxyz", true + strings.replace("xyzxyz", "abc", "xyz", -1) -> "xyzxyz", false + strings.replace("xyzxyz", "xy", "z", -1) -> "zzzz", true +*/ replace :: proc(s, old, new: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) { if old == new || n == 0 { was_allocation = false @@ -730,17 +1028,35 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator) -> return } +/* + removes the `key` string `n` times from the `s` string + if n < 0, no limit on the number of removes + returns the `output` string and true when an a allocation through a remove happened + + strings.remove("abcabc", "abc", 1) -> "abc", true + strings.remove("abcabc", "abc", -1) -> "", true + strings.remove("abcabc", "a", -1) -> "bcbc", true + strings.remove("abcabc", "x", -1) -> "abcabc", false +*/ remove :: proc(s, key: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) { return replace(s, key, "", n, allocator) } +/* + removes all the `key` string instanes from the `s` string + returns the `output` string and true when an a allocation through a remove happened + + strings.remove("abcabc", "abc") -> "", true + strings.remove("abcabc", "a") -> "bcbc", true + strings.remove("abcabc", "x") -> "abcabc", false +*/ remove_all :: proc(s, key: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { return remove(s, key, -1, allocator) } @(private) _ascii_space := [256]bool{'\t' = true, '\n' = true, '\v' = true, '\f' = true, '\r' = true, ' ' = true} - +// return true when the `r` rune is '\t', '\n', '\v', '\f', '\r' or ' ' is_ascii_space :: proc(r: rune) -> bool { if r < utf8.RUNE_SELF { return _ascii_space[u8(r)] @@ -748,6 +1064,7 @@ is_ascii_space :: proc(r: rune) -> bool { return false } +// returns true when the `r` rune is any asci or utf8 based whitespace is_space :: proc(r: rune) -> bool { if r < 0x2000 { switch r { @@ -766,10 +1083,24 @@ is_space :: proc(r: rune) -> bool { return false } +// returns true when the `r` rune is a nul byte is_null :: proc(r: rune) -> bool { return r == 0x0000 } +/* + runs trough the `s` string linearly and watches wether the `p` procedure matches the `truth` bool + returns the rune offset or -1 when no match was found + + call :: proc(r: rune) -> bool { + return r == 'a' + } + strings.index_proc("abcabc", call) -> 0 + strings.index_proc("cbacba", call) -> 2 + strings.index_proc("cbacba", call, false) -> 0 + strings.index_proc("abcabc", call, false) -> 1 + strings.index_proc("xyz", call) -> -1 +*/ index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int { for r, i in s { if p(r) == truth { @@ -779,6 +1110,7 @@ index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int { return -1 } +// same as `index_proc` but with a `p` procedure taking a rawptr for state index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> int { for r, i in s { if p(state, r) == truth { @@ -788,6 +1120,7 @@ index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: r return -1 } +// same as `index_proc` but runs through the string in reverse last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int { // TODO(bill): Probably use Rabin-Karp Search for i := len(s); i > 0; { @@ -800,6 +1133,7 @@ last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int return -1 } +// same as `index_proc_with_state` but runs through the string in reverse last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> int { // TODO(bill): Probably use Rabin-Karp Search for i := len(s); i > 0; { @@ -811,7 +1145,17 @@ last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta } return -1 } + +/* + trims the input string `s` until the procedure `p` returns false + does not allocate - only returns a cut variant of the input string + returns an empty string when no match was found at all + find :: proc(r: rune) -> bool { + return r != 'i' + } + strings.trim_left_proc("testing", find) -> "ing" +*/ trim_left_proc :: proc(s: string, p: proc(rune) -> bool) -> string { i := index_proc(s, p, false) if i == -1 { @@ -820,29 +1164,10 @@ trim_left_proc :: proc(s: string, p: proc(rune) -> bool) -> string { return s[i:] } - -index_rune :: proc(s: string, r: rune) -> int { - switch { - case 0 <= r && r < utf8.RUNE_SELF: - return index_byte(s, byte(r)) - - case r == utf8.RUNE_ERROR: - for c, i in s { - if c == utf8.RUNE_ERROR { - return i - } - } - return -1 - - case !utf8.valid_rune(r): - return -1 - } - - b, w := utf8.encode_rune(r) - return index(s, string(b[:w])) -} - - +/* + trims the input string `s` until the procedure `p` with state returns false + returns an empty string when no match was found at all +*/ trim_left_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr) -> string { i := index_proc_with_state(s, p, state, false) if i == -1 { @@ -851,6 +1176,16 @@ trim_left_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, stat return s[i:] } +/* + trims the input string `s` from the right until the procedure `p` returns false + does not allocate - only returns a cut variant of the input string + returns an empty string when no match was found at all + + find :: proc(r: rune) -> bool { + return r != 't' + } + strings.trim_left_proc("testing", find) -> "test" +*/ trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> string { i := last_index_proc(s, p, false) if i >= 0 && s[i] >= utf8.RUNE_SELF { @@ -862,6 +1197,10 @@ trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> string { return s[0:i] } +/* + trims the input string `s` from the right until the procedure `p` with state returns false + returns an empty string when no match was found at all +*/ trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr) -> string { i := last_index_proc_with_state(s, p, state, false) if i >= 0 && s[i] >= utf8.RUNE_SELF { @@ -873,7 +1212,7 @@ trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta return s[0:i] } - +// procedure for `trim_*_proc` variants, which has a string rawptr cast + rune comparison is_in_cutset :: proc(state: rawptr, r: rune) -> bool { if state == nil { return false @@ -887,7 +1226,7 @@ is_in_cutset :: proc(state: rawptr, r: rune) -> bool { return false } - +// trims the `cutset` string from the `s` string trim_left :: proc(s: string, cutset: string) -> string { if s == "" || cutset == "" { return s @@ -896,6 +1235,7 @@ trim_left :: proc(s: string, cutset: string) -> string { return trim_left_proc_with_state(s, is_in_cutset, &state) } +// trims the `cutset` string from the `s` string from the right trim_right :: proc(s: string, cutset: string) -> string { if s == "" || cutset == "" { return s @@ -904,35 +1244,48 @@ trim_right :: proc(s: string, cutset: string) -> string { return trim_right_proc_with_state(s, is_in_cutset, &state) } +// trims the `cutset` string from the `s` string, both from left and right trim :: proc(s: string, cutset: string) -> string { return trim_right(trim_left(s, cutset), cutset) } +// trims until a valid non space rune: "\t\txyz\t\t" -> "xyz\t\t" trim_left_space :: proc(s: string) -> string { return trim_left_proc(s, is_space) } +// trims from the right until a valid non space rune: "\t\txyz\t\t" -> "\t\txyz" trim_right_space :: proc(s: string) -> string { return trim_right_proc(s, is_space) } +// trims from both sides until a valid non space rune: "\t\txyz\t\t" -> "xyz" trim_space :: proc(s: string) -> string { return trim_right_space(trim_left_space(s)) } - +// trims nul runes from the left: "\x00\x00testing\x00\x00" -> "testing\x00\x00" trim_left_null :: proc(s: string) -> string { return trim_left_proc(s, is_null) } +// trims nul runes from the right: "\x00\x00testing\x00\x00" -> "\x00\x00testing" trim_right_null :: proc(s: string) -> string { return trim_right_proc(s, is_null) } +// trims nul runes from both sides: "\x00\x00testing\x00\x00" -> "testing" trim_null :: proc(s: string) -> string { return trim_right_null(trim_left_null(s)) } +/* + trims a `prefix` string from the start of the `s` string and returns the trimmed string + returns the input string `s` when no prefix was found + + strings.trim_prefix("testing", "test") -> "ing" + strings.trim_prefix("testing", "abc") -> "testing" +*/ trim_prefix :: proc(s, prefix: string) -> string { if has_prefix(s, prefix) { return s[len(prefix):] @@ -940,6 +1293,13 @@ trim_prefix :: proc(s, prefix: string) -> string { return s } +/* + trims a `suffix` string from the end of the `s` string and returns the trimmed string + returns the input string `s` when no suffix was found + + strings.trim_suffix("todo.txt", ".txt") -> "todo" + strings.trim_suffix("todo.doc", ".txt") -> "todo.doc" +*/ trim_suffix :: proc(s, suffix: string) -> string { if has_suffix(s, suffix) { return s[:len(s)-len(suffix)] @@ -947,142 +1307,151 @@ trim_suffix :: proc(s, suffix: string) -> string { return s } -split_multi :: proc(s: string, substrs: []string, skip_empty := false, allocator := context.allocator) -> []string #no_bounds_check { +/* + splits the input string `s` by all possible `substrs` []string + returns the allocated []string, nil on any empty substring or no matches + + splits := [?]string { "---", "~~~", ".", "_", "," } + res := strings.split_multi("testing,this.out_nice---done~~~last", splits[:]) + fmt.eprintln(res) // -> [testing, this, out, nice, done, last] +*/ +split_multi :: proc(s: string, substrs: []string, allocator := context.allocator) -> (buf: []string) #no_bounds_check { if s == "" || len(substrs) <= 0 { - return nil + return } - sublen := len(substrs[0]) - - for substr in substrs[1:] { - sublen = min(sublen, len(substr)) + // disallow "" substr + for substr in substrs { + if len(substr) == 0 { + return + } } - shared := len(s) - sublen + // TODO maybe remove duplicate substrs + // sort substrings by string size, largest to smallest + temp_substrs := slice.clone(substrs, context.temp_allocator) + slice.sort_by(temp_substrs, proc(a, b: string) -> bool { + return len(a) > len(b) + }) - if shared <= 0 { - return nil - } + substrings_found: int + temp := s - // number, index, last - n, i, l := 0, 0, 0 - - // count results - first_pass: for i <= shared { - for substr in substrs { - if s[i:i+sublen] == substr { - if !skip_empty || i - l > 0 { - n += 1 - } - - i += sublen - l = i + // count substr results found in string + first_pass: for len(temp) > 0 { + for substr in temp_substrs { + size := len(substr) + // check range and compare string to substr + if size <= len(temp) && temp[:size] == substr { + substrings_found += 1 + temp = temp[size:] continue first_pass } } - _, skip := utf8.decode_rune_in_string(s[i:]) - i += skip + // step through string + _, skip := utf8.decode_rune_in_string(temp[:]) + temp = temp[skip:] } - if !skip_empty || len(s) - l > 0 { - n += 1 + // skip when no results + if substrings_found < 1 { + return } - if n < 1 { - // no results - return nil - } + buf = make([]string, substrings_found + 1, allocator) + buf_index: int + temp = s + temp_old := temp - buf := make([]string, n, allocator) - - n, i, l = 0, 0, 0 - - // slice results - second_pass: for i <= shared { - for substr in substrs { - if s[i:i+sublen] == substr { - if !skip_empty || i - l > 0 { - buf[n] = s[l:i] - n += 1 - } - - i += sublen - l = i + // gather results in the same fashion + second_pass: for len(temp) > 0 { + for substr in temp_substrs { + size := len(substr) + // check range and compare string to substr + if size <= len(temp) && temp[:size] == substr { + buf[buf_index] = temp_old[:len(temp_old) - len(temp)] + buf_index += 1 + temp = temp[size:] + temp_old = temp continue second_pass } } - _, skip := utf8.decode_rune_in_string(s[i:]) - i += skip + // step through string + _, skip := utf8.decode_rune_in_string(temp[:]) + temp = temp[skip:] } - if !skip_empty || len(s) - l > 0 { - buf[n] = s[l:] - } + buf[buf_index] = temp_old[:] return buf } +// state for the split multi iterator +Split_Multi :: struct { + temp: string, + temp_old: string, + substrs: []string, +} +// returns split multi state with sorted `substrs` +split_multi_init :: proc(s: string, substrs: []string) -> Split_Multi { + // sort substrings, largest to smallest + temp_substrs := slice.clone(substrs, context.temp_allocator) + slice.sort_by(temp_substrs, proc(a, b: string) -> bool { + return len(a) > len(b) + }) - -split_multi_iterator :: proc(s: ^string, substrs: []string, skip_empty := false) -> (string, bool) #no_bounds_check { - if s == nil || s^ == "" || len(substrs) <= 0 { - return "", false + return { + temp = s, + temp_old = s, + substrs = temp_substrs, } +} - sublen := len(substrs[0]) +/* + splits the input string `s` by all possible `substrs` []string in an iterator fashion + returns the split string every iteration, the full string on no match - for substr in substrs[1:] { - sublen = min(sublen, len(substr)) + splits := [?]string { "---", "~~~", ".", "_", "," } + state := strings.split_multi_init("testing,this.out_nice---done~~~last", splits[:]) + for str in strings.split_multi_iterate(&state) { + fmt.eprintln(str) // every iteration -> [testing, this, out, nice, done, last] } - - shared := len(s) - sublen - - if shared <= 0 { - return "", false - } - - // index, last - i, l := 0, 0 - - loop: for i <= shared { +*/ +split_multi_iterate :: proc(using sm: ^Split_Multi) -> (res: string, ok: bool) #no_bounds_check { + pass: for len(temp) > 0 { for substr in substrs { - if s[i:i+sublen] == substr { - if !skip_empty || i - l > 0 { - res := s[l:i] - s^ = s[i:] - return res, true - } + size := len(substr) - i += sublen - l = i - - continue loop + // check range and compare string to substr + if size <= len(temp) && temp[:size] == substr { + res = temp_old[:len(temp_old) - len(temp)] + temp = temp[size:] + temp_old = temp + ok = true + return } } - _, skip := utf8.decode_rune_in_string(s[i:]) - i += skip + // step through string + _, skip := utf8.decode_rune_in_string(temp[:]) + temp = temp[skip:] } - if !skip_empty || len(s) - l > 0 { - res := s[l:] - s^ = s[len(s):] - return res, true + // allow last iteration + if temp_old != "" { + res = temp_old[:] + ok = true + temp_old = "" } - return "", false + return } - - - - - // scrub scruvs invalid utf-8 characters and replaces them with the replacement string // Adjacent invalid bytes are only replaced once scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string { @@ -1117,7 +1486,13 @@ scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> return to_string(b) } +/* + returns a reversed version of the `s` string + a := "abcxyz" + b := strings.reverse(a) + fmt.eprintln(a, b) // abcxyz zyxcba +*/ reverse :: proc(s: string, allocator := context.allocator) -> string { str := s n := len(str) @@ -1133,12 +1508,19 @@ reverse :: proc(s: string, allocator := context.allocator) -> string { return string(buf) } +/* + expands the string to a grid spaced by `tab_size` whenever a `\t` character appears + returns the tabbed string, panics on tab_size <= 0 + + strings.expand_tabs("abc1\tabc2\tabc3", 4) -> abc1 abc2 abc3 + strings.expand_tabs("abc1\tabc2\tabc3", 5) -> abc1 abc2 abc3 + strings.expand_tabs("abc1\tabc2\tabc3", 6) -> abc1 abc2 abc3 +*/ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> string { if tab_size <= 0 { panic("tab size must be positive") } - if s == "" { return "" } @@ -1176,7 +1558,16 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> return to_string(b) } +/* + splits the `str` string by the seperator `sep` string and returns 3 parts + `head`: before the split, `match`: the seperator, `tail`: the end of the split + returns the input string when the `sep` was not found + text := "testing this out" + strings.partition(text, " this ") -> head: "testing", match: " this ", tail: "out" + strings.partition(text, "hi") -> head: "testing t", match: "hi", tail: "s out" + strings.partition(text, "xyz") -> head: "testing this out", match: "", tail: "" +*/ partition :: proc(str, sep: string) -> (head, match, tail: string) { i := index(str, sep) if i == -1 { @@ -1392,7 +1783,7 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { return "", false } - field = s[start:] + field = s[:len(s)] ok = true s^ = s[len(s):] return From 880d330cca09038d01a9133501e6fe89186111fd Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Sun, 27 Mar 2022 16:34:00 +0200 Subject: [PATCH 0453/1052] update delay to use deltatime, add time left --- core/math/ease/ease.odin | 41 +++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/core/math/ease/ease.odin b/core/math/ease/ease.odin index 0fe59f9d2..f4310b639 100644 --- a/core/math/ease/ease.odin +++ b/core/math/ease/ease.odin @@ -1,3 +1,4 @@ +// easing procedures and flux easing used for animations package ease import "core:math" @@ -335,9 +336,8 @@ Flux_Tween :: struct($T: typeid) { diff: T, goal: T, - // using ticks for timing instead - delay_tick_start: time.Tick, - delay: time.Duration, + delay: f64, // in seconds + delay_delta: f64, duration: time.Duration, progress: f64, @@ -379,7 +379,7 @@ flux_to :: proc( goal: f32, type: Ease = .Quadratic_Out, duration: time.Duration = time.Second, - delay: time.Duration = 0, + delay: f64 = 0, ) -> (tween: ^Flux_Tween(T)) where intrinsics.type_is_float(T) { if res, ok := &flux.values[value]; ok { tween = res @@ -393,7 +393,6 @@ flux_to :: proc( goal = goal, duration = duration, delay = delay, - delay_tick_start = time.tick_now(), type = type, data = value, } @@ -416,17 +415,24 @@ flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where i // deletes tween from the map after completion flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) { size := len(flux.values) - now := time.tick_now() + dt := dt for key, tween in &flux.values { - if tween.delay != 0 { - diff := time.tick_diff(tween.delay_tick_start, now) + delay_remainder := f64(0) - // when diff reached delay, stop delaying - if diff > tween.delay { + if tween.delay > 0 { + // Update delay + tween.delay -= dt + + if tween.delay < 0 { + // We finished the delay, but in doing so consumed part of this frame's `dt` budget. + // Keep track of it so we can apply it to this tween without affecting others. + delay_remainder = tween.delay + // We're done with this delay. tween.delay = 0 } } else { + // We either had no delay, or the delay has been consumed. if !tween.inited { flux_tween_init(&tween, tween.duration) @@ -435,7 +441,10 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float } } - tween.progress += tween.rate * dt + // If part of the `dt` budget was consumed this frame, then `delay_remainder` will be + // that remainder, a negative value. Adding it to `dt` applies what's left of the `dt` + // to the tween so it advances properly, instead of too much or little. + tween.progress += tween.rate * (dt + delay_remainder) x := tween.progress >= 1 ? 1 : ease(tween.type, tween.progress) tween.value^ = tween.start + tween.diff * T(x) @@ -463,4 +472,14 @@ flux_stop :: proc(flux: ^Flux_Map($T), key: ^f32) -> bool where intrinsics.type_ } return false +} + +// returns the amount of time left for the tween animation, if the key exists in the map +// returns 0 if the tween doesnt exist on the map +flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 { + if tween, ok := flux.values[key]; ok { + return ((1 - tween.progress) * tween.rate) + tween.delay + } else { + return 0 + } } \ No newline at end of file From b1c2c0ea7a47d90f5fa67f6dc6f53b145f0046a6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 27 Mar 2022 16:49:22 +0200 Subject: [PATCH 0454/1052] [ease] Flux fixups. --- core/math/ease/ease.odin | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/core/math/ease/ease.odin b/core/math/ease/ease.odin index f4310b639..c61e29367 100644 --- a/core/math/ease/ease.odin +++ b/core/math/ease/ease.odin @@ -25,7 +25,7 @@ quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float( // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { if p < 0.5 { - return 2 * p * p; + return 2 * p * p } else { return (-2 * p * p) + (4 * p) - 1 } @@ -337,7 +337,6 @@ Flux_Tween :: struct($T: typeid) { goal: T, delay: f64, // in seconds - delay_delta: f64, duration: time.Duration, progress: f64, @@ -414,25 +413,24 @@ flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where i // calls callbacks in all stages, when they're filled // deletes tween from the map after completion flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) { - size := len(flux.values) - dt := dt - for key, tween in &flux.values { delay_remainder := f64(0) + // Update delay if necessary. if tween.delay > 0 { - // Update delay tween.delay -= dt if tween.delay < 0 { - // We finished the delay, but in doing so consumed part of this frame's `dt` budget. - // Keep track of it so we can apply it to this tween without affecting others. + // We finished the delay, but in doing so consumed part of this frame's `dt` budget. + // Keep track of it so we can apply it to this tween without affecting others. delay_remainder = tween.delay // We're done with this delay. tween.delay = 0 } - } else { - // We either had no delay, or the delay has been consumed. + } + + // We either had no delay, or the delay has been consumed. + if tween.delay <= 0 { if !tween.inited { flux_tween_init(&tween, tween.duration) From 24c48d22bc82d4204673984d3b75a207a53282b7 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 27 Mar 2022 22:13:26 +0200 Subject: [PATCH 0455/1052] [strings] Improve `cut`, add tests for it. --- core/strings/strings.odin | 37 ++++++++++++++++++----- tests/core/strings/test_core_strings.odin | 29 +++++++++++++++++- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 452c0ca0c..d01be7989 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -286,9 +286,8 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string { } /* - `rune_offset` and `rune_length` are in runes, not bytes. - If `rune_length` <= 0, then it'll return the remainder of the string starting with `rune_offset`. + If `rune_length` <= 0, then it'll return the remainder of the string starting at `rune_offset`. strings.cut("some example text", 0, 4) -> "some" strings.cut("some example text", 2, 2) -> "me" @@ -296,26 +295,48 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string { */ cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator) -> (res: string) { s := s; rune_length := rune_length - l := utf8.rune_count_in_string(s) + context.allocator = allocator - if rune_offset >= l { return "" } + // If we signal that we want the entire remainder (length <= 0) *and* + // the offset is zero, then we can early out by cloning the input if rune_offset == 0 && rune_length <= 0 { - return clone(s, allocator) + return clone(s) } - if rune_length == 0 { rune_length = l } + // We need to know if we have enough runes to cover offset + length. + rune_count := utf8.rune_count_in_string(s) + + // We're asking for a substring starting after the end of the input string. + // That's just an empty string. + if rune_offset >= rune_count { + return "" + } + + // If we don't specify the length of the substring, use the remainder. + if rune_length <= 0 { + rune_length = rune_count - rune_offset + } + + // We don't yet know how many bytes we need exactly. + // But we do know it's bounded by the number of runes * 4 bytes, + // and can be no more than the size of the input string. bytes_needed := min(rune_length * 4, len(s)) - buf := make([]u8, bytes_needed, allocator) + buf := make([]u8, bytes_needed) byte_offset := 0 - for i := 0; i < l; i += 1 { + for i := 0; i < rune_count; i += 1 { _, w := utf8.decode_rune_in_string(s) + + // If the rune is part of the substring, copy it to the output buffer. if i >= rune_offset { for j := 0; j < w; j += 1 { buf[byte_offset+j] = s[j] } byte_offset += w } + + // We're done if we reach the end of the input string, *or* + // if we've reached a specified length in runes. if rune_length > 0 { if i == rune_offset + rune_length - 1 { break } } diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index 70da1a73b..ad3f6afc4 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -32,6 +32,7 @@ main :: proc() { test_index_any_larger_string_not_found(&t) test_index_any_small_string_found(&t) test_index_any_larger_string_found(&t) + test_cut(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) if TEST_fail > 0 { @@ -42,7 +43,6 @@ main :: proc() { @test test_index_any_small_string_not_found :: proc(t: ^testing.T) { index := strings.index_any(".", "/:\"") - log(t, index) expect(t, index == -1, "index_any should be negative") } @@ -63,3 +63,30 @@ test_index_any_larger_string_found :: proc(t: ^testing.T) { index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") expect(t, index == 8, "index_any should be 8") } + +Cut_Test :: struct { + input: string, + offset: int, + length: int, + output: string, +} + +cut_tests :: []Cut_Test{ + {"some example text", 0, 4, "some" }, + {"some example text", 2, 2, "me" }, + {"some example text", 5, 7, "example" }, + {"some example text", 5, 0, "example text"}, + {"恥ずべきフクロウ", 4, 0, "フクロウ" }, +} + +@test +test_cut :: proc(t: ^testing.T) { + for test in cut_tests { + res := strings.cut(test.input, test.offset, test.length) + defer delete(res) + + msg := fmt.tprintf("cut(\"%v\", %v, %v) expected to return \"%v\", got \"%v\"", + test.input, test.offset, test.length, test.output, res) + expect(t, res == test.output, msg) + } +} \ No newline at end of file From 412c9a99d5db413580839d5f06b3de2f5ca1c435 Mon Sep 17 00:00:00 2001 From: hikari Date: Tue, 29 Mar 2022 08:56:05 +0300 Subject: [PATCH 0456/1052] sys/windows: add SetTimer() and KillTimer() procedures --- core/sys/windows/types.odin | 5 +++++ core/sys/windows/user32.odin | 3 +++ 2 files changed, 8 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 45c94e733..a01ac80eb 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -194,6 +194,8 @@ GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0 GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1 +TIMERPROC :: #type proc "stdcall" (HWND, UINT, UINT_PTR, DWORD) + WNDPROC :: #type proc "stdcall" (HWND, UINT, WPARAM, LPARAM) -> LRESULT WNDCLASSA :: struct { @@ -618,6 +620,9 @@ MK_MBUTTON :: 0x0010 MK_XBUTTON1 :: 0x0020 MK_XBUTTON2 :: 0x0040 +USER_TIMER_MAXIMUM :: 0x7FFFFFFF +USER_TIMER_MINIMUM :: 0x0000000A + _IDC_APPSTARTING := rawptr(uintptr(32650)) _IDC_ARROW := rawptr(uintptr(32512)) _IDC_CROSS := rawptr(uintptr(32515)) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 001434f80..772cad028 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -126,6 +126,9 @@ foreign user32 { GetKeyState :: proc(nVirtKey: c_int) -> SHORT --- GetAsyncKeyState :: proc(vKey: c_int) -> SHORT --- + SetTimer :: proc(hWnd: HWND, nIDEvent: UINT_PTR, uElapse: UINT, lpTimerFunc: TIMERPROC) -> UINT_PTR --- + KillTimer :: proc(hWnd: HWND, uIDEvent: UINT_PTR) -> BOOL --- + MessageBoxA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT) -> c_int --- MessageBoxW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT) -> c_int --- MessageBoxExA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT, wLanguageId: WORD) -> c_int --- From df32b5b46c03b6e2955af026074831eebd0e18d6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 29 Mar 2022 16:13:17 +0200 Subject: [PATCH 0457/1052] [windows] Fix leak in `glob`. --- core/os/dir_windows.odin | 1 + core/os/stat.odin | 1 - core/os/stat_windows.odin | 12 ++++++------ core/path/filepath/match.odin | 14 ++++++++++---- core/path/filepath/path.odin | 2 +- core/sys/windows/util.odin | 7 ++++--- tests/core/strings/test_core_strings.odin | 2 +- 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index ff7e53293..3261b8cb3 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -82,6 +82,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F wpath_search[len(wpath)+2] = 0 path := cleanpath_from_buf(wpath) + defer delete(path) find_data := &win32.WIN32_FIND_DATAW{} find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data) diff --git a/core/os/stat.odin b/core/os/stat.odin index 6f4c8b0ef..1b64ad33b 100644 --- a/core/os/stat.odin +++ b/core/os/stat.odin @@ -2,7 +2,6 @@ package os import "core:time" - File_Info :: struct { fullpath: string, name: string, diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 964625315..5da925560 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -80,7 +80,7 @@ stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) return _stat(name, attrs, allocator) } -fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Errno) { +fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, errno: Errno) { if fd == 0 { return {}, ERROR_INVALID_HANDLE } @@ -94,14 +94,14 @@ fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Errno) h := win32.HANDLE(fd) switch win32.GetFileType(h) { case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR: - fi: File_Info - fi.fullpath = path fi.name = basename(path) fi.mode |= file_type_mode(h) - return fi, ERROR_NONE + errno = ERROR_NONE + case: + fi, errno = file_info_from_get_file_information_by_handle(path, h) } - - return file_info_from_get_file_information_by_handle(path, h) + fi.fullpath = path + return } diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin index 6399f86a2..252912710 100644 --- a/core/path/filepath/match.odin +++ b/core/path/filepath/match.odin @@ -220,9 +220,11 @@ get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Match_Er // glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []string, err: Match_Error) { + context.allocator = allocator + if !has_meta(pattern) { // TODO(bill): os.lstat on here to check for error - m := make([]string, 1, allocator) + m := make([]string, 1) m[0] = pattern return m[:], .None } @@ -232,6 +234,7 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str when ODIN_OS == .Windows { temp_buf: [8]byte volume_len, dir = clean_glob_path_windows(dir, temp_buf[:]) + } else { dir = clean_glob_path(dir) } @@ -246,7 +249,7 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str if err != .None { return } - dmatches := make([dynamic]string, 0, 0, allocator) + dmatches := make([dynamic]string, 0, 0) for d in m { dmatches, err = _glob(d, file, &dmatches) if err != .None { @@ -258,11 +261,13 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str } return } -_glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]string, e: Match_Error) { +_glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := context.allocator) -> (m: [dynamic]string, e: Match_Error) { + context.allocator = allocator + if matches != nil { m = matches^ } else { - m = make([dynamic]string, 0, 0, context.allocator) + m = make([dynamic]string, 0, 0) } @@ -275,6 +280,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s { file_info, ferr := os.fstat(d) defer os.file_info_delete(file_info) + if ferr != 0 { return } diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin index c04bd5a11..42714d736 100644 --- a/core/path/filepath/path.odin +++ b/core/path/filepath/path.odin @@ -122,6 +122,7 @@ clean :: proc(path: string, allocator := context.allocator) -> string { vol_and_path = original_path, vol_len = vol_len, } + defer lazy_buffer_destroy(out) r, dot_dot := 0, 0 if rooted { @@ -170,7 +171,6 @@ clean :: proc(path: string, allocator := context.allocator) -> string { cleaned, new_allocation := from_slash(s) if new_allocation { delete(s) - lazy_buffer_destroy(out) } return cleaned } diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index efb37dbc0..5797216c3 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -45,7 +45,9 @@ utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> wstri return nil } -wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> string { +wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string) { + context.allocator = allocator + if N <= 0 { return "" } @@ -60,7 +62,7 @@ wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) // also null terminated. // If N != -1 it assumes the wide string is not null terminated and the resulting string // will not be null terminated, we therefore have to force it to be null terminated manually. - text := make([]byte, n+1 if N != -1 else n, allocator) + text := make([]byte, n+1 if N != -1 else n) n1 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(text), n, nil, nil) if n1 == 0 { @@ -74,7 +76,6 @@ wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) break } } - return string(text[:n]) } diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index ad3f6afc4..e97734dda 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -1,4 +1,4 @@ -package test_core_image +package test_core_strings import "core:strings" import "core:testing" From 6a3ec5eb3647965d6792c5ff17a4534d0e458548 Mon Sep 17 00:00:00 2001 From: hikari Date: Tue, 29 Mar 2022 22:59:45 +0300 Subject: [PATCH 0458/1052] sys/windows: add WM_SYSCOMMAND related constants --- core/sys/windows/types.odin | 25 +++++++++++++++++++++++++ core/sys/windows/user32.odin | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index a01ac80eb..50098a59c 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -594,6 +594,31 @@ SM_CARETBLINKINGENABLED :: 0x2002 SM_CONVERTIBLESLATEMODE :: 0x2003 SM_SYSTEMDOCKED :: 0x2004 +// System Menu Command Values +SC_SIZE :: 0xF000 +SC_MOVE :: 0xF010 +SC_MINIMIZE :: 0xF020 +SC_MAXIMIZE :: 0xF030 +SC_NEXTWINDOW :: 0xF040 +SC_PREVWINDOW :: 0xF050 +SC_CLOSE :: 0xF060 +SC_VSCROLL :: 0xF070 +SC_HSCROLL :: 0xF080 +SC_MOUSEMENU :: 0xF090 +SC_KEYMENU :: 0xF100 +SC_ARRANGE :: 0xF110 +SC_RESTORE :: 0xF120 +SC_TASKLIST :: 0xF130 +SC_SCREENSAVE :: 0xF140 +SC_HOTKEY :: 0xF150 +SC_DEFAULT :: 0xF160 +SC_MONITORPOWER :: 0xF170 +SC_CONTEXTHELP :: 0xF180 +SC_SEPARATOR :: 0xF00F +SCF_ISSECURE :: 0x00000001 +SC_ICON :: SC_MINIMIZE +SC_ZOOM :: SC_MAXIMIZE + CW_USEDEFAULT : c_int : -2147483648 SIZE_RESTORED :: 0 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 772cad028..bdab77e27 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -192,3 +192,7 @@ CreateWindowW :: #force_inline proc "stdcall" ( lpParam, ) } + +GET_SC_WPARAM :: #force_inline proc(wparam: WPARAM) -> i32 { + return i32(wparam) & 0xFFF0 +} From a632db361849f80b888faf282b1b95c43ec37432 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 30 Mar 2022 04:45:22 -0700 Subject: [PATCH 0459/1052] Make no crt work on Linux --- core/runtime/entry_unix.odin | 2 +- src/main.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index 1a3def200..9f7d219c3 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -30,4 +30,4 @@ when ODIN_BUILD_MODE == .Dynamic { #force_no_inline _cleanup_runtime() return 0 } -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index 63b2c8386..383997719 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -433,6 +433,10 @@ i32 linker_stage(lbGenerator *gen) { String output_ext = {}; gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); + if (build_context.no_crt) { + link_settings = gb_string_append_fmt(link_settings, "-nostdlib "); + } + // NOTE(dweiler): We use clang as a frontend for the linker as there are // other runtime and compiler support libraries that need to be linked in // very specific orders such as libgcc_s, ld-linux-so, unwind, etc. From 3a4630e6b417f5aaf4fb2b33ff545193f82310b9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 30 Mar 2022 16:15:23 +0100 Subject: [PATCH 0460/1052] Correct `atomic_cxchg_*` `atomic_cxchgweak_*` intrinsics behaviour to monotonic on failure for acq, rel, and acqrel --- src/llvm_backend_proc.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 27a6ec209..2d556b382 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1372,12 +1372,20 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); - LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("pause"), {}); + LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("pause"), {}, true); GB_ASSERT(the_asm != nullptr); LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); } else if (build_context.metrics.arch == TargetArch_arm64) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); - LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("yield"), {}); + // NOTE(bill, 2022-03-30): `isb` appears to a better option that `yield` + // See: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8258604 + LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("isb"), {}, true); + GB_ASSERT(the_asm != nullptr); + LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); + } else { + // NOTE: default to something to prevent optimization + LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); + LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit(""), {}, true); GB_ASSERT(the_asm != nullptr); LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); } @@ -1794,18 +1802,18 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, switch (id) { case BuiltinProc_atomic_cxchg: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; + case BuiltinProc_atomic_cxchg_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; + case BuiltinProc_atomic_cxchg_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; + case BuiltinProc_atomic_cxchg_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; case BuiltinProc_atomic_cxchg_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; case BuiltinProc_atomic_cxchg_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; case BuiltinProc_atomic_cxchg_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = false; break; case BuiltinProc_atomic_cxchg_acq_failrelaxed: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; case BuiltinProc_atomic_cxchgweak: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchgweak_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; - case BuiltinProc_atomic_cxchgweak_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; - case BuiltinProc_atomic_cxchgweak_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; + case BuiltinProc_atomic_cxchgweak_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; + case BuiltinProc_atomic_cxchgweak_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; + case BuiltinProc_atomic_cxchgweak_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; case BuiltinProc_atomic_cxchgweak_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; case BuiltinProc_atomic_cxchgweak_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; case BuiltinProc_atomic_cxchgweak_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = true; break; From 561b725b0ec4b2be9180c1b8e2ee9fdf0d6fab34 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 30 Mar 2022 16:15:48 +0100 Subject: [PATCH 0461/1052] Improve spin lock for atomic_mutex_lock --- core/sync/sync2/primitives_atomic.odin | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/sync/sync2/primitives_atomic.odin b/core/sync/sync2/primitives_atomic.odin index 5fc6fba85..dd082029b 100644 --- a/core/sync/sync2/primitives_atomic.odin +++ b/core/sync/sync2/primitives_atomic.odin @@ -38,6 +38,9 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) { } } + // Set just in case 100 iterations did not do it + new_state = .Waiting + for { if atomic_exchange_acquire(&m.state, .Waiting) == .Unlocked { return @@ -49,11 +52,7 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) { } - switch v := atomic_exchange_acquire(&m.state, .Locked); v { - case .Unlocked: - // Okay - case: fallthrough - case .Locked, .Waiting: + if v := atomic_exchange_acquire(&m.state, .Locked); v != .Unlocked { lock_slow(m, v) } } From 46161f7e19b346192a1a7fedb6b833acd18805bd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 30 Mar 2022 16:28:16 +0100 Subject: [PATCH 0462/1052] `threading_example` allow on Darwin --- examples/demo/demo.odin | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 8c2321dae..ee4a2dd2b 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1107,11 +1107,6 @@ prefix_table := [?]string{ } threading_example :: proc() { - if ODIN_OS == .Darwin { - // TODO: Fix threads on darwin/macOS - return - } - fmt.println("\n# threading_example") { // Basic Threads From 72ae0617694593aecf4b3d0006f2786d7ad4dea6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 30 Mar 2022 17:29:37 +0100 Subject: [PATCH 0463/1052] Add `intrinsics.wasm_memory_grow` `intrinsics.wasm_memory_size` --- core/intrinsics/intrinsics.odin | 4 ++ src/check_builtin.cpp | 69 ++++++++++++++++++++++++++++++++- src/check_decl.cpp | 4 +- src/checker_builtin_procs.hpp | 4 ++ src/llvm_backend_proc.cpp | 39 +++++++++++++++++++ 5 files changed, 118 insertions(+), 2 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index c3ef787bc..16dd5cbc5 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -201,6 +201,10 @@ type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, raw type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) --- +// WASM targets only +wasm_memory_grow :: proc(index, delta: uintptr) -> int --- +wasm_memory_size :: proc(index: uintptr) -> int --- + // Internal compiler use only __entry_point :: proc() --- \ No newline at end of file diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 4cd09b8e9..e480704e3 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -304,7 +304,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } else if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) { gbString e = expr_to_string(self.expr); gbString t = type_to_string(self.type); - error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind); + error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t); gb_string_free(t); gb_string_free(e); return false; @@ -4111,6 +4111,73 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } + case BuiltinProc_wasm_memory_grow: + { + if (!is_arch_wasm()) { + error(call, "'%.*s' is only allowed on wasm targets", LIT(builtin_name)); + return false; + } + + Operand index = {}; + Operand delta = {}; + check_expr(c, &index, ce->args[0]); if (index.mode == Addressing_Invalid) return false; + check_expr(c, &delta, ce->args[1]); if (delta.mode == Addressing_Invalid) return false; + + convert_to_typed(c, &index, t_uintptr); if (index.mode == Addressing_Invalid) return false; + convert_to_typed(c, &delta, t_uintptr); if (delta.mode == Addressing_Invalid) return false; + + if (!is_operand_value(index) || !check_is_assignable_to(c, &index, t_uintptr)) { + gbString e = expr_to_string(index.expr); + gbString t = type_to_string(index.type); + error(index.expr, "'%.*s' expected a uintptr for the memory index, got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + if (!is_operand_value(delta) || !check_is_assignable_to(c, &delta, t_uintptr)) { + gbString e = expr_to_string(delta.expr); + gbString t = type_to_string(delta.type); + error(delta.expr, "'%.*s' expected a uintptr for the memory delta, got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + operand->mode = Addressing_Value; + operand->type = t_int; + operand->value = {}; + break; + } + break; + case BuiltinProc_wasm_memory_size: + { + if (!is_arch_wasm()) { + error(call, "'%.*s' is only allowed on wasm targets", LIT(builtin_name)); + return false; + } + + Operand index = {}; + check_expr(c, &index, ce->args[0]); if (index.mode == Addressing_Invalid) return false; + + convert_to_typed(c, &index, t_uintptr); if (index.mode == Addressing_Invalid) return false; + + if (!is_operand_value(index) || !check_is_assignable_to(c, &index, t_uintptr)) { + gbString e = expr_to_string(index.expr); + gbString t = type_to_string(index.type); + error(index.expr, "'%.*s' expected a uintptr for the memory index, got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + operand->mode = Addressing_Value; + operand->type = t_int; + operand->value = {}; + break; + } + break; + } return true; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index d4a320f03..5acd56097 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1137,7 +1137,9 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix); if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { - error(e->token, "@(thread_local) is not supported for this target platform"); + e->Variable.thread_local_model.len = 0; + // NOTE(bill): ignore this message for the time begin + // error(e->token, "@(thread_local) is not supported for this target platform"); } String context_name = str_lit("variable declaration"); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index cba952ddf..c647d5a01 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -260,6 +260,8 @@ BuiltinProc__type_end, BuiltinProc_constant_utf16_cstring, + BuiltinProc_wasm_memory_grow, + BuiltinProc_wasm_memory_size, BuiltinProc_COUNT, }; @@ -523,4 +525,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("wasm_memory_grow"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("wasm_memory_size"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, }; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 2d556b382..d7f3d6c45 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2207,6 +2207,45 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return res; } + + case BuiltinProc_wasm_memory_grow: + { + char const *name = "llvm.wasm.memory.grow"; + LLVMTypeRef types[1] = { + lb_type(p->module, t_uintptr), + }; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0])); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + LLVMValueRef args[2] = {}; + args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value; + args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_uintptr).value; + + lbValue res = {}; + res.type = tv.type; + res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + return res; + } + case BuiltinProc_wasm_memory_size: + { + char const *name = "llvm.wasm.memory.size"; + LLVMTypeRef types[1] = { + lb_type(p->module, t_uintptr), + }; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0])); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + LLVMValueRef args[1] = {}; + args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value; + + lbValue res = {}; + res.type = tv.type; + res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + return res; + } + } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); From 4eb4ae6305720d226f6ccd1ee8d7b18b8436ced0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 30 Mar 2022 17:42:44 +0100 Subject: [PATCH 0464/1052] Replace `sync` with `sync2` --- core/mem/virtual/virtual_platform.odin | 2 +- core/os/os2/process.odin | 2 +- core/sync/atomic.odin | 227 ++--- core/sync/barrier.odin | 80 -- core/sync/channel.odin | 889 ------------------ core/sync/channel_unix.odin | 16 - core/sync/channel_windows.odin | 33 - core/sync/{sync2 => }/extended.odin | 0 core/sync/{sync2 => }/futex_darwin.odin | 0 core/sync/{sync2 => }/futex_freebsd.odin | 0 core/sync/{sync2 => }/futex_linux.odin | 0 core/sync/{sync2 => }/futex_openbsd.odin | 0 core/sync/{sync2 => }/futex_windows.odin | 0 core/sync/{sync2 => }/primitives.odin | 0 core/sync/{sync2 => }/primitives_atomic.odin | 0 core/sync/{sync2 => }/primitives_darwin.odin | 0 core/sync/{sync2 => }/primitives_freebsd.odin | 0 .../sync/{sync2 => }/primitives_internal.odin | 0 core/sync/{sync2 => }/primitives_linux.odin | 0 core/sync/{sync2 => }/primitives_openbsd.odin | 0 .../sync/{sync2 => }/primitives_pthreads.odin | 0 core/sync/{sync2 => }/primitives_windows.odin | 0 core/sync/{sync2 => }/sema_internal.odin | 0 core/sync/sync.odin | 123 --- core/sync/sync2/atomic.odin | 79 -- core/sync/sync_darwin.odin | 54 -- core/sync/sync_freebsd.odin | 40 - core/sync/sync_linux.odin | 36 - core/sync/sync_openbsd.odin | 36 - core/sync/sync_unix.odin | 248 ----- core/sync/{sync2 => }/sync_util.odin | 0 core/sync/sync_windows.odin | 180 ---- core/sync/wait_group.odin | 58 -- core/thread/thread_pool.odin | 17 +- core/thread/thread_unix.odin | 2 +- core/thread/thread_windows.odin | 2 +- examples/all/all_main.odin | 2 - 37 files changed, 79 insertions(+), 2047 deletions(-) delete mode 100644 core/sync/barrier.odin delete mode 100644 core/sync/channel.odin delete mode 100644 core/sync/channel_unix.odin delete mode 100644 core/sync/channel_windows.odin rename core/sync/{sync2 => }/extended.odin (100%) rename core/sync/{sync2 => }/futex_darwin.odin (100%) rename core/sync/{sync2 => }/futex_freebsd.odin (100%) rename core/sync/{sync2 => }/futex_linux.odin (100%) rename core/sync/{sync2 => }/futex_openbsd.odin (100%) rename core/sync/{sync2 => }/futex_windows.odin (100%) rename core/sync/{sync2 => }/primitives.odin (100%) rename core/sync/{sync2 => }/primitives_atomic.odin (100%) rename core/sync/{sync2 => }/primitives_darwin.odin (100%) rename core/sync/{sync2 => }/primitives_freebsd.odin (100%) rename core/sync/{sync2 => }/primitives_internal.odin (100%) rename core/sync/{sync2 => }/primitives_linux.odin (100%) rename core/sync/{sync2 => }/primitives_openbsd.odin (100%) rename core/sync/{sync2 => }/primitives_pthreads.odin (100%) rename core/sync/{sync2 => }/primitives_windows.odin (100%) rename core/sync/{sync2 => }/sema_internal.odin (100%) delete mode 100644 core/sync/sync.odin delete mode 100644 core/sync/sync2/atomic.odin delete mode 100644 core/sync/sync_darwin.odin delete mode 100644 core/sync/sync_freebsd.odin delete mode 100644 core/sync/sync_linux.odin delete mode 100644 core/sync/sync_openbsd.odin delete mode 100644 core/sync/sync_unix.odin rename core/sync/{sync2 => }/sync_util.odin (100%) delete mode 100644 core/sync/sync_windows.odin delete mode 100644 core/sync/wait_group.odin diff --git a/core/mem/virtual/virtual_platform.odin b/core/mem/virtual/virtual_platform.odin index d707bc427..367346f63 100644 --- a/core/mem/virtual/virtual_platform.odin +++ b/core/mem/virtual/virtual_platform.odin @@ -1,7 +1,7 @@ //+private package mem_virtual -import sync "core:sync/sync2" +import "core:sync" Platform_Memory_Block :: struct { block: Memory_Block, diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index 028951fe3..7fc7a4ac0 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -1,6 +1,6 @@ package os2 -import sync "core:sync/sync2" +import "core:sync" import "core:time" import "core:runtime" diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index 21dcea178..fe19f17c8 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -1,168 +1,79 @@ -package sync +package sync2 import "core:intrinsics" -Ordering :: enum { - Relaxed, // Monotonic - Release, - Acquire, - Acquire_Release, - Sequentially_Consistent, -} +cpu_relax :: intrinsics.cpu_relax -strongest_failure_ordering_table := [Ordering]Ordering{ - .Relaxed = .Relaxed, - .Release = .Relaxed, - .Acquire = .Acquire, - .Acquire_Release = .Acquire, - .Sequentially_Consistent = .Sequentially_Consistent, -} +atomic_fence :: intrinsics.atomic_fence +atomic_fence_acquire :: intrinsics.atomic_fence_acq +atomic_fence_release :: intrinsics.atomic_fence_rel +atomic_fence_acqrel :: intrinsics.atomic_fence_acqrel -strongest_failure_ordering :: #force_inline proc(order: Ordering) -> Ordering { - return strongest_failure_ordering_table[order] -} +atomic_store :: intrinsics.atomic_store +atomic_store_release :: intrinsics.atomic_store_rel +atomic_store_relaxed :: intrinsics.atomic_store_relaxed +atomic_store_unordered :: intrinsics.atomic_store_unordered -fence :: #force_inline proc($order: Ordering) { - when order == .Relaxed { #panic("there is no such thing as a relaxed fence") } - else when order == .Release { intrinsics.atomic_fence_rel() } - else when order == .Acquire { intrinsics.atomic_fence_acq() } - else when order == .Acquire_Release { intrinsics.atomic_fence_acqrel() } - else when order == .Sequentially_Consistent { intrinsics.atomic_fence() } - else { #panic("unknown order") } -} +atomic_load :: intrinsics.atomic_load +atomic_load_acquire :: intrinsics.atomic_load_acq +atomic_load_relaxed :: intrinsics.atomic_load_relaxed +atomic_load_unordered :: intrinsics.atomic_load_unordered +atomic_add :: intrinsics.atomic_add +atomic_add_acquire :: intrinsics.atomic_add_acq +atomic_add_release :: intrinsics.atomic_add_rel +atomic_add_acqrel :: intrinsics.atomic_add_acqrel +atomic_add_relaxed :: intrinsics.atomic_add_relaxed +atomic_sub :: intrinsics.atomic_sub +atomic_sub_acquire :: intrinsics.atomic_sub_acq +atomic_sub_release :: intrinsics.atomic_sub_rel +atomic_sub_acqrel :: intrinsics.atomic_sub_acqrel +atomic_sub_relaxed :: intrinsics.atomic_sub_relaxed +atomic_and :: intrinsics.atomic_and +atomic_and_acquire :: intrinsics.atomic_and_acq +atomic_and_release :: intrinsics.atomic_and_rel +atomic_and_acqrel :: intrinsics.atomic_and_acqrel +atomic_and_relaxed :: intrinsics.atomic_and_relaxed +atomic_nand :: intrinsics.atomic_nand +atomic_nand_acquire :: intrinsics.atomic_nand_acq +atomic_nand_release :: intrinsics.atomic_nand_rel +atomic_nand_acqrel :: intrinsics.atomic_nand_acqrel +atomic_nand_relaxed :: intrinsics.atomic_nand_relaxed +atomic_or :: intrinsics.atomic_or +atomic_or_acquire :: intrinsics.atomic_or_acq +atomic_or_release :: intrinsics.atomic_or_rel +atomic_or_acqrel :: intrinsics.atomic_or_acqrel +atomic_or_relaxed :: intrinsics.atomic_or_relaxed +atomic_xor :: intrinsics.atomic_xor +atomic_xor_acquire :: intrinsics.atomic_xor_acq +atomic_xor_release :: intrinsics.atomic_xor_rel +atomic_xor_acqrel :: intrinsics.atomic_xor_acqrel +atomic_xor_relaxed :: intrinsics.atomic_xor_relaxed -atomic_store :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) { - when order == .Relaxed { intrinsics.atomic_store_relaxed(dst, val) } - else when order == .Release { intrinsics.atomic_store_rel(dst, val) } - else when order == .Sequentially_Consistent { intrinsics.atomic_store(dst, val) } - else when order == .Acquire { #panic("there is not such thing as an acquire store") } - else when order == .Acquire_Release { #panic("there is not such thing as an acquire/release store") } - else { #panic("unknown order") } -} +atomic_exchange :: intrinsics.atomic_xchg +atomic_exchange_acquire :: intrinsics.atomic_xchg_acq +atomic_exchange_release :: intrinsics.atomic_xchg_rel +atomic_exchange_acqrel :: intrinsics.atomic_xchg_acqrel +atomic_exchange_relaxed :: intrinsics.atomic_xchg_relaxed -atomic_load :: #force_inline proc(dst: ^$T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_load_relaxed(dst) } - else when order == .Acquire { return intrinsics.atomic_load_acq(dst) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_load(dst) } - else when order == .Release { #panic("there is no such thing as a release load") } - else when order == .Acquire_Release { #panic("there is no such thing as an acquire/release load") } - else { #panic("unknown order") } -} - -atomic_swap :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_xchg_relaxed(dst, val) } - else when order == .Release { return intrinsics.atomic_xchg_rel(dst, val) } - else when order == .Acquire { return intrinsics.atomic_xchg_acq(dst, val) } - else when order == .Acquire_Release { return intrinsics.atomic_xchg_acqrel(dst, val) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_xchg(dst, val) } - else { #panic("unknown order") } -} - -atomic_compare_exchange :: #force_inline proc(dst: ^$T, old, new: T, $success, $failure: Ordering) -> (val: T, ok: bool) { - when failure == .Relaxed { - when success == .Relaxed { return intrinsics.atomic_cxchg_relaxed(dst, old, new) } - else when success == .Acquire { return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new) } - else when success == .Acquire_Release { return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new) } - else when success == .Sequentially_Consistent { return intrinsics.atomic_cxchg_failrelaxed(dst, old, new) } - else when success == .Release { return intrinsics.atomic_cxchg_rel(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else when failure == .Acquire { - when success == .Release { return intrinsics.atomic_cxchg_acqrel(dst, old, new) } - else when success == .Acquire { return intrinsics.atomic_cxchg_acq(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else when failure == .Sequentially_Consistent { - when success == .Sequentially_Consistent { return intrinsics.atomic_cxchg(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else when failure == .Acquire_Release { - #panic("there is not such thing as an acquire/release failure ordering") - } else when failure == .Release { - when success == .Acquire { return instrinsics.atomic_cxchg_failacq(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else { - return T{}, false - } - -} - -atomic_compare_exchange_weak :: #force_inline proc(dst: ^$T, old, new: T, $success, $failure: Ordering) -> (val: T, ok: bool) { - when failure == .Relaxed { - when success == .Relaxed { return intrinsics.atomic_cxchgweak_relaxed(dst, old, new) } - else when success == .Acquire { return intrinsics.atomic_cxchgweak_acq_failrelaxed(dst, old, new) } - else when success == .Acquire_Release { return intrinsics.atomic_cxchgweak_acqrel_failrelaxed(dst, old, new) } - else when success == .Sequentially_Consistent { return intrinsics.atomic_cxchgweak_failrelaxed(dst, old, new) } - else when success == .Release { return intrinsics.atomic_cxchgweak_rel(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else when failure == .Acquire { - when success == .Release { return intrinsics.atomic_cxchgweak_acqrel(dst, old, new) } - else when success == .Acquire { return intrinsics.atomic_cxchgweak_acq(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else when failure == .Sequentially_Consistent { - when success == .Sequentially_Consistent { return intrinsics.atomic_cxchgweak(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else when failure == .Acquire_Release { - #panic("there is not such thing as an acquire/release failure ordering") - } else when failure == .Release { - when success == .Acquire { return intrinsics.atomic_cxchgweak_failacq(dst, old, new) } - else { #panic("an unknown ordering combination") } - } else { - return T{}, false - } - -} - - -atomic_add :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_add_relaxed(dst, val) } - else when order == .Release { return intrinsics.atomic_add_rel(dst, val) } - else when order == .Acquire { return intrinsics.atomic_add_acq(dst, val) } - else when order == .Acquire_Release { return intrinsics.atomic_add_acqrel(dst, val) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_add(dst, val) } - else { #panic("unknown order") } -} - -atomic_sub :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_sub_relaxed(dst, val) } - else when order == .Release { return intrinsics.atomic_sub_rel(dst, val) } - else when order == .Acquire { return intrinsics.atomic_sub_acq(dst, val) } - else when order == .Acquire_Release { return intrinsics.atomic_sub_acqrel(dst, val) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_sub(dst, val) } - else { #panic("unknown order") } -} - -atomic_and :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_and_relaxed(dst, val) } - else when order == .Release { return intrinsics.atomic_and_rel(dst, val) } - else when order == .Acquire { return intrinsics.atomic_and_acq(dst, val) } - else when order == .Acquire_Release { return intrinsics.atomic_and_acqrel(dst, val) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_and(dst, val) } - else { #panic("unknown order") } -} - -atomic_nand :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_nand_relaxed(dst, val) } - else when order == .Release { return intrinsics.atomic_nand_rel(dst, val) } - else when order == .Acquire { return intrinsics.atomic_nand_acq(dst, val) } - else when order == .Acquire_Release { return intrinsics.atomic_nand_acqrel(dst, val) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_nand(dst, val) } - else { #panic("unknown order") } -} - -atomic_or :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_or_relaxed(dst, val) } - else when order == .Release { return intrinsics.atomic_or_rel(dst, val) } - else when order == .Acquire { return intrinsics.atomic_or_acq(dst, val) } - else when order == .Acquire_Release { return intrinsics.atomic_or_acqrel(dst, val) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_or(dst, val) } - else { #panic("unknown order") } -} - -atomic_xor :: #force_inline proc(dst: ^$T, val: T, $order: Ordering) -> T { - when order == .Relaxed { return intrinsics.atomic_xor_relaxed(dst, val) } - else when order == .Release { return intrinsics.atomic_xor_rel(dst, val) } - else when order == .Acquire { return intrinsics.atomic_xor_acq(dst, val) } - else when order == .Acquire_Release { return intrinsics.atomic_xor_acqrel(dst, val) } - else when order == .Sequentially_Consistent { return intrinsics.atomic_xor(dst, val) } - else { #panic("unknown order") } -} +// Returns value and optional ok boolean +atomic_compare_exchange_strong :: intrinsics.atomic_cxchg +atomic_compare_exchange_strong_acquire :: intrinsics.atomic_cxchg_acq +atomic_compare_exchange_strong_release :: intrinsics.atomic_cxchg_rel +atomic_compare_exchange_strong_acqrel :: intrinsics.atomic_cxchg_acqrel +atomic_compare_exchange_strong_relaxed :: intrinsics.atomic_cxchg_relaxed +atomic_compare_exchange_strong_failrelaxed :: intrinsics.atomic_cxchg_failrelaxed +atomic_compare_exchange_strong_failacquire :: intrinsics.atomic_cxchg_failacq +atomic_compare_exchange_strong_acquire_failrelaxed :: intrinsics.atomic_cxchg_acq_failrelaxed +atomic_compare_exchange_strong_acqrel_failrelaxed :: intrinsics.atomic_cxchg_acqrel_failrelaxed +// Returns value and optional ok boolean +atomic_compare_exchange_weak :: intrinsics.atomic_cxchgweak +atomic_compare_exchange_weak_acquire :: intrinsics.atomic_cxchgweak_acq +atomic_compare_exchange_weak_release :: intrinsics.atomic_cxchgweak_rel +atomic_compare_exchange_weak_acqrel :: intrinsics.atomic_cxchgweak_acqrel +atomic_compare_exchange_weak_relaxed :: intrinsics.atomic_cxchgweak_relaxed +atomic_compare_exchange_weak_failrelaxed :: intrinsics.atomic_cxchgweak_failrelaxed +atomic_compare_exchange_weak_failacquire :: intrinsics.atomic_cxchgweak_failacq +atomic_compare_exchange_weak_acquire_failrelaxed :: intrinsics.atomic_cxchgweak_acq_failrelaxed +atomic_compare_exchange_weak_acqrel_failrelaxed :: intrinsics.atomic_cxchgweak_acqrel_failrelaxed diff --git a/core/sync/barrier.odin b/core/sync/barrier.odin deleted file mode 100644 index 13c870a3b..000000000 --- a/core/sync/barrier.odin +++ /dev/null @@ -1,80 +0,0 @@ -package sync - - -/* -A barrier enabling multiple threads to synchronize the beginning of some computation -Example: - - package example - - import "core:fmt" - import "core:sync" - import "core:thread" - - barrier := &sync.Barrier{}; - - main :: proc() { - fmt.println("Start"); - - THREAD_COUNT :: 4; - threads: [THREAD_COUNT]^thread.Thread; - - sync.barrier_init(barrier, THREAD_COUNT); - defer sync.barrier_destroy(barrier); - - - for _, i in threads { - threads[i] = thread.create_and_start(proc(t: ^thread.Thread) { - // Same messages will be printed together but without any interleaving - fmt.println("Getting ready!"); - sync.barrier_wait(barrier); - fmt.println("Off their marks they go!"); - }); - } - - for t in threads { - thread.destroy(t); // join and free thread - } - fmt.println("Finished"); - } -*/ -Barrier :: struct { - mutex: Blocking_Mutex, - cond: Condition, - index: int, - generation_id: int, - thread_count: int, -} - -barrier_init :: proc(b: ^Barrier, thread_count: int) { - blocking_mutex_init(&b.mutex) - condition_init(&b.cond, &b.mutex) - b.index = 0 - b.generation_id = 0 - b.thread_count = thread_count -} - -barrier_destroy :: proc(b: ^Barrier) { - blocking_mutex_destroy(&b.mutex) - condition_destroy(&b.cond) -} - -// Block the current thread until all threads have rendezvoused -// Barrier can be reused after all threads rendezvoused once, and can be used continuously -barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) { - blocking_mutex_lock(&b.mutex) - defer blocking_mutex_unlock(&b.mutex) - local_gen := b.generation_id - b.index += 1 - if b.index < b.thread_count { - for local_gen == b.generation_id && b.index < b.thread_count { - condition_wait_for(&b.cond) - } - return false - } - - b.index = 0 - b.generation_id += 1 - condition_broadcast(&b.cond) - return true -} diff --git a/core/sync/channel.odin b/core/sync/channel.odin deleted file mode 100644 index 82b9504f4..000000000 --- a/core/sync/channel.odin +++ /dev/null @@ -1,889 +0,0 @@ -package sync - -import "core:mem" -import "core:time" -import "core:intrinsics" -import "core:math/rand" - -_, _ :: time, rand - -Channel_Direction :: enum i8 { - Both = 0, - Send = +1, - Recv = -1, -} - -Channel :: struct($T: typeid, $Direction := Channel_Direction.Both) { - using _internal: ^Raw_Channel, -} - -channel_init :: proc(ch: ^$C/Channel($T, $D), cap := 0, allocator := context.allocator) { - context.allocator = allocator - ch._internal = raw_channel_create(size_of(T), align_of(T), cap) - return -} - -channel_make :: proc($T: typeid, cap := 0, allocator := context.allocator) -> (ch: Channel(T, .Both)) { - context.allocator = allocator - ch._internal = raw_channel_create(size_of(T), align_of(T), cap) - return -} - -channel_make_send :: proc($T: typeid, cap := 0, allocator := context.allocator) -> (ch: Channel(T, .Send)) { - context.allocator = allocator - ch._internal = raw_channel_create(size_of(T), align_of(T), cap) - return -} -channel_make_recv :: proc($T: typeid, cap := 0, allocator := context.allocator) -> (ch: Channel(T, .Recv)) { - context.allocator = allocator - ch._internal = raw_channel_create(size_of(T), align_of(T), cap) - return -} - -channel_destroy :: proc(ch: $C/Channel($T, $D)) { - raw_channel_destroy(ch._internal) -} - -channel_as_send :: proc(ch: $C/Channel($T, .Both)) -> (res: Channel(T, .Send)) { - res._internal = ch._internal - return -} - -channel_as_recv :: proc(ch: $C/Channel($T, .Both)) -> (res: Channel(T, .Recv)) { - res._internal = ch._internal - return -} - - -channel_len :: proc(ch: $C/Channel($T, $D)) -> int { - return ch._internal.len if ch._internal != nil else 0 -} -channel_cap :: proc(ch: $C/Channel($T, $D)) -> int { - return ch._internal.cap if ch._internal != nil else 0 -} - - -channel_send :: proc(ch: $C/Channel($T, $D), msg: T, loc := #caller_location) where D >= .Both { - msg := msg - _ = raw_channel_send_impl(ch._internal, &msg, /*block*/true, loc) -} -channel_try_send :: proc(ch: $C/Channel($T, $D), msg: T, loc := #caller_location) -> bool where D >= .Both { - msg := msg - return raw_channel_send_impl(ch._internal, &msg, /*block*/false, loc) -} - -channel_recv :: proc(ch: $C/Channel($T, $D), loc := #caller_location) -> (msg: T) where D <= .Both { - c := ch._internal - if c == nil { - panic(message="cannot recv message; channel is nil", loc=loc) - } - mutex_lock(&c.mutex) - raw_channel_recv_impl(c, &msg, loc) - mutex_unlock(&c.mutex) - return -} -channel_try_recv :: proc(ch: $C/Channel($T, $D), loc := #caller_location) -> (msg: T, ok: bool) where D <= .Both { - c := ch._internal - if c != nil && mutex_try_lock(&c.mutex) { - if c.len > 0 { - raw_channel_recv_impl(c, &msg, loc) - ok = true - } - mutex_unlock(&c.mutex) - } - return -} -channel_try_recv_ptr :: proc(ch: $C/Channel($T, $D), msg: ^T, loc := #caller_location) -> (ok: bool) where D <= .Both { - res: T - res, ok = channel_try_recv(ch, loc) - if ok && msg != nil { - msg^ = res - } - return -} - - -channel_is_nil :: proc(ch: $C/Channel($T, $D)) -> bool { - return ch._internal == nil -} -channel_is_open :: proc(ch: $C/Channel($T, $D)) -> bool { - c := ch._internal - return c != nil && !c.closed -} - - -channel_eq :: proc(a, b: $C/Channel($T, $D)) -> bool { - return a._internal == b._internal -} -channel_ne :: proc(a, b: $C/Channel($T, $D)) -> bool { - return a._internal != b._internal -} - - -channel_can_send :: proc(ch: $C/Channel($T, $D)) -> (ok: bool) where D >= .Both { - return raw_channel_can_send(ch._internal) -} -channel_can_recv :: proc(ch: $C/Channel($T, $D)) -> (ok: bool) where D <= .Both { - return raw_channel_can_recv(ch._internal) -} - - -channel_peek :: proc(ch: $C/Channel($T, $D)) -> int { - c := ch._internal - if c == nil { - return -1 - } - if intrinsics.atomic_load(&c.closed) { - return -1 - } - return intrinsics.atomic_load(&c.len) -} - - -channel_close :: proc(ch: $C/Channel($T, $D), loc := #caller_location) { - raw_channel_close(ch._internal, loc) -} - - -channel_iterator :: proc(ch: $C/Channel($T, $D)) -> (msg: T, ok: bool) where D <= .Both { - c := ch._internal - if c == nil { - return - } - - if !c.closed || c.len > 0 { - msg, ok = channel_recv(ch), true - } - return -} -channel_drain :: proc(ch: $C/Channel($T, $D)) where D >= .Both { - raw_channel_drain(ch._internal) -} - - -channel_move :: proc(dst: $C1/Channel($T, $D1) src: $C2/Channel(T, $D2)) where D1 <= .Both, D2 >= .Both { - for msg in channel_iterator(src) { - channel_send(dst, msg) - } -} - - -Raw_Channel_Wait_Queue :: struct { - next: ^Raw_Channel_Wait_Queue, - state: ^uintptr, -} - - -Raw_Channel :: struct { - closed: bool, - ready: bool, // ready to recv - data_offset: u16, // data is stored at the end of this data structure - elem_size: u32, - len, cap: int, - read, write: int, - mutex: Mutex, - cond: Condition, - allocator: mem.Allocator, - - sendq: ^Raw_Channel_Wait_Queue, - recvq: ^Raw_Channel_Wait_Queue, -} - -raw_channel_wait_queue_insert :: proc(head: ^^Raw_Channel_Wait_Queue, val: ^Raw_Channel_Wait_Queue) { - val.next = head^ - head^ = val -} -raw_channel_wait_queue_remove :: proc(head: ^^Raw_Channel_Wait_Queue, val: ^Raw_Channel_Wait_Queue) { - p := head - for p^ != nil && p^ != val { - p = &p^.next - } - if p != nil { - p^ = p^.next - } -} - - -raw_channel_create :: proc(elem_size, elem_align: int, cap := 0) -> ^Raw_Channel { - assert(int(u32(elem_size)) == elem_size) - - s := size_of(Raw_Channel) - s = mem.align_forward_int(s, elem_align) - data_offset := uintptr(s) - s += elem_size * max(cap, 1) - - a := max(elem_align, align_of(Raw_Channel)) - - c := (^Raw_Channel)(mem.alloc(s, a)) - if c == nil { - return nil - } - - c.data_offset = u16(data_offset) - c.elem_size = u32(elem_size) - c.len, c.cap = 0, max(cap, 0) - c.read, c.write = 0, 0 - mutex_init(&c.mutex) - condition_init(&c.cond, &c.mutex) - c.allocator = context.allocator - c.closed = false - - return c -} - - -raw_channel_destroy :: proc(c: ^Raw_Channel) { - if c == nil { - return - } - context.allocator = c.allocator - intrinsics.atomic_store(&c.closed, true) - - condition_destroy(&c.cond) - mutex_destroy(&c.mutex) - free(c) -} - -raw_channel_close :: proc(c: ^Raw_Channel, loc := #caller_location) { - if c == nil { - panic(message="cannot close nil channel", loc=loc) - } - mutex_lock(&c.mutex) - defer mutex_unlock(&c.mutex) - intrinsics.atomic_store(&c.closed, true) - - // Release readers and writers - raw_channel_wait_queue_broadcast(c.recvq) - raw_channel_wait_queue_broadcast(c.sendq) - condition_broadcast(&c.cond) -} - - - -raw_channel_send_impl :: proc(c: ^Raw_Channel, msg: rawptr, block: bool, loc := #caller_location) -> bool { - send :: proc(c: ^Raw_Channel, src: rawptr) { - data := uintptr(c) + uintptr(c.data_offset) - dst := data + uintptr(c.write * int(c.elem_size)) - mem.copy(rawptr(dst), src, int(c.elem_size)) - c.len += 1 - c.write = (c.write + 1) % max(c.cap, 1) - } - - switch { - case c == nil: - panic(message="cannot send message; channel is nil", loc=loc) - case c.closed: - panic(message="cannot send message; channel is closed", loc=loc) - } - - mutex_lock(&c.mutex) - defer mutex_unlock(&c.mutex) - - if c.cap > 0 { - if !block && c.len >= c.cap { - return false - } - - for c.len >= c.cap { - condition_wait_for(&c.cond) - } - } else if c.len > 0 { // TODO(bill): determine correct behaviour - if !block { - return false - } - condition_wait_for(&c.cond) - } else if c.len == 0 && !block { - return false - } - - send(c, msg) - condition_signal(&c.cond) - raw_channel_wait_queue_signal(c.recvq) - - return true -} - -raw_channel_recv_impl :: proc(c: ^Raw_Channel, res: rawptr, loc := #caller_location) { - recv :: proc(c: ^Raw_Channel, dst: rawptr, loc := #caller_location) { - if c.len < 1 { - panic(message="cannot recv message; channel is empty", loc=loc) - } - c.len -= 1 - - data := uintptr(c) + uintptr(c.data_offset) - src := data + uintptr(c.read * int(c.elem_size)) - mem.copy(dst, rawptr(src), int(c.elem_size)) - c.read = (c.read + 1) % max(c.cap, 1) - } - - if c == nil { - panic(message="cannot recv message; channel is nil", loc=loc) - } - intrinsics.atomic_store(&c.ready, true) - for c.len < 1 { - raw_channel_wait_queue_signal(c.sendq) - condition_wait_for(&c.cond) - } - intrinsics.atomic_store(&c.ready, false) - recv(c, res, loc) - if c.cap > 0 { - if c.len == c.cap - 1 { - // NOTE(bill): Only signal on the last one - condition_signal(&c.cond) - } - } else { - condition_signal(&c.cond) - } -} - - -raw_channel_can_send :: proc(c: ^Raw_Channel) -> (ok: bool) { - if c == nil { - return false - } - mutex_lock(&c.mutex) - switch { - case c.closed: - ok = false - case c.cap > 0: - ok = c.ready && c.len < c.cap - case: - ok = c.ready && c.len == 0 - } - mutex_unlock(&c.mutex) - return -} -raw_channel_can_recv :: proc(c: ^Raw_Channel) -> (ok: bool) { - if c == nil { - return false - } - mutex_lock(&c.mutex) - ok = c.len > 0 - mutex_unlock(&c.mutex) - return -} - - -raw_channel_drain :: proc(c: ^Raw_Channel) { - if c == nil { - return - } - mutex_lock(&c.mutex) - c.len = 0 - c.read = 0 - c.write = 0 - mutex_unlock(&c.mutex) -} - - - -MAX_SELECT_CHANNELS :: 64 -SELECT_MAX_TIMEOUT :: max(time.Duration) - -Select_Command :: enum { - Recv, - Send, -} - -Select_Channel :: struct { - channel: ^Raw_Channel, - command: Select_Command, -} - - - -select :: proc(channels: ..Select_Channel) -> (index: int) { - return select_timeout(SELECT_MAX_TIMEOUT, ..channels) -} -select_timeout :: proc(timeout: time.Duration, channels: ..Select_Channel) -> (index: int) { - switch len(channels) { - case 0: - panic("sync: select with no channels") - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - - backing: [MAX_SELECT_CHANNELS]int - queues: [MAX_SELECT_CHANNELS]Raw_Channel_Wait_Queue - candidates := backing[:] - cap := len(channels) - candidates = candidates[:cap] - - count := u32(0) - for c, i in channels { - if c.channel == nil { - continue - } - switch c.command { - case .Recv: - if raw_channel_can_recv(c.channel) { - candidates[count] = i - count += 1 - } - case .Send: - if raw_channel_can_send(c.channel) { - candidates[count] = i - count += 1 - } - } - } - - if count == 0 { - wait_state: uintptr = 0 - for _, i in channels { - q := &queues[i] - q.state = &wait_state - } - - for c, i in channels { - if c.channel == nil { - continue - } - q := &queues[i] - switch c.command { - case .Recv: raw_channel_wait_queue_insert(&c.channel.recvq, q) - case .Send: raw_channel_wait_queue_insert(&c.channel.sendq, q) - } - } - raw_channel_wait_queue_wait_on(&wait_state, timeout) - for c, i in channels { - if c.channel == nil { - continue - } - q := &queues[i] - switch c.command { - case .Recv: raw_channel_wait_queue_remove(&c.channel.recvq, q) - case .Send: raw_channel_wait_queue_remove(&c.channel.sendq, q) - } - } - - for c, i in channels { - switch c.command { - case .Recv: - if raw_channel_can_recv(c.channel) { - candidates[count] = i - count += 1 - } - case .Send: - if raw_channel_can_send(c.channel) { - candidates[count] = i - count += 1 - } - } - } - if count == 0 && timeout == SELECT_MAX_TIMEOUT { - index = -1 - return - } - - assert(count != 0) - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - return -} - -select_recv :: proc(channels: ..^Raw_Channel) -> (index: int) { - switch len(channels) { - case 0: - panic("sync: select with no channels") - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - - backing: [MAX_SELECT_CHANNELS]int - queues: [MAX_SELECT_CHANNELS]Raw_Channel_Wait_Queue - candidates := backing[:] - cap := len(channels) - candidates = candidates[:cap] - - count := u32(0) - for c, i in channels { - if raw_channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - state: uintptr - for c, i in channels { - q := &queues[i] - q.state = &state - raw_channel_wait_queue_insert(&c.recvq, q) - } - raw_channel_wait_queue_wait_on(&state, SELECT_MAX_TIMEOUT) - for c, i in channels { - q := &queues[i] - raw_channel_wait_queue_remove(&c.recvq, q) - } - - for c, i in channels { - if raw_channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - assert(count != 0) - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - return -} - -select_recv_msg :: proc(channels: ..$C/Channel($T, $D)) -> (msg: T, index: int) { - switch len(channels) { - case 0: - panic("sync: select with no channels") - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - - queues: [MAX_SELECT_CHANNELS]Raw_Channel_Wait_Queue - candidates: [MAX_SELECT_CHANNELS]int - - count := u32(0) - for c, i in channels { - if raw_channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - state: uintptr - for c, i in channels { - q := &queues[i] - q.state = &state - raw_channel_wait_queue_insert(&c.recvq, q) - } - raw_channel_wait_queue_wait_on(&state, SELECT_MAX_TIMEOUT) - for c, i in channels { - q := &queues[i] - raw_channel_wait_queue_remove(&c.recvq, q) - } - - for c, i in channels { - if raw_channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - assert(count != 0) - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - msg = channel_recv(channels[index]) - - return -} - -select_send_msg :: proc(msg: $T, channels: ..$C/Channel(T, $D)) -> (index: int) { - switch len(channels) { - case 0: - panic("sync: select with no channels") - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - - backing: [MAX_SELECT_CHANNELS]int - queues: [MAX_SELECT_CHANNELS]Raw_Channel_Wait_Queue - candidates := backing[:] - cap := len(channels) - candidates = candidates[:cap] - - count := u32(0) - for c, i in channels { - if raw_channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - state: uintptr - for c, i in channels { - q := &queues[i] - q.state = &state - raw_channel_wait_queue_insert(&c.recvq, q) - } - raw_channel_wait_queue_wait_on(&state, SELECT_MAX_TIMEOUT) - for c, i in channels { - q := &queues[i] - raw_channel_wait_queue_remove(&c.recvq, q) - } - - for c, i in channels { - if raw_channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - assert(count != 0) - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - - if msg != nil { - channel_send(channels[index], msg) - } - - return -} - -select_send :: proc(channels: ..^Raw_Channel) -> (index: int) { - switch len(channels) { - case 0: - panic("sync: select with no channels") - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - candidates: [MAX_SELECT_CHANNELS]int - queues: [MAX_SELECT_CHANNELS]Raw_Channel_Wait_Queue - - count := u32(0) - for c, i in channels { - if raw_channel_can_send(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - state: uintptr - for c, i in channels { - q := &queues[i] - q.state = &state - raw_channel_wait_queue_insert(&c.sendq, q) - } - raw_channel_wait_queue_wait_on(&state, SELECT_MAX_TIMEOUT) - for c, i in channels { - q := &queues[i] - raw_channel_wait_queue_remove(&c.sendq, q) - } - - for c, i in channels { - if raw_channel_can_send(c) { - candidates[count] = i - count += 1 - } - } - assert(count != 0) - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - return -} - -select_try :: proc(channels: ..Select_Channel) -> (index: int) { - switch len(channels) { - case 0: - panic("sync: select with no channels") - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - - backing: [MAX_SELECT_CHANNELS]int - candidates := backing[:] - cap := len(channels) - candidates = candidates[:cap] - - count := u32(0) - for c, i in channels { - switch c.command { - case .Recv: - if raw_channel_can_recv(c.channel) { - candidates[count] = i - count += 1 - } - case .Send: - if raw_channel_can_send(c.channel) { - candidates[count] = i - count += 1 - } - } - } - - if count == 0 { - index = -1 - return - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - return -} - - -select_try_recv :: proc(channels: ..^Raw_Channel) -> (index: int) { - switch len(channels) { - case 0: - index = -1 - return - case 1: - index = -1 - if raw_channel_can_recv(channels[0]) { - index = 0 - } - return - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - candidates: [MAX_SELECT_CHANNELS]int - - count := u32(0) - for c, i in channels { - if raw_channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - index = -1 - return - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - return -} - - -select_try_send :: proc(channels: ..^Raw_Channel) -> (index: int) #no_bounds_check { - switch len(channels) { - case 0: - return -1 - case 1: - if raw_channel_can_send(channels[0]) { - return 0 - } - return -1 - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - candidates: [MAX_SELECT_CHANNELS]int - - count := u32(0) - for c, i in channels { - if raw_channel_can_send(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - index = -1 - return - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - return -} - -select_try_recv_msg :: proc(channels: ..$C/Channel($T, $D)) -> (msg: T, index: int) { - switch len(channels) { - case 0: - index = -1 - return - case 1: - ok: bool - if msg, ok = channel_try_recv(channels[0]); ok { - index = 0 - } - return - } - - assert(len(channels) <= MAX_SELECT_CHANNELS) - candidates: [MAX_SELECT_CHANNELS]int - - count := u32(0) - for c, i in channels { - if channel_can_recv(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - index = -1 - return - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - msg = channel_recv(channels[index]) - return -} - -select_try_send_msg :: proc(msg: $T, channels: ..$C/Channel(T, $D)) -> (index: int) { - index = -1 - switch len(channels) { - case 0: - return - case 1: - if channel_try_send(channels[0], msg) { - index = 0 - } - return - } - - - assert(len(channels) <= MAX_SELECT_CHANNELS) - candidates: [MAX_SELECT_CHANNELS]int - - count := u32(0) - for c, i in channels { - if raw_channel_can_send(c) { - candidates[count] = i - count += 1 - } - } - - if count == 0 { - index = -1 - return - } - - t := time.now() - r := rand.create(transmute(u64)t) - i := rand.uint32(&r) - - index = candidates[i % count] - channel_send(channels[index], msg) - return -} - diff --git a/core/sync/channel_unix.odin b/core/sync/channel_unix.odin deleted file mode 100644 index 47aa46004..000000000 --- a/core/sync/channel_unix.odin +++ /dev/null @@ -1,16 +0,0 @@ -// +build linux, darwin, freebsd, openbsd -package sync - -import "core:time" - -raw_channel_wait_queue_wait_on :: proc(state: ^uintptr, timeout: time.Duration) { - // stub -} - -raw_channel_wait_queue_signal :: proc(q: ^Raw_Channel_Wait_Queue) { - // stub -} - -raw_channel_wait_queue_broadcast :: proc(q: ^Raw_Channel_Wait_Queue) { - // stub -} diff --git a/core/sync/channel_windows.odin b/core/sync/channel_windows.odin deleted file mode 100644 index 5d469ffff..000000000 --- a/core/sync/channel_windows.odin +++ /dev/null @@ -1,33 +0,0 @@ -package sync - -import "core:intrinsics" -import win32 "core:sys/windows" -import "core:time" - -raw_channel_wait_queue_wait_on :: proc(state: ^uintptr, timeout: time.Duration) { - ms: win32.DWORD = win32.INFINITE - if max(time.Duration) != SELECT_MAX_TIMEOUT { - ms = win32.DWORD((max(time.duration_nanoseconds(timeout), 0) + 999999)/1000000) - } - - v := intrinsics.atomic_load(state) - for v == 0 { - win32.WaitOnAddress(state, &v, size_of(state^), ms) - v = intrinsics.atomic_load(state) - } - intrinsics.atomic_store(state, 0) -} - -raw_channel_wait_queue_signal :: proc(q: ^Raw_Channel_Wait_Queue) { - for x := q; x != nil; x = x.next { - intrinsics.atomic_add(x.state, 1) - win32.WakeByAddressSingle(x.state) - } -} - -raw_channel_wait_queue_broadcast :: proc(q: ^Raw_Channel_Wait_Queue) { - for x := q; x != nil; x = x.next { - intrinsics.atomic_add(x.state, 1) - win32.WakeByAddressAll(x.state) - } -} diff --git a/core/sync/sync2/extended.odin b/core/sync/extended.odin similarity index 100% rename from core/sync/sync2/extended.odin rename to core/sync/extended.odin diff --git a/core/sync/sync2/futex_darwin.odin b/core/sync/futex_darwin.odin similarity index 100% rename from core/sync/sync2/futex_darwin.odin rename to core/sync/futex_darwin.odin diff --git a/core/sync/sync2/futex_freebsd.odin b/core/sync/futex_freebsd.odin similarity index 100% rename from core/sync/sync2/futex_freebsd.odin rename to core/sync/futex_freebsd.odin diff --git a/core/sync/sync2/futex_linux.odin b/core/sync/futex_linux.odin similarity index 100% rename from core/sync/sync2/futex_linux.odin rename to core/sync/futex_linux.odin diff --git a/core/sync/sync2/futex_openbsd.odin b/core/sync/futex_openbsd.odin similarity index 100% rename from core/sync/sync2/futex_openbsd.odin rename to core/sync/futex_openbsd.odin diff --git a/core/sync/sync2/futex_windows.odin b/core/sync/futex_windows.odin similarity index 100% rename from core/sync/sync2/futex_windows.odin rename to core/sync/futex_windows.odin diff --git a/core/sync/sync2/primitives.odin b/core/sync/primitives.odin similarity index 100% rename from core/sync/sync2/primitives.odin rename to core/sync/primitives.odin diff --git a/core/sync/sync2/primitives_atomic.odin b/core/sync/primitives_atomic.odin similarity index 100% rename from core/sync/sync2/primitives_atomic.odin rename to core/sync/primitives_atomic.odin diff --git a/core/sync/sync2/primitives_darwin.odin b/core/sync/primitives_darwin.odin similarity index 100% rename from core/sync/sync2/primitives_darwin.odin rename to core/sync/primitives_darwin.odin diff --git a/core/sync/sync2/primitives_freebsd.odin b/core/sync/primitives_freebsd.odin similarity index 100% rename from core/sync/sync2/primitives_freebsd.odin rename to core/sync/primitives_freebsd.odin diff --git a/core/sync/sync2/primitives_internal.odin b/core/sync/primitives_internal.odin similarity index 100% rename from core/sync/sync2/primitives_internal.odin rename to core/sync/primitives_internal.odin diff --git a/core/sync/sync2/primitives_linux.odin b/core/sync/primitives_linux.odin similarity index 100% rename from core/sync/sync2/primitives_linux.odin rename to core/sync/primitives_linux.odin diff --git a/core/sync/sync2/primitives_openbsd.odin b/core/sync/primitives_openbsd.odin similarity index 100% rename from core/sync/sync2/primitives_openbsd.odin rename to core/sync/primitives_openbsd.odin diff --git a/core/sync/sync2/primitives_pthreads.odin b/core/sync/primitives_pthreads.odin similarity index 100% rename from core/sync/sync2/primitives_pthreads.odin rename to core/sync/primitives_pthreads.odin diff --git a/core/sync/sync2/primitives_windows.odin b/core/sync/primitives_windows.odin similarity index 100% rename from core/sync/sync2/primitives_windows.odin rename to core/sync/primitives_windows.odin diff --git a/core/sync/sync2/sema_internal.odin b/core/sync/sema_internal.odin similarity index 100% rename from core/sync/sync2/sema_internal.odin rename to core/sync/sema_internal.odin diff --git a/core/sync/sync.odin b/core/sync/sync.odin deleted file mode 100644 index 05c86a868..000000000 --- a/core/sync/sync.odin +++ /dev/null @@ -1,123 +0,0 @@ -package sync - -import "core:intrinsics" - -cpu_relax :: #force_inline proc "contextless" () { - intrinsics.cpu_relax() -} - -Condition_Mutex_Ptr :: union{^Mutex, ^Blocking_Mutex} - - -Ticket_Mutex :: struct { - ticket: u64, - serving: u64, -} - -ticket_mutex_init :: proc(m: ^Ticket_Mutex) { - atomic_store(&m.ticket, 0, .Relaxed) - atomic_store(&m.serving, 0, .Relaxed) -} - -ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) { - ticket := atomic_add(&m.ticket, 1, .Relaxed) - for ticket != atomic_load(&m.serving, .Acquire) { - intrinsics.cpu_relax() - } -} - -ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) { - atomic_add(&m.serving, 1, .Relaxed) -} - - -Benaphore :: struct { - counter: int, - sema: Semaphore, -} - -benaphore_init :: proc(b: ^Benaphore) { - intrinsics.atomic_store(&b.counter, 0) - semaphore_init(&b.sema) -} - -benaphore_destroy :: proc(b: ^Benaphore) { - semaphore_destroy(&b.sema) -} - -benaphore_lock :: proc(b: ^Benaphore) { - if intrinsics.atomic_add_acq(&b.counter, 1) > 1 { - semaphore_wait_for(&b.sema) - } -} - -benaphore_try_lock :: proc(b: ^Benaphore) -> bool { - v, _ := intrinsics.atomic_cxchg_acq(&b.counter, 1, 0) - return v == 0 -} - -benaphore_unlock :: proc(b: ^Benaphore) { - if intrinsics.atomic_sub_rel(&b.counter, 1) > 0 { - semaphore_post(&b.sema) - } -} - -Recursive_Benaphore :: struct { - counter: int, - owner: int, - recursion: int, - sema: Semaphore, -} - -recursive_benaphore_init :: proc(b: ^Recursive_Benaphore) { - intrinsics.atomic_store(&b.counter, 0) - semaphore_init(&b.sema) -} - -recursive_benaphore_destroy :: proc(b: ^Recursive_Benaphore) { - semaphore_destroy(&b.sema) -} - -recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) { - tid := current_thread_id() - if intrinsics.atomic_add_acq(&b.counter, 1) > 1 { - if tid != b.owner { - semaphore_wait_for(&b.sema) - } - } - // inside the lock - b.owner = tid - b.recursion += 1 -} - -recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool { - tid := current_thread_id() - if b.owner == tid { - intrinsics.atomic_add_acq(&b.counter, 1) - } else { - v, _ := intrinsics.atomic_cxchg_acq(&b.counter, 1, 0) - if v != 0 { - return false - } - // inside the lock - b.owner = tid - } - b.recursion += 1 - return true -} - -recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) { - tid := current_thread_id() - assert(tid == b.owner) - b.recursion -= 1 - recursion := b.recursion - if recursion == 0 { - b.owner = 0 - } - if intrinsics.atomic_sub_rel(&b.counter, 1) > 0 { - if recursion == 0 { - semaphore_post(&b.sema) - } - } - // outside the lock -} diff --git a/core/sync/sync2/atomic.odin b/core/sync/sync2/atomic.odin deleted file mode 100644 index fe19f17c8..000000000 --- a/core/sync/sync2/atomic.odin +++ /dev/null @@ -1,79 +0,0 @@ -package sync2 - -import "core:intrinsics" - -cpu_relax :: intrinsics.cpu_relax - -atomic_fence :: intrinsics.atomic_fence -atomic_fence_acquire :: intrinsics.atomic_fence_acq -atomic_fence_release :: intrinsics.atomic_fence_rel -atomic_fence_acqrel :: intrinsics.atomic_fence_acqrel - -atomic_store :: intrinsics.atomic_store -atomic_store_release :: intrinsics.atomic_store_rel -atomic_store_relaxed :: intrinsics.atomic_store_relaxed -atomic_store_unordered :: intrinsics.atomic_store_unordered - -atomic_load :: intrinsics.atomic_load -atomic_load_acquire :: intrinsics.atomic_load_acq -atomic_load_relaxed :: intrinsics.atomic_load_relaxed -atomic_load_unordered :: intrinsics.atomic_load_unordered - -atomic_add :: intrinsics.atomic_add -atomic_add_acquire :: intrinsics.atomic_add_acq -atomic_add_release :: intrinsics.atomic_add_rel -atomic_add_acqrel :: intrinsics.atomic_add_acqrel -atomic_add_relaxed :: intrinsics.atomic_add_relaxed -atomic_sub :: intrinsics.atomic_sub -atomic_sub_acquire :: intrinsics.atomic_sub_acq -atomic_sub_release :: intrinsics.atomic_sub_rel -atomic_sub_acqrel :: intrinsics.atomic_sub_acqrel -atomic_sub_relaxed :: intrinsics.atomic_sub_relaxed -atomic_and :: intrinsics.atomic_and -atomic_and_acquire :: intrinsics.atomic_and_acq -atomic_and_release :: intrinsics.atomic_and_rel -atomic_and_acqrel :: intrinsics.atomic_and_acqrel -atomic_and_relaxed :: intrinsics.atomic_and_relaxed -atomic_nand :: intrinsics.atomic_nand -atomic_nand_acquire :: intrinsics.atomic_nand_acq -atomic_nand_release :: intrinsics.atomic_nand_rel -atomic_nand_acqrel :: intrinsics.atomic_nand_acqrel -atomic_nand_relaxed :: intrinsics.atomic_nand_relaxed -atomic_or :: intrinsics.atomic_or -atomic_or_acquire :: intrinsics.atomic_or_acq -atomic_or_release :: intrinsics.atomic_or_rel -atomic_or_acqrel :: intrinsics.atomic_or_acqrel -atomic_or_relaxed :: intrinsics.atomic_or_relaxed -atomic_xor :: intrinsics.atomic_xor -atomic_xor_acquire :: intrinsics.atomic_xor_acq -atomic_xor_release :: intrinsics.atomic_xor_rel -atomic_xor_acqrel :: intrinsics.atomic_xor_acqrel -atomic_xor_relaxed :: intrinsics.atomic_xor_relaxed - -atomic_exchange :: intrinsics.atomic_xchg -atomic_exchange_acquire :: intrinsics.atomic_xchg_acq -atomic_exchange_release :: intrinsics.atomic_xchg_rel -atomic_exchange_acqrel :: intrinsics.atomic_xchg_acqrel -atomic_exchange_relaxed :: intrinsics.atomic_xchg_relaxed - -// Returns value and optional ok boolean -atomic_compare_exchange_strong :: intrinsics.atomic_cxchg -atomic_compare_exchange_strong_acquire :: intrinsics.atomic_cxchg_acq -atomic_compare_exchange_strong_release :: intrinsics.atomic_cxchg_rel -atomic_compare_exchange_strong_acqrel :: intrinsics.atomic_cxchg_acqrel -atomic_compare_exchange_strong_relaxed :: intrinsics.atomic_cxchg_relaxed -atomic_compare_exchange_strong_failrelaxed :: intrinsics.atomic_cxchg_failrelaxed -atomic_compare_exchange_strong_failacquire :: intrinsics.atomic_cxchg_failacq -atomic_compare_exchange_strong_acquire_failrelaxed :: intrinsics.atomic_cxchg_acq_failrelaxed -atomic_compare_exchange_strong_acqrel_failrelaxed :: intrinsics.atomic_cxchg_acqrel_failrelaxed - -// Returns value and optional ok boolean -atomic_compare_exchange_weak :: intrinsics.atomic_cxchgweak -atomic_compare_exchange_weak_acquire :: intrinsics.atomic_cxchgweak_acq -atomic_compare_exchange_weak_release :: intrinsics.atomic_cxchgweak_rel -atomic_compare_exchange_weak_acqrel :: intrinsics.atomic_cxchgweak_acqrel -atomic_compare_exchange_weak_relaxed :: intrinsics.atomic_cxchgweak_relaxed -atomic_compare_exchange_weak_failrelaxed :: intrinsics.atomic_cxchgweak_failrelaxed -atomic_compare_exchange_weak_failacquire :: intrinsics.atomic_cxchgweak_failacq -atomic_compare_exchange_weak_acquire_failrelaxed :: intrinsics.atomic_cxchgweak_acq_failrelaxed -atomic_compare_exchange_weak_acqrel_failrelaxed :: intrinsics.atomic_cxchgweak_acqrel_failrelaxed diff --git a/core/sync/sync_darwin.odin b/core/sync/sync_darwin.odin deleted file mode 100644 index f3bb4d5a3..000000000 --- a/core/sync/sync_darwin.odin +++ /dev/null @@ -1,54 +0,0 @@ -package sync - -import "core:sys/darwin" - -import "core:c" - -foreign import pthread "System.framework" - -current_thread_id :: proc "contextless" () -> int { - tid: u64 - // NOTE(Oskar): available from OSX 10.6 and iOS 3.2. - // For older versions there is `syscall(SYS_thread_selfid)`, but not really - // the same thing apparently. - foreign pthread { pthread_threadid_np :: proc "c" (rawptr, ^u64) -> c.int --- } - pthread_threadid_np(nil, &tid) - return int(tid) -} - - -// The Darwin docs say it best: -// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously. -// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens, -// but when there are none left, a thread must wait until another thread returns one. -Semaphore :: struct #align 16 { - handle: darwin.semaphore_t, -} -// TODO(tetra): Only marked with alignment because we cannot mark distinct integers with alignments. -// See core/sys/unix/pthread_linux.odin/pthread_t. - -semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { - ct := darwin.mach_task_self() - res := darwin.semaphore_create(ct, &s.handle, 0, c.int(initial_count)) - assert(res == 0) -} - -semaphore_destroy :: proc(s: ^Semaphore) { - ct := darwin.mach_task_self() - res := darwin.semaphore_destroy(ct, s.handle) - assert(res == 0) - s.handle = {} -} - -semaphore_post :: proc(s: ^Semaphore, count := 1) { - // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop. - for in 0.. int { - SYS_GETTID :: 186 - return int(intrinsics.syscall(SYS_GETTID)) -} - - -// The Darwin docs say it best: -// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously. -// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens, -// but when there are none left, a thread must wait until another thread returns one. -Semaphore :: struct #align 16 { - handle: unix.sem_t, -} - -semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { - assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0) -} - -semaphore_destroy :: proc(s: ^Semaphore) { - assert(unix.sem_destroy(&s.handle) == 0) - s.handle = {} -} - -semaphore_post :: proc(s: ^Semaphore, count := 1) { - // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop. - for in 0.. int { - return unix.sys_gettid() -} - - -// The Darwin docs say it best: -// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously. -// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens, -// but when there are none left, a thread must wait until another thread returns one. -Semaphore :: struct #align 16 { - handle: unix.sem_t, -} - -semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { - assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0) -} - -semaphore_destroy :: proc(s: ^Semaphore) { - assert(unix.sem_destroy(&s.handle) == 0) - s.handle = {} -} - -semaphore_post :: proc(s: ^Semaphore, count := 1) { - // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop. - for in 0.. int { - return os.current_thread_id() -} - -// The Darwin docs say it best: -// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously. -// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens, -// but when there are none left, a thread must wait until another thread returns one. -Semaphore :: struct #align 16 { - handle: unix.sem_t, -} - -semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { - assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0) -} - -semaphore_destroy :: proc(s: ^Semaphore) { - assert(unix.sem_destroy(&s.handle) == 0) - s.handle = {} -} - -semaphore_post :: proc(s: ^Semaphore, count := 1) { - // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop. - for in 0.. bool { - return unix.pthread_mutex_trylock(&m.handle) == 0 -} - -mutex_unlock :: proc(m: ^Mutex) { - assert(unix.pthread_mutex_unlock(&m.handle) == 0) -} - - -Blocking_Mutex :: struct { - handle: unix.pthread_mutex_t, -} - - -blocking_mutex_init :: proc(m: ^Blocking_Mutex) { - // NOTE(tetra, 2019-11-01): POSIX OOM if we cannot init the attrs or the mutex. - attrs: unix.pthread_mutexattr_t - assert(unix.pthread_mutexattr_init(&attrs) == 0) - defer unix.pthread_mutexattr_destroy(&attrs) // ignores destruction error - - assert(unix.pthread_mutex_init(&m.handle, &attrs) == 0) -} - -blocking_mutex_destroy :: proc(m: ^Blocking_Mutex) { - assert(unix.pthread_mutex_destroy(&m.handle) == 0) - m.handle = {} -} - -blocking_mutex_lock :: proc(m: ^Blocking_Mutex) { - assert(unix.pthread_mutex_lock(&m.handle) == 0) -} - -// Returns false if someone else holds the lock. -blocking_mutex_try_lock :: proc(m: ^Blocking_Mutex) -> bool { - return unix.pthread_mutex_trylock(&m.handle) == 0 -} - -blocking_mutex_unlock :: proc(m: ^Blocking_Mutex) { - assert(unix.pthread_mutex_unlock(&m.handle) == 0) -} - - - -// Blocks until signalled, and then lets past exactly -// one thread. -Condition :: struct { - handle: unix.pthread_cond_t, - mutex: Condition_Mutex_Ptr, - - // NOTE(tetra, 2019-11-11): Used to mimic the more sane behavior of Windows' AutoResetEvent. - // This means that you may signal the condition before anyone is waiting to cause the - // next thread that tries to wait to just pass by uninterrupted, without sleeping. - // Without this, signalling a condition will only wake up a thread which is already waiting, - // but not one that is about to wait, which can cause your program to become out of sync in - // ways that are hard to debug or fix. - flag: bool, // atomically mutated -} - -condition_init :: proc(c: ^Condition, mutex: Condition_Mutex_Ptr) -> bool { - // NOTE(tetra, 2019-11-01): POSIX OOM if we cannot init the attrs or the condition. - attrs: unix.pthread_condattr_t - if unix.pthread_condattr_init(&attrs) != 0 { - return false - } - defer unix.pthread_condattr_destroy(&attrs) // ignores destruction error - - c.flag = false - c.mutex = mutex - return unix.pthread_cond_init(&c.handle, &attrs) == 0 -} - -condition_destroy :: proc(c: ^Condition) { - assert(unix.pthread_cond_destroy(&c.handle) == 0) - c.handle = {} -} - -// Awaken exactly one thread who is waiting on the condition -condition_signal :: proc(c: ^Condition) -> bool { - switch m in c.mutex { - case ^Mutex: - mutex_lock(m) - defer mutex_unlock(m) - atomic_swap(&c.flag, true, .Sequentially_Consistent) - return unix.pthread_cond_signal(&c.handle) == 0 - case ^Blocking_Mutex: - blocking_mutex_lock(m) - defer blocking_mutex_unlock(m) - atomic_swap(&c.flag, true, .Sequentially_Consistent) - return unix.pthread_cond_signal(&c.handle) == 0 - } - return false -} - -// Awaken all threads who are waiting on the condition -condition_broadcast :: proc(c: ^Condition) -> bool { - return unix.pthread_cond_broadcast(&c.handle) == 0 -} - -// Wait for the condition to be signalled. -// Does not block if the condition has been signalled and no one -// has waited on it yet. -condition_wait_for :: proc(c: ^Condition) -> bool { - switch m in c.mutex { - case ^Mutex: - mutex_lock(m) - defer mutex_unlock(m) - // NOTE(tetra): If a thread comes by and steals the flag immediately after the signal occurs, - // the thread that gets signalled and wakes up, discovers that the flag was taken and goes - // back to sleep. - // Though this overall behavior is the most sane, there may be a better way to do this that means that - // the first thread to wait, gets the flag first. - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - for { - if unix.pthread_cond_wait(&c.handle, &m.handle) != 0 { - return false - } - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - } - return false - - case ^Blocking_Mutex: - blocking_mutex_lock(m) - defer blocking_mutex_unlock(m) - // NOTE(tetra): If a thread comes by and steals the flag immediately after the signal occurs, - // the thread that gets signalled and wakes up, discovers that the flag was taken and goes - // back to sleep. - // Though this overall behavior is the most sane, there may be a better way to do this that means that - // the first thread to wait, gets the flag first. - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - for { - if unix.pthread_cond_wait(&c.handle, &m.handle) != 0 { - return false - } - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - } - return false - } - return false -} - -// Wait for the condition to be signalled. -// Does not block if the condition has been signalled and no one -// has waited on it yet. -condition_wait_for_timeout :: proc(c: ^Condition, duration: time.Duration) -> bool { - switch m in c.mutex { - case ^Mutex: - mutex_lock(m) - defer mutex_unlock(m) - // NOTE(tetra): If a thread comes by and steals the flag immediately after the signal occurs, - // the thread that gets signalled and wakes up, discovers that the flag was taken and goes - // back to sleep. - // Though this overall behavior is the most sane, there may be a better way to do this that means that - // the first thread to wait, gets the flag first. - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - - ns := time.duration_nanoseconds(duration) - timeout: time.TimeSpec - timeout.tv_sec = ns / 1e9 - timeout.tv_nsec = ns % 1e9 - - for { - if unix.pthread_cond_timedwait(&c.handle, &m.handle, &timeout) != 0 { - return false - } - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - } - return false - - case ^Blocking_Mutex: - blocking_mutex_lock(m) - defer blocking_mutex_unlock(m) - // NOTE(tetra): If a thread comes by and steals the flag immediately after the signal occurs, - // the thread that gets signalled and wakes up, discovers that the flag was taken and goes - // back to sleep. - // Though this overall behavior is the most sane, there may be a better way to do this that means that - // the first thread to wait, gets the flag first. - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - - ns := time.duration_nanoseconds(duration) - - timeout: time.TimeSpec - timeout.tv_sec = ns / 1e9 - timeout.tv_nsec = ns % 1e9 - - for { - if unix.pthread_cond_timedwait(&c.handle, &m.handle, &timeout) != 0 { - return false - } - if atomic_swap(&c.flag, false, .Sequentially_Consistent) { - return true - } - } - return false - } - return false -} - - - -thread_yield :: proc() { - unix.sched_yield() -} diff --git a/core/sync/sync2/sync_util.odin b/core/sync/sync_util.odin similarity index 100% rename from core/sync/sync2/sync_util.odin rename to core/sync/sync_util.odin diff --git a/core/sync/sync_windows.odin b/core/sync/sync_windows.odin deleted file mode 100644 index 0a7cf71b2..000000000 --- a/core/sync/sync_windows.odin +++ /dev/null @@ -1,180 +0,0 @@ -// +build windows -package sync - -import win32 "core:sys/windows" -import "core:time" - -current_thread_id :: proc "contextless" () -> int { - return int(win32.GetCurrentThreadId()) -} - - -// When waited upon, blocks until the internal count is greater than zero, then subtracts one. -// Posting to the semaphore increases the count by one, or the provided amount. -Semaphore :: struct { - _handle: win32.HANDLE, -} - -semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { - s._handle = win32.CreateSemaphoreW(nil, i32(initial_count), 1<<31-1, nil) -} - -semaphore_destroy :: proc(s: ^Semaphore) { - win32.CloseHandle(s._handle) -} - -semaphore_post :: proc(s: ^Semaphore, count := 1) { - win32.ReleaseSemaphore(s._handle, i32(count), nil) -} - -semaphore_wait_for :: proc(s: ^Semaphore) { - // NOTE(tetra, 2019-10-30): wait_for_single_object decrements the count before it returns. - result := win32.WaitForSingleObject(s._handle, win32.INFINITE) - assert(result != win32.WAIT_FAILED) -} - - -Mutex :: struct { - _critical_section: win32.CRITICAL_SECTION, -} - - -mutex_init :: proc(m: ^Mutex, spin_count := 0) { - win32.InitializeCriticalSectionAndSpinCount(&m._critical_section, u32(spin_count)) -} - -mutex_destroy :: proc(m: ^Mutex) { - win32.DeleteCriticalSection(&m._critical_section) -} - -mutex_lock :: proc(m: ^Mutex) { - win32.EnterCriticalSection(&m._critical_section) -} - -mutex_try_lock :: proc(m: ^Mutex) -> bool { - return bool(win32.TryEnterCriticalSection(&m._critical_section)) -} - -mutex_unlock :: proc(m: ^Mutex) { - win32.LeaveCriticalSection(&m._critical_section) -} - -Blocking_Mutex :: struct { - _handle: win32.SRWLOCK, -} - - -blocking_mutex_init :: proc(m: ^Blocking_Mutex) { - win32.InitializeSRWLock(&m._handle) -} - -blocking_mutex_destroy :: proc(m: ^Blocking_Mutex) { - // -} - -blocking_mutex_lock :: proc(m: ^Blocking_Mutex) { - win32.AcquireSRWLockExclusive(&m._handle) -} - -blocking_mutex_try_lock :: proc(m: ^Blocking_Mutex) -> bool { - return bool(win32.TryAcquireSRWLockExclusive(&m._handle)) -} - -blocking_mutex_unlock :: proc(m: ^Blocking_Mutex) { - win32.ReleaseSRWLockExclusive(&m._handle) -} - - -// Blocks until signalled. -// When signalled, awakens exactly one waiting thread. -Condition :: struct { - _handle: win32.CONDITION_VARIABLE, - - mutex: Condition_Mutex_Ptr, -} - - -condition_init :: proc(c: ^Condition, mutex: Condition_Mutex_Ptr) -> bool { - assert(mutex != nil) - win32.InitializeConditionVariable(&c._handle) - c.mutex = mutex - return true -} - -condition_destroy :: proc(c: ^Condition) { - // -} - -condition_signal :: proc(c: ^Condition) -> bool { - if c._handle.ptr == nil { - return false - } - win32.WakeConditionVariable(&c._handle) - return true -} - -condition_broadcast :: proc(c: ^Condition) -> bool { - if c._handle.ptr == nil { - return false - } - win32.WakeAllConditionVariable(&c._handle) - return true -} - -condition_wait_for :: proc(c: ^Condition) -> bool { - switch m in &c.mutex { - case ^Mutex: - return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, win32.INFINITE) - case ^Blocking_Mutex: - return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, win32.INFINITE, 0) - } - return false -} -condition_wait_for_timeout :: proc(c: ^Condition, duration: time.Duration) -> bool { - ms := win32.DWORD((max(time.duration_nanoseconds(duration), 0) + 999999)/1000000) - switch m in &c.mutex { - case ^Mutex: - return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, ms) - case ^Blocking_Mutex: - return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, ms, 0) - } - return false -} - - - - -RW_Lock :: struct { - _handle: win32.SRWLOCK, -} - -rw_lock_init :: proc(l: ^RW_Lock) { - l._handle = win32.SRWLOCK_INIT -} -rw_lock_destroy :: proc(l: ^RW_Lock) { - // -} -rw_lock_read :: proc(l: ^RW_Lock) { - win32.AcquireSRWLockShared(&l._handle) -} -rw_lock_try_read :: proc(l: ^RW_Lock) -> bool { - return bool(win32.TryAcquireSRWLockShared(&l._handle)) -} -rw_lock_write :: proc(l: ^RW_Lock) { - win32.AcquireSRWLockExclusive(&l._handle) -} -rw_lock_try_write :: proc(l: ^RW_Lock) -> bool { - return bool(win32.TryAcquireSRWLockExclusive(&l._handle)) -} -rw_lock_read_unlock :: proc(l: ^RW_Lock) { - win32.ReleaseSRWLockShared(&l._handle) -} -rw_lock_write_unlock :: proc(l: ^RW_Lock) { - win32.ReleaseSRWLockExclusive(&l._handle) -} - - -thread_yield :: proc() { - win32.SwitchToThread() -} - diff --git a/core/sync/wait_group.odin b/core/sync/wait_group.odin deleted file mode 100644 index 63d882ed1..000000000 --- a/core/sync/wait_group.odin +++ /dev/null @@ -1,58 +0,0 @@ -package sync - -import "core:intrinsics" - -Wait_Group :: struct { - counter: int, - mutex: Blocking_Mutex, - cond: Condition, -} - -wait_group_init :: proc(wg: ^Wait_Group) { - wg.counter = 0 - blocking_mutex_init(&wg.mutex) - condition_init(&wg.cond, &wg.mutex) -} - - -wait_group_destroy :: proc(wg: ^Wait_Group) { - condition_destroy(&wg.cond) - blocking_mutex_destroy(&wg.mutex) -} - -wait_group_add :: proc(wg: ^Wait_Group, delta: int) { - if delta == 0 { - return - } - - blocking_mutex_lock(&wg.mutex) - defer blocking_mutex_unlock(&wg.mutex) - - intrinsics.atomic_add(&wg.counter, delta) - if wg.counter < 0 { - panic("sync.Wait_Group negative counter") - } - if wg.counter == 0 { - condition_broadcast(&wg.cond) - if wg.counter != 0 { - panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait") - } - } -} - -wait_group_done :: proc(wg: ^Wait_Group) { - wait_group_add(wg, -1) -} - -wait_group_wait :: proc(wg: ^Wait_Group) { - blocking_mutex_lock(&wg.mutex) - defer blocking_mutex_unlock(&wg.mutex) - - if wg.counter != 0 { - condition_wait_for(&wg.cond) - if wg.counter != 0 { - panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait") - } - } -} - diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 37ee4fa98..97ea2b77d 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -26,7 +26,7 @@ INVALID_TASK_ID :: Task_Id(-1) Pool :: struct { allocator: mem.Allocator, mutex: sync.Mutex, - sem_available: sync.Semaphore, + sem_available: sync.Sema, processing_task_count: int, // atomic is_running: bool, @@ -40,14 +40,14 @@ pool_init :: proc(pool: ^Pool, thread_count: int, allocator := context.allocator pool := (^Pool)(t.data) for pool.is_running { - sync.semaphore_wait_for(&pool.sem_available) + sync.sema_wait(&pool.sem_available) if task, ok := pool_try_and_pop_task(pool); ok { pool_do_work(pool, &task) } } - sync.semaphore_post(&pool.sem_available, 1) + sync.sema_post(&pool.sem_available, 1) } @@ -56,8 +56,6 @@ pool_init :: proc(pool: ^Pool, thread_count: int, allocator := context.allocator pool.tasks = make([dynamic]Task) pool.threads = make([]^Thread, thread_count) - sync.mutex_init(&pool.mutex) - sync.semaphore_init(&pool.sem_available) pool.is_running = true for _, i in pool.threads { @@ -76,9 +74,6 @@ pool_destroy :: proc(pool: ^Pool) { } delete(pool.threads, pool.allocator) - - sync.mutex_destroy(&pool.mutex) - sync.semaphore_destroy(&pool.sem_available) } pool_start :: proc(pool: ^Pool) { @@ -90,7 +85,7 @@ pool_start :: proc(pool: ^Pool) { pool_join :: proc(pool: ^Pool) { pool.is_running = false - sync.semaphore_post(&pool.sem_available, len(pool.threads)) + sync.sema_post(&pool.sem_available, len(pool.threads)) yield() @@ -109,7 +104,7 @@ pool_add_task :: proc(pool: ^Pool, procedure: Task_Proc, data: rawptr, user_inde task.user_index = user_index append(&pool.tasks, task) - sync.semaphore_post(&pool.sem_available, 1) + sync.sema_post(&pool.sem_available, 1) } pool_try_and_pop_task :: proc(pool: ^Pool) -> (task: Task, got_task: bool = false) { @@ -140,7 +135,7 @@ pool_wait_and_process :: proc(pool: ^Pool) { // Safety kick if len(pool.tasks) != 0 && intrinsics.atomic_load(&pool.processing_task_count) == 0 { sync.mutex_lock(&pool.mutex) - sync.semaphore_post(&pool.sem_available, len(pool.tasks)) + sync.sema_post(&pool.sem_available, len(pool.tasks)) sync.mutex_unlock(&pool.mutex) } diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index fbf89f122..8452df112 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -4,7 +4,7 @@ package thread import "core:runtime" import "core:intrinsics" -import sync "core:sync/sync2" +import "core:sync" import "core:sys/unix" Thread_State :: enum u8 { diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 428e241d0..210c54a96 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -3,7 +3,7 @@ package thread import "core:runtime" -import sync "core:sync/sync2" +import "core:sync" import win32 "core:sys/windows" Thread_Os_Specific :: struct { diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index dafd29ab3..6a039e4dd 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -96,7 +96,6 @@ import sort "core:sort" import strconv "core:strconv" import strings "core:strings" import sync "core:sync" -import sync2 "core:sync/sync2" import testing "core:testing" import scanner "core:text/scanner" import thread "core:thread" @@ -187,7 +186,6 @@ _ :: sort _ :: strconv _ :: strings _ :: sync -_ :: sync2 _ :: testing _ :: scanner _ :: thread From 645661889137f6f4cb96b9671976dbc006345497 Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 30 Mar 2022 16:54:29 -0400 Subject: [PATCH 0465/1052] finish up stat, lstat and fstat --- core/os/os2/file_linux.odin | 4 ++- core/os/os2/stat_linux.odin | 50 +++++++++++++++++++++++-------------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 7040d0ed3..3202b9e16 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -22,8 +22,10 @@ _O_APPEND :: 0o2000 _O_NONBLOCK :: 0o4000 _O_LARGEFILE :: 0o100000 _O_DIRECTORY :: 0o200000 +_O_NOFOLLOW :: 0o400000 _O_SYNC :: 0o4010000 _O_CLOEXEC :: 0o2000000 +_O_PATH :: 0o10000000 _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { cstr := strings.clone_to_cstring(name, context.temp_allocator) @@ -66,7 +68,7 @@ _name :: proc(fd: Handle, allocator := context.allocator) -> string { realpath: string err: Error - if realpath, err = _read_link_cstr(cstring(&buf[0])); err != nil || realpath[0] != '/' { + if realpath, err = _read_link_cstr(cstring(&buf[0]), allocator); err != nil || realpath[0] != '/' { return "" } return realpath diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index c4cc5fe8d..d22f32d65 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -82,39 +82,51 @@ OS_Stat :: struct { _reserve3: i64, } + _fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) { - return File_Info{}, nil -} - -_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { - return File_Info{}, nil -} - -_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { - cstr := strings.clone_to_cstring(name) - defer delete(cstr) - s: OS_Stat - result := unix.sys_lstat(cstr, &s) + result := unix.sys_fstat(int(fd), &s) if result < 0 { - return {}, _get_platform_error(int(unix.get_errno(result))) + return {}, _get_platform_error(result) } + // TODO: As of Linux 4.11, the new statx syscall can retrieve creation_time fi := File_Info { - fullpath = "", + fullpath = _name(fd, allocator), name = "", size = s.size, mode = 0, is_dir = S_ISDIR(s.mode), - creation_time = time.Time{0}, // linux does not track this - //TODO - modification_time = time.Time{0}, - access_time = time.Time{0}, + modification_time = time.Time {s.modified.seconds}, + access_time = time.Time {s.last_access.seconds}, + creation_time = time.Time{0}, // regular stat does not provide this } - + + fi.name = filepath.base(fi.fullpath) return fi, nil } +// NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath +_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { + cstr := strings.clone_to_cstring(name, context.temp_allocator) + fd := unix.sys_open(cstr, _O_RDONLY) + if fd < 0 { + return {}, _get_platform_error(fd) + } + defer unix.sys_close(fd) + return _fstat(Handle(fd), allocator) +} + +_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { + cstr := strings.clone_to_cstring(name, context.temp_allocator) + fd := unix.sys_open(cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW) + if fd < 0 { + return {}, _get_platform_error(fd) + } + defer unix.sys_close(fd) + return _fstat(Handle(fd), allocator) +} + _same_file :: proc(fi1, fi2: File_Info) -> bool { return fi1.fullpath == fi2.fullpath } From 203382461b43db30977c17f51929a565c1f3a229 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 00:14:49 +0100 Subject: [PATCH 0466/1052] Replace the atomic intrinsics Matching C11 in style --- src/check_builtin.cpp | 189 +++++++++++++++++++++++----------- src/checker.cpp | 25 ++++- src/checker_builtin_procs.hpp | 175 +++++++------------------------ src/llvm_backend_proc.cpp | 170 ++++++++---------------------- src/llvm_backend_utility.cpp | 22 ++++ src/types.cpp | 13 +++ 6 files changed, 271 insertions(+), 323 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e480704e3..3fe0f1048 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -379,6 +379,32 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } } +bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, char const *extra_message = nullptr) { + Operand x = {}; + check_expr_with_type_hint(c, &x, expr, t_atomic_memory_order); + if (x.mode == Addressing_Invalid) { + return false; + } + if (!are_types_identical(x.type, t_atomic_memory_order) || x.mode != Addressing_Constant) { + gbString str = type_to_string(x.type); + if (extra_message) { + error(x.expr, "Expected a constant Atomic_Memory_Order value for the %s of '%.*s', got %s", extra_message, LIT(builtin_name), str); + } else { + error(x.expr, "Expected a constant Atomic_Memory_Order value for '%.*s', got %s", LIT(builtin_name), str); + } + gb_string_free(str); + return false; + } + i64 value = exact_value_to_i64(x.value); + if (value < 0 || value >= OdinAtomicMemoryOrder_COUNT) { + error(x.expr, "Illegal Atomic_Memory_Order value, got %lld", cast(long long)value); + return false; + } + + return true; + +} + bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); if (ce->inlining != ProcInlining_none) { @@ -423,6 +449,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 // NOTE(bill): The first arg may be a Type, this will be checked case by case break; + case BuiltinProc_atomic_thread_fence: + case BuiltinProc_atomic_signal_fence: + // NOTE(bill): first type will require a type hint + break; + case BuiltinProc_DIRECTIVE: { ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; @@ -3198,10 +3229,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; - case BuiltinProc_atomic_fence: - case BuiltinProc_atomic_fence_acq: - case BuiltinProc_atomic_fence_rel: - case BuiltinProc_atomic_fence_acqrel: + + case BuiltinProc_atomic_thread_fence: + case BuiltinProc_atomic_signal_fence: + if (!check_atomic_memory_order_argument(c, ce->args[0], builtin_name)) { + return false; + } operand->mode = Addressing_NoValue; break; @@ -3210,9 +3243,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_unaligned_store: /*fallthrough*/ case BuiltinProc_atomic_store: - case BuiltinProc_atomic_store_rel: - case BuiltinProc_atomic_store_relaxed: - case BuiltinProc_atomic_store_unordered: { Type *elem = nullptr; if (!is_type_normal_pointer(operand->type, &elem)) { @@ -3228,14 +3258,32 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_atomic_store_explicit: + { + Type *elem = nullptr; + if (!is_type_normal_pointer(operand->type, &elem)) { + error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); + return false; + } + Operand x = {}; + check_expr_with_type_hint(c, &x, ce->args[1], elem); + check_assignment(c, &x, elem, builtin_name); + + if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name)) { + return false; + } + + operand->type = nullptr; + operand->mode = Addressing_NoValue; + break; + } + + case BuiltinProc_volatile_load: /*fallthrough*/ case BuiltinProc_unaligned_load: /*fallthrough*/ case BuiltinProc_atomic_load: - case BuiltinProc_atomic_load_acq: - case BuiltinProc_atomic_load_relaxed: - case BuiltinProc_atomic_load_unordered: { Type *elem = nullptr; if (!is_type_normal_pointer(operand->type, &elem)) { @@ -3247,41 +3295,30 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_atomic_load_explicit: + { + Type *elem = nullptr; + if (!is_type_normal_pointer(operand->type, &elem)) { + error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); + return false; + } + + if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name)) { + return false; + } + + operand->type = elem; + operand->mode = Addressing_Value; + break; + } + case BuiltinProc_atomic_add: - case BuiltinProc_atomic_add_acq: - case BuiltinProc_atomic_add_rel: - case BuiltinProc_atomic_add_acqrel: - case BuiltinProc_atomic_add_relaxed: case BuiltinProc_atomic_sub: - case BuiltinProc_atomic_sub_acq: - case BuiltinProc_atomic_sub_rel: - case BuiltinProc_atomic_sub_acqrel: - case BuiltinProc_atomic_sub_relaxed: case BuiltinProc_atomic_and: - case BuiltinProc_atomic_and_acq: - case BuiltinProc_atomic_and_rel: - case BuiltinProc_atomic_and_acqrel: - case BuiltinProc_atomic_and_relaxed: case BuiltinProc_atomic_nand: - case BuiltinProc_atomic_nand_acq: - case BuiltinProc_atomic_nand_rel: - case BuiltinProc_atomic_nand_acqrel: - case BuiltinProc_atomic_nand_relaxed: case BuiltinProc_atomic_or: - case BuiltinProc_atomic_or_acq: - case BuiltinProc_atomic_or_rel: - case BuiltinProc_atomic_or_acqrel: - case BuiltinProc_atomic_or_relaxed: case BuiltinProc_atomic_xor: - case BuiltinProc_atomic_xor_acq: - case BuiltinProc_atomic_xor_rel: - case BuiltinProc_atomic_xor_acqrel: - case BuiltinProc_atomic_xor_relaxed: - case BuiltinProc_atomic_xchg: - case BuiltinProc_atomic_xchg_acq: - case BuiltinProc_atomic_xchg_rel: - case BuiltinProc_atomic_xchg_acqrel: - case BuiltinProc_atomic_xchg_relaxed: + case BuiltinProc_atomic_exchange: { Type *elem = nullptr; if (!is_type_normal_pointer(operand->type, &elem)) { @@ -3297,25 +3334,35 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } - case BuiltinProc_atomic_cxchg: - case BuiltinProc_atomic_cxchg_acq: - case BuiltinProc_atomic_cxchg_rel: - case BuiltinProc_atomic_cxchg_acqrel: - case BuiltinProc_atomic_cxchg_relaxed: - case BuiltinProc_atomic_cxchg_failrelaxed: - case BuiltinProc_atomic_cxchg_failacq: - case BuiltinProc_atomic_cxchg_acq_failrelaxed: - case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: + case BuiltinProc_atomic_add_explicit: + case BuiltinProc_atomic_sub_explicit: + case BuiltinProc_atomic_and_explicit: + case BuiltinProc_atomic_nand_explicit: + case BuiltinProc_atomic_or_explicit: + case BuiltinProc_atomic_xor_explicit: + case BuiltinProc_atomic_exchange_explicit: + { + Type *elem = nullptr; + if (!is_type_normal_pointer(operand->type, &elem)) { + error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); + return false; + } + Operand x = {}; + check_expr_with_type_hint(c, &x, ce->args[1], elem); + check_assignment(c, &x, elem, builtin_name); - case BuiltinProc_atomic_cxchgweak: - case BuiltinProc_atomic_cxchgweak_acq: - case BuiltinProc_atomic_cxchgweak_rel: - case BuiltinProc_atomic_cxchgweak_acqrel: - case BuiltinProc_atomic_cxchgweak_relaxed: - case BuiltinProc_atomic_cxchgweak_failrelaxed: - case BuiltinProc_atomic_cxchgweak_failacq: - case BuiltinProc_atomic_cxchgweak_acq_failrelaxed: - case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: + + if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name)) { + return false; + } + + operand->type = elem; + operand->mode = Addressing_Value; + break; + } + + case BuiltinProc_atomic_compare_exchange_strong: + case BuiltinProc_atomic_compare_exchange_weak: { Type *elem = nullptr; if (!is_type_normal_pointer(operand->type, &elem)) { @@ -3333,7 +3380,33 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = elem; break; } - break; + + case BuiltinProc_atomic_compare_exchange_strong_explicit: + case BuiltinProc_atomic_compare_exchange_weak_explicit: + { + Type *elem = nullptr; + if (!is_type_normal_pointer(operand->type, &elem)) { + error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); + return false; + } + Operand x = {}; + Operand y = {}; + check_expr_with_type_hint(c, &x, ce->args[1], elem); + check_expr_with_type_hint(c, &y, ce->args[2], elem); + check_assignment(c, &x, elem, builtin_name); + check_assignment(c, &y, elem, builtin_name); + + if (!check_atomic_memory_order_argument(c, ce->args[3], builtin_name, "success ordering")) { + return false; + } + if (!check_atomic_memory_order_argument(c, ce->args[4], builtin_name, "failure ordering")) { + return false; + } + + operand->mode = Addressing_OptionalOk; + operand->type = elem; + break; + } case BuiltinProc_fixed_point_mul: case BuiltinProc_fixed_point_div: diff --git a/src/checker.cpp b/src/checker.cpp index 53bba654d..0c72a8e14 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -829,15 +829,16 @@ struct GlobalEnumValue { i64 value; }; -Slice add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count) { +Slice add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count, Type **enum_type_ = nullptr) { Scope *scope = create_scope(nullptr, builtin_pkg->scope); - Entity *e = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved); + Entity *entity = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved); Type *enum_type = alloc_type_enum(); - Type *named_type = alloc_type_named(type_name, enum_type, e); + Type *named_type = alloc_type_named(type_name, enum_type, entity); set_base_type(named_type, enum_type); enum_type->Enum.base_type = t_int; enum_type->Enum.scope = scope; + entity->type = named_type; auto fields = array_make(permanent_allocator(), value_count); for (isize i = 0; i < value_count; i++) { @@ -858,6 +859,9 @@ Slice add_global_enum_type(String const &type_name, GlobalEnumValue *v enum_type->Enum.min_value = &enum_type->Enum.fields[enum_type->Enum.min_value_index]->Constant.value; enum_type->Enum.max_value = &enum_type->Enum.fields[enum_type->Enum.max_value_index]->Constant.value; + + if (enum_type_) *enum_type_ = named_type; + return slice_from_array(fields); } void add_global_enum_constant(Slice const &fields, char const *name, i64 value) { @@ -986,6 +990,21 @@ void init_universal(void) { add_global_enum_constant(fields, "ODIN_ERROR_POS_STYLE", build_context.ODIN_ERROR_POS_STYLE); } + { + GlobalEnumValue values[OdinAtomicMemoryOrder_COUNT] = { + {"relaxed", OdinAtomicMemoryOrder_relaxed}, + {"consume", OdinAtomicMemoryOrder_consume}, + {"acquire", OdinAtomicMemoryOrder_acquire}, + {"release", OdinAtomicMemoryOrder_release}, + {"acq_rel", OdinAtomicMemoryOrder_acq_rel}, + {"seq_cst", OdinAtomicMemoryOrder_seq_cst}, + }; + + add_global_enum_type(str_lit("Atomic_Memory_Order"), values, gb_count_of(values), &t_atomic_memory_order); + GB_ASSERT(t_atomic_memory_order->kind == Type_Named); + scope_insert(intrinsics_pkg->scope, t_atomic_memory_order->Named.type_name); + } + add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG); add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c647d5a01..c6b0afee0 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -86,77 +86,30 @@ enum BuiltinProcId { BuiltinProc_prefetch_write_instruction, BuiltinProc_prefetch_write_data, - BuiltinProc_atomic_fence, - BuiltinProc_atomic_fence_acq, - BuiltinProc_atomic_fence_rel, - BuiltinProc_atomic_fence_acqrel, - + BuiltinProc_atomic_thread_fence, + BuiltinProc_atomic_signal_fence, BuiltinProc_atomic_store, - BuiltinProc_atomic_store_rel, - BuiltinProc_atomic_store_relaxed, - BuiltinProc_atomic_store_unordered, - + BuiltinProc_atomic_store_explicit, BuiltinProc_atomic_load, - BuiltinProc_atomic_load_acq, - BuiltinProc_atomic_load_relaxed, - BuiltinProc_atomic_load_unordered, - + BuiltinProc_atomic_load_explicit, BuiltinProc_atomic_add, - BuiltinProc_atomic_add_acq, - BuiltinProc_atomic_add_rel, - BuiltinProc_atomic_add_acqrel, - BuiltinProc_atomic_add_relaxed, + BuiltinProc_atomic_add_explicit, BuiltinProc_atomic_sub, - BuiltinProc_atomic_sub_acq, - BuiltinProc_atomic_sub_rel, - BuiltinProc_atomic_sub_acqrel, - BuiltinProc_atomic_sub_relaxed, + BuiltinProc_atomic_sub_explicit, BuiltinProc_atomic_and, - BuiltinProc_atomic_and_acq, - BuiltinProc_atomic_and_rel, - BuiltinProc_atomic_and_acqrel, - BuiltinProc_atomic_and_relaxed, + BuiltinProc_atomic_and_explicit, BuiltinProc_atomic_nand, - BuiltinProc_atomic_nand_acq, - BuiltinProc_atomic_nand_rel, - BuiltinProc_atomic_nand_acqrel, - BuiltinProc_atomic_nand_relaxed, + BuiltinProc_atomic_nand_explicit, BuiltinProc_atomic_or, - BuiltinProc_atomic_or_acq, - BuiltinProc_atomic_or_rel, - BuiltinProc_atomic_or_acqrel, - BuiltinProc_atomic_or_relaxed, + BuiltinProc_atomic_or_explicit, BuiltinProc_atomic_xor, - BuiltinProc_atomic_xor_acq, - BuiltinProc_atomic_xor_rel, - BuiltinProc_atomic_xor_acqrel, - BuiltinProc_atomic_xor_relaxed, - - BuiltinProc_atomic_xchg, - BuiltinProc_atomic_xchg_acq, - BuiltinProc_atomic_xchg_rel, - BuiltinProc_atomic_xchg_acqrel, - BuiltinProc_atomic_xchg_relaxed, - - BuiltinProc_atomic_cxchg, - BuiltinProc_atomic_cxchg_acq, - BuiltinProc_atomic_cxchg_rel, - BuiltinProc_atomic_cxchg_acqrel, - BuiltinProc_atomic_cxchg_relaxed, - BuiltinProc_atomic_cxchg_failrelaxed, - BuiltinProc_atomic_cxchg_failacq, - BuiltinProc_atomic_cxchg_acq_failrelaxed, - BuiltinProc_atomic_cxchg_acqrel_failrelaxed, - - BuiltinProc_atomic_cxchgweak, - BuiltinProc_atomic_cxchgweak_acq, - BuiltinProc_atomic_cxchgweak_rel, - BuiltinProc_atomic_cxchgweak_acqrel, - BuiltinProc_atomic_cxchgweak_relaxed, - BuiltinProc_atomic_cxchgweak_failrelaxed, - BuiltinProc_atomic_cxchgweak_failacq, - BuiltinProc_atomic_cxchgweak_acq_failrelaxed, - BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed, + BuiltinProc_atomic_xor_explicit, + BuiltinProc_atomic_exchange, + BuiltinProc_atomic_exchange_explicit, + BuiltinProc_atomic_compare_exchange_strong, + BuiltinProc_atomic_compare_exchange_strong_explicit, + BuiltinProc_atomic_compare_exchange_weak, + BuiltinProc_atomic_compare_exchange_weak_explicit, BuiltinProc_fixed_point_mul, BuiltinProc_fixed_point_div, @@ -352,78 +305,30 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - + {STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store_explicit"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load_explicit"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_explicit"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_explicit"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_explicit"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_explicit"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_explicit"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_explicit"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_exchange"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_exchange_explicit"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_compare_exchange_strong"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_compare_exchange_strong_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_compare_exchange_weak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_compare_exchange_weak_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_mul"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_div"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index d7f3d6c45..ad82b79e5 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1606,36 +1606,26 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } - - case BuiltinProc_atomic_fence: - LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, ""); + // TODO(bill): Which is correct? + case BuiltinProc_atomic_thread_fence: + LLVMBuildFence(p->builder, llvm_atomic_ordering_from_odin(ce->args[0]), false, ""); return {}; - case BuiltinProc_atomic_fence_acq: - LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquire, false, ""); - return {}; - case BuiltinProc_atomic_fence_rel: - LLVMBuildFence(p->builder, LLVMAtomicOrderingRelease, false, ""); - return {}; - case BuiltinProc_atomic_fence_acqrel: - LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquireRelease, false, ""); + case BuiltinProc_atomic_signal_fence: + LLVMBuildFence(p->builder, llvm_atomic_ordering_from_odin(ce->args[0]), true, ""); return {}; case BuiltinProc_volatile_store: case BuiltinProc_atomic_store: - case BuiltinProc_atomic_store_rel: - case BuiltinProc_atomic_store_relaxed: - case BuiltinProc_atomic_store_unordered: { + case BuiltinProc_atomic_store_explicit: { lbValue dst = lb_build_expr(p, ce->args[0]); lbValue val = lb_build_expr(p, ce->args[1]); val = lb_emit_conv(p, val, type_deref(dst.type)); LLVMValueRef instr = LLVMBuildStore(p->builder, val.value, dst.value); switch (id) { - case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break; - case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; - case BuiltinProc_atomic_store_rel: LLVMSetOrdering(instr, LLVMAtomicOrderingRelease); break; - case BuiltinProc_atomic_store_relaxed: LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic); break; - case BuiltinProc_atomic_store_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered); break; + case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break; + case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; + case BuiltinProc_atomic_store_explicit: LLVMSetOrdering(instr, llvm_atomic_ordering_from_odin(ce->args[2])); break; } LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); @@ -1645,18 +1635,14 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_volatile_load: case BuiltinProc_atomic_load: - case BuiltinProc_atomic_load_acq: - case BuiltinProc_atomic_load_relaxed: - case BuiltinProc_atomic_load_unordered: { + case BuiltinProc_atomic_load_explicit: { lbValue dst = lb_build_expr(p, ce->args[0]); LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, ""); switch (id) { - case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break; - case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; - case BuiltinProc_atomic_load_acq: LLVMSetOrdering(instr, LLVMAtomicOrderingAcquire); break; - case BuiltinProc_atomic_load_relaxed: LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic); break; - case BuiltinProc_atomic_load_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered); break; + case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break; + case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; + case BuiltinProc_atomic_load_explicit: LLVMSetOrdering(instr, llvm_atomic_ordering_from_odin(ce->args[1])); break; } LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); @@ -1686,40 +1672,19 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_atomic_add: - case BuiltinProc_atomic_add_acq: - case BuiltinProc_atomic_add_rel: - case BuiltinProc_atomic_add_acqrel: - case BuiltinProc_atomic_add_relaxed: case BuiltinProc_atomic_sub: - case BuiltinProc_atomic_sub_acq: - case BuiltinProc_atomic_sub_rel: - case BuiltinProc_atomic_sub_acqrel: - case BuiltinProc_atomic_sub_relaxed: case BuiltinProc_atomic_and: - case BuiltinProc_atomic_and_acq: - case BuiltinProc_atomic_and_rel: - case BuiltinProc_atomic_and_acqrel: - case BuiltinProc_atomic_and_relaxed: case BuiltinProc_atomic_nand: - case BuiltinProc_atomic_nand_acq: - case BuiltinProc_atomic_nand_rel: - case BuiltinProc_atomic_nand_acqrel: - case BuiltinProc_atomic_nand_relaxed: case BuiltinProc_atomic_or: - case BuiltinProc_atomic_or_acq: - case BuiltinProc_atomic_or_rel: - case BuiltinProc_atomic_or_acqrel: - case BuiltinProc_atomic_or_relaxed: case BuiltinProc_atomic_xor: - case BuiltinProc_atomic_xor_acq: - case BuiltinProc_atomic_xor_rel: - case BuiltinProc_atomic_xor_acqrel: - case BuiltinProc_atomic_xor_relaxed: - case BuiltinProc_atomic_xchg: - case BuiltinProc_atomic_xchg_acq: - case BuiltinProc_atomic_xchg_rel: - case BuiltinProc_atomic_xchg_acqrel: - case BuiltinProc_atomic_xchg_relaxed: { + case BuiltinProc_atomic_exchange: + case BuiltinProc_atomic_add_explicit: + case BuiltinProc_atomic_sub_explicit: + case BuiltinProc_atomic_and_explicit: + case BuiltinProc_atomic_nand_explicit: + case BuiltinProc_atomic_or_explicit: + case BuiltinProc_atomic_xor_explicit: + case BuiltinProc_atomic_exchange_explicit: { lbValue dst = lb_build_expr(p, ce->args[0]); lbValue val = lb_build_expr(p, ce->args[1]); val = lb_emit_conv(p, val, type_deref(dst.type)); @@ -1728,41 +1693,20 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, LLVMAtomicOrdering ordering = {}; switch (id) { - case BuiltinProc_atomic_add: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_add_acq: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_add_rel: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_add_acqrel: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_add_relaxed: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_sub: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_sub_acq: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_sub_rel: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_sub_acqrel: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_sub_relaxed: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_and: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_and_acq: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_and_rel: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_and_acqrel: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_and_relaxed: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_nand: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_nand_acq: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_nand_rel: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_nand_acqrel: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_nand_relaxed: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_or: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_or_acq: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_or_rel: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_or_acqrel: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_or_relaxed: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_xor: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_xor_acq: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_xor_rel: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_xor_acqrel: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_xor_relaxed: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_xchg: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_xchg_acq: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_xchg_rel: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_xchg_acqrel: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_xchg_relaxed: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingMonotonic; break; + case BuiltinProc_atomic_add: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_sub: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_and: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_nand: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_or: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_xor: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_exchange: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_add_explicit: op = LLVMAtomicRMWBinOpAdd; ordering = llvm_atomic_ordering_from_odin(ce->args[2]); break; + case BuiltinProc_atomic_sub_explicit: op = LLVMAtomicRMWBinOpSub; ordering = llvm_atomic_ordering_from_odin(ce->args[2]); break; + case BuiltinProc_atomic_and_explicit: op = LLVMAtomicRMWBinOpAnd; ordering = llvm_atomic_ordering_from_odin(ce->args[2]); break; + case BuiltinProc_atomic_nand_explicit: op = LLVMAtomicRMWBinOpNand; ordering = llvm_atomic_ordering_from_odin(ce->args[2]); break; + case BuiltinProc_atomic_or_explicit: op = LLVMAtomicRMWBinOpOr; ordering = llvm_atomic_ordering_from_odin(ce->args[2]); break; + case BuiltinProc_atomic_xor_explicit: op = LLVMAtomicRMWBinOpXor; ordering = llvm_atomic_ordering_from_odin(ce->args[2]); break; + case BuiltinProc_atomic_exchange_explicit: op = LLVMAtomicRMWBinOpXchg; ordering = llvm_atomic_ordering_from_odin(ce->args[2]); break; } lbValue res = {}; @@ -1771,24 +1715,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return res; } - case BuiltinProc_atomic_cxchg: - case BuiltinProc_atomic_cxchg_acq: - case BuiltinProc_atomic_cxchg_rel: - case BuiltinProc_atomic_cxchg_acqrel: - case BuiltinProc_atomic_cxchg_relaxed: - case BuiltinProc_atomic_cxchg_failrelaxed: - case BuiltinProc_atomic_cxchg_failacq: - case BuiltinProc_atomic_cxchg_acq_failrelaxed: - case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: - case BuiltinProc_atomic_cxchgweak: - case BuiltinProc_atomic_cxchgweak_acq: - case BuiltinProc_atomic_cxchgweak_rel: - case BuiltinProc_atomic_cxchgweak_acqrel: - case BuiltinProc_atomic_cxchgweak_relaxed: - case BuiltinProc_atomic_cxchgweak_failrelaxed: - case BuiltinProc_atomic_cxchgweak_failacq: - case BuiltinProc_atomic_cxchgweak_acq_failrelaxed: - case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: { + case BuiltinProc_atomic_compare_exchange_strong: + case BuiltinProc_atomic_compare_exchange_weak: + case BuiltinProc_atomic_compare_exchange_strong_explicit: + case BuiltinProc_atomic_compare_exchange_weak_explicit: { lbValue address = lb_build_expr(p, ce->args[0]); Type *elem = type_deref(address.type); lbValue old_value = lb_build_expr(p, ce->args[1]); @@ -1801,24 +1731,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, LLVMBool weak = false; switch (id) { - case BuiltinProc_atomic_cxchg: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = false; break; - case BuiltinProc_atomic_cxchg_acq_failrelaxed: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchgweak: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchgweak_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = true; break; - case BuiltinProc_atomic_cxchgweak_acq_failrelaxed: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; + case BuiltinProc_atomic_compare_exchange_strong: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; + case BuiltinProc_atomic_compare_exchange_weak: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; + case BuiltinProc_atomic_compare_exchange_strong_explicit: success_ordering = llvm_atomic_ordering_from_odin(ce->args[3]); failure_ordering = llvm_atomic_ordering_from_odin(ce->args[4]); weak = false; break; + case BuiltinProc_atomic_compare_exchange_weak_explicit: success_ordering = llvm_atomic_ordering_from_odin(ce->args[3]); failure_ordering = llvm_atomic_ordering_from_odin(ce->args[4]); weak = true; break; } // TODO(bill): Figure out how to make it weak diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 399d1632d..037171637 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -2005,3 +2005,25 @@ lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) { } + + +LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) { + GB_ASSERT(value.kind == ExactValue_Integer); + i64 v = exact_value_to_i64(value); + switch (v) { + case OdinAtomicMemoryOrder_relaxed: return LLVMAtomicOrderingUnordered; + case OdinAtomicMemoryOrder_consume: return LLVMAtomicOrderingMonotonic; + case OdinAtomicMemoryOrder_acquire: return LLVMAtomicOrderingAcquire; + case OdinAtomicMemoryOrder_release: return LLVMAtomicOrderingRelease; + case OdinAtomicMemoryOrder_acq_rel: return LLVMAtomicOrderingAcquireRelease; + case OdinAtomicMemoryOrder_seq_cst: return LLVMAtomicOrderingSequentiallyConsistent; + } + GB_PANIC("Unknown atomic ordering"); + return LLVMAtomicOrderingSequentiallyConsistent; +} + + +LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) { + ExactValue value = type_and_value_of_expr(expr).value; + return llvm_atomic_ordering_from_odin(value); +} diff --git a/src/types.cpp b/src/types.cpp index b231218a2..25e29820c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -692,6 +692,19 @@ gb_global Type *t_objc_id = nullptr; gb_global Type *t_objc_SEL = nullptr; gb_global Type *t_objc_Class = nullptr; +enum OdinAtomicMemoryOrder : i32 { + OdinAtomicMemoryOrder_relaxed = 0, + OdinAtomicMemoryOrder_consume = 1, + OdinAtomicMemoryOrder_acquire = 2, + OdinAtomicMemoryOrder_release = 3, + OdinAtomicMemoryOrder_acq_rel = 4, + OdinAtomicMemoryOrder_seq_cst = 5, + OdinAtomicMemoryOrder_COUNT, +}; + +gb_global Type *t_atomic_memory_order = nullptr; + + gb_global RecursiveMutex g_type_mutex; From ba1930eb01455f3f8f84a24b8438171555611b95 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 00:22:54 +0100 Subject: [PATCH 0467/1052] Update core to use new atomic intrinsics --- core/c/libc/stdatomic.odin | 255 +++++++++++++---------------- core/mem/mem.odin | 2 +- core/sync/atomic.odin | 104 ++++-------- core/sync/extended.odin | 30 ++-- core/sync/primitives_atomic.odin | 16 +- core/sync/primitives_internal.odin | 6 +- core/testing/runner_windows.odin | 4 +- 7 files changed, 174 insertions(+), 243 deletions(-) diff --git a/core/c/libc/stdatomic.odin b/core/c/libc/stdatomic.odin index fbe1ef7ea..a5dd78afc 100644 --- a/core/c/libc/stdatomic.odin +++ b/core/c/libc/stdatomic.odin @@ -47,24 +47,25 @@ kill_dependency :: #force_inline proc(value: $T) -> T { // 7.17.4 Fences atomic_thread_fence :: #force_inline proc(order: memory_order) { - switch (order) { - case .relaxed: - return - case .consume: - intrinsics.atomic_fence_acq() - case .acquire: - intrinsics.atomic_fence_acq() - case .release: - intrinsics.atomic_fence_rel() - case .acq_rel: - intrinsics.atomic_fence_acqrel() - case .seq_cst: - intrinsics.atomic_fence_acqrel() + switch order { + case .relaxed: intrinsics.atomic_thread_fence(.relaxed) + case .consume: intrinsics.atomic_thread_fence(.consume) + case .acquire: intrinsics.atomic_thread_fence(.acquire) + case .release: intrinsics.atomic_thread_fence(.release) + case .acq_rel: intrinsics.atomic_thread_fence(.acq_rel) + case .seq_cst: intrinsics.atomic_thread_fence(.seq_cst) } } atomic_signal_fence :: #force_inline proc(order: memory_order) { - atomic_thread_fence(order) + switch order { + case .relaxed: intrinsics.atomic_signal_fence(.relaxed) + case .consume: intrinsics.atomic_signal_fence(.consume) + case .acquire: intrinsics.atomic_signal_fence(.acquire) + case .release: intrinsics.atomic_signal_fence(.release) + case .acq_rel: intrinsics.atomic_signal_fence(.acq_rel) + case .seq_cst: intrinsics.atomic_signal_fence(.seq_cst) + } } // 7.17.5 Lock-free property @@ -121,13 +122,10 @@ atomic_store_explicit :: #force_inline proc(object: ^$T, desired: T, order: memo assert(order != .acquire) assert(order != .acq_rel) - #partial switch (order) { - case .relaxed: - intrinsics.atomic_store_relaxed(object, desired) - case .release: - intrinsics.atomic_store_rel(object, desired) - case .seq_cst: - intrinsics.atomic_store(object, desired) + #partial switch order { + case .relaxed: intrinsics.atomic_store_explicit(object, desired, .relaxed) + case .release: intrinsics.atomic_store_explicit(object, desired, .release) + case .seq_cst: intrinsics.atomic_store_explicit(object, desired, .seq_cst) } } @@ -139,36 +137,26 @@ atomic_load_explicit :: #force_inline proc(object: ^$T, order: memory_order) { assert(order != .release) assert(order != .acq_rel) - #partial switch (order) { - case .relaxed: - return intrinsics.atomic_load_relaxed(object) - case .consume: - return intrinsics.atomic_load_acq(object) - case .acquire: - return intrinsics.atomic_load_acq(object) - case .seq_cst: - return intrinsics.atomic_load(object) + #partial switch order { + case .relaxed: return intrinsics.atomic_load_explicit(object, .relaxed) + case .consume: return intrinsics.atomic_load_explicit(object, .consume) + case .acquire: return intrinsics.atomic_load_explicit(object, .acquire) + case .seq_cst: return intrinsics.atomic_load_explicit(object, .seq_cst) } } atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T { - return intrinsics.atomic_xchg(object, desired) + return intrinsics.atomic_exchange(object, desired) } atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T { - switch (order) { - case .relaxed: - return intrinsics.atomic_xchg_relaxed(object, desired) - case .consume: - return intrinsics.atomic_xchg_acq(object, desired) - case .acquire: - return intrinsics.atomic_xchg_acq(object, desired) - case .release: - return intrinsics.atomic_xchg_rel(object, desired) - case .acq_rel: - return intrinsics.atomic_xchg_acqrel(object, desired) - case .seq_cst: - return intrinsics.atomic_xchg(object, desired) + switch order { + case .relaxed: return intrinsics.atomic_exchange_explicit(object, desired, .relaxed) + case .consume: return intrinsics.atomic_exchange_explicit(object, desired, .consume) + case .acquire: return intrinsics.atomic_exchange_explicit(object, desired, .acquire) + case .release: return intrinsics.atomic_exchange_explicit(object, desired, .release) + case .acq_rel: return intrinsics.atomic_exchange_explicit(object, desired, .acq_rel) + case .seq_cst: return intrinsics.atomic_exchange_explicit(object, desired, .seq_cst) } return false } @@ -189,102 +177,104 @@ atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: m // [success = seq_cst, failure = acquire] => failacq // [success = acquire, failure = relaxed] => acq_failrelaxed // [success = acq_rel, failure = relaxed] => acqrel_failrelaxed -atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) { - value, ok := intrinsics.atomic_cxchg(object, expected^, desired) +atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) -> bool { + value, ok := intrinsics.atomic_compare_exchange_strong(object, expected^, desired) if !ok { expected^ = value } return ok } -atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) { +atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) -> bool { assert(failure != .release) assert(failure != .acq_rel) value: T; ok: bool - #partial switch (failure) { + #partial switch failure { case .seq_cst: assert(success != .relaxed) - #partial switch (success) { + #partial switch success { case .seq_cst: - value, ok := intrinsics.atomic_cxchg(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .seq_cst) case .acquire: - value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acquire, .seq_cst) case .consume: - value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .consume, .seq_cst) case .release: - value, ok := intrinsics.atomic_cxchg_rel(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .release, .seq_cst) case .acq_rel: - value, ok := intrinsics.atomic_cxchg_acqrel(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acq_rel, .seq_cst) } case .relaxed: assert(success != .release) - #partial switch (success) { + #partial switch success { case .relaxed: - value, ok := intrinsics.atomic_cxchg_relaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .relaxed, .relaxed) case .seq_cst: - value, ok := intrinsics.atomic_cxchg_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .relaxed) case .acquire: - value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acquire, .relaxed) case .consume: - value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .consume, .relaxed) case .acq_rel: - value, ok := intrinsics.atomic_cxchg_acqrel_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acq_rel, .relaxed) } case .consume: - fallthrough + assert(success == .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .consume) case .acquire: assert(success == .seq_cst) - value, ok := intrinsics.atomic_cxchg_failacq(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .acquire) } if !ok { expected^ = value } return ok } -atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) { - value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired) +atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) -> bool { + value, ok := intrinsics.atomic_compare_exchange_weak(object, expected^, desired) if !ok { expected^ = value } return ok } -atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) { +atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) -> bool { assert(failure != .release) assert(failure != .acq_rel) value: T; ok: bool - #partial switch (failure) { + #partial switch failure { case .seq_cst: assert(success != .relaxed) - #partial switch (success) { + #partial switch success { case .seq_cst: - value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .seq_cst) case .acquire: - value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acquire, .seq_cst) case .consume: - value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .consume, .seq_cst) case .release: - value, ok := intrinsics.atomic_cxchgweak_rel(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .release, .seq_cst) case .acq_rel: - value, ok := intrinsics.atomic_cxchgweak_acqrel(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acq_rel, .seq_cst) } case .relaxed: assert(success != .release) - #partial switch (success) { + #partial switch success { case .relaxed: - value, ok := intrinsics.atomic_cxchgweak_relaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .relaxed, .relaxed) case .seq_cst: - value, ok := intrinsics.atomic_cxchgweak_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .relaxed) case .acquire: - value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acquire, .relaxed) case .consume: - value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .consume, .relaxed) case .acq_rel: - value, ok := intrinsics.atomic_cxchgweak_acqrel_failrelaxed(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acq_rel, .relaxed) } case .consume: - fallthrough + assert(success == .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .consume) case .acquire: assert(success == .seq_cst) - value, ok := intrinsics.atomic_cxchgweak_failacq(object, expected^, desired) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .acquire) } if !ok { expected^ = value } @@ -297,19 +287,14 @@ atomic_fetch_add :: #force_inline proc(object: ^$T, operand: T) -> T { } atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { - switch (order) { - case .relaxed: - return intrinsics.atomic_add_relaxed(object, operand) - case .consume: - return intrinsics.atomic_add_acq(object, operand) - case .acquire: - return intrinsics.atomic_add_acq(object, operand) - case .release: - return intrinsics.atomic_add_rel(object, operand) - case .acq_rel: - return intrinsics.atomic_add_acqrel(object, operand) - case .seq_cst: - return intrinsics.atomic_add(object, operand) + switch order { + case .relaxed: return intrinsics.atomic_add_explicit(object, operand, .relaxed) + case .consume: return intrinsics.atomic_add_explicit(object, operand, .consume) + case .acquire: return intrinsics.atomic_add_explicit(object, operand, .acquire) + case .release: return intrinsics.atomic_add_explicit(object, operand, .release) + case .acq_rel: return intrinsics.atomic_add_explicit(object, operand, .acq_rel) + case: fallthrough + case .seq_cst: return intrinsics.atomic_add_explicit(object, operand, .seq_cst) } } @@ -318,19 +303,14 @@ atomic_fetch_sub :: #force_inline proc(object: ^$T, operand: T) -> T { } atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { - switch (order) { - case .relaxed: - return intrinsics.atomic_sub_relaxed(object, operand) - case .consume: - return intrinsics.atomic_sub_acq(object, operand) - case .acquire: - return intrinsics.atomic_sub_acq(object, operand) - case .release: - return intrinsics.atomic_sub_rel(object, operand) - case .acq_rel: - return intrinsics.atomic_sub_acqrel(object, operand) - case .seq_cst: - return intrinsics.atomic_sub(object, operand) + switch order { + case .relaxed: return intrinsics.atomic_sub_explicit(object, operand, .relaxed) + case .consume: return intrinsics.atomic_sub_explicit(object, operand, .consume) + case .acquire: return intrinsics.atomic_sub_explicit(object, operand, .acquire) + case .release: return intrinsics.atomic_sub_explicit(object, operand, .release) + case .acq_rel: return intrinsics.atomic_sub_explicit(object, operand, .acq_rel) + case: fallthrough + case .seq_cst: return intrinsics.atomic_sub_explicit(object, operand, .seq_cst) } } @@ -339,19 +319,14 @@ atomic_fetch_or :: #force_inline proc(object: ^$T, operand: T) -> T { } atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { - switch (order) { - case .relaxed: - return intrinsics.atomic_or_relaxed(object, operand) - case .consume: - return intrinsics.atomic_or_acq(object, operand) - case .acquire: - return intrinsics.atomic_or_acq(object, operand) - case .release: - return intrinsics.atomic_or_rel(object, operand) - case .acq_rel: - return intrinsics.atomic_or_acqrel(object, operand) - case .seq_cst: - return intrinsics.atomic_or(object, operand) + switch order { + case .relaxed: return intrinsics.atomic_or_explicit(object, operand, .relaxed) + case .consume: return intrinsics.atomic_or_explicit(object, operand, .consume) + case .acquire: return intrinsics.atomic_or_explicit(object, operand, .acquire) + case .release: return intrinsics.atomic_or_explicit(object, operand, .release) + case .acq_rel: return intrinsics.atomic_or_explicit(object, operand, .acq_rel) + case: fallthrough + case .seq_cst: return intrinsics.atomic_or_explicit(object, operand, .seq_cst) } } @@ -360,19 +335,14 @@ atomic_fetch_xor :: #force_inline proc(object: ^$T, operand: T) -> T { } atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { - switch (order) { - case .relaxed: - return intrinsics.atomic_xor_relaxed(object, operand) - case .consume: - return intrinsics.atomic_xor_acq(object, operand) - case .acquire: - return intrinsics.atomic_xor_acq(object, operand) - case .release: - return intrinsics.atomic_xor_rel(object, operand) - case .acq_rel: - return intrinsics.atomic_xor_acqrel(object, operand) - case .seq_cst: - return intrinsics.atomic_xor(object, operand) + switch order { + case .relaxed: return intrinsics.atomic_xor_explicit(object, operand, .relaxed) + case .consume: return intrinsics.atomic_xor_explicit(object, operand, .consume) + case .acquire: return intrinsics.atomic_xor_explicit(object, operand, .acquire) + case .release: return intrinsics.atomic_xor_explicit(object, operand, .release) + case .acq_rel: return intrinsics.atomic_xor_explicit(object, operand, .acq_rel) + case: fallthrough + case .seq_cst: return intrinsics.atomic_xor_explicit(object, operand, .seq_cst) } } @@ -380,19 +350,14 @@ atomic_fetch_and :: #force_inline proc(object: ^$T, operand: T) -> T { return intrinsics.atomic_and(object, operand) } atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { - switch (order) { - case .relaxed: - return intrinsics.atomic_and_relaxed(object, operand) - case .consume: - return intrinsics.atomic_and_acq(object, operand) - case .acquire: - return intrinsics.atomic_and_acq(object, operand) - case .release: - return intrinsics.atomic_and_rel(object, operand) - case .acq_rel: - return intrinsics.atomic_and_acqrel(object, operand) - case .seq_cst: - return intrinsics.atomic_and(object, operand) + switch order { + case .relaxed: return intrinsics.atomic_and_explicit(object, operand, .relaxed) + case .consume: return intrinsics.atomic_and_explicit(object, operand, .consume) + case .acquire: return intrinsics.atomic_and_explicit(object, operand, .acquire) + case .release: return intrinsics.atomic_and_explicit(object, operand, .release) + case .acq_rel: return intrinsics.atomic_and_explicit(object, operand, .acq_rel) + case: fallthrough + case .seq_cst: return intrinsics.atomic_and_explicit(object, operand, .seq_cst) } } diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 8eb877e75..1ebe558ef 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -16,7 +16,7 @@ zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr { // equivalent semantics to those provided by the C11 Annex K 3.7.4.1 // memset_s call. intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero - intrinsics.atomic_fence() // Prevent reordering + intrinsics.atomic_thread_fence(.seq_cst) // Prevent reordering return data } zero_item :: proc "contextless" (item: $P/^$T) { diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index fe19f17c8..703393592 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -4,76 +4,42 @@ import "core:intrinsics" cpu_relax :: intrinsics.cpu_relax -atomic_fence :: intrinsics.atomic_fence -atomic_fence_acquire :: intrinsics.atomic_fence_acq -atomic_fence_release :: intrinsics.atomic_fence_rel -atomic_fence_acqrel :: intrinsics.atomic_fence_acqrel +/* +Atomic_Memory_Order :: enum { + relaxed = 0, + consume = 1, + acquire = 2, + release = 3, + acq_rel = 4, + seq_cst = 5, +} +*/ +Atomic_Memory_Order :: intrinsics.Atomic_Memory_Order -atomic_store :: intrinsics.atomic_store -atomic_store_release :: intrinsics.atomic_store_rel -atomic_store_relaxed :: intrinsics.atomic_store_relaxed -atomic_store_unordered :: intrinsics.atomic_store_unordered -atomic_load :: intrinsics.atomic_load -atomic_load_acquire :: intrinsics.atomic_load_acq -atomic_load_relaxed :: intrinsics.atomic_load_relaxed -atomic_load_unordered :: intrinsics.atomic_load_unordered - -atomic_add :: intrinsics.atomic_add -atomic_add_acquire :: intrinsics.atomic_add_acq -atomic_add_release :: intrinsics.atomic_add_rel -atomic_add_acqrel :: intrinsics.atomic_add_acqrel -atomic_add_relaxed :: intrinsics.atomic_add_relaxed -atomic_sub :: intrinsics.atomic_sub -atomic_sub_acquire :: intrinsics.atomic_sub_acq -atomic_sub_release :: intrinsics.atomic_sub_rel -atomic_sub_acqrel :: intrinsics.atomic_sub_acqrel -atomic_sub_relaxed :: intrinsics.atomic_sub_relaxed -atomic_and :: intrinsics.atomic_and -atomic_and_acquire :: intrinsics.atomic_and_acq -atomic_and_release :: intrinsics.atomic_and_rel -atomic_and_acqrel :: intrinsics.atomic_and_acqrel -atomic_and_relaxed :: intrinsics.atomic_and_relaxed -atomic_nand :: intrinsics.atomic_nand -atomic_nand_acquire :: intrinsics.atomic_nand_acq -atomic_nand_release :: intrinsics.atomic_nand_rel -atomic_nand_acqrel :: intrinsics.atomic_nand_acqrel -atomic_nand_relaxed :: intrinsics.atomic_nand_relaxed -atomic_or :: intrinsics.atomic_or -atomic_or_acquire :: intrinsics.atomic_or_acq -atomic_or_release :: intrinsics.atomic_or_rel -atomic_or_acqrel :: intrinsics.atomic_or_acqrel -atomic_or_relaxed :: intrinsics.atomic_or_relaxed -atomic_xor :: intrinsics.atomic_xor -atomic_xor_acquire :: intrinsics.atomic_xor_acq -atomic_xor_release :: intrinsics.atomic_xor_rel -atomic_xor_acqrel :: intrinsics.atomic_xor_acqrel -atomic_xor_relaxed :: intrinsics.atomic_xor_relaxed - -atomic_exchange :: intrinsics.atomic_xchg -atomic_exchange_acquire :: intrinsics.atomic_xchg_acq -atomic_exchange_release :: intrinsics.atomic_xchg_rel -atomic_exchange_acqrel :: intrinsics.atomic_xchg_acqrel -atomic_exchange_relaxed :: intrinsics.atomic_xchg_relaxed +atomic_thread_fence :: intrinsics.atomic_thread_fence +atomic_signal_fence :: intrinsics.atomic_signal_fence +atomic_store :: intrinsics.atomic_store +atomic_store_explicit :: intrinsics.atomic_store_explicit +atomic_load :: intrinsics.atomic_load +atomic_load_explicit :: intrinsics.atomic_load_explicit +atomic_add :: intrinsics.atomic_add +atomic_add_explicit :: intrinsics.atomic_add_explicit +atomic_sub :: intrinsics.atomic_sub +atomic_sub_explicit :: intrinsics.atomic_sub_explicit +atomic_and :: intrinsics.atomic_and +atomic_and_explicit :: intrinsics.atomic_and_explicit +atomic_nand :: intrinsics.atomic_nand +atomic_nand_explicit :: intrinsics.atomic_nand_explicit +atomic_or :: intrinsics.atomic_or +atomic_or_explicit :: intrinsics.atomic_or_explicit +atomic_xor :: intrinsics.atomic_xor +atomic_xor_explicit :: intrinsics.atomic_xor_explicit +atomic_exchange :: intrinsics.atomic_exchange +atomic_exchange_explicit :: intrinsics.atomic_exchange_explicit // Returns value and optional ok boolean -atomic_compare_exchange_strong :: intrinsics.atomic_cxchg -atomic_compare_exchange_strong_acquire :: intrinsics.atomic_cxchg_acq -atomic_compare_exchange_strong_release :: intrinsics.atomic_cxchg_rel -atomic_compare_exchange_strong_acqrel :: intrinsics.atomic_cxchg_acqrel -atomic_compare_exchange_strong_relaxed :: intrinsics.atomic_cxchg_relaxed -atomic_compare_exchange_strong_failrelaxed :: intrinsics.atomic_cxchg_failrelaxed -atomic_compare_exchange_strong_failacquire :: intrinsics.atomic_cxchg_failacq -atomic_compare_exchange_strong_acquire_failrelaxed :: intrinsics.atomic_cxchg_acq_failrelaxed -atomic_compare_exchange_strong_acqrel_failrelaxed :: intrinsics.atomic_cxchg_acqrel_failrelaxed - -// Returns value and optional ok boolean -atomic_compare_exchange_weak :: intrinsics.atomic_cxchgweak -atomic_compare_exchange_weak_acquire :: intrinsics.atomic_cxchgweak_acq -atomic_compare_exchange_weak_release :: intrinsics.atomic_cxchgweak_rel -atomic_compare_exchange_weak_acqrel :: intrinsics.atomic_cxchgweak_acqrel -atomic_compare_exchange_weak_relaxed :: intrinsics.atomic_cxchgweak_relaxed -atomic_compare_exchange_weak_failrelaxed :: intrinsics.atomic_cxchgweak_failrelaxed -atomic_compare_exchange_weak_failacquire :: intrinsics.atomic_cxchgweak_failacq -atomic_compare_exchange_weak_acquire_failrelaxed :: intrinsics.atomic_cxchgweak_acq_failrelaxed -atomic_compare_exchange_weak_acqrel_failrelaxed :: intrinsics.atomic_cxchgweak_acqrel_failrelaxed +atomic_compare_exchange_strong :: intrinsics.atomic_compare_exchange_strong +atomic_compare_exchange_strong_explicit :: intrinsics.atomic_compare_exchange_strong_explicit +atomic_compare_exchange_weak :: intrinsics.atomic_compare_exchange_weak +atomic_compare_exchange_weak_explicit :: intrinsics.atomic_compare_exchange_weak_explicit \ No newline at end of file diff --git a/core/sync/extended.odin b/core/sync/extended.odin index deb48a22d..7da5d2d8c 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -146,10 +146,10 @@ Auto_Reset_Event :: struct { } auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) { - old_status := atomic_load_relaxed(&e.status) + old_status := atomic_load_explicit(&e.status, .seq_cst) for { new_status := old_status + 1 if old_status < 1 else 1 - if _, ok := atomic_compare_exchange_weak_release(&e.status, old_status, new_status); ok { + if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .seq_cst, .seq_cst); ok { break } @@ -160,7 +160,7 @@ auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) { } auto_reset_event_wait :: proc(e: ^Auto_Reset_Event) { - old_status := atomic_sub_acquire(&e.status, 1) + old_status := atomic_sub_explicit(&e.status, 1, .acquire) if old_status < 1 { sema_wait(&e.sema) } @@ -174,14 +174,14 @@ Ticket_Mutex :: struct { } ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) { - ticket := atomic_add_relaxed(&m.ticket, 1) - for ticket != atomic_load_acquire(&m.serving) { + ticket := atomic_add_explicit(&m.ticket, 1, .relaxed) + for ticket != atomic_load_explicit(&m.serving, .acquire) { cpu_relax() } } ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) { - atomic_add_relaxed(&m.serving, 1) + atomic_add_explicit(&m.serving, 1, .relaxed) } @(deferred_in=ticket_mutex_unlock) ticket_mutex_guard :: proc(m: ^Ticket_Mutex) -> bool { @@ -196,18 +196,18 @@ Benaphore :: struct { } benaphore_lock :: proc(b: ^Benaphore) { - if atomic_add_acquire(&b.counter, 1) > 1 { + if atomic_add_explicit(&b.counter, 1, .acquire) > 1 { sema_wait(&b.sema) } } benaphore_try_lock :: proc(b: ^Benaphore) -> bool { - v, _ := atomic_compare_exchange_strong_acquire(&b.counter, 1, 0) + v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .acquire, .acquire) return v == 0 } benaphore_unlock :: proc(b: ^Benaphore) { - if atomic_sub_release(&b.counter, 1) > 0 { + if atomic_sub_explicit(&b.counter, 1, .release) > 0 { sema_post(&b.sema) } } @@ -227,7 +227,7 @@ Recursive_Benaphore :: struct { recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) { tid := current_thread_id() - if atomic_add_acquire(&b.counter, 1) > 1 { + if atomic_add_explicit(&b.counter, 1, .acquire) > 1 { if tid != b.owner { sema_wait(&b.sema) } @@ -240,10 +240,10 @@ recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) { recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool { tid := current_thread_id() if b.owner == tid { - atomic_add_acquire(&b.counter, 1) + atomic_add_explicit(&b.counter, 1, .acquire) } - if v, _ := atomic_compare_exchange_strong_acquire(&b.counter, 1, 0); v != 0 { + if v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .acquire, .acquire); v != 0 { return false } // inside the lock @@ -260,7 +260,7 @@ recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) { if recursion == 0 { b.owner = 0 } - if atomic_sub_release(&b.counter, 1) > 0 { + if atomic_sub_explicit(&b.counter, 1, .release) > 0 { if recursion == 0 { sema_post(&b.sema) } @@ -293,12 +293,12 @@ once_do :: proc(o: ^Once, fn: proc()) { defer mutex_unlock(&o.m) if !o.done { fn() - atomic_store_release(&o.done, true) + atomic_store_explicit(&o.done, true, .release) } } - if atomic_load_acquire(&o.done) == false { + if atomic_load_explicit(&o.done, .acquire) == false { do_slow(o, fn) } } diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index dd082029b..8cec36602 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -24,7 +24,7 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) { new_state := curr_state // Make a copy of it spin_lock: for spin in 0.. bool { - _, ok := atomic_compare_exchange_strong_acquire(&m.state, .Unlocked, .Locked) + _, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .acquire, .acquire) return ok } @@ -290,7 +290,7 @@ Queue_Item :: struct { @(private="file") queue_item_wait :: proc(item: ^Queue_Item) { - for atomic_load_acquire(&item.futex) == 0 { + for atomic_load_explicit(&item.futex, .acquire) == 0 { futex_wait(&item.futex, 0) cpu_relax() } @@ -298,7 +298,7 @@ queue_item_wait :: proc(item: ^Queue_Item) { @(private="file") queue_item_wait_with_timeout :: proc(item: ^Queue_Item, duration: time.Duration) -> bool { start := time.tick_now() - for atomic_load_acquire(&item.futex) == 0 { + for atomic_load_explicit(&item.futex, .acquire) == 0 { remaining := duration - time.tick_since(start) if remaining < 0 { return false @@ -312,7 +312,7 @@ queue_item_wait_with_timeout :: proc(item: ^Queue_Item, duration: time.Duration) } @(private="file") queue_item_signal :: proc(item: ^Queue_Item) { - atomic_store_release(&item.futex, 1) + atomic_store_explicit(&item.futex, 1, .release) futex_signal(&item.futex) } diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin index eb692c6ae..f7516931b 100644 --- a/core/sync/primitives_internal.odin +++ b/core/sync/primitives_internal.odin @@ -10,7 +10,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { tid := Futex(current_thread_id()) for { - prev_owner := atomic_compare_exchange_strong_acquire(&m.impl.owner, tid, 0) + prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .acquire, .acquire) switch prev_owner { case 0, tid: m.impl.recursion += 1 @@ -27,7 +27,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { if m.impl.recursion != 0 { return } - atomic_exchange_release(&m.impl.owner, 0) + atomic_exchange_explicit(&m.impl.owner, 0, .release) futex_signal(&m.impl.owner) // outside the lock @@ -36,7 +36,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { tid := Futex(current_thread_id()) - prev_owner := atomic_compare_exchange_strong_acquire(&m.impl.owner, tid, 0) + prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .acquire, .acquire) switch prev_owner { case 0, tid: m.impl.recursion += 1 diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin index 560f23956..e812c410a 100644 --- a/core/testing/runner_windows.odin +++ b/core/testing/runner_windows.odin @@ -21,7 +21,7 @@ sema_wait :: proc "contextless" (s: ^Sema) { win32.WaitOnAddress(&s.count, &original_count, size_of(original_count), win32.INFINITE) original_count = s.count } - if original_count == intrinsics.atomic_cxchg(&s.count, original_count-1, original_count) { + if original_count == intrinsics.atomic_compare_exchange_strong(&s.count, original_count-1, original_count) { return } } @@ -46,7 +46,7 @@ sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) } original_count = s.count } - if original_count == intrinsics.atomic_cxchg(&s.count, original_count-1, original_count) { + if original_count == intrinsics.atomic_compare_exchange_strong(&s.count, original_count-1, original_count) { return true } } From 6bc0c611abf9426815207d06c8f1d922533b278b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 00:49:53 +0100 Subject: [PATCH 0468/1052] Enforce success failure pairings of `compare_exchange_*_explicit` at compile time --- core/sync/primitives_atomic.odin | 2 +- src/check_builtin.cpp | 92 +++++++++++++++++++++++++++++--- src/types.cpp | 13 ++++- 3 files changed, 97 insertions(+), 10 deletions(-) diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index 8cec36602..dd432745f 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -77,7 +77,7 @@ atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) { // atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> bool { - _, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .acquire, .acquire) + _, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .acquire, .consume) return ok } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 3fe0f1048..a82577b31 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -379,7 +379,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } } -bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, char const *extra_message = nullptr) { +bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, OdinAtomicMemoryOrder *memory_order_, char const *extra_message = nullptr) { Operand x = {}; check_expr_with_type_hint(c, &x, expr, t_atomic_memory_order); if (x.mode == Addressing_Invalid) { @@ -400,6 +400,9 @@ bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String con error(x.expr, "Illegal Atomic_Memory_Order value, got %lld", cast(long long)value); return false; } + if (memory_order_) { + *memory_order_ = cast(OdinAtomicMemoryOrder)value; + } return true; @@ -3232,7 +3235,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_atomic_thread_fence: case BuiltinProc_atomic_signal_fence: - if (!check_atomic_memory_order_argument(c, ce->args[0], builtin_name)) { + if (!check_atomic_memory_order_argument(c, ce->args[0], builtin_name, nullptr)) { return false; } operand->mode = Addressing_NoValue; @@ -3269,9 +3272,17 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 check_expr_with_type_hint(c, &x, ce->args[1], elem); check_assignment(c, &x, elem, builtin_name); - if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name)) { + OdinAtomicMemoryOrder memory_order = {}; + if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name, &memory_order)) { return false; } + switch (memory_order) { + case OdinAtomicMemoryOrder_consume: + case OdinAtomicMemoryOrder_acquire: + case OdinAtomicMemoryOrder_acq_rel: + error(ce->args[2], "Illegal memory order .%s for %.*s", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name)); + break; + } operand->type = nullptr; operand->mode = Addressing_NoValue; @@ -3303,10 +3314,18 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } - if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name)) { + OdinAtomicMemoryOrder memory_order = {}; + if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name, &memory_order)) { return false; } + switch (memory_order) { + case OdinAtomicMemoryOrder_release: + case OdinAtomicMemoryOrder_acq_rel: + error(ce->args[1], "Illegal memory order .%s for %.*s", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name)); + break; + } + operand->type = elem; operand->mode = Addressing_Value; break; @@ -3352,7 +3371,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 check_assignment(c, &x, elem, builtin_name); - if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name)) { + if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name, nullptr)) { return false; } @@ -3396,13 +3415,72 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 check_assignment(c, &x, elem, builtin_name); check_assignment(c, &y, elem, builtin_name); - if (!check_atomic_memory_order_argument(c, ce->args[3], builtin_name, "success ordering")) { + OdinAtomicMemoryOrder success_memory_order = {}; + OdinAtomicMemoryOrder failure_memory_order = {}; + if (!check_atomic_memory_order_argument(c, ce->args[3], builtin_name, &success_memory_order, "success ordering")) { return false; } - if (!check_atomic_memory_order_argument(c, ce->args[4], builtin_name, "failure ordering")) { + if (!check_atomic_memory_order_argument(c, ce->args[4], builtin_name, &failure_memory_order, "failure ordering")) { return false; } + bool invalid_combination = false; + + switch (success_memory_order) { + case OdinAtomicMemoryOrder_relaxed: + case OdinAtomicMemoryOrder_release: + if (failure_memory_order != OdinAtomicMemoryOrder_relaxed) { + invalid_combination = true; + } + break; + case OdinAtomicMemoryOrder_consume: + switch (failure_memory_order) { + case OdinAtomicMemoryOrder_relaxed: + case OdinAtomicMemoryOrder_consume: + break; + default: + invalid_combination = true; + break; + } + break; + case OdinAtomicMemoryOrder_acquire: + case OdinAtomicMemoryOrder_acq_rel: + switch (failure_memory_order) { + case OdinAtomicMemoryOrder_relaxed: + case OdinAtomicMemoryOrder_consume: + case OdinAtomicMemoryOrder_acquire: + break; + default: + invalid_combination = true; + break; + } + break; + case OdinAtomicMemoryOrder_seq_cst: + switch (failure_memory_order) { + case OdinAtomicMemoryOrder_relaxed: + case OdinAtomicMemoryOrder_consume: + case OdinAtomicMemoryOrder_acquire: + case OdinAtomicMemoryOrder_seq_cst: + break; + default: + invalid_combination = true; + break; + } + break; + default: + invalid_combination = true; + break; + } + + + if (invalid_combination) { + error(ce->args[3], "Illegal memory order pairing for %.*s, success = .%s, failure = .%s", + LIT(builtin_name), + OdinAtomicMemoryOrder_strings[success_memory_order], + OdinAtomicMemoryOrder_strings[failure_memory_order] + ); + } + operand->mode = Addressing_OptionalOk; operand->type = elem; break; diff --git a/src/types.cpp b/src/types.cpp index 25e29820c..16d07d392 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -693,8 +693,8 @@ gb_global Type *t_objc_SEL = nullptr; gb_global Type *t_objc_Class = nullptr; enum OdinAtomicMemoryOrder : i32 { - OdinAtomicMemoryOrder_relaxed = 0, - OdinAtomicMemoryOrder_consume = 1, + OdinAtomicMemoryOrder_relaxed = 0, // unordered + OdinAtomicMemoryOrder_consume = 1, // monotonic OdinAtomicMemoryOrder_acquire = 2, OdinAtomicMemoryOrder_release = 3, OdinAtomicMemoryOrder_acq_rel = 4, @@ -702,6 +702,15 @@ enum OdinAtomicMemoryOrder : i32 { OdinAtomicMemoryOrder_COUNT, }; +char const *OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_COUNT] = { + "relaxed", + "consume", + "acquire", + "release", + "acq_rel", + "seq_cst", +}; + gb_global Type *t_atomic_memory_order = nullptr; From ed6bf280045dff0f60dc4798293645de7ff96610 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 00:53:34 +0100 Subject: [PATCH 0469/1052] Update the intrinsics for documentation on atomics --- core/intrinsics/intrinsics.odin | 97 +++++++++++---------------------- 1 file changed, 32 insertions(+), 65 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 16dd5cbc5..4c1c166e6 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -62,77 +62,44 @@ syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- // Atomics -atomic_fence :: proc() --- -atomic_fence_acq :: proc() --- -atomic_fence_rel :: proc() --- -atomic_fence_acqrel :: proc() --- +Atomic_Memory_Order :: enum { + relaxed = 0, // unordered + consume = 1, // monotonic + acquire = 2, + release = 3, + acq_rel = 4, + seq_cst = 5, +} -atomic_store :: proc(dst: ^$T, val: T) --- -atomic_store_rel :: proc(dst: ^$T, val: T) --- -atomic_store_relaxed :: proc(dst: ^$T, val: T) --- -atomic_store_unordered :: proc(dst: ^$T, val: T) --- +atomic_thread_fence :: proc(order: Atomic_Memory_Order) --- +atomic_signal_fence :: proc(order: Atomic_Memory_Order) --- + +atomic_store :: proc(dst: ^$T, val: T) --- +atomic_store_explicit :: proc(dst: ^$T, val: T, order: Atomic_Memory_Order) --- atomic_load :: proc(dst: ^$T) -> T --- -atomic_load_acq :: proc(dst: ^$T) -> T --- -atomic_load_relaxed :: proc(dst: ^$T) -> T --- -atomic_load_unordered :: proc(dst: ^$T) -> T --- +atomic_load_explicit :: proc(dst: ^$T, order: Atomic_Memory_Order) -> T --- -atomic_add :: proc(dst; ^$T, val: T) -> T --- -atomic_add_acq :: proc(dst; ^$T, val: T) -> T --- -atomic_add_rel :: proc(dst; ^$T, val: T) -> T --- -atomic_add_acqrel :: proc(dst; ^$T, val: T) -> T --- -atomic_add_relaxed :: proc(dst; ^$T, val: T) -> T --- -atomic_sub :: proc(dst; ^$T, val: T) -> T --- -atomic_sub_acq :: proc(dst; ^$T, val: T) -> T --- -atomic_sub_rel :: proc(dst; ^$T, val: T) -> T --- -atomic_sub_acqrel :: proc(dst; ^$T, val: T) -> T --- -atomic_sub_relaxed :: proc(dst; ^$T, val: T) -> T --- -atomic_and :: proc(dst; ^$T, val: T) -> T --- -atomic_and_acq :: proc(dst; ^$T, val: T) -> T --- -atomic_and_rel :: proc(dst; ^$T, val: T) -> T --- -atomic_and_acqrel :: proc(dst; ^$T, val: T) -> T --- -atomic_and_relaxed :: proc(dst; ^$T, val: T) -> T --- -atomic_nand :: proc(dst; ^$T, val: T) -> T --- -atomic_nand_acq :: proc(dst; ^$T, val: T) -> T --- -atomic_nand_rel :: proc(dst; ^$T, val: T) -> T --- -atomic_nand_acqrel :: proc(dst; ^$T, val: T) -> T --- -atomic_nand_relaxed :: proc(dst; ^$T, val: T) -> T --- -atomic_or :: proc(dst; ^$T, val: T) -> T --- -atomic_or_acq :: proc(dst; ^$T, val: T) -> T --- -atomic_or_rel :: proc(dst; ^$T, val: T) -> T --- -atomic_or_acqrel :: proc(dst; ^$T, val: T) -> T --- -atomic_or_relaxed :: proc(dst; ^$T, val: T) -> T --- -atomic_xor :: proc(dst; ^$T, val: T) -> T --- -atomic_xor_acq :: proc(dst; ^$T, val: T) -> T --- -atomic_xor_rel :: proc(dst; ^$T, val: T) -> T --- -atomic_xor_acqrel :: proc(dst; ^$T, val: T) -> T --- -atomic_xor_relaxed :: proc(dst; ^$T, val: T) -> T --- +atomic_add :: proc(dst; ^$T, val: T) -> T --- +atomic_add_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- +atomic_sub :: proc(dst; ^$T, val: T) -> T --- +atomic_sub_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- +atomic_and :: proc(dst; ^$T, val: T) -> T --- +atomic_and_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- +atomic_nand :: proc(dst; ^$T, val: T) -> T --- +atomic_nand_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- +atomic_or :: proc(dst; ^$T, val: T) -> T --- +atomic_or_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- +atomic_xor :: proc(dst; ^$T, val: T) -> T --- +atomic_xor_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- +atomic_exchange :: proc(dst; ^$T, val: T) -> T --- +atomic_exchange_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T --- -atomic_xchg :: proc(dst; ^$T, val: T) -> T --- -atomic_xchg_acq :: proc(dst; ^$T, val: T) -> T --- -atomic_xchg_rel :: proc(dst; ^$T, val: T) -> T --- -atomic_xchg_acqrel :: proc(dst; ^$T, val: T) -> T --- -atomic_xchg_relaxed :: proc(dst; ^$T, val: T) -> T --- +atomic_compare_exchange_strong :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- +atomic_compare_exchange_strong_explicit :: proc(dst: ^$T, old, new: T, success, failure: Atomic_Memory_Order) -> (T, bool) #optional_ok --- +atomic_compare_exchange_weak :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- +atomic_compare_exchange_weak_explicit :: proc(dst: ^$T, old, new: T, success, failure: Atomic_Memory_Order) -> (T, bool) #optional_ok --- -atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- - -atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- -atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok --- // Constant type tests From 6636376a81371506d61d24aa2ea3264b6e47edcb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 00:58:01 +0100 Subject: [PATCH 0470/1052] Correct weak handling --- src/llvm_backend_proc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ad82b79e5..4de2af9d8 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1738,7 +1738,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } // TODO(bill): Figure out how to make it weak - LLVMBool single_threaded = weak; + LLVMBool single_threaded = false; LLVMValueRef value = LLVMBuildAtomicCmpXchg( p->builder, address.value, @@ -1747,6 +1747,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, failure_ordering, single_threaded ); + LLVMSetWeak(value, weak); if (tv.type->kind == Type_Tuple) { Type *fix_typed = alloc_type_tuple(); From 1eac3482a68b66978a62fd397e0b9d53ca32d053 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 01:01:51 +0100 Subject: [PATCH 0471/1052] Add checks for memory ordering on fences --- core/c/libc/stdatomic.odin | 12 ++++++------ src/check_builtin.cpp | 26 ++++++++++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/core/c/libc/stdatomic.odin b/core/c/libc/stdatomic.odin index a5dd78afc..26ea0db5e 100644 --- a/core/c/libc/stdatomic.odin +++ b/core/c/libc/stdatomic.odin @@ -47,9 +47,9 @@ kill_dependency :: #force_inline proc(value: $T) -> T { // 7.17.4 Fences atomic_thread_fence :: #force_inline proc(order: memory_order) { - switch order { - case .relaxed: intrinsics.atomic_thread_fence(.relaxed) - case .consume: intrinsics.atomic_thread_fence(.consume) + assert(order != .relaxed) + assert(order != .consume) + #partial switch order { case .acquire: intrinsics.atomic_thread_fence(.acquire) case .release: intrinsics.atomic_thread_fence(.release) case .acq_rel: intrinsics.atomic_thread_fence(.acq_rel) @@ -58,9 +58,9 @@ atomic_thread_fence :: #force_inline proc(order: memory_order) { } atomic_signal_fence :: #force_inline proc(order: memory_order) { - switch order { - case .relaxed: intrinsics.atomic_signal_fence(.relaxed) - case .consume: intrinsics.atomic_signal_fence(.consume) + assert(order != .relaxed) + assert(order != .consume) + #partial switch order { case .acquire: intrinsics.atomic_signal_fence(.acquire) case .release: intrinsics.atomic_signal_fence(.release) case .acq_rel: intrinsics.atomic_signal_fence(.acq_rel) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a82577b31..8b8814176 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3235,10 +3235,24 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_atomic_thread_fence: case BuiltinProc_atomic_signal_fence: - if (!check_atomic_memory_order_argument(c, ce->args[0], builtin_name, nullptr)) { - return false; + { + OdinAtomicMemoryOrder memory_order = {}; + if (!check_atomic_memory_order_argument(c, ce->args[0], builtin_name, &memory_order)) { + return false; + } + switch (memory_order) { + case OdinAtomicMemoryOrder_acquire: + case OdinAtomicMemoryOrder_release: + case OdinAtomicMemoryOrder_acq_rel: + case OdinAtomicMemoryOrder_seq_cst: + break; + default: + error(ce->args[0], "Illegal memory ordering for '%.*s', got .%s", LIT(builtin_name), OdinAtomicMemoryOrder_strings[memory_order]); + break; + } + + operand->mode = Addressing_NoValue; } - operand->mode = Addressing_NoValue; break; case BuiltinProc_volatile_store: @@ -3280,7 +3294,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case OdinAtomicMemoryOrder_consume: case OdinAtomicMemoryOrder_acquire: case OdinAtomicMemoryOrder_acq_rel: - error(ce->args[2], "Illegal memory order .%s for %.*s", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name)); + error(ce->args[2], "Illegal memory order .%s for '%.*s'", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name)); break; } @@ -3322,7 +3336,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 switch (memory_order) { case OdinAtomicMemoryOrder_release: case OdinAtomicMemoryOrder_acq_rel: - error(ce->args[1], "Illegal memory order .%s for %.*s", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name)); + error(ce->args[1], "Illegal memory order .%s for '%.*s'", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name)); break; } @@ -3474,7 +3488,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (invalid_combination) { - error(ce->args[3], "Illegal memory order pairing for %.*s, success = .%s, failure = .%s", + error(ce->args[3], "Illegal memory order pairing for '%.*s', success = .%s, failure = .%s", LIT(builtin_name), OdinAtomicMemoryOrder_strings[success_memory_order], OdinAtomicMemoryOrder_strings[failure_memory_order] From b2f5b7353200eb65a6adac8544106222938f302c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 01:05:50 +0100 Subject: [PATCH 0472/1052] Rename package name to `sync` --- core/sync/atomic.odin | 2 +- core/sync/extended.odin | 2 +- core/sync/futex_darwin.odin | 2 +- core/sync/futex_freebsd.odin | 2 +- core/sync/futex_linux.odin | 2 +- core/sync/futex_openbsd.odin | 2 +- core/sync/futex_windows.odin | 2 +- core/sync/primitives.odin | 2 +- core/sync/primitives_atomic.odin | 2 +- core/sync/primitives_darwin.odin | 2 +- core/sync/primitives_freebsd.odin | 2 +- core/sync/primitives_internal.odin | 2 +- core/sync/primitives_linux.odin | 2 +- core/sync/primitives_openbsd.odin | 2 +- core/sync/primitives_pthreads.odin | 2 +- core/sync/primitives_windows.odin | 2 +- core/sync/sema_internal.odin | 2 +- core/sync/sync_util.odin | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index 703393592..d6521daed 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -1,4 +1,4 @@ -package sync2 +package sync import "core:intrinsics" diff --git a/core/sync/extended.odin b/core/sync/extended.odin index 7da5d2d8c..23423e003 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -1,4 +1,4 @@ -package sync2 +package sync import "core:time" diff --git a/core/sync/futex_darwin.odin b/core/sync/futex_darwin.odin index 9dad8d375..88e354827 100644 --- a/core/sync/futex_darwin.odin +++ b/core/sync/futex_darwin.odin @@ -1,6 +1,6 @@ //+private //+build darwin -package sync2 +package sync import "core:c" import "core:time" diff --git a/core/sync/futex_freebsd.odin b/core/sync/futex_freebsd.odin index 2cbdb4aaa..2e1d065bc 100644 --- a/core/sync/futex_freebsd.odin +++ b/core/sync/futex_freebsd.odin @@ -1,6 +1,6 @@ //+private //+build freebsd -package sync2 +package sync import "core:c" import "core:os" diff --git a/core/sync/futex_linux.odin b/core/sync/futex_linux.odin index fca28cace..74f331de7 100644 --- a/core/sync/futex_linux.odin +++ b/core/sync/futex_linux.odin @@ -1,6 +1,6 @@ //+private //+build linux -package sync2 +package sync import "core:c" import "core:time" diff --git a/core/sync/futex_openbsd.odin b/core/sync/futex_openbsd.odin index dbc80747b..6ac9d3efb 100644 --- a/core/sync/futex_openbsd.odin +++ b/core/sync/futex_openbsd.odin @@ -1,6 +1,6 @@ //+private //+build openbsd -package sync2 +package sync import "core:c" import "core:os" diff --git a/core/sync/futex_windows.odin b/core/sync/futex_windows.odin index 200a119ff..1c9d8b845 100644 --- a/core/sync/futex_windows.odin +++ b/core/sync/futex_windows.odin @@ -1,6 +1,6 @@ //+private //+build windows -package sync2 +package sync import "core:time" diff --git a/core/sync/primitives.odin b/core/sync/primitives.odin index 6d056d439..483f85343 100644 --- a/core/sync/primitives.odin +++ b/core/sync/primitives.odin @@ -1,4 +1,4 @@ -package sync2 +package sync import "core:time" diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index dd432745f..401f78b91 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -1,4 +1,4 @@ -package sync2 +package sync import "core:time" diff --git a/core/sync/primitives_darwin.odin b/core/sync/primitives_darwin.odin index 66995bd01..514f66f3e 100644 --- a/core/sync/primitives_darwin.odin +++ b/core/sync/primitives_darwin.odin @@ -1,6 +1,6 @@ //+build darwin //+private -package sync2 +package sync import "core:c" import "core:time" diff --git a/core/sync/primitives_freebsd.odin b/core/sync/primitives_freebsd.odin index 2a25a18a4..e6219acf1 100644 --- a/core/sync/primitives_freebsd.odin +++ b/core/sync/primitives_freebsd.odin @@ -1,6 +1,6 @@ //+build freebsd //+private -package sync2 +package sync import "core:os" diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin index f7516931b..c1a38b4ad 100644 --- a/core/sync/primitives_internal.odin +++ b/core/sync/primitives_internal.odin @@ -1,5 +1,5 @@ //+private -package sync2 +package sync when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _Recursive_Mutex :: struct { diff --git a/core/sync/primitives_linux.odin b/core/sync/primitives_linux.odin index 89ed97985..1e75891df 100644 --- a/core/sync/primitives_linux.odin +++ b/core/sync/primitives_linux.odin @@ -1,6 +1,6 @@ //+build linux //+private -package sync2 +package sync import "core:sys/unix" diff --git a/core/sync/primitives_openbsd.odin b/core/sync/primitives_openbsd.odin index ef122b02e..4072a14e8 100644 --- a/core/sync/primitives_openbsd.odin +++ b/core/sync/primitives_openbsd.odin @@ -1,6 +1,6 @@ //+build openbsd //+private -package sync2 +package sync import "core:os" diff --git a/core/sync/primitives_pthreads.odin b/core/sync/primitives_pthreads.odin index 28053f9cc..581e9feb1 100644 --- a/core/sync/primitives_pthreads.odin +++ b/core/sync/primitives_pthreads.odin @@ -1,6 +1,6 @@ //+build linux, freebsd, openbsd //+private -package sync2 +package sync import "core:time" import "core:sys/unix" diff --git a/core/sync/primitives_windows.odin b/core/sync/primitives_windows.odin index ca7a5c9ee..055167892 100644 --- a/core/sync/primitives_windows.odin +++ b/core/sync/primitives_windows.odin @@ -1,6 +1,6 @@ //+build windows //+private -package sync2 +package sync import "core:time" import win32 "core:sys/windows" diff --git a/core/sync/sema_internal.odin b/core/sync/sema_internal.odin index f4027e908..8cf157708 100644 --- a/core/sync/sema_internal.odin +++ b/core/sync/sema_internal.odin @@ -1,5 +1,5 @@ //+private -package sync2 +package sync import "core:time" diff --git a/core/sync/sync_util.odin b/core/sync/sync_util.odin index 013bf511a..4add9064d 100644 --- a/core/sync/sync_util.odin +++ b/core/sync/sync_util.odin @@ -1,4 +1,4 @@ -package sync2 +package sync /* Example: From 97a183f4127b0cda0fdb3e1af7138def1f01ad18 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 01:13:29 +0100 Subject: [PATCH 0473/1052] Clean up thread_windows.odin --- core/thread/thread_windows.odin | 41 +++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 210c54a96..68382444c 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -3,13 +3,21 @@ package thread import "core:runtime" +import "core:intrinsics" import "core:sync" import win32 "core:sys/windows" +Thread_State :: enum u8 { + Started, + Joined, + Done, +} + Thread_Os_Specific :: struct { win32_thread: win32.HANDLE, win32_thread_id: win32.DWORD, - done: bool, // see note in `is_done` + mutex: sync.Mutex, + flags: bit_set[Thread_State; u8], } _thread_priority_map := [Thread_Priority]i32{ @@ -26,15 +34,16 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ context = t.init_context.? or_else runtime.default_context() t.id = sync.current_thread_id() + t.procedure(t) + intrinsics.atomic_store(&t.flags, t.flags + {.Done}) + if t.init_context == nil { if context.temp_allocator.data == &runtime.global_default_temp_allocator_data { runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data) } } - - sync.atomic_store(&t.done, true) return 0 } @@ -61,23 +70,31 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ return thread } -_start :: proc(thread: ^Thread) { - win32.ResumeThread(thread.win32_thread) +_start :: proc(t: ^Thread) { + sync.guard(&t.mutex) + t.flags += {.Started} + win32.ResumeThread(t.win32_thread) } -_is_done :: proc(using thread: ^Thread) -> bool { +_is_done :: proc(t: ^Thread) -> bool { // NOTE(tetra, 2019-10-31): Apparently using wait_for_single_object and // checking if it didn't time out immediately, is not good enough, // so we do it this way instead. - return sync.atomic_load(&done) + return .Done in sync.atomic_load(&t.flags) } -_join :: proc(using thread: ^Thread) { - if win32_thread != win32.INVALID_HANDLE { - win32.WaitForSingleObject(win32_thread, win32.INFINITE) - win32.CloseHandle(win32_thread) - win32_thread = win32.INVALID_HANDLE +_join :: proc(t: ^Thread) { + sync.guard(&t.mutex) + + if .Joined in t.flags || t.win32_thread == win32.INVALID_HANDLE { + return } + + win32.WaitForSingleObject(t.win32_thread, win32.INFINITE) + win32.CloseHandle(t.win32_thread) + t.win32_thread = win32.INVALID_HANDLE + + t.flags += {.Joined} } _join_multiple :: proc(threads: ..^Thread) { From 94dbac9a647fb050f3a818275111d8f7496ffd37 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 01:13:43 +0100 Subject: [PATCH 0474/1052] Disable thread pool in demo --- examples/demo/demo.odin | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index ee4a2dd2b..9c2732cca 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1145,29 +1145,29 @@ threading_example :: proc() { } } - { // Thread Pool - fmt.println("\n## Thread Pool") - task_proc :: proc(t: ^thread.Task) { - index := t.user_index % len(prefix_table) - for iteration in 1..=5 { - fmt.printf("Worker Task %d is on iteration %d\n", t.user_index, iteration) - fmt.printf("`%s`: iteration %d\n", prefix_table[index], iteration) - time.sleep(1 * time.Millisecond) - } - } + // { // Thread Pool + // fmt.println("\n## Thread Pool") + // task_proc :: proc(t: ^thread.Task) { + // index := t.user_index % len(prefix_table) + // for iteration in 1..=5 { + // fmt.printf("Worker Task %d is on iteration %d\n", t.user_index, iteration) + // fmt.printf("`%s`: iteration %d\n", prefix_table[index], iteration) + // time.sleep(1 * time.Millisecond) + // } + // } - pool: thread.Pool - thread.pool_init(pool=&pool, thread_count=3) - defer thread.pool_destroy(&pool) + // pool: thread.Pool + // thread.pool_init(pool=&pool, thread_count=3) + // defer thread.pool_destroy(&pool) - for i in 0..<30 { - thread.pool_add_task(pool=&pool, procedure=task_proc, data=nil, user_index=i) - } + // for i in 0..<30 { + // thread.pool_add_task(pool=&pool, procedure=task_proc, data=nil, user_index=i) + // } - thread.pool_start(&pool) - thread.pool_wait_and_process(&pool) - } + // thread.pool_start(&pool) + // thread.pool_wait_and_process(&pool) + // } } From 06e8476efc421a27ea8cd908cd5e6d8b319ebf0f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 10:55:18 +0100 Subject: [PATCH 0475/1052] Correct ordering in `auto_reset_event_signal` --- core/sync/extended.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sync/extended.odin b/core/sync/extended.odin index 23423e003..c8ae4493f 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -146,10 +146,10 @@ Auto_Reset_Event :: struct { } auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) { - old_status := atomic_load_explicit(&e.status, .seq_cst) + old_status := atomic_load_explicit(&e.status, .relaxed) for { new_status := old_status + 1 if old_status < 1 else 1 - if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .seq_cst, .seq_cst); ok { + if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .release, .relaxed); ok { break } From 9ea45d35db29e673e11af87cca1334a818a109d9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 31 Mar 2022 12:53:04 +0200 Subject: [PATCH 0476/1052] [ease] Fix `flux_stop`. --- core/math/ease/ease.odin | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/math/ease/ease.odin b/core/math/ease/ease.odin index c61e29367..5a767b5a9 100644 --- a/core/math/ease/ease.odin +++ b/core/math/ease/ease.odin @@ -463,13 +463,13 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float // stop a specific key inside the map // returns true when it successfully removed the key -flux_stop :: proc(flux: ^Flux_Map($T), key: ^f32) -> bool where intrinsics.type_is_float(T) { - if key in flux { - delete_key(flux, key) - return true - } +flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) { + if key in flux.values { + delete_key(&flux.values, key) + return true + } - return false + return false } // returns the amount of time left for the tween animation, if the key exists in the map @@ -480,4 +480,4 @@ flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 { } else { return 0 } -} \ No newline at end of file +} From 22b961ea53a1b9dfbc9218059b8473a0e52ae35c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 11:55:46 +0100 Subject: [PATCH 0477/1052] Update Thread Pool in `core:thread` Thanks to the work of eisbehr --- core/thread/thread_pool.odin | 236 +++++++++++++++++++++++------------ examples/demo/demo.odin | 38 +++--- 2 files changed, 173 insertions(+), 101 deletions(-) diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 97ea2b77d..3f782cf73 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -1,65 +1,75 @@ package thread +/* + thread.Pool + Copyright 2022 eisbehr + Made available under Odin's BSD-3 license. +*/ + import "core:intrinsics" import "core:sync" import "core:mem" -Task_Status :: enum i32 { - Ready, - Busy, - Waiting, - Term, -} - -Task_Proc :: #type proc(task: ^Task) +Task_Proc :: #type proc(task: Task) Task :: struct { - procedure: Task_Proc, - data: rawptr, + procedure: Task_Proc, + data: rawptr, user_index: int, + allocator: mem.Allocator, } -Task_Id :: distinct i32 -INVALID_TASK_ID :: Task_Id(-1) - - +// Do not access the pool's members directly while the pool threads are running, +// since they use different kinds of locking and mutual exclusion devices. +// Careless access can and will lead to nasty bugs. Once initialized, the +// pool's memory address is not allowed to change until it is destroyed. Pool :: struct { - allocator: mem.Allocator, - mutex: sync.Mutex, - sem_available: sync.Sema, - processing_task_count: int, // atomic - is_running: bool, + allocator: mem.Allocator, + mutex: sync.Mutex, + sem_available: sync.Sema, + + // the following values are atomic + num_waiting: int, + num_in_processing: int, + num_outstanding: int, // num_waiting + num_in_processing + num_done: int, + // end of atomics + + is_running: bool, threads: []^Thread, - tasks: [dynamic]Task, + tasks: [dynamic]Task, + tasks_done: [dynamic]Task, } -pool_init :: proc(pool: ^Pool, thread_count: int, allocator := context.allocator) { - worker_thread_internal :: proc(t: ^Thread) { - pool := (^Pool)(t.data) - - for pool.is_running { - sync.sema_wait(&pool.sem_available) - - if task, ok := pool_try_and_pop_task(pool); ok { - pool_do_work(pool, &task) - } - } - - sync.sema_post(&pool.sem_available, 1) - } - - +// Once initialized, the pool's memory address is not allowed to change until +// it is destroyed. If thread_count < 1, thread count 1 will be used. +// +// The thread pool requires an allocator which it either owns, or which is thread safe. +pool_init :: proc(pool: ^Pool, thread_count: int, allocator: mem.Allocator) { context.allocator = allocator pool.allocator = allocator - pool.tasks = make([dynamic]Task) - pool.threads = make([]^Thread, thread_count) + pool.tasks = make([dynamic]Task) + pool.tasks_done = make([dynamic]Task) + pool.threads = make([]^Thread, max(thread_count, 1)) pool.is_running = true for _, i in pool.threads { - t := create(worker_thread_internal) + t := create(proc(t: ^Thread) { + pool := (^Pool)(t.data) + + for intrinsics.atomic_load(&pool.is_running) { + sync.wait(&pool.sem_available) + + if task, ok := pool_pop_waiting(pool); ok { + pool_do_work(pool, task) + } + } + + sync.post(&pool.sem_available, 1) + }) t.user_index = i t.data = pool pool.threads[i] = t @@ -68,9 +78,10 @@ pool_init :: proc(pool: ^Pool, thread_count: int, allocator := context.allocator pool_destroy :: proc(pool: ^Pool) { delete(pool.tasks) + delete(pool.tasks_done) - for thread in &pool.threads { - destroy(thread) + for t in &pool.threads { + destroy(t) } delete(pool.threads, pool.allocator) @@ -82,10 +93,12 @@ pool_start :: proc(pool: ^Pool) { } } +// Finish tasks that have already started processing, then shut down all pool +// threads. Might leave over waiting tasks, any memory allocated for the +// user data of those tasks will not be freed. pool_join :: proc(pool: ^Pool) { - pool.is_running = false - - sync.sema_post(&pool.sem_available, len(pool.threads)) + intrinsics.atomic_store(&pool.is_running, false) + sync.post(&pool.sem_available, len(pool.threads)) yield() @@ -94,53 +107,112 @@ pool_join :: proc(pool: ^Pool) { } } -pool_add_task :: proc(pool: ^Pool, procedure: Task_Proc, data: rawptr, user_index: int = 0) { - sync.mutex_lock(&pool.mutex) - defer sync.mutex_unlock(&pool.mutex) +// Add a task to the thread pool. +// +// Tasks can be added from any thread, not just the thread that created +// the thread pool. You can even add tasks from inside other tasks. +// +// Each task also needs an allocator which it either owns, or which is thread +// safe. By default, allocations in the task are disabled by use of the +// nil_allocator. +pool_add_task :: proc(pool: ^Pool, procedure: Task_Proc, data: rawptr, user_index: int = 0, allocator := context.allocator) { + sync.guard(&pool.mutex) - task: Task - task.procedure = procedure - task.data = data - task.user_index = user_index - - append(&pool.tasks, task) - sync.sema_post(&pool.sem_available, 1) + append(&pool.tasks, Task{ + procedure = procedure, + data = data, + user_index = user_index, + allocator = allocator, + }) + intrinsics.atomic_add(&pool.num_waiting, 1) + intrinsics.atomic_add(&pool.num_outstanding, 1) + sync.post(&pool.sem_available, 1) } -pool_try_and_pop_task :: proc(pool: ^Pool) -> (task: Task, got_task: bool = false) { - if sync.mutex_try_lock(&pool.mutex) { - if len(pool.tasks) != 0 { - intrinsics.atomic_add(&pool.processing_task_count, 1) - task = pop_front(&pool.tasks) - got_task = true - } - sync.mutex_unlock(&pool.mutex) +// Number of tasks waiting to be processed. Only informational, mostly for +// debugging. Don't rely on this value being consistent with other num_* +// values. +pool_num_waiting :: #force_inline proc(pool: ^Pool) -> int { + return intrinsics.atomic_load(&pool.num_waiting) +} + +// Number of tasks currently being processed. Only informational, mostly for +// debugging. Don't rely on this value being consistent with other num_* +// values. +pool_num_in_processing :: #force_inline proc(pool: ^Pool) -> int { + return intrinsics.atomic_load(&pool.num_in_processing) +} + +// Outstanding tasks are all tasks that are not done, that is, tasks that are +// waiting, as well as tasks that are currently being processed. Only +// informational, mostly for debugging. Don't rely on this value being +// consistent with other num_* values. +pool_num_outstanding :: #force_inline proc(pool: ^Pool) -> int { + return intrinsics.atomic_load(&pool.num_outstanding) +} + +// Number of tasks which are done processing. Only informational, mostly for +// debugging. Don't rely on this value being consistent with other num_* +// values. +pool_num_done :: #force_inline proc(pool: ^Pool) -> int { + return intrinsics.atomic_load(&pool.num_done) +} + +// If tasks are only being added from one thread, and this procedure is being +// called from that same thread, it will reliably tell if the thread pool is +// empty or not. Empty in this case means there are no tasks waiting, being +// processed, or _done_. +pool_is_empty :: #force_inline proc(pool: ^Pool) -> bool { + return pool_num_outstanding(pool) == 0 && pool_num_done(pool) == 0 +} + +// Mostly for internal use. +pool_pop_waiting :: proc(pool: ^Pool) -> (task: Task, got_task: bool) { + sync.guard(&pool.mutex) + + if len(pool.tasks) != 0 { + intrinsics.atomic_sub(&pool.num_waiting, 1) + intrinsics.atomic_add(&pool.num_in_processing, 1) + task = pop_front(&pool.tasks) + got_task = true } + return } +// Use this to take out finished tasks. +pool_pop_done :: proc(pool: ^Pool) -> (task: Task, got_task: bool) { + sync.guard(&pool.mutex) -pool_do_work :: proc(pool: ^Pool, task: ^Task) { - task.procedure(task) - intrinsics.atomic_sub(&pool.processing_task_count, 1) -} - - -pool_wait_and_process :: proc(pool: ^Pool) { - for len(pool.tasks) != 0 || intrinsics.atomic_load(&pool.processing_task_count) != 0 { - if task, ok := pool_try_and_pop_task(pool); ok { - pool_do_work(pool, &task) - } - - // Safety kick - if len(pool.tasks) != 0 && intrinsics.atomic_load(&pool.processing_task_count) == 0 { - sync.mutex_lock(&pool.mutex) - sync.sema_post(&pool.sem_available, len(pool.tasks)) - sync.mutex_unlock(&pool.mutex) - } - - yield() + if len(pool.tasks_done) != 0 { + task = pop_front(&pool.tasks_done) + got_task = true + intrinsics.atomic_sub(&pool.num_done, 1) } + return +} + +// Mostly for internal use. +pool_do_work :: proc(pool: ^Pool, task: Task) { + { + context.allocator = task.allocator + task.procedure(task) + } + + sync.guard(&pool.mutex) + + append(&pool.tasks_done, task) + intrinsics.atomic_add(&pool.num_done, 1) + intrinsics.atomic_sub(&pool.num_outstanding, 1) + intrinsics.atomic_sub(&pool.num_in_processing, 1) +} + +// Process the rest of the tasks, also use this thread for processing, then join +// all the pool threads. +pool_finish :: proc(pool: ^Pool) { + for task in pool_pop_waiting(pool) { + pool_do_work(pool, task) + } pool_join(pool) } diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 9c2732cca..b3ce3ade9 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1145,29 +1145,29 @@ threading_example :: proc() { } } - // { // Thread Pool - // fmt.println("\n## Thread Pool") - // task_proc :: proc(t: ^thread.Task) { - // index := t.user_index % len(prefix_table) - // for iteration in 1..=5 { - // fmt.printf("Worker Task %d is on iteration %d\n", t.user_index, iteration) - // fmt.printf("`%s`: iteration %d\n", prefix_table[index], iteration) - // time.sleep(1 * time.Millisecond) - // } - // } + { // Thread Pool + fmt.println("\n## Thread Pool") + task_proc :: proc(t: thread.Task) { + index := t.user_index % len(prefix_table) + for iteration in 1..=5 { + fmt.printf("Worker Task %d is on iteration %d\n", t.user_index, iteration) + fmt.printf("`%s`: iteration %d\n", prefix_table[index], iteration) + time.sleep(1 * time.Millisecond) + } + } - // pool: thread.Pool - // thread.pool_init(pool=&pool, thread_count=3) - // defer thread.pool_destroy(&pool) + pool: thread.Pool + thread.pool_init(pool=&pool, thread_count=3, allocator=context.allocator) + defer thread.pool_destroy(&pool) - // for i in 0..<30 { - // thread.pool_add_task(pool=&pool, procedure=task_proc, data=nil, user_index=i) - // } + for i in 0..<30 { + thread.pool_add_task(pool=&pool, procedure=task_proc, data=nil, user_index=i) + } - // thread.pool_start(&pool) - // thread.pool_wait_and_process(&pool) - // } + thread.pool_start(&pool) + thread.pool_finish(&pool) + } } From 9f2d710c357f9d1ca28c169269a9816e1788d1b1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 12:57:24 +0100 Subject: [PATCH 0478/1052] Change `intrinsics.Atomic_Memory_Order` fields to use `Ada_Case` rather than `snake_case` --- core/c/libc/stdatomic.odin | 150 ++++++++++++++--------------- core/intrinsics/intrinsics.odin | 12 +-- core/mem/mem.odin | 2 +- core/sync/atomic.odin | 12 +-- core/sync/extended.odin | 30 +++--- core/sync/primitives_atomic.odin | 16 +-- core/sync/primitives_internal.odin | 6 +- src/checker.cpp | 12 +-- src/types.cpp | 12 +-- 9 files changed, 126 insertions(+), 126 deletions(-) diff --git a/core/c/libc/stdatomic.odin b/core/c/libc/stdatomic.odin index 26ea0db5e..9de3c4678 100644 --- a/core/c/libc/stdatomic.odin +++ b/core/c/libc/stdatomic.odin @@ -50,10 +50,10 @@ atomic_thread_fence :: #force_inline proc(order: memory_order) { assert(order != .relaxed) assert(order != .consume) #partial switch order { - case .acquire: intrinsics.atomic_thread_fence(.acquire) - case .release: intrinsics.atomic_thread_fence(.release) - case .acq_rel: intrinsics.atomic_thread_fence(.acq_rel) - case .seq_cst: intrinsics.atomic_thread_fence(.seq_cst) + case .acquire: intrinsics.atomic_thread_fence(.Acquire) + case .release: intrinsics.atomic_thread_fence(.Release) + case .acq_rel: intrinsics.atomic_thread_fence(.Acq_Rel) + case .seq_cst: intrinsics.atomic_thread_fence(.Seq_Cst) } } @@ -61,10 +61,10 @@ atomic_signal_fence :: #force_inline proc(order: memory_order) { assert(order != .relaxed) assert(order != .consume) #partial switch order { - case .acquire: intrinsics.atomic_signal_fence(.acquire) - case .release: intrinsics.atomic_signal_fence(.release) - case .acq_rel: intrinsics.atomic_signal_fence(.acq_rel) - case .seq_cst: intrinsics.atomic_signal_fence(.seq_cst) + case .acquire: intrinsics.atomic_signal_fence(.Acquire) + case .release: intrinsics.atomic_signal_fence(.Release) + case .acq_rel: intrinsics.atomic_signal_fence(.Acq_Rel) + case .seq_cst: intrinsics.atomic_signal_fence(.Seq_Cst) } } @@ -123,9 +123,9 @@ atomic_store_explicit :: #force_inline proc(object: ^$T, desired: T, order: memo assert(order != .acq_rel) #partial switch order { - case .relaxed: intrinsics.atomic_store_explicit(object, desired, .relaxed) - case .release: intrinsics.atomic_store_explicit(object, desired, .release) - case .seq_cst: intrinsics.atomic_store_explicit(object, desired, .seq_cst) + case .relaxed: intrinsics.atomic_store_explicit(object, desired, .Relaxed) + case .release: intrinsics.atomic_store_explicit(object, desired, .Release) + case .seq_cst: intrinsics.atomic_store_explicit(object, desired, .Seq_Cst) } } @@ -138,10 +138,10 @@ atomic_load_explicit :: #force_inline proc(object: ^$T, order: memory_order) { assert(order != .acq_rel) #partial switch order { - case .relaxed: return intrinsics.atomic_load_explicit(object, .relaxed) - case .consume: return intrinsics.atomic_load_explicit(object, .consume) - case .acquire: return intrinsics.atomic_load_explicit(object, .acquire) - case .seq_cst: return intrinsics.atomic_load_explicit(object, .seq_cst) + case .relaxed: return intrinsics.atomic_load_explicit(object, .Relaxed) + case .consume: return intrinsics.atomic_load_explicit(object, .Consume) + case .acquire: return intrinsics.atomic_load_explicit(object, .Acquire) + case .seq_cst: return intrinsics.atomic_load_explicit(object, .Seq_Cst) } } @@ -151,12 +151,12 @@ atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T { atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T { switch order { - case .relaxed: return intrinsics.atomic_exchange_explicit(object, desired, .relaxed) - case .consume: return intrinsics.atomic_exchange_explicit(object, desired, .consume) - case .acquire: return intrinsics.atomic_exchange_explicit(object, desired, .acquire) - case .release: return intrinsics.atomic_exchange_explicit(object, desired, .release) - case .acq_rel: return intrinsics.atomic_exchange_explicit(object, desired, .acq_rel) - case .seq_cst: return intrinsics.atomic_exchange_explicit(object, desired, .seq_cst) + case .relaxed: return intrinsics.atomic_exchange_explicit(object, desired, .Relaxed) + case .consume: return intrinsics.atomic_exchange_explicit(object, desired, .Consume) + case .acquire: return intrinsics.atomic_exchange_explicit(object, desired, .Acquire) + case .release: return intrinsics.atomic_exchange_explicit(object, desired, .Release) + case .acq_rel: return intrinsics.atomic_exchange_explicit(object, desired, .Acq_Rel) + case .seq_cst: return intrinsics.atomic_exchange_explicit(object, desired, .Seq_Cst) } return false } @@ -193,36 +193,36 @@ atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: assert(success != .relaxed) #partial switch success { case .seq_cst: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst) case .acquire: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acquire, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Seq_Cst) case .consume: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .consume, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Seq_Cst) case .release: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .release, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Release, .Seq_Cst) case .acq_rel: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acq_rel, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst) } case .relaxed: assert(success != .release) #partial switch success { case .relaxed: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .relaxed, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Relaxed, .Relaxed) case .seq_cst: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Relaxed) case .acquire: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acquire, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Relaxed) case .consume: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .consume, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Relaxed) case .acq_rel: - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .acq_rel, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Relaxed) } case .consume: assert(success == .seq_cst) - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .consume) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Consume) case .acquire: assert(success == .seq_cst) - value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .seq_cst, .acquire) + value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Acquire) } if !ok { expected^ = value } @@ -245,36 +245,36 @@ atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$ assert(success != .relaxed) #partial switch success { case .seq_cst: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst) case .acquire: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acquire, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Seq_Cst) case .consume: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .consume, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Seq_Cst) case .release: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .release, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Release, .Seq_Cst) case .acq_rel: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acq_rel, .seq_cst) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst) } case .relaxed: assert(success != .release) #partial switch success { case .relaxed: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .relaxed, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Relaxed, .Relaxed) case .seq_cst: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Relaxed) case .acquire: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acquire, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Relaxed) case .consume: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .consume, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Relaxed) case .acq_rel: - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .acq_rel, .relaxed) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Relaxed) } case .consume: assert(success == .seq_cst) - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .consume) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Consume) case .acquire: assert(success == .seq_cst) - value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .seq_cst, .acquire) + value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Acquire) } if !ok { expected^ = value } @@ -288,13 +288,13 @@ atomic_fetch_add :: #force_inline proc(object: ^$T, operand: T) -> T { atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { switch order { - case .relaxed: return intrinsics.atomic_add_explicit(object, operand, .relaxed) - case .consume: return intrinsics.atomic_add_explicit(object, operand, .consume) - case .acquire: return intrinsics.atomic_add_explicit(object, operand, .acquire) - case .release: return intrinsics.atomic_add_explicit(object, operand, .release) - case .acq_rel: return intrinsics.atomic_add_explicit(object, operand, .acq_rel) + case .relaxed: return intrinsics.atomic_add_explicit(object, operand, .Relaxed) + case .consume: return intrinsics.atomic_add_explicit(object, operand, .Consume) + case .acquire: return intrinsics.atomic_add_explicit(object, operand, .Acquire) + case .release: return intrinsics.atomic_add_explicit(object, operand, .Release) + case .acq_rel: return intrinsics.atomic_add_explicit(object, operand, .Acq_Rel) case: fallthrough - case .seq_cst: return intrinsics.atomic_add_explicit(object, operand, .seq_cst) + case .seq_cst: return intrinsics.atomic_add_explicit(object, operand, .Seq_Cst) } } @@ -304,13 +304,13 @@ atomic_fetch_sub :: #force_inline proc(object: ^$T, operand: T) -> T { atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { switch order { - case .relaxed: return intrinsics.atomic_sub_explicit(object, operand, .relaxed) - case .consume: return intrinsics.atomic_sub_explicit(object, operand, .consume) - case .acquire: return intrinsics.atomic_sub_explicit(object, operand, .acquire) - case .release: return intrinsics.atomic_sub_explicit(object, operand, .release) - case .acq_rel: return intrinsics.atomic_sub_explicit(object, operand, .acq_rel) + case .relaxed: return intrinsics.atomic_sub_explicit(object, operand, .Relaxed) + case .consume: return intrinsics.atomic_sub_explicit(object, operand, .Consume) + case .acquire: return intrinsics.atomic_sub_explicit(object, operand, .Acquire) + case .release: return intrinsics.atomic_sub_explicit(object, operand, .Release) + case .acq_rel: return intrinsics.atomic_sub_explicit(object, operand, .Acq_Rel) case: fallthrough - case .seq_cst: return intrinsics.atomic_sub_explicit(object, operand, .seq_cst) + case .seq_cst: return intrinsics.atomic_sub_explicit(object, operand, .Seq_Cst) } } @@ -320,13 +320,13 @@ atomic_fetch_or :: #force_inline proc(object: ^$T, operand: T) -> T { atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { switch order { - case .relaxed: return intrinsics.atomic_or_explicit(object, operand, .relaxed) - case .consume: return intrinsics.atomic_or_explicit(object, operand, .consume) - case .acquire: return intrinsics.atomic_or_explicit(object, operand, .acquire) - case .release: return intrinsics.atomic_or_explicit(object, operand, .release) - case .acq_rel: return intrinsics.atomic_or_explicit(object, operand, .acq_rel) + case .relaxed: return intrinsics.atomic_or_explicit(object, operand, .Relaxed) + case .consume: return intrinsics.atomic_or_explicit(object, operand, .Consume) + case .acquire: return intrinsics.atomic_or_explicit(object, operand, .Acquire) + case .release: return intrinsics.atomic_or_explicit(object, operand, .Release) + case .acq_rel: return intrinsics.atomic_or_explicit(object, operand, .Acq_Rel) case: fallthrough - case .seq_cst: return intrinsics.atomic_or_explicit(object, operand, .seq_cst) + case .seq_cst: return intrinsics.atomic_or_explicit(object, operand, .Seq_Cst) } } @@ -336,13 +336,13 @@ atomic_fetch_xor :: #force_inline proc(object: ^$T, operand: T) -> T { atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { switch order { - case .relaxed: return intrinsics.atomic_xor_explicit(object, operand, .relaxed) - case .consume: return intrinsics.atomic_xor_explicit(object, operand, .consume) - case .acquire: return intrinsics.atomic_xor_explicit(object, operand, .acquire) - case .release: return intrinsics.atomic_xor_explicit(object, operand, .release) - case .acq_rel: return intrinsics.atomic_xor_explicit(object, operand, .acq_rel) + case .relaxed: return intrinsics.atomic_xor_explicit(object, operand, .Relaxed) + case .consume: return intrinsics.atomic_xor_explicit(object, operand, .Consume) + case .acquire: return intrinsics.atomic_xor_explicit(object, operand, .Acquire) + case .release: return intrinsics.atomic_xor_explicit(object, operand, .Release) + case .acq_rel: return intrinsics.atomic_xor_explicit(object, operand, .Acq_Rel) case: fallthrough - case .seq_cst: return intrinsics.atomic_xor_explicit(object, operand, .seq_cst) + case .seq_cst: return intrinsics.atomic_xor_explicit(object, operand, .Seq_Cst) } } @@ -351,13 +351,13 @@ atomic_fetch_and :: #force_inline proc(object: ^$T, operand: T) -> T { } atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T { switch order { - case .relaxed: return intrinsics.atomic_and_explicit(object, operand, .relaxed) - case .consume: return intrinsics.atomic_and_explicit(object, operand, .consume) - case .acquire: return intrinsics.atomic_and_explicit(object, operand, .acquire) - case .release: return intrinsics.atomic_and_explicit(object, operand, .release) - case .acq_rel: return intrinsics.atomic_and_explicit(object, operand, .acq_rel) + case .relaxed: return intrinsics.atomic_and_explicit(object, operand, .Relaxed) + case .consume: return intrinsics.atomic_and_explicit(object, operand, .Consume) + case .acquire: return intrinsics.atomic_and_explicit(object, operand, .Acquire) + case .release: return intrinsics.atomic_and_explicit(object, operand, .Release) + case .acq_rel: return intrinsics.atomic_and_explicit(object, operand, .Acq_Rel) case: fallthrough - case .seq_cst: return intrinsics.atomic_and_explicit(object, operand, .seq_cst) + case .seq_cst: return intrinsics.atomic_and_explicit(object, operand, .Seq_Cst) } } diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 4c1c166e6..ce8fd96ea 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -63,12 +63,12 @@ syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- // Atomics Atomic_Memory_Order :: enum { - relaxed = 0, // unordered - consume = 1, // monotonic - acquire = 2, - release = 3, - acq_rel = 4, - seq_cst = 5, + Relaxed = 0, // Unordered + Consume = 1, // Monotonic + Acquire = 2, + Release = 3, + Acq_Rel = 4, + Seq_Cst = 5, } atomic_thread_fence :: proc(order: Atomic_Memory_Order) --- diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 1ebe558ef..817c0ea5f 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -16,7 +16,7 @@ zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr { // equivalent semantics to those provided by the C11 Annex K 3.7.4.1 // memset_s call. intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero - intrinsics.atomic_thread_fence(.seq_cst) // Prevent reordering + intrinsics.atomic_thread_fence(.Seq_Cst) // Prevent reordering return data } zero_item :: proc "contextless" (item: $P/^$T) { diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index d6521daed..f537764c4 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -6,12 +6,12 @@ cpu_relax :: intrinsics.cpu_relax /* Atomic_Memory_Order :: enum { - relaxed = 0, - consume = 1, - acquire = 2, - release = 3, - acq_rel = 4, - seq_cst = 5, + Relaxed = 0, + Consume = 1, + Acquire = 2, + Release = 3, + Acq_Rel = 4, + Seq_Cst = 5, } */ Atomic_Memory_Order :: intrinsics.Atomic_Memory_Order diff --git a/core/sync/extended.odin b/core/sync/extended.odin index c8ae4493f..24f7c096c 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -146,10 +146,10 @@ Auto_Reset_Event :: struct { } auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) { - old_status := atomic_load_explicit(&e.status, .relaxed) + old_status := atomic_load_explicit(&e.status, .Relaxed) for { new_status := old_status + 1 if old_status < 1 else 1 - if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .release, .relaxed); ok { + if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .Release, .Relaxed); ok { break } @@ -160,7 +160,7 @@ auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) { } auto_reset_event_wait :: proc(e: ^Auto_Reset_Event) { - old_status := atomic_sub_explicit(&e.status, 1, .acquire) + old_status := atomic_sub_explicit(&e.status, 1, .Acquire) if old_status < 1 { sema_wait(&e.sema) } @@ -174,14 +174,14 @@ Ticket_Mutex :: struct { } ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) { - ticket := atomic_add_explicit(&m.ticket, 1, .relaxed) - for ticket != atomic_load_explicit(&m.serving, .acquire) { + ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed) + for ticket != atomic_load_explicit(&m.serving, .Acquire) { cpu_relax() } } ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) { - atomic_add_explicit(&m.serving, 1, .relaxed) + atomic_add_explicit(&m.serving, 1, .Relaxed) } @(deferred_in=ticket_mutex_unlock) ticket_mutex_guard :: proc(m: ^Ticket_Mutex) -> bool { @@ -196,18 +196,18 @@ Benaphore :: struct { } benaphore_lock :: proc(b: ^Benaphore) { - if atomic_add_explicit(&b.counter, 1, .acquire) > 1 { + if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 { sema_wait(&b.sema) } } benaphore_try_lock :: proc(b: ^Benaphore) -> bool { - v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .acquire, .acquire) + v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .Acquire, .Acquire) return v == 0 } benaphore_unlock :: proc(b: ^Benaphore) { - if atomic_sub_explicit(&b.counter, 1, .release) > 0 { + if atomic_sub_explicit(&b.counter, 1, .Release) > 0 { sema_post(&b.sema) } } @@ -227,7 +227,7 @@ Recursive_Benaphore :: struct { recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) { tid := current_thread_id() - if atomic_add_explicit(&b.counter, 1, .acquire) > 1 { + if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 { if tid != b.owner { sema_wait(&b.sema) } @@ -240,10 +240,10 @@ recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) { recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool { tid := current_thread_id() if b.owner == tid { - atomic_add_explicit(&b.counter, 1, .acquire) + atomic_add_explicit(&b.counter, 1, .Acquire) } - if v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .acquire, .acquire); v != 0 { + if v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .Acquire, .Acquire); v != 0 { return false } // inside the lock @@ -260,7 +260,7 @@ recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) { if recursion == 0 { b.owner = 0 } - if atomic_sub_explicit(&b.counter, 1, .release) > 0 { + if atomic_sub_explicit(&b.counter, 1, .Release) > 0 { if recursion == 0 { sema_post(&b.sema) } @@ -293,12 +293,12 @@ once_do :: proc(o: ^Once, fn: proc()) { defer mutex_unlock(&o.m) if !o.done { fn() - atomic_store_explicit(&o.done, true, .release) + atomic_store_explicit(&o.done, true, .Release) } } - if atomic_load_explicit(&o.done, .acquire) == false { + if atomic_load_explicit(&o.done, .Acquire) == false { do_slow(o, fn) } } diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index 401f78b91..11fff4e60 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -24,7 +24,7 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) { new_state := curr_state // Make a copy of it spin_lock: for spin in 0.. bool { - _, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .acquire, .consume) + _, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume) return ok } @@ -290,7 +290,7 @@ Queue_Item :: struct { @(private="file") queue_item_wait :: proc(item: ^Queue_Item) { - for atomic_load_explicit(&item.futex, .acquire) == 0 { + for atomic_load_explicit(&item.futex, .Acquire) == 0 { futex_wait(&item.futex, 0) cpu_relax() } @@ -298,7 +298,7 @@ queue_item_wait :: proc(item: ^Queue_Item) { @(private="file") queue_item_wait_with_timeout :: proc(item: ^Queue_Item, duration: time.Duration) -> bool { start := time.tick_now() - for atomic_load_explicit(&item.futex, .acquire) == 0 { + for atomic_load_explicit(&item.futex, .Acquire) == 0 { remaining := duration - time.tick_since(start) if remaining < 0 { return false @@ -312,7 +312,7 @@ queue_item_wait_with_timeout :: proc(item: ^Queue_Item, duration: time.Duration) } @(private="file") queue_item_signal :: proc(item: ^Queue_Item) { - atomic_store_explicit(&item.futex, 1, .release) + atomic_store_explicit(&item.futex, 1, .Release) futex_signal(&item.futex) } diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin index c1a38b4ad..4807b41c1 100644 --- a/core/sync/primitives_internal.odin +++ b/core/sync/primitives_internal.odin @@ -10,7 +10,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { tid := Futex(current_thread_id()) for { - prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .acquire, .acquire) + prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .Acquire, .Acquire) switch prev_owner { case 0, tid: m.impl.recursion += 1 @@ -27,7 +27,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { if m.impl.recursion != 0 { return } - atomic_exchange_explicit(&m.impl.owner, 0, .release) + atomic_exchange_explicit(&m.impl.owner, 0, .Release) futex_signal(&m.impl.owner) // outside the lock @@ -36,7 +36,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { tid := Futex(current_thread_id()) - prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .acquire, .acquire) + prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .Acquire, .Acquire) switch prev_owner { case 0, tid: m.impl.recursion += 1 diff --git a/src/checker.cpp b/src/checker.cpp index 0c72a8e14..1bb786ea1 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -992,12 +992,12 @@ void init_universal(void) { { GlobalEnumValue values[OdinAtomicMemoryOrder_COUNT] = { - {"relaxed", OdinAtomicMemoryOrder_relaxed}, - {"consume", OdinAtomicMemoryOrder_consume}, - {"acquire", OdinAtomicMemoryOrder_acquire}, - {"release", OdinAtomicMemoryOrder_release}, - {"acq_rel", OdinAtomicMemoryOrder_acq_rel}, - {"seq_cst", OdinAtomicMemoryOrder_seq_cst}, + {OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_relaxed], OdinAtomicMemoryOrder_relaxed}, + {OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_consume], OdinAtomicMemoryOrder_consume}, + {OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_acquire], OdinAtomicMemoryOrder_acquire}, + {OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_release], OdinAtomicMemoryOrder_release}, + {OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_acq_rel], OdinAtomicMemoryOrder_acq_rel}, + {OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_seq_cst], OdinAtomicMemoryOrder_seq_cst}, }; add_global_enum_type(str_lit("Atomic_Memory_Order"), values, gb_count_of(values), &t_atomic_memory_order); diff --git a/src/types.cpp b/src/types.cpp index 16d07d392..e10dae1ed 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -703,12 +703,12 @@ enum OdinAtomicMemoryOrder : i32 { }; char const *OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_COUNT] = { - "relaxed", - "consume", - "acquire", - "release", - "acq_rel", - "seq_cst", + "Relaxed", + "Consume", + "Acquire", + "Release", + "Acq_Rel", + "Seq_Cst", }; gb_global Type *t_atomic_memory_order = nullptr; From 2ec3fa93b47809ca7a6c0ed4ec4bc108212262b5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 13:10:15 +0100 Subject: [PATCH 0479/1052] Remove pthreads dependency --- core/sync/futex_linux.odin | 6 ---- core/sync/primitives_freebsd.odin | 37 +++++++++++++++++++ core/sync/primitives_linux.odin | 38 ++++++++++++++++++++ core/sync/primitives_openbsd.odin | 37 +++++++++++++++++++ core/sync/primitives_pthreads.odin | 58 ------------------------------ 5 files changed, 112 insertions(+), 64 deletions(-) delete mode 100644 core/sync/primitives_pthreads.odin diff --git a/core/sync/futex_linux.odin b/core/sync/futex_linux.odin index 74f331de7..c429a9d64 100644 --- a/core/sync/futex_linux.odin +++ b/core/sync/futex_linux.odin @@ -14,12 +14,6 @@ FUTEX_PRIVATE_FLAG :: 128 FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) -foreign import libc "system:c" - -foreign libc { - __errno_location :: proc "c" () -> ^c.int --- -} - ESUCCESS :: 0 EINTR :: -4 EAGAIN :: -11 diff --git a/core/sync/primitives_freebsd.odin b/core/sync/primitives_freebsd.odin index e6219acf1..b88fca181 100644 --- a/core/sync/primitives_freebsd.odin +++ b/core/sync/primitives_freebsd.odin @@ -3,7 +3,44 @@ package sync import "core:os" +import "core:time" _current_thread_id :: proc "contextless" () -> int { return os.current_thread_id() } + +_Mutex :: struct { + mutex: Atomic_Mutex, +} + +_mutex_lock :: proc(m: ^Mutex) { + atomic_mutex_lock(&m.impl.mutex) +} + +_mutex_unlock :: proc(m: ^Mutex) { + atomic_mutex_unlock(&m.impl.mutex) +} + +_mutex_try_lock :: proc(m: ^Mutex) -> bool { + return atomic_mutex_try_lock(&m.impl.mutex) +} + +_Cond :: struct { + cond: Atomic_Cond, +} + +_cond_wait :: proc(c: ^Cond, m: ^Mutex) { + atomic_cond_wait(&c.impl.cond, &m.impl.mutex) +} + +_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) +} + +_cond_signal :: proc(c: ^Cond) { + atomic_cond_signal(&c.impl.cond) +} + +_cond_broadcast :: proc(c: ^Cond) { + atomic_cond_broadcast(&c.impl.cond) +} diff --git a/core/sync/primitives_linux.odin b/core/sync/primitives_linux.odin index 1e75891df..0a9f0cc33 100644 --- a/core/sync/primitives_linux.odin +++ b/core/sync/primitives_linux.odin @@ -3,7 +3,45 @@ package sync import "core:sys/unix" +import "core:time" _current_thread_id :: proc "contextless" () -> int { return unix.sys_gettid() } + + +_Mutex :: struct { + mutex: Atomic_Mutex, +} + +_mutex_lock :: proc(m: ^Mutex) { + atomic_mutex_lock(&m.impl.mutex) +} + +_mutex_unlock :: proc(m: ^Mutex) { + atomic_mutex_unlock(&m.impl.mutex) +} + +_mutex_try_lock :: proc(m: ^Mutex) -> bool { + return atomic_mutex_try_lock(&m.impl.mutex) +} + +_Cond :: struct { + cond: Atomic_Cond, +} + +_cond_wait :: proc(c: ^Cond, m: ^Mutex) { + atomic_cond_wait(&c.impl.cond, &m.impl.mutex) +} + +_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) +} + +_cond_signal :: proc(c: ^Cond) { + atomic_cond_signal(&c.impl.cond) +} + +_cond_broadcast :: proc(c: ^Cond) { + atomic_cond_broadcast(&c.impl.cond) +} diff --git a/core/sync/primitives_openbsd.odin b/core/sync/primitives_openbsd.odin index 4072a14e8..7794016f8 100644 --- a/core/sync/primitives_openbsd.odin +++ b/core/sync/primitives_openbsd.odin @@ -3,7 +3,44 @@ package sync import "core:os" +import "core:time" _current_thread_id :: proc "contextless" () -> int { return os.current_thread_id() } + +_Mutex :: struct { + mutex: Atomic_Mutex, +} + +_mutex_lock :: proc(m: ^Mutex) { + atomic_mutex_lock(&m.impl.mutex) +} + +_mutex_unlock :: proc(m: ^Mutex) { + atomic_mutex_unlock(&m.impl.mutex) +} + +_mutex_try_lock :: proc(m: ^Mutex) -> bool { + return atomic_mutex_try_lock(&m.impl.mutex) +} + +_Cond :: struct { + cond: Atomic_Cond, +} + +_cond_wait :: proc(c: ^Cond, m: ^Mutex) { + atomic_cond_wait(&c.impl.cond, &m.impl.mutex) +} + +_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) +} + +_cond_signal :: proc(c: ^Cond) { + atomic_cond_signal(&c.impl.cond) +} + +_cond_broadcast :: proc(c: ^Cond) { + atomic_cond_broadcast(&c.impl.cond) +} diff --git a/core/sync/primitives_pthreads.odin b/core/sync/primitives_pthreads.odin deleted file mode 100644 index 581e9feb1..000000000 --- a/core/sync/primitives_pthreads.odin +++ /dev/null @@ -1,58 +0,0 @@ -//+build linux, freebsd, openbsd -//+private -package sync - -import "core:time" -import "core:sys/unix" - -_Mutex_State :: enum i32 { - Unlocked = 0, - Locked = 1, - Waiting = 2, -} -_Mutex :: struct { - pthread_mutex: unix.pthread_mutex_t, -} - -_mutex_lock :: proc(m: ^Mutex) { - err := unix.pthread_mutex_lock(&m.impl.pthread_mutex) - assert(err == 0) -} - -_mutex_unlock :: proc(m: ^Mutex) { - err := unix.pthread_mutex_unlock(&m.impl.pthread_mutex) - assert(err == 0) -} - -_mutex_try_lock :: proc(m: ^Mutex) -> bool { - err := unix.pthread_mutex_trylock(&m.impl.pthread_mutex) - return err == 0 -} - -_Cond :: struct { - pthread_cond: unix.pthread_cond_t, -} - -_cond_wait :: proc(c: ^Cond, m: ^Mutex) { - err := unix.pthread_cond_wait(&c.impl.pthread_cond, &m.impl.pthread_mutex) - assert(err == 0) -} - - -_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { - tv_sec := i64(duration/1e9) - tv_nsec := i64(duration%1e9) - err := unix.pthread_cond_timedwait(&c.impl.pthread_cond, &m.impl.pthread_mutex, &{tv_sec, tv_nsec}) - return err == 0 -} - - -_cond_signal :: proc(c: ^Cond) { - err := unix.pthread_cond_signal(&c.impl.pthread_cond) - assert(err == 0) -} - -_cond_broadcast :: proc(c: ^Cond) { - err := unix.pthread_cond_broadcast(&c.impl.pthread_cond) - assert(err == 0) -} From 77de7ebde590c08072a52568fb15378c1ca96770 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 13:26:10 +0100 Subject: [PATCH 0480/1052] Remove code deduplication --- core/sync/primitives_internal.odin | 73 +++--------------------------- 1 file changed, 7 insertions(+), 66 deletions(-) diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin index 4807b41c1..15967d45e 100644 --- a/core/sync/primitives_internal.odin +++ b/core/sync/primitives_internal.odin @@ -94,91 +94,32 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { when ODIN_OS != .Windows { - RW_Mutex_State :: distinct uint - RW_Mutex_State_Half_Width :: size_of(RW_Mutex_State)*8/2 - RW_Mutex_State_Is_Writing :: RW_Mutex_State(1) - RW_Mutex_State_Writer :: RW_Mutex_State(1)<<1 - RW_Mutex_State_Reader :: RW_Mutex_State(1)< bool { - if mutex_try_lock(&rw.impl.mutex) { - state := atomic_load(&rw.impl.state) - if state & RW_Mutex_State_Reader_Mask == 0 { - _ = atomic_or(&rw.impl.state, RW_Mutex_State_Is_Writing) - return true - } - - mutex_unlock(&rw.impl.mutex) - } - return false + return atomic_rw_mutex_try_lock(&rw.impl.mutex) } _rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) { - state := atomic_load(&rw.impl.state) - for state & (RW_Mutex_State_Is_Writing|RW_Mutex_State_Writer_Mask) == 0 { - ok: bool - state, ok = atomic_compare_exchange_weak(&rw.impl.state, state, state + RW_Mutex_State_Reader) - if ok { - return - } - } - - mutex_lock(&rw.impl.mutex) - _ = atomic_add(&rw.impl.state, RW_Mutex_State_Reader) - mutex_unlock(&rw.impl.mutex) + atomic_rw_mutex_shared_lock(&rw.impl.mutex) } _rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) { - state := atomic_sub(&rw.impl.state, RW_Mutex_State_Reader) - - if (state & RW_Mutex_State_Reader_Mask == RW_Mutex_State_Reader) && - (state & RW_Mutex_State_Is_Writing != 0) { - sema_post(&rw.impl.sema) - } + atomic_rw_mutex_shared_unlock(&rw.impl.mutex) } _rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool { - state := atomic_load(&rw.impl.state) - if state & (RW_Mutex_State_Is_Writing|RW_Mutex_State_Writer_Mask) == 0 { - _, ok := atomic_compare_exchange_strong(&rw.impl.state, state, state + RW_Mutex_State_Reader) - if ok { - return true - } - } - if mutex_try_lock(&rw.impl.mutex) { - _ = atomic_add(&rw.impl.state, RW_Mutex_State_Reader) - mutex_unlock(&rw.impl.mutex) - return true - } - - return false + return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex) } } \ No newline at end of file From 4484a3433d6c58f1d1c594a4c36317f323cb5102 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Mar 2022 15:03:56 +0100 Subject: [PATCH 0481/1052] Update `mem.nil_allocator` to match the same in `runtime` --- core/mem/allocators.odin | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index b8bd9a065..4954122ed 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -6,7 +6,24 @@ import "core:runtime" nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) { - return nil, nil + switch mode { + case .Alloc: + return nil, .Out_Of_Memory + case .Free: + return nil, .None + case .Free_All: + return nil, .Mode_Not_Implemented + case .Resize: + if size == 0 { + return nil, .None + } + return nil, .Out_Of_Memory + case .Query_Features: + return nil, .Mode_Not_Implemented + case .Query_Info: + return nil, .Mode_Not_Implemented + } + return nil, .None } nil_allocator :: proc() -> Allocator { From c686133172d312a4a8c7c2b37b397bf011f63b1e Mon Sep 17 00:00:00 2001 From: Tetralux Date: Thu, 31 Mar 2022 06:37:11 +0000 Subject: [PATCH 0482/1052] Have get_std_handle() no longer make the handles uninheritable This caused all handles returned by GetStdHandle() to also not be inheritable, which prevents you from handing them to child processes that you might create. This fixes that. --- core/os/file_windows.odin | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 4c8d385f2..61e9e0925 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -320,9 +320,6 @@ stderr := get_std_handle(uint(win32.STD_ERROR_HANDLE)) get_std_handle :: proc "contextless" (h: uint) -> Handle { fd := win32.GetStdHandle(win32.DWORD(h)) - when size_of(uintptr) == 8 { - win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0) - } return Handle(fd) } From 78ee97ec748ad9f72fbfce664727740227d3b41e Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Thu, 31 Mar 2022 13:40:28 -0700 Subject: [PATCH 0483/1052] only install the right version of llvm --- .github/workflows/nightly.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 7175843f5..dac888ce6 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -41,7 +41,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: (Linux) Download LLVM - run: sudo apt-get install llvm-11 clang-11 llvm + run: sudo apt-get install llvm-11 clang-11 - name: build odin run: make nightly - name: Odin run @@ -129,7 +129,7 @@ jobs: run: | echo Authorizing B2 account b2 authorize-account "$APPID" "$APPKEY" - + echo Uploading artifcates to B2 chmod +x ./ci/upload_create_nightly.sh ./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/ @@ -141,7 +141,7 @@ jobs: echo Creating nightly.json python3 ci/create_nightly_json.py "$BUCKET" > nightly.json - + echo Uploading nightly.json b2 upload-file "$BUCKET" nightly.json nightly.json From 75cbb0974487cd9fee3762a0b2cd272a94402154 Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 1 Apr 2022 02:11:41 +0300 Subject: [PATCH 0484/1052] sys/windows: add intrinsics.constant_utf16_cstring --- core/sys/windows/types.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 50098a59c..05f71192c 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -3,6 +3,8 @@ package sys_windows import "core:c" +L :: intrinsics.constant_utf16_cstring + c_char :: c.char c_uchar :: c.uchar c_int :: c.int From 107bede9fdf32594d19bc290e717dca65921b088 Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 1 Apr 2022 02:23:44 +0300 Subject: [PATCH 0485/1052] sys/windows: fix building error --- core/sys/windows/types.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 05f71192c..653d2c62f 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -2,6 +2,7 @@ package sys_windows import "core:c" +import "core:intrinsics" L :: intrinsics.constant_utf16_cstring From b21cf05d44afb8697bf34d6718bb165c724d57f5 Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 1 Apr 2022 02:25:10 +0300 Subject: [PATCH 0486/1052] sys/windows: move L into util.odin --- core/sys/windows/types.odin | 3 --- core/sys/windows/util.odin | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 653d2c62f..50098a59c 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -2,9 +2,6 @@ package sys_windows import "core:c" -import "core:intrinsics" - -L :: intrinsics.constant_utf16_cstring c_char :: c.char c_uchar :: c.uchar diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index 5797216c3..d464007d3 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -3,6 +3,9 @@ package sys_windows import "core:strings" import "core:sys/win32" +import "core:intrinsics" + +L :: intrinsics.constant_utf16_cstring LOWORD :: #force_inline proc "contextless" (x: DWORD) -> WORD { return WORD(x & 0xffff) @@ -456,4 +459,4 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P } else { return false } -} \ No newline at end of file +} From 73f9d12d476f378e6b8abc7dcd5155c4f688719e Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 1 Apr 2022 06:22:27 +0300 Subject: [PATCH 0487/1052] sys/windows: add various procedures --- core/sys/windows/types.odin | 15 +++++++++++++++ core/sys/windows/user32.odin | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 50098a59c..47c180db8 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -96,6 +96,7 @@ LPPROCESS_INFORMATION :: ^PROCESS_INFORMATION PSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES LPSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES LPSTARTUPINFO :: ^STARTUPINFO +LPTRACKMOUSEEVENT :: ^TRACKMOUSEEVENT VOID :: rawptr PVOID :: rawptr LPVOID :: rawptr @@ -272,6 +273,13 @@ PAINTSTRUCT :: struct { rgbReserved: [32]BYTE, } +TRACKMOUSEEVENT :: struct { + cbSize: DWORD, + dwFlags: DWORD, + hwndTrack: HWND, + dwHoverTime: DWORD, +} + WIN32_FIND_DATAW :: struct { dwFileAttributes: DWORD, ftCreationTime: FILETIME, @@ -645,6 +653,13 @@ MK_MBUTTON :: 0x0010 MK_XBUTTON1 :: 0x0020 MK_XBUTTON2 :: 0x0040 +TME_HOVER :: 0x00000001 +TME_LEAVE :: 0x00000002 +TME_NONCLIENT :: 0x00000010 +TME_QUERY :: 0x40000000 +TME_CANCEL :: 0x80000000 +HOVER_DEFAULT :: 0xFFFFFFFF + USER_TIMER_MAXIMUM :: 0x7FFFFFFF USER_TIMER_MINIMUM :: 0x0000000A diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index bdab77e27..4068ecdb2 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -123,6 +123,11 @@ foreign user32 { BeginPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> HDC --- EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- + GetCapture :: proc() -> HWND --- + SetCapture :: proc(hWnd: HWND) -> HWND --- + ReleaseCapture :: proc() -> BOOL --- + TrackMouseEvent :: proc(lpEventTrack: LPTRACKMOUSEEVENT) -> BOOL --- + GetKeyState :: proc(nVirtKey: c_int) -> SHORT --- GetAsyncKeyState :: proc(vKey: c_int) -> SHORT --- From e28525e28c5baf6906cb3e7e1e15b11510ec959e Mon Sep 17 00:00:00 2001 From: hikari Date: Fri, 1 Apr 2022 07:28:18 +0300 Subject: [PATCH 0488/1052] sys/windows: fix some procedure definitions and types --- core/sys/windows/types.odin | 49 ++++++++++++++++++++++++++++++------ core/sys/windows/user32.odin | 43 ++++++++++++++++++++++++------- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 47c180db8..d0551c6bf 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -395,13 +395,6 @@ CS_BYTEALIGNWINDOW : UINT : 0x2000 CS_GLOBALCLASS : UINT : 0x4000 CS_DROPSHADOW : UINT : 0x0002_0000 -GWL_EXSTYLE : c_int : -20 -GWLP_HINSTANCE : c_int : -6 -GWLP_ID : c_int : -12 -GWL_STYLE : c_int : -16 -GWLP_USERDATA : c_int : -21 -GWLP_WNDPROC : c_int : -4 - WS_BORDER : UINT : 0x0080_0000 WS_CAPTION : UINT : 0x00C0_0000 WS_CHILD : UINT : 0x4000_0000 @@ -493,6 +486,48 @@ HWND_BOTTOM :: HWND( uintptr(1)) // 1 HWND_TOPMOST :: HWND(~uintptr(0)) // -1 HWND_NOTOPMOST :: HWND(~uintptr(0) - 1) // -2 +// Window field offsets for GetWindowLong() +GWL_STYLE :: -16 +GWL_EXSTYLE :: -20 +GWL_ID :: -12 + +when ODIN_ARCH == .i386 { + GWL_WNDPROC :: -4 + GWL_HINSTANCE :: -6 + GWL_HWNDPARENT :: -8 + GWL_USERDATA :: -21 +} + +GWLP_WNDPROC :: -4 +GWLP_HINSTANCE :: -6 +GWLP_HWNDPARENT :: -8 +GWLP_USERDATA :: -21 +GWLP_ID :: -12 + +// Class field offsets for GetClassLong() +GCL_CBWNDEXTRA :: -18 +GCL_CBCLSEXTRA :: -20 +GCL_STYLE :: -26 +GCW_ATOM :: -32 + +when ODIN_ARCH == .i386 { + GCL_MENUNAME :: -8 + GCL_HBRBACKGROUND :: -10 + GCL_HCURSOR :: -12 + GCL_HICON :: -14 + GCL_HMODULE :: -16 + GCL_WNDPROC :: -24 + GCL_HICONSM :: -34 +} + +GCLP_MENUNAME :: -8 +GCLP_HBRBACKGROUND :: -10 +GCLP_HCURSOR :: -12 +GCLP_HICON :: -14 +GCLP_HMODULE :: -16 +GCLP_WNDPROC :: -24 +GCLP_HICONSM :: -34 + // GetSystemMetrics() codes SM_CXSCREEN :: 0 SM_CYSCREEN :: 1 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 4068ecdb2..3985c9ad6 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -10,19 +10,19 @@ foreign user32 { GetClassInfoExA :: proc(hInsatnce: HINSTANCE, lpszClass: LPCSTR, lpwcx: ^WNDCLASSEXA) -> BOOL --- GetClassInfoExW :: proc(hInsatnce: HINSTANCE, lpszClass: LPCWSTR, lpwcx: ^WNDCLASSEXW) -> BOOL --- - GetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- - GetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- - SetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- - SetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + GetClassLongA :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- + GetClassLongW :: proc(hWnd: HWND, nIndex: c_int) -> DWORD --- + SetClassLongA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG) -> DWORD --- + SetClassLongW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG) -> DWORD --- + + GetWindowLongA :: proc(hWnd: HWND, nIndex: c_int) -> LONG --- + GetWindowLongW :: proc(hWnd: HWND, nIndex: c_int) -> LONG --- + SetWindowLongA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG) -> LONG --- + SetWindowLongW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG) -> LONG --- GetClassNameA :: proc(hWnd: HWND, lpClassName: LPSTR, nMaxCount: c_int) -> c_int --- GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int --- - GetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- - GetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- - SetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- - SetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- - RegisterClassA :: proc(lpWndClass: ^WNDCLASSA) -> ATOM --- RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- RegisterClassExA :: proc(^WNDCLASSEXA) -> ATOM --- @@ -198,6 +198,31 @@ CreateWindowW :: #force_inline proc "stdcall" ( ) } +when ODIN_ARCH == .amd64 { + @(default_calling_convention="stdcall") + foreign user32 { + GetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> ULONG_PTR --- + GetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> ULONG_PTR --- + SetClassLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + SetClassLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> ULONG_PTR --- + + GetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- + GetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int) -> LONG_PTR --- + SetWindowLongPtrA :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- + SetWindowLongPtrW :: proc(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) -> LONG_PTR --- + } +} else when ODIN_ARCH == .i386 { + GetClassLongPtrA :: GetClassLongA + GetClassLongPtrW :: GetClassLongW + SetClassLongPtrA :: SetClassLongA + SetClassLongPtrW :: SetClassLongW + + GetWindowLongPtrA :: GetWindowLongA + GetWindowLongPtrW :: GetWindowLongW + SetWindowLongPtrA :: GetWindowLongA + SetWindowLongPtrW :: GetWindowLongW +} + GET_SC_WPARAM :: #force_inline proc(wparam: WPARAM) -> i32 { return i32(wparam) & 0xFFF0 } From c78b83f142a44f055bad80d7506d58c3ced59810 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 1 Apr 2022 14:51:51 +0100 Subject: [PATCH 0489/1052] Fix `_Sema` --- core/sync/extended.odin | 4 ++-- core/sync/primitives_internal.odin | 4 ++-- core/sync/sema_internal.odin | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/sync/extended.odin b/core/sync/extended.odin index 24f7c096c..2cca6f961 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -202,7 +202,7 @@ benaphore_lock :: proc(b: ^Benaphore) { } benaphore_try_lock :: proc(b: ^Benaphore) -> bool { - v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .Acquire, .Acquire) + v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire) return v == 0 } @@ -243,7 +243,7 @@ recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool { atomic_add_explicit(&b.counter, 1, .Acquire) } - if v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 1, 0, .Acquire, .Acquire); v != 0 { + if v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire); v != 0 { return false } // inside the lock diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin index 15967d45e..de9aca991 100644 --- a/core/sync/primitives_internal.odin +++ b/core/sync/primitives_internal.odin @@ -10,7 +10,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { tid := Futex(current_thread_id()) for { - prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .Acquire, .Acquire) + prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire) switch prev_owner { case 0, tid: m.impl.recursion += 1 @@ -36,7 +36,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) { _recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { tid := Futex(current_thread_id()) - prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, tid, 0, .Acquire, .Acquire) + prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire) switch prev_owner { case 0, tid: m.impl.recursion += 1 diff --git a/core/sync/sema_internal.odin b/core/sync/sema_internal.odin index 8cf157708..d265caa81 100644 --- a/core/sync/sema_internal.odin +++ b/core/sync/sema_internal.odin @@ -25,7 +25,7 @@ when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { futex_wait(&s.impl.count, u32(original_count)) original_count = s.impl.count } - if original_count == atomic_compare_exchange_strong(&s.impl.count, original_count-1, original_count) { + if original_count == atomic_compare_exchange_strong(&s.impl.count, original_count, original_count-1) { return } } @@ -49,7 +49,7 @@ when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { } original_count = s.impl.count } - if original_count == atomic_compare_exchange_strong(&s.impl.count, original_count-1, original_count) { + if original_count == atomic_compare_exchange_strong(&s.impl.count, original_count, original_count-1) { return true } } From 2bc89260f13fee39427057e576a0789d55fd4504 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 1 Apr 2022 15:08:58 +0100 Subject: [PATCH 0490/1052] Add explicit memory ordering for the internal Sema implementation --- core/sync/sema_internal.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/sync/sema_internal.odin b/core/sync/sema_internal.odin index d265caa81..e4a3c0bfc 100644 --- a/core/sync/sema_internal.odin +++ b/core/sync/sema_internal.odin @@ -10,7 +10,7 @@ when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { } _sema_post :: proc(s: ^Sema, count := 1) { - atomic_add(&s.impl.count, Futex(count)) + atomic_add_explicit(&s.impl.count, Futex(count), .Release) if count == 1 { futex_signal(&s.impl.count) } else { @@ -20,12 +20,12 @@ when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { _sema_wait :: proc(s: ^Sema) { for { - original_count := atomic_load(&s.impl.count) + original_count := atomic_load_explicit(&s.impl.count, .Relaxed) for original_count == 0 { futex_wait(&s.impl.count, u32(original_count)) original_count = s.impl.count } - if original_count == atomic_compare_exchange_strong(&s.impl.count, original_count, original_count-1) { + if original_count == atomic_compare_exchange_strong_explicit(&s.impl.count, original_count, original_count-1, .Acquire, .Acquire) { return } } @@ -37,7 +37,7 @@ when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { } for { - original_count := atomic_load(&s.impl.count) + original_count := atomic_load_explicit(&s.impl.count, .Relaxed) for start := time.tick_now(); original_count == 0; /**/ { remaining := duration - time.tick_since(start) if remaining < 0 { @@ -49,7 +49,7 @@ when #config(ODIN_SYNC_SEMA_USE_FUTEX, true) { } original_count = s.impl.count } - if original_count == atomic_compare_exchange_strong(&s.impl.count, original_count, original_count-1) { + if original_count == atomic_compare_exchange_strong_explicit(&s.impl.count, original_count, original_count-1, .Acquire, .Acquire) { return true } } From 581d53b96ba5c102bedb8b80bb40a7ed8d78728a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 1 Apr 2022 16:24:27 +0200 Subject: [PATCH 0491/1052] [math/big] Tell Python test runner how many nails we use. `_DIGIT_NAILS` is defined as 4, meaning that we use 60 out of every 64 bits. We can use as few as 1 nail, using 63 bits out of every 64, and all tests will still pass. However, it needs more testing to see if that's a worthwhile change to make. For the tests to work properly when changing the nails, Python needs to know about it as well. In addition, compile the big math code with `-o:speed` going forward. --- tests/core/math/big/build.bat | 5 +---- tests/core/math/big/test.odin | 6 +++--- tests/core/math/big/test.py | 13 +++++++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index e383cdfc1..16bdbc8ca 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -10,8 +10,5 @@ echo --- echo Running core:math/big tests echo --- -rem Fails -:%PATH_TO_ODIN% build . %COMMON% -o:speed -out:%OUT_NAME% -rem Passes -%PATH_TO_ODIN% build . %COMMON% -o:size -out:%OUT_NAME% +%PATH_TO_ODIN% build . %COMMON% -o:speed -out:%OUT_NAME% python3 test.py %TEST_ARGS% \ No newline at end of file diff --git a/tests/core/math/big/test.odin b/tests/core/math/big/test.odin index 81f1956dc..a289c89dd 100644 --- a/tests/core/math/big/test.odin +++ b/tests/core/math/big/test.odin @@ -32,9 +32,9 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { @export test_initialize_constants :: proc "c" () -> (res: u64) { context = runtime.default_context() - res = u64(big.initialize_constants()) - //assert(MUL_KARATSUBA_CUTOFF >= 40); - return res + _ = big.initialize_constants() + + return u64(big._DIGIT_NAILS) } @export test_error_string :: proc "c" (err: big.Error) -> (res: cstring) { diff --git a/tests/core/math/big/test.py b/tests/core/math/big/test.py index d292a3ff4..d4724edb8 100644 --- a/tests/core/math/big/test.py +++ b/tests/core/math/big/test.py @@ -17,7 +17,6 @@ import gc from enum import Enum import argparse - parser = argparse.ArgumentParser( description = "Odin core:math/big test suite", epilog = "By default we run regression and random tests with preset parameters.", @@ -163,6 +162,8 @@ def load(export_name, args, res): export_name.restype = res return export_name + + # # Result values will be passed in a struct { res: cstring, err: Error } # @@ -170,7 +171,11 @@ class Res(Structure): _fields_ = [("res", c_char_p), ("err", c_uint64)] initialize_constants = load(l.test_initialize_constants, [], c_uint64) -print("initialize_constants: ", initialize_constants()) + +NAILS = initialize_constants() +LEG_BITS = 64 - NAILS + +print("LEG BITS: ", LEG_BITS) error_string = load(l.test_error_string, [c_byte], c_char_p) @@ -407,7 +412,7 @@ def test_shl_leg(a = 0, digits = 0, expected_error = Error.Okay): res = int_shl_leg(*args) expected_result = None if expected_error == Error.Okay: - expected_result = a << (digits * 60) + expected_result = a << (digits * LEG_BITS) return test("test_shl_leg", res, [a, digits], expected_error, expected_result) def test_shr_leg(a = 0, digits = 0, expected_error = Error.Okay): @@ -419,7 +424,7 @@ def test_shr_leg(a = 0, digits = 0, expected_error = Error.Okay): # Don't pass negative numbers. We have a shr_signed. return False else: - expected_result = a >> (digits * 60) + expected_result = a >> (digits * LEG_BITS) return test("test_shr_leg", res, [a, digits], expected_error, expected_result) From c3a292a8c7baeef53436ce5cd15c2e18e6c52943 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 2 Apr 2022 00:36:26 +0100 Subject: [PATCH 0492/1052] Remove hms2019 files --- examples/hms2019/basic.odin | 7 - examples/hms2019/eca.odin | 67 -- examples/hms2019/hms2019.odin | 1754 --------------------------------- 3 files changed, 1828 deletions(-) delete mode 100644 examples/hms2019/basic.odin delete mode 100644 examples/hms2019/eca.odin delete mode 100644 examples/hms2019/hms2019.odin diff --git a/examples/hms2019/basic.odin b/examples/hms2019/basic.odin deleted file mode 100644 index 4c4a4eff0..000000000 --- a/examples/hms2019/basic.odin +++ /dev/null @@ -1,7 +0,0 @@ -package basic - -import "core:fmt" - -main :: proc() { - fmt.println("Hellope!"); -} \ No newline at end of file diff --git a/examples/hms2019/eca.odin b/examples/hms2019/eca.odin deleted file mode 100644 index eaefeeb9b..000000000 --- a/examples/hms2019/eca.odin +++ /dev/null @@ -1,67 +0,0 @@ -package eca - -import "core:fmt" -import "core:math/rand" -import "core:time" -import "intrinsics" - -elementary_cellular_automata :: proc(state: $T, rule: u8, generations: int, pause: time.Duration = 0) - where intrinsics.type_is_integer(T), - intrinsics.type_is_unsigned(T) { - N :: 8*size_of(state); - - output :: proc(state: T) { - buf: [N]byte; - for i in 0.. T { - return (x >> i) & 0x1; - } - set :: proc(x: ^T, cell, k: T, rule: u8) { - x^ &~= 1<>k&1 != 0 { - x^ |= 1< 0 do time.sleep(pause); - - - k := bit(a, last) | bit(a, 0)<<1 | bit(a, 1)<<2; - set(&a1, 0, k, rule); - a1 |= (1<<0) * T(rule>>k&1); - for c in 1..>1 | bit(a, c+1)<<2; - set(&a1, c, k, rule); - } - set(&a1, last, k>>1|bit(a, 0)<<2, rule); - a, a1 = a1, a; - output(a); - if a == a1 { - return; - } - } -} - -main :: proc() { - elementary_cellular_automata( - state=rand.uint128(), - rule=30, - generations=5000, - pause=100*time.Millisecond, - ); -} \ No newline at end of file diff --git a/examples/hms2019/hms2019.odin b/examples/hms2019/hms2019.odin deleted file mode 100644 index 5c2e836f8..000000000 --- a/examples/hms2019/hms2019.odin +++ /dev/null @@ -1,1754 +0,0 @@ -package hms2019 - -import "core:fmt" -import "core:mem" -import "core:os" -import "core:reflect" -import "intrinsics" - -/* - Welcome to Handmade Seattle 2019! - - The Odin programming language is fast, concise, readable, pragmatic and open sourced. - It is designed with the intent of replacing C with the following goals: - * simplicity - * high performance - * built for modern systems - * joy of programming - - # Installing Odin - Getting Started - https://odin-lang.org/docs/install/ - Instructions for downloading and install the Odin compiler and libraries. - - # Learning Odin - Overview of Odin - https://odin-lang.org/docs/overview/ - An overview of the Odin programming language. - Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/ - Answers to common questions about Odin. -*/ - -the_basics :: proc() { - fmt.println("\n# the basics"); - - { // The Basics - fmt.println("Hellope"); - - // Lexical elements and literals - // A comment - - my_integer_variable: int; // A comment for documentaton - - // Multi-line comments begin with /* and end with */. Multi-line comments can - // also be nested (unlike in C): - /* - You can have any text or code here and - have it be commented. - /* - NOTE: comments can be nested! - */ - */ - - // String literals are enclosed in double quotes and character literals in single quotes. - // Special characters are escaped with a backslash \ - - some_string := "This is a string"; - _ = 'A'; // unicode codepoint literal - _ = '\n'; - _ = "C:\\Windows\\notepad.exe"; - // Raw string literals are enclosed with single back ticks - _ = `C:\Windows\notepad.exe`; - - // The length of a string in bytes can be found using the built-in `len` procedure: - _ = len("Foo"); - _ = len(some_string); - - - // Numbers - - // Numerical literals are written similar to most other programming languages. - // A useful feature in Odin is that underscores are allowed for better - // readability: 1_000_000_000 (one billion). A number that contains a dot is a - // floating point literal: 1.0e9 (one billion). If a number literal is suffixed - // with i, is an imaginary number literal: 2i (2 multiply the square root of -1). - - // Binary literals are prefixed with 0b, octal literals with 0o, and hexadecimal - // literals 0x. A leading zero does not produce an octal constant (unlike C). - - // In Odin, if a number constant is possible to be represented by a type without - // precision loss, it will automatically convert to that type. - - x: int = 1.0; // A float literal but it can be represented by an integer without precision loss - // Constant literals are “untyped” which means that they can implicitly convert to a type. - - y: int; // `y` is typed of type `int` - y = 1; // `1` is an untyped integer literal which can implicitly convert to `int` - - z: f64; // `z` is typed of type `f64` (64-bit floating point number) - z = 1; // `1` is an untyped integer literals which can be implicity conver to `f64` - // No need for any suffixes or decimal places like in other languages - // CONSTANTS JUST WORK!!! - - - // Assignment statements - h: int = 123; // declares a new variable `h` with type `int` and assigns a value to it - h = 637; // assigns a new value to `h` - - // `=` is the assignment operator - - // You can assign multiple variables with it: - a, b := 1, "hello"; // declares `a` and `b` and infers the types from the assignments - b, a = "byte", 0; - - // Note: `:=` is two tokens, `:` and `=`. The follow are equivalent - /* - i: int = 123; - i: = 123; - i := 123 - */ - - // Constant declarations - // Constants are entities (symbols) which have an assigned value. - // The constant’s value cannot be changed. - // The constant’s value must be able to be evaluated at compile time: - X :: "what"; // constant `X` has the untyped string value "what" - - // Constants can be explicitly typed like a variable declaration: - Y : int : 123; - Z :: Y + 7; // constant computations are possible - } -} - -control_flow :: proc() { - fmt.println("\n# control flow"); - { // Control flow - // For loop - // Odin has only one loop statement, the `for` loop - - // Basic for loop - for i := 0; i < 10; i += 1 { - fmt.println(i); - } - - // NOTE: Unlike other languages like C, there are no parentheses `( )` surrounding the three components. - // Braces `{ }` or a `do` are always required> - for i := 0; i < 10; i += 1 { } - for i := 0; i < 10; i += 1 do fmt.print(); - - // The initial and post statements are optional - i := 0; - for ; i < 10; { - i += 1; - } - - // These semicolons can be dropped. This `for` loop is equivalent to C's `while` loop - i = 0; - for i < 10 { - i += 1; - } - - // If the condition is omitted, this produces an infinite loop: - for { - break; - } - - // Range-based for loop - // The basic for loop - for i := 0; i < 10; i += 1 { - fmt.println(i); - } - // can also be written - for i in 0..<10 { - fmt.println(i); - } - for i in 0..9 { - fmt.println(i); - } - - // Certain built-in types can be iterated over - some_string := "Hello, 世界"; - for character in some_string { // Strings are assumed to be UTF-8 - fmt.println(character); - } - - some_array := [3]int{1, 4, 9}; - for value in some_array { - fmt.println(value); - } - - some_slice := []int{1, 4, 9}; - for value in some_slice { - fmt.println(value); - } - - some_dynamic_array := [dynamic]int{1, 4, 9}; - defer delete(some_dynamic_array); - for value in some_dynamic_array { - fmt.println(value); - } - - - some_map := map[string]int{"A" = 1, "C" = 9, "B" = 4}; - defer delete(some_map); - for key in some_map { - fmt.println(key); - } - - // Alternatively a second index value can be added - for character, index in some_string { - fmt.println(index, character); - } - for value, index in some_array { - fmt.println(index, value); - } - for value, index in some_slice { - fmt.println(index, value); - } - for value, index in some_dynamic_array { - fmt.println(index, value); - } - for key, value in some_map { - fmt.println(key, value); - } - - // The iterated values are copies and cannot be written to. - // The following idiom is useful for iterating over a container in a by-reference manner: - for _, i in some_slice { - some_slice[i] = (i+1)*(i+1); - } - - - // If statements - x := 123; - if x >= 0 { - fmt.println("x is positive"); - } - - if y := -34; y < 0 { - fmt.println("y is negative"); - } - - if y := 123; y < 0 { - fmt.println("y is negative"); - } else if y == 0 { - fmt.println("y is zero"); - } else { - fmt.println("y is positive"); - } - - // Switch statement - // A switch statement is another way to write a sequence of if-else statements. - // In Odin, the default case is denoted as a case without any expression. - - switch arch := ODIN_ARCH; arch { - case "386": - fmt.println("32-bit"); - case "amd64": - fmt.println("64-bit"); - case: // default - fmt.println("Unsupported architecture"); - } - - // Odin’s `switch` is like one in C or C++, except that Odin only runs the selected case. - // This means that a `break` statement is not needed at the end of each case. - // Another important difference is that the case values need not be integers nor constants. - - // To achieve a C-like fall through into the next case block, the keyword `fallthrough` can be used. - one_angry_dwarf :: proc() -> int { - fmt.println("one_angry_dwarf was called"); - return 1; - } - - switch i := 0; i { - case 0: - case one_angry_dwarf(): - } - - // A switch statement without a condition is the same as `switch true`. - // This can be used to write a clean and long if-else chain and have the - // ability to break if needed - - switch { - case x < 0: - fmt.println("x is negative"); - case x == 0: - fmt.println("x is zero"); - case: - fmt.println("x is positive"); - } - - // A `switch` statement can also use ranges like a range-based loop: - switch c := 'j'; c { - case 'A'..'Z', 'a'..'z', '0'..'9': - fmt.println("c is alphanumeric"); - } - - switch x { - case 0..<10: - fmt.println("units"); - case 10..<13: - fmt.println("pre-teens"); - case 13..<20: - fmt.println("teens"); - case 20..<30: - fmt.println("twenties"); - } - } - - { // Defer statement - // A defer statement defers the execution of a statement until the end of - // the scope it is in. - - // The following will print 4 then 234: - { - x := 123; - defer fmt.println(x); - { - defer x = 4; - x = 2; - } - fmt.println(x); - - x = 234; - } - - // You can defer an entire block too: - { - bar :: proc() {} - - defer { - fmt.println("1"); - fmt.println("2"); - } - - cond := false; - defer if cond { - bar(); - } - } - - // Defer statements are executed in the reverse order that they were declared: - { - defer fmt.println("1"); - defer fmt.println("2"); - defer fmt.println("3"); - } - // Will print 3, 2, and then 1. - - if false { - f, err := os.open("my_file.txt"); - if err != 0 { - // handle error - } - defer os.close(f); - // rest of code - } - } - - { // When statement - /* - The when statement is almost identical to the if statement but with some differences: - - * Each condition must be a constant expression as a when - statement is evaluated at compile time. - * The statements within a branch do not create a new scope - * The compiler checks the semantics and code only for statements - that belong to the first condition that is true - * An initial statement is not allowed in a when statement - * when statements are allowed at file scope - */ - - // Example - when ODIN_ARCH == "386" { - fmt.println("32 bit"); - } else when ODIN_ARCH == "amd64" { - fmt.println("64 bit"); - } else { - fmt.println("Unsupported architecture"); - } - // The when statement is very useful for writing platform specific code. - // This is akin to the #if construct in C’s preprocessor however, in Odin, - // it is type checked. - } - - { // Branch statements - cond, cond1, cond2 := false, false, false; - one_step :: proc() { fmt.println("one_step"); } - beyond :: proc() { fmt.println("beyond"); } - - // Break statement - for cond { - switch { - case: - if cond { - break; // break out of the `switch` statement - } - } - - break; // break out of the `for` statement - } - - loop: for cond1 { - for cond2 { - break loop; // leaves both loops - } - } - - // Continue statement - for cond { - if cond2 { - continue; - } - fmt.println("Hellope"); - } - - // Fallthrough statement - - // Odin’s switch is like one in C or C++, except that Odin only runs the selected - // case. This means that a break statement is not needed at the end of each case. - // Another important difference is that the case values need not be integers nor - // constants. - - // fallthrough can be used to explicitly fall through into the next case block: - - switch i := 0; i { - case 0: - one_step(); - fallthrough; - case 1: - beyond(); - } - } -} - - -named_proc_return_parameters :: proc() { - fmt.println("\n# named proc return parameters"); - - foo0 :: proc() -> int { - return 123; - } - foo1 :: proc() -> (a: int) { - a = 123; - return; - } - foo2 :: proc() -> (a, b: int) { - // Named return values act like variables within the scope - a = 321; - b = 567; - return b, a; - } - fmt.println("foo0 =", foo0()); // 123 - fmt.println("foo1 =", foo1()); // 123 - fmt.println("foo2 =", foo2()); // 567 321 -} - - -explicit_procedure_overloading :: proc() { - fmt.println("\n# explicit procedure overloading"); - - add_ints :: proc(a, b: int) -> int { - x := a + b; - fmt.println("add_ints", x); - return x; - } - add_floats :: proc(a, b: f32) -> f32 { - x := a + b; - fmt.println("add_floats", x); - return x; - } - add_numbers :: proc(a: int, b: f32, c: u8) -> int { - x := int(a) + int(b) + int(c); - fmt.println("add_numbers", x); - return x; - } - - add :: proc{add_ints, add_floats, add_numbers}; - - add(int(1), int(2)); - add(f32(1), f32(2)); - add(int(1), f32(2), u8(3)); - - add(1, 2); // untyped ints coerce to int tighter than f32 - add(1.0, 2.0); // untyped floats coerce to f32 tighter than int - add(1, 2, 3); // three parameters - - // Ambiguous answers - // add(1.0, 2); - // add(1, 2.0); -} - -struct_type :: proc() { - fmt.println("\n# struct type"); - // A struct is a record type in Odin. It is a collection of fields. - // Struct fields are accessed by using a dot: - { - Vector2 :: struct { - x: f32, - y: f32, - }; - v := Vector2{1, 2}; - v.x = 4; - fmt.println(v.x); - - // Struct fields can be accessed through a struct pointer: - - v = Vector2{1, 2}; - p := &v; - p.x = 1335; - fmt.println(v); - - // We could write p^.x, however, it is to nice abstract the ability - // to not explicitly dereference the pointer. This is very useful when - // refactoring code to use a pointer rather than a value, and vice versa. - } - { - // A struct literal can be denoted by providing the struct’s type - // followed by {}. A struct literal must either provide all the - // arguments or none: - Vector3 :: struct { - x, y, z: f32, - }; - v: Vector3; - v = Vector3{}; // Zero value - v = Vector3{1, 4, 9}; - - // You can list just a subset of the fields if you specify the - // field by name (the order of the named fields does not matter): - v = Vector3{z=1, y=2}; - assert(v.x == 0); - assert(v.y == 2); - assert(v.z == 1); - } - { - // Structs can tagged with different memory layout and alignment requirements: - - a :: struct #align 4 {}; // align to 4 bytes - b :: struct #packed {}; // remove padding between fields - c :: struct #raw_union {}; // all fields share the same offset (0). This is the same as C's union - } - -} - - -union_type :: proc() { - fmt.println("\n# union type"); - { - val: union{int, bool}; - val = 137; - if i, ok := val.(int); ok { - fmt.println(i); - } - val = true; - fmt.println(val); - - val = nil; - - switch v in val { - case int: fmt.println("int", v); - case bool: fmt.println("bool", v); - case: fmt.println("nil"); - } - } - { - // There is a duality between `any` and `union` - // An `any` has a pointer to the data and allows for any type (open) - // A `union` has as binary blob to store the data and allows only certain types (closed) - // The following code is with `any` but has the same syntax - val: any; - val = 137; - if i, ok := val.(int); ok { - fmt.println(i); - } - val = true; - fmt.println(val); - - val = nil; - - switch v in val { - case int: fmt.println("int", v); - case bool: fmt.println("bool", v); - case: fmt.println("nil"); - } - } - - Vector3 :: distinct [3]f32; - Quaternion :: distinct quaternion128; - - // More realistic examples - { - // NOTE(bill): For the above basic examples, you may not have any - // particular use for it. However, my main use for them is not for these - // simple cases. My main use is for hierarchical types. Many prefer - // subtyping, embedding the base data into the derived types. Below is - // an example of this for a basic game Entity. - - Entity :: struct { - id: u64, - name: string, - position: Vector3, - orientation: Quaternion, - - derived: any, - }; - - Frog :: struct { - using entity: Entity, - jump_height: f32, - }; - - Monster :: struct { - using entity: Entity, - is_robot: bool, - is_zombie: bool, - }; - - // See `parametric_polymorphism` procedure for details - new_entity :: proc($T: typeid) -> ^Entity { - t := new(T); - t.derived = t^; - return t; - } - - entity := new_entity(Monster); - - switch e in entity.derived { - case Frog: - fmt.println("Ribbit"); - case Monster: - if e.is_robot do fmt.println("Robotic"); - if e.is_zombie do fmt.println("Grrrr!"); - fmt.println("I'm a monster"); - } - } - - { - // NOTE(bill): A union can be used to achieve something similar. Instead - // of embedding the base data into the derived types, the derived data - // in embedded into the base type. Below is the same example of the - // basic game Entity but using an union. - - Entity :: struct { - id: u64, - name: string, - position: Vector3, - orientation: Quaternion, - - derived: union {Frog, Monster}, - }; - - Frog :: struct { - using entity: ^Entity, - jump_height: f32, - }; - - Monster :: struct { - using entity: ^Entity, - is_robot: bool, - is_zombie: bool, - }; - - // See `parametric_polymorphism` procedure for details - new_entity :: proc($T: typeid) -> ^Entity { - t := new(Entity); - t.derived = T{entity = t}; - return t; - } - - entity := new_entity(Monster); - - switch e in entity.derived { - case Frog: - fmt.println("Ribbit"); - case Monster: - if e.is_robot do fmt.println("Robotic"); - if e.is_zombie do fmt.println("Grrrr!"); - } - - // NOTE(bill): As you can see, the usage code has not changed, only its - // memory layout. Both approaches have their own advantages but they can - // be used together to achieve different results. The subtyping approach - // can allow for a greater control of the memory layout and memory - // allocation, e.g. storing the derivatives together. However, this is - // also its disadvantage. You must either preallocate arrays for each - // derivative separation (which can be easily missed) or preallocate a - // bunch of "raw" memory; determining the maximum size of the derived - // types would require the aid of metaprogramming. Unions solve this - // particular problem as the data is stored with the base data. - // Therefore, it is possible to preallocate, e.g. [100]Entity. - - // It should be noted that the union approach can have the same memory - // layout as the any and with the same type restrictions by using a - // pointer type for the derivatives. - - /* - Entity :: struct { - ... - derived: union{^Frog, ^Monster}, - } - - Frog :: struct { - using entity: Entity, - ... - } - Monster :: struct { - using entity: Entity, - ... - - } - new_entity :: proc(T: type) -> ^Entity { - t := new(T); - t.derived = t; - return t; - } - */ - } -} - -using_statement :: proc() { - fmt.println("\n# using statement"); - // using can used to bring entities declared in a scope/namespace - // into the current scope. This can be applied to import declarations, - // import names, struct fields, procedure fields, and struct values. - - Vector3 :: struct{x, y, z: f32}; - { - Entity :: struct { - position: Vector3, - orientation: quaternion128, - }; - - // It can used like this: - foo0 :: proc(entity: ^Entity) { - fmt.println(entity.position.x, entity.position.y, entity.position.z); - } - - // The entity members can be brought into the procedure scope by using it: - foo1 :: proc(entity: ^Entity) { - using entity; - fmt.println(position.x, position.y, position.z); - } - - // The using can be applied to the parameter directly: - foo2 :: proc(using entity: ^Entity) { - fmt.println(position.x, position.y, position.z); - } - - // It can also be applied to sub-fields: - foo3 :: proc(entity: ^Entity) { - using entity.position; - fmt.println(x, y, z); - } - } - { - // We can also apply the using statement to the struct fields directly, - // making all the fields of position appear as if they on Entity itself: - Entity :: struct { - using position: Vector3, - orientation: quaternion128, - }; - foo :: proc(entity: ^Entity) { - fmt.println(entity.x, entity.y, entity.z); - } - - - // Subtype polymorphism - // It is possible to get subtype polymorphism, similar to inheritance-like - // functionality in C++, but without the requirement of vtables or unknown - // struct layout: - - Colour :: struct {r, g, b, a: u8}; - Frog :: struct { - ribbit_volume: f32, - using entity: Entity, - colour: Colour, - }; - - frog: Frog; - // Both work - foo(&frog.entity); - foo(&frog); - frog.x = 123; - - // Note: using can be applied to arbitrarily many things, which allows - // the ability to have multiple subtype polymorphism (but also its issues). - - // Note: using’d fields can still be referred by name. - } - { // using on an enum declaration - - using Foo :: enum {A, B, C}; - - f0 := A; - f1 := B; - f2 := C; - fmt.println(f0, f1, f2); - fmt.println(len(Foo)); - } -} - - -implicit_context_system :: proc() { - fmt.println("\n# implicit context system"); - // In each scope, there is an implicit value named context. This - // context variable is local to each scope and is implicitly passed - // by pointer to any procedure call in that scope (if the procedure - // has the Odin calling convention). - - // The main purpose of the implicit context system is for the ability - // to intercept third-party code and libraries and modify their - // functionality. One such case is modifying how a library allocates - // something or logs something. In C, this was usually achieved with - // the library defining macros which could be overridden so that the - // user could define what he wanted. However, not many libraries - // supported this in many languages by default which meant intercepting - // third-party code to see what it does and to change how it does it is - // not possible. - - c := context; // copy the current scope's context - - context.user_index = 456; - { - context.allocator = my_custom_allocator(); - context.user_index = 123; - what_a_fool_believes(); // the `context` for this scope is implicitly passed to `what_a_fool_believes` - } - - // `context` value is local to the scope it is in - assert(context.user_index == 456); - - what_a_fool_believes :: proc() { - c := context; // this `context` is the same as the parent procedure that it was called from - // From this example, context.user_index == 123 - // An context.allocator is assigned to the return value of `my_custom_allocator()` - assert(context.user_index == 123); - - // The memory management procedure use the `context.allocator` by - // default unless explicitly specified otherwise - china_grove := new(int); - free(china_grove); - } - - my_custom_allocator :: mem.nil_allocator; - - // By default, the context value has default values for its parameters which is - // decided in the package runtime. What the defaults are are compiler specific. - - // To see what the implicit context value contains, please see the following - // definition in package runtime. -} - -parametric_polymorphism :: proc() { - fmt.println("\n# parametric polymorphism"); - - print_value :: proc(value: $T) { - fmt.printf("print_value: %T %v\n", value, value); - } - - v1: int = 1; - v2: f32 = 2.1; - v3: f64 = 3.14; - v4: string = "message"; - - print_value(v1); - print_value(v2); - print_value(v3); - print_value(v4); - - fmt.println(); - - add :: proc(p, q: $T) -> T { - x: T = p + q; - return x; - } - - a := add(3, 4); - fmt.printf("a: %T = %v\n", a, a); - - b := add(3.2, 4.3); - fmt.printf("b: %T = %v\n", b, b); - - // This is how `new` is implemented - alloc_type :: proc($T: typeid) -> ^T { - t := cast(^T)alloc(size_of(T), align_of(T)); - t^ = T{}; // Use default initialization value - return t; - } - - copy_slice :: proc(dst, src: []$T) -> int { - n := min(len(dst), len(src)); - if n > 0 { - mem.copy(&dst[0], &src[0], n*size_of(T)); - } - return n; - } - - double_params :: proc(a: $A, b: $B) -> A { - return a + A(b); - } - - fmt.println(double_params(12, 1.345)); - - - - { // Polymorphic Types and Type Specialization - Table_Slot :: struct(Key, Value: typeid) { - occupied: bool, - hash: u32, - key: Key, - value: Value, - }; - TABLE_SIZE_MIN :: 32; - Table :: struct(Key, Value: typeid) { - count: int, - allocator: mem.Allocator, - slots: []Table_Slot(Key, Value), - }; - - // Only allow types that are specializations of a (polymorphic) slice - make_slice :: proc($T: typeid/[]$E, len: int) -> T { - return make(T, len); - } - - // Only allow types that are specializations of `Table` - allocate :: proc(table: ^$T/Table, capacity: int) { - c := context; - if table.allocator.procedure != nil do c.allocator = table.allocator; - context = c; - - table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN)); - } - - expand :: proc(table: ^$T/Table) { - c := context; - if table.allocator.procedure != nil do c.allocator = table.allocator; - context = c; - - old_slots := table.slots; - defer delete(old_slots); - - cap := max(2*len(table.slots), TABLE_SIZE_MIN); - allocate(table, cap); - - for s in old_slots do if s.occupied { - put(table, s.key, s.value); - } - } - - // Polymorphic determination of a polymorphic struct - // put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) { - put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) { - hash := get_hash(key); // Ad-hoc method which would fail in a different scope - index := find_index(table, key, hash); - if index < 0 { - if f64(table.count) >= 0.75*f64(len(table.slots)) { - expand(table); - } - assert(table.count <= len(table.slots)); - - index = int(hash % u32(len(table.slots))); - - for table.slots[index].occupied { - if index += 1; index >= len(table.slots) { - index = 0; - } - } - - table.count += 1; - } - - slot := &table.slots[index]; - slot.occupied = true; - slot.hash = hash; - slot.key = key; - slot.value = value; - } - - - // find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) { - find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) { - hash := get_hash(key); - index := find_index(table, key, hash); - if index < 0 { - return Value{}, false; - } - return table.slots[index].value, true; - } - - find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int { - if len(table.slots) <= 0 do return -1; - - index := int(hash % u32(len(table.slots))); - for table.slots[index].occupied { - if table.slots[index].hash == hash { - if table.slots[index].key == key { - return index; - } - } - - if index += 1; index >= len(table.slots) { - index = 0; - } - } - - return -1; - } - - get_hash :: proc(s: string) -> u32 { // fnv32a - h: u32 = 0x811c9dc5; - for i in 0.. (res: [N]T) { - // `N` is the constant value passed - // `I` is the type of N - // `T` is the type passed - fmt.printf("Generating an array of type %v from the value %v of type %v\n", - typeid_of(type_of(res)), N, typeid_of(I)); - for i in 0.. (c: [M][P]T) { - for i in 0.. Vector3 { - i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1); - j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0); - return i - j; - } - - blah :: proc(a: Vector3) -> f32 { - return a.x + a.y + a.z; - } - - x := cross(a, b); - fmt.println(x); - fmt.println(blah(x)); - } -} - -map_type :: proc() { - fmt.println("\n# map type"); - - m := make(map[string]int); - defer delete(m); - - m["Bob"] = 2; - m["Ted"] = 5; - fmt.println(m["Bob"]); - - delete_key(&m, "Ted"); - - // If an element of a key does not exist, the zero value of the - // element will be returned. To check to see if an element exists - // can be done in two ways: - elem, ok := m["Bob"]; - exists := "Bob" in m; - -} - -implicit_selector_expression :: proc() { - fmt.println("\n# implicit selector expression"); - - Foo :: enum {A, B, C}; - - f: Foo; - f = Foo.A; - f = .A; - - BAR :: bit_set[Foo]{.B, .C}; - - switch f { - case .A: - fmt.println("HERE"); - case .B: - fmt.println("NEVER"); - case .C: - fmt.println("FOREVER"); - } - - my_map := make(map[Foo]int); - defer delete(my_map); - - my_map[.A] = 123; - my_map[Foo.B] = 345; - - fmt.println(my_map[.A] + my_map[Foo.B] + my_map[.C]); -} - - -complete_switch :: proc() { - fmt.println("\n# complete_switch"); - { // enum - Foo :: enum { - A, - B, - C, - D, - }; - - f := Foo.A; - #complete switch f { - case .A: fmt.println("A"); - case .B: fmt.println("B"); - case .C: fmt.println("C"); - case .D: fmt.println("D"); - case: fmt.println("?"); - } - } - { // union - Foo :: union {int, bool}; - f: Foo = 123; - #complete switch in f { - case int: fmt.println("int"); - case bool: fmt.println("bool"); - case: - } - } -} - -cstring_example :: proc() { - fmt.println("\n# cstring_example"); - - W :: "Hellope"; - X :: cstring(W); - Y :: string(X); - - w := W; - _ = w; - x: cstring = X; - y: string = Y; - z := string(x); - fmt.println(x, y, z); - fmt.println(len(x), len(y), len(z)); - fmt.println(len(W), len(X), len(Y)); - // IMPORTANT NOTE for cstring variables - // len(cstring) is O(N) - // cast(string)cstring is O(N) -} - -bit_set_type :: proc() { - fmt.println("\n# bit_set type"); - - { - using Day :: enum { - Sunday, - Monday, - Tuesday, - Wednesday, - Thursday, - Friday, - Saturday, - }; - - Days :: distinct bit_set[Day]; - WEEKEND :: Days{Sunday, Saturday}; - - d: Days; - d = {Sunday, Monday}; - e := d | WEEKEND; - e |= {Monday}; - fmt.println(d, e); - - ok := Saturday in e; // `in` is only allowed for `map` and `bit_set` types - fmt.println(ok); - if Saturday in e { - fmt.println("Saturday in", e); - } - X :: Saturday in WEEKEND; // Constant evaluation - fmt.println(X); - fmt.println("Cardinality:", card(e)); - } - { - x: bit_set['A'..'Z']; - #assert(size_of(x) == size_of(u32)); - y: bit_set[0..8; u16]; - fmt.println(typeid_of(type_of(x))); // bit_set[A..Z] - fmt.println(typeid_of(type_of(y))); // bit_set[0..8; u16] - - incl(&x, 'F'); - assert('F' in x); - excl(&x, 'F'); - assert('F' not_in x); - - y |= {1, 4, 2}; - assert(2 in y); - } - { - Letters :: bit_set['A'..'Z']; - a := Letters{'A', 'B'}; - b := Letters{'A', 'B', 'C', 'D', 'F'}; - c := Letters{'A', 'B'}; - - assert(a <= b); // 'a' is a subset of 'b' - assert(b >= a); // 'b' is a superset of 'a' - assert(a < b); // 'a' is a strict subset of 'b' - assert(b > a); // 'b' is a strict superset of 'a' - - assert(!(a < c)); // 'a' is a not strict subset of 'c' - assert(!(c > a)); // 'c' is a not strict superset of 'a' - } -} - -deferred_procedure_associations :: proc() { - fmt.println("\n# deferred procedure associations"); - - @(deferred_out=closure) - open :: proc(s: string) -> bool { - fmt.println(s); - return true; - } - - closure :: proc(ok: bool) { - fmt.println("Goodbye?", ok); - } - - if open("Welcome") { - fmt.println("Something in the middle, mate."); - } -} - -reflection :: proc() { - fmt.println("\n# reflection"); - - Foo :: struct { - x: int `tag1`, - y: string `json:"y_field"`, - z: bool, // no tag - }; - - id := typeid_of(Foo); - names := reflect.struct_field_names(id); - types := reflect.struct_field_types(id); - tags := reflect.struct_field_tags(id); - - assert(len(names) == len(types) && len(names) == len(tags)); - - fmt.println("Foo :: struct {"); - for tag, i in tags { - name, type := names[i], types[i]; - if tag != "" { - fmt.printf("\t%s: %T `%s`,\n", name, type, tag); - } else { - fmt.printf("\t%s: %T,\n", name, type); - } - } - fmt.println("}"); - - - for tag, i in tags { - if val, ok := reflect.struct_tag_lookup(tag, "json"); ok { - fmt.printf("json: %s -> %s\n", names[i], val); - } - } -} - -quaternions :: proc() { - // Not just an April Fool's Joke any more, but a fully working thing! - fmt.println("\n# quaternions"); - - { // Quaternion operations - q := 1 + 2i + 3j + 4k; - r := quaternion(5, 6, 7, 8); - t := q * r; - fmt.printf("(%v) * (%v) = %v\n", q, r, t); - v := q / r; - fmt.printf("(%v) / (%v) = %v\n", q, r, v); - u := q + r; - fmt.printf("(%v) + (%v) = %v\n", q, r, u); - s := q - r; - fmt.printf("(%v) - (%v) = %v\n", q, r, s); - } - { // The quaternion types - q128: quaternion128; // 4xf32 - q256: quaternion256; // 4xf64 - q128 = quaternion(1, 0, 0, 0); - q256 = 1; // quaternion(1, 0, 0, 0); - } - { // Built-in procedures - q := 1 + 2i + 3j + 4k; - fmt.println("q =", q); - fmt.println("real(q) =", real(q)); - fmt.println("imag(q) =", imag(q)); - fmt.println("jmag(q) =", jmag(q)); - fmt.println("kmag(q) =", kmag(q)); - fmt.println("conj(q) =", conj(q)); - fmt.println("abs(q) =", abs(q)); - } - { // Conversion of a complex type to a quaternion type - c := 1 + 2i; - q := quaternion256(c); - fmt.println(c); - fmt.println(q); - } - { // Memory layout of Quaternions - q := 1 + 2i + 3j + 4k; - a := transmute([4]f64)q; - fmt.println("Quaternion memory layout: xyzw/(ijkr)"); - fmt.println(q); // 1.000+2.000i+3.000j+4.000k - fmt.println(a); // [2.000, 3.000, 4.000, 1.000] - } -} - -inline_for_statement :: proc() { - fmt.println("\n#inline for statements"); - - // 'inline for' works the same as if the 'inline' prefix did not - // exist but these ranged loops are explicitly unrolled which can - // be very very useful for certain optimizations - - fmt.println("Ranges"); - inline for x, i in 1..<4 { - fmt.println(x, i); - } - - fmt.println("Strings"); - inline for r, i in "Hello, 世界" { - fmt.println(r, i); - } - - fmt.println("Arrays"); - inline for elem, idx in ([4]int{1, 4, 9, 16}) { - fmt.println(elem, idx); - } - - - Foo_Enum :: enum { - A = 1, - B, - C = 6, - D, - }; - fmt.println("Enum types"); - inline for elem, idx in Foo_Enum { - fmt.println(elem, idx); - } -} - -where_clauses :: proc() { - fmt.println("\n#procedure 'where' clauses"); - - { // Sanity checks - simple_sanity_check :: proc(x: [2]int) - where len(x) > 1, - type_of(x) == [2]int { - fmt.println(x); - } - } - { // Parametric polymorphism checks - cross_2d :: proc(a, b: $T/[2]$E) -> E - where intrinsics.type_is_numeric(E) { - return a.x*b.y - a.y*b.x; - } - cross_3d :: proc(a, b: $T/[3]$E) -> T - where intrinsics.type_is_numeric(E) { - x := a.y*b.z - a.z*b.y; - y := a.z*b.x - a.x*b.z; - z := a.x*b.y - a.y*b.z; - return T{x, y, z}; - } - - a := [2]int{1, 2}; - b := [2]int{5, -3}; - fmt.println(cross_2d(a, b)); - - x := [3]f32{1, 4, 9}; - y := [3]f32{-5, 0, 3}; - fmt.println(cross_3d(x, y)); - - // Failure case - // i := [2]bool{true, false}; - // j := [2]bool{false, true}; - // fmt.println(cross_2d(i, j)); - - } - - { // Procedure groups usage - foo :: proc(x: [$N]int) -> bool - where N > 2 { - fmt.println(#procedure, "was called with the parameter", x); - return true; - } - - bar :: proc(x: [$N]int) -> bool - where 0 < N, - N <= 2 { - fmt.println(#procedure, "was called with the parameter", x); - return false; - } - - baz :: proc{foo, bar}; - - x := [3]int{1, 2, 3}; - y := [2]int{4, 9}; - ok_x := baz(x); - ok_y := baz(y); - assert(ok_x == true); - assert(ok_y == false); - } - - { // Record types - Foo :: struct(T: typeid, N: int) - where intrinsics.type_is_integer(T), - N > 2 { - x: [N]T, - y: [N-2]T, - }; - - T :: i32; - N :: 5; - f: Foo(T, N); - #assert(size_of(f) == (N+N-2)*size_of(T)); - } -} - - -when ODIN_OS == "windows" do foreign import kernel32 "system:kernel32.lib" - -foreign_system :: proc() { - fmt.println("\n#foreign system"); - when ODIN_OS == "windows" { - // It is sometimes necessarily to interface with foreign code, - // such as a C library. In Odin, this is achieved through the - // foreign system. You can “import” a library into the code - // using the same semantics as a normal import declaration. - - // This foreign import declaration will create a - // “foreign import name” which can then be used to associate - // entities within a foreign block. - - foreign kernel32 { - ExitProcess :: proc "stdcall" (exit_code: u32) --- - } - - // Foreign procedure declarations have the cdecl/c calling - // convention by default unless specified otherwise. Due to - // foreign procedures do not have a body declared within this - // code, you need append the --- symbol to the end to distinguish - // it as a procedure literal without a body and not a procedure type. - - // The attributes system can be used to change specific properties - // of entities declared within a block: - - @(default_calling_convention = "std") - foreign kernel32 { - @(link_name="GetLastError") get_last_error :: proc() -> i32 --- - } - - // Example using the link_prefix attribute - @(default_calling_convention = "std") - @(link_prefix = "Get") - foreign kernel32 { - LastError :: proc() -> i32 --- - } - } -} - -ranged_fields_for_array_compound_literals :: proc() { - fmt.println("\n#ranged fields for array compound literals"); - { // Normal Array Literal - foo := [?]int{1, 4, 9, 16}; - fmt.println(foo); - } - { // Indexed - foo := [?]int{ - 3 = 16, - 1 = 4, - 2 = 9, - 0 = 1, - }; - fmt.println(foo); - } - { // Ranges - i := 2; - foo := [?]int { - 0 = 123, - 5..9 = 54, - 10..<16 = i*3 + (i-1)*2, - }; - #assert(len(foo) == 16); - fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] - } - { // Slice and Dynamic Array support - i := 2; - foo_slice := []int { - 0 = 123, - 5..9 = 54, - 10..<16 = i*3 + (i-1)*2, - }; - assert(len(foo_slice) == 16); - fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] - - foo_dynamic_array := [dynamic]int { - 0 = 123, - 5..9 = 54, - 10..<16 = i*3 + (i-1)*2, - }; - assert(len(foo_dynamic_array) == 16); - fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] - } -} - -deprecated_attribute :: proc() { - @(deprecated="Use foo_v2 instead") - foo_v1 :: proc(x: int) { - fmt.println("foo_v1"); - } - foo_v2 :: proc(x: int) { - fmt.println("foo_v2"); - } - - // NOTE: Uncomment to see the warning messages - // foo_v1(1); -} - -range_statements_with_multiple_return_values :: proc() { - // IMPORTANT NOTE(bill, 2019-11-02): This feature is subject to be changed/removed - fmt.println("\n#range statements with multiple return values"); - My_Iterator :: struct { - index: int, - data: []i32, - }; - make_my_iterator :: proc(data: []i32) -> My_Iterator { - return My_Iterator{data = data}; - } - my_iterator :: proc(it: ^My_Iterator) -> (val: i32, idx: int, cond: bool) { - if cond = it.index < len(it.data); cond { - val = it.data[it.index]; - idx = it.index; - it.index += 1; - } - return; - } - - data := make([]i32, 6); - for _, i in data { - data[i] = i32(i*i); - } - - { - it := make_my_iterator(data); - for val in my_iterator(&it) { - fmt.println(val); - } - } - { - it := make_my_iterator(data); - for val, idx in my_iterator(&it) { - fmt.println(val, idx); - } - } - { - it := make_my_iterator(data); - for { - val, _, cond := my_iterator(&it); - if !cond do break; - fmt.println(val); - } - } -} - -soa_struct_layout :: proc() { - // IMPORTANT NOTE(bill, 2019-11-03): This feature is subject to be changed/removed - // NOTE(bill): Most likely #soa [N]T - fmt.println("\n#SOA Struct Layout"); - - { - Vector3 :: struct {x, y, z: f32}; - - N :: 2; - v_aos: [N]Vector3; - v_aos[0].x = 1; - v_aos[0].y = 4; - v_aos[0].z = 9; - - fmt.println(len(v_aos)); - fmt.println(v_aos[0]); - fmt.println(v_aos[0].x); - fmt.println(&v_aos[0].x); - - v_aos[1] = {0, 3, 4}; - v_aos[1].x = 2; - fmt.println(v_aos[1]); - fmt.println(v_aos); - - v_soa: #soa[N]Vector3; - - v_soa[0].x = 1; - v_soa[0].y = 4; - v_soa[0].z = 9; - - - // Same syntax as AOS and treat as if it was an array - fmt.println(len(v_soa)); - fmt.println(v_soa[0]); - fmt.println(v_soa[0].x); - v_soa[1] = {0, 3, 4}; - v_soa[1].x = 2; - fmt.println(v_soa[1]); - - // Can use SOA syntax if necessary - v_soa.x[0] = 1; - v_soa.y[0] = 4; - v_soa.z[0] = 9; - fmt.println(v_soa.x[0]); - - // Same pointer addresses with both syntaxes - assert(&v_soa[0].x == &v_soa.x[0]); - - - // Same fmt printing - fmt.println(v_aos); - fmt.println(v_soa); - } - { - // Works with arrays of length <= 4 which have the implicit fields xyzw/rgba - Vector3 :: distinct [3]f32; - - N :: 2; - v_aos: [N]Vector3; - v_aos[0].x = 1; - v_aos[0].y = 4; - v_aos[0].z = 9; - - v_soa: #soa[N]Vector3; - - v_soa[0].x = 1; - v_soa[0].y = 4; - v_soa[0].z = 9; - } -} - - -main :: proc() { - when true { - the_basics(); - control_flow(); - named_proc_return_parameters(); - explicit_procedure_overloading(); - struct_type(); - union_type(); - using_statement(); - implicit_context_system(); - parametric_polymorphism(); - array_programming(); - map_type(); - implicit_selector_expression(); - complete_switch(); - cstring_example(); - bit_set_type(); - deferred_procedure_associations(); - reflection(); - quaternions(); - inline_for_statement(); - where_clauses(); - foreign_system(); - ranged_fields_for_array_compound_literals(); - deprecated_attribute(); - range_statements_with_multiple_return_values(); - soa_struct_layout(); - } -} - From c21c993646e91bba76ba9d350cbe1f9c42f18ff4 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 2 Apr 2022 01:54:35 +0200 Subject: [PATCH 0493/1052] [strings] fix. --- core/strings/strings.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index d01be7989..8e774b367 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1804,7 +1804,7 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { return "", false } - field = s[:len(s)] + field = s[start:] ok = true s^ = s[len(s):] return From 88de3a1c0633761e2f73f4e576a0dfd2bb9c32bf Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 1 Apr 2022 22:41:35 -0400 Subject: [PATCH 0494/1052] add _chtimes --- core/os/os2/file_linux.odin | 10 ++++++++-- core/sys/unix/syscalls_linux.odin | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 3202b9e16..89075e00c 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -27,6 +27,8 @@ _O_SYNC :: 0o4010000 _O_CLOEXEC :: 0o2000000 _O_PATH :: 0o10000000 +_AT_FDCWD :: -100 + _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { cstr := strings.clone_to_cstring(name, context.temp_allocator) @@ -250,8 +252,12 @@ _lchown :: proc(name: string, uid, gid: int) -> Error { } _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { - //TODO - return nil + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + times := [2]Unix_File_Time { + { atime._nsec, 0 }, + { mtime._nsec, 0 }, + } + return _ok_or_error(unix.sys_utimensat(_AT_FDCWD, name_cstr, ×, 0)) } _exists :: proc(name: string) -> bool { diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 8a1aadb9c..6fc6dc594 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1779,6 +1779,12 @@ sys_fork :: proc() -> int { } } +// NOTE: Unsure about if this works directly on 32 bit archs. It may need 32 bit version of the time struct. +// As of Linux 5.1, there is a utimensat_time64 function. Maybe use this in the future? +sys_utimensat :: proc(dfd: int, path: cstring, times: rawptr, flags: int) -> int { + return int(intrinsics.syscall(SYS_utimensat, uintptr(dfd), uintptr(rawptr(path)), uintptr(times), uintptr(flags))) +} + get_errno :: proc(res: int) -> i32 { if res < 0 && res > -4096 { return i32(-res) From 850d4a1e1b8abdc9c3a5f35a768529c93ba68eeb Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 2 Apr 2022 07:38:11 +0300 Subject: [PATCH 0495/1052] sys/windows: add a couple of procedures and types --- core/sys/windows/types.odin | 63 ++++++++++++++++++++++++++++++++++++ core/sys/windows/user32.odin | 5 +++ 2 files changed, 68 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index d0551c6bf..e5e630c54 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -30,6 +30,7 @@ HBRUSH :: distinct HANDLE HGDIOBJ :: distinct HANDLE HBITMAP :: distinct HANDLE HGLOBAL :: distinct HANDLE +HHOOK :: distinct HANDLE BOOL :: distinct b32 BYTE :: distinct u8 BOOLEAN :: distinct b8 @@ -199,6 +200,24 @@ TIMERPROC :: #type proc "stdcall" (HWND, UINT, UINT_PTR, DWORD) WNDPROC :: #type proc "stdcall" (HWND, UINT, WPARAM, LPARAM) -> LRESULT +HOOKPROC :: #type proc "stdcall" (code: c_int, wParam: WPARAM, lParam: LPARAM) -> LRESULT + +CWPRETSTRUCT :: struct { + lResult: LRESULT, + lParam: LPARAM, + wParam: WPARAM, + message: UINT, + hwnd: HWND, +} + +KBDLLHOOKSTRUCT :: struct { + vkCode: DWORD, + scanCode: DWORD, + flags: DWORD, + time: DWORD, + dwExtraInfo: ULONG_PTR, +} + WNDCLASSA :: struct { style: UINT, lpfnWndProc: WNDPROC, @@ -698,6 +717,50 @@ HOVER_DEFAULT :: 0xFFFFFFFF USER_TIMER_MAXIMUM :: 0x7FFFFFFF USER_TIMER_MINIMUM :: 0x0000000A + +// SetWindowsHook() codes +WH_MIN :: -1 +WH_MSGFILTER :: -1 +WH_JOURNALRECORD :: 0 +WH_JOURNALPLAYBACK :: 1 +WH_KEYBOARD :: 2 +WH_GETMESSAGE :: 3 +WH_CALLWNDPROC :: 4 +WH_CBT :: 5 +WH_SYSMSGFILTER :: 6 +WH_MOUSE :: 7 +WH_HARDWARE :: 8 +WH_DEBUG :: 9 +WH_SHELL :: 10 +WH_FOREGROUNDIDLE :: 11 +WH_CALLWNDPROCRET :: 12 +WH_KEYBOARD_LL :: 13 +WH_MOUSE_LL :: 14 +WH_MAX :: 14 +WH_MINHOOK :: WH_MIN +WH_MAXHOOK :: WH_MAX + +// Hook Codes +HC_ACTION :: 0 +HC_GETNEXT :: 1 +HC_SKIP :: 2 +HC_NOREMOVE :: 3 +HC_NOREM :: HC_NOREMOVE +HC_SYSMODALON :: 4 +HC_SYSMODALOFF :: 5 + +// CBT Hook Codes +HCBT_MOVESIZE :: 0 +HCBT_MINMAX :: 1 +HCBT_QS :: 2 +HCBT_CREATEWND :: 3 +HCBT_DESTROYWND :: 4 +HCBT_ACTIVATE :: 5 +HCBT_CLICKSKIPPED :: 6 +HCBT_KEYSKIPPED :: 7 +HCBT_SYSCOMMAND :: 8 +HCBT_SETFOCUS :: 9 + _IDC_APPSTARTING := rawptr(uintptr(32650)) _IDC_ARROW := rawptr(uintptr(32512)) _IDC_CROSS := rawptr(uintptr(32515)) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 3985c9ad6..5b910ae73 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -131,6 +131,11 @@ foreign user32 { GetKeyState :: proc(nVirtKey: c_int) -> SHORT --- GetAsyncKeyState :: proc(vKey: c_int) -> SHORT --- + SetWindowsHookExA :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- + SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- + UnhookWindowsHookEx :: proc(hhk: HHOOK) -> BOOL --- + CallNextHookEx :: proc(hhk: HHOOK, nCode: c_int, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + SetTimer :: proc(hWnd: HWND, nIDEvent: UINT_PTR, uElapse: UINT, lpTimerFunc: TIMERPROC) -> UINT_PTR --- KillTimer :: proc(hWnd: HWND, uIDEvent: UINT_PTR) -> BOOL --- From 4c14e929527627a87b076b0433e95a7cdcf68f79 Mon Sep 17 00:00:00 2001 From: hikari Date: Sat, 2 Apr 2022 08:23:12 +0300 Subject: [PATCH 0496/1052] sys/windows: add several procedures and macros --- core/sys/windows/types.odin | 17 +++++++++++++++++ core/sys/windows/user32.odin | 23 +++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index e5e630c54..de19cd6cc 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -707,6 +707,23 @@ MK_MBUTTON :: 0x0010 MK_XBUTTON1 :: 0x0020 MK_XBUTTON2 :: 0x0040 +// Value for rolling one detent +WHEEL_DELTA :: 120 + +// Setting to scroll one page for SPI_GET/SETWHEELSCROLLLINES +WHEEL_PAGESCROLL :: max(UINT) + +// XButton values are WORD flags +XBUTTON1 :: 0x0001 +XBUTTON2 :: 0x0002 +// Were there to be an XBUTTON3, its value would be 0x0004 + +MAPVK_VK_TO_VSC :: 0 +MAPVK_VSC_TO_VK :: 1 +MAPVK_VK_TO_CHAR :: 2 +MAPVK_VSC_TO_VK_EX :: 3 +MAPVK_VK_TO_VSC_EX :: 4 + TME_HOVER :: 0x00000001 TME_LEAVE :: 0x00000002 TME_NONCLIENT :: 0x00000010 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 5b910ae73..2316d3363 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -131,6 +131,9 @@ foreign user32 { GetKeyState :: proc(nVirtKey: c_int) -> SHORT --- GetAsyncKeyState :: proc(vKey: c_int) -> SHORT --- + MapVirtualKeyA :: proc(uCode: UINT, uMapType: UINT) -> UINT --- + MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT --- + SetWindowsHookExA :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- UnhookWindowsHookEx :: proc(hhk: HHOOK) -> BOOL --- @@ -228,6 +231,22 @@ when ODIN_ARCH == .amd64 { SetWindowLongPtrW :: GetWindowLongW } -GET_SC_WPARAM :: #force_inline proc(wparam: WPARAM) -> i32 { - return i32(wparam) & 0xFFF0 +GET_SC_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_int { + return c_int(wParam) & 0xFFF0 +} + +GET_WHEEL_DELTA_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_short { + return cast(c_short)HIWORD(cast(DWORD)wParam) +} + +GET_KEYSTATE_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD { + return LOWORD(cast(DWORD)wParam) +} + +GET_NCHITTEST_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_short { + return cast(c_short)LOWORD(cast(DWORD)wParam) +} + +GET_XBUTTON_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD { + return HIWORD(cast(DWORD)wParam) } From cb5a6b531a1742125cdab2a4fae00a32d418e2ab Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 2 Apr 2022 15:31:50 +0200 Subject: [PATCH 0497/1052] Allow optional message for `#assert`. --- src/check_builtin.cpp | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8b8814176..b537e407a 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -830,8 +830,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } } else if (name == "assert") { - if (ce->args.count != 1) { - error(call, "'#assert' expects 1 argument, got %td", ce->args.count); + if (ce->args.count != 1 && ce->args.count != 2) { + error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); return false; } if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { @@ -840,15 +840,37 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 gb_string_free(str); return false; } + if (ce->args.count == 2) { + Ast *arg = unparen_expr(ce->args[1]); + if (arg == nullptr || arg->kind != Ast_BasicLit || arg->BasicLit.token.kind != Token_String) { + gbString str = expr_to_string(arg); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + } + if (!operand->value.value_bool) { - gbString arg = expr_to_string(ce->args[0]); - error(call, "Compile time assertion: %s", arg); + gbString arg1 = expr_to_string(ce->args[0]); + gbString arg2 = {}; + + if (ce->args.count == 1) { + error(call, "Compile time assertion: %s", arg1); + } else { + arg2 = expr_to_string(ce->args[1]); + error(call, "Compile time assertion: %s (%s)", arg1, arg2); + } + if (c->proc_name != "") { gbString str = type_to_string(c->curr_proc_sig); error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); gb_string_free(str); } - gb_string_free(arg); + + gb_string_free(arg1); + if (ce->args.count == 2) { + gb_string_free(arg2); + } } operand->type = t_untyped_bool; From a232c0888c4b711ceb94563defdeef514eafb28a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 2 Apr 2022 14:38:42 +0100 Subject: [PATCH 0498/1052] `intrinsics.atomic_type_is_lock_free` --- core/c/libc/stdatomic.odin | 2 +- core/intrinsics/intrinsics.odin | 2 ++ src/check_builtin.cpp | 30 ++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 2 ++ src/entity.cpp | 6 +++--- src/llvm_backend_proc.cpp | 2 +- src/types.cpp | 11 +++++++++++ 7 files changed, 50 insertions(+), 5 deletions(-) diff --git a/core/c/libc/stdatomic.odin b/core/c/libc/stdatomic.odin index 9de3c4678..6e1581c58 100644 --- a/core/c/libc/stdatomic.odin +++ b/core/c/libc/stdatomic.odin @@ -70,7 +70,7 @@ atomic_signal_fence :: #force_inline proc(order: memory_order) { // 7.17.5 Lock-free property atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool { - return size_of(T) <= 8 && (intrinsics.type_is_integer(T) || intrinsics.type_is_pointer(T)) + return intrinsics.atomic_type_is_lock_free(T) } // 7.17.6 Atomic integer types diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index ce8fd96ea..a25e9783d 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -71,6 +71,8 @@ Atomic_Memory_Order :: enum { Seq_Cst = 5, } +atomic_type_is_lock_free :: proc($T: typeid) -> bool --- + atomic_thread_fence :: proc(order: Atomic_Memory_Order) --- atomic_signal_fence :: proc(order: Atomic_Memory_Order) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8b8814176..abe58855b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -449,6 +449,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_objc_find_class: case BuiltinProc_objc_register_selector: case BuiltinProc_objc_register_class: + case BuiltinProc_atomic_type_is_lock_free: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -3232,6 +3233,35 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; + case BuiltinProc_atomic_type_is_lock_free: + { + Ast *expr = ce->args[0]; + Operand o = {}; + check_expr_or_type(c, &o, expr); + + if (o.mode == Addressing_Invalid || o.mode == Addressing_Builtin) { + return false; + } + if (o.type == nullptr || o.type == t_invalid || is_type_asm_proc(o.type)) { + error(o.expr, "Invalid argument to '%.*s'", LIT(builtin_name)); + return false; + } + if (is_type_polymorphic(o.type)) { + error(o.expr, "'%.*s' of polymorphic type cannot be determined", LIT(builtin_name)); + return false; + } + if (is_type_untyped(o.type)) { + error(o.expr, "'%.*s' of untyped type is not allowed", LIT(builtin_name)); + return false; + } + Type *t = o.type; + bool is_lock_free = is_type_lock_free(t); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + operand->value = exact_value_bool(is_lock_free); + break; + } case BuiltinProc_atomic_thread_fence: case BuiltinProc_atomic_signal_fence: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c6b0afee0..fe14ae372 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -86,6 +86,7 @@ enum BuiltinProcId { BuiltinProc_prefetch_write_instruction, BuiltinProc_prefetch_write_data, + BuiltinProc_atomic_type_is_lock_free, BuiltinProc_atomic_thread_fence, BuiltinProc_atomic_signal_fence, BuiltinProc_atomic_store, @@ -305,6 +306,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_type_is_lock_free"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/entity.cpp b/src/entity.cpp index 17fa884e1..1f87f7af6 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -45,9 +45,9 @@ enum EntityFlag : u64 { EntityFlag_NoAlias = 1ull<<9, EntityFlag_TypeField = 1ull<<10, EntityFlag_Value = 1ull<<11, - EntityFlag_Sret = 1ull<<12, - EntityFlag_ByVal = 1ull<<13, - EntityFlag_BitFieldValue = 1ull<<14, + + + EntityFlag_PolyConst = 1ull<<15, EntityFlag_NotExported = 1ull<<16, EntityFlag_ConstInput = 1ull<<17, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 4de2af9d8..96ff19d10 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -447,7 +447,7 @@ void lb_begin_procedure_body(lbProcedure *p) { Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); Entity *e = alloc_entity_param(nullptr, make_token_ident(name), ptr_type, false, false); - e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + e->flags |= EntityFlag_NoAlias; return_ptr_value.value = LLVMGetParam(p->value, 0); LLVMSetValueName2(return_ptr_value.value, cast(char const *)name.text, name.len); diff --git a/src/types.cpp b/src/types.cpp index e10dae1ed..b4dc17256 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2218,6 +2218,17 @@ bool elem_type_can_be_constant(Type *t) { return true; } +bool is_type_lock_free(Type *t) { + t = core_type(t); + if (t == t_invalid) { + return false; + } + i64 sz = type_size_of(t); + // TODO(bill): Figure this out correctly + return sz <= build_context.max_align; +} + + bool is_type_comparable(Type *t) { t = base_type(t); From 1ec997461d52a4d847e702ea33b40773719a592a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 2 Apr 2022 15:00:28 +0100 Subject: [PATCH 0499/1052] Add extra checks to atomic intrinsics --- src/check_builtin.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index abe58855b..24025f08c 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3392,6 +3392,21 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 check_expr_with_type_hint(c, &x, ce->args[1], elem); check_assignment(c, &x, elem, builtin_name); + Type *t = type_deref(operand->type); + switch (id) { + case BuiltinProc_atomic_add: + case BuiltinProc_atomic_sub: + if (!is_type_numeric(t)) { + gbString str = type_to_string(t); + error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str); + gb_string_free(str); + } else if (is_type_different_to_arch_endianness(t)) { + gbString str = type_to_string(t); + error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); + gb_string_free(str); + } + } + operand->type = elem; operand->mode = Addressing_Value; break; @@ -3419,6 +3434,22 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } + Type *t = type_deref(operand->type); + switch (id) { + case BuiltinProc_atomic_add_explicit: + case BuiltinProc_atomic_sub_explicit: + if (!is_type_numeric(t)) { + gbString str = type_to_string(t); + error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str); + gb_string_free(str); + } else if (is_type_different_to_arch_endianness(t)) { + gbString str = type_to_string(t); + error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); + gb_string_free(str); + } + break; + } + operand->type = elem; operand->mode = Addressing_Value; break; @@ -3439,6 +3470,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 check_assignment(c, &x, elem, builtin_name); check_assignment(c, &y, elem, builtin_name); + Type *t = type_deref(operand->type); + if (!is_type_comparable(t)) { + gbString str = type_to_string(t); + error(operand->expr, "Expected a comparable type for '%.*s', got %s", LIT(builtin_name), str); + gb_string_free(str); + } + operand->mode = Addressing_OptionalOk; operand->type = elem; break; @@ -3468,6 +3506,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } + Type *t = type_deref(operand->type); + if (!is_type_comparable(t)) { + gbString str = type_to_string(t); + error(operand->expr, "Expected a comparable type for '%.*s', got %s", LIT(builtin_name), str); + gb_string_free(str); + } + bool invalid_combination = false; switch (success_memory_order) { From e80bee68673c4e50640d55d8fe71a09e8d4bc2a1 Mon Sep 17 00:00:00 2001 From: bkrypt <4868093+bkrypt@users.noreply.github.com> Date: Sat, 2 Apr 2022 21:55:01 +0200 Subject: [PATCH 0500/1052] Change order of `O_CREATE` & `O_APPEND` checks --- core/os/file_windows.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 4c8d385f2..ebf2508ca 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -20,13 +20,13 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE } + if mode&O_CREATE != 0 { + access |= win32.FILE_GENERIC_WRITE + } if mode&O_APPEND != 0 { access &~= win32.FILE_GENERIC_WRITE access |= win32.FILE_APPEND_DATA } - if mode&O_CREATE != 0 { - access |= win32.FILE_GENERIC_WRITE - } share_mode := win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE sa: ^win32.SECURITY_ATTRIBUTES = nil From f4daf46ff4a029f1c6086c2b3eae18194a819161 Mon Sep 17 00:00:00 2001 From: Florian Behr Date: Sun, 3 Apr 2022 15:18:01 +0200 Subject: [PATCH 0501/1052] Fixes for stb_easy_font --- vendor/stb/easy_font/stb_easy_font.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/stb/easy_font/stb_easy_font.odin b/vendor/stb/easy_font/stb_easy_font.odin index 3a60301e5..1e18057c6 100644 --- a/vendor/stb/easy_font/stb_easy_font.odin +++ b/vendor/stb/easy_font/stb_easy_font.odin @@ -12,12 +12,12 @@ draw_segs :: proc(x, y: f32, segs: []u8, vertical: bool, c: color, vbuf: []byte, x, y, offset := x, y, offset for i in 0..>31) & 1) + x += f32((segs[i]>>3) & 1) if n != 0 && offset+64 <= len(vbuf) { y0 := y + f32(segs[i]>>4) for j in 0..<4 { - (^f32)(&vbuf[offset+0])^ = x + ((vertical ? 1 : len) if j==1 || j==2 else 0) - (^f32)(&vbuf[offset+4])^ = y0 + ((vertical ? len : 1) if j >= 2 else 0) + (^f32)(&vbuf[offset+0])^ = x + f32((vertical ? 1 : n) if j==1 || j==2 else 0) + (^f32)(&vbuf[offset+4])^ = y0 + f32((vertical ? n : 1) if j >= 2 else 0) (^f32)(&vbuf[offset+8])^ = 0 (^color)(&vbuf[offset+12])^ = c offset += 16 @@ -53,7 +53,7 @@ print :: proc(x, y: f32, text: string, color: color, vertex_buffer: []byte) -> i num_h := charinfo[c-32 + 1].h_seg - h_seg num_v := charinfo[c-32 + 1].v_seg - v_seg offset = draw_segs(x, y_ch, hseg[h_seg:][:num_h], false, color, vertex_buffer, offset) - offset = draw_segs(x, y_ch, hseg[v_seg:][:num_v], true, color, vertex_buffer, offset) + offset = draw_segs(x, y_ch, vseg[v_seg:][:num_v], true, color, vertex_buffer, offset) x += f32(advance & 15) x += _spacing_val } From 376327c87b6a9398159591f775325ac16b5e0b79 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 3 Apr 2022 18:53:27 +0200 Subject: [PATCH 0502/1052] [vendor:easy_font] API improvements. Add `print(x, y, text, color, quad_buffer)` version that takes `[]quad`. (Same internal memory layout as []u8 API, but more convenient for the caller.) Add optional `scale := f32(1.0)` param to `print` to embiggen the glyph quads. ```odin // Example for use with vendor:raylib quads: [999]easy_font.Quad = --- color := rl.GREEN c := transmute(easy_font.Color)color num_quads := easy_font.print(10, 60, TEXT, c, quads[:]) for q in quads[:num_quads] { tl := q.tl.v br := q.br.v color = transmute(rl.Color)q.tl.c r := rl.Rectangle{x = tl.x, y = tl.y, width = br.x - tl.x, height = br.y - tl.y} // Yes, we could just use the `color` from above, but this shows how to get it back from the vertex. // And in practice this code will likely not live as close to the `easy_font` call. rl.DrawRectangleRec(r, color) } ``` --- vendor/stb/easy_font/stb_easy_font.odin | 141 +++++++++++++++++++----- 1 file changed, 114 insertions(+), 27 deletions(-) diff --git a/vendor/stb/easy_font/stb_easy_font.odin b/vendor/stb/easy_font/stb_easy_font.odin index 1e18057c6..0208ca316 100644 --- a/vendor/stb/easy_font/stb_easy_font.odin +++ b/vendor/stb/easy_font/stb_easy_font.odin @@ -1,32 +1,105 @@ package stb_easy_font -// Source port of stb_easy_font.h +/* + Source port of stb_easy_font.h + + Original port: gingerBill + Bugfixes: Florian Behr & Jeroen van Rijn + Additions: Jeroen van Rijn + + Changelog: + 2022-04-03 + Bug fixes + Add `print(x, y, text, color, quad_buffer)` version that takes `[]quad`. + (Same internal memory layout as []u8 API, but more convenient for the caller.) + Add optional `scale := f32(1.0)` param to `print` to embiggen the glyph quads. + + 2021-09-14 + Original Odin version +*/ + +/* + // Example for use with vendor:raylib + + quads: [999]easy_font.Quad = --- + + color := rl.GREEN + c := transmute(easy_font.Color)color + num_quads := easy_font.print(10, 60, TEXT, c, quads[:]) + + for q in quads[:num_quads] { + tl := q.tl.v + br := q.br.v + color = transmute(rl.Color)q.tl.c + + r := rl.Rectangle{x = tl.x, y = tl.y, width = br.x - tl.x, height = br.y - tl.y} + + // Yes, we could just use the `color` from above, but this shows how to get it back from the vertex. + // And in practice this code will likely not live as close to the `easy_font` call. + rl.DrawRectangleRec(r, color) + } +*/ import "core:math" +import "core:mem" -color :: struct { - c: [4]u8, +Color :: [4]u8 + +Vertex :: struct { + v: [3]f32, + c: Color, } +#assert(size_of(Vertex) == 16) -draw_segs :: proc(x, y: f32, segs: []u8, vertical: bool, c: color, vbuf: []byte, offset: int) -> int { - x, y, offset := x, y, offset - for i in 0..>3) & 1) - if n != 0 && offset+64 <= len(vbuf) { - y0 := y + f32(segs[i]>>4) - for j in 0..<4 { - (^f32)(&vbuf[offset+0])^ = x + f32((vertical ? 1 : n) if j==1 || j==2 else 0) - (^f32)(&vbuf[offset+4])^ = y0 + f32((vertical ? n : 1) if j >= 2 else 0) - (^f32)(&vbuf[offset+8])^ = 0 - (^color)(&vbuf[offset+12])^ = c - offset += 16 - } +Quad :: struct #packed { + tl: Vertex, + tr: Vertex, + br: Vertex, + bl: Vertex, +} +#assert(size_of(Quad) == 64) + +// Same memory layout, but takes a []quad instead of []byte +draw_segs_quad_buffer :: proc(x, y: f32, segs: []u8, vertical: bool, c: Color, buf: []Quad, start_offset: int, scale := f32(1.0)) -> (quads: int) { + x, y := x, y + quads = start_offset + + for seg in segs { + stroke_length := f32(seg & 7) * scale + x += f32((seg >> 3) & 1) * scale + if stroke_length != 0 && quads + 1 <= len(buf) { + y0 := y + (f32(seg >> 4) * scale) + + horz := scale if vertical else stroke_length + vert := stroke_length if vertical else scale + + buf[quads].tl.c = c + buf[quads].tl.v = { x, y0, 0 } + + buf[quads].tr.c = c + buf[quads].tr.v = { x + horz, y0, 0 } + + buf[quads].br.c = c + buf[quads].br.v = { x + horz, y0 + vert, 0 } + + buf[quads].bl.c = c + buf[quads].bl.v = { x, y0 + vert, 0 } + + quads += 1 } } + return quads +} + +// Compatible with original C API +draw_segs_vertex_buffer :: proc(x, y: f32, segs: []u8, vertical: bool, c: Color, vbuf: []byte, start_offset: int, scale := f32(1.0)) -> (offset: int) { + buf := mem.slice_data_cast([]Quad, vbuf) + offset = draw_segs_quad_buffer(x, y, segs, vertical, c, buf, start_offset / size_of(Quad), scale) * size_of(Quad) return offset } +draw_segs :: proc{ draw_segs_quad_buffer, draw_segs_vertex_buffer } + @(private) _spacing_val := f32(0) @@ -34,13 +107,17 @@ font_spacing :: proc(spacing: f32) { _spacing_val = spacing } -print :: proc(x, y: f32, text: string, color: color, vertex_buffer: []byte) -> int { - x, y := x, y +// Same memory layout, but takes a []quad instead of []byte +print_quad_buffer :: proc(x, y: f32, text: string, color: Color, quad_buffer: []Quad, scale := f32(1.0)) -> (quads: int) { + x, y, color := x, y, color text := text start_x := x - offset := 0 - - for len(text) != 0 && offset < len(vertex_buffer) { + + if color == {} { + color = {255, 255, 255, 255} + } + + for len(text) != 0 && quads < len(quad_buffer) { c := text[0] if c == '\n' { y += 12 @@ -52,17 +129,27 @@ print :: proc(x, y: f32, text: string, color: color, vertex_buffer: []byte) -> i v_seg := charinfo[c-32].v_seg num_h := charinfo[c-32 + 1].h_seg - h_seg num_v := charinfo[c-32 + 1].v_seg - v_seg - offset = draw_segs(x, y_ch, hseg[h_seg:][:num_h], false, color, vertex_buffer, offset) - offset = draw_segs(x, y_ch, vseg[v_seg:][:num_v], true, color, vertex_buffer, offset) - x += f32(advance & 15) - x += _spacing_val + + quads = draw_segs(x, y_ch, hseg[h_seg:][:num_h], false, color, quad_buffer, quads, scale) + quads = draw_segs(x, y_ch, vseg[v_seg:][:num_v], true, color, quad_buffer, quads, scale) + + x += f32(advance & 15) * scale + x += _spacing_val * scale } text = text[1:] } - return offset/64 + return } +// Compatible with original C API +print_vertex_buffer :: proc(x, y: f32, text: string, color: Color, vertex_buffer: []byte, scale := f32(1.0)) -> int { + buf := mem.slice_data_cast([]Quad, vertex_buffer) + return print_quad_buffer(x, y, text, color, buf, scale) +} + +print :: proc{ print_quad_buffer, print_vertex_buffer } + width :: proc(text: string) -> int { length := f32(0) max_length := f32(0) From b5aa50aaa44211bb7db37569722b255262a59d09 Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Sun, 3 Apr 2022 19:37:54 +0200 Subject: [PATCH 0503/1052] documentation for the rest of the strings library --- core/strings/ascii_set.odin | 2 + core/strings/builder.odin | 130 +++++++++++++++++++++++++++++++---- core/strings/conversion.odin | 54 +++++++++++++-- core/strings/intern.odin | 12 ++++ core/strings/reader.odin | 36 +++++++++- 5 files changed, 212 insertions(+), 22 deletions(-) diff --git a/core/strings/ascii_set.odin b/core/strings/ascii_set.odin index 582049eee..9b59666f3 100644 --- a/core/strings/ascii_set.odin +++ b/core/strings/ascii_set.odin @@ -5,6 +5,7 @@ import "core:unicode/utf8" Ascii_Set :: distinct [8]u32 +// create an ascii set of all unique characters in the string ascii_set_make :: proc(chars: string) -> (as: Ascii_Set, ok: bool) #no_bounds_check { for i in 0.. (as: Ascii_Set, ok: bool) #no_bounds_ch return } +// returns true when the `c` byte is contained in the `as` ascii set ascii_set_contains :: proc(as: Ascii_Set, c: byte) -> bool #no_bounds_check { return as[c>>5] & (1<<(c&31)) != 0 } \ No newline at end of file diff --git a/core/strings/builder.odin b/core/strings/builder.odin index 6952ba088..d6065cf70 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -7,40 +7,56 @@ import "core:io" Builder_Flush_Proc :: #type proc(b: ^Builder) -> (do_reset: bool) +/* + dynamic byte buffer / string builder with helper procedures + the dynamic array is wrapped inside the struct to be more opaque + you can use `fmt.sbprint*` procedures with a `^strings.Builder` directly +*/ Builder :: struct { buf: [dynamic]byte, } +// return a builder, default length 0 / cap 16 are done through make make_builder_none :: proc(allocator := context.allocator) -> Builder { return Builder{buf=make([dynamic]byte, allocator)} } +// return a builder, with a set length `len` and cap 16 byte buffer make_builder_len :: proc(len: int, allocator := context.allocator) -> Builder { return Builder{buf=make([dynamic]byte, len, allocator)} } +// return a builder, with a set length `len` byte buffer and a custom `cap` make_builder_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder { return Builder{buf=make([dynamic]byte, len, cap, allocator)} } +// overload simple `make_builder_*` with or without len / cap parameters make_builder :: proc{ make_builder_none, make_builder_len, make_builder_len_cap, } +// initialize a builder, default length 0 / cap 16 are done through make +// replaces the existing `buf` init_builder_none :: proc(b: ^Builder, allocator := context.allocator) { b.buf = make([dynamic]byte, allocator) } +// initialize a builder, with a set length `len` and cap 16 byte buffer +// replaces the existing `buf` init_builder_len :: proc(b: ^Builder, len: int, allocator := context.allocator) { b.buf = make([dynamic]byte, len, allocator) } +// initialize a builder, with a set length `len` byte buffer and a custom `cap` +// replaces the existing `buf` init_builder_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) { b.buf = make([dynamic]byte, len, cap, allocator) } +// overload simple `init_builder_*` with or without len / ap parameters init_builder :: proc{ init_builder_none, init_builder_len, @@ -76,30 +92,42 @@ _builder_stream_vtable := &io.Stream_VTable{ }, } +// return an `io.Stream` from a builder to_stream :: proc(b: ^Builder) -> io.Stream { return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b} } + +// return an `io.Writer` from a builder to_writer :: proc(b: ^Builder) -> io.Writer { return io.to_writer(to_stream(b)) } - - - +// delete and clear the builder byte buffer content destroy_builder :: proc(b: ^Builder) { delete(b.buf) clear(&b.buf) } +// reserve the builfer byte buffer to a specific cap, when it's higher than before grow_builder :: proc(b: ^Builder, cap: int) { reserve(&b.buf, cap) } +// clear the builder byte buffer content reset_builder :: proc(b: ^Builder) { clear(&b.buf) } - +/* + create an empty builder with the same slice length as its cap + uses the `mem.nil_allocator` to avoid allocation and keep a fixed length + used in `fmt.bprint*` + + bytes: [8]byte // <-- gets filled + builder := strings.builder_from_slice(bytes[:]) + strings.write_byte(&builder, 'a') -> "a" + strings.write_byte(&builder, 'b') -> "ab" +*/ builder_from_slice :: proc(backing: []byte) -> Builder { s := transmute(mem.Raw_Slice)backing d := mem.Raw_Dynamic_Array{ @@ -112,20 +140,36 @@ builder_from_slice :: proc(backing: []byte) -> Builder { buf = transmute([dynamic]byte)d, } } + +// cast the builder byte buffer to a string and return it to_string :: proc(b: Builder) -> string { return string(b.buf[:]) } +// return the length of the builder byte buffer builder_len :: proc(b: Builder) -> int { return len(b.buf) } + +// return the cap of the builder byte buffer builder_cap :: proc(b: Builder) -> int { return cap(b.buf) } + +// returns the space left in the builder byte buffer to use up builder_space :: proc(b: Builder) -> int { - return max(cap(b.buf), len(b.buf), 0) + return cap(b.buf) - len(b.buf) } +/* + appends a byte to the builder, returns the append diff + + builder := strings.make_builder() + strings.write_byte(&builder, 'a') // 1 + strings.write_byte(&builder, 'b') // 1 + strings.write_byte(&builder, 'c') // 1 + fmt.println(strings.to_string(builder)) // -> abc +*/ write_byte :: proc(b: ^Builder, x: byte) -> (n: int) { n0 := len(b.buf) append(&b.buf, x) @@ -133,6 +177,14 @@ write_byte :: proc(b: ^Builder, x: byte) -> (n: int) { return n1-n0 } +/* + appends a slice of bytes to the builder, returns the append diff + + builder := strings.make_builder() + bytes := [?]byte { 'a', 'b', 'c' } + strings.write_bytes(&builder, bytes[:]) // 3 + fmt.println(strings.to_string(builder)) // -> abc +*/ write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) { n0 := len(b.buf) append(&b.buf, ..x) @@ -140,11 +192,28 @@ write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) { return n1-n0 } +/* + appends a single rune into the builder, returns written rune size and an `io.Error` + + builder := strings.make_builder() + strings.write_rune_builder(&builder, 'ä') // 2 None + strings.write_rune_builder(&builder, 'b') // 1 None + strings.write_rune_builder(&builder, 'c') // 1 None + fmt.println(strings.to_string(builder)) // -> äbc +*/ write_rune_builder :: proc(b: ^Builder, r: rune) -> (int, io.Error) { return io.write_rune(to_writer(b), r) } +/* + appends a quoted rune into the builder, returns written size + builder := strings.make_builder() + strings.write_string(&builder, "abc") // 3 + strings.write_quoted_rune_builder(&builder, 'ä') // 4 + strings.write_string(&builder, "abc") // 3 + fmt.println(strings.to_string(builder)) // -> abc'ä'abc +*/ write_quoted_rune_builder :: proc(b: ^Builder, r: rune) -> (n: int) { return write_quoted_rune(to_writer(b), r) } @@ -155,7 +224,7 @@ _write_byte :: proc(w: io.Writer, c: byte) -> int { return 1 if err == nil else 0 } - +// writer append a quoted rune into the byte buffer, return the written size write_quoted_rune :: proc(w: io.Writer, r: rune) -> (n: int) { quote := byte('\'') n += _write_byte(w, quote) @@ -173,50 +242,75 @@ write_quoted_rune :: proc(w: io.Writer, r: rune) -> (n: int) { return } - +// overload for `write_string_*` variants write_string :: proc{ write_string_builder, write_string_writer, } +/* + appends a string to the builder, return the written byte size + + builder := strings.make_builder() + strings.write_string(&builder, "a") // 1 + strings.write_string(&builder, "bc") // 2 + strings.write_string(&builder, "xyz") // 3 + fmt.println(strings.to_string(builder)) // -> abcxyz +*/ write_string_builder :: proc(b: ^Builder, s: string) -> (n: int) { return write_string_writer(to_writer(b), s) } +// appends a string to the writer write_string_writer :: proc(w: io.Writer, s: string) -> (n: int) { n, _ = io.write(w, transmute([]byte)s) return } - - - +// pops and returns the last byte in the builder +// returns 0 when the builder is empty pop_byte :: proc(b: ^Builder) -> (r: byte) { if len(b.buf) == 0 { return 0 } + r = b.buf[len(b.buf)-1] d := cast(^mem.Raw_Dynamic_Array)&b.buf d.len = max(d.len-1, 0) return } +// pops the last rune in the builder and returns the popped rune and its rune width +// returns 0, 0 when the builder is empty pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) { + if len(b.buf) == 0 { + return 0, 0 + } + r, width = utf8.decode_last_rune(b.buf[:]) d := cast(^mem.Raw_Dynamic_Array)&b.buf d.len = max(d.len-width, 0) return } - @(private) DIGITS_LOWER := "0123456789abcdefx" +// overload for `write_quoted_string_*` variants write_quoted_string :: proc{ write_quoted_string_builder, write_quoted_string_writer, } +/* + append a quoted string into the builder, return the written byte size + + builder := strings.make_builder() + strings.write_quoted_string(&builder, "a") // 3 + strings.write_quoted_string(&builder, "bc", '\'') // 4 + strings.write_quoted_string(&builder, "xyz") // 5 + fmt.println(strings.to_string(builder)) // -> "a"'bc'xyz" +*/ write_quoted_string_builder :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) { n, _ = io.write_quoted_string(to_writer(b), str, quote) return @@ -228,11 +322,13 @@ write_quoted_string_writer :: proc(w: io.Writer, str: string, quote: byte = '"') return } +// overload for `write_encoded_rune_*` write_encoded_rune :: proc{ write_encoded_rune_builder, write_encoded_rune_writer, } +// appends a rune to the builder, optional `write_quote` boolean tag, returns the written rune size write_encoded_rune_builder :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) { n, _ = io.write_encoded_rune(to_writer(b), r, write_quote) return @@ -244,12 +340,15 @@ write_encoded_rune_writer :: proc(w: io.Writer, r: rune, write_quote := true) -> return } - +// overload for `write_escaped_rune_*` write_escaped_rune :: proc{ write_escaped_rune_builder, write_escaped_rune_writer, } +// appends a rune to the builder, fully written out in case of escaped runes e.g. '\a' will be written as such +// when `r` and `quote` match and `quote` is `\\` - they will be written as two slashes +// `html_safe` flag in case the runes '<', '>', '&' should be encoded as digits e.g. `\u0026` write_escaped_rune_builder :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) { n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe) return @@ -261,21 +360,26 @@ write_escaped_rune_writer :: proc(w: io.Writer, r: rune, quote: byte, html_safe return } - +// writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) { buf: [32]byte s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil) return write_string(b, s) } + +// writes a i64 value `i` in `base` = 10 into the builder, returns the written amount of characters write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) { buf: [32]byte s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) return write_string(b, s) } +// writes a uint value `i` in `base` = 10 into the builder, returns the written amount of characters write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) { return write_u64(b, u64(i), base) } + +// writes a int value `i` in `base` = 10 into the builder, returns the written amount of characters write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) { return write_i64(b, i64(i), base) } diff --git a/core/strings/conversion.odin b/core/strings/conversion.odin index b0d42b2eb..5e7110281 100644 --- a/core/strings/conversion.odin +++ b/core/strings/conversion.odin @@ -58,6 +58,13 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> return to_string(b) } +/* + returns the input string `s` with all runes set to lowered case + always allocates using the `allocator` + + strings.to_lower("test") -> test + strings.to_lower("Test") -> test +*/ to_lower :: proc(s: string, allocator := context.allocator) -> string { b: Builder init_builder(&b, 0, len(s), allocator) @@ -66,6 +73,14 @@ to_lower :: proc(s: string, allocator := context.allocator) -> string { } return to_string(b) } + +/* + returns the input string `s` with all runes set to upper case + always allocates using the `allocator` + + strings.to_lower("test") -> TEST + strings.to_lower("Test") -> TEST +*/ to_upper :: proc(s: string, allocator := context.allocator) -> string { b: Builder init_builder(&b, 0, len(s), allocator) @@ -75,13 +90,13 @@ to_upper :: proc(s: string, allocator := context.allocator) -> string { return to_string(b) } - - - +// returns true when the `c` rune is a space, '-' or '_' +// useful when treating strings like words in a text editor or html paths is_delimiter :: proc(c: rune) -> bool { return c == '-' || c == '_' || is_space(c) } +// returns true when the `r` rune is a non alpha or `unicode.is_space` rune is_separator :: proc(r: rune) -> bool { if r <= 0x7f { switch r { @@ -101,7 +116,10 @@ is_separator :: proc(r: rune) -> bool { return unicode.is_space(r) } - +/* + iterator that loops through the string and calls the callback with the `prev`, `curr` and `next` rune + on empty string `s` the callback gets called once with empty runes +*/ string_case_iterator :: proc(w: io.Writer, s: string, callback: proc(w: io.Writer, prev, curr, next: rune)) { prev, curr: rune for next in s { @@ -122,8 +140,9 @@ string_case_iterator :: proc(w: io.Writer, s: string, callback: proc(w: io.Write } } - to_lower_camel_case :: to_camel_case + +// converts the `s` string to "lowerCamelCase" to_camel_case :: proc(s: string, allocator := context.allocator) -> string { s := s s = trim_space(s) @@ -147,6 +166,8 @@ to_camel_case :: proc(s: string, allocator := context.allocator) -> string { } to_upper_camel_case :: to_pascal_case + +// converts the `s` string to "PascalCase" to_pascal_case :: proc(s: string, allocator := context.allocator) -> string { s := s s = trim_space(s) @@ -169,6 +190,15 @@ to_pascal_case :: proc(s: string, allocator := context.allocator) -> string { return to_string(b) } +/* + returns the `s` string to words seperated by the given `delimiter` rune + all runes will be upper or lowercased based on the `all_uppercase` bool + + strings.to_delimiter_case("Hello World", '_', false) -> hello_world + strings.to_delimiter_case("Hello World", ' ', true) -> HELLO WORLD + strings.to_delimiter_case("Hello World", ' ', true) -> HELLO WORLD + strings.to_delimiter_case("aBC", '_', false) -> a_b_c +*/ to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allocator := context.allocator) -> string { s := s s = trim_space(s) @@ -208,24 +238,34 @@ to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allo return to_string(b) } - +/* + converts the `s` string to "snake_case" with all runes lowercased + + strings.to_snake_case("HelloWorld") -> hello_world + strings.to_snake_case("Hello World") -> hello_world +*/ to_snake_case :: proc(s: string, allocator := context.allocator) -> string { return to_delimiter_case(s, '_', false, allocator) } to_screaming_snake_case :: to_upper_snake_case + +// converts the `s` string to "SNAKE_CASE" with all runes uppercased to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> string { return to_delimiter_case(s, '_', true, allocator) } +// converts the `s` string to "kebab-case" with all runes lowercased to_kebab_case :: proc(s: string, allocator := context.allocator) -> string { return to_delimiter_case(s, '-', false, allocator) } -to_upper_case :: proc(s: string, allocator := context.allocator) -> string { +// converts the `s` string to "KEBAB-CASE" with all runes uppercased +to_upper_kebab_case :: proc(s: string, allocator := context.allocator) -> string { return to_delimiter_case(s, '-', true, allocator) } +// converts the `s` string to "Ada_case" to_ada_case :: proc(s: string, allocator := context.allocator) -> string { delimiter :: '_' diff --git a/core/strings/intern.odin b/core/strings/intern.odin index ff26d7dbb..27c3db084 100644 --- a/core/strings/intern.odin +++ b/core/strings/intern.odin @@ -2,21 +2,26 @@ package strings import "core:mem" +// custom string entry struct Intern_Entry :: struct { len: int, str: [1]byte, // string is allocated inline with the entry to keep allocations simple } +// "intern" is a more memory efficient string map +// `allocator` is used to allocate the actual `Intern_Entry` strings Intern :: struct { allocator: mem.Allocator, entries: map[string]^Intern_Entry, } +// initialize the entries map and set the allocator for the string entries intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator) { m.allocator = allocator m.entries = make(map[string]^Intern_Entry, 16, map_allocator) } +// free the map and all its content allocated using the `.allocator` intern_destroy :: proc(m: ^Intern) { for _, value in m.entries { free(value, m.allocator) @@ -24,15 +29,22 @@ intern_destroy :: proc(m: ^Intern) { delete(m.entries) } +// returns the `text` string from the intern map - gets set if it didnt exist yet +// the returned string lives as long as the map entry lives intern_get :: proc(m: ^Intern, text: string) -> string { entry := _intern_get_entry(m, text) #no_bounds_check return string(entry.str[:entry.len]) } + +// returns the `text` cstring from the intern map - gets set if it didnt exist yet +// the returned cstring lives as long as the map entry lives intern_get_cstring :: proc(m: ^Intern, text: string) -> cstring { entry := _intern_get_entry(m, text) return cstring(&entry.str[0]) } +// looks up wether the `text` string exists in the map, returns the entry +// sets & allocates the entry if it wasnt set yet _intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_check { if prev, ok := m.entries[text]; ok { return prev diff --git a/core/strings/reader.odin b/core/strings/reader.odin index ba266c0b5..9b2e10b68 100644 --- a/core/strings/reader.odin +++ b/core/strings/reader.odin @@ -3,46 +3,60 @@ package strings import "core:io" import "core:unicode/utf8" +/* + io stream data for a string reader that can read based on bytes or runes + implements the vtable when using the io.Reader variants + "read" calls advance the current reading offset `i` +*/ Reader :: struct { s: string, // read-only buffer i: i64, // current reading index prev_rune: int, // previous reading index of rune or < 0 } +// init the reader to the string `s` reader_init :: proc(r: ^Reader, s: string) { r.s = s r.i = 0 r.prev_rune = -1 } +// returns a stream from the reader data reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) { s.stream_data = r s.stream_vtable = _reader_vtable return } +// init a reader to the string `s` and return an io.Reader to_reader :: proc(r: ^Reader, s: string) -> io.Reader { reader_init(r, s) rr, _ := io.to_reader(reader_to_stream(r)) return rr } + +// init a reader to the string `s` and return an io.Reader_At to_reader_at :: proc(r: ^Reader, s: string) -> io.Reader_At { reader_init(r, s) rr, _ := io.to_reader_at(reader_to_stream(r)) return rr } + +// init a reader to the string `s` and return an io.Byte_Reader to_byte_reader :: proc(r: ^Reader, s: string) -> io.Byte_Reader { reader_init(r, s) rr, _ := io.to_byte_reader(reader_to_stream(r)) return rr } + +// init a reader to the string `s` and return an io.Rune_Reader to_rune_reader :: proc(r: ^Reader, s: string) -> io.Rune_Reader { reader_init(r, s) rr, _ := io.to_rune_reader(reader_to_stream(r)) return rr } - +// remaining length of the reader reader_length :: proc(r: ^Reader) -> int { if r.i >= i64(len(r.s)) { return 0 @@ -50,10 +64,13 @@ reader_length :: proc(r: ^Reader) -> int { return int(i64(len(r.s)) - r.i) } +// returns the string length stored by the reader reader_size :: proc(r: ^Reader) -> i64 { return i64(len(r.s)) } +// reads len(p) bytes into the slice from the string in the reader +// returns `n` amount of read bytes and an io.Error reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) { if r.i >= i64(len(r.s)) { return 0, .EOF @@ -63,6 +80,9 @@ reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) { r.i += i64(n) return } + +// reads len(p) bytes into the slice from the string in the reader at an offset +// returns `n` amount of read bytes and an io.Error reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Error) { if off < 0 { return 0, .Invalid_Offset @@ -76,6 +96,8 @@ reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Erro } return } + +// reads and returns a single byte - error when out of bounds reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) { r.prev_rune = -1 if r.i >= i64(len(r.s)) { @@ -85,6 +107,8 @@ reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) { r.i += 1 return b, nil } + +// decreases the reader offset - error when below 0 reader_unread_byte :: proc(r: ^Reader) -> io.Error { if r.i <= 0 { return .Invalid_Unread @@ -93,6 +117,8 @@ reader_unread_byte :: proc(r: ^Reader) -> io.Error { r.i -= 1 return nil } + +// reads and returns a single rune and the rune size - error when out bounds reader_read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: io.Error) { if r.i >= i64(len(r.s)) { r.prev_rune = -1 @@ -107,6 +133,9 @@ reader_read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: io.Error) { r.i += i64(size) return } + +// decreases the reader offset by the last rune +// can only be used once and after a valid read_rune call reader_unread_rune :: proc(r: ^Reader) -> io.Error { if r.i <= 0 { return .Invalid_Unread @@ -118,6 +147,8 @@ reader_unread_rune :: proc(r: ^Reader) -> io.Error { r.prev_rune = -1 return nil } + +// seeks the reader offset to a wanted offset reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { r.prev_rune = -1 abs: i64 @@ -138,6 +169,8 @@ reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.E r.i = abs return abs, nil } + +// writes the string content left to read into the io.Writer `w` reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) { r.prev_rune = -1 if r.i >= i64(len(r.s)) { @@ -157,7 +190,6 @@ reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) { return } - @(private) _reader_vtable := &io.Stream_VTable{ impl_size = proc(s: io.Stream) -> i64 { From 2e6ad2a711a6dd47cac0462498d3c8b629f646fc Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 3 Apr 2022 21:06:06 +0200 Subject: [PATCH 0504/1052] Add extra help line for define/config. --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 9e470923d..52177e326 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2009,6 +2009,7 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-define:="); print_usage_line(2, "Defines a global constant with a value"); print_usage_line(2, "Example: -define:SPAM=123"); + print_usage_line(2, "To use: #config(SPAM, default_value)"); print_usage_line(0, ""); } From 2289b7a33de6e265a8d0c4c497a2afa4c2b140e2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 4 Apr 2022 17:04:05 +0100 Subject: [PATCH 0505/1052] Remove `#caller_location` from certain calls in `core:container/small_array` --- core/container/small_array/small_array.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index d09e0c81c..5cd421c84 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -25,14 +25,14 @@ slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T { } -get :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> T { +get :: proc(a: $A/Small_Array($N, $T), index: int) -> T { return a.data[index] } -get_ptr :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> ^T { +get_ptr :: proc(a: ^$A/Small_Array($N, $T), index: int) -> ^T { return &a.data[index] } -set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T, loc := #caller_location) { +set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T) { a.data[index] = item } From 2a59aebe5b6460df77501703621e5efe55503f8b Mon Sep 17 00:00:00 2001 From: hikari Date: Tue, 5 Apr 2022 14:03:29 +0300 Subject: [PATCH 0506/1052] sys/windows: add Dwmapi.lib binding --- core/sys/windows/dwmapi.odin | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 core/sys/windows/dwmapi.odin diff --git a/core/sys/windows/dwmapi.odin b/core/sys/windows/dwmapi.odin new file mode 100644 index 000000000..468b5bb87 --- /dev/null +++ b/core/sys/windows/dwmapi.odin @@ -0,0 +1,9 @@ +// +build windows +package sys_windows + +foreign import dwmapi "system:Dwmapi.lib" + +@(default_calling_convention="stdcall") +foreign dwmapi { + DwmFlush :: proc() -> HRESULT --- +} From cdb003bf23afa9456fd784c4aaa9633695fc14ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 5 Apr 2022 13:32:06 +0100 Subject: [PATCH 0507/1052] Add Packages and Nightly Builds to README.md --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5b8c25492..f05ec2b27 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,10 @@ main :: proc() { Instructions for downloading and installing the Odin compiler and libraries. +#### [Nightly Builds]https://odin-lang.org/docs/nightly/) + +Get the latest nightly builds of Odin. + ### Learning Odin #### [Overview of Odin](https://odin-lang.org/docs/overview) @@ -68,6 +72,10 @@ An overview of the Odin programming language. Answers to common questions about Odin. +#### [Packages](https://pkg.odin-lang.org/) + +Documentation for all the official packages part of the [core](https://pkg.odin-lang.org/core/) and [vendor](https://pkg.odin-lang.org/vendor/) library collections. + #### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki) A wiki maintained by the Odin community. @@ -76,12 +84,6 @@ A wiki maintained by the Odin community. Get live support and talk with other odiners on the Odin Discord. -### References - -#### [Language Specification](https://odin-lang.org/docs/spec/) - -The official Odin Language specification. - ### Articles #### [The Odin Blog](https://odin-lang.org/news/) From ca549939f38c9bf41ddd0d72d1619843fde2a027 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 5 Apr 2022 13:33:25 +0100 Subject: [PATCH 0508/1052] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f05ec2b27..166112c43 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ main :: proc() { Instructions for downloading and installing the Odin compiler and libraries. -#### [Nightly Builds]https://odin-lang.org/docs/nightly/) +#### [Nightly Builds](https://odin-lang.org/docs/nightly/) Get the latest nightly builds of Odin. From 7f6c6945aef7b26632093fa36b56b2951cb27165 Mon Sep 17 00:00:00 2001 From: Despacito696969 <56641258+Despacito696969@users.noreply.github.com> Date: Tue, 5 Apr 2022 20:17:47 +0200 Subject: [PATCH 0509/1052] Fix for `slice_to_components` Using `slice_to_components` wouldn't compile because `s.data` is type of `rawptr` and return type is `^T` --- core/mem/mem.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 817c0ea5f..d3dcf3a3d 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -166,7 +166,7 @@ slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T { slice_to_components :: proc "contextless" (slice: $E/[]$T) -> (data: ^T, len: int) { s := transmute(Raw_Slice)slice - return s.data, s.len + return (^T)(s.data), s.len } buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E { From ad0a413b40cc95e240f8a83fa21a709b4ab2b1bb Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 5 Apr 2022 20:26:18 +0200 Subject: [PATCH 0510/1052] Give build/run/check/test/doc a `-file` flag. A package has canonically always been a directory, but odin allowing you to build a single-file package confused newcomers who didn't understand why they could then not access variables and procedures from another file in the same directory. This change disallows building single-file packages by default, requiring the `-file` flag to acknowledge you understand the nuance. `-help` for these commands also clarifies the difference. ``` W:\Odin>odin build -help odin is a tool for managing Odin source code Usage: odin build [arguments] build Compile directory of .odin files as an executable. One must contain the program's entry point, all must be in the same package. Use `-file` to build a single file instead. Examples: odin build . # Build package in current directory odin build

$sr;R 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 literal 0 HcmV?d00001 diff --git a/tests/core/encoding/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin similarity index 64% rename from tests/core/encoding/test_core_json.odin rename to tests/core/encoding/json/test_core_json.odin index 702086ea2..60e71bf72 100644 --- a/tests/core/encoding/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -9,32 +9,30 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } main :: proc() { - t := testing.T{} - + t := testing.T{} + parse_json(&t) marshal_json(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) if TEST_fail > 0 { os.exit(1) } diff --git a/tests/core/encoding/varint/test_core_varint.odin b/tests/core/encoding/varint/test_core_varint.odin new file mode 100644 index 000000000..5b8ccdc2a --- /dev/null +++ b/tests/core/encoding/varint/test_core_varint.odin @@ -0,0 +1,81 @@ +package test_core_varint + +import "core:encoding/varint" +import "core:testing" +import "core:fmt" +import "core:os" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + + test_dwarf(&t) + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } +} + +@(test) +test_dwarf :: proc(t: ^testing.T) { + for vector in ULEB_Vectors { + val, size := varint.decode_uleb128(vector.encoded) + + msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) + expect(t, size == vector.size && val == vector.value, msg) + } + + for vector in ILEB_Vectors { + val, size := varint.decode_ileb128(vector.encoded) + + msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) + expect(t, size == vector.size && val == vector.value, msg) + } +} + +ULEB_Test_Vector :: struct { + encoded: []u8, + value: u128, + size: int, +} + +ULEB_Vectors :: []ULEB_Test_Vector{ + { []u8{0x00}, 0, 1 }, + { []u8{0x7f}, 127, 1 }, + { []u8{0xE5, 0x8E, 0x26}, 624485, 3 }, + { []u8{0x80}, 0, 0 }, + { []u8{}, 0, 0 }, +} + +ILEB_Test_Vector :: struct { + encoded: []u8, + value: i128, + size: int, +} + +ILEB_Vectors :: []ILEB_Test_Vector{ + { []u8{0x00}, 0, 1 }, + { []u8{0xC0, 0xBB, 0x78}, -123456, 3 }, + { []u8{}, 0, 0 }, +} \ No newline at end of file diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index f68767612..607642339 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -15,14 +15,12 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(" FAIL:", message) + fmt.printf("[%v] %v\n", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { fmt.printf("[%v] ", loc) diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 2171a0d92..52005d915 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -32,23 +32,21 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } I_Error :: image.Error diff --git a/tests/core/math/noise/test_core_math_noise.odin b/tests/core/math/noise/test_core_math_noise.odin index be89d076a..a0360e695 100644 --- a/tests/core/math/noise/test_core_math_noise.odin +++ b/tests/core/math/noise/test_core_math_noise.odin @@ -13,23 +13,21 @@ V3 :: noise.Vec3 V4 :: noise.Vec4 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } main :: proc() { diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index ef31f91db..3837436bc 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -10,34 +10,31 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } - main :: proc() { - t := testing.T{} - test_parse_demo(&t) + t := testing.T{} + test_parse_demo(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } @@ -50,4 +47,4 @@ test_parse_demo :: proc(t: ^testing.T) { for key, value in pkg.files { expect(t, value.syntax_error_count == 0, fmt.tprintf("%v should contain zero errors", key)) } -} +} \ No newline at end of file diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index c1f9603fd..70da1a73b 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -9,59 +9,57 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } main :: proc() { - t := testing.T{} - test_index_any_small_string_not_found(&t) - test_index_any_larger_string_not_found(&t) - test_index_any_small_string_found(&t) - test_index_any_larger_string_found(&t) + t := testing.T{} + test_index_any_small_string_not_found(&t) + test_index_any_larger_string_not_found(&t) + test_index_any_small_string_found(&t) + test_index_any_larger_string_found(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } } @test test_index_any_small_string_not_found :: proc(t: ^testing.T) { - index := strings.index_any(".", "/:\"") - log(t, index) - expect(t, index == -1, "index_any should be negative") + index := strings.index_any(".", "/:\"") + log(t, index) + expect(t, index == -1, "index_any should be negative") } @test test_index_any_larger_string_not_found :: proc(t: ^testing.T) { - index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"") - expect(t, index == -1, "index_any should be negative") + index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"") + expect(t, index == -1, "index_any should be negative") } @test test_index_any_small_string_found :: proc(t: ^testing.T) { - index := strings.index_any(".", "/:.\"") - expect(t, index == 0, "index_any should be 0") + index := strings.index_any(".", "/:.\"") + expect(t, index == 0, "index_any should be 0") } @test test_index_any_larger_string_found :: proc(t: ^testing.T) { - index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") - expect(t, index == 8, "index_any should be 8") + index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") + expect(t, index == 8, "index_any should be 8") } From e76a5d8e12ae3d6e8e75e8df53a30bfbcc66b829 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 8 Mar 2022 18:07:16 +0100 Subject: [PATCH 0343/1052] [varint] Add signed LEB128 encoding. --- core/encoding/varint/leb128.odin | 96 ++++++++++++++++--- .../encoding/varint/test_core_varint.odin | 47 +++++++-- 2 files changed, 119 insertions(+), 24 deletions(-) diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin index 0c314b3f8..7640ba1fb 100644 --- a/core/encoding/varint/leb128.odin +++ b/core/encoding/varint/leb128.odin @@ -6,21 +6,31 @@ Jeroen van Rijn: Initial implementation. */ -// package varint implements variable length integer encoding and decoding -// using the LEB128 format as used by DWARF debug and other file formats +// package varint implements variable length integer encoding and decoding using +// the LEB128 format as used by DWARF debug info, Android .dex and other file formats. package varint -// Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used. -// Returns `size` == 0 for an invalid value, empty slice, or a varint > 16 bytes. // In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file. -decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int) { +// Instead we'll set limits on the values we'll encode/decode +// 18 * 7 bits = 126, which means that a possible 19th byte may at most be `0b0000_0011`. +LEB128_MAX_BYTES :: 19 + +Error :: enum { + None = 0, + Buffer_Too_Small = 1, + Value_Too_Large = 2, +} + +// Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used. +// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. +decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int, err: Error) { more := true for v, i in buf { size = i + 1 - if size > size_of(u128) { - return + if size == LEB128_MAX_BYTES && v > 0b0000_0011 { + return 0, 0, .Value_Too_Large } val |= u128(v & 0x7f) << uint(i * 7) @@ -33,25 +43,26 @@ decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int) { // If the buffer runs out before the number ends, return an error. if more { - return 0, 0 + return 0, 0, .Buffer_Too_Small } return } // Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used. -// Returns `size` == 0 for an invalid value, empty slice, or a varint > 16 bytes. -// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file. -decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int) { +// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. +decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { shift: uint if len(buf) == 0 { - return + return 0, 0, .Buffer_Too_Small } for v in buf { size += 1 - if size > size_of(i128) { - return + + // 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011. + if size == LEB128_MAX_BYTES && v > 0b0000_0011 { + return 0, 0, .Value_Too_Large } val |= i128(v & 0x7f) << shift @@ -64,4 +75,61 @@ decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int) { val |= max(i128) << shift } return +} + +// Encode `val` into `buf` as an unsigned LEB128 encoded series of bytes. +// `buf` must be appropriately sized. +encode_uleb128 :: proc(buf: []u8, val: u128) -> (size: int, err: Error) { + val := val + + for { + size += 1 + + if size > len(buf) { + return 0, .Buffer_Too_Small + } + + low := val & 0x7f + val >>= 7 + + if val > 0 { + low |= 0x80 // more bytes to follow + } + buf[size - 1] = u8(low) + + if val == 0 { break } + } + return +} + +@(private) +SIGN_MASK :: (i128(1) << 121) // sign extend mask + +// Encode `val` into `buf` as a signed LEB128 encoded series of bytes. +// `buf` must be appropriately sized. +encode_ileb128 :: proc(buf: []u8, val: i128) -> (size: int, err: Error) { + val := val + more := true + + for more { + size += 1 + + if size > len(buf) { + return 0, .Buffer_Too_Small + } + + low := val & 0x7f + val >>= 7 + + low = (low ~ SIGN_MASK) - SIGN_MASK + + if (val == 0 && low & 0x40 != 0x40) || (val == -1 && low & 0x40 == 0x40) { + more = false + } else { + low |= 0x80 + } + + buf[size - 1] = u8(low) + } + return } \ No newline at end of file diff --git a/tests/core/encoding/varint/test_core_varint.odin b/tests/core/encoding/varint/test_core_varint.odin index 5b8ccdc2a..63a9d1d72 100644 --- a/tests/core/encoding/varint/test_core_varint.odin +++ b/tests/core/encoding/varint/test_core_varint.odin @@ -4,6 +4,7 @@ import "core:encoding/varint" import "core:testing" import "core:fmt" import "core:os" +import "core:slice" TEST_count := 0 TEST_fail := 0 @@ -39,18 +40,40 @@ main :: proc() { @(test) test_dwarf :: proc(t: ^testing.T) { + buf: [varint.LEB128_MAX_BYTES]u8 + for vector in ULEB_Vectors { - val, size := varint.decode_uleb128(vector.encoded) + val, size, err := varint.decode_uleb128(vector.encoded) msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) expect(t, size == vector.size && val == vector.value, msg) + + msg = fmt.tprintf("Expected decoder to return error %v, got %v", vector.error, err) + expect(t, err == vector.error, msg) + + if err == .None { // Try to roundtrip + size, err = varint.encode_uleb128(buf[:], vector.value) + + msg = fmt.tprintf("Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size]) + expect(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), msg) + } } for vector in ILEB_Vectors { - val, size := varint.decode_ileb128(vector.encoded) + val, size, err := varint.decode_ileb128(vector.encoded) msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) expect(t, size == vector.size && val == vector.value, msg) + + msg = fmt.tprintf("Expected decoder to return error %v, got %v", vector.error, err) + expect(t, err == vector.error, msg) + + if err == .None { // Try to roundtrip + size, err = varint.encode_ileb128(buf[:], vector.value) + + msg = fmt.tprintf("Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size]) + expect(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), msg) + } } } @@ -58,24 +81,28 @@ ULEB_Test_Vector :: struct { encoded: []u8, value: u128, size: int, + error: varint.Error, } ULEB_Vectors :: []ULEB_Test_Vector{ - { []u8{0x00}, 0, 1 }, - { []u8{0x7f}, 127, 1 }, - { []u8{0xE5, 0x8E, 0x26}, 624485, 3 }, - { []u8{0x80}, 0, 0 }, - { []u8{}, 0, 0 }, + { []u8{0x00}, 0, 1, .None }, + { []u8{0x7f}, 127, 1, .None }, + { []u8{0xE5, 0x8E, 0x26}, 624485, 3, .None }, + { []u8{0x80}, 0, 0, .Buffer_Too_Small }, + { []u8{}, 0, 0, .Buffer_Too_Small }, } ILEB_Test_Vector :: struct { encoded: []u8, value: i128, size: int, + error: varint.Error, } ILEB_Vectors :: []ILEB_Test_Vector{ - { []u8{0x00}, 0, 1 }, - { []u8{0xC0, 0xBB, 0x78}, -123456, 3 }, - { []u8{}, 0, 0 }, + { []u8{0x00}, 0, 1, .None }, + { []u8{0x3f}, 63, 1, .None }, + { []u8{0x40}, -64, 1, .None }, + { []u8{0xC0, 0xBB, 0x78}, -123456, 3, .None }, + { []u8{}, 0, 0, .Buffer_Too_Small }, } \ No newline at end of file From b94a7a87fabba83ecb7774f6a2d8a23c0075955a Mon Sep 17 00:00:00 2001 From: gitlost Date: Tue, 8 Mar 2022 18:06:25 +0000 Subject: [PATCH 0344/1052] Fix issue #1574 "fract in linalg/glm is broken" by fixing trunc_f16/32/64 in "math.odin" (~ typos on expressions) Fix classify_f16 Inf test (would fail for subnormal 0h0001) by changing multiplier 0.5 -> 0.25 Add some useful consts to "math.odin" (INF_F16 etc) Add comment to "demo.odin" mentioning that -0.0 must be used to specify negative zero --- core/math/math.odin | 31 +- examples/demo/demo.odin | 1 + tests/common/common.odin | 41 +++ tests/core/Makefile | 11 +- .../linalg/glsl/test_linalg_glsl_math.odin | 85 +++++ tests/core/math/test_core_math.odin | 310 ++++++++++++++++++ 6 files changed, 472 insertions(+), 7 deletions(-) create mode 100644 tests/common/common.odin create mode 100644 tests/core/math/linalg/glsl/test_linalg_glsl_math.odin create mode 100644 tests/core/math/test_core_math.odin diff --git a/core/math/math.odin b/core/math/math.odin index b81598da9..afbda051d 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -396,7 +396,7 @@ trunc_f16 :: proc "contextless" (x: f16) -> f16 { e := (x >> shift) & mask - bias if e < shift { - x &= ~(1 << (shift-e)) - 1 + x &~= 1 << (shift-e) - 1 } return transmute(f16)x } @@ -428,7 +428,7 @@ trunc_f32 :: proc "contextless" (x: f32) -> f32 { e := (x >> shift) & mask - bias if e < shift { - x &= ~(1 << (shift-e)) - 1 + x &~= 1 << (shift-e) - 1 } return transmute(f32)x } @@ -460,7 +460,7 @@ trunc_f64 :: proc "contextless" (x: f64) -> f64 { e := (x >> shift) & mask - bias if e < shift { - x &= ~(1 << (shift-e)) - 1 + x &~= 1 << (shift-e) - 1 } return transmute(f64)x } @@ -473,6 +473,7 @@ trunc_f64 :: proc "contextless" (x: f64) -> f64 { } trunc_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(trunc_f64(f64(x))) } trunc_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(trunc_f64(f64(x))) } +// Removes the fractional part of the value, i.e. rounds towards zero. trunc :: proc{ trunc_f16, trunc_f16le, trunc_f16be, trunc_f32, trunc_f32le, trunc_f32be, @@ -958,7 +959,7 @@ classify_f16 :: proc "contextless" (x: f16) -> Float_Class { return .Neg_Zero } return .Zero - case x*0.5 == x: + case x*0.25 == x: if x < 0 { return .Neg_Inf } @@ -1027,6 +1028,8 @@ classify_f64 :: proc "contextless" (x: f64) -> Float_Class { } classify_f64le :: proc "contextless" (x: f64le) -> Float_Class { return #force_inline classify_f64(f64(x)) } classify_f64be :: proc "contextless" (x: f64be) -> Float_Class { return #force_inline classify_f64(f64(x)) } +// Returns the `Float_Class` of the value, i.e. whether normal, subnormal, zero, negative zero, NaN, infinity or +// negative infinity. classify :: proc{ classify_f16, classify_f16le, classify_f16be, classify_f32, classify_f32le, classify_f32be, @@ -1715,4 +1718,22 @@ F32_BIAS :: 0x7f F64_MASK :: 0x7ff F64_SHIFT :: 64 - 12 -F64_BIAS :: 0x3ff \ No newline at end of file +F64_BIAS :: 0x3ff + +INF_F16 :f16: 0h7C00 +NEG_INF_F16 :f16: 0hFC00 + +SNAN_F16 :f16: 0h7C01 +QNAN_F16 :f16: 0h7E01 + +INF_F32 :f32: 0h7F80_0000 +NEG_INF_F32 :f32: 0hFF80_0000 + +SNAN_F32 :f32: 0hFF80_0001 +QNAN_F32 :f32: 0hFFC0_0001 + +INF_F64 :f64: 0h7FF0_0000_0000_0000 +NEG_INF_F64 :f64: 0hFFF0_0000_0000_0000 + +SNAN_F64 :f64: 0h7FF0_0000_0000_0001 +QNAN_F64 :f64: 0h7FF8_0000_0000_0001 \ No newline at end of file diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 044860ff7..4d4490446 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -94,6 +94,7 @@ the_basics :: proc() { z: f64 // `z` is typed of type `f64` (64-bit floating point number) z = 1 // `1` is an untyped integer literal which can be implicitly converted to `f64` // No need for any suffixes or decimal places like in other languages + // (with the exception of negative zero, which must be given as `-0.0`) // CONSTANTS JUST WORK!!! diff --git a/tests/common/common.odin b/tests/common/common.odin new file mode 100644 index 000000000..2f5272b03 --- /dev/null +++ b/tests/common/common.odin @@ -0,0 +1,41 @@ +// Boilerplate for tests +package common + +import "core:testing" +import "core:fmt" +import "core:os" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] FAIL %s\n", loc, message) + return + } + fmt.printf("[%v] PASS\n", loc) + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v]", loc) + fmt.printf(" log: %v\n", v) + } +} + +report :: proc(t: ^testing.T) { + if TEST_fail > 0 { + if TEST_fail > 1 { + fmt.printf("%v/%v tests successful, %v tests failed.\n", TEST_count - TEST_fail, TEST_count, TEST_fail) + } else { + fmt.printf("%v/%v tests successful, %v test failed.\n", TEST_count - TEST_fail, TEST_count, TEST_fail) + } + os.exit(1) + } else { + fmt.printf("%v/%v tests successful.\n", TEST_count, TEST_count) + } +} diff --git a/tests/core/Makefile b/tests/core/Makefile index 1c2cee6bd..c003e4bc8 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,7 +1,8 @@ ODIN=../../odin PYTHON=$(shell which python3) -all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test +all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test \ + math_test linalg_glsl_math_test download_test_assets: $(PYTHON) download_assets.py @@ -22,4 +23,10 @@ crypto_test: $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check noise_test: - $(ODIN) run math/noise -out=test_noise \ No newline at end of file + $(ODIN) run math/noise -out=test_noise + +math_test: + $(ODIN) run math/test_core_math.odin -collection:tests=.. + +linalg_glsl_math_test: + $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -collection:tests=.. \ No newline at end of file diff --git a/tests/core/math/linalg/glsl/test_linalg_glsl_math.odin b/tests/core/math/linalg/glsl/test_linalg_glsl_math.odin new file mode 100644 index 000000000..e0b4f5145 --- /dev/null +++ b/tests/core/math/linalg/glsl/test_linalg_glsl_math.odin @@ -0,0 +1,85 @@ +// Tests "linalg_glsl_math.odin" in "core:math/linalg/glsl". +// Must be run with `-collection:tests=` flag, e.g. +// ./odin run tests/core/math/linalg/glsl/test_linalg_glsl_math.odin -collection:tests=./tests +package test_core_math_linalg_glsl_math + +import glsl "core:math/linalg/glsl" + +import "core:fmt" +import "core:math" +import "core:testing" +import tc "tests:common" + +main :: proc() { + + t := testing.T{} + + test_fract_f32(&t) + test_fract_f64(&t) + + tc.report(&t) +} + +@test +test_fract_f32 :: proc(t: ^testing.T) { + + using math + + r: f32 + + Datum :: struct { + i: int, + v: f32, + e: f32, + } + @static data := []Datum{ + { 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken + { 1, -10.5, -0.5 }, + { 2, F32_MIN, F32_MIN }, // 0x1p-126 + { 3, -F32_MIN, -F32_MIN }, + { 4, 0.0, 0.0 }, + { 5, -0.0, -0.0 }, + { 6, 1, 0.0 }, + { 7, -1, -0.0 }, + { 8, 0h3F80_0001, 0h3400_0000 }, // 0x1.000002p+0, 0x1p-23 + { 9, -0h3F80_0001, -0h3400_0000 }, + } + + for d, i in data { + assert(i == d.i) + r = glsl.fract(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%v (%h)) -> %v (%h) != %v", i, #procedure, d.v, d.v, r, r, d.e)) + } +} + +@test +test_fract_f64 :: proc(t: ^testing.T) { + + using math + + r: f64 + + Datum :: struct { + i: int, + v: f64, + e: f64, + } + @static data := []Datum{ + { 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken + { 1, -10.5, -0.5 }, + { 2, F64_MIN, F64_MIN }, // 0x1p-1022 + { 3, -F64_MIN, -F64_MIN }, + { 4, 0.0, 0.0 }, + { 5, -0.0, -0.0 }, + { 6, 1, 0.0 }, + { 7, -1, -0.0 }, + { 8, 0h3FF0_0000_0000_0001, 0h3CB0_0000_0000_0000 }, // 0x1.0000000000001p+0, 0x1p-52 + { 9, -0h3FF0_0000_0000_0001, -0h3CB0_0000_0000_0000 }, + } + + for d, i in data { + assert(i == d.i) + r = glsl.fract(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%v (%h)) -> %v (%h) != %v", i, #procedure, d.v, d.v, r, r, d.e)) + } +} diff --git a/tests/core/math/test_core_math.odin b/tests/core/math/test_core_math.odin new file mode 100644 index 000000000..57da27002 --- /dev/null +++ b/tests/core/math/test_core_math.odin @@ -0,0 +1,310 @@ +// Tests "math.odin" in "core:math". +// Must be run with `-collection:tests=` flag, e.g. +// ./odin run tests/core/math/test_core_math.odin -collection:tests=./tests +package test_core_math + +import "core:fmt" +import "core:math" +import "core:testing" +import tc "tests:common" + +main :: proc() { + t := testing.T{} + + test_classify_f16(&t) + test_classify_f32(&t) + test_classify_f64(&t) + + test_trunc_f16(&t) + test_trunc_f32(&t) + test_trunc_f64(&t) + + tc.report(&t) +} + +@test +test_classify_f16 :: proc(t: ^testing.T) { + + using math + using Float_Class + + r: Float_Class + + Datum :: struct { + i: int, + v: f16, + e: math.Float_Class, + } + @static data := []Datum{ + { 0, 1.2, Normal }, + { 1, 0h0001, Subnormal }, + { 2, 0.0, Zero }, + { 3, -0.0, Neg_Zero }, + { 4, SNAN_F16, NaN }, + { 5, QNAN_F16, NaN }, + { 6, INF_F16, Inf }, + { 7, NEG_INF_F16, Neg_Inf }, + } + + for d, i in data { + assert(i == d.i) + r = classify_f16(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) + } + + /* Check all subnormals (exponent 0, 10-bit significand non-zero) */ + for i :u16 = 1; i < 0x400; i += 1 { + v :f16 = transmute(f16)i + r = classify_f16(v) + e :Float_Class: Subnormal + tc.expect(t, r == e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, v, r, e)) + } +} + +@test +test_classify_f32 :: proc(t: ^testing.T) { + + using math + using Float_Class + + r: Float_Class + + Datum :: struct { + i: int, + v: f32, + e: math.Float_Class, + } + @static data := []Datum{ + { 0, 1.2, Normal }, + { 1, 0h0000_0001, Subnormal }, + { 2, 0.0, Zero }, + { 3, -0.0, Neg_Zero }, + { 4, SNAN_F32, NaN }, + { 5, QNAN_F32, NaN }, + { 6, INF_F32, Inf }, + { 7, NEG_INF_F32, Neg_Inf }, + } + + for d, i in data { + assert(i == d.i) + r = classify_f32(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) + } +} + +@test +test_classify_f64 :: proc(t: ^testing.T) { + + using math + using Float_Class + + r: Float_Class + + Datum :: struct { + i: int, + v: f64, + e: math.Float_Class, + } + @static data := []Datum{ + { 0, 1.2, Normal }, + { 1, 0h0000_0000_0000_0001, Subnormal }, + { 2, 0.0, Zero }, + { 3, -0.0, Neg_Zero }, + { 4, SNAN_F64, NaN }, + { 5, QNAN_F64, NaN }, + { 6, INF_F64, Inf }, + { 7, NEG_INF_F64, Neg_Inf }, + } + + for d, i in data { + assert(i == d.i) + r = classify_f64(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) + } +} + +@test +test_trunc_f16 :: proc(t: ^testing.T) { + + using math + + r, v: f16 + + Datum :: struct { + i: int, + v: f16, + e: f16, + } + @static data := []Datum{ + { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken + { 1, -10.5, -10 }, + + { 2, F16_MAX, F16_MAX }, + { 3, -F16_MAX, -F16_MAX }, + { 4, F16_MIN, 0.0 }, + { 5, -F16_MIN, -0.0 }, + { 6, 0.0, 0.0 }, + { 7, -0.0, -0.0 }, + { 8, 1, 1 }, + { 9, -1, -1 }, + { 10, INF_F16, INF_F16 }, + { 11, NEG_INF_F16, NEG_INF_F16 }, + + /* From https://en.wikipedia.org/wiki/Half-precision_floating-point_format */ + { 12, 0h3C01, 1 }, // 0x1.004p+0 (smallest > 1) + { 13, -0h3C01, -1 }, + { 14, 0h3BFF, 0.0 }, // 0x1.ffcp-1 (largest < 1) + { 15, -0h3BFF, -0.0 }, + { 16, 0h0001, 0.0 }, // 0x0.004p-14 (smallest subnormal) + { 17, -0h0001, -0.0 }, + { 18, 0h03FF, 0.0 }, // 0x0.ffcp-14 (largest subnormal) + { 19, -0h03FF, -0.0 }, + + { 20, 0hC809, -8 }, // -0x1.024p+3 + { 21, 0h4458, 4 }, // 0x1.16p+2 + } + + for d, i in data { + assert(i == d.i) + r = trunc_f16(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + } + + v = SNAN_F16 + r = trunc_f16(v) + tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + + v = QNAN_F16 + r = trunc_f16(v) + tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) +} + +@test +test_trunc_f32 :: proc(t: ^testing.T) { + + using math + + r, v: f32 + + Datum :: struct { + i: int, + v: f32, + e: f32, + } + @static data := []Datum{ + { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken + { 1, -10.5, -10 }, + + { 2, F32_MAX, F32_MAX }, + { 3, -F32_MAX, -F32_MAX }, + { 4, F32_MIN, 0.0 }, + { 5, -F32_MIN, -0.0 }, + { 6, 0.0, 0.0 }, + { 7, -0.0, -0.0 }, + { 8, 1, 1 }, + { 9, -1, -1 }, + { 10, INF_F32, INF_F32 }, + { 11, NEG_INF_F32, NEG_INF_F32 }, + + /* From https://en.wikipedia.org/wiki/Single-precision_floating-point_format */ + { 12, 0h3F80_0001, 1 }, // 0x1.000002p+0 (smallest > 1) + { 13, -0h3F80_0001, -1 }, + { 14, 0h3F7F_FFFF, 0.0 }, // 0x1.fffffep-1 (largest < 1) + { 15, -0h3F7F_FFFF, -0.0 }, + { 16, 0h0000_0001, 0.0 }, // 0x0.000002p-126 (smallest subnormal) + { 17, -0h0000_0001, -0.0 }, + { 18, 0h007F_FFFF, 0.0 }, // 0x0.fffffep-126 (largest subnormal) + { 19, -0h007F_FFFF, -0.0 }, + + /* From libc-test src/math/sanity/truncf.h */ + { 20, 0hC101_11D0, -8 }, // -0x1.0223ap+3 + { 21, 0h408B_0C34, 4 }, // 0x1.161868p+2 + { 22, 0hC106_1A5A, -8 }, // -0x1.0c34b4p+3 + { 23, 0hC0D1_0378, -6 }, // -0x1.a206fp+2 + { 24, 0h4114_45DE, 9 }, // 0x1.288bbcp+3 + { 25, 0h3F29_77E8, 0.0 }, // 0x1.52efdp-1 + { 26, 0hBED0_2E64, -0.0 }, // -0x1.a05cc8p-2 + { 27, 0h3F0F_CF7D, 0.0 }, // 0x1.1f9efap-1 + { 28, 0h3F46_2ED8, 0.0 }, // 0x1.8c5dbp-1 + { 29, 0hBF2D_C375, -0.0 }, // -0x1.5b86eap-1 + } + + for d, i in data { + assert(i == d.i) + r = trunc_f32(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + } + + v = SNAN_F32 + r = trunc_f32(v) + tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + + v = QNAN_F32 + r = trunc_f32(v) + tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) +} + +@test +test_trunc_f64 :: proc(t: ^testing.T) { + + using math + + r, v: f64 + + Datum :: struct { + i: int, + v: f64, + e: f64, + } + data := []Datum{ + { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken + { 1, -10.5, -10 }, + + { 2, F64_MAX, F64_MAX }, + { 3, -F64_MAX, -F64_MAX }, + { 4, F64_MIN, 0.0 }, + { 5, -F64_MIN, -0.0 }, + { 6, 0.0, 0.0 }, + { 7, -0.0, -0.0 }, + { 8, 1, 1 }, + { 9, -1, -1 }, + { 10, INF_F64, INF_F64 }, + { 11, NEG_INF_F64, NEG_INF_F64 }, + + /* From https://en.wikipedia.org/wiki/Double-precision_floating-point_format */ + { 12, 0h3FF0_0000_0000_0001, 1 }, // 0x1.0000000000001p+0 (smallest > 1) + { 13, -0h3FF0_0000_0000_0001, -1 }, + { 14, 0h3FEF_FFFF_FFFF_FFFF, 0.0 }, // 0x1.fffffffffffffp-1 (largest < 1) + { 15, -0h3FEF_FFFF_FFFF_FFFF, -0.0 }, + { 16, 0h0000_0000_0000_0001, 0.0 }, // 0x0.0000000000001p-1022 (smallest subnormal) + { 17, -0h0000_0000_0000_0001, -0.0 }, + { 18, 0h000F_FFFF_FFFF_FFFF, 0.0 }, // 0x0.fffffffffffffp-1022 (largest subnormal) + { 19, -0h000F_FFFF_FFFF_FFFF, -0.0 }, + + /* From libc-test src/math/sanity/trunc.h */ + { 20, 0hC020_2239_F3C6_A8F1, -8 }, // -0x1.02239f3c6a8f1p+3 + { 21, 0h4011_6186_8E18_BC67, 4 }, // 0x1.161868e18bc67p+2 + { 22, 0hC020_C34B_3E01_E6E7, -8 }, // -0x1.0c34b3e01e6e7p+3 + { 23, 0hC01A_206F_0A19_DCC4, -6 }, // -0x1.a206f0a19dcc4p+2 + { 24, 0h4022_88BB_B0D6_A1E6, 9 }, // 0x1.288bbb0d6a1e6p+3 + { 25, 0h3FE5_2EFD_0CD8_0497, 0.0 }, // 0x1.52efd0cd80497p-1 + { 26, 0hBFDA_05CC_7544_81D1, -0.0 }, // -0x1.a05cc754481d1p-2 + { 27, 0h3FE1_F9EF_9347_45CB, 0.0 }, // 0x1.1f9ef934745cbp-1 + { 28, 0h3FE8_C5DB_097F_7442, 0.0 }, // 0x1.8c5db097f7442p-1 + { 29, 0hBFE5_B86E_A811_8A0E, -0.0 }, // -0x1.5b86ea8118a0ep-1 + } + + for d, i in data { + assert(i == d.i) + r = trunc_f64(d.v) + tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + } + + v = SNAN_F64 + r = trunc_f64(v) + tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + + v = QNAN_F64 + r = trunc_f64(v) + tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) +} From 76b10b5f5dd17b2c4e80f391883ec42500a85875 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 8 Mar 2022 19:28:55 +0100 Subject: [PATCH 0345/1052] [varint] Add additional LEB128 tests. --- core/encoding/varint/leb128.odin | 8 ++- .../encoding/varint/test_core_varint.odin | 62 ++++++++++++++++--- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin index 7640ba1fb..898c6af67 100644 --- a/core/encoding/varint/leb128.odin +++ b/core/encoding/varint/leb128.odin @@ -10,6 +10,8 @@ // the LEB128 format as used by DWARF debug info, Android .dex and other file formats. package varint +import "core:fmt" + // In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file. // Instead we'll set limits on the values we'll encode/decode // 18 * 7 bits = 126, which means that a possible 19th byte may at most be `0b0000_0011`. @@ -29,6 +31,7 @@ decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int, err: Error) { for v, i in buf { size = i + 1 + // 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011. if size == LEB128_MAX_BYTES && v > 0b0000_0011 { return 0, 0, .Value_Too_Large } @@ -60,8 +63,8 @@ decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { for v in buf { size += 1 - // 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011. - if size == LEB128_MAX_BYTES && v > 0b0000_0011 { + // 18 * 7 bits = 126, which including sign means we can have a 19th byte. + if size == LEB128_MAX_BYTES && v > 0x7f { return 0, 0, .Value_Too_Large } @@ -86,6 +89,7 @@ encode_uleb128 :: proc(buf: []u8, val: u128) -> (size: int, err: Error) { size += 1 if size > len(buf) { + fmt.println(val, buf[:size - 1]) return 0, .Buffer_Too_Small } diff --git a/tests/core/encoding/varint/test_core_varint.odin b/tests/core/encoding/varint/test_core_varint.odin index 63a9d1d72..813c52018 100644 --- a/tests/core/encoding/varint/test_core_varint.odin +++ b/tests/core/encoding/varint/test_core_varint.odin @@ -5,10 +5,13 @@ import "core:testing" import "core:fmt" import "core:os" import "core:slice" +import "core:math/rand" TEST_count := 0 TEST_fail := 0 +RANDOM_TESTS :: 100 + when ODIN_TEST { expect :: testing.expect log :: testing.log @@ -30,7 +33,7 @@ when ODIN_TEST { main :: proc() { t := testing.T{} - test_dwarf(&t) + test_leb128(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) if TEST_fail > 0 { @@ -39,7 +42,7 @@ main :: proc() { } @(test) -test_dwarf :: proc(t: ^testing.T) { +test_leb128 :: proc(t: ^testing.T) { buf: [varint.LEB128_MAX_BYTES]u8 for vector in ULEB_Vectors { @@ -75,6 +78,46 @@ test_dwarf :: proc(t: ^testing.T) { expect(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), msg) } } + + for num_bytes in 1..uint(16) { + for _ in 0..RANDOM_TESTS { + unsigned, signed := get_random(num_bytes) + + { + encode_size, encode_err := varint.encode_uleb128(buf[:], unsigned) + msg := fmt.tprintf("%v failed to encode as an unsigned LEB128 value, got %v", unsigned, encode_err) + expect(t, encode_err == .None, msg) + + decoded, decode_size, decode_err := varint.decode_uleb128(buf[:]) + msg = fmt.tprintf("Expected %02x to decode as %v, got %v", buf[:encode_size], unsigned, decoded) + expect(t, decode_err == .None && decode_size == encode_size && decoded == unsigned, msg) + } + + { + encode_size, encode_err := varint.encode_ileb128(buf[:], signed) + msg := fmt.tprintf("%v failed to encode as a signed LEB128 value, got %v", signed, encode_err) + expect(t, encode_err == .None, msg) + + decoded, decode_size, decode_err := varint.decode_ileb128(buf[:]) + msg = fmt.tprintf("Expected %02x to decode as %v, got %v, err: %v", buf[:encode_size], signed, decoded, decode_err) + expect(t, decode_err == .None && decode_size == encode_size && decoded == signed, msg) + } + } + } +} + +get_random :: proc(byte_count: uint) -> (u: u128, i: i128) { + assert(byte_count >= 0 && byte_count <= size_of(u128)) + + for _ in 1..byte_count { + u <<= 8 + u |= u128(rand.uint32() & 0xff) + } + + bias := i128(1 << (byte_count * 7)) - 1 + i = i128(u) - bias + + return } ULEB_Test_Vector :: struct { @@ -85,11 +128,13 @@ ULEB_Test_Vector :: struct { } ULEB_Vectors :: []ULEB_Test_Vector{ - { []u8{0x00}, 0, 1, .None }, - { []u8{0x7f}, 127, 1, .None }, - { []u8{0xE5, 0x8E, 0x26}, 624485, 3, .None }, - { []u8{0x80}, 0, 0, .Buffer_Too_Small }, - { []u8{}, 0, 0, .Buffer_Too_Small }, + { []u8{0x00}, 0, 1, .None }, + { []u8{0x7f}, 127, 1, .None }, + { []u8{0xE5, 0x8E, 0x26}, 624485, 3, .None }, + { []u8{0x80}, 0, 0, .Buffer_Too_Small }, + { []u8{}, 0, 0, .Buffer_Too_Small }, + + { []u8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03}, max(u128), 19, .None }, } ILEB_Test_Vector :: struct { @@ -105,4 +150,7 @@ ILEB_Vectors :: []ILEB_Test_Vector{ { []u8{0x40}, -64, 1, .None }, { []u8{0xC0, 0xBB, 0x78}, -123456, 3, .None }, { []u8{}, 0, 0, .Buffer_Too_Small }, + + { []u8{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7e}, min(i128), 19, .None }, + { []u8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01}, max(i128), 19, .None }, } \ No newline at end of file From 52e60526effe7c8265f4a60e87abd9fc69ce9332 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 8 Mar 2022 19:32:30 +0100 Subject: [PATCH 0346/1052] tabs. --- tests/core/encoding/varint/test_core_varint.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/core/encoding/varint/test_core_varint.odin b/tests/core/encoding/varint/test_core_varint.odin index 813c52018..093b043d7 100644 --- a/tests/core/encoding/varint/test_core_varint.odin +++ b/tests/core/encoding/varint/test_core_varint.odin @@ -129,12 +129,12 @@ ULEB_Test_Vector :: struct { ULEB_Vectors :: []ULEB_Test_Vector{ { []u8{0x00}, 0, 1, .None }, - { []u8{0x7f}, 127, 1, .None }, + { []u8{0x7f}, 127, 1, .None }, { []u8{0xE5, 0x8E, 0x26}, 624485, 3, .None }, - { []u8{0x80}, 0, 0, .Buffer_Too_Small }, - { []u8{}, 0, 0, .Buffer_Too_Small }, + { []u8{0x80}, 0, 0, .Buffer_Too_Small }, + { []u8{}, 0, 0, .Buffer_Too_Small }, - { []u8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03}, max(u128), 19, .None }, + { []u8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03}, max(u128), 19, .None }, } ILEB_Test_Vector :: struct { @@ -149,7 +149,7 @@ ILEB_Vectors :: []ILEB_Test_Vector{ { []u8{0x3f}, 63, 1, .None }, { []u8{0x40}, -64, 1, .None }, { []u8{0xC0, 0xBB, 0x78}, -123456, 3, .None }, - { []u8{}, 0, 0, .Buffer_Too_Small }, + { []u8{}, 0, 0, .Buffer_Too_Small }, { []u8{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7e}, min(i128), 19, .None }, { []u8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01}, max(i128), 19, .None }, From 26ffec845ba0212e838657320ac70ab464b2bd3e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 8 Mar 2022 19:38:36 +0100 Subject: [PATCH 0347/1052] [crypto] Remove unused `mem` import for siphash. --- core/crypto/siphash/siphash.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin index 63576551c..a6c75f315 100644 --- a/core/crypto/siphash/siphash.odin +++ b/core/crypto/siphash/siphash.odin @@ -14,7 +14,6 @@ package siphash import "core:crypto" import "core:crypto/util" -import "core:mem" /* High level API From 2a41814985f99d76ca07b48896eb79a1e2b4dea9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 8 Mar 2022 19:56:42 +0100 Subject: [PATCH 0348/1052] [varint] Tighten max input bounds. --- core/encoding/varint/leb128.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin index 898c6af67..476b9c2c9 100644 --- a/core/encoding/varint/leb128.odin +++ b/core/encoding/varint/leb128.odin @@ -32,7 +32,7 @@ decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int, err: Error) { size = i + 1 // 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011. - if size == LEB128_MAX_BYTES && v > 0b0000_0011 { + if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0b0000_0011 { return 0, 0, .Value_Too_Large } @@ -64,7 +64,7 @@ decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { size += 1 // 18 * 7 bits = 126, which including sign means we can have a 19th byte. - if size == LEB128_MAX_BYTES && v > 0x7f { + if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0x7f { return 0, 0, .Value_Too_Large } From 64705ddd1df8c6c63a971b01d6a832d1eb75ae56 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 8 Mar 2022 20:08:56 +0100 Subject: [PATCH 0349/1052] [varint] Add doc.odin --- core/encoding/varint/doc.odin | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 core/encoding/varint/doc.odin diff --git a/core/encoding/varint/doc.odin b/core/encoding/varint/doc.odin new file mode 100644 index 000000000..dd068b261 --- /dev/null +++ b/core/encoding/varint/doc.odin @@ -0,0 +1,27 @@ +/* + Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others. + + Author of this Odin package: Jeroen van Rijn + + Example: + ```odin + import "core:encoding/varint" + import "core:fmt" + + main :: proc() { + buf: [varint.LEB128_MAX_BYTES]u8 + + value := u128(42) + + encode_size, encode_err := varint.encode_uleb128(buf[:], value) + assert(encode_size == 1 && encode_err == .None) + + fmt.println(buf[:encode_size]) + + decoded_val, decode_size, decode_err := varint.decode_uleb128(buf[:encode_size]) + assert(decoded_val == value && decode_size == encode_size && decode_err == .None) + } + ``` + +*/ +package varint \ No newline at end of file From 832003dd4b20b3581e22f57ffef72e67d6cb7146 Mon Sep 17 00:00:00 2001 From: CiD- Date: Tue, 8 Mar 2022 17:15:45 -0500 Subject: [PATCH 0350/1052] os2 tests --- core/os/os2/errors_linux.odin | 11 +++++++++++ core/os/os2/file.odin | 4 ---- core/os/os2/file_linux.odin | 29 +---------------------------- tests/core/Makefile | 7 +++++-- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index f074c7c86..d9056bd6b 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -1,6 +1,8 @@ //+private package os2 +import "core:sys/unix" + EPERM :: 1 ENOENT :: 2 ESRCH :: 3 @@ -126,6 +128,15 @@ ENOTRECOVERABLE:: 131 /* State not recoverable */ ERFKILL :: 132 /* Operation not possible due to RF-kill */ EHWPOISON :: 133 /* Memory page has hardware error */ +_get_platform_error :: proc(res: int) -> Error { + errno := unix.get_errno(res) + return Platform_Error{i32(errno)} +} + +_ok_or_error :: proc(res: int) -> Error { + return res >= 0 ? nil : _get_platform_error(res) +} + _error_string :: proc(errno: i32) -> string { if errno == 0 { return "" diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 09e1e8daf..707df37a2 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -61,10 +61,6 @@ create :: proc(name: string, perm: File_Mode = 0) -> (Handle, Error) { return open(name, {.Read, .Write, .Create}, perm) } -opendir :: proc(name: string) -> (Handle, Error) { - return _opendir(name) -} - open :: proc(name: string, flags := File_Flags{.Read}, perm: File_Mode = 0) -> (Handle, Error) { flags := flags if .Write not_in flags { diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index a88515b0e..db0e2efa8 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -7,22 +7,8 @@ import "core:strings" import "core:sys/unix" -_get_platform_error :: proc(res: int) -> Error { - errno := unix.get_errno(res) - return Platform_Error{i32(errno)} -} - -_ok_or_error :: proc(res: int) -> Error { - return res >= 0 ? nil : _get_platform_error(res) -} - _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { - switch kind { - case .stdin: return Handle(0) - case .stdout: return Handle(1) - case .stderr: return Handle(2) - } - unreachable() + return Handle(kind) } __O_RDONLY :: 0o0 @@ -38,19 +24,6 @@ __O_DIRECTORY :: 0o200000 __O_SYNC :: 0o4010000 __O_CLOEXEC :: 0o2000000 -_opendir :: proc(name: string) -> (Handle, Error) { - cstr := strings.clone_to_cstring(name, context.temp_allocator) - - flags := __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC - - handle_i := unix.sys_open(cstr, flags) - if handle_i < 0 { - return INVALID_HANDLE, _get_platform_error(handle_i) - } - - return Handle(handle_i), nil -} - _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { cstr := strings.clone_to_cstring(name, context.temp_allocator) diff --git a/tests/core/Makefile b/tests/core/Makefile index 1c2cee6bd..0c3e1e09a 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,7 +1,7 @@ ODIN=../../odin PYTHON=$(shell which python3) -all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test +all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test os2_test download_test_assets: $(PYTHON) download_assets.py @@ -22,4 +22,7 @@ crypto_test: $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check noise_test: - $(ODIN) run math/noise -out=test_noise \ No newline at end of file + $(ODIN) run math/noise -out=test_noise + +os2_test: + $(ODIN) run os2/test_os2.odin -out=test_os2 From ff60b752bd11e654b5bfe210043cd63379e2ca34 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Mar 2022 22:35:10 +0000 Subject: [PATCH 0351/1052] Replace `#if` with `if` where possible --- src/main.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1e1e957cb..e01ea0308 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -384,7 +384,7 @@ i32 linker_stage(lbGenerator *gen) { // NOTE(zangent): Sometimes, you have to use -framework on MacOS. // This allows you to specify '-f' in a #foreign_system_library, // without having to implement any new syntax specifically for MacOS. - #if defined(GB_SYSTEM_OSX) + if (build_context.metrics.os == TargetOs_darwin) { if (string_ends_with(lib, str_lit(".framework"))) { // framework thingie String lib_name = lib; @@ -400,7 +400,7 @@ i32 linker_stage(lbGenerator *gen) { // dynamic or static system lib, just link regularly searching system library paths lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); } - #else + } else { // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, // since those are statically linked to at link time. shared libraries (.so) has to be // available at runtime wherever the executable is run, so we make require those to be @@ -418,7 +418,7 @@ i32 linker_stage(lbGenerator *gen) { // dynamic or static system lib, just link regularly searching system library paths lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); } - #endif + } } gbString object_files = gb_string_make(heap_allocator(), ""); @@ -456,11 +456,11 @@ i32 linker_stage(lbGenerator *gen) { // line arguments prepared previously are incompatible with ld. // // Shared libraries are .dylib on MacOS and .so on Linux. - #if defined(GB_SYSTEM_OSX) + if (build_context.metrics.os == TargetOs_darwin) { output_ext = STR_LIT(".dylib"); - #else + } else { output_ext = STR_LIT(".so"); - #endif + } link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } else if (build_context.metrics.os != TargetOs_openbsd) { @@ -477,24 +477,24 @@ i32 linker_stage(lbGenerator *gen) { gbString platform_lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(platform_lib_str)); - #if defined(GB_SYSTEM_OSX) + if (build_context.metrics.os == TargetOs_darwin) { platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib"); - #else + } else { platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm"); - #endif + } - #if defined(GB_SYSTEM_OSX) + if (build_context.metrics.arch == TargetOs_darwin) { // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. // NOTE: If you change this (although this minimum is as low as you can go with Odin working) // make sure to also change the 'mtriple' param passed to 'opt' - #if defined(GB_CPU_ARM) - link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 "); - #else - link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.8.0 "); - #endif + if (build_context.metrics.arch == TargetArch_amd64) { + link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 "); + } else { + link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.8.0 "); + } // This points the linker to where the entry point is link_settings = gb_string_appendc(link_settings, " -e _main "); - #endif + } gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument "); defer (gb_string_free(link_command_line)); From 0278ac85a04309c8777663afe733e984a44bbcc8 Mon Sep 17 00:00:00 2001 From: Al Hoang <3811822-hoanga@users.noreply.gitlab.com> Date: Tue, 8 Mar 2022 23:48:25 -0600 Subject: [PATCH 0352/1052] update to build for FreeBSD --- Makefile | 6 ++++++ core/os/os_freebsd.odin | 4 ++-- core/os/stat_unix.odin | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ceff3c207..b8bf26a88 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,12 @@ ifeq ($(OS), OpenBSD) CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) endif +ifeq ($(OS), FreeBSD) + LLVM_CONFIG=/usr/local/bin/llvm-config11 + + CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) + LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) +endif all: debug demo diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index e31eb31bb..4f31b1492 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -232,10 +232,10 @@ foreign libc { @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- - @(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 --- + @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 --- @(link_name="gettid") _unix_gettid :: proc() -> u64 --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- - @(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int --- + @(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int --- @(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int --- @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int --- diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin index 2aa9fc283..c82466b08 100644 --- a/core/os/stat_unix.odin +++ b/core/os/stat_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd, openbsd +//+build linux, darwin, openbsd package os import "core:time" From ba412fd87bc1a24ca8ce9ee9ae665aa15b4cde2b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Mar 2022 09:36:21 +0000 Subject: [PATCH 0353/1052] Fix typo --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index e01ea0308..4d25aea48 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -483,7 +483,7 @@ i32 linker_stage(lbGenerator *gen) { platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm"); } - if (build_context.metrics.arch == TargetOs_darwin) { + if (build_context.metrics.os == TargetOs_darwin) { // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. // NOTE: If you change this (although this minimum is as low as you can go with Odin working) // make sure to also change the 'mtriple' param passed to 'opt' From ea9c2fed57a885b74f3ed96461b7aba485b78e36 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Mar 2022 10:52:37 +0000 Subject: [PATCH 0354/1052] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index abbdccecd..e8b3d3050 100644 --- a/.gitignore +++ b/.gitignore @@ -279,3 +279,5 @@ shared/ *.ll *.sublime-workspace +examples/bug/ +build.sh From 8e4d6b3e5dde51fdd71a49b2bf703ae3428c1c21 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Mar 2022 11:24:36 +0000 Subject: [PATCH 0355/1052] Fix typo --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 4d25aea48..aab695de2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -487,7 +487,7 @@ i32 linker_stage(lbGenerator *gen) { // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. // NOTE: If you change this (although this minimum is as low as you can go with Odin working) // make sure to also change the 'mtriple' param passed to 'opt' - if (build_context.metrics.arch == TargetArch_amd64) { + if (build_context.metrics.arch == TargetArch_arm64) { link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 "); } else { link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.8.0 "); From 5eebdebec89aa4a6041cf1eb4b72a74bbd669db4 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 05:09:39 -0800 Subject: [PATCH 0356/1052] Make llvm-config build more general for linux --- Makefile | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index ceff3c207..e77acea93 100644 --- a/Makefile +++ b/Makefile @@ -30,25 +30,29 @@ ifeq ($(OS), Darwin) ifeq ($(shell $(LLVM_CONFIG) --version | grep -E $(LLVM_VERSION_PATTERN)),) ifeq ($(ARCH), arm64) $(error "Requirement: llvm-config must be base version 13 for arm64") - else + else $(error "Requirement: llvm-config must be base version greater than 11 for amd64/x86") - endif - endif + endif + endif LDFLAGS:=$(LDFLAGS) -liconv -ldl CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) LDFLAGS:=$(LDFLAGS) -lLLVM-C endif ifeq ($(OS), Linux) - LLVM_CONFIG=llvm-config-11 - ifneq ($(shell which llvm-config-11 2>/dev/null),) - LLVM_CONFIG=llvm-config-11 - else ifneq ($(shell which llvm-config-11-64 2>/dev/null),) - LLVM_CONFIG=llvm-config-11-64 - else - ifeq ($(shell $(LLVM_CONFIG) --version | grep '^11\.'),) - $(error "Requirement: llvm-config must be version 11") - endif + LLVM_CONFIG=llvm-config + + LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0" + + LLVM_VERSION_PATTERN_SEPERATOR = )|( + LLVM_VERSION_PATTERNS_ESCAPED_DOT = $(subst .,\.,$(LLVM_VERSIONS)) + LLVM_VERSION_PATTERNS_REPLACE_PERCENT = $(subst %,.*,$(LLVM_VERSION_PATTERNS_ESCAPED_DOT)) + LLVM_VERSION_PATTERN_REMOVE_ELEMENTS = $(subst " ",$(LLVM_VERSION_PATTERN_SEPERATOR),$(LLVM_VERSION_PATTERNS_REPLACE_PERCENT)) + LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR = $(subst ",,$(LLVM_VERSION_PATTERN_REMOVE_ELEMENTS)) + LLVM_VERSION_PATTERN = "^(($(LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR)))" + + ifeq ($(shell $(LLVM_CONFIG) --version | grep -E $(LLVM_VERSION_PATTERN)),) + $(error "Requirement: llvm-config must be base version greater than 11") endif LDFLAGS:=$(LDFLAGS) -ldl From 3092fb2ff3ab776290eefb8df27def79cc1fbe77 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:01:40 -0800 Subject: [PATCH 0357/1052] Add initial cut of build script --- build_odin.sh | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100755 build_odin.sh diff --git a/build_odin.sh b/build_odin.sh new file mode 100755 index 000000000..5b3767a1a --- /dev/null +++ b/build_odin.sh @@ -0,0 +1,118 @@ +#!/bin/bash +set -eu + +GIT_SHA=$(git rev-parse --short HEAD) +DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value" +LDFLAGS="-pthread -lm -lstdc++" +CFLAGS="-std=c++14 -DGIT_SHA=\"$GIT_SHA\"" +CFLAGS="$CFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\"" +CC=clang +OS=$(uname) + +panic() { + printf "%s\n" "$1" + exit 1 +} + +config_darwin() { + ARCH=$(uname -m) + LLVM_CONFIG=llvm-config + + # allow for arm only llvm's with version 13 + if [ ARCH == arm64 ]; then + LLVM_VERSIONS="13.%.%" + else + # allow for x86 / amd64 all llvm versions begining from 11 + LLVM_VERSIONS="13.%.%" "12.0.1" "11.1.0" + fi + + if [ $($LLVM_CONFIG --version | grep -E $(LLVM_VERSION_PATTERN)) == 0 ]; then + if [ ARCH == arm64 ]; then + panic "Requirement: llvm-config must be base version 13 for arm64" + else + panic "Requirement: llvm-config must be base version greater than 11 for amd64/x86" + fi + fi + + LDFLAGS="$LDFLAGS -liconv -ldl" + CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS -lLLVM-C" +} + +config_openbsd() { + LLVM_CONFIG=/usr/local/bin/llvm-config + + LDFLAGS="$LDFLAGS -liconv" + CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" +} + +config_linux() { + LLVM_CONFIG=llvm-config + + LDFLAGS="$LDFLAGS -ldl" + CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" +} + +build_odin() { + set -x + $CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin + set +x +} + +run_demo() { + ./odin run examples/demo/demo.odin +} + +case $OS in +Linux) + config_linux + ;; +Darwin) + config_darwin + ;; +OpenBSD) + config_openbsd + ;; +esac + +if [[ $# -eq 0 ]]; then + EXTRAFLAGS="-g" + + build_odin + run_demo + + exit 0 +fi + +if [[ $# -eq 1 ]]; then + case $1 in + report) + EXTRAFLAGS="-g" + build_odin + ./odin report + exit 0 + ;; + debug) + EXTRAFLAGS="-g" + ;; + release) + EXTRAFLAGS="-O3" + ;; + release_native) + EXTRAFLAGS="-O3 -march=native" + ;; + nightly) + EXTRAFLAGS="-DNIGHTLY -O3" + ;; + *) + panic "Unsupported build option!" + ;; + esac + + build_odin + run_demo + + exit 0 +fi From d1477bcfa74fbc04813ceff4e603c1c982fd4d33 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:07:19 -0800 Subject: [PATCH 0358/1052] Fix wonky copied space issues --- build_odin.sh | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/build_odin.sh b/build_odin.sh index 5b3767a1a..e836cb0ac 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -16,43 +16,43 @@ panic() { config_darwin() { ARCH=$(uname -m) - LLVM_CONFIG=llvm-config + LLVM_CONFIG=llvm-config - # allow for arm only llvm's with version 13 + # allow for arm only llvm's with version 13 if [ ARCH == arm64 ]; then - LLVM_VERSIONS="13.%.%" + LLVM_VERSIONS="13.%.%" else - # allow for x86 / amd64 all llvm versions begining from 11 - LLVM_VERSIONS="13.%.%" "12.0.1" "11.1.0" + # allow for x86 / amd64 all llvm versions begining from 11 + LLVM_VERSIONS="13.%.%" "12.0.1" "11.1.0" fi if [ $($LLVM_CONFIG --version | grep -E $(LLVM_VERSION_PATTERN)) == 0 ]; then if [ ARCH == arm64 ]; then - panic "Requirement: llvm-config must be base version 13 for arm64" + panic "Requirement: llvm-config must be base version 13 for arm64" else panic "Requirement: llvm-config must be base version greater than 11 for amd64/x86" fi - fi + fi - LDFLAGS="$LDFLAGS -liconv -ldl" - CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" - LDFLAGS="$LDFLAGS -lLLVM-C" + LDFLAGS="$LDFLAGS -liconv -ldl" + CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS -lLLVM-C" } config_openbsd() { - LLVM_CONFIG=/usr/local/bin/llvm-config + LLVM_CONFIG=/usr/local/bin/llvm-config - LDFLAGS="$LDFLAGS -liconv" - CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" - LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" + LDFLAGS="$LDFLAGS -liconv" + CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" } config_linux() { - LLVM_CONFIG=llvm-config + LLVM_CONFIG=llvm-config - LDFLAGS="$LDFLAGS -ldl" - CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" - LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" + LDFLAGS="$LDFLAGS -ldl" + CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" } build_odin() { From 005d52cab7db883269e325ca8c0bb9e56a6e542e Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:08:48 -0800 Subject: [PATCH 0359/1052] more spacing issues --- build_odin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_odin.sh b/build_odin.sh index e836cb0ac..634e4aa7f 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -26,7 +26,7 @@ config_darwin() { LLVM_VERSIONS="13.%.%" "12.0.1" "11.1.0" fi - if [ $($LLVM_CONFIG --version | grep -E $(LLVM_VERSION_PATTERN)) == 0 ]; then + if [ $($LLVM_CONFIG --version | grep -E $(LLVM_VERSION_PATTERN)) == 0 ]; then if [ ARCH == arm64 ]; then panic "Requirement: llvm-config must be base version 13 for arm64" else From f5cc8bd7bf0071d46fb39091a23fe19def22c02b Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:14:30 -0800 Subject: [PATCH 0360/1052] only build odin for report when necessary --- build_odin.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build_odin.sh b/build_odin.sh index 634e4aa7f..77d69a6e5 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -89,8 +89,11 @@ fi if [[ $# -eq 1 ]]; then case $1 in report) - EXTRAFLAGS="-g" - build_odin + if [[ ! -f "./odin" ]]; then + EXTRAFLAGS="-g" + build_odin + fi + ./odin report exit 0 ;; From db169a4334862a8e49b7492452e4da51aeee814a Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:26:25 -0800 Subject: [PATCH 0361/1052] Cleanup build mode selection --- build_odin.sh | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/build_odin.sh b/build_odin.sh index 77d69a6e5..dac89acf7 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -56,6 +56,23 @@ config_linux() { } build_odin() { + case $1 in + debug) + EXTRAFLAGS="-g" + ;; + release) + EXTRAFLAGS="-O3" + ;; + release-native) + EXTRAFLAGS="-O3 -march=native" + ;; + nightly) + EXTRAFLAGS="-DNIGHTLY -O3" + ;; + *) + panic "Build mode unsupported!" + esac + set -x $CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin set +x @@ -75,14 +92,13 @@ Darwin) OpenBSD) config_openbsd ;; +*) + panic "Platform unsupported!" esac if [[ $# -eq 0 ]]; then - EXTRAFLAGS="-g" - - build_odin + build_odin debug run_demo - exit 0 fi @@ -90,32 +106,17 @@ if [[ $# -eq 1 ]]; then case $1 in report) if [[ ! -f "./odin" ]]; then - EXTRAFLAGS="-g" - build_odin + build_odin debug fi ./odin report exit 0 ;; - debug) - EXTRAFLAGS="-g" - ;; - release) - EXTRAFLAGS="-O3" - ;; - release_native) - EXTRAFLAGS="-O3 -march=native" - ;; - nightly) - EXTRAFLAGS="-DNIGHTLY -O3" - ;; *) - panic "Unsupported build option!" + build_odin $1 ;; esac - build_odin run_demo - exit 0 fi From d5b0632e4f7aa289c2876d6248508bff6e68a7b5 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:27:52 -0800 Subject: [PATCH 0362/1052] add handling for too many args --- build_odin.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build_odin.sh b/build_odin.sh index dac89acf7..8cd0849a7 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -119,4 +119,6 @@ if [[ $# -eq 1 ]]; then run_demo exit 0 +else + panic "Too many arguments!" fi From 9aea990184b35dadbd786b70730111735fb4fc0a Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:49:52 -0800 Subject: [PATCH 0363/1052] clean up osx semver handling in build --- build_odin.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build_odin.sh b/build_odin.sh index 8cd0849a7..80c35dc44 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -14,19 +14,21 @@ panic() { exit 1 } +function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } + config_darwin() { ARCH=$(uname -m) LLVM_CONFIG=llvm-config # allow for arm only llvm's with version 13 if [ ARCH == arm64 ]; then - LLVM_VERSIONS="13.%.%" + MIN_LLVM_VERSION=("13.0.0") else # allow for x86 / amd64 all llvm versions begining from 11 - LLVM_VERSIONS="13.%.%" "12.0.1" "11.1.0" + MIN_LLVM_VERSION=("11.1.0") fi - if [ $($LLVM_CONFIG --version | grep -E $(LLVM_VERSION_PATTERN)) == 0 ]; then + if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then if [ ARCH == arm64 ]; then panic "Requirement: llvm-config must be base version 13 for arm64" else From 34a9f55f3771c05695f3e4c886b7c067d7aec5e2 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:52:22 -0800 Subject: [PATCH 0364/1052] Update ci to use build script --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 412587b3c..cbe3fc08c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: - name: Download LLVM, botan run: sudo apt-get install llvm-11 clang-11 llvm libbotan-2-dev botan - name: build odin - run: make release + run: ./build_odin.sh release - name: Odin version run: ./odin version timeout-minutes: 1 @@ -55,7 +55,7 @@ jobs: TMP_PATH=$(xcrun --show-sdk-path)/user/include echo "CPATH=$TMP_PATH" >> $GITHUB_ENV - name: build odin - run: make release + run: ./build_odin.sh release - name: Odin version run: ./odin version timeout-minutes: 1 From c543ecd64c0681a7dc92fd3edef670380a24756e Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 06:57:59 -0800 Subject: [PATCH 0365/1052] Try to find llvm-config-11 on goofy misconfigured CI box --- build_odin.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build_odin.sh b/build_odin.sh index 80c35dc44..911e8a2d5 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -52,6 +52,15 @@ config_openbsd() { config_linux() { LLVM_CONFIG=llvm-config + MIN_LLVM_VERSION=("11.1.0") + if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then + + LLVM_CONFIG=llvm-config-11 + if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then + panic "Requirement: llvm-config must be base version greater than 11" + fi + fi + LDFLAGS="$LDFLAGS -ldl" CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" From 17eebf338c7c2428db99470f8e1dd6c8d2f7ac0f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Mar 2022 15:05:51 +0000 Subject: [PATCH 0366/1052] Fix #1606 (Call `runtime._cleanup_runtime_contextless()` for `os.exit`) --- core/os/os_darwin.odin | 1 + core/os/os_freebsd.odin | 1 + core/os/os_linux.odin | 1 + core/os/os_openbsd.odin | 2 ++ core/os/os_wasi.odin | 2 ++ core/os/os_windows.odin | 2 ++ core/runtime/core.odin | 5 +++++ 7 files changed, 14 insertions(+) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 4365842b0..ace622582 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -680,6 +680,7 @@ make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { } exit :: proc "contextless" (code: int) -> ! { + runtime._cleanup_runtime_contextless() _unix_exit(i32(code)) } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index e31eb31bb..7fb9dd26f 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -419,6 +419,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { } exit :: proc "contextless" (code: int) -> ! { + runtime._cleanup_runtime_contextless() _unix_exit(c.int(code)) } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 200d6d68d..9716e2925 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -802,6 +802,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { } exit :: proc "contextless" (code: int) -> ! { + runtime._cleanup_runtime_contextless() _unix_exit(c.int(code)) } diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 3862851a1..bca93880a 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -5,6 +5,7 @@ foreign import libc "system:c" import "core:runtime" import "core:strings" import "core:c" +import "core:runtime" Handle :: distinct i32 Pid :: distinct i32 @@ -658,6 +659,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { } exit :: proc "contextless" (code: int) -> ! { + runtime._cleanup_runtime_contextless() _unix_exit(c.int(code)) } diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index d2ba166bd..7bab1b949 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -1,6 +1,7 @@ package os import "core:sys/wasm/wasi" +import "core:runtime" Handle :: distinct i32 Errno :: distinct i32 @@ -93,5 +94,6 @@ heap_free :: proc(ptr: rawptr) { exit :: proc "contextless" (code: int) -> ! { + runtime._cleanup_runtime_contextless() wasi.proc_exit(wasi.exitcode_t(code)) } \ No newline at end of file diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index e6efb89df..fe9496e4c 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -2,6 +2,7 @@ package os import win32 "core:sys/windows" +import "core:runtime" Handle :: distinct uintptr File_Time :: distinct u64 @@ -128,6 +129,7 @@ get_page_size :: proc() -> int { exit :: proc "contextless" (code: int) -> ! { + runtime._cleanup_runtime_contextless() win32.ExitProcess(win32.DWORD(code)) } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 8d315a238..08ca4c049 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -459,6 +459,11 @@ _cleanup_runtime :: proc() { default_temp_allocator_destroy(&global_default_temp_allocator_data) } +_cleanup_runtime_contextless :: proc "contextless" () { + context = default_context() + _cleanup_runtime() +} + ///////////////////////////// ///////////////////////////// From 6d1a91f5b309e7d7dde69a91293b3f8908a1748d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Mar 2022 15:11:38 +0000 Subject: [PATCH 0367/1052] Fix typo --- core/os/os_openbsd.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index bca93880a..a99c8fef0 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -2,7 +2,6 @@ package os foreign import libc "system:c" -import "core:runtime" import "core:strings" import "core:c" import "core:runtime" From 7adaa4dc2b3784997ad38e499133bdfe4651c02c Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 07:15:08 -0800 Subject: [PATCH 0368/1052] refix make, adjust build for CI weirdness --- Makefile | 22 +++++++++------------- build_odin.sh | 16 ++++++++++------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index e77acea93..8de6ff06b 100644 --- a/Makefile +++ b/Makefile @@ -40,19 +40,15 @@ ifeq ($(OS), Darwin) LDFLAGS:=$(LDFLAGS) -lLLVM-C endif ifeq ($(OS), Linux) - LLVM_CONFIG=llvm-config - - LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0" - - LLVM_VERSION_PATTERN_SEPERATOR = )|( - LLVM_VERSION_PATTERNS_ESCAPED_DOT = $(subst .,\.,$(LLVM_VERSIONS)) - LLVM_VERSION_PATTERNS_REPLACE_PERCENT = $(subst %,.*,$(LLVM_VERSION_PATTERNS_ESCAPED_DOT)) - LLVM_VERSION_PATTERN_REMOVE_ELEMENTS = $(subst " ",$(LLVM_VERSION_PATTERN_SEPERATOR),$(LLVM_VERSION_PATTERNS_REPLACE_PERCENT)) - LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR = $(subst ",,$(LLVM_VERSION_PATTERN_REMOVE_ELEMENTS)) - LLVM_VERSION_PATTERN = "^(($(LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR)))" - - ifeq ($(shell $(LLVM_CONFIG) --version | grep -E $(LLVM_VERSION_PATTERN)),) - $(error "Requirement: llvm-config must be base version greater than 11") + LLVM_CONFIG=llvm-config-11 + ifneq ($(shell which llvm-config-11 2>/dev/null),) + LLVM_CONFIG=llvm-config-11 + else ifneq ($(shell which llvm-config-11-64 2>/dev/null),) + LLVM_CONFIG=llvm-config-11-64 + else + ifeq ($(shell $(LLVM_CONFIG) --version | grep '^11\.'),) + $(error "Requirement: llvm-config must be version 11") + endif endif LDFLAGS:=$(LDFLAGS) -ldl diff --git a/build_odin.sh b/build_odin.sh index 911e8a2d5..c707f4e67 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -50,15 +50,19 @@ config_openbsd() { } config_linux() { - LLVM_CONFIG=llvm-config + if which llvm-config > /dev/null 2>&1; then + LLVM_CONFIG=llvm-config + elif which llvm-config-11 > /dev/null 2>&1; then + LLVM_CONFIG=llvm-config-11 + elif which llvm-config-11-64 > /dev/null 2>&1; then + LLVM_CONFIG=llvm-config-11-64 + else + panic "Unable to find LLVM-config" + fi MIN_LLVM_VERSION=("11.1.0") if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then - - LLVM_CONFIG=llvm-config-11 - if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then - panic "Requirement: llvm-config must be base version greater than 11" - fi + panic "Requirement: llvm-config must be base version greater than 11" fi LDFLAGS="$LDFLAGS -ldl" From dc8d28c383a404d01dcbcb65ba84ff814da9424e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Mar 2022 15:15:30 +0000 Subject: [PATCH 0369/1052] Fix #1607 --- src/llvm_backend_expr.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 844deb43c..026350440 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2202,6 +2202,21 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } } + if (is_type_matrix(a) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { + Type *tl = base_type(a); + lbValue lhs = lb_address_from_load_or_generate_local(p, left); + lbValue rhs = lb_address_from_load_or_generate_local(p, right); + + + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(permanent_allocator(), 3); + args[0] = lb_emit_conv(p, lhs, t_rawptr); + args[1] = lb_emit_conv(p, rhs, t_rawptr); + args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); + lbValue val = lb_emit_runtime_call(p, "memory_compare", args); + lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type)); + return lb_emit_conv(p, res, t_bool); + } if (is_type_array(a) || is_type_enumerated_array(a)) { Type *tl = base_type(a); lbValue lhs = lb_address_from_load_or_generate_local(p, left); From 3bd1ac4c82a0e6944f3218ad38c4f5f5995d703e Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 07:18:41 -0800 Subject: [PATCH 0370/1052] test adjusting apt arg order --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cbe3fc08c..d5179e51b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Download LLVM, botan - run: sudo apt-get install llvm-11 clang-11 llvm libbotan-2-dev botan + run: sudo apt-get install llvm llvm-11 clang-11 libbotan-2-dev botan - name: build odin run: ./build_odin.sh release - name: Odin version From 1306c53fb1829b3454c795bf923c8c7f6f3c4483 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 07:21:19 -0800 Subject: [PATCH 0371/1052] more build tweaks? --- build_odin.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build_odin.sh b/build_odin.sh index c707f4e67..dc6434e19 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -62,6 +62,7 @@ config_linux() { MIN_LLVM_VERSION=("11.1.0") if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then + echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version) panic "Requirement: llvm-config must be base version greater than 11" fi From 7f8a9587e0d375486e3b45f9627463b8ec9421a1 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 07:22:48 -0800 Subject: [PATCH 0372/1052] more build tweaks? --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5179e51b..a7aa1b265 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Download LLVM, botan - run: sudo apt-get install llvm llvm-11 clang-11 libbotan-2-dev botan + run: sudo apt-get install llvm-11 clang-11 libbotan-2-dev botan - name: build odin run: ./build_odin.sh release - name: Odin version From a2250a5d4918498f6c68423c7dcd02c1910ceaec Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 07:24:49 -0800 Subject: [PATCH 0373/1052] lower minimum llvm version --- build_odin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_odin.sh b/build_odin.sh index dc6434e19..11d098952 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -60,7 +60,7 @@ config_linux() { panic "Unable to find LLVM-config" fi - MIN_LLVM_VERSION=("11.1.0") + MIN_LLVM_VERSION=("11.0.0") if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version) panic "Requirement: llvm-config must be base version greater than 11" From 2652c2d7a573cc44379d7843472b9f379246d31b Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 9 Mar 2022 07:42:38 -0800 Subject: [PATCH 0374/1052] normalize version parser --- build_odin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_odin.sh b/build_odin.sh index 11d098952..a323782a1 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -14,7 +14,7 @@ panic() { exit 1 } -function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } +version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } config_darwin() { ARCH=$(uname -m) From bad295cf695e623591f737fb68556ea0a76a53ce Mon Sep 17 00:00:00 2001 From: CiD- Date: Thu, 10 Mar 2022 09:23:33 -0500 Subject: [PATCH 0375/1052] add test directory... --- tests/core/os2/test_os2.odin | 170 +++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 tests/core/os2/test_os2.odin diff --git a/tests/core/os2/test_os2.odin b/tests/core/os2/test_os2.odin new file mode 100644 index 000000000..7fa0dd20d --- /dev/null +++ b/tests/core/os2/test_os2.odin @@ -0,0 +1,170 @@ +package test_os2 + +import "core:fmt" +import "core:os/os2" +import "core:sys/unix" +import "core:testing" +import "core:intrinsics" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) where intrinsics.type_is_comparable(T) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + ok := value == expected + if !ok { + fmt.printf("expected %v, got %v", expected, value) + TEST_fail += 1 + return + } + fmt.println(" PASS") + } + + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() +{ + t: testing.T + file_test(&t) + path_test(&t) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +@private +_expect_no_error :: proc(t: ^testing.T, e: os2.Error, loc := #caller_location) { + expect(t, e == nil, "unexpected error", loc) +} + + +F_OK :: 0 // Test for file existance +X_OK :: 1 // Test for execute permission +W_OK :: 2 // Test for write permission +R_OK :: 4 // Test for read permission + +@test +file_test :: proc(t: ^testing.T) { + + /* Things to test: + * std_handle,create,open,close,name,seek,read,read_at,read_from,write,write_at, + * write_to,file_size,sync,flush,truncate,remove,rename,link,symlink,read_link, + * unlink,chdir,chmod,chown,lchown,chtimes,exists,is_file,is_dir + */ + + stdin := os2.std_handle(.stdin) + expect_value(t, stdin, 0) + stdout := os2.std_handle(.stdout) + expect_value(t, stdout, 1) + stderr := os2.std_handle(.stderr) + expect_value(t, stderr, 2) + + fd, err := os2.open("filethatdoesntexist.txt") + expect(t, err != nil, "missing error") + expect_value(t, fd, os2.INVALID_HANDLE) + + fd, err = os2.open("write.txt", {.Write, .Create, .Trunc}, 0o664) + _expect_no_error(t, err) + expect(t, fd != os2.INVALID_HANDLE, "unexpected handle") + + s1 := "hello" + b1 := transmute([]u8)s1 + + n: int + n, err = os2.write_at(fd, b1, 10) + _expect_no_error(t, err) + expect_value(t, n, 5) + + s2 := "abcdefghij" + b2 := transmute([]u8)s2 + + n, err = os2.write(fd, b2) + _expect_no_error(t, err) + expect_value(t, n, 10) + + _expect_no_error(t, os2.sync(fd)) + _expect_no_error(t, os2.close(fd)) + + fd, err = os2.open("write.txt") + _expect_no_error(t, err) + + buf: [32]u8 + + n, err = os2.read(fd, buf[:]) + _expect_no_error(t, err) + expect_value(t, n, 15) + expect_value(t, string(buf[:n]), "abcdefghijhello") + + n, err = os2.read_at(fd, buf[0:2], 1) + _expect_no_error(t, err) + expect_value(t, n, 2) + expect_value(t, string(buf[0:2]), "bc") + + _expect_no_error(t, os2.close(fd)) +} + +@test +path_test :: proc(t: ^testing.T) { + err: os2.Error + if os2.exists("a") { + err = os2.remove_all("a") + _expect_no_error(t, err) + } + + err = os2.mkdir_all("a/b/c/d", 0) + _expect_no_error(t, err) + + expect(t, os2.exists("a"), "directory does not exist") + + fd: os2.Handle + fd, err = os2.create("a/b/c/file.txt", 0o644) + _expect_no_error(t, err) + + err = os2.close(fd) + _expect_no_error(t, err) + + expect(t, unix.sys_access("a/b/c/file.txt", X_OK) < 0, "unexpected exec permission") + + err = os2.rename("a/b/c/file.txt", "a/b/file.txt") + _expect_no_error(t, err) + + expect(t, unix.sys_access("a/b/c/file.txt", F_OK) < 0, "unexpected exec permission") + + err = os2.symlink("b/c/d", "a/symlink_to_d") + _expect_no_error(t, err) + + symlink: string + symlink, err = os2.read_link("a/symlink_to_d") + _expect_no_error(t, err) + expect_value(t, symlink, "b/c/d") + + fd, err = os2.create("a/symlink_to_d/shnt.txt", 0o744) + _expect_no_error(t, err) + + err = os2.close(fd) + _expect_no_error(t, err) + + expect_value(t, unix.sys_access("a/b/c/d/shnt.txt", X_OK | R_OK | W_OK), 0) + + err = os2.remove_all("a") + _expect_no_error(t, err) + + expect(t, !os2.exists("a"), "directory a exists") +} From 0b61215f7bf056e3ae4b5619542481c2a1b3fdc0 Mon Sep 17 00:00:00 2001 From: Jason Kercher Date: Thu, 10 Mar 2022 11:12:06 -0500 Subject: [PATCH 0376/1052] getting tests to run --- core/os/os2/env_windows.odin | 4 ++-- core/os/os2/file_windows.odin | 5 ----- tests/core/Makefile | 32 ++++++++++++++++++++++++++++++++ tests/core/build.bat | 7 ++++++- tests/core/os2/test_os2.odin | 18 ++++++++++++++---- 5 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 tests/core/Makefile diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin index a3b97375b..1e1ffba4d 100644 --- a/core/os/os2/env_windows.odin +++ b/core/os/os2/env_windows.odin @@ -1,8 +1,8 @@ //+private package os2 -import "core:runtime" -import "core:mem" +//import "core:runtime" +//import "core:mem" import win32 "core:sys/windows" _get_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index dd33d8a53..9fdbd9a5a 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -36,11 +36,6 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { unreachable() } -_opendir :: proc(path: string) -> (handle: Handle, err: Error) { - return INVALID_HANDLE, .Invalid_Argument -} - - _open :: proc(path: string, flags: File_Flags, perm: File_Mode) -> (handle: Handle, err: Error) { handle = INVALID_HANDLE if len(path) == 0 { diff --git a/tests/core/Makefile b/tests/core/Makefile new file mode 100644 index 000000000..82bcae068 --- /dev/null +++ b/tests/core/Makefile @@ -0,0 +1,32 @@ +ODIN=../../odin +PYTHON=$(shell which python3) + +all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test os2_test + +download_test_assets: + $(PYTHON) download_assets.py + +image_test: + $(ODIN) run image/test_core_image.odin + +compress_test: + $(ODIN) run compress/test_core_compress.odin + +strings_test: + $(ODIN) run strings/test_core_strings.odin + +hash_test: + $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check + +crypto_test: + $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check + +noise_test: + $(ODIN) run math/noise -out=test_noise + +os2_test: + $(ODIN) run os2/test_os2.odin -out=test_os2 + +encoding_test: + $(ODIN) run encoding/json -out=test_json + $(ODIN) run encoding/varint -out=test_varint diff --git a/tests/core/build.bat b/tests/core/build.bat index 0227ac6bb..8cf6486d3 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -41,4 +41,9 @@ echo --- echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% \ No newline at end of file +%PATH_TO_ODIN% run math/noise %COMMON% + +echo --- +echo Running core:os/os2 tests +echo --- +%PATH_TO_ODIN% run os2 %COMMON% diff --git a/tests/core/os2/test_os2.odin b/tests/core/os2/test_os2.odin index 7fa0dd20d..f8ef133a5 100644 --- a/tests/core/os2/test_os2.odin +++ b/tests/core/os2/test_os2.odin @@ -2,10 +2,14 @@ package test_os2 import "core:fmt" import "core:os/os2" -import "core:sys/unix" import "core:testing" import "core:intrinsics" +// really only want sys_access for more finite testing +when ODIN_OS == .Linux { + import "core:sys/unix" +} + TEST_count := 0 TEST_fail := 0 @@ -140,12 +144,16 @@ path_test :: proc(t: ^testing.T) { err = os2.close(fd) _expect_no_error(t, err) - expect(t, unix.sys_access("a/b/c/file.txt", X_OK) < 0, "unexpected exec permission") + when ODIN_OS == .Linux { + expect(t, unix.sys_access("a/b/c/file.txt", X_OK) < 0, "unexpected exec permission") + } err = os2.rename("a/b/c/file.txt", "a/b/file.txt") _expect_no_error(t, err) - expect(t, unix.sys_access("a/b/c/file.txt", F_OK) < 0, "unexpected exec permission") + when ODIN_OS == .Linux { + expect(t, unix.sys_access("a/b/c/file.txt", F_OK) < 0, "unexpected exec permission") + } err = os2.symlink("b/c/d", "a/symlink_to_d") _expect_no_error(t, err) @@ -161,7 +169,9 @@ path_test :: proc(t: ^testing.T) { err = os2.close(fd) _expect_no_error(t, err) - expect_value(t, unix.sys_access("a/b/c/d/shnt.txt", X_OK | R_OK | W_OK), 0) + when ODIN_OS == .Linux { + expect_value(t, unix.sys_access("a/b/c/d/shnt.txt", X_OK | R_OK | W_OK), 0) + } err = os2.remove_all("a") _expect_no_error(t, err) From c6dc5170042057da9bd4708f81017a3a994b2293 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 11 Mar 2022 08:52:16 +0000 Subject: [PATCH 0377/1052] Correct: murmur32 --- core/hash/hash.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/hash/hash.odin b/core/hash/hash.odin index 5044d567a..f2152f1b6 100644 --- a/core/hash/hash.odin +++ b/core/hash/hash.odin @@ -151,7 +151,7 @@ murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 { k1 ~= u32(tail[2]) << 16 fallthrough case 2: - k1 ~= u32(tail[2]) << 8 + k1 ~= u32(tail[1]) << 8 fallthrough case 1: k1 ~= u32(tail[0]) From 7a7b87181dda2f5b3ac3f3286861f033fdd60aa9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 11 Mar 2022 11:09:58 +0100 Subject: [PATCH 0378/1052] [examples] Add `core:encoding/varint` to `examples/all`. --- examples/all/all_main.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index e694060d2..7d2082250 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -54,6 +54,7 @@ import base64 "core:encoding/base64" import csv "core:encoding/csv" import hxa "core:encoding/hxa" import json "core:encoding/json" +import varint "core:encoding/varint" import fmt "core:fmt" import hash "core:hash" @@ -153,6 +154,7 @@ _ :: base64 _ :: csv _ :: hxa _ :: json +_ :: varint _ :: fmt _ :: hash _ :: image From 0e6de5673b2689b50ebe98a2607d94fcdf9e768d Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Fri, 11 Mar 2022 08:06:23 -0500 Subject: [PATCH 0379/1052] fix thread data races --- core/thread/thread_unix.odin | 120 ++++++++++++----------------------- 1 file changed, 40 insertions(+), 80 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index b6679bbc2..35b887de1 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -4,33 +4,22 @@ package thread import "core:runtime" import "core:intrinsics" -import "core:sync" +import sync "core:sync/sync2" import "core:sys/unix" +Thread_State :: enum u8 { + Started, + Joined, + Done, +} + // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t. // Also see core/sys/darwin/mach_darwin.odin/semaphore_t. Thread_Os_Specific :: struct #align 16 { unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux. - - // NOTE: pthread has a proc to query this, but it is marked - // as non-portable ("np") so we do this instead. - done: bool, - - // since libpthread doesn't seem to have a way to create a thread - // in a suspended state, we have it wait on this gate, which we - // signal to start it. - // destroyed after thread is started. - start_gate: sync.Condition, - start_mutex: sync.Mutex, - - // if true, the thread has been started and the start_gate has been destroyed. - started: bool, - - // NOTE: with pthreads, it is undefined behavior for multiple threads - // to call join on the same thread at the same time. - // this value is atomically updated to detect this. - // See the comment in `join`. - already_joined: bool, + cond: sync.Cond, + mutex: sync.Mutex, + flags: bit_set[Thread_State; u8], } // // Creates a thread which will run the given procedure. @@ -38,26 +27,31 @@ Thread_Os_Specific :: struct #align 16 { // _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread { __linux_thread_entry_proc :: proc "c" (t: rawptr) -> rawptr { - context = runtime.default_context() t := (^Thread)(t) - sync.condition_wait_for(&t.start_gate) - sync.condition_destroy(&t.start_gate) - sync.mutex_destroy(&t.start_mutex) - t.start_gate = {} - t.start_mutex = {} - context = t.init_context.? or_else runtime.default_context() - + context = runtime.default_context() + + sync.lock(&t.mutex) + t.id = sync.current_thread_id() - t.procedure(t) - if t.init_context == nil { - if context.temp_allocator.data == &runtime.global_default_temp_allocator_data { - runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data) - } + if .Started not_in t.flags { + sync.wait(&t.cond, &t.mutex) + } + + init_context := t.init_context + context = init_context.? or_else runtime.default_context() + + t.procedure(t) + + t.flags += { .Done } + + sync.unlock(&t.mutex) + + if init_context == nil && context.temp_allocator.data == &runtime.global_default_temp_allocator_data { + runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data) } - intrinsics.atomic_store(&t.done, true) return nil } @@ -76,9 +70,6 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ return nil } thread.creation_allocator = context.allocator - - sync.mutex_init(&thread.start_mutex) - sync.condition_init(&thread.start_gate, &thread.start_mutex) // Set thread priority. policy: i32 @@ -97,65 +88,36 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ res = unix.pthread_attr_setschedparam(&attrs, ¶ms) assert(res == 0) + thread.procedure = procedure if unix.pthread_create(&thread.unix_thread, &attrs, __linux_thread_entry_proc, thread) != 0 { free(thread, thread.creation_allocator) - - sync.condition_destroy(&thread.start_gate) - sync.mutex_destroy(&thread.start_mutex) return nil } - thread.procedure = procedure - return thread } _start :: proc(t: ^Thread) { - if intrinsics.atomic_xchg(&t.started, true) { - return - } - sync.condition_signal(&t.start_gate) + sync.lock(&t.mutex) + t.flags += { .Started } + sync.signal(&t.cond) + sync.unlock(&t.mutex) } _is_done :: proc(t: ^Thread) -> bool { - return intrinsics.atomic_load(&t.done) + return intrinsics.atomic_and(&t.flags, { .Done }) != nil } _join :: proc(t: ^Thread) { - if unix.pthread_equal(unix.pthread_self(), t.unix_thread) { - return - } - // if unix.pthread_self().x == t.unix_thread.x do return; + sync.guard(&t.mutex) - // NOTE(tetra): It's apparently UB for multiple threads to join the same thread - // at the same time. - // If someone else already did, spin until the thread dies. - // See note on `already_joined` field. - // TODO(tetra): I'm not sure if we should do this, or panic, since I'm not - // sure it makes sense to need to join from multiple threads? - if intrinsics.atomic_xchg(&t.already_joined, true) { - for { - if intrinsics.atomic_load(&t.done) { - return - } - intrinsics.cpu_relax() - } - } - - // NOTE(tetra): If we're already dead, don't bother calling to pthread_join as that - // will just return 3 (ESRCH). - // We do this instead because I don't know if there is a danger - // that you may join a different thread from the one you called join on, - // if the thread handle is reused. - if intrinsics.atomic_load(&t.done) { + if .Joined in t.flags || unix.pthread_equal(unix.pthread_self(), t.unix_thread) { return } - ret_val: rawptr - _ = unix.pthread_join(t.unix_thread, &ret_val) - if !intrinsics.atomic_load(&t.done) { - panic("thread not done after join") - } + unix.pthread_join(t.unix_thread, nil) + + t.flags += { .Joined } } _join_multiple :: proc(threads: ..^Thread) { @@ -164,14 +126,12 @@ _join_multiple :: proc(threads: ..^Thread) { } } - _destroy :: proc(t: ^Thread) { _join(t) t.unix_thread = {} free(t, t.creation_allocator) } - _terminate :: proc(t: ^Thread, exit_code: int) { // TODO(bill) } From 7f845bb1655e671c19ae08d6be6b4c4e359a8152 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Fri, 11 Mar 2022 08:30:03 -0500 Subject: [PATCH 0380/1052] fix for spurious wakeups --- core/thread/thread_unix.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 35b887de1..8e1ab2b2c 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -35,7 +35,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ t.id = sync.current_thread_id() - if .Started not_in t.flags { + for (.Started not_in t.flags) { sync.wait(&t.cond, &t.mutex) } From 52df80dccd6a340a582b2b2a8ede682274fec0cd Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Fri, 11 Mar 2022 08:35:23 -0500 Subject: [PATCH 0381/1052] fix for mac & use atomic store on write side to avoid race --- core/thread/thread_unix.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 8e1ab2b2c..e40091cca 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -44,7 +44,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ t.procedure(t) - t.flags += { .Done } + intrinsics.atomic_store(&t.flags, t.flags + { .Done }); sync.unlock(&t.mutex) @@ -105,7 +105,7 @@ _start :: proc(t: ^Thread) { } _is_done :: proc(t: ^Thread) -> bool { - return intrinsics.atomic_and(&t.flags, { .Done }) != nil + return .Done in intrinsics.atomic_load(&t.flags); } _join :: proc(t: ^Thread) { From 32ba5e7ad2e7d814835da2590462a586b33862d0 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Fri, 11 Mar 2022 08:36:04 -0500 Subject: [PATCH 0382/1052] formatting --- core/thread/thread_unix.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index e40091cca..38bf8241d 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -44,7 +44,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ t.procedure(t) - intrinsics.atomic_store(&t.flags, t.flags + { .Done }); + intrinsics.atomic_store(&t.flags, t.flags + { .Done }) sync.unlock(&t.mutex) @@ -105,7 +105,7 @@ _start :: proc(t: ^Thread) { } _is_done :: proc(t: ^Thread) -> bool { - return .Done in intrinsics.atomic_load(&t.flags); + return .Done in intrinsics.atomic_load(&t.flags) } _join :: proc(t: ^Thread) { From 3da8fa9b27a399d465f616c779d24de00a60e4a1 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Fri, 11 Mar 2022 08:41:03 -0500 Subject: [PATCH 0383/1052] can use sync.guard here --- core/thread/thread_unix.odin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 38bf8241d..fbf89f122 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -98,10 +98,9 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ } _start :: proc(t: ^Thread) { - sync.lock(&t.mutex) + sync.guard(&t.mutex) t.flags += { .Started } sync.signal(&t.cond) - sync.unlock(&t.mutex) } _is_done :: proc(t: ^Thread) -> bool { From e008b5a1602d669c865ac3ad42bc6f65b34d8012 Mon Sep 17 00:00:00 2001 From: "U-JSM\\jkercher" Date: Fri, 11 Mar 2022 10:47:59 -0500 Subject: [PATCH 0384/1052] build os2 test on windows --- tests/core/build.bat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/core/build.bat b/tests/core/build.bat index 8cf6486d3..27b444e44 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -46,4 +46,5 @@ echo --- echo --- echo Running core:os/os2 tests echo --- -%PATH_TO_ODIN% run os2 %COMMON% +Rem Needed Shlwapi.lib for PathFileExistsW +%PATH_TO_ODIN% run os2 %COMMON% -extra-linker-flags:Shlwapi.lib From 8982ae34e38d5937b7cb74d95c30cb6a2bac8146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 12 Mar 2022 09:19:52 +0000 Subject: [PATCH 0385/1052] fix linux_arm64 - SYS_fork doesn't exist, uses SYS_clone - properly cast AT_FDCWD to uintptr --- core/os/os_linux.odin | 26 +++++++++++++++----------- core/sys/unix/syscalls_linux.odin | 2 ++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 9716e2925..ed73341c0 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -269,7 +269,7 @@ X_OK :: 1 // Test for execute permission W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission -AT_FDCWD :: -100 +AT_FDCWD :: ~uintptr(99) /* -100 */ AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) @@ -278,7 +278,11 @@ _unix_personality :: proc(persona: u64) -> int { } _unix_fork :: proc() -> Pid { - res := int(intrinsics.syscall(unix.SYS_fork)) + when ODIN_ARCH != .arm64 { + res := int(intrinsics.syscall(unix.SYS_fork)) + } else { + res := int(intrinsics.syscall(unix.SYS_clone, unix.SIGCHLD)) + } return -1 if res < 0 else Pid(res) } @@ -286,7 +290,7 @@ _unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle { when ODIN_ARCH != .arm64 { res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open - res := int(intrinsics.syscall(unix.SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) + res := int(intrinsics.syscall(unix.SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } return -1 if res < 0 else Handle(res) } @@ -321,7 +325,7 @@ _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int { } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have stat - return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0)) + return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0)) } } @@ -339,7 +343,7 @@ _unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int { } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have any lstat - return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) + return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) } } @@ -347,7 +351,7 @@ _unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } else { // NOTE: arm64 does not have readlink - return int(intrinsics.syscall(unix.SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) + return int(intrinsics.syscall(unix.SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } } @@ -355,7 +359,7 @@ _unix_access :: proc(path: cstring, mask: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask))) } else { // NOTE: arm64 does not have access - return int(intrinsics.syscall(unix.SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask))) + return int(intrinsics.syscall(unix.SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask))) } } @@ -371,7 +375,7 @@ _unix_rename :: proc(old, new: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) } else { // NOTE: arm64 does not have rename - return int(intrinsics.syscall(unix.SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new)))) + return int(intrinsics.syscall(unix.SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new)))) } } @@ -379,7 +383,7 @@ _unix_unlink :: proc(path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have unlink - return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0))) + return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0)) } } @@ -387,7 +391,7 @@ _unix_rmdir :: proc(path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have rmdir - return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR)) + return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR)) } } @@ -395,7 +399,7 @@ _unix_mkdir :: proc(path: cstring, mode: u32) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir - return int(intrinsics.syscall(unix.SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + return int(intrinsics.syscall(unix.SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) } } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 0082c7261..3d06d42d4 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -675,6 +675,8 @@ when ODIN_ARCH == .amd64 { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 + + SIGCHLD :: 17 } else when ODIN_ARCH == .i386 { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 From 15f9795ab051b0ed711be51c0e1cbb4f7fbaae52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 12 Mar 2022 09:21:46 +0000 Subject: [PATCH 0386/1052] enable linux_arm64 check in CI --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 412587b3c..a42716dd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,6 +87,9 @@ jobs: - name: Odin check examples/all for Darwin arm64 run: ./odin check examples/all -vet -strict-style -target:darwin_arm64 timeout-minutes: 10 + - name: Odin check examples/all for Linux arm64 + run: ./odin check examples/all -vet -strict-style -target:linux_arm64 + timeout-minutes: 10 build_windows: runs-on: windows-2019 steps: From f7c8b40ea2c133d91827ed788adfb23b24fa1838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 12 Mar 2022 09:40:55 +0000 Subject: [PATCH 0387/1052] use distinct type for fpos_t on OpenBSD --- core/c/libc/stdio.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index fc65b954a..c0d9f9d14 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -79,7 +79,7 @@ when ODIN_OS == .Linux { } when ODIN_OS == .OpenBSD { - fpos_t :: i64 + fpos_t :: distinct i64 _IOFBF :: 0 _IOLBF :: 1 From c12c7d53701e1ba9d110a9c4bd61fc2cb19a8fd1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Mar 2022 10:47:52 +0000 Subject: [PATCH 0388/1052] Remove tag --- core/sync/sync2/primitives.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sync/sync2/primitives.odin b/core/sync/sync2/primitives.odin index 046ecbc35..6d056d439 100644 --- a/core/sync/sync2/primitives.odin +++ b/core/sync/sync2/primitives.odin @@ -11,7 +11,7 @@ current_thread_id :: proc "contextless" () -> int { // // A Mutex must not be copied after first use Mutex :: struct { - impl: _Mutex `This is a tag`, + impl: _Mutex, } // mutex_lock locks m From f907516cbd0078b69996929d02742d0c1a48c226 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 12 Mar 2022 10:48:31 +0000 Subject: [PATCH 0389/1052] #Fix 1615 Replace `llvm.readcyclecounter` with `cntvct_el0` on arm64 --- src/llvm_backend_proc.cpp | 21 +++++++++++++++------ src/llvm_backend_utility.cpp | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index eb6c89b85..1698c211b 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1402,14 +1402,23 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_read_cycle_counter: { - char const *name = "llvm.readcyclecounter"; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, ""); res.type = tv.type; + + if (build_context.metrics.arch == TargetArch_arm64) { + LLVMTypeRef func_type = LLVMFunctionType(LLVMInt64TypeInContext(p->module->ctx), nullptr, 0, false); + bool has_side_effects = false; + LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("mrs x9, cntvct_el0"), str_lit("=r"), has_side_effects); + GB_ASSERT(the_asm != nullptr); + res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); + } else { + char const *name = "llvm.readcyclecounter"; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s", name); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); + + res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, ""); + } return res; } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 431cfea9b..15075380a 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1779,7 +1779,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin return LLVMGetInlineAsm(func_type, cast(char *)str.text, cast(size_t)str.len, cast(char *)clobbers.text, cast(size_t)clobbers.len, - /*HasSideEffects*/true, /*IsAlignStack*/false, + has_side_effects, is_align_stack, dialect #if LLVM_VERSION_MAJOR >= 13 , /*CanThrow*/false From ca67cf032c5a8e0c0fe711fe668cf4d77b080a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 13 Mar 2022 11:42:42 +0000 Subject: [PATCH 0390/1052] freebsd_amd64 support --- core/c/libc/stdio.odin | 25 ++ core/c/libc/wctype.odin | 14 +- core/os/dir_freebsd.odin | 70 ++++++ core/os/os_freebsd.odin | 311 +++++++++++++++++++++--- core/os/stat_unix.odin | 4 +- core/sync/sync2/futex_freebsd.odin | 75 ++++++ core/sync/sync2/primitives_freebsd.odin | 9 + core/sync/sync_freebsd.odin | 14 +- core/sys/unix/pthread_freebsd.odin | 90 +++---- 9 files changed, 515 insertions(+), 97 deletions(-) create mode 100644 core/os/dir_freebsd.odin create mode 100644 core/sync/sync2/futex_freebsd.odin create mode 100644 core/sync/sync2/primitives_freebsd.odin diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index fc65b954a..004b923e8 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -103,6 +103,31 @@ when ODIN_OS == .OpenBSD { } } +when ODIN_OS == .FreeBSD { + fpos_t :: distinct i64 + + _IOFBF :: 0 + _IOLBF :: 1 + _IONBF :: 1 + + BUFSIZ :: 1024 + + EOF :: int(-1) + + FOPEN_MAX :: 20 + FILENAME_MAX :: 1024 + + SEEK_SET :: 0 + SEEK_CUR :: 1 + SEEK_END :: 2 + + foreign libc { + stderr: ^FILE + stdin: ^FILE + stdout: ^FILE + } +} + when ODIN_OS == .Darwin { fpos_t :: distinct i64 diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin index f833af51f..43aee9dc6 100644 --- a/core/c/libc/wctype.odin +++ b/core/c/libc/wctype.odin @@ -13,21 +13,23 @@ when ODIN_OS == .Windows { when ODIN_OS == .Windows { wctrans_t :: distinct wchar_t wctype_t :: distinct ushort -} -when ODIN_OS == .Linux { +} else when ODIN_OS == .Linux { wctrans_t :: distinct intptr_t wctype_t :: distinct ulong -} -when ODIN_OS == .Darwin { +} else when ODIN_OS == .Darwin { wctrans_t :: distinct int wctype_t :: distinct u32 -} -when ODIN_OS == .OpenBSD { +} else when ODIN_OS == .OpenBSD { wctrans_t :: distinct rawptr wctype_t :: distinct rawptr + +} else when ODIN_OS == .FreeBSD { + wctrans_t :: distinct int + wctype_t :: distinct ulong + } @(default_calling_convention="c") diff --git a/core/os/dir_freebsd.odin b/core/os/dir_freebsd.odin new file mode 100644 index 000000000..74c410a51 --- /dev/null +++ b/core/os/dir_freebsd.odin @@ -0,0 +1,70 @@ +package os + +import "core:strings" +import "core:mem" + +read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { + dirp: Dir + dirp, err = _fdopendir(fd) + if err != ERROR_NONE { + return + } + + defer _closedir(dirp) + + dirpath: string + dirpath, err = absolute_path_from_handle(fd) + + if err != ERROR_NONE { + return + } + + defer delete(dirpath) + + n := n + size := n + if n <= 0 { + n = -1 + size = 100 + } + + dfi := make([dynamic]File_Info, 0, size, allocator) + + for { + entry: Dirent + end_of_stream: bool + entry, err, end_of_stream = _readdir(dirp) + if err != ERROR_NONE { + for fi_ in dfi { + file_info_delete(fi_, allocator) + } + delete(dfi) + return + } else if end_of_stream { + break + } + + fi_: File_Info + filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) + + if filename == "." || filename == ".." { + continue + } + + fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) + defer delete(fullpath, context.temp_allocator) + + fi_, err = stat(fullpath, allocator) + if err != ERROR_NONE { + for fi__ in dfi { + file_info_delete(fi__, allocator) + } + delete(dfi) + return + } + + append(&dfi, fi_) + } + + return dfi[:], ERROR_NONE +} diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 9d09a790a..4a95028c1 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -10,7 +10,6 @@ import "core:c" Handle :: distinct i32 File_Time :: distinct u64 Errno :: distinct i32 -Syscall :: distinct i32 INVALID_HANDLE :: ~Handle(0) @@ -142,40 +141,74 @@ RTLD_TRACE :: 0x200 RTLD_NODELETE :: 0x01000 RTLD_NOLOAD :: 0x02000 +MAX_PATH :: 1024 + args := _alloc_command_line_arguments() Unix_File_Time :: struct { - seconds: i64, + seconds: time_t, nanoseconds: c.long, } +dev_t :: u64 +ino_t :: u64 +nlink_t :: u64 +off_t :: i64 +mode_t :: u16 pid_t :: u32 +uid_t :: u32 +gid_t :: u32 +blkcnt_t :: i64 +blksize_t :: i32 +fflags_t :: u32 + +when ODIN_ARCH == .amd64 /* LP64 */ { + time_t :: i64 +} else { + time_t :: i32 +} + OS_Stat :: struct { - device_id: u64, - serial: u64, - nlink: u64, - mode: u32, + device_id: dev_t, + serial: ino_t, + nlink: nlink_t, + mode: mode_t, _padding0: i16, - uid: u32, - gid: u32, + uid: uid_t, + gid: gid_t, _padding1: i32, - rdev: u64, + rdev: dev_t, last_access: Unix_File_Time, modified: Unix_File_Time, status_change: Unix_File_Time, birthtime: Unix_File_Time, - size: i64, - blocks: i64, - block_size: i32, + size: off_t, + blocks: blkcnt_t, + block_size: blksize_t, - flags: u32, + flags: fflags_t, gen: u64, - lspare: i64, + lspare: [10]u64, } + +// since FreeBSD v12 +Dirent :: struct { + ino: ino_t, + off: off_t, + reclen: u16, + type: u8, + _pad0: u8, + namlen: u16, + _pad1: u16, + name: [256]byte, +} + +Dir :: distinct rawptr // DIR* + // File type S_IFMT :: 0o170000 // Type of file mask S_IFIFO :: 0o010000 // Named pipe (fifo) @@ -211,13 +244,13 @@ S_ISGID :: 0o2000 // Set group id on execution S_ISVTX :: 0o1000 // Directory restrcted delete -S_ISLNK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK -S_ISREG :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG -S_ISDIR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR -S_ISCHR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR -S_ISBLK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK -S_ISFIFO :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO -S_ISSOCK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK +S_ISLNK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFLNK +S_ISREG :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFREG +S_ISDIR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFDIR +S_ISCHR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFCHR +S_ISBLK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFBLK +S_ISFIFO :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFIFO +S_ISSOCK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFSOCK F_OK :: 0 // Test for file existance X_OK :: 1 // Test for execute permission @@ -225,27 +258,38 @@ W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission foreign libc { - @(link_name="__error") __errno_location :: proc() -> ^int --- - @(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int --- + @(link_name="__error") __errno_location :: proc() -> ^int --- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- - @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 --- - @(link_name="gettid") _unix_gettid :: proc() -> u64 --- + @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- - @(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int --- + @(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int --- + @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int --- @(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int --- + @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t --- @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int --- + @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- + @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- + @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int --- + @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int --- + @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int --- + @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int --- + + @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- + @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- + @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- + @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr --- @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr --- @(link_name="free") _unix_free :: proc(ptr: rawptr) --- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- + @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- - @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- - @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } @@ -318,12 +362,102 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { return s.size, ERROR_NONE } -stdin: Handle = 0 +rename :: proc(old_path, new_path: string) -> Errno { + old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) + new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) + res := _unix_rename(old_path_cstr, new_path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +remove :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_unlink(path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_mkdir(path_cstr, mode) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +remove_directory :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_rmdir(path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +is_file_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + +is_file_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + +is_dir_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_file :: proc {is_file_path, is_file_handle} +is_dir :: proc {is_dir_path, is_dir_handle} + +// NOTE(bill): Uses startup to initialize it + +stdin: Handle = 0 stdout: Handle = 1 stderr: Handle = 2 +/* TODO(zangent): Implement these! +last_write_time :: proc(fd: Handle) -> File_Time {} +last_write_time_by_name :: proc(name: string) -> File_Time {} +*/ last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { - s, err := fstat(fd) + s, err := _fstat(fd) if err != ERROR_NONE { return 0, err } @@ -332,7 +466,7 @@ last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { } last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { - s, err := stat(name) + s, err := _stat(name) if err != ERROR_NONE { return 0, err } @@ -340,18 +474,33 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { return File_Time(modified), ERROR_NONE } -stat :: proc(path: string) -> (OS_Stat, Errno) { +@private +_stat :: proc(path: string) -> (OS_Stat, Errno) { cstr := strings.clone_to_cstring(path, context.temp_allocator) - s: OS_Stat - result := _unix_stat(cstr, &s) + s: OS_Stat = --- + result := _unix_lstat(cstr, &s) if result == -1 { return s, Errno(get_last_error()) } return s, ERROR_NONE } -fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { - s: OS_Stat +@private +_lstat :: proc(path: string) -> (OS_Stat, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + + // deliberately uninitialized + s: OS_Stat = --- + res := _unix_lstat(cstr, &s) + if res == -1 { + return s, Errno(get_last_error()) + } + return s, ERROR_NONE +} + +@private +_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { + s: OS_Stat = --- result := _unix_fstat(fd, &s) if result == -1 { return s, Errno(get_last_error()) @@ -359,6 +508,95 @@ fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { return s, ERROR_NONE } +@private +_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { + dirp := _unix_fdopendir(fd) + if dirp == cast(Dir)nil { + return nil, Errno(get_last_error()) + } + return dirp, ERROR_NONE +} + +@private +_closedir :: proc(dirp: Dir) -> Errno { + rc := _unix_closedir(dirp) + if rc != 0 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +@private +_rewinddir :: proc(dirp: Dir) { + _unix_rewinddir(dirp) +} + +@private +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { + result: ^Dirent + rc := _unix_readdir_r(dirp, &entry, &result) + + if rc != 0 { + err = Errno(get_last_error()) + return + } + err = ERROR_NONE + + if result == nil { + end_of_stream = true + return + } + + return +} + +@private +_readlink :: proc(path: string) -> (string, Errno) { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + + bufsz : uint = MAX_PATH + buf := make([]byte, MAX_PATH) + for { + rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) + if rc == -1 { + delete(buf) + return "", Errno(get_last_error()) + } else if rc == int(bufsz) { + bufsz += MAX_PATH + delete(buf) + buf = make([]byte, bufsz) + } else { + return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + } + } + unreachable() +} + +// XXX FreeBSD +absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { + return "", Errno(ENOSYS) +} + +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { + rel := rel + if rel == "" { + rel = "." + } + + rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) + + path_ptr := _unix_realpath(rel_cstr, nil) + if path_ptr == nil { + return "", Errno(get_last_error()) + } + defer _unix_free(path_ptr) + + path_cstr := transmute(cstring)path_ptr + path = strings.clone( string(path_cstr) ) + + return path, ERROR_NONE +} + access :: proc(path: string, mask: int) -> (bool, Errno) { cstr := strings.clone_to_cstring(path, context.temp_allocator) result := _unix_access(cstr, c.int(mask)) @@ -464,4 +702,3 @@ _alloc_command_line_arguments :: proc() -> []string { } return res } - diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin index c82466b08..395d2e73e 100644 --- a/core/os/stat_unix.odin +++ b/core/os/stat_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, openbsd +//+build linux, darwin, freebsd, openbsd package os import "core:time" @@ -61,7 +61,7 @@ _make_time_from_unix_file_time :: proc(uft: Unix_File_Time) -> time.Time { _fill_file_info_from_stat :: proc(fi: ^File_Info, s: OS_Stat) { fi.size = s.size fi.mode = cast(File_Mode)s.mode - fi.is_dir = S_ISDIR(u32(s.mode)) + fi.is_dir = S_ISDIR(s.mode) // NOTE(laleksic, 2021-01-21): Not really creation time, but closest we can get (maybe better to leave it 0?) fi.creation_time = _make_time_from_unix_file_time(s.status_change) diff --git a/core/sync/sync2/futex_freebsd.odin b/core/sync/sync2/futex_freebsd.odin new file mode 100644 index 000000000..2cbdb4aaa --- /dev/null +++ b/core/sync/sync2/futex_freebsd.odin @@ -0,0 +1,75 @@ +//+private +//+build freebsd +package sync2 + +import "core:c" +import "core:os" +import "core:time" + +UMTX_OP_WAIT :: 2 +UMTX_OP_WAKE :: 3 + +foreign import libc "system:c" + +foreign libc { + _umtx_op :: proc "c" (obj: rawptr, op: c.int, val: c.ulong, uaddr: rawptr, uaddr2: rawptr) -> c.int --- +} + +_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { + timeout := os.Unix_File_Time{ + seconds = 5, + nanoseconds = 0, + } + + for { + res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout) + + if res != -1 { + return true + } + + if os.Errno(os.get_last_error()) == os.ETIMEDOUT { + continue + } + + panic("_futex_wait failure") + } + unreachable() +} + +_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { + if duration <= 0 { + return false + } + + res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &os.Unix_File_Time{ + seconds = (os.time_t)(duration/1e9), + nanoseconds = (c.long)(duration%1e9), + }) + + if res != -1 { + return true + } + + if os.Errno(os.get_last_error()) == os.ETIMEDOUT { + return false + } + + panic("_futex_wait_with_timeout failure") +} + +_futex_signal :: proc(f: ^Futex) { + res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil) + + if res == -1 { + panic("_futex_signal failure") + } +} + +_futex_broadcast :: proc(f: ^Futex) { + res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil) + + if res == -1 { + panic("_futex_broadcast failure") + } +} diff --git a/core/sync/sync2/primitives_freebsd.odin b/core/sync/sync2/primitives_freebsd.odin new file mode 100644 index 000000000..2a25a18a4 --- /dev/null +++ b/core/sync/sync2/primitives_freebsd.odin @@ -0,0 +1,9 @@ +//+build freebsd +//+private +package sync2 + +import "core:os" + +_current_thread_id :: proc "contextless" () -> int { + return os.current_thread_id() +} diff --git a/core/sync/sync_freebsd.odin b/core/sync/sync_freebsd.odin index 240308b7d..20e6bfceb 100644 --- a/core/sync/sync_freebsd.odin +++ b/core/sync/sync_freebsd.odin @@ -5,8 +5,8 @@ import "core:intrinsics" current_thread_id :: proc "contextless" () -> int { - SYS_GETTID :: 186; - return int(intrinsics.syscall(SYS_GETTID)); + SYS_GETTID :: 186 + return int(intrinsics.syscall(SYS_GETTID)) } @@ -19,22 +19,22 @@ Semaphore :: struct #align 16 { } semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { - assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0); + assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0) } semaphore_destroy :: proc(s: ^Semaphore) { - assert(unix.sem_destroy(&s.handle) == 0); - s.handle = {}; + assert(unix.sem_destroy(&s.handle) == 0) + s.handle = {} } semaphore_post :: proc(s: ^Semaphore, count := 1) { // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop. for in 0.. ^sem_t ---; + sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t --- - sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---; - sem_destroy :: proc(sem: ^sem_t) -> c.int ---; - sem_post :: proc(sem: ^sem_t) -> c.int ---; - sem_wait :: proc(sem: ^sem_t) -> c.int ---; - sem_trywait :: proc(sem: ^sem_t) -> c.int ---; - // sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---; + sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int --- + sem_destroy :: proc(sem: ^sem_t) -> c.int --- + sem_post :: proc(sem: ^sem_t) -> c.int --- + sem_wait :: proc(sem: ^sem_t) -> c.int --- + sem_trywait :: proc(sem: ^sem_t) -> c.int --- + // sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int --- // NOTE: unclear whether pthread_yield is well-supported on Linux systems, // see https://linux.die.net/man/3/pthread_yield - pthread_yield :: proc() ---; + pthread_yield :: proc() --- } From ed4c9335db7ba30679797eda7afe6c61a313ecc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 13 Mar 2022 11:43:36 +0000 Subject: [PATCH 0391/1052] enable freebsd_amd64 inside CI --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 412587b3c..ecb01e8a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,9 @@ jobs: - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 timeout-minutes: 10 + - name: Odin check examples/all for FreeBSD amd64 + run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64 + timeout-minutes: 10 - name: Odin check examples/all for OpenBSD amd64 run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64 timeout-minutes: 10 From 036900da51fb256bb9dbbc82172880440601b6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 13 Mar 2022 12:41:03 +0000 Subject: [PATCH 0392/1052] fix mode_t on darwin - fix mkdir() prototype (mode_t is u16) - remove explicit cast --- core/os/os_darwin.odin | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index ace622582..ae5336849 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -260,13 +260,13 @@ S_ISUID :: 0o4000 // Set user id on execution S_ISGID :: 0o2000 // Set group id on execution S_ISVTX :: 0o1000 // Directory restrcted delete -S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } -S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } -S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } -S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } -S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } -S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } -S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } +S_ISLNK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFLNK } +S_ISREG :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFREG } +S_ISDIR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFDIR } +S_ISCHR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFCHR } +S_ISBLK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFBLK } +S_ISFIFO :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFIFO } +S_ISSOCK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFSOCK } R_OK :: 4 // Test for read permission W_OK :: 2 // Test for write permission @@ -313,7 +313,7 @@ foreign libc { @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- - @(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u32) -> c.int --- + @(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u16) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring --- @@ -433,7 +433,7 @@ is_file_handle :: proc(fd: Handle) -> bool { if err != ERROR_NONE { return false } - return S_ISREG(cast(u32)s.mode) + return S_ISREG(s.mode) } is_file_path :: proc(path: string, follow_links: bool = true) -> bool { @@ -447,7 +447,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool { if err != ERROR_NONE { return false } - return S_ISREG(cast(u32)s.mode) + return S_ISREG(s.mode) } @@ -456,7 +456,7 @@ is_dir_handle :: proc(fd: Handle) -> bool { if err != ERROR_NONE { return false } - return S_ISDIR(cast(u32)s.mode) + return S_ISDIR(s.mode) } is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { @@ -470,7 +470,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { if err != ERROR_NONE { return false } - return S_ISDIR(cast(u32)s.mode) + return S_ISDIR(s.mode) } is_file :: proc {is_file_path, is_file_handle} @@ -670,7 +670,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { return ERROR_NONE } -make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { +make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno { path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { From ef3f448861303dcfe3c0bb7164d47ad694a03c0e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 14 Mar 2022 13:06:50 +0100 Subject: [PATCH 0393/1052] Remove accidentally committed test binary. --- tests/core/crypto_hash | Bin 626328 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 tests/core/crypto_hash diff --git a/tests/core/crypto_hash b/tests/core/crypto_hash deleted file mode 100755 index 32f8217be6856cf6dcbfef1a3cd3a128eb3386e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 626328 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

l|lFHtAfq{92f~g>_#$F_h6VYbm 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�?Y|f@T&I1$%ssD7{mQ{Bs0>)>OP} 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 z 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